Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1221426 > unrolled thread
| Started by | Cyrille Pitchen <cyrille.pitchen@atmel.com> |
|---|---|
| First post | 2015-09-09 15:30 +0200 |
| Last post | 2015-09-10 12:30 +0200 |
| Articles | 2 — 2 participants |
Back to article view | Back to linux.kernel
This discussion starts older than the indexed window; earlier articles aren't shown. The article labeled Started by
below is the oldest one visible, not the original post.
[PATCH linux-next v6 4/8] mtd: spi-nor: use optimized commands for read/write/erase operations Cyrille Pitchen <cyrille.pitchen@atmel.com> - 2015-09-09 15:30 +0200
Re: [PATCH linux-next v6 4/8] mtd: spi-nor: use optimized commands for read/write/erase operations Jonas Gorski <jogo@openwrt.org> - 2015-09-10 12:30 +0200
| From | Cyrille Pitchen <cyrille.pitchen@atmel.com> |
|---|---|
| Date | 2015-09-09 15:30 +0200 |
| Subject | [PATCH linux-next v6 4/8] mtd: spi-nor: use optimized commands for read/write/erase operations |
| Message-ID | <q6NBN-4jS-13@gated-at.bofh.it> |
The op codes used by the spi-nor framework are now tuned depending on the
memory manufacturer.
Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com>
---
drivers/mtd/spi-nor/spi-nor.c | 156 +++++++++++++++++++++++++++++++++++-------
include/linux/mtd/spi-nor.h | 6 ++
2 files changed, 138 insertions(+), 24 deletions(-)
diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index 4b36aada3f4c..820a2177ed5e 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -193,6 +193,8 @@ static inline int set_4byte(struct spi_nor *nor, const struct flash_info *info,
write_disable(nor);
return status;
+ case CFI_MFR_AMD:
+ return 0;
default:
/* Spansion style */
nor->cmd_buf[0] = enable << 7;
@@ -945,7 +947,7 @@ static int spansion_quad_enable(struct spi_nor *nor)
}
/* set read/write protocols */
- nor->read_proto = SPI_PROTO_1_1_4;
+ nor->read_proto = SPI_PROTO_1_4_4;
nor->write_proto = SPI_PROTO_1_1_4;
return 0;
@@ -1059,7 +1061,7 @@ static int set_dual_mode(struct spi_nor *nor, const struct flash_info *info)
return status;
case CFI_MFR_MACRONIX:
case CFI_MFR_AMD:
- nor->read_proto = SPI_PROTO_1_1_2;
+ nor->read_proto = SPI_PROTO_1_2_2;
break;
default:
break;
@@ -1068,6 +1070,130 @@ static int set_dual_mode(struct spi_nor *nor, const struct flash_info *info)
return 0;
}
+static void macronix_set_commands(struct spi_nor *nor)
+{
+ switch (nor->flash_read) {
+ case SPI_NOR_QUAD: /* QPI mode */
+ nor->read_opcode = SPINOR_OP_READ_1_4_4;
+ break;
+
+ case SPI_NOR_DUAL:
+ nor->read_opcode = SPINOR_OP_READ_1_2_2;
+ break;
+
+ case SPI_NOR_FAST:
+ nor->read_opcode = SPINOR_OP_READ_FAST;
+ break;
+
+ case SPI_NOR_NORMAL:
+ default:
+ nor->read_opcode = SPINOR_OP_READ;
+ break;
+ }
+
+ nor->program_opcode = SPINOR_OP_PP;
+}
+
+static void micron_set_commands(struct spi_nor *nor)
+{
+ switch (nor->flash_read) {
+ case SPI_NOR_QUAD: /* Quad I/O operations */
+ nor->read_opcode = SPINOR_OP_READ_1_4_4;
+ break;
+
+ case SPI_NOR_DUAL: /* Dual I/O operations */
+ nor->read_opcode = SPINOR_OP_READ_1_2_2;
+ break;
+
+ case SPI_NOR_FAST:
+ nor->read_opcode = SPINOR_OP_READ_FAST;
+ break;
+
+ case SPI_NOR_NORMAL:
+ default:
+ nor->read_opcode = SPINOR_OP_READ;
+ break;
+ }
+
+ nor->program_opcode = SPINOR_OP_PP;
+}
+
+static void spansion_set_commands(struct spi_nor *nor,
+ const struct flash_info *info)
+{
+ bool addr_4byte = (nor->addr_width == 4);
+ struct mtd_info *mtd = nor->mtd;
+
+ switch (nor->flash_read) {
+ case SPI_NOR_QUAD:
+ if (addr_4byte) {
+ nor->read_opcode = SPINOR_OP_READ4_1_4_4;
+ nor->program_opcode = SPINOR_OP_PP_4B_1_1_4;
+ } else {
+ nor->read_opcode = SPINOR_OP_READ_1_4_4;
+ nor->program_opcode = SPINOR_OP_PP_1_1_4;
+ }
+ break;
+
+ case SPI_NOR_DUAL:
+ if (addr_4byte) {
+ nor->read_opcode = SPINOR_OP_READ4_1_2_2;
+ nor->program_opcode = SPINOR_OP_PP_4B;
+ } else {
+ nor->read_opcode = SPINOR_OP_READ_1_2_2;
+ nor->program_opcode = SPINOR_OP_PP;
+ }
+ break;
+
+ case SPI_NOR_FAST:
+ if (addr_4byte) {
+ nor->read_opcode = SPINOR_OP_READ4_FAST;
+ nor->program_opcode = SPINOR_OP_PP_4B;
+ } else {
+ nor->read_opcode = SPINOR_OP_READ_FAST;
+ nor->program_opcode = SPINOR_OP_PP;
+ }
+ break;
+
+ case SPI_NOR_NORMAL:
+ default:
+ if (addr_4byte) {
+ nor->read_opcode = SPINOR_OP_READ4;
+ nor->program_opcode = SPINOR_OP_PP_4B;
+ } else {
+ nor->read_opcode = SPINOR_OP_READ;
+ nor->program_opcode = SPINOR_OP_PP;
+ }
+ break;
+ }
+
+ if (addr_4byte) {
+ nor->erase_opcode = SPINOR_OP_SE_4B;
+ mtd->erasesize = info->sector_size;
+ }
+}
+
+static void tune_manufacturer_commands(struct spi_nor *nor,
+ const struct flash_info *info)
+{
+ switch (JEDEC_MFR(info)) {
+ case CFI_MFR_MACRONIX:
+ macronix_set_commands(nor);
+ break;
+
+ case CFI_MFR_ST:
+ micron_set_commands(nor);
+ break;
+
+ case CFI_MFR_AMD:
+ spansion_set_commands(nor, info);
+ break;
+
+ default:
+ break;
+ }
+}
+
static int spi_nor_check(struct spi_nor *nor)
{
if (!nor->dev || !nor->read || !nor->write ||
@@ -1253,32 +1379,14 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
else if (mtd->size > 0x1000000) {
/* enable 4-byte addressing if the device exceeds 16MiB */
nor->addr_width = 4;
- if (JEDEC_MFR(info) == CFI_MFR_AMD) {
- /* Dedicated 4-byte command set */
- switch (nor->flash_read) {
- case SPI_NOR_QUAD:
- nor->read_opcode = SPINOR_OP_READ4_1_1_4;
- break;
- case SPI_NOR_DUAL:
- nor->read_opcode = SPINOR_OP_READ4_1_1_2;
- break;
- case SPI_NOR_FAST:
- nor->read_opcode = SPINOR_OP_READ4_FAST;
- break;
- case SPI_NOR_NORMAL:
- nor->read_opcode = SPINOR_OP_READ4;
- break;
- }
- nor->program_opcode = SPINOR_OP_PP_4B;
- /* No small sector erase for 4-byte command set */
- nor->erase_opcode = SPINOR_OP_SE_4B;
- mtd->erasesize = info->sector_size;
- } else
- set_4byte(nor, info, 1);
+ set_4byte(nor, info, 1);
} else {
nor->addr_width = 3;
}
+ /* Tune read, page program and erase commands */
+ tune_manufacturer_commands(nor, info);
+
nor->read_dummy = spi_nor_read_dummy_cycles(nor);
dev_info(dev, "%s (%lld Kbytes)\n", info->name,
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
index ce81b0e2cb37..f13cd2cb3ac5 100644
--- a/include/linux/mtd/spi-nor.h
+++ b/include/linux/mtd/spi-nor.h
@@ -25,8 +25,11 @@
#define SPINOR_OP_READ 0x03 /* Read data bytes (low frequency) */
#define SPINOR_OP_READ_FAST 0x0b /* Read data bytes (high frequency) */
#define SPINOR_OP_READ_1_1_2 0x3b /* Read data bytes (Dual SPI) */
+#define SPINOR_OP_READ_1_2_2 0xbb /* Read data bytes (Dual SPI) */
#define SPINOR_OP_READ_1_1_4 0x6b /* Read data bytes (Quad SPI) */
+#define SPINOR_OP_READ_1_4_4 0xeb /* Read data bytes (Quad SPI) */
#define SPINOR_OP_PP 0x02 /* Page program (up to 256 bytes) */
+#define SPINOR_OP_PP_1_1_4 0x32 /* Page program (up to 256 bytes) */
#define SPINOR_OP_BE_4K 0x20 /* Erase 4KiB block */
#define SPINOR_OP_BE_4K_PMC 0xd7 /* Erase 4KiB block on PMC chips */
#define SPINOR_OP_BE_32K 0x52 /* Erase 32KiB block */
@@ -40,8 +43,11 @@
#define SPINOR_OP_READ4 0x13 /* Read data bytes (low frequency) */
#define SPINOR_OP_READ4_FAST 0x0c /* Read data bytes (high frequency) */
#define SPINOR_OP_READ4_1_1_2 0x3c /* Read data bytes (Dual SPI) */
+#define SPINOR_OP_READ4_1_2_2 0xbc /* Read data bytes (Dual SPI) */
#define SPINOR_OP_READ4_1_1_4 0x6c /* Read data bytes (Quad SPI) */
+#define SPINOR_OP_READ4_1_4_4 0xec /* Read data bytes (Quad SPI) */
#define SPINOR_OP_PP_4B 0x12 /* Page program (up to 256 bytes) */
+#define SPINOR_OP_PP_4B_1_1_4 0x34 /* Page Program (up to 512 bytes) */
#define SPINOR_OP_SE_4B 0xdc /* Sector erase (usually 64KiB) */
/* Used for SST flashes only. */
--
1.8.2.2
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [next] | [standalone]
| From | Jonas Gorski <jogo@openwrt.org> |
|---|---|
| Date | 2015-09-10 12:30 +0200 |
| Subject | Re: [PATCH linux-next v6 4/8] mtd: spi-nor: use optimized commands for read/write/erase operations |
| Message-ID | <q77h8-74B-13@gated-at.bofh.it> |
| In reply to | #1221426 |
On Wed, Sep 9, 2015 at 3:24 PM, Cyrille Pitchen <cyrille.pitchen@atmel.com> wrote: > The op codes used by the spi-nor framework are now tuned depending on the > memory manufacturer. > > Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com> To be honest, I'm not sure if it's worth it using the dual/quad I/O commands on spansion, as they have different dummy cycle requirements than the fast/dual/quad reads. E.g. on S25FL128S, Fast/dual/quad is fine with 8 dummy cycles up to 104 MHz, but Quad I/O needs 1 cycle for <= 50 MHz, 4 for <= 90 MHz, and 5 for <= 104 MHz. Which means we would need a lot more logic in there or setting it from dts, and for existing users already using dual/quad mode this would break it. And for m25p80 it would mean to split the cmd + address into two transfers, all to save 20~30 clock cycles, which will likely be dwarfed by the savings of the dual/quadness of the data. Apart from the fact that I would assume many spi-controllers will have problems with dummy cycles that aren't a multiple of 8, and would therefore require bitshifting the data when reading, which will definitely eat up any time savings from the dual/quad written address. And for the quad program command the datasheet says it only has any performance improvement if running at less than 12 MHz, so probably not much to gain for most users. Jonas -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web