diff options
-rw-r--r-- | drivers/mtd/spi/spi-nor-core.c | 88 | ||||
-rw-r--r-- | drivers/mtd/ubi/build.c | 4 | ||||
-rw-r--r-- | drivers/mtd/ubi/io.c | 9 | ||||
-rw-r--r-- | include/linux/mtd/spi-nor.h | 1 |
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 = ¯onix_octal_fixups; + if (JEDEC_MFR(nor->info) == SNOR_MFR_MACRONIX && + nor->info->flags & SPI_NOR_OCTAL_DTR_READ) + nor->fixups = ¯onix_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; |