1 From 3274ba26f27becfc4193ec6e229288140651f240 Mon Sep 17 00:00:00 2001
2 From: Cyrille Pitchen <cyrille.pitchen@atmel.com>
3 Date: Thu, 27 Oct 2016 12:03:57 +0200
4 Subject: [PATCH] mtd: spi-nor: add a stateless method to support memory size
7 This patch provides an alternative mean to support memory above 16MiB
8 (128Mib) by replacing 3byte address op codes by their associated 4byte
11 Using the dedicated 4byte address op codes doesn't change the internal
12 state of the SPI NOR memory as opposed to using other means such as
13 updating a Base Address Register (BAR) and sending command to enter/leave
16 Hence when a CPU reset occurs, early bootloaders don't need to be aware
17 of BAR value or 4byte mode being enabled: they can still access the first
18 16MiB of the SPI NOR memory using the regular 3byte address op codes.
20 Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com>
21 Tested-by: Vignesh R <vigneshr@ti.com>
22 Acked-by: Marek Vasut <marek.vasut@gmail.com>
24 drivers/mtd/spi-nor/spi-nor.c | 101 +++++++++++++++++++++++++++++++++---------
25 1 file changed, 80 insertions(+), 21 deletions(-)
27 --- a/drivers/mtd/spi-nor/spi-nor.c
28 +++ b/drivers/mtd/spi-nor/spi-nor.c
29 @@ -81,6 +81,10 @@ struct flash_info {
30 * because it has the same value as
33 +#define SPI_NOR_4B_OPCODES BIT(11) /*
34 + * Use dedicated 4byte address op codes
35 + * to support memory size above 128Mib.
39 #define JEDEC_MFR(info) ((info)->id[0])
40 @@ -194,6 +198,78 @@ static inline struct spi_nor *mtd_to_spi
45 +static u8 spi_nor_convert_opcode(u8 opcode, const u8 table[][2], size_t size)
49 + for (i = 0; i < size; i++)
50 + if (table[i][0] == opcode)
53 + /* No conversion found, keep input op code. */
57 +static inline u8 spi_nor_convert_3to4_read(u8 opcode)
59 + static const u8 spi_nor_3to4_read[][2] = {
60 + { SPINOR_OP_READ, SPINOR_OP_READ_4B },
61 + { SPINOR_OP_READ_FAST, SPINOR_OP_READ_FAST_4B },
62 + { SPINOR_OP_READ_1_1_2, SPINOR_OP_READ_1_1_2_4B },
63 + { SPINOR_OP_READ_1_2_2, SPINOR_OP_READ_1_2_2_4B },
64 + { SPINOR_OP_READ_1_1_4, SPINOR_OP_READ_1_1_4_4B },
65 + { SPINOR_OP_READ_1_4_4, SPINOR_OP_READ_1_4_4_4B },
68 + return spi_nor_convert_opcode(opcode, spi_nor_3to4_read,
69 + ARRAY_SIZE(spi_nor_3to4_read));
72 +static inline u8 spi_nor_convert_3to4_program(u8 opcode)
74 + static const u8 spi_nor_3to4_program[][2] = {
75 + { SPINOR_OP_PP, SPINOR_OP_PP_4B },
76 + { SPINOR_OP_PP_1_1_4, SPINOR_OP_PP_1_1_4_4B },
77 + { SPINOR_OP_PP_1_4_4, SPINOR_OP_PP_1_4_4_4B },
80 + return spi_nor_convert_opcode(opcode, spi_nor_3to4_program,
81 + ARRAY_SIZE(spi_nor_3to4_program));
84 +static inline u8 spi_nor_convert_3to4_erase(u8 opcode)
86 + static const u8 spi_nor_3to4_erase[][2] = {
87 + { SPINOR_OP_BE_4K, SPINOR_OP_BE_4K_4B },
88 + { SPINOR_OP_BE_32K, SPINOR_OP_BE_32K_4B },
89 + { SPINOR_OP_SE, SPINOR_OP_SE_4B },
92 + return spi_nor_convert_opcode(opcode, spi_nor_3to4_erase,
93 + ARRAY_SIZE(spi_nor_3to4_erase));
96 +static void spi_nor_set_4byte_opcodes(struct spi_nor *nor,
97 + const struct flash_info *info)
99 + /* Do some manufacturer fixups first */
100 + switch (JEDEC_MFR(info)) {
101 + case SNOR_MFR_SPANSION:
102 + /* No small sector erase for 4-byte command set */
103 + nor->erase_opcode = SPINOR_OP_SE;
104 + nor->mtd.erasesize = info->sector_size;
111 + nor->read_opcode = spi_nor_convert_3to4_read(nor->read_opcode);
112 + nor->program_opcode = spi_nor_convert_3to4_program(nor->program_opcode);
113 + nor->erase_opcode = spi_nor_convert_3to4_erase(nor->erase_opcode);
116 /* Enable/disable 4-byte addressing mode. */
117 static inline int set_4byte(struct spi_nor *nor, const struct flash_info *info,
119 @@ -1634,27 +1710,10 @@ int spi_nor_scan(struct spi_nor *nor, co
120 else if (mtd->size > 0x1000000) {
121 /* enable 4-byte addressing if the device exceeds 16MiB */
123 - if (JEDEC_MFR(info) == SNOR_MFR_SPANSION) {
124 - /* Dedicated 4-byte command set */
125 - switch (nor->flash_read) {
127 - nor->read_opcode = SPINOR_OP_READ_1_1_4_4B;
130 - nor->read_opcode = SPINOR_OP_READ_1_1_2_4B;
133 - nor->read_opcode = SPINOR_OP_READ_FAST_4B;
135 - case SPI_NOR_NORMAL:
136 - nor->read_opcode = SPINOR_OP_READ_4B;
139 - nor->program_opcode = SPINOR_OP_PP_4B;
140 - /* No small sector erase for 4-byte command set */
141 - nor->erase_opcode = SPINOR_OP_SE_4B;
142 - mtd->erasesize = info->sector_size;
144 + if (JEDEC_MFR(info) == SNOR_MFR_SPANSION ||
145 + info->flags & SPI_NOR_4B_OPCODES)
146 + spi_nor_set_4byte_opcodes(nor, info);
148 set_4byte(nor, info, 1);