X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=drivers%2Fmtd%2Fspi%2Fspi-nor-core.c;h=8a226a7af553c4f63f1a26367cb8ad12dfa702d4;hb=fc97ff2695d6d7fbea7d5fda7b080f405d6ee744;hp=8dd44c0f1e1bfd39b3412982dc45b6b6c5064d6e;hpb=f6adec1af4b2f5d3012480c6cdce7743b74a6156;p=platform%2Fkernel%2Fu-boot.git diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c index 8dd44c0..8a226a7 100644 --- a/drivers/mtd/spi/spi-nor-core.c +++ b/drivers/mtd/spi/spi-nor-core.c @@ -10,6 +10,7 @@ */ #include +#include #include #include #include @@ -26,6 +27,7 @@ #include #include +#include #include #include @@ -63,6 +65,10 @@ struct sfdp_parameter_header { #define SFDP_SECTOR_MAP_ID 0xff81 /* Sector Map Table */ #define SFDP_SST_ID 0x01bf /* Manufacturer specific Table */ #define SFDP_PROFILE1_ID 0xff05 /* xSPI Profile 1.0 Table */ +#define SFDP_SCCR_MAP_ID 0xff87 /* + * Status, Control and Configuration + * Register Map. + */ #define SFDP_SIGNATURE 0x50444653U #define SFDP_JESD216_MAJOR 1 @@ -172,6 +178,9 @@ struct sfdp_header { #define PROFILE1_DWORD5_DUMMY_100MHZ GENMASK(11, 7) #define PROFILE1_DUMMY_DEFAULT 20 +/* Status, Control and Configuration Register Map(SCCR) */ +#define SCCR_DWORD22_OCTAL_DTR_EN_VOLATILE BIT(31) + struct sfdp_bfpt { u32 dwords[BFPT_DWORD_MAX]; }; @@ -315,6 +324,31 @@ static int spi_nor_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len) return spi_nor_read_write_reg(nor, &op, buf); } +#ifdef CONFIG_SPI_FLASH_SPANSION +static int spansion_read_any_reg(struct spi_nor *nor, u32 addr, u8 dummy, + u8 *val) +{ + struct spi_mem_op op = + SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_RDAR, 1), + SPI_MEM_OP_ADDR(nor->addr_width, addr, 1), + SPI_MEM_OP_DUMMY(dummy / 8, 1), + SPI_MEM_OP_DATA_IN(1, NULL, 1)); + + return spi_nor_read_write_reg(nor, &op, val); +} + +static int spansion_write_any_reg(struct spi_nor *nor, u32 addr, u8 val) +{ + struct spi_mem_op op = + SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WRAR, 1), + SPI_MEM_OP_ADDR(nor->addr_width, addr, 1), + SPI_MEM_OP_NO_DUMMY, + SPI_MEM_OP_DATA_OUT(1, NULL, 1)); + + return spi_nor_read_write_reg(nor, &op, &val); +} +#endif + static ssize_t spi_nor_read_data(struct spi_nor *nor, loff_t from, size_t len, u_char *buf) { @@ -637,6 +671,9 @@ static int set_4byte(struct spi_nor *nor, const struct flash_info *info, } return status; + case SNOR_MFR_CYPRESS: + cmd = enable ? SPINOR_OP_EN4B : SPINOR_OP_EX4B_CYPRESS; + return nor->write_reg(nor, cmd, NULL, 0); default: /* Spansion style */ nor->cmd_buf[0] = enable << 7; @@ -644,6 +681,35 @@ static int set_4byte(struct spi_nor *nor, const struct flash_info *info, } } +#ifdef CONFIG_SPI_FLASH_SPANSION +/* + * Read status register 1 by using Read Any Register command to support multi + * die package parts. + */ +static int spansion_sr_ready(struct spi_nor *nor, u32 addr_base, u8 dummy) +{ + u32 reg_addr = addr_base + SPINOR_REG_ADDR_STR1V; + u8 sr; + int ret; + + ret = spansion_read_any_reg(nor, reg_addr, dummy, &sr); + if (ret < 0) + return ret; + + if (sr & (SR_E_ERR | SR_P_ERR)) { + if (sr & SR_E_ERR) + dev_dbg(nor->dev, "Erase Error occurred\n"); + else + dev_dbg(nor->dev, "Programming Error occurred\n"); + + nor->write_reg(nor, SPINOR_OP_CLSR, NULL, 0); + return -EIO; + } + + return !(sr & SR_WIP); +} +#endif + static int spi_nor_sr_ready(struct spi_nor *nor) { int sr = read_sr(nor); @@ -688,7 +754,7 @@ static int spi_nor_fsr_ready(struct spi_nor *nor) return fsr & FSR_READY; } -static int spi_nor_ready(struct spi_nor *nor) +static int spi_nor_default_ready(struct spi_nor *nor) { int sr, fsr; @@ -701,6 +767,14 @@ static int spi_nor_ready(struct spi_nor *nor) return sr && fsr; } +static int spi_nor_ready(struct spi_nor *nor) +{ + if (nor->ready) + return nor->ready(nor); + + return spi_nor_default_ready(nor); +} + /* * Service routine to read status register until ready, or timeout occurs. * Returns non-zero if error. @@ -841,30 +915,40 @@ 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); + bool addr_known = false; u32 addr, len, rem; - int ret; + int ret, err; dev_dbg(nor->dev, "at 0x%llx, len %lld\n", (long long)instr->addr, (long long)instr->len); - if (!instr->len) - return 0; - div_u64_rem(instr->len, mtd->erasesize, &rem); - if (rem) - return -EINVAL; + if (rem) { + ret = -EINVAL; + goto err; + } addr = instr->addr; len = instr->len; + instr->state = MTD_ERASING; + addr_known = true; + while (len) { WATCHDOG_RESET(); + if (!IS_ENABLED(CONFIG_SPL_BUILD) && ctrlc()) { + addr_known = false; + ret = -EINTR; + goto erase_err; + } #ifdef CONFIG_SPI_FLASH_BAR ret = write_bar(nor, addr); if (ret < 0) - return ret; + goto erase_err; #endif - write_enable(nor); + ret = write_enable(nor); + if (ret < 0) + goto erase_err; ret = spi_nor_erase_sector(nor, addr); if (ret < 0) @@ -878,16 +962,29 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr) goto erase_err; } + addr_known = false; erase_err: #ifdef CONFIG_SPI_FLASH_BAR - ret = clean_bar(nor); + err = clean_bar(nor); + if (!ret) + ret = err; #endif - write_disable(nor); + err = write_disable(nor); + if (!ret) + ret = err; + +err: + if (ret) { + instr->fail_addr = addr_known ? addr : MTD_FAIL_ADDR_UNKNOWN; + instr->state = MTD_ERASE_FAILED; + } else { + instr->state = MTD_ERASE_DONE; + } return ret; } -#ifdef CONFIG_SPI_FLASH_S28HS512T +#ifdef CONFIG_SPI_FLASH_SPANSION /** * spansion_erase_non_uniform() - erase non-uniform sectors for Spansion/Cypress * chips @@ -1218,13 +1315,13 @@ static int stm_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len) } /* - * Check if a region of the flash is (completely) locked. See stm_lock() for + * Check if a region of the flash is (completely) unlocked. See stm_lock() for * more info. * - * Returns 1 if entire region is locked, 0 if any portion is unlocked, and + * Returns 1 if entire region is unlocked, 0 if any portion is locked, and * negative on errors. */ -static int stm_is_locked(struct spi_nor *nor, loff_t ofs, uint64_t len) +static int stm_is_unlocked(struct spi_nor *nor, loff_t ofs, uint64_t len) { int status; @@ -1232,7 +1329,7 @@ static int stm_is_locked(struct spi_nor *nor, loff_t ofs, uint64_t len) if (status < 0) return status; - return stm_is_locked_sr(nor, ofs, len, status); + return stm_is_unlocked_sr(nor, ofs, len, status); } #endif /* CONFIG_SPI_FLASH_STMICRO */ @@ -1465,16 +1562,16 @@ static int sst26_lock(struct spi_nor *nor, loff_t ofs, uint64_t len) } /* - * Returns EACCES (positive value) if region is locked, 0 if region is unlocked, - * and negative on errors. + * Returns EACCES (positive value) if region is (partially) locked, 0 if region + * is completely unlocked, and negative on errors. */ -static int sst26_is_locked(struct spi_nor *nor, loff_t ofs, uint64_t len) +static int sst26_is_unlocked(struct spi_nor *nor, loff_t ofs, uint64_t len) { /* - * is_locked function is used for check before reading or erasing flash - * region, so offset and length might be not 64k allighned, so adjust - * them to be 64k allighned as sst26_lock_ctl works only with 64k - * allighned regions. + * is_unlocked function is used for check before reading or erasing + * flash region, so offset and length might be not 64k aligned, so + * adjust them to be 64k aligned as sst26_lock_ctl works only with 64k + * aligned regions. */ ofs -= ofs & (SZ_64K - 1); len = len & (SZ_64K - 1) ? (len & ~(SZ_64K - 1)) + SZ_64K : len; @@ -1598,9 +1695,6 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len, dev_dbg(nor->dev, "to 0x%08x, len %zd\n", (u32)to, len); - if (!len) - return 0; - for (i = 0; i < len; ) { ssize_t written; loff_t addr = to + i; @@ -1686,6 +1780,61 @@ static int macronix_quad_enable(struct spi_nor *nor) } #endif +#ifdef CONFIG_SPI_FLASH_SPANSION +/** + * spansion_quad_enable_volatile() - enable Quad I/O mode in volatile register. + * @nor: pointer to a 'struct spi_nor' + * @addr_base: base address of register (can be >0 in multi-die parts) + * @dummy: number of dummy cycles for register read + * + * It is recommended to update volatile registers in the field application due + * to a risk of the non-volatile registers corruption by power interrupt. This + * function sets Quad Enable bit in CFR1 volatile. + * + * Return: 0 on success, -errno otherwise. + */ +static int spansion_quad_enable_volatile(struct spi_nor *nor, u32 addr_base, + u8 dummy) +{ + u32 addr = addr_base + SPINOR_REG_ADDR_CFR1V; + + u8 cr; + int ret; + + /* Check current Quad Enable bit value. */ + ret = spansion_read_any_reg(nor, addr, dummy, &cr); + if (ret < 0) { + dev_dbg(nor->dev, + "error while reading configuration register\n"); + return -EINVAL; + } + + if (cr & CR_QUAD_EN_SPAN) + return 0; + + cr |= CR_QUAD_EN_SPAN; + + write_enable(nor); + + ret = spansion_write_any_reg(nor, addr, cr); + + if (ret < 0) { + dev_dbg(nor->dev, + "error while writing configuration register\n"); + return -EINVAL; + } + + /* Read back and check it. */ + ret = spansion_read_any_reg(nor, addr, dummy, &cr); + if (ret || !(cr & CR_QUAD_EN_SPAN)) { + dev_dbg(nor->dev, "Spansion Quad bit not set\n"); + return -EINVAL; + } + + return 0; +} +#endif + #if defined(CONFIG_SPI_FLASH_SPANSION) || defined(CONFIG_SPI_FLASH_WINBOND) /* * Write status Register and configuration register with 2 bytes @@ -2315,6 +2464,44 @@ out: } /** + * spi_nor_parse_sccr() - Parse the Status, Control and Configuration Register + * Map. + * @nor: pointer to a 'struct spi_nor' + * @sccr_header: pointer to the 'struct sfdp_parameter_header' describing + * the SCCR Map table length and version. + * + * Return: 0 on success, -errno otherwise. + */ +static int spi_nor_parse_sccr(struct spi_nor *nor, + const struct sfdp_parameter_header *sccr_header) +{ + u32 *table, addr; + size_t len; + int ret, i; + + len = sccr_header->length * sizeof(*table); + table = kmalloc(len, GFP_KERNEL); + if (!table) + return -ENOMEM; + + addr = SFDP_PARAM_HEADER_PTP(sccr_header); + ret = spi_nor_read_sfdp(nor, addr, len, table); + if (ret) + goto out; + + /* Fix endianness of the table DWORDs. */ + for (i = 0; i < sccr_header->length; i++) + table[i] = le32_to_cpu(table[i]); + + if (FIELD_GET(SCCR_DWORD22_OCTAL_DTR_EN_VOLATILE, table[22])) + nor->flags |= SNOR_F_IO_MODE_EN_VOLATILE; + +out: + kfree(table); + return ret; +} + +/** * spi_nor_parse_sfdp() - parse the Serial Flash Discoverable Parameters. * @nor: pointer to a 'struct spi_nor' * @params: pointer to the 'struct spi_nor_flash_parameter' to be @@ -2420,6 +2607,10 @@ static int spi_nor_parse_sfdp(struct spi_nor *nor, err = spi_nor_parse_profile1(nor, param_header, params); break; + case SFDP_SCCR_MAP_ID: + err = spi_nor_parse_sccr(nor, param_header); + break; + default: break; } @@ -2484,18 +2675,28 @@ static int spi_nor_init_params(struct spi_nor *nor, params->size = info->sector_size * info->n_sectors; params->page_size = info->page_size; + if (!(info->flags & SPI_NOR_NO_FR)) { + /* Default to Fast Read for DT and non-DT platform devices. */ + params->hwcaps.mask |= SNOR_HWCAPS_READ_FAST; + + /* Mask out Fast Read if not requested at DT instantiation. */ +#if CONFIG_IS_ENABLED(DM_SPI) + if (!ofnode_read_bool(dev_ofnode(nor->spi->dev), + "m25p,fast-read")) + params->hwcaps.mask &= ~SNOR_HWCAPS_READ_FAST; +#endif + } + /* (Fast) Read settings. */ params->hwcaps.mask |= SNOR_HWCAPS_READ; spi_nor_set_read_settings(¶ms->reads[SNOR_CMD_READ], 0, 0, SPINOR_OP_READ, SNOR_PROTO_1_1_1); - if (!(info->flags & SPI_NOR_NO_FR)) { - params->hwcaps.mask |= SNOR_HWCAPS_READ_FAST; + if (params->hwcaps.mask & SNOR_HWCAPS_READ_FAST) spi_nor_set_read_settings(¶ms->reads[SNOR_CMD_READ_FAST], 0, 8, SPINOR_OP_READ_FAST, SNOR_PROTO_1_1_1); - } if (info->flags & SPI_NOR_DUAL_READ) { params->hwcaps.mask |= SNOR_HWCAPS_READ_1_1_2; @@ -2738,10 +2939,11 @@ spi_nor_adjust_hwcaps(struct spi_nor *nor, unsigned int cap; /* - * Enable all caps by default. We will mask them after checking what's - * really supported using spi_mem_supports_op(). + * Start by assuming the controller supports every capability. + * We will mask them after checking what's really supported + * using spi_mem_supports_op(). */ - *hwcaps = SNOR_HWCAPS_ALL; + *hwcaps = SNOR_HWCAPS_ALL & params->hwcaps.mask; /* X-X-X modes are not supported yet, mask them all. */ *hwcaps &= ~SNOR_HWCAPS_X_X_X; @@ -2965,6 +3167,149 @@ static int spi_nor_setup(struct spi_nor *nor, const struct flash_info *info, return nor->setup(nor, info, params); } +#ifdef CONFIG_SPI_FLASH_SPANSION +static int s25hx_t_mdp_ready(struct spi_nor *nor) +{ + u32 addr; + int ret; + + for (addr = 0; addr < nor->mtd.size; addr += SZ_128M) { + ret = spansion_sr_ready(nor, addr, 0); + if (!ret) + return ret; + } + + return 1; +} + +static int s25hx_t_quad_enable(struct spi_nor *nor) +{ + u32 addr; + int ret; + + for (addr = 0; addr < nor->mtd.size; addr += SZ_128M) { + ret = spansion_quad_enable_volatile(nor, addr, 0); + if (ret) + return ret; + } + + return 0; +} + +static int s25hx_t_erase_non_uniform(struct spi_nor *nor, loff_t addr) +{ + /* Support 32 x 4KB sectors at bottom */ + return spansion_erase_non_uniform(nor, addr, SPINOR_OP_BE_4K_4B, 0, + SZ_128K); +} + +static int s25hx_t_setup(struct spi_nor *nor, const struct flash_info *info, + const struct spi_nor_flash_parameter *params) +{ + int ret; + u8 cfr3v; + +#ifdef CONFIG_SPI_FLASH_BAR + return -ENOTSUPP; /* Bank Address Register is not supported */ +#endif + /* + * Read CFR3V to check if uniform sector is selected. If not, assign an + * erase hook that supports non-uniform erase. + */ + ret = spansion_read_any_reg(nor, SPINOR_REG_ADDR_CFR3V, 0, &cfr3v); + if (ret) + return ret; + if (!(cfr3v & CFR3V_UNHYSA)) + nor->erase = s25hx_t_erase_non_uniform; + + /* + * For the multi-die package parts, the ready() hook is needed to check + * all dies' status via read any register. + */ + if (nor->mtd.size > SZ_128M) + nor->ready = s25hx_t_mdp_ready; + + return spi_nor_default_setup(nor, info, params); +} + +static void s25hx_t_default_init(struct spi_nor *nor) +{ + nor->setup = s25hx_t_setup; +} + +static int s25hx_t_post_bfpt_fixup(struct spi_nor *nor, + const struct sfdp_parameter_header *header, + const struct sfdp_bfpt *bfpt, + struct spi_nor_flash_parameter *params) +{ + int ret; + u32 addr; + u8 cfr3v; + + /* erase size in case it is set to 4K from BFPT */ + nor->erase_opcode = SPINOR_OP_SE_4B; + nor->mtd.erasesize = nor->info->sector_size; + + ret = set_4byte(nor, nor->info, 1); + if (ret) + return ret; + nor->addr_width = 4; + + /* + * The page_size is set to 512B from BFPT, but it actually depends on + * the configuration register. Look up the CFR3V and determine the + * page_size. For multi-die package parts, use 512B only when the all + * dies are configured to 512B buffer. + */ + for (addr = 0; addr < params->size; addr += SZ_128M) { + ret = spansion_read_any_reg(nor, addr + SPINOR_REG_ADDR_CFR3V, + 0, &cfr3v); + if (ret) + return ret; + + if (!(cfr3v & CFR3V_PGMBUF)) { + params->page_size = 256; + return 0; + } + } + params->page_size = 512; + + return 0; +} + +static void s25hx_t_post_sfdp_fixup(struct spi_nor *nor, + struct spi_nor_flash_parameter *params) +{ + /* READ_FAST_4B (0Ch) requires mode cycles*/ + params->reads[SNOR_CMD_READ_FAST].num_mode_clocks = 8; + /* PP_1_1_4 is not supported */ + params->hwcaps.mask &= ~SNOR_HWCAPS_PP_1_1_4; + /* Use volatile register to enable quad */ + params->quad_enable = s25hx_t_quad_enable; +} + +static struct spi_nor_fixups s25hx_t_fixups = { + .default_init = s25hx_t_default_init, + .post_bfpt = s25hx_t_post_bfpt_fixup, + .post_sfdp = s25hx_t_post_sfdp_fixup, +}; + +static int s25fl256l_setup(struct spi_nor *nor, const struct flash_info *info, + const struct spi_nor_flash_parameter *params) +{ + return -ENOTSUPP; /* Bank Address Register is not supported */ +} + +static void s25fl256l_default_init(struct spi_nor *nor) +{ + nor->setup = s25fl256l_setup; +} + +static struct spi_nor_fixups s25fl256l_fixups = { + .default_init = s25fl256l_default_init, +}; +#endif + #ifdef CONFIG_SPI_FLASH_S28HS512T /** * spi_nor_cypress_octal_dtr_enable() - Enable octal DTR on Cypress flashes. @@ -3230,6 +3575,84 @@ static struct spi_nor_fixups mt35xu512aba_fixups = { }; #endif /* CONFIG_SPI_FLASH_MT35XU */ +#if CONFIG_IS_ENABLED(SPI_FLASH_MACRONIX) +/** + * spi_nor_macronix_octal_dtr_enable() - Enable octal DTR on Macronix flashes. + * @nor: pointer to a 'struct spi_nor' + * + * Set Macronix max dummy cycles 20 to allow the flash to run at fastest frequency. + * + * Return: 0 on success, -errno otherwise. + */ +static int spi_nor_macronix_octal_dtr_enable(struct spi_nor *nor) +{ + struct spi_mem_op op; + int ret; + u8 buf; + + ret = write_enable(nor); + if (ret) + return ret; + + buf = SPINOR_REG_MXIC_DC_20; + op = (struct spi_mem_op) + SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WR_CR2, 1), + SPI_MEM_OP_ADDR(4, SPINOR_REG_MXIC_CR2_DC, 1), + SPI_MEM_OP_NO_DUMMY, + SPI_MEM_OP_DATA_OUT(1, &buf, 1)); + + ret = spi_mem_exec_op(nor->spi, &op); + if (ret) + return ret; + + ret = spi_nor_wait_till_ready(nor); + if (ret) + return ret; + + nor->read_dummy = MXIC_MAX_DC; + ret = write_enable(nor); + if (ret) + return ret; + + buf = SPINOR_REG_MXIC_OPI_DTR_EN; + op = (struct spi_mem_op) + SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WR_CR2, 1), + SPI_MEM_OP_ADDR(4, SPINOR_REG_MXIC_CR2_MODE, 1), + SPI_MEM_OP_NO_DUMMY, + SPI_MEM_OP_DATA_OUT(1, &buf, 1)); + + ret = spi_mem_exec_op(nor->spi, &op); + if (ret) { + dev_err(nor->dev, "Failed to enable octal DTR mode\n"); + return ret; + } + nor->reg_proto = SNOR_PROTO_8_8_8_DTR; + + return 0; +} + +static void macronix_octal_default_init(struct spi_nor *nor) +{ + nor->octal_dtr_enable = spi_nor_macronix_octal_dtr_enable; +} + +static void macronix_octal_post_sfdp_fixup(struct spi_nor *nor, + struct spi_nor_flash_parameter *params) +{ + /* + * Adding SNOR_HWCAPS_PP_8_8_8_DTR in hwcaps.mask when + * SPI_NOR_OCTAL_DTR_READ flag exists. + */ + if (params->hwcaps.mask & SNOR_HWCAPS_READ_8_8_8_DTR) + params->hwcaps.mask |= SNOR_HWCAPS_PP_8_8_8_DTR; +} + +static struct spi_nor_fixups macronix_octal_fixups = { + .default_init = macronix_octal_default_init, + .post_sfdp = macronix_octal_post_sfdp_fixup, +}; +#endif /* CONFIG_SPI_FLASH_MACRONIX */ + /** spi_nor_octal_dtr_enable() - enable Octal DTR I/O if needed * @nor: pointer to a 'struct spi_nor' * @@ -3246,6 +3669,9 @@ static int spi_nor_octal_dtr_enable(struct spi_nor *nor) nor->write_proto == SNOR_PROTO_8_8_8_DTR)) return 0; + if (!(nor->flags & SNOR_F_IO_MODE_EN_VOLATILE)) + return 0; + ret = nor->octal_dtr_enable(nor); if (ret) return ret; @@ -3323,7 +3749,12 @@ static int spi_nor_soft_reset(struct spi_nor *nor) enum spi_nor_cmd_ext ext; ext = nor->cmd_ext_type; - nor->cmd_ext_type = SPI_NOR_EXT_REPEAT; + if (nor->cmd_ext_type == SPI_NOR_EXT_NONE) { + nor->cmd_ext_type = SPI_NOR_EXT_REPEAT; +#if CONFIG_IS_ENABLED(SPI_NOR_BOOT_SOFT_RESET_EXT_INVERT) + nor->cmd_ext_type = SPI_NOR_EXT_INVERT; +#endif /* SPI_NOR_BOOT_SOFT_RESET_EXT_INVERT */ + } op = (struct spi_mem_op)SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_SRSTEN, 0), SPI_MEM_OP_NO_DUMMY, @@ -3373,6 +3804,24 @@ int spi_nor_remove(struct spi_nor *nor) void spi_nor_set_fixups(struct spi_nor *nor) { +#ifdef CONFIG_SPI_FLASH_SPANSION + if (JEDEC_MFR(nor->info) == SNOR_MFR_CYPRESS) { + switch (nor->info->id[1]) { + case 0x2a: /* S25HL (QSPI, 3.3V) */ + case 0x2b: /* S25HS (QSPI, 1.8V) */ + nor->fixups = &s25hx_t_fixups; + break; + + default: + break; + } + } + + if (CONFIG_IS_ENABLED(SPI_FLASH_BAR) && + !strcmp(nor->info->name, "s25fl256l")) + nor->fixups = &s25fl256l_fixups; +#endif + #ifdef CONFIG_SPI_FLASH_S28HS512T if (!strcmp(nor->info->name, "s28hs512t")) nor->fixups = &s28hs512t_fixups; @@ -3382,6 +3831,10 @@ void spi_nor_set_fixups(struct spi_nor *nor) if (!strcmp(nor->info->name, "mt35xu512aba")) nor->fixups = &mt35xu512aba_fixups; #endif + +#if CONFIG_IS_ENABLED(SPI_FLASH_MACRONIX) + nor->fixups = ¯onix_octal_fixups; +#endif /* SPI_FLASH_MACRONIX */ } int spi_nor_scan(struct spi_nor *nor) @@ -3391,6 +3844,11 @@ int spi_nor_scan(struct spi_nor *nor) struct mtd_info *mtd = &nor->mtd; struct spi_slave *spi = nor->spi; int ret; + int cfi_mtd_nb = 0; + +#ifdef CONFIG_FLASH_CFI_MTD + cfi_mtd_nb = CFI_FLASH_BANKS; +#endif /* Reset SPI protocol for all commands. */ nor->reg_proto = SNOR_PROTO_1_1_1; @@ -3442,8 +3900,12 @@ int spi_nor_scan(struct spi_nor *nor) if (ret) return ret; - if (!mtd->name) - mtd->name = info->name; + if (!mtd->name) { + sprintf(nor->mtd_name, "%s%d", + MTD_DEV_TYPE(MTD_DEV_TYPE_NOR), + cfi_mtd_nb + dev_seq(nor->dev)); + mtd->name = nor->mtd_name; + } mtd->dev = nor->dev; mtd->priv = nor; mtd->type = MTD_NORFLASH; @@ -3462,7 +3924,7 @@ int spi_nor_scan(struct spi_nor *nor) info->flags & SPI_NOR_HAS_LOCK) { nor->flash_lock = stm_lock; nor->flash_unlock = stm_unlock; - nor->flash_is_locked = stm_is_locked; + nor->flash_is_unlocked = stm_is_unlocked; } #endif @@ -3474,7 +3936,7 @@ int spi_nor_scan(struct spi_nor *nor) if (info->flags & SPI_NOR_HAS_SST26LOCK) { nor->flash_lock = sst26_lock; nor->flash_unlock = sst26_unlock; - nor->flash_is_locked = sst26_is_locked; + nor->flash_is_unlocked = sst26_is_unlocked; } #endif @@ -3548,7 +4010,7 @@ int spi_nor_scan(struct spi_nor *nor) nor->rdsr_dummy = params.rdsr_dummy; nor->rdsr_addr_nbytes = params.rdsr_addr_nbytes; - nor->name = mtd->name; + nor->name = info->name; nor->size = mtd->size; nor->erase_size = mtd->erasesize; nor->sector_size = mtd->erasesize;