summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/mtd/spi/spi-nor-core.c88
-rw-r--r--drivers/mtd/ubi/build.c4
-rw-r--r--drivers/mtd/ubi/io.c9
-rw-r--r--include/linux/mtd/spi-nor.h1
4 files changed, 65 insertions, 37 deletions
diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c
index 6f5395c7b9b..f5c9868bbca 100644
--- a/drivers/mtd/spi/spi-nor-core.c
+++ b/drivers/mtd/spi/spi-nor-core.c
@@ -194,27 +194,26 @@ struct sfdp_bfpt {
/**
* struct spi_nor_fixups - SPI NOR fixup hooks
- * @default_init: called after default flash parameters init. Used to tweak
- * flash parameters when information provided by the flash_info
- * table is incomplete or wrong.
* @post_bfpt: called after the BFPT table has been parsed
- * @post_sfdp: called after SFDP has been parsed (is also called for SPI NORs
- * that do not support RDSFDP). Typically used to tweak various
- * parameters that could not be extracted by other means (i.e.
- * when information provided by the SFDP/flash_info tables are
- * incomplete or wrong).
+ * @post_sfdp: called after SFDP has been parsed. Typically used to tweak
+ * various parameters that could not be extracted by other means
+ * (i.e. when information provided by the SFDP tables are incomplete
+ * or wrong).
+ * @late_init: used to initialize flash parameters that are not declared in the
+ * JESD216 SFDP standard, or where SFDP tables not defined at all.
*
* 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 spi_nor_flash_parameter *params);
+ void (*late_init)(struct spi_nor *nor,
+ struct spi_nor_flash_parameter *params);
};
#define SPI_NOR_SRST_SLEEP_LEN 200
@@ -3045,13 +3044,12 @@ static int spi_nor_parse_sfdp(struct spi_nor *nor,
/**
* spi_nor_post_sfdp_fixups() - Updates the flash's parameters and settings
- * after SFDP has been parsed (is also called for SPI NORs that do not
- * support RDSFDP).
+ * after SFDP has been parsed.
* @nor: pointer to a 'struct spi_nor'
*
* Typically used to tweak various parameters that could not be extracted by
- * other means (i.e. when information provided by the SFDP/flash_info tables
- * are incomplete or wrong).
+ * other means (i.e. when information provided by the SFDP tables are incomplete
+ * or wrong).
*/
static void spi_nor_post_sfdp_fixups(struct spi_nor *nor,
struct spi_nor_flash_parameter *params)
@@ -3060,10 +3058,11 @@ static void spi_nor_post_sfdp_fixups(struct spi_nor *nor,
nor->fixups->post_sfdp(nor, params);
}
-static void spi_nor_default_init_fixups(struct spi_nor *nor)
+static void spi_nor_late_init_fixups(struct spi_nor *nor,
+ struct spi_nor_flash_parameter *params)
{
- if (nor->fixups && nor->fixups->default_init)
- nor->fixups->default_init(nor);
+ if (nor->fixups && nor->fixups->late_init)
+ nor->fixups->late_init(nor, params);
}
static int spi_nor_init_params(struct spi_nor *nor,
@@ -3081,6 +3080,7 @@ static int spi_nor_init_params(struct spi_nor *nor,
memset(params, 0, sizeof(*params));
/* Set SPI NOR sizes. */
+ params->writesize = 1;
params->size = info->sector_size * info->n_sectors;
params->page_size = info->page_size;
@@ -3176,8 +3176,6 @@ static int spi_nor_init_params(struct spi_nor *nor,
}
}
- spi_nor_default_init_fixups(nor);
-
/* Override the parameters with data read from SFDP tables. */
nor->addr_width = 0;
nor->mtd.erasesize = 0;
@@ -3193,6 +3191,8 @@ static int spi_nor_init_params(struct spi_nor *nor,
} else {
memcpy(params, &sfdp_params, sizeof(*params));
}
+
+ spi_nor_post_sfdp_fixups(nor, params);
}
#if CONFIG_IS_ENABLED(DM_SPI) && CONFIG_IS_ENABLED(SPI_ADVANCE)
/*
@@ -3250,7 +3250,7 @@ static int spi_nor_init_params(struct spi_nor *nor,
params->page_size <<= 1;
}
#endif
- spi_nor_post_sfdp_fixups(nor, params);
+ spi_nor_late_init_fixups(nor, params);
return 0;
}
@@ -3714,7 +3714,8 @@ static int s25fs_s_setup(struct spi_nor *nor, const struct flash_info *info,
return spi_nor_default_setup(nor, info, params);
}
-static void s25fs_s_default_init(struct spi_nor *nor)
+static void s25fs_s_late_init(struct spi_nor *nor,
+ struct spi_nor_flash_parameter *params)
{
nor->setup = s25fs_s_setup;
}
@@ -3764,9 +3765,9 @@ static void s25fs_s_post_sfdp_fixup(struct spi_nor *nor,
}
static struct spi_nor_fixups s25fs_s_fixups = {
- .default_init = s25fs_s_default_init,
.post_bfpt = s25fs_s_post_bfpt_fixup,
.post_sfdp = s25fs_s_post_sfdp_fixup,
+ .late_init = s25fs_s_late_init,
};
static int s25_s28_mdp_ready(struct spi_nor *nor)
@@ -3850,9 +3851,17 @@ static int s25_s28_setup(struct spi_nor *nor, const struct flash_info *info,
return spi_nor_default_setup(nor, info, params);
}
-static void s25_default_init(struct spi_nor *nor)
+static void s25_late_init(struct spi_nor *nor,
+ struct spi_nor_flash_parameter *params)
{
nor->setup = s25_s28_setup;
+
+ /*
+ * Programming is supported only in 16-byte ECC data unit granularity.
+ * Byte-programming, bit-walking, or multiple program operations to the
+ * same ECC data unit without an erase are not allowed.
+ */
+ params->writesize = 16;
}
static int s25_s28_post_bfpt_fixup(struct spi_nor *nor,
@@ -3931,9 +3940,9 @@ static void s25_post_sfdp_fixup(struct spi_nor *nor,
}
static struct spi_nor_fixups s25_fixups = {
- .default_init = s25_default_init,
.post_bfpt = s25_s28_post_bfpt_fixup,
.post_sfdp = s25_post_sfdp_fixup,
+ .late_init = s25_late_init,
};
static int s25fl256l_setup(struct spi_nor *nor, const struct flash_info *info,
@@ -3942,13 +3951,14 @@ static int s25fl256l_setup(struct spi_nor *nor, const struct flash_info *info,
return -ENOTSUPP; /* Bank Address Register is not supported */
}
-static void s25fl256l_default_init(struct spi_nor *nor)
+static void s25fl256l_late_init(struct spi_nor *nor,
+ struct spi_nor_flash_parameter *params)
{
nor->setup = s25fl256l_setup;
}
static struct spi_nor_fixups s25fl256l_fixups = {
- .default_init = s25fl256l_default_init,
+ .late_init = s25fl256l_late_init,
};
#endif
@@ -4011,10 +4021,18 @@ static int spi_nor_cypress_octal_dtr_enable(struct spi_nor *nor)
return 0;
}
-static void s28hx_t_default_init(struct spi_nor *nor)
+static void s28hx_t_late_init(struct spi_nor *nor,
+ struct spi_nor_flash_parameter *params)
{
nor->octal_dtr_enable = spi_nor_cypress_octal_dtr_enable;
nor->setup = s25_s28_setup;
+
+ /*
+ * Programming is supported only in 16-byte ECC data unit granularity.
+ * Byte-programming, bit-walking, or multiple program operations to the
+ * same ECC data unit without an erase are not allowed.
+ */
+ params->writesize = 16;
}
static void s28hx_t_post_sfdp_fixup(struct spi_nor *nor,
@@ -4049,9 +4067,9 @@ static void s28hx_t_post_sfdp_fixup(struct spi_nor *nor,
}
static struct spi_nor_fixups s28hx_t_fixups = {
- .default_init = s28hx_t_default_init,
.post_sfdp = s28hx_t_post_sfdp_fixup,
.post_bfpt = s25_s28_post_bfpt_fixup,
+ .late_init = s28hx_t_late_init,
};
#endif /* CONFIG_SPI_FLASH_S28HX_T */
@@ -4103,7 +4121,8 @@ static int spi_nor_micron_octal_dtr_enable(struct spi_nor *nor)
return 0;
}
-static void mt35xu512aba_default_init(struct spi_nor *nor)
+static void mt35xu512aba_late_init(struct spi_nor *nor,
+ struct spi_nor_flash_parameter *params)
{
nor->octal_dtr_enable = spi_nor_micron_octal_dtr_enable;
}
@@ -4132,8 +4151,8 @@ static void mt35xu512aba_post_sfdp_fixup(struct spi_nor *nor,
}
static struct spi_nor_fixups mt35xu512aba_fixups = {
- .default_init = mt35xu512aba_default_init,
.post_sfdp = mt35xu512aba_post_sfdp_fixup,
+ .late_init = mt35xu512aba_late_init,
};
#endif /* CONFIG_SPI_FLASH_MT35XU */
@@ -4193,7 +4212,8 @@ static int spi_nor_macronix_octal_dtr_enable(struct spi_nor *nor)
return 0;
}
-static void macronix_octal_default_init(struct spi_nor *nor)
+static void macronix_octal_late_init(struct spi_nor *nor,
+ struct spi_nor_flash_parameter *params)
{
nor->octal_dtr_enable = spi_nor_macronix_octal_dtr_enable;
}
@@ -4210,8 +4230,8 @@ static void macronix_octal_post_sfdp_fixup(struct spi_nor *nor,
}
static struct spi_nor_fixups macronix_octal_fixups = {
- .default_init = macronix_octal_default_init,
.post_sfdp = macronix_octal_post_sfdp_fixup,
+ .late_init = macronix_octal_late_init,
};
#endif /* CONFIG_SPI_FLASH_MACRONIX */
@@ -4422,7 +4442,9 @@ void spi_nor_set_fixups(struct spi_nor *nor)
#endif
#if CONFIG_IS_ENABLED(SPI_FLASH_MACRONIX)
- nor->fixups = &macronix_octal_fixups;
+ if (JEDEC_MFR(nor->info) == SNOR_MFR_MACRONIX &&
+ nor->info->flags & SPI_NOR_OCTAL_DTR_READ)
+ nor->fixups = &macronix_octal_fixups;
#endif /* SPI_FLASH_MACRONIX */
}
@@ -4499,7 +4521,7 @@ int spi_nor_scan(struct spi_nor *nor)
mtd->dev = nor->dev;
mtd->priv = nor;
mtd->type = MTD_NORFLASH;
- mtd->writesize = 1;
+ mtd->writesize = params.writesize;
mtd->flags = MTD_CAP_NORFLASH;
mtd->size = params.size;
mtd->_erase = spi_nor_erase;
diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c
index cf0d702421f..104537784ab 100644
--- a/drivers/mtd/ubi/build.c
+++ b/drivers/mtd/ubi/build.c
@@ -679,10 +679,8 @@ static int io_init(struct ubi_device *ubi, int max_beb_per1024)
ubi->bad_peb_limit = get_bad_peb_limit(ubi, max_beb_per1024);
}
- if (ubi->mtd->type == MTD_NORFLASH) {
- ubi_assert(ubi->mtd->writesize == 1);
+ if (ubi->mtd->type == MTD_NORFLASH)
ubi->nor_flash = 1;
- }
ubi->min_io_size = ubi->mtd->writesize;
ubi->hdrs_min_io_size = ubi->mtd->writesize >> ubi->mtd->subpage_sft;
diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c
index 14be95b74bc..45699b4a477 100644
--- a/drivers/mtd/ubi/io.c
+++ b/drivers/mtd/ubi/io.c
@@ -563,7 +563,14 @@ int ubi_io_sync_erase(struct ubi_device *ubi, int pnum, int torture)
return -EROFS;
}
- if (ubi->nor_flash) {
+ /*
+ * If the flash is ECC-ed then we have to erase the ECC block before we
+ * can write to it. But the write is in preparation to an erase in the
+ * first place. This means we cannot zero out EC and VID before the
+ * erase and we just have to hope the flash starts erasing from the
+ * start of the page.
+ */
+ if (ubi->nor_flash && ubi->mtd->writesize == 1) {
err = nor_erase_prepare(ubi, pnum);
if (err)
return err;
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
index 047e83e8463..1ae586b2e5f 100644
--- a/include/linux/mtd/spi-nor.h
+++ b/include/linux/mtd/spi-nor.h
@@ -457,6 +457,7 @@ enum spi_nor_pp_command_index {
struct spi_nor_flash_parameter {
u64 size;
+ u32 writesize;
u32 page_size;
u8 rdsr_dummy;
u8 rdsr_addr_nbytes;