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 -----BEGIN PGP SIGNATURE----- iQEzBAABCgAdFiEEHUIqys8OyG1eHf7fS1VPR6WNFOkFAmTfS0cACgkQS1VPR6WN FOmCKwf/UJEfKyMsWlgO5WRqxzYsPow5SjjMY+XRLS+V6zpQZb//+COdESEbm5bL 1Lmo8e1J/I17sVn80KwHvnen3z+Nd6HqpgIRIlMWkitieiWgnGsAVqOpiR+5yY/n ki0gz4ne2nrLxB3223zqV5wYr6s1A7ZCOqAZQNPUjOkbHDkBVeex9p36jXStjR4w exbRNijsEYMrtthsuUY3rJd1n1a6yvaYkubclT/H6myzPgzeyaeWRw5cHjVBKh9D SQ1NUBEdljciyosJ4ugfsG6jnG7DpVacr7Zxl5F6caUmeiNBG/dgUvkIZzIxffkB BRvg0czpomB6sKEdY0j1QDPt0rtrdw== =uEXl -----END PGP SIGNATURE----- Merge tag 'spi-nor/for-6.6' into mtd/next 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 <miquel.raynal@bootlin.com>
This commit is contained in:
commit
f7091fb725
|
@ -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
|
||||
|
@ -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.
|
||||
|
|
|
@ -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 = {
|
||||
|
@ -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 = {
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
@ -430,24 +418,17 @@ 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)
|
||||
|
@ -455,8 +436,6 @@ 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;
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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 &&
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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");
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -397,7 +399,7 @@ 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);
|
||||
|
@ -405,6 +407,7 @@ struct spi_nor_flash_parameter {
|
|||
int (*ready)(struct spi_nor *nor);
|
||||
|
||||
const struct spi_nor_locking_ops *locking_ops;
|
||||
void *priv;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -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);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
@ -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 = {
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -120,7 +120,7 @@ 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);
|
||||
|
@ -128,7 +128,7 @@ static int micron_st_nor_octal_dtr_enable(struct spi_nor *nor, bool enable)
|
|||
|
||||
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)
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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 = {
|
||||
|
|
|
@ -4,14 +4,19 @@
|
|||
* Copyright (C) 2014, Freescale Semiconductor, Inc.
|
||||
*/
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/mtd/spi-nor.h>
|
||||
|
||||
#include "core.h"
|
||||
|
||||
/* flash_info mfr_flag. Used to clear sticky prorietary SR bits. */
|
||||
#define USE_CLSR BIT(0)
|
||||
#define USE_CLPEF BIT(1)
|
||||
|
||||
#define SPINOR_OP_CLSR 0x30 /* Clear status register 1 */
|
||||
#define SPINOR_OP_CLPEF 0x82 /* Clear program/erase failure flags */
|
||||
#define SPINOR_OP_RD_ANY_REG 0x65 /* Read any register */
|
||||
#define SPINOR_OP_WR_ANY_REG 0x71 /* Write any register */
|
||||
#define SPINOR_REG_CYPRESS_VREG 0x00800000
|
||||
|
@ -19,21 +24,16 @@
|
|||
#define SPINOR_REG_CYPRESS_STR1V \
|
||||
(SPINOR_REG_CYPRESS_VREG + SPINOR_REG_CYPRESS_STR1)
|
||||
#define SPINOR_REG_CYPRESS_CFR1 0x2
|
||||
#define SPINOR_REG_CYPRESS_CFR1V \
|
||||
(SPINOR_REG_CYPRESS_VREG + SPINOR_REG_CYPRESS_CFR1)
|
||||
#define SPINOR_REG_CYPRESS_CFR1_QUAD_EN BIT(1) /* Quad Enable */
|
||||
#define SPINOR_REG_CYPRESS_CFR2 0x3
|
||||
#define SPINOR_REG_CYPRESS_CFR2V \
|
||||
(SPINOR_REG_CYPRESS_VREG + SPINOR_REG_CYPRESS_CFR2)
|
||||
#define SPINOR_REG_CYPRESS_CFR2_MEMLAT_MASK GENMASK(3, 0)
|
||||
#define SPINOR_REG_CYPRESS_CFR2_MEMLAT_11_24 0xb
|
||||
#define SPINOR_REG_CYPRESS_CFR2_ADRBYT BIT(7)
|
||||
#define SPINOR_REG_CYPRESS_CFR3 0x4
|
||||
#define SPINOR_REG_CYPRESS_CFR3V \
|
||||
(SPINOR_REG_CYPRESS_VREG + SPINOR_REG_CYPRESS_CFR3)
|
||||
#define SPINOR_REG_CYPRESS_CFR3_PGSZ BIT(4) /* Page size. */
|
||||
#define SPINOR_REG_CYPRESS_CFR5 0x6
|
||||
#define SPINOR_REG_CYPRESS_CFR5V \
|
||||
(SPINOR_REG_CYPRESS_VREG + SPINOR_REG_CYPRESS_CFR5)
|
||||
#define SPINOR_REG_CYPRESS_CFR5_BIT6 BIT(6)
|
||||
#define SPINOR_REG_CYPRESS_CFR5_DDR BIT(1)
|
||||
#define SPINOR_REG_CYPRESS_CFR5_OPI BIT(0)
|
||||
|
@ -57,22 +57,32 @@
|
|||
SPI_MEM_OP_DUMMY(ndummy, 0), \
|
||||
SPI_MEM_OP_DATA_IN(1, buf, 0))
|
||||
|
||||
#define SPANSION_CLSR_OP \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_CLSR, 0), \
|
||||
#define SPANSION_OP(opcode) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(opcode, 0), \
|
||||
SPI_MEM_OP_NO_ADDR, \
|
||||
SPI_MEM_OP_NO_DUMMY, \
|
||||
SPI_MEM_OP_NO_DATA)
|
||||
|
||||
/**
|
||||
* struct spansion_nor_params - Spansion private parameters.
|
||||
* @clsr: Clear Status Register or Clear Program and Erase Failure Flag
|
||||
* opcode.
|
||||
*/
|
||||
struct spansion_nor_params {
|
||||
u8 clsr;
|
||||
};
|
||||
|
||||
/**
|
||||
* spansion_nor_clear_sr() - Clear the Status Register.
|
||||
* @nor: pointer to 'struct spi_nor'.
|
||||
*/
|
||||
static void spansion_nor_clear_sr(struct spi_nor *nor)
|
||||
{
|
||||
const struct spansion_nor_params *priv_params = nor->params->priv;
|
||||
int ret;
|
||||
|
||||
if (nor->spimem) {
|
||||
struct spi_mem_op op = SPANSION_CLSR_OP;
|
||||
struct spi_mem_op op = SPANSION_OP(priv_params->clsr);
|
||||
|
||||
spi_nor_spimem_setup_op(nor, &op, nor->reg_proto);
|
||||
|
||||
|
@ -88,11 +98,17 @@ static void spansion_nor_clear_sr(struct spi_nor *nor)
|
|||
|
||||
static int cypress_nor_sr_ready_and_clear_reg(struct spi_nor *nor, u64 addr)
|
||||
{
|
||||
struct spi_nor_flash_parameter *params = nor->params;
|
||||
struct spi_mem_op op =
|
||||
CYPRESS_NOR_RD_ANY_REG_OP(nor->params->addr_mode_nbytes, addr,
|
||||
CYPRESS_NOR_RD_ANY_REG_OP(params->addr_mode_nbytes, addr,
|
||||
0, nor->bouncebuf);
|
||||
int ret;
|
||||
|
||||
if (nor->reg_proto == SNOR_PROTO_8_8_8_DTR) {
|
||||
op.dummy.nbytes = params->rdsr_dummy;
|
||||
op.data.nbytes = 2;
|
||||
}
|
||||
|
||||
ret = spi_nor_read_any_reg(nor, &op, nor->reg_proto);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -141,18 +157,26 @@ static int cypress_nor_sr_ready_and_clear(struct spi_nor *nor)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int cypress_nor_octal_dtr_en(struct spi_nor *nor)
|
||||
static int cypress_nor_set_memlat(struct spi_nor *nor, u64 addr)
|
||||
{
|
||||
struct spi_mem_op op;
|
||||
u8 *buf = nor->bouncebuf;
|
||||
int ret;
|
||||
u8 addr_mode_nbytes = nor->params->addr_mode_nbytes;
|
||||
|
||||
/* Use 24 dummy cycles for memory array reads. */
|
||||
*buf = SPINOR_REG_CYPRESS_CFR2_MEMLAT_11_24;
|
||||
op = (struct spi_mem_op)
|
||||
CYPRESS_NOR_WR_ANY_REG_OP(addr_mode_nbytes,
|
||||
SPINOR_REG_CYPRESS_CFR2V, 1, buf);
|
||||
CYPRESS_NOR_RD_ANY_REG_OP(addr_mode_nbytes, addr, 0, buf);
|
||||
|
||||
ret = spi_nor_read_any_reg(nor, &op, nor->reg_proto);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Use 24 dummy cycles for memory array reads. */
|
||||
*buf &= ~SPINOR_REG_CYPRESS_CFR2_MEMLAT_MASK;
|
||||
*buf |= FIELD_PREP(SPINOR_REG_CYPRESS_CFR2_MEMLAT_MASK,
|
||||
SPINOR_REG_CYPRESS_CFR2_MEMLAT_11_24);
|
||||
op = (struct spi_mem_op)
|
||||
CYPRESS_NOR_WR_ANY_REG_OP(addr_mode_nbytes, addr, 1, buf);
|
||||
|
||||
ret = spi_nor_write_any_volatile_reg(nor, &op, nor->reg_proto);
|
||||
if (ret)
|
||||
|
@ -160,15 +184,41 @@ static int cypress_nor_octal_dtr_en(struct spi_nor *nor)
|
|||
|
||||
nor->read_dummy = 24;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cypress_nor_set_octal_dtr_bits(struct spi_nor *nor, u64 addr)
|
||||
{
|
||||
struct spi_mem_op op;
|
||||
u8 *buf = nor->bouncebuf;
|
||||
|
||||
/* Set the octal and DTR enable bits. */
|
||||
buf[0] = SPINOR_REG_CYPRESS_CFR5_OCT_DTR_EN;
|
||||
op = (struct spi_mem_op)
|
||||
CYPRESS_NOR_WR_ANY_REG_OP(addr_mode_nbytes,
|
||||
SPINOR_REG_CYPRESS_CFR5V, 1, buf);
|
||||
CYPRESS_NOR_WR_ANY_REG_OP(nor->params->addr_mode_nbytes,
|
||||
addr, 1, buf);
|
||||
|
||||
ret = spi_nor_write_any_volatile_reg(nor, &op, nor->reg_proto);
|
||||
if (ret)
|
||||
return ret;
|
||||
return spi_nor_write_any_volatile_reg(nor, &op, nor->reg_proto);
|
||||
}
|
||||
|
||||
static int cypress_nor_octal_dtr_en(struct spi_nor *nor)
|
||||
{
|
||||
const struct spi_nor_flash_parameter *params = nor->params;
|
||||
u8 *buf = nor->bouncebuf;
|
||||
u64 addr;
|
||||
int i, ret;
|
||||
|
||||
for (i = 0; i < params->n_dice; i++) {
|
||||
addr = params->vreg_offset[i] + SPINOR_REG_CYPRESS_CFR2;
|
||||
ret = cypress_nor_set_memlat(nor, addr);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
addr = params->vreg_offset[i] + SPINOR_REG_CYPRESS_CFR5;
|
||||
ret = cypress_nor_set_octal_dtr_bits(nor, addr);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Read flash ID to make sure the switch was successful. */
|
||||
ret = spi_nor_read_id(nor, nor->addr_nbytes, 3, buf,
|
||||
|
@ -184,11 +234,10 @@ static int cypress_nor_octal_dtr_en(struct spi_nor *nor)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int cypress_nor_octal_dtr_dis(struct spi_nor *nor)
|
||||
static int cypress_nor_set_single_spi_bits(struct spi_nor *nor, u64 addr)
|
||||
{
|
||||
struct spi_mem_op op;
|
||||
u8 *buf = nor->bouncebuf;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* The register is 1-byte wide, but 1-byte transactions are not allowed
|
||||
|
@ -198,11 +247,23 @@ static int cypress_nor_octal_dtr_dis(struct spi_nor *nor)
|
|||
buf[0] = SPINOR_REG_CYPRESS_CFR5_OCT_DTR_DS;
|
||||
buf[1] = 0;
|
||||
op = (struct spi_mem_op)
|
||||
CYPRESS_NOR_WR_ANY_REG_OP(nor->addr_nbytes,
|
||||
SPINOR_REG_CYPRESS_CFR5V, 2, buf);
|
||||
ret = spi_nor_write_any_volatile_reg(nor, &op, SNOR_PROTO_8_8_8_DTR);
|
||||
if (ret)
|
||||
return ret;
|
||||
CYPRESS_NOR_WR_ANY_REG_OP(nor->addr_nbytes, addr, 2, buf);
|
||||
return spi_nor_write_any_volatile_reg(nor, &op, SNOR_PROTO_8_8_8_DTR);
|
||||
}
|
||||
|
||||
static int cypress_nor_octal_dtr_dis(struct spi_nor *nor)
|
||||
{
|
||||
const struct spi_nor_flash_parameter *params = nor->params;
|
||||
u8 *buf = nor->bouncebuf;
|
||||
u64 addr;
|
||||
int i, ret;
|
||||
|
||||
for (i = 0; i < params->n_dice; i++) {
|
||||
addr = params->vreg_offset[i] + SPINOR_REG_CYPRESS_CFR5;
|
||||
ret = cypress_nor_set_single_spi_bits(nor, addr);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Read flash ID to make sure the switch was successful. */
|
||||
ret = spi_nor_read_id(nor, 0, 0, buf, SNOR_PROTO_1_1_1);
|
||||
|
@ -283,10 +344,6 @@ static int cypress_nor_quad_enable_volatile(struct spi_nor *nor)
|
|||
u8 i;
|
||||
int ret;
|
||||
|
||||
if (!params->n_dice)
|
||||
return cypress_nor_quad_enable_volatile_reg(nor,
|
||||
SPINOR_REG_CYPRESS_CFR1V);
|
||||
|
||||
for (i = 0; i < params->n_dice; i++) {
|
||||
addr = params->vreg_offset[i] + SPINOR_REG_CYPRESS_CFR1;
|
||||
ret = cypress_nor_quad_enable_volatile_reg(nor, addr);
|
||||
|
@ -408,28 +465,17 @@ static int cypress_nor_set_addr_mode_nbytes(struct spi_nor *nor)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int cypress_nor_get_page_size_single_chip(struct spi_nor *nor)
|
||||
{
|
||||
struct spi_mem_op op =
|
||||
CYPRESS_NOR_RD_ANY_REG_OP(nor->params->addr_mode_nbytes,
|
||||
SPINOR_REG_CYPRESS_CFR3V, 0,
|
||||
nor->bouncebuf);
|
||||
int ret;
|
||||
|
||||
ret = spi_nor_read_any_reg(nor, &op, nor->reg_proto);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (nor->bouncebuf[0] & SPINOR_REG_CYPRESS_CFR3_PGSZ)
|
||||
nor->params->page_size = 512;
|
||||
else
|
||||
nor->params->page_size = 256;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int cypress_nor_get_page_size_mcp(struct spi_nor *nor)
|
||||
/**
|
||||
* cypress_nor_get_page_size() - Get flash page size configuration.
|
||||
* @nor: pointer to a 'struct spi_nor'
|
||||
*
|
||||
* The BFPT table advertises a 512B or 256B page size depending on part but the
|
||||
* page size is actually configurable (with the default being 256B). Read from
|
||||
* CFR3V[4] and set the correct size.
|
||||
*
|
||||
* Return: 0 on success, -errno otherwise.
|
||||
*/
|
||||
static int cypress_nor_get_page_size(struct spi_nor *nor)
|
||||
{
|
||||
struct spi_mem_op op =
|
||||
CYPRESS_NOR_RD_ANY_REG_OP(nor->params->addr_mode_nbytes,
|
||||
|
@ -459,23 +505,6 @@ static int cypress_nor_get_page_size_mcp(struct spi_nor *nor)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* cypress_nor_get_page_size() - Get flash page size configuration.
|
||||
* @nor: pointer to a 'struct spi_nor'
|
||||
*
|
||||
* The BFPT table advertises a 512B or 256B page size depending on part but the
|
||||
* page size is actually configurable (with the default being 256B). Read from
|
||||
* CFR3V[4] and set the correct size.
|
||||
*
|
||||
* Return: 0 on success, -errno otherwise.
|
||||
*/
|
||||
static int cypress_nor_get_page_size(struct spi_nor *nor)
|
||||
{
|
||||
if (nor->params->n_dice)
|
||||
return cypress_nor_get_page_size_mcp(nor);
|
||||
return cypress_nor_get_page_size_single_chip(nor);
|
||||
}
|
||||
|
||||
static void cypress_nor_ecc_init(struct spi_nor *nor)
|
||||
{
|
||||
/*
|
||||
|
@ -512,25 +541,39 @@ s25fs256t_post_bfpt_fixup(struct spi_nor *nor,
|
|||
if (nor->bouncebuf[0])
|
||||
return -ENODEV;
|
||||
|
||||
return cypress_nor_get_page_size(nor);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int s25fs256t_post_sfdp_fixup(struct spi_nor *nor)
|
||||
{
|
||||
struct spi_nor_flash_parameter *params = nor->params;
|
||||
|
||||
/*
|
||||
* S25FS256T does not define the SCCR map, but we would like to use the
|
||||
* same code base for both single and multi chip package devices, thus
|
||||
* set the vreg_offset and n_dice to be able to do so.
|
||||
*/
|
||||
params->vreg_offset = devm_kmalloc(nor->dev, sizeof(u32), GFP_KERNEL);
|
||||
if (!params->vreg_offset)
|
||||
return -ENOMEM;
|
||||
|
||||
params->vreg_offset[0] = SPINOR_REG_CYPRESS_VREG;
|
||||
params->n_dice = 1;
|
||||
|
||||
/* PP_1_1_4_4B is supported but missing in 4BAIT. */
|
||||
params->hwcaps.mask |= SNOR_HWCAPS_PP_1_1_4;
|
||||
spi_nor_set_pp_settings(¶ms->page_programs[SNOR_CMD_PP_1_1_4],
|
||||
SPINOR_OP_PP_1_1_4_4B,
|
||||
SNOR_PROTO_1_1_4);
|
||||
|
||||
return 0;
|
||||
return cypress_nor_get_page_size(nor);
|
||||
}
|
||||
|
||||
static void s25fs256t_late_init(struct spi_nor *nor)
|
||||
static int s25fs256t_late_init(struct spi_nor *nor)
|
||||
{
|
||||
cypress_nor_ecc_init(nor);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct spi_nor_fixups s25fs256t_fixups = {
|
||||
|
@ -558,10 +601,20 @@ s25hx_t_post_bfpt_fixup(struct spi_nor *nor,
|
|||
|
||||
static int s25hx_t_post_sfdp_fixup(struct spi_nor *nor)
|
||||
{
|
||||
struct spi_nor_erase_type *erase_type =
|
||||
nor->params->erase_map.erase_type;
|
||||
struct spi_nor_flash_parameter *params = nor->params;
|
||||
struct spi_nor_erase_type *erase_type = params->erase_map.erase_type;
|
||||
unsigned int i;
|
||||
|
||||
if (!params->n_dice || !params->vreg_offset) {
|
||||
dev_err(nor->dev, "%s failed. The volatile register offset could not be retrieved from SFDP.\n",
|
||||
__func__);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
/* The 2 Gb parts duplicate info and advertise 4 dice instead of 2. */
|
||||
if (params->size == SZ_256M)
|
||||
params->n_dice = 2;
|
||||
|
||||
/*
|
||||
* In some parts, 3byte erase opcodes are advertised by 4BAIT.
|
||||
* Convert them to 4byte erase opcodes.
|
||||
|
@ -579,25 +632,19 @@ static int s25hx_t_post_sfdp_fixup(struct spi_nor *nor)
|
|||
}
|
||||
}
|
||||
|
||||
/* The 2 Gb parts duplicate info and advertise 4 dice instead of 2. */
|
||||
if (nor->params->size == SZ_256M)
|
||||
nor->params->n_dice = 2;
|
||||
|
||||
return cypress_nor_get_page_size(nor);
|
||||
}
|
||||
|
||||
static void s25hx_t_late_init(struct spi_nor *nor)
|
||||
static int s25hx_t_late_init(struct spi_nor *nor)
|
||||
{
|
||||
struct spi_nor_flash_parameter *params = nor->params;
|
||||
|
||||
/* Fast Read 4B requires mode cycles */
|
||||
params->reads[SNOR_CMD_READ_FAST].num_mode_clocks = 8;
|
||||
|
||||
params->ready = cypress_nor_sr_ready_and_clear;
|
||||
cypress_nor_ecc_init(nor);
|
||||
|
||||
/* Replace ready() with multi die version */
|
||||
if (params->n_dice)
|
||||
params->ready = cypress_nor_sr_ready_and_clear;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct spi_nor_fixups s25hx_t_fixups = {
|
||||
|
@ -607,7 +654,7 @@ static struct spi_nor_fixups s25hx_t_fixups = {
|
|||
};
|
||||
|
||||
/**
|
||||
* cypress_nor_octal_dtr_enable() - Enable octal DTR on Cypress flashes.
|
||||
* cypress_nor_set_octal_dtr() - Enable or disable octal DTR on Cypress flashes.
|
||||
* @nor: pointer to a 'struct spi_nor'
|
||||
* @enable: whether to enable or disable Octal DTR
|
||||
*
|
||||
|
@ -616,7 +663,7 @@ static struct spi_nor_fixups s25hx_t_fixups = {
|
|||
*
|
||||
* Return: 0 on success, -errno otherwise.
|
||||
*/
|
||||
static int cypress_nor_octal_dtr_enable(struct spi_nor *nor, bool enable)
|
||||
static int cypress_nor_set_octal_dtr(struct spi_nor *nor, bool enable)
|
||||
{
|
||||
return enable ? cypress_nor_octal_dtr_en(nor) :
|
||||
cypress_nor_octal_dtr_dis(nor);
|
||||
|
@ -624,22 +671,34 @@ static int cypress_nor_octal_dtr_enable(struct spi_nor *nor, bool enable)
|
|||
|
||||
static int s28hx_t_post_sfdp_fixup(struct spi_nor *nor)
|
||||
{
|
||||
struct spi_nor_flash_parameter *params = nor->params;
|
||||
|
||||
if (!params->n_dice || !params->vreg_offset) {
|
||||
dev_err(nor->dev, "%s failed. The volatile register offset could not be retrieved from SFDP.\n",
|
||||
__func__);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
/* The 2 Gb parts duplicate info and advertise 4 dice instead of 2. */
|
||||
if (params->size == SZ_256M)
|
||||
params->n_dice = 2;
|
||||
|
||||
/*
|
||||
* On older versions of the flash the xSPI Profile 1.0 table has the
|
||||
* 8D-8D-8D Fast Read opcode as 0x00. But it actually should be 0xEE.
|
||||
*/
|
||||
if (nor->params->reads[SNOR_CMD_READ_8_8_8_DTR].opcode == 0)
|
||||
nor->params->reads[SNOR_CMD_READ_8_8_8_DTR].opcode =
|
||||
if (params->reads[SNOR_CMD_READ_8_8_8_DTR].opcode == 0)
|
||||
params->reads[SNOR_CMD_READ_8_8_8_DTR].opcode =
|
||||
SPINOR_OP_CYPRESS_RD_FAST;
|
||||
|
||||
/* This flash is also missing the 4-byte Page Program opcode bit. */
|
||||
spi_nor_set_pp_settings(&nor->params->page_programs[SNOR_CMD_PP],
|
||||
spi_nor_set_pp_settings(¶ms->page_programs[SNOR_CMD_PP],
|
||||
SPINOR_OP_PP_4B, SNOR_PROTO_1_1_1);
|
||||
/*
|
||||
* Since xSPI Page Program opcode is backward compatible with
|
||||
* Legacy SPI, use Legacy SPI opcode there as well.
|
||||
*/
|
||||
spi_nor_set_pp_settings(&nor->params->page_programs[SNOR_CMD_PP_8_8_8_DTR],
|
||||
spi_nor_set_pp_settings(¶ms->page_programs[SNOR_CMD_PP_8_8_8_DTR],
|
||||
SPINOR_OP_PP_4B, SNOR_PROTO_8_8_8_DTR);
|
||||
|
||||
/*
|
||||
|
@ -647,7 +706,7 @@ static int s28hx_t_post_sfdp_fixup(struct spi_nor *nor)
|
|||
* address bytes needed for Read Status Register command as 0 but the
|
||||
* actual value for that is 4.
|
||||
*/
|
||||
nor->params->rdsr_addr_nbytes = 4;
|
||||
params->rdsr_addr_nbytes = 4;
|
||||
|
||||
return cypress_nor_get_page_size(nor);
|
||||
}
|
||||
|
@ -656,19 +715,18 @@ static int s28hx_t_post_bfpt_fixup(struct spi_nor *nor,
|
|||
const struct sfdp_parameter_header *bfpt_header,
|
||||
const struct sfdp_bfpt *bfpt)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = cypress_nor_set_addr_mode_nbytes(nor);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
return cypress_nor_set_addr_mode_nbytes(nor);
|
||||
}
|
||||
|
||||
static void s28hx_t_late_init(struct spi_nor *nor)
|
||||
static int s28hx_t_late_init(struct spi_nor *nor)
|
||||
{
|
||||
nor->params->octal_dtr_enable = cypress_nor_octal_dtr_enable;
|
||||
struct spi_nor_flash_parameter *params = nor->params;
|
||||
|
||||
params->set_octal_dtr = cypress_nor_set_octal_dtr;
|
||||
params->ready = cypress_nor_sr_ready_and_clear;
|
||||
cypress_nor_ecc_init(nor);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct spi_nor_fixups s28hx_t_fixups = {
|
||||
|
@ -792,47 +850,59 @@ static const struct flash_info spansion_nor_parts[] = {
|
|||
FIXUP_FLAGS(SPI_NOR_4B_OPCODES) },
|
||||
{ "s25fs256t", INFO6(0x342b19, 0x0f0890, 0, 0)
|
||||
PARSE_SFDP
|
||||
MFR_FLAGS(USE_CLPEF)
|
||||
.fixups = &s25fs256t_fixups },
|
||||
{ "s25hl512t", INFO6(0x342a1a, 0x0f0390, 256 * 1024, 256)
|
||||
{ "s25hl512t", INFO6(0x342a1a, 0x0f0390, 0, 0)
|
||||
PARSE_SFDP
|
||||
MFR_FLAGS(USE_CLSR)
|
||||
MFR_FLAGS(USE_CLPEF)
|
||||
.fixups = &s25hx_t_fixups },
|
||||
{ "s25hl01gt", INFO6(0x342a1b, 0x0f0390, 256 * 1024, 512)
|
||||
{ "s25hl01gt", INFO6(0x342a1b, 0x0f0390, 0, 0)
|
||||
PARSE_SFDP
|
||||
MFR_FLAGS(USE_CLSR)
|
||||
MFR_FLAGS(USE_CLPEF)
|
||||
.fixups = &s25hx_t_fixups },
|
||||
{ "s25hl02gt", INFO6(0x342a1c, 0x0f0090, 0, 0)
|
||||
PARSE_SFDP
|
||||
MFR_FLAGS(USE_CLPEF)
|
||||
FLAGS(NO_CHIP_ERASE)
|
||||
.fixups = &s25hx_t_fixups },
|
||||
{ "s25hs512t", INFO6(0x342b1a, 0x0f0390, 256 * 1024, 256)
|
||||
{ "s25hs512t", INFO6(0x342b1a, 0x0f0390, 0, 0)
|
||||
PARSE_SFDP
|
||||
MFR_FLAGS(USE_CLSR)
|
||||
MFR_FLAGS(USE_CLPEF)
|
||||
.fixups = &s25hx_t_fixups },
|
||||
{ "s25hs01gt", INFO6(0x342b1b, 0x0f0390, 256 * 1024, 512)
|
||||
{ "s25hs01gt", INFO6(0x342b1b, 0x0f0390, 0, 0)
|
||||
PARSE_SFDP
|
||||
MFR_FLAGS(USE_CLSR)
|
||||
MFR_FLAGS(USE_CLPEF)
|
||||
.fixups = &s25hx_t_fixups },
|
||||
{ "s25hs02gt", INFO6(0x342b1c, 0x0f0090, 0, 0)
|
||||
PARSE_SFDP
|
||||
MFR_FLAGS(USE_CLPEF)
|
||||
FLAGS(NO_CHIP_ERASE)
|
||||
.fixups = &s25hx_t_fixups },
|
||||
{ "cy15x104q", INFO6(0x042cc2, 0x7f7f7f, 512 * 1024, 1)
|
||||
FLAGS(SPI_NOR_NO_ERASE) },
|
||||
{ "s28hl512t", INFO(0x345a1a, 0, 256 * 1024, 256)
|
||||
{ "s28hl512t", INFO(0x345a1a, 0, 0, 0)
|
||||
PARSE_SFDP
|
||||
MFR_FLAGS(USE_CLPEF)
|
||||
.fixups = &s28hx_t_fixups,
|
||||
},
|
||||
{ "s28hl01gt", INFO(0x345a1b, 0, 256 * 1024, 512)
|
||||
{ "s28hl01gt", INFO(0x345a1b, 0, 0, 0)
|
||||
PARSE_SFDP
|
||||
MFR_FLAGS(USE_CLPEF)
|
||||
.fixups = &s28hx_t_fixups,
|
||||
},
|
||||
{ "s28hs512t", INFO(0x345b1a, 0, 256 * 1024, 256)
|
||||
{ "s28hs512t", INFO(0x345b1a, 0, 0, 0)
|
||||
PARSE_SFDP
|
||||
MFR_FLAGS(USE_CLPEF)
|
||||
.fixups = &s28hx_t_fixups,
|
||||
},
|
||||
{ "s28hs01gt", INFO(0x345b1b, 0, 256 * 1024, 512)
|
||||
{ "s28hs01gt", INFO(0x345b1b, 0, 0, 0)
|
||||
PARSE_SFDP
|
||||
MFR_FLAGS(USE_CLPEF)
|
||||
.fixups = &s28hx_t_fixups,
|
||||
},
|
||||
{ "s28hs02gt", INFO(0x345b1c, 0, 0, 0)
|
||||
PARSE_SFDP
|
||||
MFR_FLAGS(USE_CLPEF)
|
||||
.fixups = &s28hx_t_fixups,
|
||||
},
|
||||
};
|
||||
|
@ -876,17 +946,35 @@ static int spansion_nor_sr_ready_and_clear(struct spi_nor *nor)
|
|||
return !(nor->bouncebuf[0] & SR_WIP);
|
||||
}
|
||||
|
||||
static void spansion_nor_late_init(struct spi_nor *nor)
|
||||
static int spansion_nor_late_init(struct spi_nor *nor)
|
||||
{
|
||||
if (nor->params->size > SZ_16M) {
|
||||
struct spi_nor_flash_parameter *params = nor->params;
|
||||
struct spansion_nor_params *priv_params;
|
||||
u8 mfr_flags = nor->info->mfr_flags;
|
||||
|
||||
if (params->size > SZ_16M) {
|
||||
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;
|
||||
}
|
||||
|
||||
if (nor->info->mfr_flags & USE_CLSR)
|
||||
nor->params->ready = spansion_nor_sr_ready_and_clear;
|
||||
if (mfr_flags & (USE_CLSR | USE_CLPEF)) {
|
||||
priv_params = devm_kmalloc(nor->dev, sizeof(*priv_params),
|
||||
GFP_KERNEL);
|
||||
if (!priv_params)
|
||||
return -ENOMEM;
|
||||
|
||||
if (mfr_flags & USE_CLSR)
|
||||
priv_params->clsr = SPINOR_OP_CLSR;
|
||||
else if (mfr_flags & USE_CLPEF)
|
||||
priv_params->clsr = SPINOR_OP_CLPEF;
|
||||
|
||||
params->priv = priv_params;
|
||||
params->ready = spansion_nor_sr_ready_and_clear;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct spi_nor_fixups spansion_nor_fixups = {
|
||||
|
|
|
@ -49,9 +49,11 @@ static const struct spi_nor_locking_ops sst26vf_nor_locking_ops = {
|
|||
.is_locked = sst26vf_nor_is_locked,
|
||||
};
|
||||
|
||||
static void sst26vf_nor_late_init(struct spi_nor *nor)
|
||||
static int sst26vf_nor_late_init(struct spi_nor *nor)
|
||||
{
|
||||
nor->params->locking_ops = &sst26vf_nor_locking_ops;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct spi_nor_fixups sst26vf_nor_fixups = {
|
||||
|
@ -111,6 +113,10 @@ static const struct flash_info sst_nor_parts[] = {
|
|||
SPI_NOR_QUAD_READ) },
|
||||
{ "sst26vf016b", INFO(0xbf2641, 0, 64 * 1024, 32)
|
||||
NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ) },
|
||||
{ "sst26vf032b", INFO(0xbf2642, 0, 0, 0)
|
||||
FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE)
|
||||
PARSE_SFDP
|
||||
.fixups = &sst26vf_nor_fixups },
|
||||
{ "sst26vf064b", INFO(0xbf2643, 0, 64 * 1024, 128)
|
||||
FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE)
|
||||
NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)
|
||||
|
@ -203,10 +209,12 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void sst_nor_late_init(struct spi_nor *nor)
|
||||
static int sst_nor_late_init(struct spi_nor *nor)
|
||||
{
|
||||
if (nor->info->mfr_flags & SST_WRITE)
|
||||
nor->mtd._write = sst_nor_write;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct spi_nor_fixups sst_nor_fixups = {
|
||||
|
|
|
@ -214,8 +214,13 @@ static int spi_nor_sr_lock(struct spi_nor *nor, loff_t ofs, uint64_t len)
|
|||
|
||||
status_new = (status_old & ~mask & ~tb_mask) | val;
|
||||
|
||||
/* Disallow further writes if WP pin is asserted */
|
||||
status_new |= SR_SRWD;
|
||||
/*
|
||||
* Disallow further writes if WP# pin is neither left floating nor
|
||||
* wrongly tied to GND (that includes internal pull-downs).
|
||||
* WP# pin hard strapped to GND can be a valid use case.
|
||||
*/
|
||||
if (!(nor->flags & SNOR_F_NO_WP))
|
||||
status_new |= SR_SRWD;
|
||||
|
||||
if (!use_top)
|
||||
status_new |= tb_mask;
|
||||
|
|
|
@ -120,8 +120,9 @@ static const struct flash_info winbond_nor_parts[] = {
|
|||
NO_SFDP_FLAGS(SECT_4K) },
|
||||
{ "w25q80bl", INFO(0xef4014, 0, 64 * 1024, 16)
|
||||
NO_SFDP_FLAGS(SECT_4K) },
|
||||
{ "w25q128", INFO(0xef4018, 0, 64 * 1024, 256)
|
||||
NO_SFDP_FLAGS(SECT_4K) },
|
||||
{ "w25q128", INFO(0xef4018, 0, 0, 0)
|
||||
PARSE_SFDP
|
||||
FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) },
|
||||
{ "w25q256", INFO(0xef4019, 0, 64 * 1024, 512)
|
||||
NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)
|
||||
.fixups = &w25q256_fixups },
|
||||
|
@ -216,7 +217,7 @@ static const struct spi_nor_otp_ops winbond_nor_otp_ops = {
|
|||
.is_locked = spi_nor_otp_is_locked_sr2,
|
||||
};
|
||||
|
||||
static void winbond_nor_late_init(struct spi_nor *nor)
|
||||
static int winbond_nor_late_init(struct spi_nor *nor)
|
||||
{
|
||||
struct spi_nor_flash_parameter *params = nor->params;
|
||||
|
||||
|
@ -232,6 +233,8 @@ static void winbond_nor_late_init(struct spi_nor *nor)
|
|||
* from BFPT, if any.
|
||||
*/
|
||||
params->set_4byte_addr_mode = winbond_nor_set_4byte_addr_mode;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct spi_nor_fixups winbond_nor_fixups = {
|
||||
|
|
|
@ -155,10 +155,12 @@ static int xilinx_nor_setup(struct spi_nor *nor,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void xilinx_nor_late_init(struct spi_nor *nor)
|
||||
static int xilinx_nor_late_init(struct spi_nor *nor)
|
||||
{
|
||||
nor->params->setup = xilinx_nor_setup;
|
||||
nor->params->ready = xilinx_nor_sr_ready;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct spi_nor_fixups xilinx_nor_fixups = {
|
||||
|
|
Loading…
Reference in New Issue