diff options
Diffstat (limited to 'drivers/mtd/spi-nor/spi-nor.c')
-rw-r--r-- | drivers/mtd/spi-nor/spi-nor.c | 5434 |
1 files changed, 0 insertions, 5434 deletions
diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c deleted file mode 100644 index 4fc632ec18fe..000000000000 --- a/drivers/mtd/spi-nor/spi-nor.c +++ /dev/null @@ -1,5434 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Based on m25p80.c, by Mike Lavender (mike@steroidmicros.com), with - * influence from lart.c (Abraham Van Der Merwe) and mtd_dataflash.c - * - * Copyright (C) 2005, Intec Automation Inc. - * Copyright (C) 2014, Freescale Semiconductor, Inc. - */ - -#include <linux/err.h> -#include <linux/errno.h> -#include <linux/module.h> -#include <linux/device.h> -#include <linux/mutex.h> -#include <linux/math64.h> -#include <linux/sizes.h> -#include <linux/slab.h> -#include <linux/sort.h> - -#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> - -/* Define max times to check status register before we give up. */ - -/* - * For everything but full-chip erase; probably could be much smaller, but kept - * around for safety for now - */ -#define DEFAULT_READY_WAIT_JIFFIES (40UL * HZ) - -/* - * For full-chip erase, calibrated to a 2MB flash (M25P16); should be scaled up - * for larger flash - */ -#define CHIP_ERASE_2MB_READY_WAIT_JIFFIES (40UL * HZ) - -#define SPI_NOR_MAX_ID_LEN 6 -#define SPI_NOR_MAX_ADDR_WIDTH 4 - -struct sfdp_parameter_header { - u8 id_lsb; - u8 minor; - u8 major; - u8 length; /* in double words */ - u8 parameter_table_pointer[3]; /* byte address */ - u8 id_msb; -}; - -#define SFDP_PARAM_HEADER_ID(p) (((p)->id_msb << 8) | (p)->id_lsb) -#define SFDP_PARAM_HEADER_PTP(p) \ - (((p)->parameter_table_pointer[2] << 16) | \ - ((p)->parameter_table_pointer[1] << 8) | \ - ((p)->parameter_table_pointer[0] << 0)) - -#define SFDP_BFPT_ID 0xff00 /* Basic Flash Parameter Table */ -#define SFDP_SECTOR_MAP_ID 0xff81 /* Sector Map Table */ -#define SFDP_4BAIT_ID 0xff84 /* 4-byte Address Instruction Table */ - -#define SFDP_SIGNATURE 0x50444653U -#define SFDP_JESD216_MAJOR 1 -#define SFDP_JESD216_MINOR 0 -#define SFDP_JESD216A_MINOR 5 -#define SFDP_JESD216B_MINOR 6 - -struct sfdp_header { - u32 signature; /* Ox50444653U <=> "SFDP" */ - u8 minor; - u8 major; - u8 nph; /* 0-base number of parameter headers */ - u8 unused; - - /* Basic Flash Parameter Table. */ - struct sfdp_parameter_header bfpt_header; -}; - -/* Basic Flash Parameter Table */ - -/* - * JESD216 rev B defines a Basic Flash Parameter Table of 16 DWORDs. - * They are indexed from 1 but C arrays are indexed from 0. - */ -#define BFPT_DWORD(i) ((i) - 1) -#define BFPT_DWORD_MAX 16 - -/* The first version of JESD216 defined only 9 DWORDs. */ -#define BFPT_DWORD_MAX_JESD216 9 - -/* 1st DWORD. */ -#define BFPT_DWORD1_FAST_READ_1_1_2 BIT(16) -#define BFPT_DWORD1_ADDRESS_BYTES_MASK GENMASK(18, 17) -#define BFPT_DWORD1_ADDRESS_BYTES_3_ONLY (0x0UL << 17) -#define BFPT_DWORD1_ADDRESS_BYTES_3_OR_4 (0x1UL << 17) -#define BFPT_DWORD1_ADDRESS_BYTES_4_ONLY (0x2UL << 17) -#define BFPT_DWORD1_DTR BIT(19) -#define BFPT_DWORD1_FAST_READ_1_2_2 BIT(20) -#define BFPT_DWORD1_FAST_READ_1_4_4 BIT(21) -#define BFPT_DWORD1_FAST_READ_1_1_4 BIT(22) - -/* 5th DWORD. */ -#define BFPT_DWORD5_FAST_READ_2_2_2 BIT(0) -#define BFPT_DWORD5_FAST_READ_4_4_4 BIT(4) - -/* 11th DWORD. */ -#define BFPT_DWORD11_PAGE_SIZE_SHIFT 4 -#define BFPT_DWORD11_PAGE_SIZE_MASK GENMASK(7, 4) - -/* 15th DWORD. */ - -/* - * (from JESD216 rev B) - * Quad Enable Requirements (QER): - * - 000b: Device does not have a QE bit. Device detects 1-1-4 and 1-4-4 - * reads based on instruction. DQ3/HOLD# functions are hold during - * instruction phase. - * - 001b: QE is bit 1 of status register 2. It is set via Write Status with - * two data bytes where bit 1 of the second byte is one. - * [...] - * Writing only one byte to the status register has the side-effect of - * clearing status register 2, including the QE bit. The 100b code is - * used if writing one byte to the status register does not modify - * status register 2. - * - 010b: QE is bit 6 of status register 1. It is set via Write Status with - * one data byte where bit 6 is one. - * [...] - * - 011b: QE is bit 7 of status register 2. It is set via Write status - * register 2 instruction 3Eh with one data byte where bit 7 is one. - * [...] - * The status register 2 is read using instruction 3Fh. - * - 100b: QE is bit 1 of status register 2. It is set via Write Status with - * two data bytes where bit 1 of the second byte is one. - * [...] - * In contrast to the 001b code, writing one byte to the status - * register does not modify status register 2. - * - 101b: QE is bit 1 of status register 2. Status register 1 is read using - * Read Status instruction 05h. Status register2 is read using - * instruction 35h. QE is set via Write Status instruction 01h with - * two data bytes where bit 1 of the second byte is one. - * [...] - */ -#define BFPT_DWORD15_QER_MASK GENMASK(22, 20) -#define BFPT_DWORD15_QER_NONE (0x0UL << 20) /* Micron */ -#define BFPT_DWORD15_QER_SR2_BIT1_BUGGY (0x1UL << 20) -#define BFPT_DWORD15_QER_SR1_BIT6 (0x2UL << 20) /* Macronix */ -#define BFPT_DWORD15_QER_SR2_BIT7 (0x3UL << 20) -#define BFPT_DWORD15_QER_SR2_BIT1_NO_RD (0x4UL << 20) -#define BFPT_DWORD15_QER_SR2_BIT1 (0x5UL << 20) /* Spansion */ - -struct sfdp_bfpt { - u32 dwords[BFPT_DWORD_MAX]; -}; - -/** - * 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 { - char *name; - - /* - * This array stores the ID bytes. - * The first three bytes are the JEDIC ID. - * JEDEC ID zero means "no ID" (mostly older chips). - */ - u8 id[SPI_NOR_MAX_ID_LEN]; - u8 id_len; - - /* The size listed here is what works with SPINOR_OP_SE, which isn't - * necessarily called a "sector" by the vendor. - */ - unsigned sector_size; - u16 n_sectors; - - u16 page_size; - u16 addr_width; - - 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 */ -#define SPI_NOR_NO_FR BIT(3) /* Can't do fastread */ -#define SECT_4K_PMC BIT(4) /* SPINOR_OP_BE_4K_PMC works uniformly */ -#define SPI_NOR_DUAL_READ BIT(5) /* Flash supports Dual Read */ -#define SPI_NOR_QUAD_READ BIT(6) /* Flash supports Quad Read */ -#define USE_FSR BIT(7) /* use flag status register */ -#define SPI_NOR_HAS_LOCK BIT(8) /* Flash supports lock/unlock via SR */ -#define SPI_NOR_HAS_TB BIT(9) /* - * Flash SR has Top/Bottom (TB) protect - * 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 - * because it has the same value as - * ATMEL flashes) - */ -#define SPI_NOR_4B_OPCODES BIT(11) /* - * Use dedicated 4byte address op codes - * to support memory size above 128Mib. - */ -#define NO_CHIP_ERASE BIT(12) /* Chip does not support chip erase */ -#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; -}; - -#define JEDEC_MFR(info) ((info)->id[0]) - -/** - * 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 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; - - 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); - } - } - - 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; -} - -/** - * 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 ssize_t spi_nor_spimem_read_data(struct spi_nor *nor, loff_t from, - size_t len, u8 *buf) -{ - 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); -} - -/** - * 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 nor->controller_ops->read(nor, from, len, buf); -} - -/** - * 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 ssize_t spi_nor_spimem_write_data(struct spi_nor *nor, loff_t to, - size_t len, const u8 *buf) -{ - 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)); - - 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 spi_nor_spimem_xfer_data(nor, &op); -} - -/** - * 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 ssize_t spi_nor_write_data(struct spi_nor *nor, loff_t to, size_t len, - const u8 *buf) -{ - if (nor->spimem) - return spi_nor_spimem_write_data(nor, to, len, buf); - - return nor->controller_ops->write(nor, to, len, buf); -} - -/** - * 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 spi_nor_write_enable(struct spi_nor *nor) -{ - 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; -} - -/** - * 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 spi_nor_write_disable(struct spi_nor *nor) -{ - 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; -} - -/** - * 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) -{ - 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)); - - 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) -{ - int ret; - - 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)); - - 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; -} - -/** - * 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) -{ - int ret; - - 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)); - - 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; -} - -/** - * 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) -{ - int ret; - - 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; -} - -/** - * 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) -{ - int ret; - - 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); -} - -/** - * 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) -{ - int ret; - - 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); - } - - if (ret) - dev_dbg(nor->dev, "error %d setting 4-byte mode\n", ret); - - return ret; -} - -/** - * 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; -} - -/** - * 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 ret; - - ret = macronix_set_4byte(nor, enable); - if (ret || enable) - return ret; - - /* - * 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; - - ret = spi_nor_write_ear(nor, 0); - if (ret) - return ret; - - 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; - - 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); - } - - 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 ret = spi_nor_read_sr(nor, nor->bouncebuf); - - 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"); - - spi_nor_clear_sr(nor); - return -EIO; - } - - 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 ret = spi_nor_read_fsr(nor, nor->bouncebuf); - - 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 (nor->bouncebuf[0] & FSR_PT_ERR) - dev_err(nor->dev, - "Attempted to modify a protected sector.\n"); - - spi_nor_clear_fsr(nor); - return -EIO; - } - - 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; - - if (nor->flags & SNOR_F_READY_XSR_RDY) - sr = s3an_sr_ready(nor); - else - sr = spi_nor_sr_ready(nor); - if (sr < 0) - return sr; - fsr = nor->flags & SNOR_F_USE_FSR ? spi_nor_fsr_ready(nor) : 1; - if (fsr < 0) - return fsr; - return sr && fsr; -} - -/** - * 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) -{ - unsigned long deadline; - int timeout = 0, ret; - - deadline = jiffies + timeout_jiffies; - - while (!timeout) { - if (time_after_eq(jiffies, deadline)) - timeout = 1; - - ret = spi_nor_ready(nor); - if (ret < 0) - return ret; - if (ret) - return 0; - - cond_resched(); - } - - 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); -} - -/** - * 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. - * - * Return: 0 on success, -errno otherwise. - */ -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 |