162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2005, Intec Automation Inc. 462306a36Sopenharmony_ci * Copyright (C) 2014, Freescale Semiconductor, Inc. 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/mtd/spi-nor.h> 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include "core.h" 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci/* flash_info mfr_flag. Used to read proprietary FSR register. */ 1262306a36Sopenharmony_ci#define USE_FSR BIT(0) 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#define SPINOR_OP_RDFSR 0x70 /* Read flag status register */ 1562306a36Sopenharmony_ci#define SPINOR_OP_CLFSR 0x50 /* Clear flag status register */ 1662306a36Sopenharmony_ci#define SPINOR_OP_MT_DTR_RD 0xfd /* Fast Read opcode in DTR mode */ 1762306a36Sopenharmony_ci#define SPINOR_OP_MT_RD_ANY_REG 0x85 /* Read volatile register */ 1862306a36Sopenharmony_ci#define SPINOR_OP_MT_WR_ANY_REG 0x81 /* Write volatile register */ 1962306a36Sopenharmony_ci#define SPINOR_REG_MT_CFR0V 0x00 /* For setting octal DTR mode */ 2062306a36Sopenharmony_ci#define SPINOR_REG_MT_CFR1V 0x01 /* For setting dummy cycles */ 2162306a36Sopenharmony_ci#define SPINOR_REG_MT_CFR1V_DEF 0x1f /* Default dummy cycles */ 2262306a36Sopenharmony_ci#define SPINOR_MT_OCT_DTR 0xe7 /* Enable Octal DTR. */ 2362306a36Sopenharmony_ci#define SPINOR_MT_EXSPI 0xff /* Enable Extended SPI (default) */ 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci/* Flag Status Register bits */ 2662306a36Sopenharmony_ci#define FSR_READY BIT(7) /* Device status, 0 = Busy, 1 = Ready */ 2762306a36Sopenharmony_ci#define FSR_E_ERR BIT(5) /* Erase operation status */ 2862306a36Sopenharmony_ci#define FSR_P_ERR BIT(4) /* Program operation status */ 2962306a36Sopenharmony_ci#define FSR_PT_ERR BIT(1) /* Protection error bit */ 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci/* Micron ST SPI NOR flash operations. */ 3262306a36Sopenharmony_ci#define MICRON_ST_NOR_WR_ANY_REG_OP(naddr, addr, ndata, buf) \ 3362306a36Sopenharmony_ci SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_MT_WR_ANY_REG, 0), \ 3462306a36Sopenharmony_ci SPI_MEM_OP_ADDR(naddr, addr, 0), \ 3562306a36Sopenharmony_ci SPI_MEM_OP_NO_DUMMY, \ 3662306a36Sopenharmony_ci SPI_MEM_OP_DATA_OUT(ndata, buf, 0)) 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci#define MICRON_ST_RDFSR_OP(buf) \ 3962306a36Sopenharmony_ci SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_RDFSR, 0), \ 4062306a36Sopenharmony_ci SPI_MEM_OP_NO_ADDR, \ 4162306a36Sopenharmony_ci SPI_MEM_OP_NO_DUMMY, \ 4262306a36Sopenharmony_ci SPI_MEM_OP_DATA_IN(1, buf, 0)) 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci#define MICRON_ST_CLFSR_OP \ 4562306a36Sopenharmony_ci SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_CLFSR, 0), \ 4662306a36Sopenharmony_ci SPI_MEM_OP_NO_ADDR, \ 4762306a36Sopenharmony_ci SPI_MEM_OP_NO_DUMMY, \ 4862306a36Sopenharmony_ci SPI_MEM_OP_NO_DATA) 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_cistatic int micron_st_nor_octal_dtr_en(struct spi_nor *nor) 5162306a36Sopenharmony_ci{ 5262306a36Sopenharmony_ci struct spi_mem_op op; 5362306a36Sopenharmony_ci u8 *buf = nor->bouncebuf; 5462306a36Sopenharmony_ci int ret; 5562306a36Sopenharmony_ci u8 addr_mode_nbytes = nor->params->addr_mode_nbytes; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci /* Use 20 dummy cycles for memory array reads. */ 5862306a36Sopenharmony_ci *buf = 20; 5962306a36Sopenharmony_ci op = (struct spi_mem_op) 6062306a36Sopenharmony_ci MICRON_ST_NOR_WR_ANY_REG_OP(addr_mode_nbytes, 6162306a36Sopenharmony_ci SPINOR_REG_MT_CFR1V, 1, buf); 6262306a36Sopenharmony_ci ret = spi_nor_write_any_volatile_reg(nor, &op, nor->reg_proto); 6362306a36Sopenharmony_ci if (ret) 6462306a36Sopenharmony_ci return ret; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci buf[0] = SPINOR_MT_OCT_DTR; 6762306a36Sopenharmony_ci op = (struct spi_mem_op) 6862306a36Sopenharmony_ci MICRON_ST_NOR_WR_ANY_REG_OP(addr_mode_nbytes, 6962306a36Sopenharmony_ci SPINOR_REG_MT_CFR0V, 1, buf); 7062306a36Sopenharmony_ci ret = spi_nor_write_any_volatile_reg(nor, &op, nor->reg_proto); 7162306a36Sopenharmony_ci if (ret) 7262306a36Sopenharmony_ci return ret; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci /* Read flash ID to make sure the switch was successful. */ 7562306a36Sopenharmony_ci ret = spi_nor_read_id(nor, 0, 8, buf, SNOR_PROTO_8_8_8_DTR); 7662306a36Sopenharmony_ci if (ret) { 7762306a36Sopenharmony_ci dev_dbg(nor->dev, "error %d reading JEDEC ID after enabling 8D-8D-8D mode\n", ret); 7862306a36Sopenharmony_ci return ret; 7962306a36Sopenharmony_ci } 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci if (memcmp(buf, nor->info->id, nor->info->id_len)) 8262306a36Sopenharmony_ci return -EINVAL; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci return 0; 8562306a36Sopenharmony_ci} 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_cistatic int micron_st_nor_octal_dtr_dis(struct spi_nor *nor) 8862306a36Sopenharmony_ci{ 8962306a36Sopenharmony_ci struct spi_mem_op op; 9062306a36Sopenharmony_ci u8 *buf = nor->bouncebuf; 9162306a36Sopenharmony_ci int ret; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci /* 9462306a36Sopenharmony_ci * The register is 1-byte wide, but 1-byte transactions are not allowed 9562306a36Sopenharmony_ci * in 8D-8D-8D mode. The next register is the dummy cycle configuration 9662306a36Sopenharmony_ci * register. Since the transaction needs to be at least 2 bytes wide, 9762306a36Sopenharmony_ci * set the next register to its default value. This also makes sense 9862306a36Sopenharmony_ci * because the value was changed when enabling 8D-8D-8D mode, it should 9962306a36Sopenharmony_ci * be reset when disabling. 10062306a36Sopenharmony_ci */ 10162306a36Sopenharmony_ci buf[0] = SPINOR_MT_EXSPI; 10262306a36Sopenharmony_ci buf[1] = SPINOR_REG_MT_CFR1V_DEF; 10362306a36Sopenharmony_ci op = (struct spi_mem_op) 10462306a36Sopenharmony_ci MICRON_ST_NOR_WR_ANY_REG_OP(nor->addr_nbytes, 10562306a36Sopenharmony_ci SPINOR_REG_MT_CFR0V, 2, buf); 10662306a36Sopenharmony_ci ret = spi_nor_write_any_volatile_reg(nor, &op, SNOR_PROTO_8_8_8_DTR); 10762306a36Sopenharmony_ci if (ret) 10862306a36Sopenharmony_ci return ret; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci /* Read flash ID to make sure the switch was successful. */ 11162306a36Sopenharmony_ci ret = spi_nor_read_id(nor, 0, 0, buf, SNOR_PROTO_1_1_1); 11262306a36Sopenharmony_ci if (ret) { 11362306a36Sopenharmony_ci dev_dbg(nor->dev, "error %d reading JEDEC ID after disabling 8D-8D-8D mode\n", ret); 11462306a36Sopenharmony_ci return ret; 11562306a36Sopenharmony_ci } 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci if (memcmp(buf, nor->info->id, nor->info->id_len)) 11862306a36Sopenharmony_ci return -EINVAL; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci return 0; 12162306a36Sopenharmony_ci} 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_cistatic int micron_st_nor_set_octal_dtr(struct spi_nor *nor, bool enable) 12462306a36Sopenharmony_ci{ 12562306a36Sopenharmony_ci return enable ? micron_st_nor_octal_dtr_en(nor) : 12662306a36Sopenharmony_ci micron_st_nor_octal_dtr_dis(nor); 12762306a36Sopenharmony_ci} 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_cistatic void mt35xu512aba_default_init(struct spi_nor *nor) 13062306a36Sopenharmony_ci{ 13162306a36Sopenharmony_ci nor->params->set_octal_dtr = micron_st_nor_set_octal_dtr; 13262306a36Sopenharmony_ci} 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_cistatic int mt35xu512aba_post_sfdp_fixup(struct spi_nor *nor) 13562306a36Sopenharmony_ci{ 13662306a36Sopenharmony_ci /* Set the Fast Read settings. */ 13762306a36Sopenharmony_ci nor->params->hwcaps.mask |= SNOR_HWCAPS_READ_8_8_8_DTR; 13862306a36Sopenharmony_ci spi_nor_set_read_settings(&nor->params->reads[SNOR_CMD_READ_8_8_8_DTR], 13962306a36Sopenharmony_ci 0, 20, SPINOR_OP_MT_DTR_RD, 14062306a36Sopenharmony_ci SNOR_PROTO_8_8_8_DTR); 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci nor->cmd_ext_type = SPI_NOR_EXT_REPEAT; 14362306a36Sopenharmony_ci nor->params->rdsr_dummy = 8; 14462306a36Sopenharmony_ci nor->params->rdsr_addr_nbytes = 0; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci /* 14762306a36Sopenharmony_ci * The BFPT quad enable field is set to a reserved value so the quad 14862306a36Sopenharmony_ci * enable function is ignored by spi_nor_parse_bfpt(). Make sure we 14962306a36Sopenharmony_ci * disable it. 15062306a36Sopenharmony_ci */ 15162306a36Sopenharmony_ci nor->params->quad_enable = NULL; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci return 0; 15462306a36Sopenharmony_ci} 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_cistatic const struct spi_nor_fixups mt35xu512aba_fixups = { 15762306a36Sopenharmony_ci .default_init = mt35xu512aba_default_init, 15862306a36Sopenharmony_ci .post_sfdp = mt35xu512aba_post_sfdp_fixup, 15962306a36Sopenharmony_ci}; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_cistatic const struct flash_info micron_nor_parts[] = { 16262306a36Sopenharmony_ci { "mt35xu512aba", INFO(0x2c5b1a, 0, 128 * 1024, 512) 16362306a36Sopenharmony_ci NO_SFDP_FLAGS(SECT_4K | SPI_NOR_OCTAL_READ | 16462306a36Sopenharmony_ci SPI_NOR_OCTAL_DTR_READ | SPI_NOR_OCTAL_DTR_PP) 16562306a36Sopenharmony_ci FIXUP_FLAGS(SPI_NOR_4B_OPCODES | SPI_NOR_IO_MODE_EN_VOLATILE) 16662306a36Sopenharmony_ci MFR_FLAGS(USE_FSR) 16762306a36Sopenharmony_ci .fixups = &mt35xu512aba_fixups 16862306a36Sopenharmony_ci }, 16962306a36Sopenharmony_ci { "mt35xu02g", INFO(0x2c5b1c, 0, 128 * 1024, 2048) 17062306a36Sopenharmony_ci NO_SFDP_FLAGS(SECT_4K | SPI_NOR_OCTAL_READ) 17162306a36Sopenharmony_ci FIXUP_FLAGS(SPI_NOR_4B_OPCODES) 17262306a36Sopenharmony_ci MFR_FLAGS(USE_FSR) 17362306a36Sopenharmony_ci }, 17462306a36Sopenharmony_ci}; 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_cistatic const struct flash_info st_nor_parts[] = { 17762306a36Sopenharmony_ci { "n25q016a", INFO(0x20bb15, 0, 64 * 1024, 32) 17862306a36Sopenharmony_ci NO_SFDP_FLAGS(SECT_4K | SPI_NOR_QUAD_READ) }, 17962306a36Sopenharmony_ci { "n25q032", INFO(0x20ba16, 0, 64 * 1024, 64) 18062306a36Sopenharmony_ci NO_SFDP_FLAGS(SPI_NOR_QUAD_READ) }, 18162306a36Sopenharmony_ci { "n25q032a", INFO(0x20bb16, 0, 64 * 1024, 64) 18262306a36Sopenharmony_ci NO_SFDP_FLAGS(SPI_NOR_QUAD_READ) }, 18362306a36Sopenharmony_ci { "n25q064", INFO(0x20ba17, 0, 64 * 1024, 128) 18462306a36Sopenharmony_ci NO_SFDP_FLAGS(SECT_4K | SPI_NOR_QUAD_READ) }, 18562306a36Sopenharmony_ci { "n25q064a", INFO(0x20bb17, 0, 64 * 1024, 128) 18662306a36Sopenharmony_ci NO_SFDP_FLAGS(SECT_4K | SPI_NOR_QUAD_READ) }, 18762306a36Sopenharmony_ci { "n25q128a11", INFO(0x20bb18, 0, 64 * 1024, 256) 18862306a36Sopenharmony_ci FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_4BIT_BP | 18962306a36Sopenharmony_ci SPI_NOR_BP3_SR_BIT6) 19062306a36Sopenharmony_ci NO_SFDP_FLAGS(SECT_4K | SPI_NOR_QUAD_READ) 19162306a36Sopenharmony_ci MFR_FLAGS(USE_FSR) 19262306a36Sopenharmony_ci }, 19362306a36Sopenharmony_ci { "n25q128a13", INFO(0x20ba18, 0, 64 * 1024, 256) 19462306a36Sopenharmony_ci FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_4BIT_BP | 19562306a36Sopenharmony_ci SPI_NOR_BP3_SR_BIT6) 19662306a36Sopenharmony_ci NO_SFDP_FLAGS(SECT_4K | SPI_NOR_QUAD_READ) 19762306a36Sopenharmony_ci MFR_FLAGS(USE_FSR) 19862306a36Sopenharmony_ci }, 19962306a36Sopenharmony_ci { "mt25ql256a", INFO6(0x20ba19, 0x104400, 64 * 1024, 512) 20062306a36Sopenharmony_ci NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) 20162306a36Sopenharmony_ci FIXUP_FLAGS(SPI_NOR_4B_OPCODES) 20262306a36Sopenharmony_ci MFR_FLAGS(USE_FSR) 20362306a36Sopenharmony_ci }, 20462306a36Sopenharmony_ci { "n25q256a", INFO(0x20ba19, 0, 64 * 1024, 512) 20562306a36Sopenharmony_ci NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | 20662306a36Sopenharmony_ci SPI_NOR_QUAD_READ) 20762306a36Sopenharmony_ci MFR_FLAGS(USE_FSR) 20862306a36Sopenharmony_ci }, 20962306a36Sopenharmony_ci { "mt25qu256a", INFO6(0x20bb19, 0x104400, 64 * 1024, 512) 21062306a36Sopenharmony_ci FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_4BIT_BP | 21162306a36Sopenharmony_ci SPI_NOR_BP3_SR_BIT6) 21262306a36Sopenharmony_ci NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) 21362306a36Sopenharmony_ci FIXUP_FLAGS(SPI_NOR_4B_OPCODES) 21462306a36Sopenharmony_ci MFR_FLAGS(USE_FSR) 21562306a36Sopenharmony_ci }, 21662306a36Sopenharmony_ci { "n25q256ax1", INFO(0x20bb19, 0, 64 * 1024, 512) 21762306a36Sopenharmony_ci NO_SFDP_FLAGS(SECT_4K | SPI_NOR_QUAD_READ) 21862306a36Sopenharmony_ci MFR_FLAGS(USE_FSR) 21962306a36Sopenharmony_ci }, 22062306a36Sopenharmony_ci { "mt25ql512a", INFO6(0x20ba20, 0x104400, 64 * 1024, 1024) 22162306a36Sopenharmony_ci NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) 22262306a36Sopenharmony_ci FIXUP_FLAGS(SPI_NOR_4B_OPCODES) 22362306a36Sopenharmony_ci MFR_FLAGS(USE_FSR) 22462306a36Sopenharmony_ci }, 22562306a36Sopenharmony_ci { "n25q512ax3", INFO(0x20ba20, 0, 64 * 1024, 1024) 22662306a36Sopenharmony_ci FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_4BIT_BP | 22762306a36Sopenharmony_ci SPI_NOR_BP3_SR_BIT6) 22862306a36Sopenharmony_ci NO_SFDP_FLAGS(SECT_4K | SPI_NOR_QUAD_READ) 22962306a36Sopenharmony_ci MFR_FLAGS(USE_FSR) 23062306a36Sopenharmony_ci }, 23162306a36Sopenharmony_ci { "mt25qu512a", INFO6(0x20bb20, 0x104400, 64 * 1024, 1024) 23262306a36Sopenharmony_ci NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) 23362306a36Sopenharmony_ci FIXUP_FLAGS(SPI_NOR_4B_OPCODES) 23462306a36Sopenharmony_ci MFR_FLAGS(USE_FSR) 23562306a36Sopenharmony_ci }, 23662306a36Sopenharmony_ci { "n25q512a", INFO(0x20bb20, 0, 64 * 1024, 1024) 23762306a36Sopenharmony_ci FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_4BIT_BP | 23862306a36Sopenharmony_ci SPI_NOR_BP3_SR_BIT6) 23962306a36Sopenharmony_ci NO_SFDP_FLAGS(SECT_4K | SPI_NOR_QUAD_READ) 24062306a36Sopenharmony_ci MFR_FLAGS(USE_FSR) 24162306a36Sopenharmony_ci }, 24262306a36Sopenharmony_ci { "n25q00", INFO(0x20ba21, 0, 64 * 1024, 2048) 24362306a36Sopenharmony_ci FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_4BIT_BP | 24462306a36Sopenharmony_ci SPI_NOR_BP3_SR_BIT6 | NO_CHIP_ERASE) 24562306a36Sopenharmony_ci NO_SFDP_FLAGS(SECT_4K | SPI_NOR_QUAD_READ) 24662306a36Sopenharmony_ci MFR_FLAGS(USE_FSR) 24762306a36Sopenharmony_ci }, 24862306a36Sopenharmony_ci { "n25q00a", INFO(0x20bb21, 0, 64 * 1024, 2048) 24962306a36Sopenharmony_ci FLAGS(NO_CHIP_ERASE) 25062306a36Sopenharmony_ci NO_SFDP_FLAGS(SECT_4K | SPI_NOR_QUAD_READ) 25162306a36Sopenharmony_ci MFR_FLAGS(USE_FSR) 25262306a36Sopenharmony_ci }, 25362306a36Sopenharmony_ci { "mt25ql02g", INFO(0x20ba22, 0, 64 * 1024, 4096) 25462306a36Sopenharmony_ci FLAGS(NO_CHIP_ERASE) 25562306a36Sopenharmony_ci NO_SFDP_FLAGS(SECT_4K | SPI_NOR_QUAD_READ) 25662306a36Sopenharmony_ci MFR_FLAGS(USE_FSR) 25762306a36Sopenharmony_ci }, 25862306a36Sopenharmony_ci { "mt25qu02g", INFO(0x20bb22, 0, 64 * 1024, 4096) 25962306a36Sopenharmony_ci FLAGS(NO_CHIP_ERASE) 26062306a36Sopenharmony_ci NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | 26162306a36Sopenharmony_ci SPI_NOR_QUAD_READ) 26262306a36Sopenharmony_ci MFR_FLAGS(USE_FSR) 26362306a36Sopenharmony_ci }, 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci { "m25p05", INFO(0x202010, 0, 32 * 1024, 2) }, 26662306a36Sopenharmony_ci { "m25p10", INFO(0x202011, 0, 32 * 1024, 4) }, 26762306a36Sopenharmony_ci { "m25p20", INFO(0x202012, 0, 64 * 1024, 4) }, 26862306a36Sopenharmony_ci { "m25p40", INFO(0x202013, 0, 64 * 1024, 8) }, 26962306a36Sopenharmony_ci { "m25p80", INFO(0x202014, 0, 64 * 1024, 16) }, 27062306a36Sopenharmony_ci { "m25p16", INFO(0x202015, 0, 64 * 1024, 32) }, 27162306a36Sopenharmony_ci { "m25p32", INFO(0x202016, 0, 64 * 1024, 64) }, 27262306a36Sopenharmony_ci { "m25p64", INFO(0x202017, 0, 64 * 1024, 128) }, 27362306a36Sopenharmony_ci { "m25p128", INFO(0x202018, 0, 256 * 1024, 64) }, 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci { "m25p05-nonjedec", INFO(0, 0, 32 * 1024, 2) }, 27662306a36Sopenharmony_ci { "m25p10-nonjedec", INFO(0, 0, 32 * 1024, 4) }, 27762306a36Sopenharmony_ci { "m25p20-nonjedec", INFO(0, 0, 64 * 1024, 4) }, 27862306a36Sopenharmony_ci { "m25p40-nonjedec", INFO(0, 0, 64 * 1024, 8) }, 27962306a36Sopenharmony_ci { "m25p80-nonjedec", INFO(0, 0, 64 * 1024, 16) }, 28062306a36Sopenharmony_ci { "m25p16-nonjedec", INFO(0, 0, 64 * 1024, 32) }, 28162306a36Sopenharmony_ci { "m25p32-nonjedec", INFO(0, 0, 64 * 1024, 64) }, 28262306a36Sopenharmony_ci { "m25p64-nonjedec", INFO(0, 0, 64 * 1024, 128) }, 28362306a36Sopenharmony_ci { "m25p128-nonjedec", INFO(0, 0, 256 * 1024, 64) }, 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci { "m45pe10", INFO(0x204011, 0, 64 * 1024, 2) }, 28662306a36Sopenharmony_ci { "m45pe80", INFO(0x204014, 0, 64 * 1024, 16) }, 28762306a36Sopenharmony_ci { "m45pe16", INFO(0x204015, 0, 64 * 1024, 32) }, 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci { "m25pe20", INFO(0x208012, 0, 64 * 1024, 4) }, 29062306a36Sopenharmony_ci { "m25pe80", INFO(0x208014, 0, 64 * 1024, 16) }, 29162306a36Sopenharmony_ci { "m25pe16", INFO(0x208015, 0, 64 * 1024, 32) 29262306a36Sopenharmony_ci NO_SFDP_FLAGS(SECT_4K) }, 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci { "m25px16", INFO(0x207115, 0, 64 * 1024, 32) 29562306a36Sopenharmony_ci NO_SFDP_FLAGS(SECT_4K) }, 29662306a36Sopenharmony_ci { "m25px32", INFO(0x207116, 0, 64 * 1024, 64) 29762306a36Sopenharmony_ci NO_SFDP_FLAGS(SECT_4K) }, 29862306a36Sopenharmony_ci { "m25px32-s0", INFO(0x207316, 0, 64 * 1024, 64) 29962306a36Sopenharmony_ci NO_SFDP_FLAGS(SECT_4K) }, 30062306a36Sopenharmony_ci { "m25px32-s1", INFO(0x206316, 0, 64 * 1024, 64) 30162306a36Sopenharmony_ci NO_SFDP_FLAGS(SECT_4K) }, 30262306a36Sopenharmony_ci { "m25px64", INFO(0x207117, 0, 64 * 1024, 128) }, 30362306a36Sopenharmony_ci { "m25px80", INFO(0x207114, 0, 64 * 1024, 16) }, 30462306a36Sopenharmony_ci}; 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci/** 30762306a36Sopenharmony_ci * micron_st_nor_read_fsr() - Read the Flag Status Register. 30862306a36Sopenharmony_ci * @nor: pointer to 'struct spi_nor' 30962306a36Sopenharmony_ci * @fsr: pointer to a DMA-able buffer where the value of the 31062306a36Sopenharmony_ci * Flag Status Register will be written. Should be at least 2 31162306a36Sopenharmony_ci * bytes. 31262306a36Sopenharmony_ci * 31362306a36Sopenharmony_ci * Return: 0 on success, -errno otherwise. 31462306a36Sopenharmony_ci */ 31562306a36Sopenharmony_cistatic int micron_st_nor_read_fsr(struct spi_nor *nor, u8 *fsr) 31662306a36Sopenharmony_ci{ 31762306a36Sopenharmony_ci int ret; 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci if (nor->spimem) { 32062306a36Sopenharmony_ci struct spi_mem_op op = MICRON_ST_RDFSR_OP(fsr); 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci if (nor->reg_proto == SNOR_PROTO_8_8_8_DTR) { 32362306a36Sopenharmony_ci op.addr.nbytes = nor->params->rdsr_addr_nbytes; 32462306a36Sopenharmony_ci op.dummy.nbytes = nor->params->rdsr_dummy; 32562306a36Sopenharmony_ci /* 32662306a36Sopenharmony_ci * We don't want to read only one byte in DTR mode. So, 32762306a36Sopenharmony_ci * read 2 and then discard the second byte. 32862306a36Sopenharmony_ci */ 32962306a36Sopenharmony_ci op.data.nbytes = 2; 33062306a36Sopenharmony_ci } 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci spi_nor_spimem_setup_op(nor, &op, nor->reg_proto); 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci ret = spi_mem_exec_op(nor->spimem, &op); 33562306a36Sopenharmony_ci } else { 33662306a36Sopenharmony_ci ret = spi_nor_controller_ops_read_reg(nor, SPINOR_OP_RDFSR, fsr, 33762306a36Sopenharmony_ci 1); 33862306a36Sopenharmony_ci } 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci if (ret) 34162306a36Sopenharmony_ci dev_dbg(nor->dev, "error %d reading FSR\n", ret); 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci return ret; 34462306a36Sopenharmony_ci} 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci/** 34762306a36Sopenharmony_ci * micron_st_nor_clear_fsr() - Clear the Flag Status Register. 34862306a36Sopenharmony_ci * @nor: pointer to 'struct spi_nor'. 34962306a36Sopenharmony_ci */ 35062306a36Sopenharmony_cistatic void micron_st_nor_clear_fsr(struct spi_nor *nor) 35162306a36Sopenharmony_ci{ 35262306a36Sopenharmony_ci int ret; 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci if (nor->spimem) { 35562306a36Sopenharmony_ci struct spi_mem_op op = MICRON_ST_CLFSR_OP; 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci spi_nor_spimem_setup_op(nor, &op, nor->reg_proto); 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci ret = spi_mem_exec_op(nor->spimem, &op); 36062306a36Sopenharmony_ci } else { 36162306a36Sopenharmony_ci ret = spi_nor_controller_ops_write_reg(nor, SPINOR_OP_CLFSR, 36262306a36Sopenharmony_ci NULL, 0); 36362306a36Sopenharmony_ci } 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci if (ret) 36662306a36Sopenharmony_ci dev_dbg(nor->dev, "error %d clearing FSR\n", ret); 36762306a36Sopenharmony_ci} 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci/** 37062306a36Sopenharmony_ci * micron_st_nor_ready() - Query the Status Register as well as the Flag Status 37162306a36Sopenharmony_ci * Register to see if the flash is ready for new commands. If there are any 37262306a36Sopenharmony_ci * errors in the FSR clear them. 37362306a36Sopenharmony_ci * @nor: pointer to 'struct spi_nor'. 37462306a36Sopenharmony_ci * 37562306a36Sopenharmony_ci * Return: 1 if ready, 0 if not ready, -errno on errors. 37662306a36Sopenharmony_ci */ 37762306a36Sopenharmony_cistatic int micron_st_nor_ready(struct spi_nor *nor) 37862306a36Sopenharmony_ci{ 37962306a36Sopenharmony_ci int sr_ready, ret; 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci sr_ready = spi_nor_sr_ready(nor); 38262306a36Sopenharmony_ci if (sr_ready < 0) 38362306a36Sopenharmony_ci return sr_ready; 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci ret = micron_st_nor_read_fsr(nor, nor->bouncebuf); 38662306a36Sopenharmony_ci if (ret) { 38762306a36Sopenharmony_ci /* 38862306a36Sopenharmony_ci * Some controllers, such as Intel SPI, do not support low 38962306a36Sopenharmony_ci * level operations such as reading the flag status 39062306a36Sopenharmony_ci * register. They only expose small amount of high level 39162306a36Sopenharmony_ci * operations to the software. If this is the case we use 39262306a36Sopenharmony_ci * only the status register value. 39362306a36Sopenharmony_ci */ 39462306a36Sopenharmony_ci return ret == -EOPNOTSUPP ? sr_ready : ret; 39562306a36Sopenharmony_ci } 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci if (nor->bouncebuf[0] & (FSR_E_ERR | FSR_P_ERR)) { 39862306a36Sopenharmony_ci if (nor->bouncebuf[0] & FSR_E_ERR) 39962306a36Sopenharmony_ci dev_err(nor->dev, "Erase operation failed.\n"); 40062306a36Sopenharmony_ci else 40162306a36Sopenharmony_ci dev_err(nor->dev, "Program operation failed.\n"); 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci if (nor->bouncebuf[0] & FSR_PT_ERR) 40462306a36Sopenharmony_ci dev_err(nor->dev, 40562306a36Sopenharmony_ci "Attempted to modify a protected sector.\n"); 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci micron_st_nor_clear_fsr(nor); 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci /* 41062306a36Sopenharmony_ci * WEL bit remains set to one when an erase or page program 41162306a36Sopenharmony_ci * error occurs. Issue a Write Disable command to protect 41262306a36Sopenharmony_ci * against inadvertent writes that can possibly corrupt the 41362306a36Sopenharmony_ci * contents of the memory. 41462306a36Sopenharmony_ci */ 41562306a36Sopenharmony_ci ret = spi_nor_write_disable(nor); 41662306a36Sopenharmony_ci if (ret) 41762306a36Sopenharmony_ci return ret; 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci return -EIO; 42062306a36Sopenharmony_ci } 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci return sr_ready && !!(nor->bouncebuf[0] & FSR_READY); 42362306a36Sopenharmony_ci} 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_cistatic void micron_st_nor_default_init(struct spi_nor *nor) 42662306a36Sopenharmony_ci{ 42762306a36Sopenharmony_ci nor->flags |= SNOR_F_HAS_LOCK; 42862306a36Sopenharmony_ci nor->flags &= ~SNOR_F_HAS_16BIT_SR; 42962306a36Sopenharmony_ci nor->params->quad_enable = NULL; 43062306a36Sopenharmony_ci} 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_cistatic int micron_st_nor_late_init(struct spi_nor *nor) 43362306a36Sopenharmony_ci{ 43462306a36Sopenharmony_ci struct spi_nor_flash_parameter *params = nor->params; 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci if (nor->info->mfr_flags & USE_FSR) 43762306a36Sopenharmony_ci params->ready = micron_st_nor_ready; 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci if (!params->set_4byte_addr_mode) 44062306a36Sopenharmony_ci params->set_4byte_addr_mode = spi_nor_set_4byte_addr_mode_wren_en4b_ex4b; 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci return 0; 44362306a36Sopenharmony_ci} 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_cistatic const struct spi_nor_fixups micron_st_nor_fixups = { 44662306a36Sopenharmony_ci .default_init = micron_st_nor_default_init, 44762306a36Sopenharmony_ci .late_init = micron_st_nor_late_init, 44862306a36Sopenharmony_ci}; 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ciconst struct spi_nor_manufacturer spi_nor_micron = { 45162306a36Sopenharmony_ci .name = "micron", 45262306a36Sopenharmony_ci .parts = micron_nor_parts, 45362306a36Sopenharmony_ci .nparts = ARRAY_SIZE(micron_nor_parts), 45462306a36Sopenharmony_ci .fixups = µn_st_nor_fixups, 45562306a36Sopenharmony_ci}; 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ciconst struct spi_nor_manufacturer spi_nor_st = { 45862306a36Sopenharmony_ci .name = "st", 45962306a36Sopenharmony_ci .parts = st_nor_parts, 46062306a36Sopenharmony_ci .nparts = ARRAY_SIZE(st_nor_parts), 46162306a36Sopenharmony_ci .fixups = µn_st_nor_fixups, 46262306a36Sopenharmony_ci}; 463