Skip to content

Commit

Permalink
Merge tag 'spi-nor/for-6.2' into mtd/next
Browse files Browse the repository at this point in the history
SPI NOR core changes:
* Add support for flash reset using the dt reset-gpios property.
* Update hwcaps.mask to include 8D-8D-8D read and page program ops
  when xSPI profile 1.0 table is defined.
* Bypass zero erase size in spi_nor_find_best_erase_type().
* Fix select_uniform_erase to skip 0 erase size
* Add generic flash driver. If a flash is not found in the flash_info
  array, fall back to the generic flash driver which is described solely
  by the flash's SFDP tables.
* Fix the number of bytes for the dummy cycles in
  spi_nor_spimem_check_readop().
* Introduce SPI_NOR_QUAD_PP flag, as PP_1_1_4 is not SFDP discoverable.

SPI NOR manufacturer drivers changes:
* Spansion:
  - use PARSE_SFDP for s28hs512t,
  - add support for s28hl512t, s28hl01gt, and s28hs01gt.
* Gigadevice: Replace default_init() with post_bfpt() for gd25q256.
* Micron - ST: Enable locking for mt25qu256a.
* Winbond: Add support for W25Q512NW-IQ.
* ISSI: Use PARSE_SFDP and SPI_NOR_QUAD_PP.

Fix merge conflict in the jedec,spi-nor bindings.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
  • Loading branch information
miquelraynal committed Dec 5, 2022
2 parents 1d46f1a + 1799cd8 commit a34506e
Show file tree
Hide file tree
Showing 14 changed files with 228 additions and 45 deletions.
6 changes: 6 additions & 0 deletions Documentation/ABI/testing/sysfs-bus-spi-devices-spi-nor
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,19 @@ Contact: linux-mtd@lists.infradead.org
Description: (RO) The JEDEC ID of the SPI NOR flash as reported by the
flash device.

The attribute is not present if the flash doesn't support
the "Read JEDEC ID" command (9Fh). This is the case for
non-JEDEC compliant flashes.

What: /sys/bus/spi/devices/.../spi-nor/manufacturer
Date: April 2021
KernelVersion: 5.14
Contact: linux-mtd@lists.infradead.org
Description: (RO) Manufacturer of the SPI NOR flash.

The attribute is not present if the flash device isn't
known to the kernel and is only probed by its SFDP
tables.

What: /sys/bus/spi/devices/.../spi-nor/partname
Date: April 2021
Expand Down
8 changes: 8 additions & 0 deletions Documentation/devicetree/bindings/mtd/jedec,spi-nor.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,17 @@ properties:
be used on such systems, to denote the absence of a reliable reset
mechanism.

reset-gpios:
description:
A GPIO line connected to the RESET (active low) signal of the device.
If "broken-flash-reset" is present then having this property does not
make any difference.

unevaluatedProperties: false

examples:
- |
#include <dt-bindings/gpio/gpio.h>
spi {
#address-cells = <1>;
#size-cells = <0>;
Expand All @@ -83,6 +90,7 @@ examples:
reg = <0>;
spi-max-frequency = <40000000>;
m25p,fast-read;
reset-gpios = <&gpio 12 GPIO_ACTIVE_LOW>;
};
};
...
85 changes: 80 additions & 5 deletions drivers/mtd/spi-nor/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -1184,6 +1184,8 @@ spi_nor_find_best_erase_type(const struct spi_nor_erase_map *map,
continue;

erase = &map->erase_type[i];
if (!erase->size)
continue;

/* Alignment is not mandatory for overlaid regions */
if (region->offset & SNOR_OVERLAID_REGION &&
Expand Down Expand Up @@ -1632,6 +1634,16 @@ static const struct spi_nor_manufacturer *manufacturers[] = {
&spi_nor_xmc,
};

static const struct flash_info spi_nor_generic_flash = {
.name = "spi-nor-generic",
/*
* JESD216 rev A doesn't specify the page size, therefore we need a
* sane default.
*/
.page_size = 256,
.parse_sfdp = true,
};

static const struct flash_info *spi_nor_match_id(struct spi_nor *nor,
const u8 *id)
{
Expand Down Expand Up @@ -1664,7 +1676,20 @@ static const struct flash_info *spi_nor_detect(struct spi_nor *nor)
return ERR_PTR(ret);
}

/* Cache the complete flash ID. */
nor->id = devm_kmemdup(nor->dev, id, SPI_NOR_MAX_ID_LEN, GFP_KERNEL);
if (!nor->id)
return ERR_PTR(-ENOMEM);

info = spi_nor_match_id(nor, id);

/* Fallback to a generic flash described only by its SFDP data. */
if (!info) {
ret = spi_nor_check_sfdp_signature(nor);
if (!ret)
info = &spi_nor_generic_flash;
}

if (!info) {
dev_err(nor->dev, "unrecognized JEDEC id bytes: %*ph\n",
SPI_NOR_MAX_ID_LEN, id);
Expand Down Expand Up @@ -1914,7 +1939,8 @@ static int spi_nor_spimem_check_readop(struct spi_nor *nor,
spi_nor_spimem_setup_op(nor, &op, read->proto);

/* convert the dummy cycles to the number of bytes */
op.dummy.nbytes = (nor->read_dummy * op.dummy.buswidth) / 8;
op.dummy.nbytes = (read->num_mode_clocks + read->num_wait_states) *
op.dummy.buswidth / 8;
if (spi_nor_protocol_is_dtr(nor->read_proto))
op.dummy.nbytes *= 2;

Expand Down Expand Up @@ -2091,8 +2117,12 @@ static int spi_nor_select_pp(struct spi_nor *nor,
* spi_nor_select_uniform_erase() - select optimum uniform erase type
* @map: the erase map of the SPI NOR
* @wanted_size: the erase type size to search for. Contains the value of
* info->sector_size or of the "small sector" size in case
* CONFIG_MTD_SPI_NOR_USE_4K_SECTORS is defined.
* info->sector_size, the "small sector" size in case
* CONFIG_MTD_SPI_NOR_USE_4K_SECTORS is defined or 0 if
* there is no information about the sector size. The
* latter is the case if the flash parameters are parsed
* solely by SFDP, then the largest supported erase type
* is selected.
*
* Once the optimum uniform sector erase command is found, disable all the
* other.
Expand All @@ -2113,6 +2143,10 @@ spi_nor_select_uniform_erase(struct spi_nor_erase_map *map,

tested_erase = &map->erase_type[i];

/* Skip masked erase types. */
if (!tested_erase->size)
continue;

/*
* If the current erase size is the one, stop here:
* we have found the right uniform Sector Erase command.
Expand Down Expand Up @@ -2565,6 +2599,12 @@ static void spi_nor_init_default_params(struct spi_nor *nor)
params->hwcaps.mask |= SNOR_HWCAPS_PP;
spi_nor_set_pp_settings(&params->page_programs[SNOR_CMD_PP],
SPINOR_OP_PP, SNOR_PROTO_1_1_1);

if (info->flags & SPI_NOR_QUAD_PP) {
params->hwcaps.mask |= SNOR_HWCAPS_PP_1_1_4;
spi_nor_set_pp_settings(&params->page_programs[SNOR_CMD_PP_1_1_4],
SPINOR_OP_PP_1_1_4, SNOR_PROTO_1_1_4);
}
}

/**
Expand Down Expand Up @@ -2840,10 +2880,20 @@ static void spi_nor_put_device(struct mtd_info *mtd)

void spi_nor_restore(struct spi_nor *nor)
{
int ret;

/* restore the addressing mode */
if (nor->addr_nbytes == 4 && !(nor->flags & SNOR_F_4B_OPCODES) &&
nor->flags & SNOR_F_BROKEN_RESET)
nor->params->set_4byte_addr_mode(nor, false);
nor->flags & SNOR_F_BROKEN_RESET) {
ret = nor->params->set_4byte_addr_mode(nor, false);
if (ret)
/*
* Do not stop the execution in the hope that the flash
* will default to the 3-byte address mode after the
* software reset.
*/
dev_err(nor->dev, "Failed to exit 4-byte address mode, err = %d\n", ret);
}

if (nor->flags & SNOR_F_SOFT_RESET)
spi_nor_soft_reset(nor);
Expand Down Expand Up @@ -2935,6 +2985,27 @@ static void spi_nor_set_mtd_info(struct spi_nor *nor)
mtd->_put_device = spi_nor_put_device;
}

static int spi_nor_hw_reset(struct spi_nor *nor)
{
struct gpio_desc *reset;

reset = devm_gpiod_get_optional(nor->dev, "reset", GPIOD_OUT_LOW);
if (IS_ERR_OR_NULL(reset))
return PTR_ERR_OR_ZERO(reset);

/*
* Experimental delay values by looking at different flash device
* vendors datasheets.
*/
usleep_range(1, 5);
gpiod_set_value_cansleep(reset, 1);
usleep_range(100, 150);
gpiod_set_value_cansleep(reset, 0);
usleep_range(1000, 1200);

return 0;
}

int spi_nor_scan(struct spi_nor *nor, const char *name,
const struct spi_nor_hwcaps *hwcaps)
{
Expand Down Expand Up @@ -2967,6 +3038,10 @@ int spi_nor_scan(struct spi_nor *nor, const char *name,
if (!nor->bouncebuf)
return -ENOMEM;

ret = spi_nor_hw_reset(nor);
if (ret)
return ret;

info = spi_nor_get_flash_info(nor, name);
if (IS_ERR(info))
return PTR_ERR(info);
Expand Down
5 changes: 5 additions & 0 deletions drivers/mtd/spi-nor/core.h
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,7 @@ struct spi_nor_fixups {
* SPI_NOR_NO_ERASE: no erase command needed.
* NO_CHIP_ERASE: chip does not support chip erase.
* SPI_NOR_NO_FR: can't do fastread.
* SPI_NOR_QUAD_PP: flash supports Quad Input Page Program.
*
* @no_sfdp_flags: flags that indicate support that can be discovered via SFDP.
* Used when SFDP tables are not defined in the flash. These
Expand Down Expand Up @@ -507,6 +508,7 @@ struct flash_info {
#define SPI_NOR_NO_ERASE BIT(6)
#define NO_CHIP_ERASE BIT(7)
#define SPI_NOR_NO_FR BIT(8)
#define SPI_NOR_QUAD_PP BIT(9)

u8 no_sfdp_flags;
#define SPI_NOR_SKIP_SFDP BIT(0)
Expand Down Expand Up @@ -701,6 +703,9 @@ int spi_nor_controller_ops_read_reg(struct spi_nor *nor, u8 opcode,
int spi_nor_controller_ops_write_reg(struct spi_nor *nor, u8 opcode,
const u8 *buf, size_t len);

int spi_nor_check_sfdp_signature(struct spi_nor *nor);
int spi_nor_parse_sfdp(struct spi_nor *nor);

static inline struct spi_nor *mtd_to_spi_nor(struct mtd_info *mtd)
{
return container_of(mtd, struct spi_nor, mtd);
Expand Down
2 changes: 1 addition & 1 deletion drivers/mtd/spi-nor/debugfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ static int spi_nor_params_show(struct seq_file *s, void *data)
int i;

seq_printf(s, "name\t\t%s\n", info->name);
seq_printf(s, "id\t\t%*ph\n", info->id_len, info->id);
seq_printf(s, "id\t\t%*ph\n", SPI_NOR_MAX_ID_LEN, nor->id);
string_get_size(params->size, 1, STRING_UNITS_2, buf, sizeof(buf));
seq_printf(s, "size\t\t%s\n", buf);
seq_printf(s, "write size\t%u\n", params->writesize);
Expand Down
24 changes: 17 additions & 7 deletions drivers/mtd/spi-nor/gigadevice.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,29 @@

#include "core.h"

static void gd25q256_default_init(struct spi_nor *nor)
static int
gd25q256_post_bfpt(struct spi_nor *nor,
const struct sfdp_parameter_header *bfpt_header,
const struct sfdp_bfpt *bfpt)
{
/*
* 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.
* GD25Q256C supports the first version of JESD216 which does not define
* the Quad Enable methods. Overwrite the default Quad Enable method.
*
* GD25Q256 GENERATION | SFDP MAJOR VERSION | SFDP MINOR VERSION
* GD25Q256C | SFDP_JESD216_MAJOR | SFDP_JESD216_MINOR
* GD25Q256D | SFDP_JESD216_MAJOR | SFDP_JESD216B_MINOR
* GD25Q256E | SFDP_JESD216_MAJOR | SFDP_JESD216B_MINOR
*/
nor->params->quad_enable = spi_nor_sr1_bit6_quad_enable;
if (bfpt_header->major == SFDP_JESD216_MAJOR &&
bfpt_header->minor == SFDP_JESD216_MINOR)
nor->params->quad_enable = spi_nor_sr1_bit6_quad_enable;

return 0;
}

static const struct spi_nor_fixups gd25q256_fixups = {
.default_init = gd25q256_default_init,
.post_bfpt = gd25q256_post_bfpt,
};

static const struct flash_info gigadevice_nor_parts[] = {
Expand Down
5 changes: 3 additions & 2 deletions drivers/mtd/spi-nor/issi.c
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,10 @@ static const struct flash_info issi_nor_parts[] = {
NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ "is25wp128", INFO(0x9d7018, 0, 64 * 1024, 256)
NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ "is25wp256", INFO(0x9d7019, 0, 64 * 1024, 512)
NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)
{ "is25wp256", INFO(0x9d7019, 0, 0, 0)
PARSE_SFDP
FIXUP_FLAGS(SPI_NOR_4B_OPCODES)
FLAGS(SPI_NOR_QUAD_PP)
.fixups = &is25lp256_fixups },

/* PMC */
Expand Down
12 changes: 9 additions & 3 deletions drivers/mtd/spi-nor/micron-st.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,18 +52,21 @@ static int micron_st_nor_octal_dtr_en(struct spi_nor *nor)
struct spi_mem_op op;
u8 *buf = nor->bouncebuf;
int ret;
u8 addr_mode_nbytes = nor->params->addr_mode_nbytes;

/* Use 20 dummy cycles for memory array reads. */
*buf = 20;
op = (struct spi_mem_op)
MICRON_ST_NOR_WR_ANY_REG_OP(3, SPINOR_REG_MT_CFR1V, 1, buf);
MICRON_ST_NOR_WR_ANY_REG_OP(addr_mode_nbytes,
SPINOR_REG_MT_CFR1V, 1, buf);
ret = spi_nor_write_any_volatile_reg(nor, &op, nor->reg_proto);
if (ret)
return ret;

buf[0] = SPINOR_MT_OCT_DTR;
op = (struct spi_mem_op)
MICRON_ST_NOR_WR_ANY_REG_OP(3, SPINOR_REG_MT_CFR0V, 1, buf);
MICRON_ST_NOR_WR_ANY_REG_OP(addr_mode_nbytes,
SPINOR_REG_MT_CFR0V, 1, buf);
ret = spi_nor_write_any_volatile_reg(nor, &op, nor->reg_proto);
if (ret)
return ret;
Expand Down Expand Up @@ -98,7 +101,8 @@ static int micron_st_nor_octal_dtr_dis(struct spi_nor *nor)
buf[0] = SPINOR_MT_EXSPI;
buf[1] = SPINOR_REG_MT_CFR1V_DEF;
op = (struct spi_mem_op)
MICRON_ST_NOR_WR_ANY_REG_OP(4, SPINOR_REG_MT_CFR0V, 2, buf);
MICRON_ST_NOR_WR_ANY_REG_OP(nor->addr_nbytes,
SPINOR_REG_MT_CFR0V, 2, buf);
ret = spi_nor_write_any_volatile_reg(nor, &op, SNOR_PROTO_8_8_8_DTR);
if (ret)
return ret;
Expand Down Expand Up @@ -201,6 +205,8 @@ static const struct flash_info st_nor_parts[] = {
MFR_FLAGS(USE_FSR)
},
{ "mt25qu256a", INFO6(0x20bb19, 0x104400, 64 * 1024, 512)
FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_4BIT_BP |
SPI_NOR_BP3_SR_BIT6)
NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)
FIXUP_FLAGS(SPI_NOR_4B_OPCODES)
MFR_FLAGS(USE_FSR)
Expand Down
37 changes: 35 additions & 2 deletions drivers/mtd/spi-nor/sfdp.c
Original file line number Diff line number Diff line change
Expand Up @@ -135,8 +135,7 @@ struct sfdp_4bait {
/**
* spi_nor_read_raw() - raw read of serial flash memory. read_opcode,
* addr_nbytes and read_dummy members of the struct spi_nor
* should be previously
* set.
* should be previously set.
* @nor: pointer to a 'struct spi_nor'
* @addr: offset in the serial flash memory
* @len: number of bytes to read
Expand Down Expand Up @@ -1183,10 +1182,17 @@ static int spi_nor_parse_profile1(struct spi_nor *nor,
dummy = round_up(dummy, 2);

/* Update the fast read settings. */
nor->params->hwcaps.mask |= SNOR_HWCAPS_READ_8_8_8_DTR;
spi_nor_set_read_settings(&nor->params->reads[SNOR_CMD_READ_8_8_8_DTR],
0, dummy, opcode,
SNOR_PROTO_8_8_8_DTR);

/*
* Page Program is "Required Command" in the xSPI Profile 1.0. Update
* the params->hwcaps.mask here.
*/
nor->params->hwcaps.mask |= SNOR_HWCAPS_PP_8_8_8_DTR;

out:
kfree(dwords);
return ret;
Expand Down Expand Up @@ -1249,6 +1255,33 @@ static void spi_nor_post_sfdp_fixups(struct spi_nor *nor)
nor->info->fixups->post_sfdp(nor);
}

/**
* spi_nor_check_sfdp_signature() - check for a valid SFDP signature
* @nor: pointer to a 'struct spi_nor'
*
* Used to detect if the flash supports the RDSFDP command as well as the
* presence of a valid SFDP table.
*
* Return: 0 on success, -errno otherwise.
*/
int spi_nor_check_sfdp_signature(struct spi_nor *nor)
{
u32 signature;
int err;

/* Get the SFDP header. */
err = spi_nor_read_sfdp_dma_unsafe(nor, 0, sizeof(signature),
&signature);
if (err < 0)
return err;

/* Check the SFDP signature. */
if (le32_to_cpu(signature) != SFDP_SIGNATURE)
return -EINVAL;

return 0;
}

/**
* spi_nor_parse_sfdp() - parse the Serial Flash Discoverable Parameters.
* @nor: pointer to a 'struct spi_nor'
Expand Down
Loading

0 comments on commit a34506e

Please sign in to comment.