MT25Q[UL] Micron flashes support this by the Bits [2:0] in the Enhanced Volatile Configuration Register. Checked datasheet: - mt25t-qljs-L512-xBA-xxT.pdf Signed-off-by: Alexander Stein <alexander.stein@xxxxxxxxxxxxxxx> --- Changes in v2: * Various format fixes * Apply property only to MT25Q devices (e.g. N25Q devices support a different set of impedances) * Use spi_nor_spimem_setup_op() before issuing a command * Add more return code checking * Add a warning if setting drive strength fails at some point * Use GENMASK() drivers/mtd/spi-nor/micron-st.c | 152 ++++++++++++++++++++++++++++++-- 1 file changed, 146 insertions(+), 6 deletions(-) diff --git a/drivers/mtd/spi-nor/micron-st.c b/drivers/mtd/spi-nor/micron-st.c index c224e59820a1..492805a5a278 100644 --- a/drivers/mtd/spi-nor/micron-st.c +++ b/drivers/mtd/spi-nor/micron-st.c @@ -16,6 +16,11 @@ #define SPINOR_MT_OCT_DTR 0xe7 /* Enable Octal DTR. */ #define SPINOR_MT_EXSPI 0xff /* Enable Extended SPI (default) */ +struct micron_drive_strength { + u32 ohms; + u8 val; +}; + static int spi_nor_micron_octal_dtr_enable(struct spi_nor *nor, bool enable) { struct spi_mem_op op; @@ -118,6 +123,135 @@ static struct spi_nor_fixups mt35xu512aba_fixups = { .post_sfdp = mt35xu512aba_post_sfdp_fixup, }; +/* + * Read Micron enhanced volatile configuration register + * Return negative if error occurred or configuration register value + */ +static int micron_read_evcr(struct spi_nor *nor) +{ + int ret; + + if (nor->spimem) { + struct spi_mem_op op = + SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_RD_EVCR, 1), + SPI_MEM_OP_NO_ADDR, + SPI_MEM_OP_NO_DUMMY, + SPI_MEM_OP_DATA_IN(1, nor->bouncebuf, 1)); + + spi_nor_spimem_setup_op(nor, &op, nor->reg_proto); + + ret = spi_mem_exec_op(nor->spimem, &op); + } else { + ret = nor->controller_ops->read_reg(nor, SPINOR_OP_RD_EVCR, + nor->bouncebuf, 1); + } + + if (ret < 0) { + dev_err(nor->dev, "error %d reading EVCR\n", ret); + return ret; + } + + return nor->bouncebuf[0]; +} + +/* + * Write Micron enhanced volatile configuration register + * Return negative if error occurred or configuration register value + */ +static int micron_write_evcr(struct spi_nor *nor, u8 evcr) +{ + int ret; + + nor->bouncebuf[0] = evcr; + + ret = spi_nor_write_enable(nor); + if (ret) + return ret; + + if (nor->spimem) { + struct spi_mem_op op = + SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WD_EVCR, 1), + SPI_MEM_OP_NO_ADDR, + SPI_MEM_OP_NO_DUMMY, + SPI_MEM_OP_DATA_OUT(1, nor->bouncebuf, 1)); + + spi_nor_spimem_setup_op(nor, &op, nor->reg_proto); + + return spi_mem_exec_op(nor->spimem, &op); + } + + return nor->controller_ops->write_reg(nor, SPINOR_OP_WD_EVCR, + nor->bouncebuf, 1); +} + +/* + * Supported values from Enahanced Volatile COnfiguration Register (Bits 2:0) + */ +static const struct micron_drive_strength drive_strength_data[] = { + { .ohms = 90, .val = 1 }, + { .ohms = 45, .val = 3 }, + { .ohms = 20, .val = 5 }, + { .ohms = 30, .val = 7 }, +}; + +static const struct micron_drive_strength *micron_st_find_drive_strength_entry(u32 ohms) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(drive_strength_data); i++) { + if (ohms == drive_strength_data[i].ohms) + return &drive_strength_data[i]; + } + return NULL; +} + +static void mt25q_post_sfdp(struct spi_nor *nor) +{ + struct device_node *np = spi_nor_get_flash_node(nor); + u32 ohms; + + if (!np) + return; + + if (!of_property_read_u32(np, "output-driver-strength", &ohms)) { + struct micron_drive_strength const *entry = + micron_st_find_drive_strength_entry(ohms); + + if (entry) { + int evcrr; + int ret; + u8 evcr; + + evcrr = micron_read_evcr(nor); + if (evcrr < 0) { + dev_warn(nor->dev, + "Reading EVCR failed: %d\n", + evcrr); + return; + } + + evcr = (u8)(evcrr & GENMASK(7, 3)) | entry->val; + + ret = micron_write_evcr(nor, evcr); + if (ret) + dev_warn(nor->dev, + "Setting EVCR failed: %d\n", + ret); + + dev_dbg(nor->dev, "%s: EVCR 0x%x\n", __func__, + (u32)micron_read_evcr(nor)); + } else { + dev_warn(nor->dev, + "Invalid output-driver-strength property specified: %u", + ohms); + } + } +} + +static struct spi_nor_fixups mt25q_fixups = { + .post_sfdp = mt25q_post_sfdp, +}; + static const struct flash_info micron_parts[] = { { "mt35xu512aba", INFO(0x2c5b1a, 0, 128 * 1024, 512, SECT_4K | USE_FSR | SPI_NOR_OCTAL_READ | @@ -149,25 +283,29 @@ static const struct flash_info st_parts[] = { SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) }, { "mt25ql256a", INFO6(0x20ba19, 0x104400, 64 * 1024, 512, SECT_4K | USE_FSR | SPI_NOR_DUAL_READ | - SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, + SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) + .fixups = &mt25q_fixups }, { "n25q256a", INFO(0x20ba19, 0, 64 * 1024, 512, SECT_4K | USE_FSR | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, { "mt25qu256a", INFO6(0x20bb19, 0x104400, 64 * 1024, 512, SECT_4K | USE_FSR | SPI_NOR_DUAL_READ | - SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, + SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) + .fixups = &mt25q_fixups }, { "n25q256ax1", INFO(0x20bb19, 0, 64 * 1024, 512, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) }, { "mt25ql512a", INFO6(0x20ba20, 0x104400, 64 * 1024, 1024, SECT_4K | USE_FSR | SPI_NOR_DUAL_READ | - SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, + SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) + .fixups = &mt25q_fixups }, { "n25q512ax3", INFO(0x20ba20, 0, 64 * 1024, 1024, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_4BIT_BP | SPI_NOR_BP3_SR_BIT6) }, { "mt25qu512a", INFO6(0x20bb20, 0x104400, 64 * 1024, 1024, SECT_4K | USE_FSR | SPI_NOR_DUAL_READ | - SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, + SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) + .fixups = &mt25q_fixups }, { "n25q512a", INFO(0x20bb20, 0, 64 * 1024, 1024, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | @@ -182,10 +320,12 @@ static const struct flash_info st_parts[] = { NO_CHIP_ERASE) }, { "mt25ql02g", INFO(0x20ba22, 0, 64 * 1024, 4096, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | - NO_CHIP_ERASE) }, + NO_CHIP_ERASE) + .fixups = &mt25q_fixups }, { "mt25qu02g", INFO(0x20bb22, 0, 64 * 1024, 4096, SECT_4K | USE_FSR | SPI_NOR_DUAL_READ | - SPI_NOR_QUAD_READ | NO_CHIP_ERASE) }, + SPI_NOR_QUAD_READ | NO_CHIP_ERASE) + .fixups = &mt25q_fixups }, { "m25p05", INFO(0x202010, 0, 32 * 1024, 2, 0) }, { "m25p10", INFO(0x202011, 0, 32 * 1024, 4, 0) }, -- 2.25.1