diff options
Diffstat (limited to 'drivers/mtd/spi-nor/spi-nor.c')
-rw-r--r-- | drivers/mtd/spi-nor/spi-nor.c | 3007 |
1 files changed, 2059 insertions, 948 deletions
diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index 654bdc41fc99..4fc632ec18fe 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -19,6 +19,7 @@ #include <linux/mtd/mtd.h> #include <linux/of_platform.h> +#include <linux/sched/task_stack.h> #include <linux/spi/flash.h> #include <linux/mtd/spi-nor.h> @@ -39,71 +40,6 @@ #define SPI_NOR_MAX_ID_LEN 6 #define SPI_NOR_MAX_ADDR_WIDTH 4 -struct spi_nor_read_command { - u8 num_mode_clocks; - u8 num_wait_states; - u8 opcode; - enum spi_nor_protocol proto; -}; - -struct spi_nor_pp_command { - u8 opcode; - enum spi_nor_protocol proto; -}; - -enum spi_nor_read_command_index { - SNOR_CMD_READ, - SNOR_CMD_READ_FAST, - SNOR_CMD_READ_1_1_1_DTR, - - /* Dual SPI */ - SNOR_CMD_READ_1_1_2, - SNOR_CMD_READ_1_2_2, - SNOR_CMD_READ_2_2_2, - SNOR_CMD_READ_1_2_2_DTR, - - /* Quad SPI */ - SNOR_CMD_READ_1_1_4, - SNOR_CMD_READ_1_4_4, - SNOR_CMD_READ_4_4_4, - SNOR_CMD_READ_1_4_4_DTR, - - /* Octal SPI */ - SNOR_CMD_READ_1_1_8, - SNOR_CMD_READ_1_8_8, - SNOR_CMD_READ_8_8_8, - SNOR_CMD_READ_1_8_8_DTR, - - SNOR_CMD_READ_MAX -}; - -enum spi_nor_pp_command_index { - SNOR_CMD_PP, - - /* Quad SPI */ - SNOR_CMD_PP_1_1_4, - SNOR_CMD_PP_1_4_4, - SNOR_CMD_PP_4_4_4, - - /* Octal SPI */ - SNOR_CMD_PP_1_1_8, - SNOR_CMD_PP_1_8_8, - SNOR_CMD_PP_8_8_8, - - SNOR_CMD_PP_MAX -}; - -struct spi_nor_flash_parameter { - u64 size; - u32 page_size; - - struct spi_nor_hwcaps hwcaps; - struct spi_nor_read_command reads[SNOR_CMD_READ_MAX]; - struct spi_nor_pp_command page_programs[SNOR_CMD_PP_MAX]; - - int (*quad_enable)(struct spi_nor *nor); -}; - struct sfdp_parameter_header { u8 id_lsb; u8 minor; @@ -149,7 +85,7 @@ struct sfdp_header { #define BFPT_DWORD(i) ((i) - 1) #define BFPT_DWORD_MAX 16 -/* The first version of JESB216 defined only 9 DWORDs. */ +/* The first version of JESD216 defined only 9 DWORDs. */ #define BFPT_DWORD_MAX_JESD216 9 /* 1st DWORD. */ @@ -218,16 +154,26 @@ struct sfdp_bfpt { /** * struct spi_nor_fixups - SPI NOR fixup hooks + * @default_init: called after default flash parameters init. Used to tweak + * flash parameters when information provided by the flash_info + * table is incomplete or wrong. * @post_bfpt: called after the BFPT table has been parsed + * @post_sfdp: called after SFDP has been parsed (is also called for SPI NORs + * that do not support RDSFDP). Typically used to tweak various + * parameters that could not be extracted by other means (i.e. + * when information provided by the SFDP/flash_info tables are + * incomplete or wrong). * * Those hooks can be used to tweak the SPI NOR configuration when the SFDP * table is broken or not available. */ struct spi_nor_fixups { + void (*default_init)(struct spi_nor *nor); int (*post_bfpt)(struct spi_nor *nor, const struct sfdp_parameter_header *bfpt_header, const struct sfdp_bfpt *bfpt, struct spi_nor_flash_parameter *params); + void (*post_sfdp)(struct spi_nor *nor); }; struct flash_info { @@ -250,7 +196,7 @@ struct flash_info { u16 page_size; u16 addr_width; - u16 flags; + u32 flags; #define SECT_4K BIT(0) /* SPINOR_OP_BE_4K works uniformly */ #define SPI_NOR_NO_ERASE BIT(1) /* No erase command needed */ #define SST_WRITE BIT(2) /* use SST byte programming */ @@ -265,6 +211,14 @@ struct flash_info { * bit. Must be used with * SPI_NOR_HAS_LOCK. */ +#define SPI_NOR_XSR_RDY BIT(10) /* + * S3AN flashes have specific opcode to + * read the status register. + * Flags SPI_NOR_XSR_RDY and SPI_S3AN + * use the same bit as one implies the + * other, but we will get rid of + * SPI_S3AN soon. + */ #define SPI_S3AN BIT(10) /* * Xilinx Spartan 3AN In-System Flash * (MFR cannot be used for probing @@ -279,296 +233,637 @@ struct flash_info { #define SPI_NOR_SKIP_SFDP BIT(13) /* Skip parsing of SFDP tables */ #define USE_CLSR BIT(14) /* use CLSR command */ #define SPI_NOR_OCTAL_READ BIT(15) /* Flash supports Octal Read */ +#define SPI_NOR_TB_SR_BIT6 BIT(16) /* + * Top/Bottom (TB) is bit 6 of + * status register. Must be used with + * SPI_NOR_HAS_TB. + */ /* Part specific fixup hooks. */ const struct spi_nor_fixups *fixups; - - int (*quad_enable)(struct spi_nor *nor); }; #define JEDEC_MFR(info) ((info)->id[0]) -/* - * Read the status register, returning its value in the location - * Return the status register value. - * Returns negative if error occurred. +/** + * spi_nor_spimem_xfer_data() - helper function to read/write data to + * flash's memory region + * @nor: pointer to 'struct spi_nor' + * @op: pointer to 'struct spi_mem_op' template for transfer + * + * Return: number of bytes transferred on success, -errno otherwise */ -static int read_sr(struct spi_nor *nor) +static ssize_t spi_nor_spimem_xfer_data(struct spi_nor *nor, + struct spi_mem_op *op) { + bool usebouncebuf = false; + void *rdbuf = NULL; + const void *buf; int ret; - u8 val; - ret = nor->read_reg(nor, SPINOR_OP_RDSR, &val, 1); - if (ret < 0) { - pr_err("error %d reading SR\n", (int) ret); - return ret; + if (op->data.dir == SPI_MEM_DATA_IN) + buf = op->data.buf.in; + else + buf = op->data.buf.out; + + if (object_is_on_stack(buf) || !virt_addr_valid(buf)) + usebouncebuf = true; + + if (usebouncebuf) { + if (op->data.nbytes > nor->bouncebuf_size) + op->data.nbytes = nor->bouncebuf_size; + + if (op->data.dir == SPI_MEM_DATA_IN) { + rdbuf = op->data.buf.in; + op->data.buf.in = nor->bouncebuf; + } else { + op->data.buf.out = nor->bouncebuf; + memcpy(nor->bouncebuf, buf, + op->data.nbytes); + } } - return val; + ret = spi_mem_adjust_op_size(nor->spimem, op); + if (ret) + return ret; + + ret = spi_mem_exec_op(nor->spimem, op); + if (ret) + return ret; + + if (usebouncebuf && op->data.dir == SPI_MEM_DATA_IN) + memcpy(rdbuf, nor->bouncebuf, op->data.nbytes); + + return op->data.nbytes; } -/* - * Read the flag status register, returning its value in the location - * Return the status register value. - * Returns negative if error occurred. +/** + * spi_nor_spimem_read_data() - read data from flash's memory region via + * spi-mem + * @nor: pointer to 'struct spi_nor' + * @from: offset to read from + * @len: number of bytes to read + * @buf: pointer to dst buffer + * + * Return: number of bytes read successfully, -errno otherwise */ -static int read_fsr(struct spi_nor *nor) +static ssize_t spi_nor_spimem_read_data(struct spi_nor *nor, loff_t from, + size_t len, u8 *buf) { - int ret; - u8 val; + struct spi_mem_op op = + SPI_MEM_OP(SPI_MEM_OP_CMD(nor->read_opcode, 1), + SPI_MEM_OP_ADDR(nor->addr_width, from, 1), + SPI_MEM_OP_DUMMY(nor->read_dummy, 1), + SPI_MEM_OP_DATA_IN(len, buf, 1)); + + /* get transfer protocols. */ + op.cmd.buswidth = spi_nor_get_protocol_inst_nbits(nor->read_proto); + op.addr.buswidth = spi_nor_get_protocol_addr_nbits(nor->read_proto); + op.dummy.buswidth = op.addr.buswidth; + op.data.buswidth = spi_nor_get_protocol_data_nbits(nor->read_proto); + + /* convert the dummy cycles to the number of bytes */ + op.dummy.nbytes = (nor->read_dummy * op.dummy.buswidth) / 8; + + return spi_nor_spimem_xfer_data(nor, &op); +} - ret = nor->read_reg(nor, SPINOR_OP_RDFSR, &val, 1); - if (ret < 0) { - pr_err("error %d reading FSR\n", ret); - return ret; - } +/** + * spi_nor_read_data() - read data from flash memory + * @nor: pointer to 'struct spi_nor' + * @from: offset to read from + * @len: number of bytes to read + * @buf: pointer to dst buffer + * + * Return: number of bytes read successfully, -errno otherwise + */ +static ssize_t spi_nor_read_data(struct spi_nor *nor, loff_t from, size_t len, + u8 *buf) +{ + if (nor->spimem) + return spi_nor_spimem_read_data(nor, from, len, buf); - return val; + return nor->controller_ops->read(nor, from, len, buf); } -/* - * Read configuration register, returning its value in the - * location. Return the configuration register value. - * Returns negative if error occurred. +/** + * spi_nor_spimem_write_data() - write data to flash memory via + * spi-mem + * @nor: pointer to 'struct spi_nor' + * @to: offset to write to + * @len: number of bytes to write + * @buf: pointer to src buffer + * + * Return: number of bytes written successfully, -errno otherwise */ -static int read_cr(struct spi_nor *nor) +static ssize_t spi_nor_spimem_write_data(struct spi_nor *nor, loff_t to, + size_t len, const u8 *buf) { - int ret; - u8 val; + struct spi_mem_op op = + SPI_MEM_OP(SPI_MEM_OP_CMD(nor->program_opcode, 1), + SPI_MEM_OP_ADDR(nor->addr_width, to, 1), + SPI_MEM_OP_NO_DUMMY, + SPI_MEM_OP_DATA_OUT(len, buf, 1)); - ret = nor->read_reg(nor, SPINOR_OP_RDCR, &val, 1); - if (ret < 0) { - dev_err(nor->dev, "error %d reading CR\n", ret); - return ret; - } + op.cmd.buswidth = spi_nor_get_protocol_inst_nbits(nor->write_proto); + op.addr.buswidth = spi_nor_get_protocol_addr_nbits(nor->write_proto); + op.data.buswidth = spi_nor_get_protocol_data_nbits(nor->write_proto); + + if (nor->program_opcode == SPINOR_OP_AAI_WP && nor->sst_write_second) + op.addr.nbytes = 0; - return val; + return spi_nor_spimem_xfer_data(nor, &op); } -/* - * Write status register 1 byte - * Returns negative if error occurred. +/** + * spi_nor_write_data() - write data to flash memory + * @nor: pointer to 'struct spi_nor' + * @to: offset to write to + * @len: number of bytes to write + * @buf: pointer to src buffer + * + * Return: number of bytes written successfully, -errno otherwise */ -static int write_sr(struct spi_nor *nor, u8 val) +static ssize_t spi_nor_write_data(struct spi_nor *nor, loff_t to, size_t len, + const u8 *buf) { - nor->cmd_buf[0] = val; - return nor->write_reg(nor, SPINOR_OP_WRSR, nor->cmd_buf, 1); + if (nor->spimem) + return spi_nor_spimem_write_data(nor, to, len, buf); + + return nor->controller_ops->write(nor, to, len, buf); } -/* - * Set write enable latch with Write Enable command. - * Returns negative if error occurred. +/** + * spi_nor_write_enable() - Set write enable latch with Write Enable command. + * @nor: pointer to 'struct spi_nor'. + * + * Return: 0 on success, -errno otherwise. */ -static int write_enable(struct spi_nor *nor) +static int spi_nor_write_enable(struct spi_nor *nor) { - return nor->write_reg(nor, SPINOR_OP_WREN, NULL, 0); + int ret; + + if (nor->spimem) { + struct spi_mem_op op = + SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WREN, 1), + SPI_MEM_OP_NO_ADDR, + SPI_MEM_OP_NO_DUMMY, + SPI_MEM_OP_NO_DATA); + + ret = spi_mem_exec_op(nor->spimem, &op); + } else { + ret = nor->controller_ops->write_reg(nor, SPINOR_OP_WREN, + NULL, 0); + } + + if (ret) + dev_dbg(nor->dev, "error %d on Write Enable\n", ret); + + return ret; } -/* - * Send write disable instruction to the chip. +/** + * spi_nor_write_disable() - Send Write Disable instruction to the chip. + * @nor: pointer to 'struct spi_nor'. + * + * Return: 0 on success, -errno otherwise. */ -static int write_disable(struct spi_nor *nor) +static int spi_nor_write_disable(struct spi_nor *nor) { - return nor->write_reg(nor, SPINOR_OP_WRDI, NULL, 0); + int ret; + + if (nor->spimem) { + struct spi_mem_op op = + SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WRDI, 1), + SPI_MEM_OP_NO_ADDR, + SPI_MEM_OP_NO_DUMMY, + SPI_MEM_OP_NO_DATA); + + ret = spi_mem_exec_op(nor->spimem, &op); + } else { + ret = nor->controller_ops->write_reg(nor, SPINOR_OP_WRDI, + NULL, 0); + } + + if (ret) + dev_dbg(nor->dev, "error %d on Write Disable\n", ret); + + return ret; } -static struct spi_nor *mtd_to_spi_nor(struct mtd_info *mtd) +/** + * spi_nor_read_sr() - Read the Status Register. + * @nor: pointer to 'struct spi_nor'. + * @sr: pointer to a DMA-able buffer where the value of the + * Status Register will be written. + * + * Return: 0 on success, -errno otherwise. + */ +static int spi_nor_read_sr(struct spi_nor *nor, u8 *sr) { - return mtd->priv; -} + int ret; + if (nor->spimem) { + struct spi_mem_op op = + SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_RDSR, 1), + SPI_MEM_OP_NO_ADDR, + SPI_MEM_OP_NO_DUMMY, + SPI_MEM_OP_DATA_IN(1, sr, 1)); -static u8 spi_nor_convert_opcode(u8 opcode, const u8 table[][2], size_t size) + ret = spi_mem_exec_op(nor->spimem, &op); + } else { + ret = nor->controller_ops->read_reg(nor, SPINOR_OP_RDSR, + sr, 1); + } + + if (ret) + dev_dbg(nor->dev, "error %d reading SR\n", ret); + + return ret; +} + +/** + * spi_nor_read_fsr() - Read the Flag Status Register. + * @nor: pointer to 'struct spi_nor' + * @fsr: pointer to a DMA-able buffer where the value of the + * Flag Status Register will be written. + * + * Return: 0 on success, -errno otherwise. + */ +static int spi_nor_read_fsr(struct spi_nor *nor, u8 *fsr) { - size_t i; + int ret; - for (i = 0; i < size; i++) - if (table[i][0] == opcode) - return table[i][1]; + if (nor->spimem) { + struct spi_mem_op op = + SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_RDFSR, 1), + SPI_MEM_OP_NO_ADDR, + SPI_MEM_OP_NO_DUMMY, + SPI_MEM_OP_DATA_IN(1, fsr, 1)); - /* No conversion found, keep input op code. */ - return opcode; + ret = spi_mem_exec_op(nor->spimem, &op); + } else { + ret = nor->controller_ops->read_reg(nor, SPINOR_OP_RDFSR, + fsr, 1); + } + + if (ret) + dev_dbg(nor->dev, "error %d reading FSR\n", ret); + + return ret; } -static u8 spi_nor_convert_3to4_read(u8 opcode) +/** + * spi_nor_read_cr() - Read the Configuration Register using the + * SPINOR_OP_RDCR (35h) command. + * @nor: pointer to 'struct spi_nor' + * @cr: pointer to a DMA-able buffer where the value of the + * Configuration Register will be written. + * + * Return: 0 on success, -errno otherwise. + */ +static int spi_nor_read_cr(struct spi_nor *nor, u8 *cr) { - static const u8 spi_nor_3to4_read[][2] = { - { SPINOR_OP_READ, SPINOR_OP_READ_4B }, - { SPINOR_OP_READ_FAST, SPINOR_OP_READ_FAST_4B }, - { SPINOR_OP_READ_1_1_2, SPINOR_OP_READ_1_1_2_4B }, - { SPINOR_OP_READ_1_2_2, SPINOR_OP_READ_1_2_2_4B }, - { SPINOR_OP_READ_1_1_4, SPINOR_OP_READ_1_1_4_4B }, - { SPINOR_OP_READ_1_4_4, SPINOR_OP_READ_1_4_4_4B }, - { SPINOR_OP_READ_1_1_8, SPINOR_OP_READ_1_1_8_4B }, - { SPINOR_OP_READ_1_8_8, SPINOR_OP_READ_1_8_8_4B }, + int ret; - { SPINOR_OP_READ_1_1_1_DTR, SPINOR_OP_READ_1_1_1_DTR_4B }, - { SPINOR_OP_READ_1_2_2_DTR, SPINOR_OP_READ_1_2_2_DTR_4B }, - { SPINOR_OP_READ_1_4_4_DTR, SPINOR_OP_READ_1_4_4_DTR_4B }, - }; + if (nor->spimem) { + struct spi_mem_op op = + SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_RDCR, 1), + SPI_MEM_OP_NO_ADDR, + SPI_MEM_OP_NO_DUMMY, + SPI_MEM_OP_DATA_IN(1, cr, 1)); - return spi_nor_convert_opcode(opcode, spi_nor_3to4_read, - ARRAY_SIZE(spi_nor_3to4_read)); + ret = spi_mem_exec_op(nor->spimem, &op); + } else { + ret = nor->controller_ops->read_reg(nor, SPINOR_OP_RDCR, cr, 1); + } + + if (ret) + dev_dbg(nor->dev, "error %d reading CR\n", ret); + + return ret; } -static u8 spi_nor_convert_3to4_program(u8 opcode) +/** + * macronix_set_4byte() - Set 4-byte address mode for Macronix flashes. + * @nor: pointer to 'struct spi_nor'. + * @enable: true to enter the 4-byte address mode, false to exit the 4-byte + * address mode. + * + * Return: 0 on success, -errno otherwise. + */ +static int macronix_set_4byte(struct spi_nor *nor, bool enable) { - static const u8 spi_nor_3to4_program[][2] = { - { SPINOR_OP_PP, SPINOR_OP_PP_4B }, - { SPINOR_OP_PP_1_1_4, SPINOR_OP_PP_1_1_4_4B }, - { SPINOR_OP_PP_1_4_4, SPINOR_OP_PP_1_4_4_4B }, - { SPINOR_OP_PP_1_1_8, SPINOR_OP_PP_1_1_8_4B }, - { SPINOR_OP_PP_1_8_8, SPINOR_OP_PP_1_8_8_4B }, - }; + int ret; - return spi_nor_convert_opcode(opcode, spi_nor_3to4_program, - ARRAY_SIZE(spi_nor_3to4_program)); + if (nor->spimem) { + struct spi_mem_op op = + SPI_MEM_OP(SPI_MEM_OP_CMD(enable ? + SPINOR_OP_EN4B : + SPINOR_OP_EX4B, + 1), + SPI_MEM_OP_NO_ADDR, + SPI_MEM_OP_NO_DUMMY, + SPI_MEM_OP_NO_DATA); + + ret = spi_mem_exec_op(nor->spimem, &op); + } else { + ret = nor->controller_ops->write_reg(nor, + enable ? SPINOR_OP_EN4B : + SPINOR_OP_EX4B, + NULL, 0); + } + + if (ret) + dev_dbg(nor->dev, "error %d setting 4-byte mode\n", ret); + + return ret; } -static u8 spi_nor_convert_3to4_erase(u8 opcode) +/** + * st_micron_set_4byte() - Set 4-byte address mode for ST and Micron flashes. + * @nor: pointer to 'struct spi_nor'. + * @enable: true to enter the 4-byte address mode, false to exit the 4-byte + * address mode. + * + * Return: 0 on success, -errno otherwise. + */ +static int st_micron_set_4byte(struct spi_nor *nor, bool enable) { - static const u8 spi_nor_3to4_erase[][2] = { - { SPINOR_OP_BE_4K, SPINOR_OP_BE_4K_4B }, - { SPINOR_OP_BE_32K, SPINOR_OP_BE_32K_4B }, - { SPINOR_OP_SE, SPINOR_OP_SE_4B }, - }; + int ret; - return spi_nor_convert_opcode(opcode, spi_nor_3to4_erase, - ARRAY_SIZE(spi_nor_3to4_erase)); + ret = spi_nor_write_enable(nor); + if (ret) + return ret; + + ret = macronix_set_4byte(nor, enable); + if (ret) + return ret; + + return spi_nor_write_disable(nor); } -static void spi_nor_set_4byte_opcodes(struct spi_nor *nor) +/** + * spansion_set_4byte() - Set 4-byte address mode for Spansion flashes. + * @nor: pointer to 'struct spi_nor'. + * @enable: true to enter the 4-byte address mode, false to exit the 4-byte + * address mode. + * + * Return: 0 on success, -errno otherwise. + */ +static int spansion_set_4byte(struct spi_nor *nor, bool enable) { - /* Do some manufacturer fixups first */ - switch (JEDEC_MFR(nor->info)) { - case SNOR_MFR_SPANSION: - /* No small sector erase for 4-byte command set */ - nor->erase_opcode = SPINOR_OP_SE; - nor->mtd.erasesize = nor->info->sector_size; - break; + int ret; - default: - break; + nor->bouncebuf[0] = enable << 7; + + if (nor->spimem) { + struct spi_mem_op op = + SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_BRWR, 1), + SPI_MEM_OP_NO_ADDR, + SPI_MEM_OP_NO_DUMMY, + SPI_MEM_OP_DATA_OUT(1, nor->bouncebuf, 1)); + + ret = spi_mem_exec_op(nor->spimem, &op); + } else { + ret = nor->controller_ops->write_reg(nor, SPINOR_OP_BRWR, + nor->bouncebuf, 1); } - nor->read_opcode = spi_nor_convert_3to4_read(nor->read_opcode); - nor->program_opcode = spi_nor_convert_3to4_program(nor->program_opcode); - nor->erase_opcode = spi_nor_convert_3to4_erase(nor->erase_opcode); + if (ret) + dev_dbg(nor->dev, "error %d setting 4-byte mode\n", ret); - if (!spi_nor_has_uniform_erase(nor)) { - struct spi_nor_erase_map *map = &nor->erase_map; - struct spi_nor_erase_type *erase; - int i; + return ret; +} - for (i = 0; i < SNOR_ERASE_TYPE_MAX; i++) { - erase = &map->erase_type[i]; - erase->opcode = - spi_nor_convert_3to4_erase(erase->opcode); - } +/** + * spi_nor_write_ear() - Write Extended Address Register. + * @nor: pointer to 'struct spi_nor'. + * @ear: value to write to the Extended Address Register. + * + * Return: 0 on success, -errno otherwise. + */ +static int spi_nor_write_ear(struct spi_nor *nor, u8 ear) +{ + int ret; + + nor->bouncebuf[0] = ear; + + if (nor->spimem) { + struct spi_mem_op op = + SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WREAR, 1), + SPI_MEM_OP_NO_ADDR, + SPI_MEM_OP_NO_DUMMY, + SPI_MEM_OP_DATA_OUT(1, nor->bouncebuf, 1)); + + ret = spi_mem_exec_op(nor->spimem, &op); + } else { + ret = nor->controller_ops->write_reg(nor, SPINOR_OP_WREAR, + nor->bouncebuf, 1); } + + if (ret) + dev_dbg(nor->dev, "error %d writing EAR\n", ret); + + return ret; } -/* Enable/disable 4-byte addressing mode. */ -static int set_4byte(struct spi_nor *nor, bool enable) +/** + * winbond_set_4byte() - Set 4-byte address mode for Winbond flashes. + * @nor: pointer to 'struct spi_nor'. + * @enable: true to enter the 4-byte address mode, false to exit the 4-byte + * address mode. + * + * Return: 0 on success, -errno otherwise. + */ +static int winbond_set_4byte(struct spi_nor *nor, bool enable) { - int status; - bool need_wren = false; - u8 cmd; + int ret; - switch (JEDEC_MFR(nor->info)) { - case SNOR_MFR_ST: - case SNOR_MFR_MICRON: - /* Some Micron need WREN command; all will accept it */ - need_wren = true; - /* fall through */ - case SNOR_MFR_MACRONIX: - case SNOR_MFR_WINBOND: - if (need_wren) - write_enable(nor); + ret = macronix_set_4byte(nor, enable); + if (ret || enable) + return ret; - cmd = enable ? SPINOR_OP_EN4B : SPINOR_OP_EX4B; - status = nor->write_reg(nor, cmd, NULL, 0); - if (need_wren) - write_disable(nor); + /* + * On Winbond W25Q256FV, leaving 4byte mode causes the Extended Address + * Register to be set to 1, so all 3-byte-address reads come from the + * second 16M. We must clear the register to enable normal behavior. + */ + ret = spi_nor_write_enable(nor); + if (ret) + return ret; - if (!status && !enable && - JEDEC_MFR(nor->info) == SNOR_MFR_WINBOND) { - /* - * On Winbond W25Q256FV, leaving 4byte mode causes - * the Extended Address Register to be set to 1, so all - * 3-byte-address reads come from the second 16M. - * We must clear the register to enable normal behavior. - */ - write_enable(nor); - nor->cmd_buf[0] = 0; - nor->write_reg(nor, SPINOR_OP_WREAR, nor->cmd_buf, 1); - write_disable(nor); - } + ret = spi_nor_write_ear(nor, 0); + if (ret) + return ret; - return status; - default: - /* Spansion style */ - nor->cmd_buf[0] = enable << 7; - return nor->write_reg(nor, SPINOR_OP_BRWR, nor->cmd_buf, 1); + return spi_nor_write_disable(nor); +} + +/** + * spi_nor_xread_sr() - Read the Status Register on S3AN flashes. + * @nor: pointer to 'struct spi_nor'. + * @sr: pointer to a DMA-able buffer where the value of the + * Status Register will be written. + * + * Return: 0 on success, -errno otherwise. + */ +static int spi_nor_xread_sr(struct spi_nor *nor, u8 *sr) +{ + int ret; + + if (nor->spimem) { + struct spi_mem_op op = + SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_XRDSR, 1), + SPI_MEM_OP_NO_ADDR, + SPI_MEM_OP_NO_DUMMY, + SPI_MEM_OP_DATA_IN(1, sr, 1)); + + ret = spi_mem_exec_op(nor->spimem, &op); + } else { + ret = nor->controller_ops->read_reg(nor, SPINOR_OP_XRDSR, + sr, 1); } + + if (ret) + dev_dbg(nor->dev, "error %d reading XRDSR\n", ret); + + return ret; } +/** + * s3an_sr_ready() - Query the Status Register of the S3AN flash to see if the + * flash is ready for new commands. + * @nor: pointer to 'struct spi_nor'. + * + * Return: 0 on success, -errno otherwise. + */ static int s3an_sr_ready(struct spi_nor *nor) { int ret; - u8 val; - ret = nor->read_reg(nor, SPINOR_OP_XRDSR, &val, 1); - if (ret < 0) { - dev_err(nor->dev, "error %d reading XRDSR\n", (int) ret); + ret = spi_nor_xread_sr(nor, nor->bouncebuf); + if (ret) return ret; + + return !!(nor->bouncebuf[0] & XSR_RDY); +} + +/** + * spi_nor_clear_sr() - Clear the Status Register. + * @nor: pointer to 'struct spi_nor'. + */ +static void spi_nor_clear_sr(struct spi_nor *nor) +{ + int ret; + + if (nor->spimem) { + struct spi_mem_op op = + SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_CLSR, 1), + SPI_MEM_OP_NO_ADDR, + SPI_MEM_OP_NO_DUMMY, + SPI_MEM_OP_NO_DATA); + + ret = spi_mem_exec_op(nor->spimem, &op); + } else { + ret = nor->controller_ops->write_reg(nor, SPINOR_OP_CLSR, + NULL, 0); } - return !!(val & XSR_RDY); + if (ret) + dev_dbg(nor->dev, "error %d clearing SR\n", ret); } +/** + * spi_nor_sr_ready() - Query the Status Register to see if the flash is ready + * for new commands. + * @nor: pointer to 'struct spi_nor'. + * + * Return: 0 on success, -errno otherwise. + */ static int spi_nor_sr_ready(struct spi_nor *nor) { - int sr = read_sr(nor); - if (sr < 0) - return sr; + int ret = spi_nor_read_sr(nor, nor->bouncebuf); - if (nor->flags & SNOR_F_USE_CLSR && sr & (SR_E_ERR | SR_P_ERR)) { - if (sr & SR_E_ERR) + if (ret) + return ret; + + if (nor->flags & SNOR_F_USE_CLSR && + nor->bouncebuf[0] & (SR_E_ERR | SR_P_ERR)) { + if (nor->bouncebuf[0] & SR_E_ERR) dev_err(nor->dev, "Erase Error occurred\n"); else dev_err(nor->dev, "Programming Error occurred\n"); - nor->write_reg(nor, SPINOR_OP_CLSR, NULL, 0); + spi_nor_clear_sr(nor); return -EIO; } - return !(sr & SR_WIP); + return !(nor->bouncebuf[0] & SR_WIP); } +/** + * spi_nor_clear_fsr() - Clear the Flag Status Register. + * @nor: pointer to 'struct spi_nor'. + */ +static void spi_nor_clear_fsr(struct spi_nor *nor) +{ + int ret; + + if (nor->spimem) { + struct spi_mem_op op = + SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_CLFSR, 1), + SPI_MEM_OP_NO_ADDR, + SPI_MEM_OP_NO_DUMMY, + SPI_MEM_OP_NO_DATA); + + ret = spi_mem_exec_op(nor->spimem, &op); + } else { + ret = nor->controller_ops->write_reg(nor, SPINOR_OP_CLFSR, + NULL, 0); + } + + if (ret) + dev_dbg(nor->dev, "error %d clearing FSR\n", ret); +} + +/** + * spi_nor_fsr_ready() - Query the Flag Status Register to see if the flash is + * ready for new commands. + * @nor: pointer to 'struct spi_nor'. + * + * Return: 0 on success, -errno otherwise. + */ static int spi_nor_fsr_ready(struct spi_nor *nor) { - int fsr = read_fsr(nor); - if (fsr < 0) - return fsr; + int ret = spi_nor_read_fsr(nor, nor->bouncebuf); - if (fsr & (FSR_E_ERR | FSR_P_ERR)) { - if (fsr & FSR_E_ERR) + if (ret) + return ret; + + if (nor->bouncebuf[0] & (FSR_E_ERR | FSR_P_ERR)) { + if (nor->bouncebuf[0] & FSR_E_ERR) dev_err(nor->dev, "Erase operation failed.\n"); else dev_err(nor->dev, "Program operation failed.\n"); - if (fsr & FSR_PT_ERR) + if (nor->bouncebuf[0] & FSR_PT_ERR) dev_err(nor->dev, "Attempted to modify a protected sector.\n"); - nor->write_reg(nor, SPINOR_OP_CLFSR, NULL, 0); + spi_nor_clear_fsr(nor); return -EIO; } - return fsr & FSR_READY; + return nor->bouncebuf[0] & FSR_READY; } +/** + * spi_nor_ready() - Query the flash to see if it is ready for new commands. + * @nor: pointer to 'struct spi_nor'. + * + * Return: 0 on success, -errno otherwise. + */ static int spi_nor_ready(struct spi_nor *nor) { int sr, fsr; @@ -585,9 +880,13 @@ static int spi_nor_ready(struct spi_nor *nor) return sr && fsr; } -/* - * Service routine to read status register until ready, or timeout occurs. - * Returns non-zero if error. +/** + * spi_nor_wait_till_ready_with_timeout() - Service routine to read the + * Status Register until ready, or timeout occurs. + * @nor: pointer to "struct spi_nor". + * @timeout_jiffies: jiffies to wait until timeout. + * + * Return: 0 on success, -errno otherwise. */ static int spi_nor_wait_till_ready_with_timeout(struct spi_nor *nor, unsigned long timeout_jiffies) @@ -610,39 +909,418 @@ static int spi_nor_wait_till_ready_with_timeout(struct spi_nor *nor, cond_resched(); } - dev_err(nor->dev, "flash operation timed out\n"); + dev_dbg(nor->dev, "flash operation timed out\n"); return -ETIMEDOUT; } +/** + * spi_nor_wait_till_ready() - Wait for a predefined amount of time for the + * flash to be ready, or timeout occurs. + * @nor: pointer to "struct spi_nor". + * + * Return: 0 on success, -errno otherwise. + */ static int spi_nor_wait_till_ready(struct spi_nor *nor) { return spi_nor_wait_till_ready_with_timeout(nor, DEFAULT_READY_WAIT_JIFFIES); } -/* - * Erase the whole flash memory +/** + * spi_nor_write_sr() - Write the Status Register. + * @nor: pointer to 'struct spi_nor'. + * @sr: pointer to DMA-able buffer to write to the Status Register. + * @len: number of bytes to write to the Status Register. + * + * Return: 0 on success, -errno otherwise. + */ +static int spi_nor_write_sr(struct spi_nor *nor, const u8 *sr, size_t len) +{ + int ret; + + ret = spi_nor_write_enable(nor); + if (ret) + return ret; + + if (nor->spimem) { + struct spi_mem_op op = + SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WRSR, 1), + SPI_MEM_OP_NO_ADDR, + SPI_MEM_OP_NO_DUMMY, + SPI_MEM_OP_DATA_OUT(len, sr, 1)); + + ret = spi_mem_exec_op(nor->spimem, &op); + } else { + ret = nor->controller_ops->write_reg(nor, SPINOR_OP_WRSR, + sr, len); + } + + if (ret) { + dev_dbg(nor->dev, "error %d writing SR\n", ret); + return ret; + } + + return spi_nor_wait_till_ready(nor); +} + +/** + * spi_nor_write_sr1_and_check() - Write one byte to the Status Register 1 and + * ensure that the byte written match the received value. + * @nor: pointer to a 'struct spi_nor'. + * @sr1: byte value to be written to the Status Register. + * + * Return: 0 on success, -errno otherwise. + */ +static int spi_nor_write_sr1_and_check(struct spi_nor *nor, u8 sr1) +{ + int ret; + + nor->bouncebuf[0] = sr1; + + ret = spi_nor_write_sr(nor, nor->bouncebuf, 1); + if (ret) + return ret; + + ret = spi_nor_read_sr(nor, nor->bouncebuf); + if (ret) + return ret; + + if (nor->bouncebuf[0] != sr1) { + dev_dbg(nor->dev, "SR1: read back test failed\n"); + return -EIO; + } + + return 0; +} + +/** + * spi_nor_write_16bit_sr_and_check() - Write the Status Register 1 and the + * Status Register 2 in one shot. Ensure that the byte written in the Status + * Register 1 match the received value, and that the 16-bit Write did not + * affect what was already in the Status Register 2. + * @nor: pointer to a 'struct spi_nor'. + * @sr1: byte value to be written to the Status Register 1. + * + * Return: 0 on success, -errno otherwise. + */ +static int spi_nor_write_16bit_sr_and_check(struct spi_nor *nor, u8 sr1) +{ + int ret; + u8 *sr_cr = nor->bouncebuf; + u8 cr_written; + + /* Make sure we don't overwrite the contents of Status Register 2. */ + if (!(nor->flags & SNOR_F_NO_READ_CR)) { + ret = spi_nor_read_cr(nor, &sr_cr[1]); + if (ret) + return ret; + } else if (nor->params.quad_enable) { + /* + * If the Status Register 2 Read command (35h) is not + * supported, we should at least be sure we don't + * change the value of the SR2 Quad Enable bit. + * + * We can safely assume that when the Quad Enable method is + * set, the value of the QE bit is one, as a consequence of the + * nor->params.quad_enable() call. + * + * We can safely assume that the Quad Enable bit is present in + * the Status Register 2 at BIT(1). According to the JESD216 + * revB standard, BFPT DWORDS[15], bits 22:20, the 16-bit + * Write Status (01h) command is available just for the cases + * in which the QE bit is described in SR2 at BIT(1). + */ + sr_cr[1] = SR2_QUAD_EN_BIT1; + } else { + sr_cr[1] = 0; + } + + sr_cr[0] = sr1; + + ret = spi_nor_write_sr(nor, sr_cr, 2); + if (ret) + return ret; + + if (nor->flags & SNOR_F_NO_READ_CR) + return 0; + + cr_written = sr_cr[1]; + + ret = spi_nor_read_cr(nor, &sr_cr[1]); + if (ret) + return ret; + + if (cr_written != sr_cr[1]) { + dev_dbg(nor->dev, "CR: read back test failed\n"); + return -EIO; + } + + return 0; +} + +/** + * spi_nor_write_16bit_cr_and_check() - Write the Status Register 1 and the + * Configuration Register in one shot. Ensure that the byte written in the + * Configuration Register match the received value, and that the 16-bit Write + * did not affect what was already in the Status Register 1. + * @nor: pointer to a 'struct spi_nor'. + * @cr: byte value to be written to the Configuration Register. * - * Returns 0 if successful, non-zero otherwise. + * Return: 0 on success, -errno otherwise. */ -static int erase_chip(struct spi_nor *nor) +static int spi_nor_write_16bit_cr_and_check(struct spi_nor *nor, u8 cr) { + int ret; + u8 *sr_cr = nor->bouncebuf; + u8 sr_written; + + /* Keep the current value of the Status Register 1. */ + ret = spi_nor_read_sr(nor, sr_cr); + if (ret) + return ret; + + sr_cr[1] = cr; + + ret = spi_nor_write_sr(nor, sr_cr, 2); + if (ret) + return ret; + + sr_written = sr_cr[0]; + + ret = spi_nor_read_sr(nor, sr_cr); + if (ret) + return ret; + + if (sr_written != sr_cr[0]) { + dev_dbg(nor->dev, "SR: Read back test failed\n"); + return -EIO; + } + + if (nor->flags & SNOR_F_NO_READ_CR) + return 0; + + ret = spi_nor_read_cr(nor, &sr_cr[1]); + if (ret) + return ret; + + if (cr != sr_cr[1]) { + dev_dbg(nor->dev, "CR: read back test failed\n"); + return -EIO; + } + + return 0; +} + +/** + * spi_nor_write_sr_and_check() - Write the Status Register 1 and ensure that + * the byte written match the received value without affecting other bits in the + * Status Register 1 and 2. + * @nor: pointer to a 'struct spi_nor'. + * @sr1: byte value to be written to the Status Register. + * + * Return: 0 on success, -errno otherwise. + */ +static int spi_nor_write_sr_and_check(struct spi_nor *nor, u8 sr1) +{ + if (nor->flags & SNOR_F_HAS_16BIT_SR) + return spi_nor_write_16bit_sr_and_check(nor, sr1); + + return spi_nor_write_sr1_and_check(nor, sr1); +} + +/** + * spi_nor_write_sr2() - Write the Status Register 2 using the + * SPINOR_OP_WRSR2 (3eh) command. + * @nor: pointer to 'struct spi_nor'. + * @sr2: pointer to DMA-able buffer to write to the Status Register 2. + * + * Return: 0 on success, -errno otherwise. + */ +static int spi_nor_write_sr2(struct spi_nor *nor, const u8 *sr2) +{ + int ret; + + ret = spi_nor_write_enable(nor); + if (ret) + return ret; + + if (nor->spimem) { + struct spi_mem_op op = + SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WRSR2, 1), + SPI_MEM_OP_NO_ADDR, + SPI_MEM_OP_NO_DUMMY, + SPI_MEM_OP_DATA_OUT(1, sr2, 1)); + + ret = spi_mem_exec_op(nor->spimem, &op); + } else { + ret = nor->controller_ops->write_reg(nor, SPINOR_OP_WRSR2, + sr2, 1); + } + + if (ret) { + dev_dbg(nor->dev, "error %d writing SR2\n", ret); + return ret; + } + + return spi_nor_wait_till_ready(nor); +} + +/** + * spi_nor_read_sr2() - Read the Status Register 2 using the + * SPINOR_OP_RDSR2 (3fh) command. + * @nor: pointer to 'struct spi_nor'. + * @sr2: pointer to DMA-able buffer where the value of the + * Status Register 2 will be written. + * + * Return: 0 on success, -errno otherwise. + */ +static int spi_nor_read_sr2(struct spi_nor *nor, u8 *sr2) +{ + int ret; + + if (nor->spimem) { + struct spi_mem_op op = + SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_RDSR2, 1), + SPI_MEM_OP_NO_ADDR, + SPI_MEM_OP_NO_DUMMY, + SPI_MEM_OP_DATA_IN(1, sr2, 1)); + + ret = spi_mem_exec_op(nor->spimem, &op); + } else { + ret = nor->controller_ops->read_reg(nor, SPINOR_OP_RDSR2, + sr2, 1); + } + + if (ret) + dev_dbg(nor->dev, "error %d reading SR2\n", ret); + + return ret; +} + +/** + * spi_nor_erase_chip() - Erase the entire flash memory. + * @nor: pointer to 'struct spi_nor'. + * + * Return: 0 on success, -errno otherwise. + */ +static int spi_nor_erase_chip(struct spi_nor *nor) +{ + int ret; + dev_dbg(nor->dev, " %lldKiB\n", (long long)(nor->mtd.size >> 10)); - return nor->write_reg(nor, SPINOR_OP_CHIP_ERASE, NULL, 0); + if (nor->spimem) { + struct spi_mem_op op = + SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_CHIP_ERASE, 1), + SPI_MEM_OP_NO_ADDR, + SPI_MEM_OP_NO_DUMMY, + SPI_MEM_OP_NO_DATA); + + ret = spi_mem_exec_op(nor->spimem, &op); + } else { + ret = nor->controller_ops->write_reg(nor, SPINOR_OP_CHIP_ERASE, + NULL, 0); + } + + if (ret) + dev_dbg(nor->dev, "error %d erasing chip\n", ret); + + return ret; +} + +static struct spi_nor *mtd_to_spi_nor(struct mtd_info *mtd) +{ + return mtd->priv; +} + +static u8 spi_nor_convert_opcode(u8 opcode, const u8 table[][2], size_t size) +{ + size_t i; + + for (i = 0; i < size; i++) + if (table[i][0] == opcode) + return table[i][1]; + + /* No conversion found, keep input op code. */ + return opcode; +} + +static u8 spi_nor_convert_3to4_read(u8 opcode) +{ + static const u8 spi_nor_3to4_read[][2] = { + { SPINOR_OP_READ, SPINOR_OP_READ_4B }, + { SPINOR_OP_READ_FAST, SPINOR_OP_READ_FAST_4B }, + { SPINOR_OP_READ_1_1_2, SPINOR_OP_READ_1_1_2_4B }, + { SPINOR_OP_READ_1_2_2, SPINOR_OP_READ_1_2_2_4B }, + { SPINOR_OP_READ_1_1_4, SPINOR_OP_READ_1_1_4_4B }, + { SPINOR_OP_READ_1_4_4, SPINOR_OP_READ_1_4_4_4B }, + { SPINOR_OP_READ_1_1_8, SPINOR_OP_READ_1_1_8_4B }, + { SPINOR_OP_READ_1_8_8, SPINOR_OP_READ_1_8_8_4B }, + + { SPINOR_OP_READ_1_1_1_DTR, SPINOR_OP_READ_1_1_1_DTR_4B }, + { SPINOR_OP_READ_1_2_2_DTR, SPINOR_OP_READ_1_2_2_DTR_4B }, + { SPINOR_OP_READ_1_4_4_DTR, SPINOR_OP_READ_1_4_4_DTR_4B }, + }; + + return spi_nor_convert_opcode(opcode, spi_nor_3to4_read, + ARRAY_SIZE(spi_nor_3to4_read)); +} + +static u8 spi_nor_convert_3to4_program(u8 opcode) +{ + static const u8 spi_nor_3to4_program[][2] = { + { SPINOR_OP_PP, SPINOR_OP_PP_4B }, + { SPINOR_OP_PP_1_1_4, SPINOR_OP_PP_1_1_4_4B }, + { SPINOR_OP_PP_1_4_4, SPINOR_OP_PP_1_4_4_4B }, + { SPINOR_OP_PP_1_1_8, SPINOR_OP_PP_1_1_8_4B }, + { SPINOR_OP_PP_1_8_8, SPINOR_OP_PP_1_8_8_4B }, + }; + + return spi_nor_convert_opcode(opcode, spi_nor_3to4_program, + ARRAY_SIZE(spi_nor_3to4_program)); +} + +static u8 spi_nor_convert_3to4_erase(u8 opcode) +{ + static const u8 spi_nor_3to4_erase[][2] = { + { SPINOR_OP_BE_4K, SPINOR_OP_BE_4K_4B }, + { SPINOR_OP_BE_32K, SPINOR_OP_BE_32K_4B }, + { SPINOR_OP_SE, SPINOR_OP_SE_4B }, + }; + + return spi_nor_convert_opcode(opcode, spi_nor_3to4_erase, + ARRAY_SIZE(spi_nor_3to4_erase)); +} + +static void spi_nor_set_4byte_opcodes(struct spi_nor *nor) +{ + nor->read_opcode = spi_nor_convert_3to4_read(nor->read_opcode); + nor->program_opcode = spi_nor_convert_3to4_program(nor->program_opcode); + nor->erase_opcode = spi_nor_convert_3to4_erase(nor->erase_opcode); + + if (!spi_nor_has_uniform_erase(nor)) { + struct spi_nor_erase_map *map = &nor->params.erase_map; + struct spi_nor_erase_type *erase; + int i; + + for (i = 0; i < SNOR_ERASE_TYPE_MAX; i++) { + erase = &map->erase_type[i]; + erase->opcode = + spi_nor_convert_3to4_erase(erase->opcode); + } + } } -static int spi_nor_lock_and_prep(struct spi_nor *nor, enum spi_nor_ops ops) +static int spi_nor_lock_and_prep(struct spi_nor *nor) { int ret = 0; mutex_lock(&nor->lock); - if (nor->prepare) { - ret = nor->prepare(nor, ops); + if (nor->controller_ops && nor->controller_ops->prepare) { + ret = nor->controller_ops->prepare(nor); if (ret) { - dev_err(nor->dev, "failed in the preparation.\n"); mutex_unlock(&nor->lock); return ret; } @@ -650,10 +1328,10 @@ static int spi_nor_lock_and_prep(struct spi_nor *nor, enum spi_nor_ops ops) return ret; } -static void spi_nor_unlock_and_unprep(struct spi_nor *nor, enum spi_nor_ops ops) +static void spi_nor_unlock_and_unprep(struct spi_nor *nor) { - if (nor->unprepare) - nor->unprepare(nor, ops); + if (nor->controller_ops && nor->controller_ops->unprepare) + nor->controller_ops->unprepare(nor); mutex_unlock(&nor->lock); } @@ -666,10 +1344,9 @@ static void spi_nor_unlock_and_unprep(struct spi_nor *nor, enum spi_nor_ops ops) * Addr can safely be unsigned int, the biggest S3AN device is smaller than * 4 MiB. */ -static loff_t spi_nor_s3an_addr_convert(struct spi_nor *nor, unsigned int addr) +static u32 s3an_convert_addr(struct spi_nor *nor, u32 addr) { - unsigned int offset; - unsigned int page; + u32 offset, page; offset = addr % nor->page_size; page = addr / nor->page_size; @@ -678,30 +1355,46 @@ static loff_t spi_nor_s3an_addr_convert(struct spi_nor *nor, unsigned int addr) return page | offset; } +static u32 spi_nor_convert_addr(struct spi_nor *nor, loff_t addr) +{ + if (!nor->params.convert_addr) + return addr; + + return nor->params.convert_addr(nor, addr); +} + /* * Initiate the erasure of a single sector */ static int spi_nor_erase_sector(struct spi_nor *nor, u32 addr) { - u8 buf[SPI_NOR_MAX_ADDR_WIDTH]; int i; - if (nor->flags & SNOR_F_S3AN_ADDR_DEFAULT) - addr = spi_nor_s3an_addr_convert(nor, addr); + addr = spi_nor_convert_addr(nor, addr); + + if (nor->spimem) { + struct spi_mem_op op = + SPI_MEM_OP(SPI_MEM_OP_CMD(nor->erase_opcode, 1), + SPI_MEM_OP_ADDR(nor->addr_width, addr, 1), + SPI_MEM_OP_NO_DUMMY, + SPI_MEM_OP_NO_DATA); - if (nor->erase) - return nor->erase(nor, addr); + return spi_mem_exec_op(nor->spimem, &op); + } else if (nor->controller_ops->erase) { + return nor->controller_ops->erase(nor, addr); + } /* * Default implementation, if driver doesn't have a specialized HW * control */ for (i = nor->addr_width - 1; i >= 0; i--) { - buf[i] = addr & 0xff; + nor->bouncebuf[i] = addr & 0xff; addr >>= 8; } - return nor->write_reg(nor, nor->erase_opcode, buf, nor->addr_width); + return nor->controller_ops->write_reg(nor, nor->erase_opcode, + nor->bouncebuf, nor->addr_width); } /** @@ -876,7 +1569,7 @@ static int spi_nor_init_erase_cmd_list(struct spi_nor *nor, struct list_head *erase_list, u64 addr, u32 len) { - const struct spi_nor_erase_map *map = &nor->erase_map; + const struct spi_nor_erase_map *map = &nor->params.erase_map; const struct spi_nor_erase_type *erase, *prev_erase = NULL; struct spi_nor_erase_region *region; struct spi_nor_erase_command *cmd = NULL; @@ -951,7 +1644,9 @@ static int spi_nor_erase_multi_sectors(struct spi_nor *nor, u64 addr, u32 len) list_for_each_entry_safe(cmd, next, &erase_list, list) { nor->erase_opcode = cmd->opcode; while (cmd->count) { - write_enable(nor); + ret = spi_nor_write_enable(nor); + if (ret) + goto destroy_erase_cmd_list; ret = spi_nor_erase_sector(nor, addr); if (ret) @@ -998,7 +1693,7 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr) addr = instr->addr; len = instr->len; - ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_ERASE); + ret = spi_nor_lock_and_prep(nor); if (ret) return ret; @@ -1006,12 +1701,13 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr) if (len == mtd->size && !(nor->flags & SNOR_F_NO_OP_CHIP_ERASE)) { unsigned long timeout; - write_enable(nor); + ret = spi_nor_write_enable(nor); + if (ret) + goto erase_err; - if (erase_chip(nor)) { - ret = -EIO; + ret = spi_nor_erase_chip(nor); + if (ret) goto erase_err; - } /* * Scale the timeout linearly with the size of the flash, with @@ -1034,7 +1730,9 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr) /* "sector"-at-a-time erase */ } else if (spi_nor_has_uniform_erase(nor)) { while (len) { - write_enable(nor); + ret = spi_nor_write_enable(nor); + if (ret) + goto erase_err; ret = spi_nor_erase_sector(nor, addr); if (ret) @@ -1055,43 +1753,26 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr) goto erase_err; } - write_disable(nor); + ret = spi_nor_write_disable(nor); erase_err: - spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_ERASE); + spi_nor_unlock_and_unprep(nor); return ret; } -/* Write status register and ensure bits in mask match written values */ -static int write_sr_and_check(struct spi_nor *nor, u8 status_new, u8 mask) -{ - int ret; - - write_enable(nor); - ret = write_sr(nor, status_new); - if (ret) - return ret; - - ret = spi_nor_wait_till_ready(nor); - if (ret) - return ret; - - ret = read_sr(nor); - if (ret < 0) - return ret; - - return ((ret & mask) != (status_new & mask)) ? -EIO : 0; -} - static void stm_get_locked_range(struct spi_nor *nor, u8 sr, loff_t *ofs, uint64_t *len) { struct mtd_info *mtd = &nor->mtd; u8 mask = SR_BP2 | SR_BP1 | SR_BP0; + u8 tb_mask = SR_TB_BIT5; int shift = ffs(mask) - 1; int pow; + if (nor->flags & SNOR_F_HAS_SR_TB_BIT6) + tb_mask = SR_TB_BIT6; + if (!(sr & mask)) { /* No protection */ *ofs = 0; @@ -1099,7 +1780,7 @@ static void stm_get_locked_range(struct spi_nor *nor, u8 sr, loff_t *ofs, } else { pow = ((sr & mask) ^ mask) >> shift; *len = mtd->size >> pow; - if (nor->flags & SNOR_F_HAS_SR_TB && sr & SR_TB) + if (nor->flags & SNOR_F_HAS_SR_TB && sr & tb_mask) *ofs = 0; else *ofs = mtd->size - *len; @@ -1176,16 +1857,19 @@ static int stm_is_unlocked_sr(struct spi_nor *nor, loff_t ofs, uint64_t len, static int stm_lock(struct spi_nor *nor, loff_t ofs, uint64_t len) { struct mtd_info *mtd = &nor->mtd; - int status_old, status_new; + int ret, status_old, status_new; u8 mask = SR_BP2 | SR_BP1 | SR_BP0; + u8 tb_mask = SR_TB_BIT5; u8 shift = ffs(mask) - 1, pow, val; loff_t lock_len; bool can_be_top = true, can_be_bottom = nor->flags & SNOR_F_HAS_SR_TB; bool use_top; - status_old = read_sr(nor); - if (status_old < 0) - return status_old; + ret = spi_nor_read_sr(nor, nor->bouncebuf); + if (ret) + return ret; + + status_old = nor->bouncebuf[0]; /* If nothing in our range is unlocked, we don't need to do anything */ if (stm_is_locked_sr(nor, ofs, len, status_old)) @@ -1212,6 +1896,9 @@ static int stm_lock(struct spi_nor *nor, loff_t ofs, uint64_t len) else lock_len = ofs + len; + if (nor->flags & SNOR_F_HAS_SR_TB_BIT6) + tb_mask = SR_TB_BIT6; + /* * Need smallest pow such that: * @@ -1229,13 +1916,13 @@ static int stm_lock(struct spi_nor *nor, loff_t ofs, uint64_t len) if (!(val & mask)) return -EINVAL; - status_new = (status_old & ~mask & ~SR_TB) | val; + status_new = (status_old & ~mask & ~tb_mask) | val; /* Disallow further writes if WP pin is asserted */ status_new |= SR_SRWD; if (!use_top) - status_new |= SR_TB; + status_new |= tb_mask; /* Don't bother if they're the same */ if (status_new == status_old) @@ -1245,7 +1932,7 @@ static int stm_lock(struct spi_nor *nor, loff_t ofs, uint64_t len) if ((status_new & mask) < (status_old & mask)) return -EINVAL; - return write_sr_and_check(nor, status_new, mask); + return spi_nor_write_sr_and_check(nor, status_new); } /* @@ -1256,16 +1943,19 @@ static int stm_lock(struct spi_nor *nor, loff_t ofs, uint64_t len) static int stm_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len) { struct mtd_info *mtd = &nor->mtd; - int status_old, status_new; + int ret, status_old, status_new; u8 mask = SR_BP2 | SR_BP1 | SR_BP0; + u8 tb_mask = SR_TB_BIT5; u8 shift = ffs(mask) - 1, pow, val; loff_t lock_len; bool can_be_top = true, can_be_bottom = nor->flags & SNOR_F_HAS_SR_TB; bool use_top; - status_old = read_sr(nor); - if (status_old < 0) - return status_old; + ret = spi_nor_read_sr(nor, nor->bouncebuf); + if (ret) + return ret; + + status_old = nor->bouncebuf[0]; /* If nothing in our range is locked, we don't need to do anything */ if (stm_is_unlocked_sr(nor, ofs, len, status_old)) @@ -1292,6 +1982,8 @@ static int stm_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len) else lock_len = ofs; + if (nor->flags & SNOR_F_HAS_SR_TB_BIT6) + tb_mask = SR_TB_BIT6; /* * Need largest pow such that: * @@ -1311,14 +2003,14 @@ static int stm_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len) return -EINVAL; } - status_new = (status_old & ~mask & ~SR_TB) | val; + status_new = (status_old & ~mask & ~tb_mask) | val; /* Don't protect status register if we're fully unlocked */ if (lock_len == 0) status_new &= ~SR_SRWD; if (!use_top) - status_new |= SR_TB; + status_new |= tb_mask; /* Don't bother if they're the same */ if (status_new == status_old) @@ -1328,7 +2020,7 @@ static int stm_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len) if ((status_new & mask) > (status_old & mask)) return -EINVAL; - return write_sr_and_check(nor, status_new, mask); + return spi_nor_write_sr_and_check(nor, status_new); } /* @@ -1340,27 +2032,33 @@ static int stm_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len) */ static int stm_is_locked(struct spi_nor *nor, loff_t ofs, uint64_t len) { - int status; + int ret; - status = read_sr(nor); - if (status < 0) - return status; + ret = spi_nor_read_sr(nor, nor->bouncebuf); + if (ret) + return ret; - return stm_is_locked_sr(nor, ofs, len, status); + return stm_is_locked_sr(nor, ofs, len, nor->bouncebuf[0]); } +static const struct spi_nor_locking_ops stm_locking_ops = { + .lock = stm_lock, + .unlock = stm_unlock, + .is_locked = stm_is_locked, +}; + static int spi_nor_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) { struct spi_nor *nor = mtd_to_spi_nor(mtd); int ret; - ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_LOCK); + ret = spi_nor_lock_and_prep(nor); if (ret) return ret; - ret = nor->flash_lock(nor, ofs, len); + ret = nor->params.locking_ops->lock(nor, ofs, len); - spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_UNLOCK); + spi_nor_unlock_and_unprep(nor); return ret; } @@ -1369,13 +2067,13 @@ static int spi_nor_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) struct spi_nor *nor = mtd_to_spi_nor(mtd); int ret; - ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_UNLOCK); + ret = spi_nor_lock_and_prep(nor); if (ret) return ret; - ret = nor->flash_unlock(nor, ofs, len); + ret = nor->params.locking_ops->unlock(nor, ofs, len); - spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_LOCK); + spi_nor_unlock_and_unprep(nor); return ret; } @@ -1384,209 +2082,71 @@ static int spi_nor_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len) struct spi_nor *nor = mtd_to_spi_nor(mtd); int ret; - ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_UNLOCK); + ret = spi_nor_lock_and_prep(nor); if (ret) return ret; - ret = nor->flash_is_locked(nor, ofs, len); + ret = nor->params.locking_ops->is_locked(nor, ofs, len); - spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_LOCK); + spi_nor_unlock_and_unprep(nor); return ret; } -/* - * Write status Register and configuration register with 2 bytes - * The first byte will be written to the status register, while the - * second byte will be written to the configuration register. - * Return negative if error occurred. - */ -static int write_sr_cr(struct spi_nor *nor, u8 *sr_cr) -{ - int ret; - - write_enable(nor); - - ret = nor->write_reg(nor, SPINOR_OP_WRSR, sr_cr, 2); - if (ret < 0) { - dev_err(nor->dev, - "error while writing configuration register\n"); - return -EINVAL; - } - - ret = spi_nor_wait_till_ready(nor); - if (ret) { - dev_err(nor->dev, - "timeout while writing configuration register\n"); - return ret; - } - - return 0; -} - /** - * macronix_quad_enable() - set QE bit in Status Register. + * spi_nor_sr1_bit6_quad_enable() - Set the Quad Enable BIT(6) in the Status + * Register 1. * @nor: pointer to a 'struct spi_nor' * - * Set the Quad Enable (QE) bit in the Status Register. - * - * bit 6 of the Status Register is the QE bit for Macronix like QSPI memories. + * Bit 6 of the Status Register 1 is the QE bit for Macronix like QSPI memories. * * Return: 0 on success, -errno otherwise. */ -static int macronix_quad_enable(struct spi_nor *nor) +static int spi_nor_sr1_bit6_quad_enable(struct spi_nor *nor) { - int ret, val; - - val = read_sr(nor); - if (val < 0) - return val; - if (val & SR_QUAD_EN_MX) - return 0; - - write_enable(nor); - - write_sr(nor, val | SR_QUAD_EN_MX); - - ret = spi_nor_wait_till_ready(nor); - if (ret) - return ret; - - ret = read_sr(nor); - if (!(ret > 0 && (ret & SR_QUAD_EN_MX))) { - dev_err(nor->dev, "Macronix Quad bit not set\n"); - return -EINVAL; - } - - return 0; -} - -/** - * spansion_quad_enable() - set QE bit in Configuraiton Register. - * @nor: pointer to a 'struct spi_nor' - * - * Set the Quad Enable (QE) bit in the Configuration Register. - * This function is kept for legacy purpose because it has been used for a - * long time without anybody complaining but it should be considered as - * deprecated and maybe buggy. - * First, this function doesn't care about the previous values of the Status - * and Configuration Registers when it sets the QE bit (bit 1) in the - * Configuration Register: all other bits are cleared, which may have unwanted - * side effects like removing some block protections. - * Secondly, it uses the Read Configuration Register (35h) instruction though - * some very old and few memories don't support this instruction. If a pull-up - * resistor is present on the MISO/IO1 line, we might still be able to pass the - * "read back" test because the QSPI memory doesn't recognize the command, - * so leaves the MISO/IO1 line state unchanged, hence read_cr() returns 0xFF. - * - * bit 1 of the Configuration Register is the QE bit for Spansion like QSPI - * memories. - * - * Return: 0 on success, -errno otherwise. - */ -static int spansion_quad_enable(struct spi_nor *nor) -{ - u8 sr_cr[2] = {0, CR_QUAD_EN_SPAN}; int ret; - ret = write_sr_cr(nor, sr_cr); + ret = spi_nor_read_sr(nor, nor->bouncebuf); if (ret) return ret; - /* read back and check it */ - ret = read_cr(nor); - if (!(ret > 0 && (ret & CR_QUAD_EN_SPAN))) { - dev_err(nor->dev, "Spansion Quad bit not set\n"); - return -EINVAL; - } - - return 0; -} - -/** - * spansion_no_read_cr_quad_enable() - set QE bit in Configuration Register. - * @nor: pointer to a 'struct spi_nor' - * - * Set the Quad Enable (QE) bit in the Configuration Register. - * This function should be used with QSPI memories not supporting the Read - * Configuration Register (35h) instruction. - * - * bit 1 of the Configuration Register is the QE bit for Spansion like QSPI - * memories. - * - * Return: 0 on success, -errno otherwise. - */ -static int spansion_no_read_cr_quad_enable(struct spi_nor *nor) -{ - u8 sr_cr[2]; - int ret; + if (nor->bouncebuf[0] & SR1_QUAD_EN_BIT6) + return 0; - /* Keep the current value of the Status Register. */ - ret = read_sr(nor); - if (ret < 0) { - dev_err(nor->dev, "error while reading status register\n"); - return -EINVAL; - } - sr_cr[0] = ret; - sr_cr[1] = CR_QUAD_EN_SPAN; + nor->bouncebuf[0] |= SR1_QUAD_EN_BIT6; - return write_sr_cr(nor, sr_cr); + return spi_nor_write_sr1_and_check(nor, nor->bouncebuf[0]); } /** - * spansion_read_cr_quad_enable() - set QE bit in Configuration Register. - * @nor: pointer to a 'struct spi_nor' + * spi_nor_sr2_bit1_quad_enable() - set the Quad Enable BIT(1) in the Status + * Register 2. + * @nor: pointer to a 'struct spi_nor'. * - * Set the Quad Enable (QE) bit in the Configuration Register. - * This function should be used with QSPI memories supporting the Read - * Configuration Register (35h) instruction. - * - * bit 1 of the Configuration Register is the QE bit for Spansion like QSPI - * memories. + * Bit 1 of the Status Register 2 is the QE bit for Spansion like QSPI memories. * * Return: 0 on success, -errno otherwise. */ -static int spansion_read_cr_quad_enable(struct spi_nor *nor) +static int spi_nor_sr2_bit1_quad_enable(struct spi_nor *nor) { - struct device *dev = nor->dev; - u8 sr_cr[2]; int ret; - /* Check current Quad Enable bit value. */ - ret = read_cr(nor); - if (ret < 0) { - dev_err(dev, "error while reading configuration register\n"); - return -EINVAL; - } - - if (ret & CR_QUAD_EN_SPAN) - return 0; - - sr_cr[1] = ret | CR_QUAD_EN_SPAN; + if (nor->flags & SNOR_F_NO_READ_CR) + return spi_nor_write_16bit_cr_and_check(nor, SR2_QUAD_EN_BIT1); - /* Keep the current value of the Status Register. */ - ret = read_sr(nor); - if (ret < 0) { - dev_err(dev, "error while reading status register\n"); - return -EINVAL; - } - sr_cr[0] = ret; - - ret = write_sr_cr(nor, sr_cr); + ret = spi_nor_read_cr(nor, nor->bouncebuf); if (ret) return ret; - /* Read back and check it. */ - ret = read_cr(nor); - if (!(ret > 0 && (ret & CR_QUAD_EN_SPAN))) { - dev_err(nor->dev, "Spansion Quad bit not set\n"); - return -EINVAL; - } + if (nor->bouncebuf[0] & SR2_QUAD_EN_BIT1) + return 0; - return 0; + nor->bouncebuf[0] |= SR2_QUAD_EN_BIT1; + + return spi_nor_write_16bit_cr_and_check(nor, nor->bouncebuf[0]); } /** - * sr2_bit7_quad_enable() - set QE bit in Status Register 2. + * spi_nor_sr2_bit7_quad_enable() - set QE bit in Status Register 2. * @nor: pointer to a 'struct spi_nor' * * Set the Quad Enable (QE) bit in the Status Register 2. @@ -1597,132 +2157,39 @@ static int spansion_read_cr_quad_enable(struct spi_nor *nor) * * Return: 0 on success, -errno otherwise. */ -static int sr2_bit7_quad_enable(struct spi_nor *nor) +static int spi_nor_sr2_bit7_quad_enable(struct spi_nor *nor) { - u8 sr2; + u8 *sr2 = nor->bouncebuf; int ret; + u8 sr2_written; /* Check current Quad Enable bit value. */ - ret = nor->read_reg(nor, SPINOR_OP_RDSR2, &sr2, 1); + ret = spi_nor_read_sr2(nor, sr2); if (ret) return ret; - if (sr2 & SR2_QUAD_EN_BIT7) + if (*sr2 & SR2_QUAD_EN_BIT7) return 0; /* Update the Quad Enable bit. */ - sr2 |= SR2_QUAD_EN_BIT7; - - write_enable(nor); - - ret = nor->write_reg(nor, SPINOR_OP_WRSR2, &sr2, 1); - if (ret < 0) { - dev_err(nor->dev, "error while writing status register 2\n"); - return -EINVAL; - } - - ret = spi_nor_wait_till_ready(nor); - if (ret < 0) { - dev_err(nor->dev, "timeout while writing status register 2\n"); - return ret; - } - - /* Read back and check it. */ - ret = nor->read_reg(nor, SPINOR_OP_RDSR2, &sr2, 1); - if (!(ret > 0 && (sr2 & SR2_QUAD_EN_BIT7))) { - dev_err(nor->dev, "SR2 Quad bit not set\n"); - return -EINVAL; - } + *sr2 |= SR2_QUAD_EN_BIT7; - return 0; -} - -/** - * spi_nor_clear_sr_bp() - clear the Status Register Block Protection bits. - * @nor: pointer to a 'struct spi_nor' - * - * Read-modify-write function that clears the Block Protection bits from the - * Status Register without affecting other bits. - * - * Return: 0 on success, -errno otherwise. - */ -static int spi_nor_clear_sr_bp(struct spi_nor *nor) -{ - int ret; - u8 mask = SR_BP2 | SR_BP1 | SR_BP0; - - ret = read_sr(nor); - if (ret < 0) { - dev_err(nor->dev, "error while reading status register\n"); + ret = spi_nor_write_sr2(nor, sr2); + if (ret) return ret; - } - write_enable(nor); + sr2_written = *sr2; - ret = write_sr(nor, ret & ~mask); - if (ret) { - dev_err(nor->dev, "write to status register failed\n"); - return ret; - } - - ret = spi_nor_wait_till_ready(nor); + /* Read back and check it. */ + ret = spi_nor_read_sr2(nor, sr2); if (ret) - dev_err(nor->dev, "timeout while writing status register\n"); - return ret; -} - -/** - * spi_nor_spansion_clear_sr_bp() - clear the Status Register Block Protection - * bits on spansion flashes. - * @nor: pointer to a 'struct spi_nor' - * - * Read-modify-write function that clears the Block Protection bits from the - * Status Register without affecting other bits. The function is tightly - * coupled with the spansion_quad_enable() function. Both assume that the Write - * Register with 16 bits, together with the Read Configuration Register (35h) - * instructions are supported. - * - * Return: 0 on success, -errno otherwise. - */ -static int spi_nor_spansion_clear_sr_bp(struct spi_nor *nor) -{ - int ret; - u8 mask = SR_BP2 | SR_BP1 | SR_BP0; - u8 sr_cr[2] = {0}; - - /* Check current Quad Enable bit value. */ - ret = read_cr(nor); - if (ret < 0) { - dev_err(nor->dev, - "error while reading configuration register\n"); return ret; - } - /* - * When the configuration register Quad Enable bit is one, only the - * Write Status (01h) command with two data bytes may be used. - */ - if (ret & CR_QUAD_EN_SPAN) { - sr_cr[1] = ret; - - ret = read_sr(nor); - if (ret < 0) { - dev_err(nor->dev, - "error while reading status register\n"); - return ret; - } - sr_cr[0] = ret & ~mask; - - ret = write_sr_cr(nor, sr_cr); - if (ret) - dev_err(nor->dev, "16-bit write register failed\n"); - return ret; + if (*sr2 != sr2_written) { + dev_dbg(nor->dev, "SR2: Read back test failed\n"); + return -EIO; } - /* - * If the Quad Enable bit is zero, use the Write Status (01h) command - * with one data byte. - */ - return spi_nor_clear_sr_bp(nor); + return 0; } /* Used when the "_ext_id" is two bytes at most */ @@ -1822,6 +2289,21 @@ static struct spi_nor_fixups mx25l25635_fixups = { .post_bfpt = mx25l25635_post_bfpt_fixups, }; +static void gd25q256_default_init(struct spi_nor *nor) +{ + /* + * Some manufacturer like GigaDevice may use different + * bit to set QE on different memories, so the MFR can't + * indicate the quad_enable method for this case, we need + * to set it in the default_init fixup hook. + */ + nor->params.quad_enable = spi_nor_sr1_bit6_quad_enable; +} + +static struct spi_nor_fixups gd25q256_fixups = { + .default_init = gd25q256_default_init, +}; + /* NOTE: double check command sets and memory organization when you add * more nor chips. This current list focusses on newer chips, which * have been converging on command sets which including JEDEC ID. @@ -1843,6 +2325,9 @@ static const struct flash_info spi_nor_ids[] = { { "at25df321a", INFO(0x1f4701, 0, 64 * 1024, 64, SECT_4K) }, { "at25df641", INFO(0x1f4800, 0, 64 * 1024, 128, SECT_4K) }, + { "at25sl321", INFO(0x1f4216, 0, 64 * 1024, 64, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { "at26f004", INFO(0x1f0400, 0, 64 * 1024, 8, SECT_4K) }, { "at26df081a", INFO(0x1f4501, 0, 64 * 1024, 16, SECT_4K) }, { "at26df161a", INFO(0x1f4601, 0, 64 * 1024, 32, SECT_4K) }, @@ -1858,6 +2343,8 @@ static const struct flash_info spi_nor_ids[] = { { "en25q64", INFO(0x1c3017, 0, 64 * 1024, 128, SECT_4K) }, { "en25q80a", INFO(0x1c3014, 0, 64 * 1024, 16, SECT_4K | SPI_NOR_DUAL_READ) }, + { "en25qh16", INFO(0x1c7015, 0, 64 * 1024, 32, + SECT_4K | SPI_NOR_DUAL_READ) }, { "en25qh32", INFO(0x1c7016, 0, 64 * 1024, 64, 0) }, { "en25qh64", INFO(0x1c7017, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_DUAL_READ) }, @@ -1906,6 +2393,11 @@ static const struct flash_info spi_nor_ids[] = { SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) }, { + "gd25lq128d", INFO(0xc86018, 0, 64 * 1024, 256, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | + SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) + }, + { "gd25q128", INFO(0xc84018, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) @@ -1913,8 +2405,9 @@ static const struct flash_info spi_nor_ids[] = { { "gd25q256", INFO(0xc84019, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | - SPI_NOR_4B_OPCODES | SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) - .quad_enable = macronix_quad_enable, + SPI_NOR_4B_OPCODES | SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | + SPI_NOR_TB_SR_BIT6) + .fixups = &gd25q256_fixups, }, /* Intel/Numonyx -- xxxs33b */ @@ -1946,6 +2439,10 @@ static const struct flash_info spi_nor_ids[] = { SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, { "is25wp128", INFO(0x9d7018, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { "is25wp256", INFO(0x9d7019, 0, 64 * 1024, 512, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | + SPI_NOR_4B_OPCODES) + .fixups = &is25lp256_fixups }, /* Macronix */ { "mx25l512e", INFO(0xc22010, 0, 64 * 1024, 1, SECT_4K) }, @@ -1964,6 +2461,8 @@ static const struct flash_info spi_nor_ids[] = { { "mx25u6435f", INFO(0xc22537, 0, 64 * 1024, 128, SECT_4K) }, { "mx25l12805d", INFO(0xc22018, 0, 64 * 1024, 256, 0) }, { "mx25l12855e", INFO(0xc22618, 0, 64 * 1024, 256, 0) }, + { "mx25r3235f", INFO(0xc22816, 0, 64 * 1024, 64, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, { "mx25u12835f", INFO(0xc22538, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, { "mx25l25635e", INFO(0xc22019, 0, 64 * 1024, 512, @@ -1984,12 +2483,30 @@ static const struct flash_info spi_nor_ids[] = { { "n25q032a", INFO(0x20bb16, 0, 64 * 1024, 64, SPI_NOR_QUAD_READ) }, { "n25q064", INFO(0x20ba17, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_QUAD_READ) }, { "n25q064a", INFO(0x20bb17, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_QUAD_READ) }, - { "n25q128a11", INFO(0x20bb18, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_QUAD_READ) }, - { "n25q128a13", INFO(0x20ba18, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_QUAD_READ) }, - { "n25q256a", INFO(0x20ba19, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { "n25q256ax1", INFO(0x20bb19, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_QUAD_READ) }, - { "n25q512a", INFO(0x20bb20, 0, 64 * 1024, 1024, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) }, + { "n25q128a11", INFO(0x20bb18, 0, 64 * 1024, 256, SECT_4K | + USE_FSR | SPI_NOR_QUAD_READ) }, + { "n25q128a13", INFO(0x20ba18, 0, 64 * 1024, 256, SECT_4K | + USE_FSR | SPI_NOR_QUAD_READ) }, + { "mt25ql256a", INFO6(0x20ba19, 0x104400, 64 * 1024, 512, + SECT_4K | USE_FSR | SPI_NOR_DUAL_READ | + SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, + { "n25q256a", INFO(0x20ba19, 0, 64 * 1024, 512, SECT_4K | + USE_FSR | SPI_NOR_DUAL_READ | + SPI_NOR_QUAD_READ) }, + { "mt25qu256a", INFO6(0x20bb19, 0x104400, 64 * 1024, 512, + SECT_4K | USE_FSR | SPI_NOR_DUAL_READ | + SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, + { "n25q256ax1", INFO(0x20bb19, 0, 64 * 1024, 512, SECT_4K | + USE_FSR | SPI_NOR_QUAD_READ) }, + { "mt25ql512a", INFO6(0x20ba20, 0x104400, 64 * 1024, 1024, + SECT_4K | USE_FSR | SPI_NOR_DUAL_READ | + SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, { "n25q512ax3", INFO(0x20ba20, 0, 64 * 1024, 1024, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) }, + { "mt25qu512a", INFO6(0x20bb20, 0x104400, 64 * 1024, 1024, + SECT_4K | USE_FSR | SPI_NOR_DUAL_READ | + SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, + { "n25q512a", INFO(0x20bb20, 0, 64 * 1024, 1024, SECT_4K | + USE_FSR | SPI_NOR_QUAD_READ) }, { "n25q00", INFO(0x20ba21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) }, { "n25q00a", INFO(0x20bb21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) }, { "mt25ql02g", INFO(0x20ba22, 0, 64 * 1024, 4096, @@ -2003,6 +2520,9 @@ static const struct flash_info spi_nor_ids[] = { SECT_4K | USE_FSR | SPI_NOR_OCTAL_READ | SPI_NOR_4B_OPCODES) }, + { "mt35xu02g", INFO(0x2c5b1c, 0, 128 * 1024, 2048, + SECT_4K | USE_FSR | SPI_NOR_OCTAL_READ | + SPI_NOR_4B_OPCODES) }, /* PMC */ { "pm25lv512", INFO(0, 0, 32 * 1024, 2, SECT_4K_PMC) }, @@ -2022,7 +2542,7 @@ static const struct flash_info spi_nor_ids[] = { { "s25fl256s1", INFO(0x010219, 0x4d01, 64 * 1024, 512, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) }, { "s25fl512s", INFO6(0x010220, 0x4d0080, 256 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | - SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | USE_CLSR) }, + SPI_NOR_HAS_LOCK | USE_CLSR) }, { "s25fs512s", INFO6(0x010220, 0x4d0081, 256 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) }, { "s70fl01gs", INFO(0x010221, 0x4d00, 256 * 1024, 256, 0) }, { "s25sl12800", INFO(0x012018, 0x0300, 256 * 1024, 64, 0) }, @@ -2060,6 +2580,10 @@ static const struct flash_info spi_nor_ids[] = { { "sst25wf040b", INFO(0x621613, 0, 64 * 1024, 8, SECT_4K) }, { "sst25wf040", INFO(0xbf2504, 0, 64 * 1024, 8, SECT_4K | SST_WRITE) }, { "sst25wf080", INFO(0xbf2505, 0, 64 * 1024, 16, SECT_4K | SST_WRITE) }, + { "sst26wf016b", INFO(0xbf2651, 0, 64 * 1024, 32, SECT_4K | + SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { "sst26vf016b", INFO(0xbf2641, 0, 64 * 1024, 32, SECT_4K | + SPI_NOR_DUAL_READ) }, { "sst26vf064b", INFO(0xbf2643, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, /* ST Microelectronics -- newer production may have feature updates */ @@ -2130,6 +2654,11 @@ static const struct flash_info spi_nor_ids[] = { SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) }, + { + "w25q32jwm", INFO(0xef8016, 0, 64 * 1024, 64, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | + SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) + }, { "w25x64", INFO(0xef3017, 0, 64 * 1024, 128, SECT_4K) }, { "w25q64", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) }, { @@ -2150,7 +2679,13 @@ static const struct flash_info spi_nor_ids[] = { { "w25q80", INFO(0xef5014, 0, 64 * 1024, 16, SECT_4K) }, { "w25q80bl", INFO(0xef4014, 0, 64 * 1024, 16, SECT_4K) }, { "w25q128", INFO(0xef4018, 0, 64 * 1024, 256, SECT_4K) }, - { "w25q256", INFO(0xef4019, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { "w25q256", INFO(0xef4019, 0, 64 * 1024, 512, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | + SPI_NOR_4B_OPCODES) }, + { "w25q256jvm", INFO(0xef7019, 0, 64 * 1024, 512, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { "w25q256jw", INFO(0xef6019, 0, 64 * 1024, 512, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, { "w25m512jv", INFO(0xef7119, 0, 64 * 1024, 1024, SECT_4K | SPI_NOR_QUAD_READ | SPI_NOR_DUAL_READ) }, @@ -2177,12 +2712,23 @@ static const struct flash_info spi_nor_ids[] = { static const struct flash_info *spi_nor_read_id(struct spi_nor *nor) { int tmp; - u8 id[SPI_NOR_MAX_ID_LEN]; + u8 *id = nor->bouncebuf; const struct flash_info *info; - tmp = nor->read_reg(nor, SPINOR_OP_RDID, id, SPI_NOR_MAX_ID_LEN); - if (tmp < 0) { - dev_err(nor->dev, "error %d reading JEDEC ID\n", tmp); + if (nor->spimem) { + struct spi_mem_op op = + SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_RDID, 1), + SPI_MEM_OP_NO_ADDR, + SPI_MEM_OP_NO_DUMMY, + SPI_MEM_OP_DATA_IN(SPI_NOR_MAX_ID_LEN, id, 1)); + + tmp = spi_mem_exec_op(nor->spimem, &op); + } else { + tmp = nor->controller_ops->read_reg(nor, SPINOR_OP_RDID, id, + SPI_NOR_MAX_ID_LEN); + } + if (tmp) { + dev_dbg(nor->dev, "error %d reading JEDEC ID\n", tmp); return ERR_PTR(tmp); } @@ -2202,21 +2748,20 @@ static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) { struct spi_nor *nor = mtd_to_spi_nor(mtd); - int ret; + ssize_t ret; dev_dbg(nor->dev, "from 0x%08x, len %zd\n", (u32)from, len); - ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_READ); + ret = spi_nor_lock_and_prep(nor); if (ret) return ret; while (len) { loff_t addr = from; - if (nor->flags & SNOR_F_S3AN_ADDR_DEFAULT) - addr = spi_nor_s3an_addr_convert(nor, addr); + addr = spi_nor_convert_addr(nor, addr); - ret = nor->read(nor, addr, len, buf); + ret = spi_nor_read_data(nor, addr, len, buf); if (ret == 0) { /* We shouldn't see 0-length reads */ ret = -EIO; @@ -2234,7 +2779,7 @@ static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len, ret = 0; read_err: - spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_READ); + spi_nor_unlock_and_unprep(nor); return ret; } @@ -2242,78 +2787,85 @@ static int sst_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf) { struct spi_nor *nor = mtd_to_spi_nor(mtd); - size_t actual; + size_t actual = 0; int ret; dev_dbg(nor->dev, "to 0x%08x, len %zd\n", (u32)to, len); - ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_WRITE); + ret = spi_nor_lock_and_prep(nor); if (ret) return ret; - write_enable(nor); + ret = spi_nor_write_enable(nor); + if (ret) + goto out; nor->sst_write_second = false; - actual = to % 2; /* Start write from odd address. */ - if (actual) { + if (to % 2) { nor->program_opcode = SPINOR_OP_BP; /* write one byte. */ - ret = nor->write(nor, to, 1, buf); + ret = spi_nor_write_data(nor, to, 1, buf); if (ret < 0) - goto sst_write_err; - WARN(ret != 1, "While writing 1 byte written %i bytes\n", - (int)ret); + goto out; + WARN(ret != 1, "While writing 1 byte written %i bytes\n", ret); ret = spi_nor_wait_till_ready(nor); if (ret) - goto sst_write_err; + goto out; + + to++; + actual++; } - to += actual; /* Write out most of the data here. */ for (; actual < len - 1; actual += 2) { nor->program_opcode = SPINOR_OP_AAI_WP; /* write two bytes. */ - ret = nor->write(nor, to, 2, buf + actual); + ret = spi_nor_write_data(nor, to, 2, buf + actual); if (ret < 0) - goto sst_write_err; - WARN(ret != 2, "While writing 2 bytes written %i bytes\n", - (int)ret); + goto out; + WARN(ret != 2, "While writing 2 bytes written %i bytes\n", ret); ret = spi_nor_wait_till_ready(nor); if (ret) - goto sst_write_err; + goto out; to += 2; nor->sst_write_second = true; } nor->sst_write_second = false; - write_disable(nor); + ret = spi_nor_write_disable(nor); + if (ret) + goto out; + ret = spi_nor_wait_till_ready(nor); if (ret) - goto sst_write_err; + goto out; /* Write out trailing byte if it exists. */ if (actual != len) { - write_enable(nor); + ret = spi_nor_write_enable(nor); + if (ret) + goto out; nor->program_opcode = SPINOR_OP_BP; - ret = nor->write(nor, to, 1, buf + actual); + ret = spi_nor_write_data(nor, to, 1, buf + actual); if (ret < 0) - goto sst_write_err; - WARN(ret != 1, "While writing 1 byte written %i bytes\n", - (int)ret); + goto out; + WARN(ret != 1, "While writing 1 byte written %i bytes\n", ret); ret = spi_nor_wait_till_ready(nor); if (ret) - goto sst_write_err; - write_disable(nor); + goto out; + actual += 1; + + ret = spi_nor_write_disable(nor); } -sst_write_err: +out: *retlen += actual; - spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_WRITE); + spi_nor_unlock_and_unprep(nor); return ret; } @@ -2331,7 +2883,7 @@ 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); - ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_WRITE); + ret = spi_nor_lock_and_prep(nor); if (ret) return ret; @@ -2358,11 +2910,13 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len, page_remain = min_t(size_t, nor->page_size - page_offset, len - i); - if (nor->flags & SNOR_F_S3AN_ADDR_DEFAULT) - addr = spi_nor_s3an_addr_convert(nor, addr); + addr = spi_nor_convert_addr(nor, addr); - write_enable(nor); - ret = nor->write(nor, addr, page_remain, buf + i); + ret = spi_nor_write_enable(nor); + if (ret) + goto write_err; + + ret = spi_nor_write_data(nor, addr, page_remain, buf + i); if (ret < 0) goto write_err; written = ret; @@ -2375,31 +2929,39 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len, } write_err: - spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_WRITE); + spi_nor_unlock_and_unprep(nor); return ret; } static int spi_nor_check(struct spi_nor *nor) { - if (!nor->dev || !nor->read || !nor->write || - !nor->read_reg || !nor->write_reg) { + if (!nor->dev || + (!nor->spimem && !nor->controller_ops) || + (!nor->spimem && nor->controller_ops && + (!nor->controller_ops->read || + !nor->controller_ops->write || + !nor->controller_ops->read_reg || + !nor->controller_ops->write_reg))) { pr_err("spi-nor: please fill all the necessary fields!\n"); return -EINVAL; } + if (nor->spimem && nor->controller_ops) { + dev_err(nor->dev, "nor->spimem and nor->controller_ops are mutually exclusive, please set just one of them.\n"); + return -EINVAL; + } + return 0; } -static int s3an_nor_scan(struct spi_nor *nor) +static int s3an_nor_setup(struct spi_nor *nor, + const struct spi_nor_hwcaps *hwcaps) { int ret; - u8 val; - ret = nor->read_reg(nor, SPINOR_OP_XRDSR, &val, 1); - if (ret < 0) { - dev_err(nor->dev, "error %d reading XRDSR\n", (int) ret); + ret = spi_nor_xread_sr(nor, nor->bouncebuf); + if (ret) return ret; - } nor->erase_opcode = SPINOR_OP_XSE; nor->program_opcode = SPINOR_OP_XPP; @@ -2417,7 +2979,7 @@ static int s3an_nor_scan(struct spi_nor *nor) * The current addressing mode can be read from the XRDSR register * and should not be changed, because is a destructive operation. */ - if (val & XSR_PAGESIZE) { + if (nor->bouncebuf[0] & XSR_PAGESIZE) { /* Flash in Power of 2 mode */ nor->page_size = (nor->page_size == 264) ? 256 : 512; nor->mtd.writebufsize = nor->page_size; @@ -2425,7 +2987,8 @@ static int s3an_nor_scan(struct spi_nor *nor) nor->mtd.erasesize = 8 * nor->page_size; } else { /* Flash in Default addressing mode */ - nor->flags |= SNOR_F_S3AN_ADDR_DEFAULT; + nor->params.convert_addr = s3an_convert_addr; + nor->mtd.erasesize = nor->info->sector_size; } return 0; @@ -2522,14 +3085,14 @@ static int spi_nor_hwcaps_pp2cmd(u32 hwcaps) */ static int spi_nor_read_raw(struct spi_nor *nor, u32 addr, size_t len, u8 *buf) { - int ret; + ssize_t ret; while (len) { - ret = nor->read(nor, addr, len, buf); - if (!ret || ret > len) - return -EIO; + ret = spi_nor_read_data(nor, addr, len, buf); if (ret < 0) return ret; + if (!ret || ret > len) + return -EIO; buf += ret; addr += ret; @@ -2575,6 +3138,126 @@ static int spi_nor_read_sfdp(struct spi_nor *nor, u32 addr, } /** + * spi_nor_spimem_check_op - check if the operation is supported + * by controller + *@nor: pointer to a 'struct spi_nor' + *@op: pointer to op template to be checked + * + * Returns 0 if operation is supported, -ENOTSUPP otherwise. + */ +static int spi_nor_spimem_check_op(struct spi_nor *nor, + struct spi_mem_op *op) +{ + /* + * First test with 4 address bytes. The opcode itself might + * be a 3B addressing opcode but we don't care, because + * SPI controller implementation should not check the opcode, + * but just the sequence. + */ + op->addr.nbytes = 4; + if (!spi_mem_supports_op(nor->spimem, op)) { + if (nor->mtd.size > SZ_16M) + return -ENOTSUPP; + + /* If flash size <= 16MB, 3 address bytes are sufficient */ + op->addr.nbytes = 3; + if (!spi_mem_supports_op(nor->spimem, op)) + return -ENOTSUPP; + } + + return 0; +} + +/** + * spi_nor_spimem_check_readop - check if the read op is supported + * by controller + *@nor: pointer to a 'struct spi_nor' + *@read: pointer to op template to be checked + * + * Returns 0 if operation is supported, -ENOTSUPP otherwise. + */ +static int spi_nor_spimem_check_readop(struct spi_nor *nor, + const struct spi_nor_read_command *read) +{ + struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(read->opcode, 1), + SPI_MEM_OP_ADDR(3, 0, 1), + SPI_MEM_OP_DUMMY(0, 1), + SPI_MEM_OP_DATA_IN(0, NULL, 1)); + + op.cmd.buswidth = spi_nor_get_protocol_inst_nbits(read->proto); + op.addr.buswidth = spi_nor_get_protocol_addr_nbits(read->proto); + op.data.buswidth = spi_nor_get_protocol_data_nbits(read->proto); + op.dummy.buswidth = op.addr.buswidth; + op.dummy.nbytes = (read->num_mode_clocks + read->num_wait_states) * + op.dummy.buswidth / 8; + + return spi_nor_spimem_check_op(nor, &op); +} + +/** + * spi_nor_spimem_check_pp - check if the page program op is supported + * by controller + *@nor: pointer to a 'struct spi_nor' + *@pp: pointer to op template to be checked + * + * Returns 0 if operation is supported, -ENOTSUPP otherwise. + */ +static int spi_nor_spimem_check_pp(struct spi_nor *nor, + const struct spi_nor_pp_command *pp) +{ + struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(pp->opcode, 1), + SPI_MEM_OP_ADDR(3, 0, 1), + SPI_MEM_OP_NO_DUMMY, + SPI_MEM_OP_DATA_OUT(0, NULL, 1)); + + op.cmd.buswidth = spi_nor_get_protocol_inst_nbits(pp->proto); + op.addr.buswidth = spi_nor_get_protocol_addr_nbits(pp->proto); + op.data.buswidth = spi_nor_get_protocol_data_nbits(pp->proto); + + return spi_nor_spimem_check_op(nor, &op); +} + +/** + * spi_nor_spimem_adjust_hwcaps - Find optimal Read/Write protocol + * based on SPI controller capabilities + * @nor: pointer to a 'struct spi_nor' + * @hwcaps: pointer to resulting capabilities after adjusting + * according to controller and flash's capability + */ +static void +spi_nor_spimem_adjust_hwcaps(struct spi_nor *nor, u32 *hwcaps) +{ + struct spi_nor_flash_parameter *params = &nor->params; + unsigned int cap; + + /* DTR modes are not supported yet, mask them all. */ + *hwcaps &= ~SNOR_HWCAPS_DTR; + + /* X-X-X modes are not supported yet, mask them all. */ + *hwcaps &= ~SNOR_HWCAPS_X_X_X; + + for (cap = 0; cap < sizeof(*hwcaps) * BITS_PER_BYTE; cap++) { + int rdidx, ppidx; + + if (!(*hwcaps & BIT(cap))) + continue; + + rdidx = spi_nor_hwcaps_read2cmd(BIT(cap)); + if (rdidx >= 0 && + spi_nor_spimem_check_readop(nor, ¶ms->reads[rdidx])) + *hwcaps &= ~BIT(cap); + + ppidx = spi_nor_hwcaps_pp2cmd(BIT(cap)); + if (ppidx < 0) + continue; + + if (spi_nor_spimem_check_pp(nor, + ¶ms->page_programs[ppidx])) + *hwcaps &= ~BIT(cap); + } +} + +/** * spi_nor_read_sfdp_dma_unsafe() - read Serial Flash Discoverable Parameters. * @nor: pointer to a 'struct spi_nor' * @addr: offset in the SFDP area to start reading data from @@ -2892,7 +3575,7 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor, const struct sfdp_parameter_header *bfpt_header, struct spi_nor_flash_parameter *params) { - struct spi_nor_erase_map *map = &nor->erase_map; + struct spi_nor_erase_map *map = ¶ms->erase_map; struct spi_nor_erase_type *erase_type = map->erase_type; struct sfdp_bfpt bfpt; size_t len; @@ -2973,7 +3656,7 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor, * Erase Types defined in the bfpt table. */ erase_mask = 0; - memset(&nor->erase_map, 0, sizeof(nor->erase_map)); + memset(¶ms->erase_map, 0, sizeof(params->erase_map)); for (i = 0; i < ARRAY_SIZE(sfdp_bfpt_erases); i++) { const struct sfdp_bfpt_erase *er = &sfdp_bfpt_erases[i]; u32 erasesize; @@ -3026,20 +3709,39 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor, break; case BFPT_DWORD15_QER_SR2_BIT1_BUGGY: + /* + * Writing only one byte to the Status Register has the + * side-effect of clearing Status Register 2. + */ case BFPT_DWORD15_QER_SR2_BIT1_NO_RD: - params->quad_enable = spansion_no_read_cr_quad_enable; + /* + * Read Configuration Register (35h) instruction is not + * supported. + */ + nor->flags |= SNOR_F_HAS_16BIT_SR | SNOR_F_NO_READ_CR; + params->quad_enable = spi_nor_sr2_bit1_quad_enable; break; case BFPT_DWORD15_QER_SR1_BIT6: - params->quad_enable = macronix_quad_enable; + nor->flags &= ~SNOR_F_HAS_16BIT_SR; + params->quad_enable = spi_nor_sr1_bit6_quad_enable; break; case BFPT_DWORD15_QER_SR2_BIT7: - params->quad_enable = sr2_bit7_quad_enable; + nor->flags &= ~SNOR_F_HAS_16BIT_SR; + params->quad_enable = spi_nor_sr2_bit7_quad_enable; break; case BFPT_DWORD15_QER_SR2_BIT1: - params->quad_enable = spansion_read_cr_quad_enable; + /* + * JESD216 rev B or later does not specify if writing only one + * byte to the Status Register clears or not the Status + * Register 2, so let's be cautious and keep the default + * assumption of a 16-bit Write Status (01h) command. + */ + nor->flags |= SNOR_F_HAS_16BIT_SR; + + params->quad_enable = spi_nor_sr2_bit1_quad_enable; break; default: @@ -3248,14 +3950,18 @@ spi_nor_region_check_overlay(struct spi_nor_erase_region *region, /** * spi_nor_init_non_uniform_erase_map() - initialize the non-uniform erase map * @nor: pointer to a 'struct spi_nor' + * @params: pointer to a duplicate 'struct spi_nor_flash_parameter' that is + * used for storing SFDP parsed data * @smpt: pointer to the sector map parameter table * * Return: 0 on success, -errno otherwise. */ -static int spi_nor_init_non_uniform_erase_map(struct spi_nor *nor, - const u32 *smpt) +static int +spi_nor_init_non_uniform_erase_map(struct spi_nor *nor, + struct spi_nor_flash_parameter *params, + const u32 *smpt) { - struct spi_nor_erase_map *map = &nor->erase_map; + struct spi_nor_erase_map *map = ¶ms->erase_map; struct spi_nor_erase_type *erase = map->erase_type; struct spi_nor_erase_region *region; u64 offset; @@ -3334,6 +4040,8 @@ static int spi_nor_init_non_uniform_erase_map(struct spi_nor *nor, * spi_nor_parse_smpt() - parse Sector Map Parameter Table * @nor: pointer to a 'struct spi_nor' * @smpt_header: sector map parameter table header + * @params: pointer to a duplicate 'struct spi_nor_flash_parameter' + * that is used for storing SFDP parsed data * * This table is optional, but when available, we parse it to identify the * location and size of sectors within the main data array of the flash memory @@ -3342,7 +4050,8 @@ static int spi_nor_init_non_uniform_erase_map(struct spi_nor *nor, * Return: 0 on success, -errno otherwise. */ static int spi_nor_parse_smpt(struct spi_nor *nor, - const struct sfdp_parameter_header *smpt_header) + const struct sfdp_parameter_header *smpt_header, + struct spi_nor_flash_parameter *params) { const u32 *sector_map; u32 *smpt; @@ -3371,11 +4080,11 @@ static int spi_nor_parse_smpt(struct spi_nor *nor, goto out; } - ret = spi_nor_init_non_uniform_erase_map(nor, sector_map); + ret = spi_nor_init_non_uniform_erase_map(nor, params, sector_map); if (ret) goto out; - spi_nor_regions_sort_erase_types(&nor->erase_map); + spi_nor_regions_sort_erase_types(¶ms->erase_map); /* fall through */ out: kfree(smpt); @@ -3431,7 +4140,7 @@ static int spi_nor_parse_4bait(struct spi_nor *nor, { 0u /* not used */, BIT(12) }, }; struct spi_nor_pp_command *params_pp = params->page_programs; - struct spi_nor_erase_map *map = &nor->erase_map; + struct spi_nor_erase_map *map = ¶ms->erase_map; struct spi_nor_erase_type *erase_type = map->erase_type; u32 *dwords; size_t len; @@ -3453,7 +4162,7 @@ static int spi_nor_parse_4bait(struct spi_nor *nor, addr = SFDP_PARAM_HEADER_PTP(param_header); ret = spi_nor_read_sfdp(nor, addr, len, dwords); if (ret) - return ret; + goto out; /* Fix endianness of the 4BAIT DWORDs. */ for (i = 0; i < SFDP_4BAIT_DWORD_MAX; i++) @@ -3631,7 +4340,7 @@ static int spi_nor_parse_sfdp(struct spi_nor *nor, err = spi_nor_read_sfdp(nor, sizeof(header), psize, param_headers); if (err < 0) { - dev_err(dev, "failed to read SFDP parameter headers\n"); + dev_dbg(dev, "failed to read SFDP parameter headers\n"); goto exit; } } @@ -3661,7 +4370,7 @@ static int spi_nor_parse_sfdp(struct spi_nor *nor, switch (SFDP_PARAM_HEADER_ID(param_header)) { case SFDP_SECTOR_MAP_ID: - err = spi_nor_parse_smpt(nor, param_header); + err = spi_nor_parse_smpt(nor, param_header, params); break; case SFDP_4BAIT_ID: @@ -3690,133 +4399,7 @@ exit: return err; } -static int spi_nor_init_params(struct spi_nor *nor, - struct spi_nor_flash_parameter *params) -{ - struct spi_nor_erase_map *map = &nor->erase_map; - const struct flash_info *info = nor->info; - u8 i, erase_mask; - - /* Set legacy flash parameters as default. */ - memset(params, 0, sizeof(*params)); - - /* Set SPI NOR sizes. */ - params->size = (u64)info->sector_size * info->n_sectors; - params->page_size = info->page_size; - - /* (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; - 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; - spi_nor_set_read_settings(¶ms->reads[SNOR_CMD_READ_1_1_2], - 0, 8, SPINOR_OP_READ_1_1_2, - SNOR_PROTO_1_1_2); - } - - if (info->flags & SPI_NOR_QUAD_READ) { - params->hwcaps.mask |= SNOR_HWCAPS_READ_1_1_4; - spi_nor_set_read_settings(¶ms->reads[SNOR_CMD_READ_1_1_4], - 0, 8, SPINOR_OP_READ_1_1_4, - SNOR_PROTO_1_1_4); - } - - if (info->flags & SPI_NOR_OCTAL_READ) { - params->hwcaps.mask |= SNOR_HWCAPS_READ_1_1_8; - spi_nor_set_read_settings(¶ms->reads[SNOR_CMD_READ_1_1_8], - 0, 8, SPINOR_OP_READ_1_1_8, - SNOR_PROTO_1_1_8); - } - - /* Page Program settings. */ - params->hwcaps.mask |= SNOR_HWCAPS_PP; - spi_nor_set_pp_settings(¶ms->page_programs[SNOR_CMD_PP], - SPINOR_OP_PP, SNOR_PROTO_1_1_1); - - /* - * Sector Erase settings. Sort Erase Types in ascending order, with the - * smallest erase size starting at BIT(0). - */ - erase_mask = 0; - i = 0; - if (info->flags & SECT_4K_PMC) { - erase_mask |= BIT(i); - spi_nor_set_erase_type(&map->erase_type[i], 4096u, - SPINOR_OP_BE_4K_PMC); - i++; - } else if (info->flags & SECT_4K) { - erase_mask |= BIT(i); - spi_nor_set_erase_type(&map->erase_type[i], 4096u, - SPINOR_OP_BE_4K); - i++; - } - erase_mask |= BIT(i); - spi_nor_set_erase_type(&map->erase_type[i], info->sector_size, - SPINOR_OP_SE); - spi_nor_init_uniform_erase_map(map, erase_mask, params->size); - - /* Select the procedure to set the Quad Enable bit. */ - if (params->hwcaps.mask & (SNOR_HWCAPS_READ_QUAD | - SNOR_HWCAPS_PP_QUAD)) { - switch (JEDEC_MFR(info)) { - case SNOR_MFR_MACRONIX: - params->quad_enable = macronix_quad_enable; - break; - - case SNOR_MFR_ST: - case SNOR_MFR_MICRON: - break; - - default: - /* Kept only for backward compatibility purpose. */ - params->quad_enable = spansion_quad_enable; - break; - } - - /* - * Some manufacturer like GigaDevice may use different - * bit to set QE on different memories, so the MFR can't - * indicate the quad_enable method for this case, we need - * set it in flash info list. - */ - if (info->quad_enable) - params->quad_enable = info->quad_enable; - } - - if ((info->flags & (SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)) && - !(info->flags & SPI_NOR_SKIP_SFDP)) { - struct spi_nor_flash_parameter sfdp_params; - struct spi_nor_erase_map prev_map; - - memcpy(&sfdp_params, params, sizeof(sfdp_params)); - memcpy(&prev_map, &nor->erase_map, sizeof(prev_map)); - - if (spi_nor_parse_sfdp(nor, &sfdp_params)) { - nor->addr_width = 0; - nor->flags &= ~SNOR_F_4B_OPCODES; - /* restore previous erase map */ - memcpy(&nor->erase_map, &prev_map, - sizeof(nor->erase_map)); - } else { - memcpy(params, &sfdp_params, sizeof(*params)); - } - } - - return 0; -} - static int spi_nor_select_read(struct spi_nor *nor, - const struct spi_nor_flash_parameter *params, u32 shared_hwcaps) { int cmd, best_match = fls(shared_hwcaps & SNOR_HWCAPS_READ_MASK) - 1; @@ -3829,7 +4412,7 @@ static int spi_nor_select_read(struct spi_nor *nor, if (cmd < 0) return -EINVAL; - read = ¶ms->reads[cmd]; + read = &nor->params.reads[cmd]; nor->read_opcode = read->opcode; nor->read_proto = read->proto; @@ -3848,7 +4431,6 @@ static int spi_nor_select_read(struct spi_nor *nor, } static int spi_nor_select_pp(struct spi_nor *nor, - const struct spi_nor_flash_parameter *params, u32 shared_hwcaps) { int cmd, best_match = fls(shared_hwcaps & SNOR_HWCAPS_PP_MASK) - 1; @@ -3861,7 +4443,7 @@ static int spi_nor_select_pp(struct spi_nor *nor, if (cmd < 0) return -EINVAL; - pp = ¶ms->page_programs[cmd]; + pp = &nor->params.page_programs[cmd]; nor->program_opcode = pp->opcode; nor->write_proto = pp->proto; return 0; @@ -3920,11 +4502,12 @@ spi_nor_select_uniform_erase(struct spi_nor_erase_map *map, return erase; } -static int spi_nor_select_erase(struct spi_nor *nor, u32 wanted_size) +static int spi_nor_select_erase(struct spi_nor *nor) { - struct spi_nor_erase_map *map = &nor->erase_map; + struct spi_nor_erase_map *map = &nor->params.erase_map; const struct spi_nor_erase_type *erase = NULL; struct mtd_info *mtd = &nor->mtd; + u32 wanted_size = nor->info->sector_size; int i; /* @@ -3967,12 +4550,11 @@ static int spi_nor_select_erase(struct spi_nor *nor, u32 wanted_size) return 0; } -static int spi_nor_setup(struct spi_nor *nor, - const struct spi_nor_flash_parameter *params, - const struct spi_nor_hwcaps *hwcaps) +static int spi_nor_default_setup(struct spi_nor *nor, + const struct spi_nor_hwcaps *hwcaps) { + struct spi_nor_flash_parameter *params = &nor->params; u32 ignored_mask, shared_mask; - bool enable_quad_io; int err; /* @@ -3981,49 +4563,407 @@ static int spi_nor_setup(struct spi_nor *nor, */ shared_mask = hwcaps->mask & params->hwcaps.mask; - /* SPI n-n-n protocols are not supported yet. */ - ignored_mask = (SNOR_HWCAPS_READ_2_2_2 | - SNOR_HWCAPS_READ_4_4_4 | - SNOR_HWCAPS_READ_8_8_8 | - SNOR_HWCAPS_PP_4_4_4 | - SNOR_HWCAPS_PP_8_8_8); - if (shared_mask & ignored_mask) { - dev_dbg(nor->dev, - "SPI n-n-n protocols are not supported yet.\n"); - shared_mask &= ~ignored_mask; + if (nor->spimem) { + /* + * When called from spi_nor_probe(), all caps are set and we + * need to discard some of them based on what the SPI + * controller actually supports (using spi_mem_supports_op()). + */ + spi_nor_spimem_adjust_hwcaps(nor, &shared_mask); + } else { + /* + * SPI n-n-n protocols are not supported when the SPI + * controller directly implements the spi_nor interface. + * Yet another reason to switch to spi-mem. + */ + ignored_mask = SNOR_HWCAPS_X_X_X; + if (shared_mask & ignored_mask) { + dev_dbg(nor->dev, + "SPI n-n-n protocols are not supported.\n"); + shared_mask &= ~ignored_mask; + } } /* Select the (Fast) Read command. */ - err = spi_nor_select_read(nor, params, shared_mask); + err = spi_nor_select_read(nor, shared_mask); if (err) { - dev_err(nor->dev, + dev_dbg(nor->dev, "can't select read settings supported by both the SPI controller and memory.\n"); return err; } /* Select the Page Program command. */ - err = spi_nor_select_pp(nor, params, shared_mask); + err = spi_nor_select_pp(nor, shared_mask); if (err) { - dev_err(nor->dev, + dev_dbg(nor->dev, "can't select write settings supported by both the SPI controller and memory.\n"); return err; } /* Select the Sector Erase command. */ - err = spi_nor_select_erase(nor, nor->info->sector_size); + err = spi_nor_select_erase(nor); if (err) { - dev_err(nor->dev, + dev_dbg(nor->dev, "can't select erase settings supported by both the SPI controller and memory.\n"); return err; } - /* Enable Quad I/O if needed. */ - enable_quad_io = (spi_nor_get_protocol_width(nor->read_proto) == 4 || - spi_nor_get_protocol_width(nor->write_proto) == 4); - if (enable_quad_io && params->quad_enable) - nor->quad_enable = params->quad_enable; - else - nor->quad_enable = NULL; + return 0; +} + +static int spi_nor_setup(struct spi_nor *nor, + const struct spi_nor_hwcaps *hwcaps) +{ + if (!nor->params.setup) + return 0; + + return nor->params.setup(nor, hwcaps); +} + +static void atmel_set_default_init(struct spi_nor *nor) +{ + nor->flags |= SNOR_F_HAS_LOCK; +} + +static void intel_set_default_init(struct spi_nor *nor) +{ + nor->flags |= SNOR_F_HAS_LOCK; +} + +static void issi_set_default_init(struct spi_nor *nor) +{ + nor->params.quad_enable = spi_nor_sr1_bit6_quad_enable; +} + +static void macronix_set_default_init(struct spi_nor *nor) +{ + nor->params.quad_enable = spi_nor_sr1_bit6_quad_enable; + nor->params.set_4byte = macronix_set_4byte; +} + +static void sst_set_default_init(struct spi_nor *nor) +{ + nor->flags |= SNOR_F_HAS_LOCK; +} + +static void st_micron_set_default_init(struct spi_nor *nor) +{ + nor->flags |= SNOR_F_HAS_LOCK; + nor->flags &= ~SNOR_F_HAS_16BIT_SR; + nor->params.quad_enable = NULL; + nor->params.set_4byte = st_micron_set_4byte; +} + +static void winbond_set_default_init(struct spi_nor *nor) +{ + nor->params.set_4byte = winbond_set_4byte; +} + +/** + * spi_nor_manufacturer_init_params() - Initialize the flash's parameters and + * settings based on MFR register and ->default_init() hook. + * @nor: pointer to a 'struct spi-nor'. + */ +static void spi_nor_manufacturer_init_params(struct spi_nor *nor) +{ + /* Init flash parameters based on MFR */ + switch (JEDEC_MFR(nor->info)) { + case SNOR_MFR_ATMEL: + atmel_set_default_init(nor); + break; + + case SNOR_MFR_INTEL: + intel_set_default_init(nor); + break; + + case SNOR_MFR_ISSI: + issi_set_default_init(nor); + break; + + case SNOR_MFR_MACRONIX: + macronix_set_default_init(nor); + break; + + case SNOR_MFR_ST: + case SNOR_MFR_MICRON: + st_micron_set_default_init(nor); + break; + + case SNOR_MFR_SST: + sst_set_default_init(nor); + break; + + case SNOR_MFR_WINBOND: + winbond_set_default_init(nor); + break; + + default: + break; + } + + if (nor->info->fixups && nor->info->fixups->default_init) + nor->info->fixups->default_init(nor); +} + +/** + * spi_nor_sfdp_init_params() - Initialize the flash's parameters and settings + * based on JESD216 SFDP standard. + * @nor: pointer to a 'struct spi-nor'. + * + * The method has a roll-back mechanism: in case the SFDP parsing fails, the + * legacy flash parameters and settings will be restored. + */ +static void spi_nor_sfdp_init_params(struct spi_nor *nor) +{ + struct spi_nor_flash_parameter sfdp_params; + + memcpy(&sfdp_params, &nor->params, sizeof(sfdp_params)); + + if (spi_nor_parse_sfdp(nor, &sfdp_params)) { + nor->addr_width = 0; + nor->flags &= ~SNOR_F_4B_OPCODES; + } else { + memcpy(&nor->params, &sfdp_params, sizeof(nor->params)); + } +} + +/** + * spi_nor_info_init_params() - Initialize the flash's parameters and settings + * based on nor->info data. + * @nor: pointer to a 'struct spi-nor'. + */ +static void spi_nor_info_init_params(struct spi_nor *nor) +{ + struct spi_nor_flash_parameter *params = &nor->params; + struct spi_nor_erase_map *map = ¶ms->erase_map; + const struct flash_info *info = nor->info; + struct device_node *np = spi_nor_get_flash_node(nor); + u8 i, erase_mask; + + /* Initialize legacy flash parameters and settings. */ + params->quad_enable = spi_nor_sr2_bit1_quad_enable; + params->set_4byte = spansion_set_4byte; + params->setup = spi_nor_default_setup; + /* Default to 16-bit Write Status (01h) Command */ + nor->flags |= SNOR_F_HAS_16BIT_SR; + + /* Set SPI NOR sizes. */ + params->size = (u64)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 (np && !of_property_read_bool(np, "m25p,fast-read")) + params->hwcaps.mask &= ~SNOR_HWCAPS_READ_FAST; + } + + /* (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 (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; + spi_nor_set_read_settings(¶ms->reads[SNOR_CMD_READ_1_1_2], + 0, 8, SPINOR_OP_READ_1_1_2, + SNOR_PROTO_1_1_2); + } + + if (info->flags & SPI_NOR_QUAD_READ) { + params->hwcaps.mask |= SNOR_HWCAPS_READ_1_1_4; + spi_nor_set_read_settings(¶ms->reads[SNOR_CMD_READ_1_1_4], + 0, 8, SPINOR_OP_READ_1_1_4, + SNOR_PROTO_1_1_4); + } + + if (info->flags & SPI_NOR_OCTAL_READ) { + params->hwcaps.mask |= SNOR_HWCAPS_READ_1_1_8; + spi_nor_set_read_settings(¶ms->reads[SNOR_CMD_READ_1_1_8], + 0, 8, SPINOR_OP_READ_1_1_8, + SNOR_PROTO_1_1_8); + } + + /* Page Program settings. */ + params->hwcaps.mask |= SNOR_HWCAPS_PP; + spi_nor_set_pp_settings(¶ms->page_programs[SNOR_CMD_PP], + SPINOR_OP_PP, SNOR_PROTO_1_1_1); + + /* + * Sector Erase settings. Sort Erase Types in ascending order, with the + * smallest erase size starting at BIT(0). + */ + erase_mask = 0; + i = 0; + if (info->flags & SECT_4K_PMC) { + erase_mask |= BIT(i); + spi_nor_set_erase_type(&map->erase_type[i], 4096u, + SPINOR_OP_BE_4K_PMC); + i++; + } else if (info->flags & SECT_4K) { + erase_mask |= BIT(i); + spi_nor_set_erase_type(&map->erase_type[i], 4096u, + SPINOR_OP_BE_4K); + i++; + } + erase_mask |= BIT(i); + spi_nor_set_erase_type(&map->erase_type[i], info->sector_size, + SPINOR_OP_SE); + spi_nor_init_uniform_erase_map(map, erase_mask, params->size); +} + +static void spansion_post_sfdp_fixups(struct spi_nor *nor) +{ + if (nor->params.size <= SZ_16M) + return; + + nor->flags |= SNOR_F_4B_OPCODES; + /* No small sector erase for 4-byte command set */ + nor->erase_opcode = SPINOR_OP_SE; + nor->mtd.erasesize = nor->info->sector_size; +} + +static void s3an_post_sfdp_fixups(struct spi_nor *nor) +{ + nor->params.setup = s3an_nor_setup; +} + +/** + * spi_nor_post_sfdp_fixups() - Updates the flash's parameters and settings + * after SFDP has been parsed (is also called for SPI NORs that do not + * support RDSFDP). + * @nor: pointer to a 'struct spi_nor' + * + * Typically used to tweak various parameters that could not be extracted by + * other means (i.e. when information provided by the SFDP/flash_info tables + * are incomplete or wrong). + */ +static void spi_nor_post_sfdp_fixups(struct spi_nor *nor) +{ + switch (JEDEC_MFR(nor->info)) { + case SNOR_MFR_SPANSION: + spansion_post_sfdp_fixups(nor); + break; + + default: + break; + } + + if (nor->info->flags & SPI_S3AN) + s3an_post_sfdp_fixups(nor); + + if (nor->info->fixups && nor->info->fixups->post_sfdp) + nor->info->fixups->post_sfdp(nor); +} + +/** + * spi_nor_late_init_params() - Late initialization of default flash parameters. + * @nor: pointer to a 'struct spi_nor' + * + * Used to set default flash parameters and settings when the ->default_init() + * hook or the SFDP parser let voids. + */ +static void spi_nor_late_init_params(struct spi_nor *nor) +{ + /* + * NOR protection support. When locking_ops are not provided, we pick + * the default ones. + */ + if (nor->flags & SNOR_F_HAS_LOCK && !nor->params.locking_ops) + nor->params.locking_ops = &stm_locking_ops; +} + +/** + * spi_nor_init_params() - Initialize the flash's parameters and settings. + * @nor: pointer to a 'struct spi-nor'. + * + * The flash parameters and settings are initialized based on a sequence of + * calls that are ordered by priority: + * + * 1/ Default flash parameters initialization. The initializations are done + * based on nor->info data: + * spi_nor_info_init_params() + * + * which can be overwritten by: + * 2/ Manufacturer flash parameters initialization. The initializations are + * done based on MFR register, or when the decisions can not be done solely + * based on MFR, by using specific flash_info tweeks, ->default_init(): + * spi_nor_manufacturer_init_params() + * + * which can be overwritten by: + * 3/ SFDP flash parameters initialization. JESD216 SFDP is a standard and + * should be more accurate that the above. + * spi_nor_sfdp_init_params() + * + * Please note that there is a ->post_bfpt() fixup hook that can overwrite + * the flash parameters and settings immediately after parsing the Basic + * Flash Parameter Table. + * + * which can be overwritten by: + * 4/ Post SFDP flash parameters initialization. Used to tweak various + * parameters that could not be extracted by other means (i.e. when + * information provided by the SFDP/flash_info tables are incomplete or + * wrong). + * spi_nor_post_sfdp_fixups() + * + * 5/ Late default flash parameters initialization, used when the + * ->default_init() hook or the SFDP parser do not set specific params. + * spi_nor_late_init_params() + */ +static void spi_nor_init_params(struct spi_nor *nor) +{ + spi_nor_info_init_params(nor); + + spi_nor_manufacturer_init_params(nor); + + if ((nor->info->flags & (SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)) && + !(nor->info->flags & SPI_NOR_SKIP_SFDP)) + spi_nor_sfdp_init_params(nor); + + spi_nor_post_sfdp_fixups(nor); + + spi_nor_late_init_params(nor); +} + +/** + * spi_nor_quad_enable() - enable Quad I/O if needed. + * @nor: pointer to a 'struct spi_nor' + * + * Return: 0 on success, -errno otherwise. + */ +static int spi_nor_quad_enable(struct spi_nor *nor) +{ + if (!nor->params.quad_enable) + return 0; + + if (!(spi_nor_get_protocol_width(nor->read_proto) == 4 || + spi_nor_get_protocol_width(nor->write_proto) == 4)) + return 0; + + return nor->params.quad_enable(nor); +} + +/** + * spi_nor_unlock_all() - Unlocks the entire flash memory array. + * @nor: pointer to a 'struct spi_nor'. + * + * Some SPI NOR flashes are write protected by default after a power-on reset + * cycle, in order to avoid inadvertent writes during power-up. Backward + * compatibility imposes to unlock the entire flash memory array at power-up + * by default. + */ +static int spi_nor_unlock_all(struct spi_nor *nor) +{ + if (nor->flags & SNOR_F_HAS_LOCK) + return spi_nor_unlock(&nor->mtd, 0, nor->params.size); return 0; } @@ -4032,24 +4972,16 @@ static int spi_nor_init(struct spi_nor *nor) { int err; - if (nor->clear_sr_bp) { - if (nor->quad_enable == spansion_quad_enable) - nor->clear_sr_bp = spi_nor_spansion_clear_sr_bp; - - err = nor->clear_sr_bp(nor); - if (err) { - dev_err(nor->dev, - "fail to clear block protection bits\n"); - return err; - } + err = spi_nor_quad_enable(nor); + if (err) { + dev_dbg(nor->dev, "quad mode not supported\n"); + return err; } - if (nor->quad_enable) { - err = nor->quad_enable(nor); - if (err) { - dev_err(nor->dev, "quad mode not supported\n"); - return err; - } + err = spi_nor_unlock_all(nor); + if (err) { + dev_dbg(nor->dev, "Failed to unlock the entire flash memory array\n"); + return err; } if (nor->addr_width == 4 && !(nor->flags & SNOR_F_4B_OPCODES)) { @@ -4062,7 +4994,7 @@ static int spi_nor_init(struct spi_nor *nor) */ WARN_ONCE(nor->flags & SNOR_F_BROKEN_RESET, "enabling reset hack; may not recover from unexpected reboots\n"); - set_4byte(nor, true); + nor->params.set_4byte(nor, true); } return 0; @@ -4086,7 +5018,7 @@ void spi_nor_restore(struct spi_nor *nor) /* restore the addressing mode */ if (nor->addr_width == 4 && !(nor->flags & SNOR_F_4B_OPCODES) && nor->flags & SNOR_F_BROKEN_RESET) - set_4byte(nor, false); + nor->params.set_4byte(nor, false); } EXPORT_SYMBOL_GPL(spi_nor_restore); @@ -4102,25 +5034,47 @@ static const struct flash_info *spi_nor_match_id(const char *name) return NULL; } -int spi_nor_scan(struct spi_nor *nor, const char *name, - const struct spi_nor_hwcaps *hwcaps) +static int spi_nor_set_addr_width(struct spi_nor *nor) +{ + if (nor->addr_width) { + /* already configured from SFDP */ + } else if (nor->info->addr_width) { + nor->addr_width = nor->info->addr_width; + } else if (nor->mtd.size > 0x1000000) { + /* enable 4-byte addressing if the device exceeds 16MiB */ + nor->addr_width = 4; + } else { + nor->addr_width = 3; + } + + if (nor->addr_width > SPI_NOR_MAX_ADDR_WIDTH) { + dev_dbg(nor->dev, "address width is too large: %u\n", + nor->addr_width); + return -EINVAL; + } + + /* Set 4byte opcodes when possible. */ + if (nor->addr_width == 4 && nor->flags & SNOR_F_4B_OPCODES && + !(nor->flags & SNOR_F_HAS_4BAIT)) + spi_nor_set_4byte_opcodes(nor); + + return 0; +} + +static void spi_nor_debugfs_init(struct spi_nor *nor, + const struct flash_info *info) { - struct spi_nor_flash_parameter params; - const struct flash_info *info = NULL; - struct device *dev = nor->dev; struct mtd_info *mtd = &nor->mtd; - struct device_node *np = spi_nor_get_flash_node(nor); - int ret; - int i; - ret = spi_nor_check(nor); - if (ret) - return ret; + mtd->dbg.partname = info->name; + mtd->dbg.partid = devm_kasprintf(nor->dev, GFP_KERNEL, "spi-nor:%*phN", + info->id_len, info->id); +} - /* Reset SPI protocol for all commands. */ - nor->reg_proto = SNOR_PROTO_1_1_1; - nor->read_proto = SNOR_PROTO_1_1_1; - nor->write_proto = SNOR_PROTO_1_1_1; +static const struct flash_info *spi_nor_get_flash_info(struct spi_nor *nor, + const char *name) +{ + const struct flash_info *info = NULL; if (name) info = spi_nor_match_id(name); @@ -4128,7 +5082,7 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, if (!info) info = spi_nor_read_id(nor); if (IS_ERR_OR_NULL(info)) - return -ENOENT; + return ERR_PTR(-ENOENT); /* * If caller has specified name of flash model that can normally be @@ -4139,7 +5093,7 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, jinfo = spi_nor_read_id(nor); if (IS_ERR(jinfo)) { - return PTR_ERR(jinfo); + return jinfo; } else if (jinfo != info) { /* * JEDEC knows better, so overwrite platform ID. We @@ -4148,14 +5102,57 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, * marked read-only, and we don't want to lose that * information, even if it's not 100% accurate. */ - dev_warn(dev, "found %s, expected %s\n", + dev_warn(nor->dev, "found %s, expected %s\n", jinfo->name, info->name); info = jinfo; } } + return info; +} + +int spi_nor_scan(struct spi_nor *nor, const char *name, + const struct spi_nor_hwcaps *hwcaps) +{ + const struct flash_info *info; + struct device *dev = nor->dev; + struct mtd_info *mtd = &nor->mtd; + struct device_node *np = spi_nor_get_flash_node(nor); + struct spi_nor_flash_parameter *params = &nor->params; + int ret; + int i; + + ret = spi_nor_check(nor); + if (ret) + return ret; + + /* Reset SPI protocol for all commands. */ + nor->reg_proto = SNOR_PROTO_1_1_1; + nor->read_proto = SNOR_PROTO_1_1_1; + nor->write_proto = SNOR_PROTO_1_1_1; + + /* + * We need the bounce buffer early to read/write registers when going + * through the spi-mem layer (buffers have to be DMA-able). + * For spi-mem drivers, we'll reallocate a new buffer if + * nor->page_size turns out to be greater than PAGE_SIZE (which + * shouldn't happen before long since NOR pages are usually less + * than 1KB) after spi_nor_scan() returns. + */ + nor->bouncebuf_size = PAGE_SIZE; + nor->bouncebuf = devm_kmalloc(dev, nor->bouncebuf_size, + GFP_KERNEL); + if (!nor->bouncebuf) + return -ENOMEM; + + info = spi_nor_get_flash_info(nor, name); + if (IS_ERR(info)) + return PTR_ERR(info); + nor->info = info; + spi_nor_debugfs_init(nor, info); + mutex_init(&nor->lock); /* @@ -4163,23 +5160,14 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, * spi_nor_wait_till_ready(). Xilinx S3AN share MFR * with Atmel spi-nor */ - if (info->flags & SPI_S3AN) + if (info->flags & SPI_NOR_XSR_RDY) nor->flags |= SNOR_F_READY_XSR_RDY; - /* - * Atmel, SST, Intel/Numonyx, and others serial NOR tend to power up - * with the software protection bits set. - */ - if (JEDEC_MFR(nor->info) == SNOR_MFR_ATMEL || - JEDEC_MFR(nor->info) == SNOR_MFR_INTEL || - JEDEC_MFR(nor->info) == SNOR_MFR_SST || - nor->info->flags & SPI_NOR_HAS_LOCK) - nor->clear_sr_bp = spi_nor_clear_sr_bp; - - /* Parse the Serial Flash Discoverable Parameters table. */ - ret = spi_nor_init_params(nor, ¶ms); - if (ret) - return ret; + if (info->flags & SPI_NOR_HAS_LOCK) + nor->flags |= SNOR_F_HAS_LOCK; + + /* Init flash parameters based on flash_info struct and SFDP */ + spi_nor_init_params(nor); if (!mtd->name) mtd->name = dev_name(dev); @@ -4187,21 +5175,12 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, mtd->type = MTD_NORFLASH; mtd->writesize = 1; mtd->flags = MTD_CAP_NORFLASH; - mtd->size = params.size; + mtd->size = params->size; mtd->_erase = spi_nor_erase; mtd->_read = spi_nor_read; mtd->_resume = spi_nor_resume; - /* NOR protection support for STmicro/Micron chips and similar */ - if (JEDEC_MFR(info) == SNOR_MFR_ST || - JEDEC_MFR(info) == SNOR_MFR_MICRON || - info->flags & SPI_NOR_HAS_LOCK) { - nor->flash_lock = stm_lock; - nor->flash_unlock = stm_unlock; - nor->flash_is_locked = stm_is_locked; - } - - if (nor->flash_lock && nor->flash_unlock && nor->flash_is_locked) { + if (nor->params.locking_ops) { mtd->_lock = spi_nor_lock; mtd->_unlock = spi_nor_unlock; mtd->_is_locked = spi_nor_is_locked; @@ -4215,8 +5194,12 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, if (info->flags & USE_FSR) nor->flags |= SNOR_F_USE_FSR; - if (info->flags & SPI_NOR_HAS_TB) + if (info->flags & SPI_NOR_HAS_TB) { nor->flags |= SNOR_F_HAS_SR_TB; + if (info->flags & SPI_NOR_TB_SR_BIT6) + nor->flags |= SNOR_F_HAS_SR_TB_BIT6; + } + if (info->flags & NO_CHIP_ERASE) nor->flags |= SNOR_F_NO_OP_CHIP_ERASE; if (info->flags & USE_CLSR) @@ -4226,68 +5209,28 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, mtd->flags |= MTD_NO_ERASE; mtd->dev.parent = dev; - nor->page_size = params.page_size; + nor->page_size = params->page_size; mtd->writebufsize = nor->page_size; - if (np) { - /* If we were instantiated by DT, use it */ - if (of_property_read_bool(np, "m25p,fast-read")) - params.hwcaps.mask |= SNOR_HWCAPS_READ_FAST; - else - params.hwcaps.mask &= ~SNOR_HWCAPS_READ_FAST; - } else { - /* If we weren't instantiated by DT, default to fast-read */ - params.hwcaps.mask |= SNOR_HWCAPS_READ_FAST; - } - if (of_property_read_bool(np, "broken-flash-reset")) nor->flags |= SNOR_F_BROKEN_RESET; - /* Some devices cannot do fast-read, no matter what DT tells us */ - if (info->flags & SPI_NOR_NO_FR) - params.hwcaps.mask &= ~SNOR_HWCAPS_READ_FAST; - /* * Configure the SPI memory: * - select op codes for (Fast) Read, Page Program and Sector Erase. * - set the number of dummy cycles (mode cycles + wait states). * - set the SPI protocols for register and memory accesses. - * - set the Quad Enable bit if needed (required by SPI x-y-4 protos). */ - ret = spi_nor_setup(nor, ¶ms, hwcaps); + ret = spi_nor_setup(nor, hwcaps); if (ret) return ret; - if (nor->addr_width) { - /* already configured from SFDP */ - } else if (info->addr_width) { - nor->addr_width = info->addr_width; - } else if (mtd->size > 0x1000000) { - /* enable 4-byte addressing if the device exceeds 16MiB */ - nor->addr_width = 4; - } else { - nor->addr_width = 3; - } - - if (info->flags & SPI_NOR_4B_OPCODES || - (JEDEC_MFR(info) == SNOR_MFR_SPANSION && mtd->size > SZ_16M)) + if (info->flags & SPI_NOR_4B_OPCODES) nor->flags |= SNOR_F_4B_OPCODES; - if (nor->addr_width == 4 && nor->flags & SNOR_F_4B_OPCODES && - !(nor->flags & SNOR_F_HAS_4BAIT)) - spi_nor_set_4byte_opcodes(nor); - - if (nor->addr_width > SPI_NOR_MAX_ADDR_WIDTH) { - dev_err(dev, "address width is too large: %u\n", - nor->addr_width); - return -EINVAL; - } - - if (info->flags & SPI_S3AN) { - ret = s3an_nor_scan(nor); - if (ret) - return ret; - } + ret = spi_nor_set_addr_width(nor); + if (ret) + return ret; /* Send all the required SPI flash commands to initialize device */ ret = spi_nor_init(nor); @@ -4317,6 +5260,174 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, } EXPORT_SYMBOL_GPL(spi_nor_scan); +static int spi_nor_probe(struct spi_mem *spimem) +{ + struct spi_device *spi = spimem->spi; + struct flash_platform_data *data = dev_get_platdata(&spi->dev); + struct spi_nor *nor; + /* + * Enable all caps by default. The core will mask them after + * checking what's really supported using spi_mem_supports_op(). + */ + const struct spi_nor_hwcaps hwcaps = { .mask = SNOR_HWCAPS_ALL }; + char *flash_name; + int ret; + + nor = devm_kzalloc(&spi->dev, sizeof(*nor), GFP_KERNEL); + if (!nor) + return -ENOMEM; + + nor->spimem = spimem; + nor->dev = &spi->dev; + spi_nor_set_flash_node(nor, spi->dev.of_node); + + spi_mem_set_drvdata(spimem, nor); + + if (data && data->name) + nor->mtd.name = data->name; + + if (!nor->mtd.name) + nor->mtd.name = spi_mem_get_name(spimem); + + /* + * For some (historical?) reason many platforms provide two different + * names in flash_platform_data: "name" and "type". Quite often name is + * set to "m25p80" and then "type" provides a real chip name. + * If that's the case, respect "type" and ignore a "name". + */ + if (data && data->type) + flash_name = data->type; + else if (!strcmp(spi->modalias, "spi-nor")) + flash_name = NULL; /* auto-detect */ + else + flash_name = spi->modalias; + + ret = spi_nor_scan(nor, flash_name, &hwcaps); + if (ret) + return ret; + + /* + * None of the existing parts have > 512B pages, but let's play safe + * and add this logic so that if anyone ever adds support for such + * a NOR we don't end up with buffer overflows. + */ + if (nor->page_size > PAGE_SIZE) { + nor->bouncebuf_size = nor->page_size; + devm_kfree(nor->dev, nor->bouncebuf); + nor->bouncebuf = devm_kmalloc(nor->dev, + nor->bouncebuf_size, + GFP_KERNEL); + if (!nor->bouncebuf) + return -ENOMEM; + } + + return mtd_device_register(&nor->mtd, data ? data->parts : NULL, + data ? data->nr_parts : 0); +} + +static int spi_nor_remove(struct spi_mem *spimem) +{ + struct spi_nor *nor = spi_mem_get_drvdata(spimem); + + spi_nor_restore(nor); + + /* Clean up MTD stuff. */ + return mtd_device_unregister(&nor->mtd); +} + +static void spi_nor_shutdown(struct spi_mem *spimem) +{ + struct spi_nor *nor = spi_mem_get_drvdata(spimem); + + spi_nor_restore(nor); +} + +/* + * Do NOT add to this array without reading the following: + * + * Historically, many flash devices are bound to this driver by their name. But + * since most of these flash are compatible to some extent, and their + * differences can often be differentiated by the JEDEC read-ID command, we + * encourage new users to add support to the spi-nor library, and simply bind + * against a generic string here (e.g., "jedec,spi-nor"). + * + * Many flash names are kept here in this list (as well as in spi-nor.c) to + * keep them available as module aliases for existing platforms. + */ +static const struct spi_device_id spi_nor_dev_ids[] = { + /* + * Allow non-DT platform devices to bind to the "spi-nor" modalias, and + * hack around the fact that the SPI core does not provide uevent + * matching for .of_match_table + */ + {"spi-nor"}, + + /* + * Entries not used in DTs that should be safe to drop after replacing + * them with "spi-nor" in platform data. + */ + {"s25sl064a"}, {"w25x16"}, {"m25p10"}, {"m25px64"}, + + /* + * Entries that were used in DTs without "jedec,spi-nor" fallback and + * should be kept for backward compatibility. + */ + {"at25df321a"}, {"at25df641"}, {"at26df081a"}, + {"mx25l4005a"}, {"mx25l1606e"}, {"mx25l6405d"}, {"mx25l12805d"}, + {"mx25l25635e"},{"mx66l51235l"}, + {"n25q064"}, {"n25q128a11"}, {"n25q128a13"}, {"n25q512a"}, + {"s25fl256s1"}, {"s25fl512s"}, {"s25sl12801"}, {"s25fl008k"}, + {"s25fl064k"}, + {"sst25vf040b"},{"sst25vf016b"},{"sst25vf032b"},{"sst25wf040"}, + {"m25p40"}, {"m25p80"}, {"m25p16"}, {"m25p32"}, + {"m25p64"}, {"m25p128"}, + {"w25x80"}, {"w25x32"}, {"w25q32"}, {"w25q32dw"}, + {"w25q80bl"}, {"w25q128"}, {"w25q256"}, + + /* Flashes that can't be detected using JEDEC */ + {"m25p05-nonjedec"}, {"m25p10-nonjedec"}, {"m25p20-nonjedec"}, + {"m25p40-nonjedec"}, {"m25p80-nonjedec"}, {"m25p16-nonjedec"}, + {"m25p32-nonjedec"}, {"m25p64-nonjedec"}, {"m25p128-nonjedec"}, + + /* Everspin MRAMs (non-JEDEC) */ + { "mr25h128" }, /* 128 Kib, 40 MHz */ + { "mr25h256" }, /* 256 Kib, 40 MHz */ + { "mr25h10" }, /* 1 Mib, 40 MHz */ + { "mr25h40" }, /* 4 Mib, 40 MHz */ + + { }, +}; +MODULE_DEVICE_TABLE(spi, spi_nor_dev_ids); + +static const struct of_device_id spi_nor_of_table[] = { + /* + * Generic compatibility for SPI NOR that can be identified by the + * JEDEC READ ID opcode (0x9F). Use this, if possible. + */ + { .compatible = "jedec,spi-nor" }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, spi_nor_of_table); + +/* + * REVISIT: many of these chips have deep power-down modes, which + * should clearly be entered on suspend() to minimize power use. + * And also when they're otherwise idle... + */ +static struct spi_mem_driver spi_nor_driver = { + .spidrv = { + .driver = { + .name = "spi-nor", + .of_match_table = spi_nor_of_table, + }, + .id_table = spi_nor_dev_ids, + }, + .probe = spi_nor_probe, + .remove = spi_nor_remove, + .shutdown = spi_nor_shutdown, +}; +module_spi_mem_driver(spi_nor_driver); + MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Huang Shijie <shijie8@gmail.com>"); MODULE_AUTHOR("Mike Lavender"); |