OpenWrt – Blame information for rev 3
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 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 |
||
5 | above 128Mib |
||
6 | |||
7 | This patch provides an alternative mean to support memory above 16MiB |
||
8 | (128Mib) by replacing 3byte address op codes by their associated 4byte |
||
9 | address versions. |
||
10 | |||
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 |
||
14 | the 4byte mode. |
||
15 | |||
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. |
||
19 | |||
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> |
||
23 | --- |
||
24 | drivers/mtd/spi-nor/spi-nor.c | 101 +++++++++++++++++++++++++++++++++--------- |
||
25 | 1 file changed, 80 insertions(+), 21 deletions(-) |
||
26 | |||
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 |
||
31 | * ATMEL flashes) |
||
32 | */ |
||
33 | +#define SPI_NOR_4B_OPCODES BIT(11) /* |
||
34 | + * Use dedicated 4byte address op codes |
||
35 | + * to support memory size above 128Mib. |
||
36 | + */ |
||
37 | }; |
||
38 | |||
39 | #define JEDEC_MFR(info) ((info)->id[0]) |
||
40 | @@ -194,6 +198,78 @@ static inline struct spi_nor *mtd_to_spi |
||
41 | return mtd->priv; |
||
42 | } |
||
43 | |||
44 | + |
||
45 | +static u8 spi_nor_convert_opcode(u8 opcode, const u8 table[][2], size_t size) |
||
46 | +{ |
||
47 | + size_t i; |
||
48 | + |
||
49 | + for (i = 0; i < size; i++) |
||
50 | + if (table[i][0] == opcode) |
||
51 | + return table[i][1]; |
||
52 | + |
||
53 | + /* No conversion found, keep input op code. */ |
||
54 | + return opcode; |
||
55 | +} |
||
56 | + |
||
57 | +static inline u8 spi_nor_convert_3to4_read(u8 opcode) |
||
58 | +{ |
||
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 }, |
||
66 | + }; |
||
67 | + |
||
68 | + return spi_nor_convert_opcode(opcode, spi_nor_3to4_read, |
||
69 | + ARRAY_SIZE(spi_nor_3to4_read)); |
||
70 | +} |
||
71 | + |
||
72 | +static inline u8 spi_nor_convert_3to4_program(u8 opcode) |
||
73 | +{ |
||
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 }, |
||
78 | + }; |
||
79 | + |
||
80 | + return spi_nor_convert_opcode(opcode, spi_nor_3to4_program, |
||
81 | + ARRAY_SIZE(spi_nor_3to4_program)); |
||
82 | +} |
||
83 | + |
||
84 | +static inline u8 spi_nor_convert_3to4_erase(u8 opcode) |
||
85 | +{ |
||
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 }, |
||
90 | + }; |
||
91 | + |
||
92 | + return spi_nor_convert_opcode(opcode, spi_nor_3to4_erase, |
||
93 | + ARRAY_SIZE(spi_nor_3to4_erase)); |
||
94 | +} |
||
95 | + |
||
96 | +static void spi_nor_set_4byte_opcodes(struct spi_nor *nor, |
||
97 | + const struct flash_info *info) |
||
98 | +{ |
||
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; |
||
105 | + break; |
||
106 | + |
||
107 | + default: |
||
108 | + break; |
||
109 | + } |
||
110 | + |
||
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); |
||
114 | +} |
||
115 | + |
||
116 | /* Enable/disable 4-byte addressing mode. */ |
||
117 | static inline int set_4byte(struct spi_nor *nor, const struct flash_info *info, |
||
118 | int enable) |
||
3 | office | 119 | @@ -1628,27 +1704,10 @@ int spi_nor_scan(struct spi_nor *nor, co |
1 | office | 120 | else if (mtd->size > 0x1000000) { |
121 | /* enable 4-byte addressing if the device exceeds 16MiB */ |
||
122 | nor->addr_width = 4; |
||
123 | - if (JEDEC_MFR(info) == SNOR_MFR_SPANSION) { |
||
124 | - /* Dedicated 4-byte command set */ |
||
125 | - switch (nor->flash_read) { |
||
126 | - case SPI_NOR_QUAD: |
||
127 | - nor->read_opcode = SPINOR_OP_READ_1_1_4_4B; |
||
128 | - break; |
||
129 | - case SPI_NOR_DUAL: |
||
130 | - nor->read_opcode = SPINOR_OP_READ_1_1_2_4B; |
||
131 | - break; |
||
132 | - case SPI_NOR_FAST: |
||
133 | - nor->read_opcode = SPINOR_OP_READ_FAST_4B; |
||
134 | - break; |
||
135 | - case SPI_NOR_NORMAL: |
||
136 | - nor->read_opcode = SPINOR_OP_READ_4B; |
||
137 | - break; |
||
138 | - } |
||
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; |
||
143 | - } else |
||
144 | + if (JEDEC_MFR(info) == SNOR_MFR_SPANSION || |
||
145 | + info->flags & SPI_NOR_4B_OPCODES) |
||
146 | + spi_nor_set_4byte_opcodes(nor, info); |
||
147 | + else |
||
148 | set_4byte(nor, info, 1); |
||
149 | } else { |
||
150 | nor->addr_width = 3; |