Skip to content

Commit

Permalink
Merge tag 'spi-nor/for-6.6' into mtd/next
Browse files Browse the repository at this point in the history
SPI NOR core changes:
* fix assumption on enabling quad mode in
  spi_nor_write_16bit_sr_and_check()
* avoid setting SRWD bit in SR if WP# signal not connected as it will
  configure the SR permanently as read only. Add "no-wp" dt property.
* clarify the need for spi-nor compatibles in dt-bindings

SPI NOR manufacturer drivers changes:
* spansion:
  - add support for S28HS02GT
  - switch methods to use vreg_offset from SFDP instead of hardcoding
    the register value
* microchip/sst:
  - add support for sst26vf032b flash
* winbond:
  - correct flags for Winbond w25q128

Signed-off-by: Miquel Raynal <[email protected]>
  • Loading branch information
miquelraynal committed Aug 18, 2023
2 parents a417ab3 + 69d50d0 commit f7091fb
Show file tree
Hide file tree
Showing 14 changed files with 312 additions and 185 deletions.
21 changes: 19 additions & 2 deletions Documentation/devicetree/bindings/mtd/jedec,spi-nor.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,10 @@ properties:
- const: jedec,spi-nor
- const: jedec,spi-nor
description:
Must also include "jedec,spi-nor" for any SPI NOR flash that can be
identified by the JEDEC READ ID opcode (0x9F).
SPI NOR flashes compatible with the JEDEC SFDP standard or which may be
identified with the READ ID opcode (0x9F) do not deserve a specific
compatible. They should instead only be matched against the generic
"jedec,spi-nor" compatible.

reg:
minItems: 1
Expand All @@ -70,6 +72,21 @@ properties:
be used on such systems, to denote the absence of a reliable reset
mechanism.

no-wp:
type: boolean
description:
The status register write disable (SRWD) bit in status register, combined
with the WP# signal, provides hardware data protection for the device. When
the SRWD bit is set to 1, and the WP# signal is either driven LOW or hard
strapped to LOW, the status register nonvolatile bits become read-only and
the WRITE STATUS REGISTER operation will not execute. The only way to exit
this hardware-protected mode is to drive WP# HIGH. If the WP# signal of the
flash device is not connected or is wrongly tied to GND (that includes internal
pull-downs) then status register permanently becomes read-only as the SRWD bit
cannot be reset. This boolean flag can be used on such systems to avoid setting
the SRWD bit while writing the status register. WP# signal hard strapped to GND
can be a valid use case.

reset-gpios:
description:
A GPIO line connected to the RESET (active low) signal of the device.
Expand Down
8 changes: 6 additions & 2 deletions drivers/mtd/spi-nor/atmel.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,11 @@ static const struct spi_nor_locking_ops at25fs_nor_locking_ops = {
.is_locked = at25fs_nor_is_locked,
};

static void at25fs_nor_late_init(struct spi_nor *nor)
static int at25fs_nor_late_init(struct spi_nor *nor)
{
nor->params->locking_ops = &at25fs_nor_locking_ops;

return 0;
}

static const struct spi_nor_fixups at25fs_nor_fixups = {
Expand Down Expand Up @@ -149,9 +151,11 @@ static const struct spi_nor_locking_ops atmel_nor_global_protection_ops = {
.is_locked = atmel_nor_is_global_protected,
};

static void atmel_nor_global_protection_late_init(struct spi_nor *nor)
static int atmel_nor_global_protection_late_init(struct spi_nor *nor)
{
nor->params->locking_ops = &atmel_nor_global_protection_ops;

return 0;
}

static const struct spi_nor_fixups atmel_nor_global_protection_fixups = {
Expand Down
33 changes: 6 additions & 27 deletions drivers/mtd/spi-nor/controllers/nxp-spifi.c
Original file line number Diff line number Diff line change
Expand Up @@ -394,30 +394,18 @@ static int nxp_spifi_probe(struct platform_device *pdev)
if (IS_ERR(spifi->flash_base))
return PTR_ERR(spifi->flash_base);

spifi->clk_spifi = devm_clk_get(&pdev->dev, "spifi");
spifi->clk_spifi = devm_clk_get_enabled(&pdev->dev, "spifi");
if (IS_ERR(spifi->clk_spifi)) {
dev_err(&pdev->dev, "spifi clock not found\n");
dev_err(&pdev->dev, "spifi clock not found or unable to enable\n");
return PTR_ERR(spifi->clk_spifi);
}

spifi->clk_reg = devm_clk_get(&pdev->dev, "reg");
spifi->clk_reg = devm_clk_get_enabled(&pdev->dev, "reg");
if (IS_ERR(spifi->clk_reg)) {
dev_err(&pdev->dev, "reg clock not found\n");
dev_err(&pdev->dev, "reg clock not found or unable to enable\n");
return PTR_ERR(spifi->clk_reg);
}

ret = clk_prepare_enable(spifi->clk_reg);
if (ret) {
dev_err(&pdev->dev, "unable to enable reg clock\n");
return ret;
}

ret = clk_prepare_enable(spifi->clk_spifi);
if (ret) {
dev_err(&pdev->dev, "unable to enable spifi clock\n");
goto dis_clk_reg;
}

spifi->dev = &pdev->dev;
platform_set_drvdata(pdev, spifi);

Expand All @@ -430,33 +418,24 @@ static int nxp_spifi_probe(struct platform_device *pdev)
flash_np = of_get_next_available_child(pdev->dev.of_node, NULL);
if (!flash_np) {
dev_err(&pdev->dev, "no SPI flash device to configure\n");
ret = -ENODEV;
goto dis_clks;
return -ENODEV;
}

ret = nxp_spifi_setup_flash(spifi, flash_np);
of_node_put(flash_np);
if (ret) {
dev_err(&pdev->dev, "unable to setup flash chip\n");
goto dis_clks;
return ret;
}

return 0;

dis_clks:
clk_disable_unprepare(spifi->clk_spifi);
dis_clk_reg:
clk_disable_unprepare(spifi->clk_reg);
return ret;
}

static int nxp_spifi_remove(struct platform_device *pdev)
{
struct nxp_spifi *spifi = platform_get_drvdata(pdev);

mtd_device_unregister(&spifi->nor.mtd);
clk_disable_unprepare(spifi->clk_spifi);
clk_disable_unprepare(spifi->clk_reg);

return 0;
}
Expand Down
57 changes: 34 additions & 23 deletions drivers/mtd/spi-nor/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -870,21 +870,22 @@ static int spi_nor_write_16bit_sr_and_check(struct spi_nor *nor, u8 sr1)
ret = spi_nor_read_cr(nor, &sr_cr[1]);
if (ret)
return ret;
} else if (nor->params->quad_enable) {
} else if (spi_nor_get_protocol_width(nor->read_proto) == 4 &&
spi_nor_get_protocol_width(nor->write_proto) == 4 &&
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.
* When the Quad Enable method is set and the buswidth is 4, we
* can safely assume that 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).
* 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 {
Expand Down Expand Up @@ -2844,6 +2845,9 @@ static void spi_nor_init_flags(struct spi_nor *nor)
if (of_property_read_bool(np, "broken-flash-reset"))
nor->flags |= SNOR_F_BROKEN_RESET;

if (of_property_read_bool(np, "no-wp"))
nor->flags |= SNOR_F_NO_WP;

if (flags & SPI_NOR_SWP_IS_VOLATILE)
nor->flags |= SNOR_F_SWP_IS_VOLATILE;

Expand Down Expand Up @@ -2897,16 +2901,23 @@ static void spi_nor_init_fixup_flags(struct spi_nor *nor)
* SFDP standard, or where SFDP tables are not defined at all.
* Will replace the spi_nor_manufacturer_init_params() method.
*/
static void spi_nor_late_init_params(struct spi_nor *nor)
static int spi_nor_late_init_params(struct spi_nor *nor)
{
struct spi_nor_flash_parameter *params = nor->params;
int ret;

if (nor->manufacturer && nor->manufacturer->fixups &&
nor->manufacturer->fixups->late_init)
nor->manufacturer->fixups->late_init(nor);
nor->manufacturer->fixups->late_init) {
ret = nor->manufacturer->fixups->late_init(nor);
if (ret)
return ret;
}

if (nor->info->fixups && nor->info->fixups->late_init)
nor->info->fixups->late_init(nor);
if (nor->info->fixups && nor->info->fixups->late_init) {
ret = nor->info->fixups->late_init(nor);
if (ret)
return ret;
}

/* Default method kept for backward compatibility. */
if (!params->set_4byte_addr_mode)
Expand All @@ -2924,6 +2935,8 @@ static void spi_nor_late_init_params(struct spi_nor *nor)

if (nor->info->n_banks > 1)
params->bank_size = div64_u64(params->size, nor->info->n_banks);

return 0;
}

/**
Expand Down Expand Up @@ -3082,22 +3095,20 @@ static int spi_nor_init_params(struct spi_nor *nor)
spi_nor_init_params_deprecated(nor);
}

spi_nor_late_init_params(nor);

return 0;
return spi_nor_late_init_params(nor);
}

/** spi_nor_octal_dtr_enable() - enable Octal DTR I/O if needed
/** spi_nor_set_octal_dtr() - enable or disable Octal DTR I/O.
* @nor: pointer to a 'struct spi_nor'
* @enable: whether to enable or disable Octal DTR
*
* Return: 0 on success, -errno otherwise.
*/
static int spi_nor_octal_dtr_enable(struct spi_nor *nor, bool enable)
static int spi_nor_set_octal_dtr(struct spi_nor *nor, bool enable)
{
int ret;

if (!nor->params->octal_dtr_enable)
if (!nor->params->set_octal_dtr)
return 0;

if (!(nor->read_proto == SNOR_PROTO_8_8_8_DTR &&
Expand All @@ -3107,7 +3118,7 @@ static int spi_nor_octal_dtr_enable(struct spi_nor *nor, bool enable)
if (!(nor->flags & SNOR_F_IO_MODE_EN_VOLATILE))
return 0;

ret = nor->params->octal_dtr_enable(nor, enable);
ret = nor->params->set_octal_dtr(nor, enable);
if (ret)
return ret;

Expand Down Expand Up @@ -3168,7 +3179,7 @@ static int spi_nor_init(struct spi_nor *nor)
{
int err;

err = spi_nor_octal_dtr_enable(nor, true);
err = spi_nor_set_octal_dtr(nor, true);
if (err) {
dev_dbg(nor->dev, "octal mode not supported\n");
return err;
Expand Down Expand Up @@ -3270,7 +3281,7 @@ static int spi_nor_suspend(struct mtd_info *mtd)
int ret;

/* Disable octal DTR mode if we enabled it. */
ret = spi_nor_octal_dtr_enable(nor, false);
ret = spi_nor_set_octal_dtr(nor, false);
if (ret)
dev_err(nor->dev, "suspend() failed\n");

Expand Down
9 changes: 6 additions & 3 deletions drivers/mtd/spi-nor/core.h
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ enum spi_nor_option_flags {
SNOR_F_SWP_IS_VOLATILE = BIT(13),
SNOR_F_RWW = BIT(14),
SNOR_F_ECC = BIT(15),
SNOR_F_NO_WP = BIT(16),
};

struct spi_nor_read_command {
Expand Down Expand Up @@ -363,7 +364,7 @@ struct spi_nor_otp {
* @erase_map: the erase map parsed from the SFDP Sector Map Parameter
* Table.
* @otp: SPI NOR OTP info.
* @octal_dtr_enable: enables SPI NOR octal DTR mode.
* @set_octal_dtr: enables or disables SPI NOR octal DTR mode.
* @quad_enable: enables SPI NOR quad mode.
* @set_4byte_addr_mode: puts the SPI NOR in 4 byte addressing mode.
* @convert_addr: converts an absolute address into something the flash
Expand All @@ -377,6 +378,7 @@ struct spi_nor_otp {
* than reading the status register to indicate they
* are ready for a new command
* @locking_ops: SPI NOR locking methods.
* @priv: flash's private data.
*/
struct spi_nor_flash_parameter {
u64 bank_size;
Expand All @@ -397,14 +399,15 @@ struct spi_nor_flash_parameter {
struct spi_nor_erase_map erase_map;
struct spi_nor_otp otp;

int (*octal_dtr_enable)(struct spi_nor *nor, bool enable);
int (*set_octal_dtr)(struct spi_nor *nor, bool enable);
int (*quad_enable)(struct spi_nor *nor);
int (*set_4byte_addr_mode)(struct spi_nor *nor, bool enable);
u32 (*convert_addr)(struct spi_nor *nor, u32 addr);
int (*setup)(struct spi_nor *nor, const struct spi_nor_hwcaps *hwcaps);
int (*ready)(struct spi_nor *nor);

const struct spi_nor_locking_ops *locking_ops;
void *priv;
};

/**
Expand All @@ -431,7 +434,7 @@ struct spi_nor_fixups {
const struct sfdp_parameter_header *bfpt_header,
const struct sfdp_bfpt *bfpt);
int (*post_sfdp)(struct spi_nor *nor);
void (*late_init)(struct spi_nor *nor);
int (*late_init)(struct spi_nor *nor);
};

/**
Expand Down
1 change: 1 addition & 0 deletions drivers/mtd/spi-nor/debugfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ static const char *const snor_f_names[] = {
SNOR_F_NAME(SWP_IS_VOLATILE),
SNOR_F_NAME(RWW),
SNOR_F_NAME(ECC),
SNOR_F_NAME(NO_WP),
};
#undef SNOR_F_NAME

Expand Down
4 changes: 3 additions & 1 deletion drivers/mtd/spi-nor/issi.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ static const struct spi_nor_fixups is25lp256_fixups = {
.post_bfpt = is25lp256_post_bfpt_fixups,
};

static void pm25lv_nor_late_init(struct spi_nor *nor)
static int pm25lv_nor_late_init(struct spi_nor *nor)
{
struct spi_nor_erase_map *map = &nor->params->erase_map;
int i;
Expand All @@ -38,6 +38,8 @@ static void pm25lv_nor_late_init(struct spi_nor *nor)
for (i = 0; i < SNOR_ERASE_TYPE_MAX; i++)
if (map->erase_type[i].size == 4096)
map->erase_type[i].opcode = SPINOR_OP_BE_4K_PMC;

return 0;
}

static const struct spi_nor_fixups pm25lv_nor_fixups = {
Expand Down
4 changes: 3 additions & 1 deletion drivers/mtd/spi-nor/macronix.c
Original file line number Diff line number Diff line change
Expand Up @@ -110,10 +110,12 @@ static void macronix_nor_default_init(struct spi_nor *nor)
nor->params->quad_enable = spi_nor_sr1_bit6_quad_enable;
}

static void macronix_nor_late_init(struct spi_nor *nor)
static int macronix_nor_late_init(struct spi_nor *nor)
{
if (!nor->params->set_4byte_addr_mode)
nor->params->set_4byte_addr_mode = spi_nor_set_4byte_addr_mode_en4b_ex4b;

return 0;
}

static const struct spi_nor_fixups macronix_nor_fixups = {
Expand Down
8 changes: 5 additions & 3 deletions drivers/mtd/spi-nor/micron-st.c
Original file line number Diff line number Diff line change
Expand Up @@ -120,15 +120,15 @@ static int micron_st_nor_octal_dtr_dis(struct spi_nor *nor)
return 0;
}

static int micron_st_nor_octal_dtr_enable(struct spi_nor *nor, bool enable)
static int micron_st_nor_set_octal_dtr(struct spi_nor *nor, bool enable)
{
return enable ? micron_st_nor_octal_dtr_en(nor) :
micron_st_nor_octal_dtr_dis(nor);
}

static void mt35xu512aba_default_init(struct spi_nor *nor)
{
nor->params->octal_dtr_enable = micron_st_nor_octal_dtr_enable;
nor->params->set_octal_dtr = micron_st_nor_set_octal_dtr;
}

static int mt35xu512aba_post_sfdp_fixup(struct spi_nor *nor)
Expand Down Expand Up @@ -429,7 +429,7 @@ static void micron_st_nor_default_init(struct spi_nor *nor)
nor->params->quad_enable = NULL;
}

static void micron_st_nor_late_init(struct spi_nor *nor)
static int micron_st_nor_late_init(struct spi_nor *nor)
{
struct spi_nor_flash_parameter *params = nor->params;

Expand All @@ -438,6 +438,8 @@ static void micron_st_nor_late_init(struct spi_nor *nor)

if (!params->set_4byte_addr_mode)
params->set_4byte_addr_mode = spi_nor_set_4byte_addr_mode_wren_en4b_ex4b;

return 0;
}

static const struct spi_nor_fixups micron_st_nor_fixups = {
Expand Down
Loading

0 comments on commit f7091fb

Please sign in to comment.