On 15/11/19 2:28 pm, Mason Yang wrote: > mx25uw51245g is a SPI NOR that supports 1-1-1/8-8-8 mode and the SFDPRD > command but returns an empty SFDP page. This forces us to add a new entry > in the flash_info table and patch spi_nor_fixups hooks to tweak flash > parameters for spi_nor_read/pp_setting() and then to enter > Octal 8D-8D-8D modes. > > Signed-off-by: Boris Brezillon <boris.brezillon@xxxxxxxxxxx> > Signed-off-by: Mason Yang <masonccyang@xxxxxxxxxxx> > --- > drivers/mtd/spi-nor/spi-nor.c | 114 ++++++++++++++++++++++++++++++++++++++++++ > include/linux/mtd/spi-nor.h | 3 ++ > 2 files changed, 117 insertions(+) > > diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c > index 4cdf52d..9013590 100644 > --- a/drivers/mtd/spi-nor/spi-nor.c > +++ b/drivers/mtd/spi-nor/spi-nor.c > @@ -615,6 +615,56 @@ static int write_disable(struct spi_nor *nor) > } > > /* > + * Read configuration register 2, returning its value in the > + * location. Return the configuration register 2 value. > + * Returns negative if error occurred. > + */ > +static int read_cr2(struct spi_nor *nor, u32 addr) Please prefix spi_nor_* for all new functions. Also, include manf name if its vendor specific. > +{ > + int ret; > + > + if (nor->spimem) { > + struct spi_mem_op op = > + SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_RDCR2, 1), > + SPI_MEM_OP_ADDR(4, addr, 1), > + SPI_MEM_OP_DUMMY(4, 1), > + SPI_MEM_OP_DATA_IN(1, nor->bouncebuf, 1)); > + > + if (spi_nor_protocol_is_8_8_8(nor->read_proto)) { > + op.cmd.buswidth = 8; > + op.addr.buswidth = 8; > + op.dummy.buswidth = 8; > + op.data.buswidth = 8; > + op.cmd.nbytes = 2; > + > + if (spi_nor_protocol_is_8D_8D_8D(nor->read_proto)) { > + op.dummy.nbytes *= 2; > + op.cmd.dtr = true; > + op.addr.dtr = true; > + op.dummy.dtr = true; > + op.data.dtr = true; > + } > + > + if (nor->ext_cmd_mode == EXT_CMD_IS_INVERSE) > + op.cmd.ext_opcode = ~SPINOR_OP_RDCR2; > + else > + op.cmd.ext_opcode = SPINOR_OP_RDCR2; > + } > + > + ret = spi_mem_exec_op(nor->spimem, &op); > + } else { > + ret = -ENOTSUPP; > + } > + > + if (ret < 0) { > + dev_err(nor->dev, "error %d reading CR\n", ret); > + return ret; > + } > + > + return nor->bouncebuf[0]; > +} > + > +/* > * Write configuration register 2 one byte > * Returns negative if error occurred. > */ > @@ -2275,10 +2325,72 @@ static int spi_nor_spansion_clear_sr_bp(struct spi_nor *nor) > return 0; > } > > +static void > +spi_nor_set_read_settings(struct spi_nor_read_command *read, > + u8 num_mode_clocks, > + u8 num_wait_states, > + u8 opcode, > + enum spi_nor_protocol proto); > + > +static void > +spi_nor_set_pp_settings(struct spi_nor_pp_command *pp, > + u8 opcode, > + enum spi_nor_protocol proto); > + > +static void > +mx25uw51245g_default_init(struct spi_nor *nor) > +{ > + struct spi_nor_flash_parameter *params = &nor->params; > + > + if (!(nor->spimem->spi->mode & (SPI_RX_OCTAL | SPI_TX_OCTAL))) > + return; > + > + /* Octal 8S-8S-8S mode */ > + params->hwcaps.mask |= SNOR_HWCAPS_OPI_FULL_STR; > + spi_nor_set_read_settings(¶ms->reads[SNOR_CMD_READ_8_8_8], > + 0, 20, SPINOR_OP_READ_8_8_8, > + SNOR_PROTO_8_8_8); > + > + spi_nor_set_pp_settings(¶ms->page_programs[SNOR_CMD_PP_8_8_8], > + SPINOR_OP_PP_8_8_8, SNOR_PROTO_8_8_8); > + > + /* Octal 8D-8D-8D mode */ > + params->hwcaps.mask |= SNOR_HWCAPS_OPI_FULL_DTR; > + spi_nor_set_read_settings(¶ms->reads[SNOR_CMD_READ_8D_8D_8D], > + 0, 20, SPINOR_OP_READ_8D_8D_8D, > + SNOR_PROTO_8_8_8_DTR); > + > + spi_nor_set_pp_settings(¶ms->page_programs[SNOR_CMD_PP_8D_8D_8D], > + SPINOR_OP_PP_8D_8D_8D, SNOR_PROTO_8_8_8_DTR); > + > + nor->ext_cmd_mode = EXT_CMD_IS_INVERSE; > +} I don't see anything that is macronix specific here.. Can this be moved to generic code with information parsed from SFDP table? > + > +static void > +mx25uw51245g_post_sfdp_fixups(struct spi_nor *nor) > +{ > + struct spi_nor_flash_parameter *params = &nor->params; > + u8 cr2; > + > + cr2 = read_cr2(nor, CR2_REG0) & CR2_REG0_MODE_MASK; > + > + if (params->hwcaps.mask & SNOR_HWCAPS_OPI_FULL_DTR) > + cr2 |= CR2_REG0_MODE_OPI_DTR; > + else if (params->hwcaps.mask & SNOR_HWCAPS_OPI_FULL_STR) > + cr2 |= CR2_REG0_MODE_OPI_STR; > + > + write_cr2(nor, CR2_REG0, cr2); > +} > + I see this as a misuse of sfdp_fixups hook: * @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). * This should only tweak options parsed by SFDP and not be used to configure flash to a different mode. Please add a separate function to do so. See https://patchwork.kernel.org/patch/10638085/ Also, I guess JESD216C provides a way to discover command sequence to enter OPI mode? > static struct spi_nor_fixups mx25l25635_fixups = { > .post_bfpt = mx25l25635_post_bfpt_fixups, > }; > > +static struct spi_nor_fixups mx25uw51245g_fixups = { > + .default_init = mx25uw51245g_default_init, > + .post_sfdp = mx25uw51245g_post_sfdp_fixups, > +}; > + > static void gd25q256_default_init(struct spi_nor *nor) > { > /* > @@ -2442,6 +2554,8 @@ static void gd25q256_default_init(struct spi_nor *nor) > SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) > .fixups = &mx25l25635_fixups }, > { "mx25u25635f", INFO(0xc22539, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_4B_OPCODES) }, > + { "mx25uw51245g", INFO(0xc2813a, 0, 64 * 1024, 1024, SECT_4K | SPI_NOR_4B_OPCODES) > + .fixups = &mx25uw51245g_fixups}, > { "mx25v8035f", INFO(0xc22314, 0, 64 * 1024, 16, > SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, > { "mx25l25655e", INFO(0xc22619, 0, 64 * 1024, 512, 0) }, > diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h > index 2e720ca..3aa54dd 100644 > --- a/include/linux/mtd/spi-nor.h > +++ b/include/linux/mtd/spi-nor.h > @@ -114,6 +114,9 @@ > /* Write CFG Reg 2 - defined in JEDEC JESD216C. */ > #define SPINOR_OP_WRCR2 0x72 /* Write configuration register 2 */ > > +/* Used for Macronix flashes only */ > +#define SPINOR_OP_RDCR2 0x71 /* Read configuration register 2 */ > + > /* Used for Macronix and Winbond flashes. */ > #define SPINOR_OP_EN4B 0xb7 /* Enter 4-byte mode */ > #define SPINOR_OP_EX4B 0xe9 /* Exit 4-byte mode */ > -- Regards Vignesh ______________________________________________________ Linux MTD discussion mailing list http://lists.infradead.org/mailman/listinfo/linux-mtd/