diff --git a/drivers/mtd/spi-nor/spansion.c b/drivers/mtd/spi-nor/spansion.c index c5988312cc91..56b43074ef17 100644 --- a/drivers/mtd/spi-nor/spansion.c +++ b/drivers/mtd/spi-nor/spansion.c @@ -23,6 +23,88 @@ #define SPINOR_REG_CYPRESS_CFR5V_OCT_DTR_DS 0 #define SPINOR_OP_CYPRESS_RD_FAST 0xee +/* Cypress SPI NOR flash operations. */ +#define CYPRESS_NOR_WR_ANY_REG_OP(naddr, addr, ndata, buf) \ + SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WR_ANY_REG, 0), \ + SPI_MEM_OP_ADDR(naddr, addr, 0), \ + SPI_MEM_OP_NO_DUMMY, \ + SPI_MEM_OP_DATA_OUT(ndata, buf, 0)) + +static int cypress_nor_octal_dtr_en(struct spi_nor *nor) +{ + struct spi_mem_op op; + u8 *buf = nor->bouncebuf; + int ret; + + /* Use 24 dummy cycles for memory array reads. */ + *buf = SPINOR_REG_CYPRESS_CFR2V_MEMLAT_11_24; + op = (struct spi_mem_op) + CYPRESS_NOR_WR_ANY_REG_OP(3, SPINOR_REG_CYPRESS_CFR2V, 1, buf); + + ret = spi_nor_write_any_volatile_reg(nor, &op, nor->reg_proto); + if (ret) + return ret; + + ret = spi_nor_wait_till_ready(nor); + if (ret) + return ret; + + nor->read_dummy = 24; + + /* Set the octal and DTR enable bits. */ + buf[0] = SPINOR_REG_CYPRESS_CFR5V_OCT_DTR_EN; + op = (struct spi_mem_op) + CYPRESS_NOR_WR_ANY_REG_OP(3, SPINOR_REG_CYPRESS_CFR5V, 1, buf); + + ret = spi_nor_write_any_volatile_reg(nor, &op, nor->reg_proto); + if (ret) + return ret; + + /* Read flash ID to make sure the switch was successful. */ + ret = spi_nor_read_id(nor, 4, 3, buf, SNOR_PROTO_8_8_8_DTR); + if (ret) { + dev_dbg(nor->dev, "error %d reading JEDEC ID after enabling 8D-8D-8D mode\n", ret); + return ret; + } + + if (memcmp(buf, nor->info->id, nor->info->id_len)) + return -EINVAL; + + return 0; +} + +static int cypress_nor_octal_dtr_dis(struct spi_nor *nor) +{ + struct spi_mem_op op; + u8 *buf = nor->bouncebuf; + int ret; + + /* + * The register is 1-byte wide, but 1-byte transactions are not allowed + * in 8D-8D-8D mode. Since there is no register at the next location, + * just initialize the value to 0 and let the transaction go on. + */ + buf[0] = SPINOR_REG_CYPRESS_CFR5V_OCT_DTR_DS; + buf[1] = 0; + op = (struct spi_mem_op) + CYPRESS_NOR_WR_ANY_REG_OP(4, SPINOR_REG_CYPRESS_CFR5V, 2, buf); + ret = spi_nor_write_any_volatile_reg(nor, &op, SNOR_PROTO_8_8_8_DTR); + if (ret) + return ret; + + /* Read flash ID to make sure the switch was successful. */ + ret = spi_nor_read_id(nor, 0, 0, buf, SNOR_PROTO_1_1_1); + if (ret) { + dev_dbg(nor->dev, "error %d reading JEDEC ID after disabling 8D-8D-8D mode\n", ret); + return ret; + } + + if (memcmp(buf, nor->info->id, nor->info->id_len)) + return -EINVAL; + + return 0; +} + /** * cypress_nor_octal_dtr_enable() - Enable octal DTR on Cypress flashes. * @nor: pointer to a 'struct spi_nor' @@ -35,80 +117,8 @@ */ static int cypress_nor_octal_dtr_enable(struct spi_nor *nor, bool enable) { - struct spi_mem_op op; - u8 *buf = nor->bouncebuf; - int ret; - - if (enable) { - /* Use 24 dummy cycles for memory array reads. */ - ret = spi_nor_write_enable(nor); - if (ret) - return ret; - - *buf = SPINOR_REG_CYPRESS_CFR2V_MEMLAT_11_24; - op = (struct spi_mem_op) - SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WR_ANY_REG, 1), - SPI_MEM_OP_ADDR(3, SPINOR_REG_CYPRESS_CFR2V, - 1), - SPI_MEM_OP_NO_DUMMY, - SPI_MEM_OP_DATA_OUT(1, buf, 1)); - - ret = spi_mem_exec_op(nor->spimem, &op); - if (ret) - return ret; - - ret = spi_nor_wait_till_ready(nor); - if (ret) - return ret; - - nor->read_dummy = 24; - } - - /* Set/unset the octal and DTR enable bits. */ - ret = spi_nor_write_enable(nor); - if (ret) - return ret; - - if (enable) { - buf[0] = SPINOR_REG_CYPRESS_CFR5V_OCT_DTR_EN; - } else { - /* - * The register is 1-byte wide, but 1-byte transactions are not - * allowed in 8D-8D-8D mode. Since there is no register at the - * next location, just initialize the value to 0 and let the - * transaction go on. - */ - buf[0] = SPINOR_REG_CYPRESS_CFR5V_OCT_DTR_DS; - buf[1] = 0; - } - - op = (struct spi_mem_op) - SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WR_ANY_REG, 1), - SPI_MEM_OP_ADDR(enable ? 3 : 4, - SPINOR_REG_CYPRESS_CFR5V, - 1), - SPI_MEM_OP_NO_DUMMY, - SPI_MEM_OP_DATA_OUT(enable ? 1 : 2, buf, 1)); - - if (!enable) - spi_nor_spimem_setup_op(nor, &op, SNOR_PROTO_8_8_8_DTR); - - ret = spi_mem_exec_op(nor->spimem, &op); - if (ret) - return ret; - - /* Read flash ID to make sure the switch was successful. */ - if (enable) - ret = spi_nor_read_id(nor, 4, 3, buf, SNOR_PROTO_8_8_8_DTR); - else - ret = spi_nor_read_id(nor, 0, 0, buf, SNOR_PROTO_1_1_1); - if (ret) - return ret; - - if (memcmp(buf, nor->info->id, nor->info->id_len)) - return -EINVAL; - - return 0; + return enable ? cypress_nor_octal_dtr_en(nor) : + cypress_nor_octal_dtr_dis(nor); } static void s28hs512t_default_init(struct spi_nor *nor)