@@ -758,6 +758,21 @@ static void spi_nor_set_4byte_opcodes(struct spi_nor *nor)
}
}
+static int spi_nor_write_ear(struct spi_nor *nor, u8 ear)
+{
+ if (nor->spimem) {
+ struct spi_mem_op op =
+ SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WREAR, 1),
+ SPI_MEM_OP_NO_ADDR,
+ SPI_MEM_OP_NO_DUMMY,
+ SPI_MEM_OP_DATA_OUT(0, NULL, 1));
+
+ return spi_nor_data_op(nor, &op, &ear, 1);
+ }
+
+ return nor->write_reg(nor, SPINOR_OP_WREAR, &ear, 1);
+}
+
static int macronix_set_4byte(struct spi_nor *nor, bool enable)
{
if (nor->spimem) {
@@ -777,6 +792,39 @@ static int macronix_set_4byte(struct spi_nor *nor, bool enable)
NULL, 0);
}
+static int st_micron_set_4byte(struct spi_nor *nor, bool enable)
+{
+ int ret;
+
+ write_enable(nor);
+ ret = macronix_set_4byte(nor, enable);
+ write_disable(nor);
+
+ return ret;
+}
+
+static int winbond_set_4byte(struct spi_nor *nor, bool enable)
+{
+ int ret;
+
+ ret = macronix_set_4byte(nor, enable);
+ if (ret || enable)
+ return ret;
+
+ /*
+ * On Winbond W25Q256FV, leaving 4byte mode causes the Extended Address
+ * Register to be set to 1, so all 3-byte-address reads come from the
+ * second 16M.
+ * We must clear the register to enable normal behavior.
+ */
+ write_enable(nor);
+ nor->cmd_buf[0] = 0;
+ ret = spi_nor_write_ear(nor, nor->cmd_buf[0]);
+ write_disable(nor);
+
+ return ret;
+}
+
static int spansion_set_4byte(struct spi_nor *nor, bool enable)
{
u8 quad_en = enable << 7;
@@ -794,62 +842,6 @@ static int spansion_set_4byte(struct spi_nor *nor, bool enable)
return nor->write_reg(nor, SPINOR_OP_BRWR, &quad_en, 1);
}
-static int spi_nor_write_ear(struct spi_nor *nor, u8 ear)
-{
- if (nor->spimem) {
- struct spi_mem_op op =
- SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WREAR, 1),
- SPI_MEM_OP_NO_ADDR,
- SPI_MEM_OP_NO_DUMMY,
- SPI_MEM_OP_DATA_OUT(0, NULL, 1));
-
- return spi_nor_data_op(nor, &op, &ear, 1);
- }
-
- return nor->write_reg(nor, SPINOR_OP_WREAR, &ear, 1);
-}
-
-/* Enable/disable 4-byte addressing mode. */
-static int set_4byte(struct spi_nor *nor, bool enable)
-{
- int status;
- bool need_wren = false;
-
- switch (JEDEC_MFR(nor->info)) {
- case SNOR_MFR_ST:
- case SNOR_MFR_MICRON:
- /* Some Micron need WREN command; all will accept it */
- need_wren = true;
- /* fall through */
- case SNOR_MFR_MACRONIX:
- case SNOR_MFR_WINBOND:
- if (need_wren)
- write_enable(nor);
-
- status = macronix_set_4byte(nor, enable);
- if (need_wren)
- write_disable(nor);
-
- if (!status && !enable &&
- JEDEC_MFR(nor->info) == SNOR_MFR_WINBOND) {
- /*
- * On Winbond W25Q256FV, leaving 4byte mode causes
- * the Extended Address Register to be set to 1, so all
- * 3-byte-address reads come from the second 16M.
- * We must clear the register to enable normal behavior.
- */
- write_enable(nor);
- spi_nor_write_ear(nor, 0);
- write_disable(nor);
- }
-
- return status;
- default:
- /* Spansion style */
- return spansion_set_4byte(nor, enable);
- }
-}
-
static int spi_nor_xread_sr(struct spi_nor *nor, u8 *sr)
{
if (nor->spimem) {
@@ -4287,11 +4279,18 @@ static int spi_nor_parse_sfdp(struct spi_nor *nor,
static void macronix_set_default_init(struct spi_nor *nor)
{
nor->quad_enable = macronix_quad_enable;
+ nor->set_4byte = macronix_set_4byte;
}
static void st_micron_set_default_init(struct spi_nor *nor)
{
nor->quad_enable = NULL;
+ nor->set_4byte = st_micron_set_4byte;
+}
+
+static void winbond_set_default_init(struct spi_nor *nor)
+{
+ nor->set_4byte = winbond_set_4byte;
}
static void spi_nor_mfr_init_params(struct spi_nor *nor,
@@ -4307,6 +4306,9 @@ static void spi_nor_mfr_init_params(struct spi_nor *nor,
st_micron_set_default_init(nor);
break;
+ case SNOR_MFR_WINBOND:
+ winbond_set_default_init(nor);
+ break;
default:
break;
}
@@ -4685,7 +4687,7 @@ static int spi_nor_init(struct spi_nor *nor)
*/
WARN_ONCE(nor->flags & SNOR_F_BROKEN_RESET,
"enabling reset hack; may not recover from unexpected reboots\n");
- set_4byte(nor, true);
+ nor->set_4byte(nor, true);
}
return 0;
@@ -4709,7 +4711,7 @@ void spi_nor_restore(struct spi_nor *nor)
/* restore the addressing mode */
if (nor->addr_width == 4 && !(nor->flags & SNOR_F_4B_OPCODES) &&
nor->flags & SNOR_F_BROKEN_RESET)
- set_4byte(nor, false);
+ nor->set_4byte(nor, false);
}
EXPORT_SYMBOL_GPL(spi_nor_restore);
@@ -4801,6 +4803,7 @@ int spi_nor_scan(struct spi_nor *nor, const char *name,
/* Kept only for backward compatibility purpose. */
nor->quad_enable = spansion_quad_enable;
+ nor->set_4byte = spansion_set_4byte;
/* Init flash parameters based on flash_info struct and SFDP */
spi_nor_init_params(nor, ¶ms);
@@ -378,6 +378,8 @@ struct flash_info;
* @flash_unlock: [FLASH-SPECIFIC] unlock a region of the SPI NOR
* @flash_is_locked: [FLASH-SPECIFIC] check if a region of the SPI NOR is
* @quad_enable: [FLASH-SPECIFIC] enables SPI NOR quad mode
+ * @set_4byte: [FLASH-SPECIFIC] puts the SPI NOR in 4 byte addressing
+ * mode
* @clear_sr_bp: [FLASH-SPECIFIC] clears the Block Protection Bits from
* the SPI NOR Status Register.
* completely locked
@@ -420,6 +422,7 @@ struct spi_nor {
int (*flash_unlock)(struct spi_nor *nor, loff_t ofs, uint64_t len);
int (*flash_is_locked)(struct spi_nor *nor, loff_t ofs, uint64_t len);
int (*quad_enable)(struct spi_nor *nor);
+ int (*set_4byte)(struct spi_nor *nor, bool enable);
int (*clear_sr_bp)(struct spi_nor *nor);
void *priv;