OpenWrt – Blame information for rev 4
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
4 | office | 1 | From 825d57369b196b64387348922b47adc5b651622c Mon Sep 17 00:00:00 2001 |
2 | From: Yangbo Lu <yangbo.lu@nxp.com> |
||
3 | Date: Wed, 17 Jan 2018 14:55:47 +0800 |
||
4 | Subject: [PATCH 05/30] mtd: spi-nor: support layerscape |
||
5 | |||
6 | This is an integrated patch for layerscape qspi support. |
||
7 | |||
8 | Signed-off-by: Suresh Gupta <suresh.gupta@nxp.com> |
||
9 | Signed-off-by: Yunhui Cui <B56489@freescale.com> |
||
10 | Signed-off-by: mar.krzeminski <mar.krzeminski@gmail.com> |
||
11 | Signed-off-by: Alison Wang <b18965@freescale.com> |
||
12 | Signed-off-by: Nobuhiro Iwamatsu <nobuhiro.iwamatsu.kw@hitachi.com> |
||
13 | Signed-off-by: LABBE Corentin <clabbe.montjoie@gmail.com> |
||
14 | Signed-off-by: Yuan Yao <yao.yuan@nxp.com> |
||
15 | Signed-off-by: Alexander Kurz <akurz@blala.de> |
||
16 | Signed-off-by: L. D. Pinney <ldpinney@gmail.com> |
||
17 | Signed-off-by: Ash Benz <ash.benz@bk.ru> |
||
18 | Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> |
||
19 | --- |
||
20 | drivers/mtd/mtdchar.c | 2 +- |
||
21 | drivers/mtd/spi-nor/fsl-quadspi.c | 327 +++++++++++++++++++++++++++++++------- |
||
22 | drivers/mtd/spi-nor/spi-nor.c | 136 ++++++++++++++-- |
||
23 | include/linux/mtd/spi-nor.h | 14 +- |
||
24 | 4 files changed, 409 insertions(+), 70 deletions(-) |
||
25 | |||
26 | --- a/drivers/mtd/mtdchar.c |
||
27 | +++ b/drivers/mtd/mtdchar.c |
||
28 | @@ -451,7 +451,7 @@ static int mtdchar_readoob(struct file * |
||
29 | * data. For our userspace tools it is important to dump areas |
||
30 | * with ECC errors! |
||
31 | * For kernel internal usage it also might return -EUCLEAN |
||
32 | - * to signal the caller that a bitflip has occured and has |
||
33 | + * to signal the caller that a bitflip has occurred and has |
||
34 | * been corrected by the ECC algorithm. |
||
35 | * |
||
36 | * Note: currently the standard NAND function, nand_read_oob_std, |
||
37 | --- a/drivers/mtd/spi-nor/fsl-quadspi.c |
||
38 | +++ b/drivers/mtd/spi-nor/fsl-quadspi.c |
||
39 | @@ -41,6 +41,8 @@ |
||
40 | #define QUADSPI_QUIRK_TKT253890 (1 << 2) |
||
41 | /* Controller cannot wake up from wait mode, TKT245618 */ |
||
42 | #define QUADSPI_QUIRK_TKT245618 (1 << 3) |
||
43 | +/* QSPI_AMBA_BASE is internally added by SOC design */ |
||
44 | +#define QUADSPI_AMBA_BASE_INTERNAL (0x10000) |
||
45 | |||
46 | /* The registers */ |
||
47 | #define QUADSPI_MCR 0x00 |
||
48 | @@ -193,7 +195,7 @@ |
||
49 | #define QUADSPI_LUT_NUM 64 |
||
50 | |||
51 | /* SEQID -- we can have 16 seqids at most. */ |
||
52 | -#define SEQID_QUAD_READ 0 |
||
53 | +#define SEQID_READ 0 |
||
54 | #define SEQID_WREN 1 |
||
55 | #define SEQID_WRDI 2 |
||
56 | #define SEQID_RDSR 3 |
||
57 | @@ -205,15 +207,22 @@ |
||
58 | #define SEQID_RDCR 9 |
||
59 | #define SEQID_EN4B 10 |
||
60 | #define SEQID_BRWR 11 |
||
61 | +#define SEQID_RDAR_OR_RD_EVCR 12 |
||
62 | +#define SEQID_WRAR 13 |
||
63 | +#define SEQID_WD_EVCR 14 |
||
64 | |||
65 | #define QUADSPI_MIN_IOMAP SZ_4M |
||
66 | |||
67 | +#define FLASH_VENDOR_SPANSION_FS "s25fs" |
||
68 | +#define SPANSION_S25FS_FAMILY (1 << 1) |
||
69 | + |
||
70 | enum fsl_qspi_devtype { |
||
71 | FSL_QUADSPI_VYBRID, |
||
72 | FSL_QUADSPI_IMX6SX, |
||
73 | FSL_QUADSPI_IMX7D, |
||
74 | FSL_QUADSPI_IMX6UL, |
||
75 | FSL_QUADSPI_LS1021A, |
||
76 | + FSL_QUADSPI_LS2080A, |
||
77 | }; |
||
78 | |||
79 | struct fsl_qspi_devtype_data { |
||
80 | @@ -224,7 +233,7 @@ struct fsl_qspi_devtype_data { |
||
81 | int driver_data; |
||
82 | }; |
||
83 | |||
84 | -static struct fsl_qspi_devtype_data vybrid_data = { |
||
85 | +static const struct fsl_qspi_devtype_data vybrid_data = { |
||
86 | .devtype = FSL_QUADSPI_VYBRID, |
||
87 | .rxfifo = 128, |
||
88 | .txfifo = 64, |
||
89 | @@ -232,7 +241,7 @@ static struct fsl_qspi_devtype_data vybr |
||
90 | .driver_data = QUADSPI_QUIRK_SWAP_ENDIAN, |
||
91 | }; |
||
92 | |||
93 | -static struct fsl_qspi_devtype_data imx6sx_data = { |
||
94 | +static const struct fsl_qspi_devtype_data imx6sx_data = { |
||
95 | .devtype = FSL_QUADSPI_IMX6SX, |
||
96 | .rxfifo = 128, |
||
97 | .txfifo = 512, |
||
98 | @@ -241,7 +250,7 @@ static struct fsl_qspi_devtype_data imx6 |
||
99 | | QUADSPI_QUIRK_TKT245618, |
||
100 | }; |
||
101 | |||
102 | -static struct fsl_qspi_devtype_data imx7d_data = { |
||
103 | +static const struct fsl_qspi_devtype_data imx7d_data = { |
||
104 | .devtype = FSL_QUADSPI_IMX7D, |
||
105 | .rxfifo = 512, |
||
106 | .txfifo = 512, |
||
107 | @@ -250,7 +259,7 @@ static struct fsl_qspi_devtype_data imx7 |
||
108 | | QUADSPI_QUIRK_4X_INT_CLK, |
||
109 | }; |
||
110 | |||
111 | -static struct fsl_qspi_devtype_data imx6ul_data = { |
||
112 | +static const struct fsl_qspi_devtype_data imx6ul_data = { |
||
113 | .devtype = FSL_QUADSPI_IMX6UL, |
||
114 | .rxfifo = 128, |
||
115 | .txfifo = 512, |
||
116 | @@ -267,6 +276,14 @@ static struct fsl_qspi_devtype_data ls10 |
||
117 | .driver_data = 0, |
||
118 | }; |
||
119 | |||
120 | +static struct fsl_qspi_devtype_data ls2080a_data = { |
||
121 | + .devtype = FSL_QUADSPI_LS2080A, |
||
122 | + .rxfifo = 128, |
||
123 | + .txfifo = 64, |
||
124 | + .ahb_buf_size = 1024, |
||
125 | + .driver_data = QUADSPI_AMBA_BASE_INTERNAL | QUADSPI_QUIRK_TKT253890, |
||
126 | +}; |
||
127 | + |
||
128 | #define FSL_QSPI_MAX_CHIP 4 |
||
129 | struct fsl_qspi { |
||
130 | struct spi_nor nor[FSL_QSPI_MAX_CHIP]; |
||
131 | @@ -282,6 +299,7 @@ struct fsl_qspi { |
||
132 | u32 nor_size; |
||
133 | u32 nor_num; |
||
134 | u32 clk_rate; |
||
135 | + u32 ddr_smp; |
||
136 | unsigned int chip_base_addr; /* We may support two chips. */ |
||
137 | bool has_second_chip; |
||
138 | bool big_endian; |
||
139 | @@ -309,6 +327,23 @@ static inline int needs_wakeup_wait_mode |
||
140 | return q->devtype_data->driver_data & QUADSPI_QUIRK_TKT245618; |
||
141 | } |
||
142 | |||
143 | +static inline int has_added_amba_base_internal(struct fsl_qspi *q) |
||
144 | +{ |
||
145 | + return q->devtype_data->driver_data & QUADSPI_AMBA_BASE_INTERNAL; |
||
146 | +} |
||
147 | + |
||
148 | +static u32 fsl_get_nor_vendor(struct spi_nor *nor) |
||
149 | +{ |
||
150 | + u32 vendor_id; |
||
151 | + |
||
152 | + if (nor->vendor) { |
||
153 | + if (memcmp(nor->vendor, FLASH_VENDOR_SPANSION_FS, |
||
154 | + sizeof(FLASH_VENDOR_SPANSION_FS) - 1)) |
||
155 | + vendor_id = SPANSION_S25FS_FAMILY; |
||
156 | + } |
||
157 | + return vendor_id; |
||
158 | +} |
||
159 | + |
||
160 | /* |
||
161 | * R/W functions for big- or little-endian registers: |
||
162 | * The qSPI controller's endian is independent of the CPU core's endian. |
||
163 | @@ -331,6 +366,31 @@ static u32 qspi_readl(struct fsl_qspi *q |
||
164 | return ioread32(addr); |
||
165 | } |
||
166 | |||
167 | +static inline u32 *u8tou32(u32 *dest, const u8 *src, size_t n) |
||
168 | +{ |
||
169 | + size_t i; |
||
170 | + *dest = 0; |
||
171 | + |
||
172 | + n = n > 4 ? 4 : n; |
||
173 | + for (i = 0; i < n; i++) |
||
174 | + *dest |= *src++ << i * 8; |
||
175 | + |
||
176 | + return dest; |
||
177 | + |
||
178 | +} |
||
179 | + |
||
180 | +static inline u8 *u32tou8(u8 *dest, const u32 *src, size_t n) |
||
181 | +{ |
||
182 | + size_t i; |
||
183 | + u8 *xdest = dest; |
||
184 | + |
||
185 | + n = n > 4 ? 4 : n; |
||
186 | + for (i = 0; i < n; i++) |
||
187 | + *xdest++ = *src >> i * 8; |
||
188 | + |
||
189 | + return dest; |
||
190 | +} |
||
191 | + |
||
192 | /* |
||
193 | * An IC bug makes us to re-arrange the 32-bit data. |
||
194 | * The following chips, such as IMX6SLX, have fixed this bug. |
||
195 | @@ -373,8 +433,15 @@ static void fsl_qspi_init_lut(struct fsl |
||
196 | void __iomem *base = q->iobase; |
||
197 | int rxfifo = q->devtype_data->rxfifo; |
||
198 | u32 lut_base; |
||
199 | - u8 cmd, addrlen, dummy; |
||
200 | int i; |
||
201 | + u32 vendor; |
||
202 | + |
||
203 | + struct spi_nor *nor = &q->nor[0]; |
||
204 | + u8 addrlen = (nor->addr_width == 3) ? ADDR24BIT : ADDR32BIT; |
||
205 | + u8 read_op = nor->read_opcode; |
||
206 | + u8 read_dm = nor->read_dummy; |
||
207 | + |
||
208 | + vendor = fsl_get_nor_vendor(nor); |
||
209 | |||
210 | fsl_qspi_unlock_lut(q); |
||
211 | |||
212 | @@ -382,24 +449,50 @@ static void fsl_qspi_init_lut(struct fsl |
||
213 | for (i = 0; i < QUADSPI_LUT_NUM; i++) |
||
214 | qspi_writel(q, 0, base + QUADSPI_LUT_BASE + i * 4); |
||
215 | |||
216 | - /* Quad Read */ |
||
217 | - lut_base = SEQID_QUAD_READ * 4; |
||
218 | + /* Read */ |
||
219 | + lut_base = SEQID_READ * 4; |
||
220 | |||
221 | - if (q->nor_size <= SZ_16M) { |
||
222 | - cmd = SPINOR_OP_READ_1_1_4; |
||
223 | - addrlen = ADDR24BIT; |
||
224 | - dummy = 8; |
||
225 | - } else { |
||
226 | - /* use the 4-byte address */ |
||
227 | - cmd = SPINOR_OP_READ_1_1_4; |
||
228 | - addrlen = ADDR32BIT; |
||
229 | - dummy = 8; |
||
230 | - } |
||
231 | - |
||
232 | - qspi_writel(q, LUT0(CMD, PAD1, cmd) | LUT1(ADDR, PAD1, addrlen), |
||
233 | + if (nor->flash_read == SPI_NOR_FAST) { |
||
234 | + qspi_writel(q, LUT0(CMD, PAD1, read_op) | |
||
235 | + LUT1(ADDR, PAD1, addrlen), |
||
236 | + base + QUADSPI_LUT(lut_base)); |
||
237 | + qspi_writel(q, LUT0(DUMMY, PAD1, read_dm) | |
||
238 | + LUT1(FSL_READ, PAD1, rxfifo), |
||
239 | + base + QUADSPI_LUT(lut_base + 1)); |
||
240 | + } else if (nor->flash_read == SPI_NOR_QUAD) { |
||
241 | + if (q->nor_size == 0x4000000) { |
||
242 | + read_op = 0xEC; |
||
243 | + qspi_writel(q, |
||
244 | + LUT0(CMD, PAD1, read_op) | LUT1(ADDR, PAD4, addrlen), |
||
245 | base + QUADSPI_LUT(lut_base)); |
||
246 | - qspi_writel(q, LUT0(DUMMY, PAD1, dummy) | LUT1(FSL_READ, PAD4, rxfifo), |
||
247 | + qspi_writel(q, |
||
248 | + LUT0(MODE, PAD4, 0xff) | LUT1(DUMMY, PAD4, read_dm), |
||
249 | base + QUADSPI_LUT(lut_base + 1)); |
||
250 | + qspi_writel(q, |
||
251 | + LUT0(FSL_READ, PAD4, rxfifo), |
||
252 | + base + QUADSPI_LUT(lut_base + 2)); |
||
253 | + } else { |
||
254 | + qspi_writel(q, LUT0(CMD, PAD1, read_op) | |
||
255 | + LUT1(ADDR, PAD1, addrlen), |
||
256 | + base + QUADSPI_LUT(lut_base)); |
||
257 | + qspi_writel(q, LUT0(DUMMY, PAD1, read_dm) | |
||
258 | + LUT1(FSL_READ, PAD4, rxfifo), |
||
259 | + base + QUADSPI_LUT(lut_base + 1)); |
||
260 | + } |
||
261 | + } else if (nor->flash_read == SPI_NOR_DDR_QUAD) { |
||
262 | + /* read mode : 1-4-4, such as Spansion s25fl128s. */ |
||
263 | + qspi_writel(q, LUT0(CMD, PAD1, read_op) |
||
264 | + | LUT1(ADDR_DDR, PAD4, addrlen), |
||
265 | + base + QUADSPI_LUT(lut_base)); |
||
266 | + |
||
267 | + qspi_writel(q, LUT0(MODE_DDR, PAD4, 0xff) |
||
268 | + | LUT1(DUMMY, PAD1, read_dm), |
||
269 | + base + QUADSPI_LUT(lut_base + 1)); |
||
270 | + |
||
271 | + qspi_writel(q, LUT0(FSL_READ_DDR, PAD4, rxfifo) |
||
272 | + | LUT1(JMP_ON_CS, PAD1, 0), |
||
273 | + base + QUADSPI_LUT(lut_base + 2)); |
||
274 | + } |
||
275 | |||
276 | /* Write enable */ |
||
277 | lut_base = SEQID_WREN * 4; |
||
278 | @@ -409,16 +502,8 @@ static void fsl_qspi_init_lut(struct fsl |
||
279 | /* Page Program */ |
||
280 | lut_base = SEQID_PP * 4; |
||
281 | |||
282 | - if (q->nor_size <= SZ_16M) { |
||
283 | - cmd = SPINOR_OP_PP; |
||
284 | - addrlen = ADDR24BIT; |
||
285 | - } else { |
||
286 | - /* use the 4-byte address */ |
||
287 | - cmd = SPINOR_OP_PP; |
||
288 | - addrlen = ADDR32BIT; |
||
289 | - } |
||
290 | - |
||
291 | - qspi_writel(q, LUT0(CMD, PAD1, cmd) | LUT1(ADDR, PAD1, addrlen), |
||
292 | + qspi_writel(q, LUT0(CMD, PAD1, nor->program_opcode) | |
||
293 | + LUT1(ADDR, PAD1, addrlen), |
||
294 | base + QUADSPI_LUT(lut_base)); |
||
295 | qspi_writel(q, LUT0(FSL_WRITE, PAD1, 0), |
||
296 | base + QUADSPI_LUT(lut_base + 1)); |
||
297 | @@ -432,10 +517,8 @@ static void fsl_qspi_init_lut(struct fsl |
||
298 | /* Erase a sector */ |
||
299 | lut_base = SEQID_SE * 4; |
||
300 | |||
301 | - cmd = q->nor[0].erase_opcode; |
||
302 | - addrlen = q->nor_size <= SZ_16M ? ADDR24BIT : ADDR32BIT; |
||
303 | - |
||
304 | - qspi_writel(q, LUT0(CMD, PAD1, cmd) | LUT1(ADDR, PAD1, addrlen), |
||
305 | + qspi_writel(q, LUT0(CMD, PAD1, nor->erase_opcode) | |
||
306 | + LUT1(ADDR, PAD1, addrlen), |
||
307 | base + QUADSPI_LUT(lut_base)); |
||
308 | |||
309 | /* Erase the whole chip */ |
||
310 | @@ -476,6 +559,44 @@ static void fsl_qspi_init_lut(struct fsl |
||
311 | qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_BRWR), |
||
312 | base + QUADSPI_LUT(lut_base)); |
||
313 | |||
314 | + |
||
315 | + /* |
||
316 | + * Flash Micron and Spansion command confilict |
||
317 | + * use the same value 0x65. But it indicates different meaning. |
||
318 | + */ |
||
319 | + lut_base = SEQID_RDAR_OR_RD_EVCR * 4; |
||
320 | + |
||
321 | + if (vendor == SPANSION_S25FS_FAMILY) { |
||
322 | + /* |
||
323 | + * Read any device register. |
||
324 | + * Used for Spansion S25FS-S family flash only. |
||
325 | + */ |
||
326 | + qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_SPANSION_RDAR) | |
||
327 | + LUT1(ADDR, PAD1, ADDR24BIT), |
||
328 | + base + QUADSPI_LUT(lut_base)); |
||
329 | + qspi_writel(q, LUT0(DUMMY, PAD1, 8) | LUT1(FSL_READ, PAD1, 1), |
||
330 | + base + QUADSPI_LUT(lut_base + 1)); |
||
331 | + } else { |
||
332 | + qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_RD_EVCR), |
||
333 | + base + QUADSPI_LUT(lut_base)); |
||
334 | + } |
||
335 | + |
||
336 | + /* |
||
337 | + * Write any device register. |
||
338 | + * Used for Spansion S25FS-S family flash only. |
||
339 | + */ |
||
340 | + lut_base = SEQID_WRAR * 4; |
||
341 | + qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_SPANSION_WRAR) | |
||
342 | + LUT1(ADDR, PAD1, ADDR24BIT), |
||
343 | + base + QUADSPI_LUT(lut_base)); |
||
344 | + qspi_writel(q, LUT0(FSL_WRITE, PAD1, 1), |
||
345 | + base + QUADSPI_LUT(lut_base + 1)); |
||
346 | + |
||
347 | + /* Write EVCR register */ |
||
348 | + lut_base = SEQID_WD_EVCR * 4; |
||
349 | + qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_WD_EVCR), |
||
350 | + base + QUADSPI_LUT(lut_base)); |
||
351 | + |
||
352 | fsl_qspi_lock_lut(q); |
||
353 | } |
||
354 | |||
355 | @@ -483,8 +604,24 @@ static void fsl_qspi_init_lut(struct fsl |
||
356 | static int fsl_qspi_get_seqid(struct fsl_qspi *q, u8 cmd) |
||
357 | { |
||
358 | switch (cmd) { |
||
359 | + case SPINOR_OP_READ_1_4_4_D: |
||
360 | + case SPINOR_OP_READ4_1_4_4_D: |
||
361 | + case SPINOR_OP_READ4_1_1_4: |
||
362 | case SPINOR_OP_READ_1_1_4: |
||
363 | - return SEQID_QUAD_READ; |
||
364 | + case SPINOR_OP_READ_FAST: |
||
365 | + case SPINOR_OP_READ4_FAST: |
||
366 | + return SEQID_READ; |
||
367 | + /* |
||
368 | + * Spansion & Micron use the same command value 0x65 |
||
369 | + * Spansion: SPINOR_OP_SPANSION_RDAR, read any register. |
||
370 | + * Micron: SPINOR_OP_RD_EVCR, |
||
371 | + * read enhanced volatile configuration register. |
||
372 | + * case SPINOR_OP_RD_EVCR: |
||
373 | + */ |
||
374 | + case SPINOR_OP_SPANSION_RDAR: |
||
375 | + return SEQID_RDAR_OR_RD_EVCR; |
||
376 | + case SPINOR_OP_SPANSION_WRAR: |
||
377 | + return SEQID_WRAR; |
||
378 | case SPINOR_OP_WREN: |
||
379 | return SEQID_WREN; |
||
380 | case SPINOR_OP_WRDI: |
||
381 | @@ -496,6 +633,7 @@ static int fsl_qspi_get_seqid(struct fsl |
||
382 | case SPINOR_OP_CHIP_ERASE: |
||
383 | return SEQID_CHIP_ERASE; |
||
384 | case SPINOR_OP_PP: |
||
385 | + case SPINOR_OP_PP_4B: |
||
386 | return SEQID_PP; |
||
387 | case SPINOR_OP_RDID: |
||
388 | return SEQID_RDID; |
||
389 | @@ -507,6 +645,8 @@ static int fsl_qspi_get_seqid(struct fsl |
||
390 | return SEQID_EN4B; |
||
391 | case SPINOR_OP_BRWR: |
||
392 | return SEQID_BRWR; |
||
393 | + case SPINOR_OP_WD_EVCR: |
||
394 | + return SEQID_WD_EVCR; |
||
395 | default: |
||
396 | if (cmd == q->nor[0].erase_opcode) |
||
397 | return SEQID_SE; |
||
398 | @@ -531,8 +671,11 @@ fsl_qspi_runcmd(struct fsl_qspi *q, u8 c |
||
399 | /* save the reg */ |
||
400 | reg = qspi_readl(q, base + QUADSPI_MCR); |
||
401 | |||
402 | - qspi_writel(q, q->memmap_phy + q->chip_base_addr + addr, |
||
403 | - base + QUADSPI_SFAR); |
||
404 | + if (has_added_amba_base_internal(q)) |
||
405 | + qspi_writel(q, q->chip_base_addr + addr, base + QUADSPI_SFAR); |
||
406 | + else |
||
407 | + qspi_writel(q, q->memmap_phy + q->chip_base_addr + addr, |
||
408 | + base + QUADSPI_SFAR); |
||
409 | qspi_writel(q, QUADSPI_RBCT_WMRK_MASK | QUADSPI_RBCT_RXBRD_USEIPS, |
||
410 | base + QUADSPI_RBCT); |
||
411 | qspi_writel(q, reg | QUADSPI_MCR_CLR_RXF_MASK, base + QUADSPI_MCR); |
||
412 | @@ -582,10 +725,10 @@ static void fsl_qspi_read_data(struct fs |
||
413 | q->chip_base_addr, tmp); |
||
414 | |||
415 | if (len >= 4) { |
||
416 | - *((u32 *)rxbuf) = tmp; |
||
417 | + u32tou8(rxbuf, &tmp, 4); |
||
418 | rxbuf += 4; |
||
419 | } else { |
||
420 | - memcpy(rxbuf, &tmp, len); |
||
421 | + u32tou8(rxbuf, &tmp, len); |
||
422 | break; |
||
423 | } |
||
424 | |||
425 | @@ -619,11 +762,12 @@ static inline void fsl_qspi_invalid(stru |
||
426 | } |
||
427 | |||
428 | static ssize_t fsl_qspi_nor_write(struct fsl_qspi *q, struct spi_nor *nor, |
||
429 | - u8 opcode, unsigned int to, u32 *txbuf, |
||
430 | + u8 opcode, unsigned int to, u8 *txbuf, |
||
431 | unsigned count) |
||
432 | { |
||
433 | int ret, i, j; |
||
434 | u32 tmp; |
||
435 | + u8 byts; |
||
436 | |||
437 | dev_dbg(q->dev, "to 0x%.8x:0x%.8x, len : %d\n", |
||
438 | q->chip_base_addr, to, count); |
||
439 | @@ -633,10 +777,13 @@ static ssize_t fsl_qspi_nor_write(struct |
||
440 | qspi_writel(q, tmp | QUADSPI_MCR_CLR_TXF_MASK, q->iobase + QUADSPI_MCR); |
||
441 | |||
442 | /* fill the TX data to the FIFO */ |
||
443 | + byts = count; |
||
444 | for (j = 0, i = ((count + 3) / 4); j < i; j++) { |
||
445 | - tmp = fsl_qspi_endian_xchg(q, *txbuf); |
||
446 | + u8tou32(&tmp, txbuf, byts); |
||
447 | + tmp = fsl_qspi_endian_xchg(q, tmp); |
||
448 | qspi_writel(q, tmp, q->iobase + QUADSPI_TBDR); |
||
449 | - txbuf++; |
||
450 | + txbuf += 4; |
||
451 | + byts -= 4; |
||
452 | } |
||
453 | |||
454 | /* fill the TXFIFO upto 16 bytes for i.MX7d */ |
||
455 | @@ -657,11 +804,43 @@ static void fsl_qspi_set_map_addr(struct |
||
456 | { |
||
457 | int nor_size = q->nor_size; |
||
458 | void __iomem *base = q->iobase; |
||
459 | + u32 mem_base; |
||
460 | + |
||
461 | + if (has_added_amba_base_internal(q)) |
||
462 | + mem_base = 0x0; |
||
463 | + else |
||
464 | + mem_base = q->memmap_phy; |
||
465 | + |
||
466 | + qspi_writel(q, nor_size + mem_base, base + QUADSPI_SFA1AD); |
||
467 | + qspi_writel(q, nor_size * 2 + mem_base, base + QUADSPI_SFA2AD); |
||
468 | + qspi_writel(q, nor_size * 3 + mem_base, base + QUADSPI_SFB1AD); |
||
469 | + qspi_writel(q, nor_size * 4 + mem_base, base + QUADSPI_SFB2AD); |
||
470 | +} |
||
471 | + |
||
472 | +/* |
||
473 | + * enable controller ddr quad mode to support different |
||
474 | + * vender flashes ddr quad mode. |
||
475 | + */ |
||
476 | +static void set_ddr_quad_mode(struct fsl_qspi *q) |
||
477 | +{ |
||
478 | + u32 reg, reg2; |
||
479 | + |
||
480 | + reg = qspi_readl(q, q->iobase + QUADSPI_MCR); |
||
481 | + |
||
482 | + /* Firstly, disable the module */ |
||
483 | + qspi_writel(q, reg | QUADSPI_MCR_MDIS_MASK, q->iobase + QUADSPI_MCR); |
||
484 | + |
||
485 | + /* Set the Sampling Register for DDR */ |
||
486 | + reg2 = qspi_readl(q, q->iobase + QUADSPI_SMPR); |
||
487 | + reg2 &= ~QUADSPI_SMPR_DDRSMP_MASK; |
||
488 | + reg2 |= (((q->ddr_smp) << QUADSPI_SMPR_DDRSMP_SHIFT) & |
||
489 | + QUADSPI_SMPR_DDRSMP_MASK); |
||
490 | + qspi_writel(q, reg2, q->iobase + QUADSPI_SMPR); |
||
491 | + |
||
492 | + /* Enable the module again (enable the DDR too) */ |
||
493 | + reg |= QUADSPI_MCR_DDR_EN_MASK; |
||
494 | + qspi_writel(q, reg, q->iobase + QUADSPI_MCR); |
||
495 | |||
496 | - qspi_writel(q, nor_size + q->memmap_phy, base + QUADSPI_SFA1AD); |
||
497 | - qspi_writel(q, nor_size * 2 + q->memmap_phy, base + QUADSPI_SFA2AD); |
||
498 | - qspi_writel(q, nor_size * 3 + q->memmap_phy, base + QUADSPI_SFB1AD); |
||
499 | - qspi_writel(q, nor_size * 4 + q->memmap_phy, base + QUADSPI_SFB2AD); |
||
500 | } |
||
501 | |||
502 | /* |
||
503 | @@ -704,6 +883,11 @@ static void fsl_qspi_init_abh_read(struc |
||
504 | seqid = fsl_qspi_get_seqid(q, q->nor[0].read_opcode); |
||
505 | qspi_writel(q, seqid << QUADSPI_BFGENCR_SEQID_SHIFT, |
||
506 | q->iobase + QUADSPI_BFGENCR); |
||
507 | + |
||
508 | + /* enable the DDR quad read */ |
||
509 | + if (q->nor->flash_read == SPI_NOR_DDR_QUAD) |
||
510 | + set_ddr_quad_mode(q); |
||
511 | + |
||
512 | } |
||
513 | |||
514 | /* This function was used to prepare and enable QSPI clock */ |
||
515 | @@ -822,6 +1006,7 @@ static const struct of_device_id fsl_qsp |
||
516 | { .compatible = "fsl,imx7d-qspi", .data = (void *)&imx7d_data, }, |
||
517 | { .compatible = "fsl,imx6ul-qspi", .data = (void *)&imx6ul_data, }, |
||
518 | { .compatible = "fsl,ls1021a-qspi", .data = (void *)&ls1021a_data, }, |
||
519 | + { .compatible = "fsl,ls2080a-qspi", .data = (void *)&ls2080a_data, }, |
||
520 | { /* sentinel */ } |
||
521 | }; |
||
522 | MODULE_DEVICE_TABLE(of, fsl_qspi_dt_ids); |
||
523 | @@ -835,8 +1020,12 @@ static int fsl_qspi_read_reg(struct spi_ |
||
524 | { |
||
525 | int ret; |
||
526 | struct fsl_qspi *q = nor->priv; |
||
527 | + u32 to = 0; |
||
528 | |||
529 | - ret = fsl_qspi_runcmd(q, opcode, 0, len); |
||
530 | + if (opcode == SPINOR_OP_SPANSION_RDAR) |
||
531 | + u8tou32(&to, nor->cmd_buf, 4); |
||
532 | + |
||
533 | + ret = fsl_qspi_runcmd(q, opcode, to, len); |
||
534 | if (ret) |
||
535 | return ret; |
||
536 | |||
537 | @@ -848,9 +1037,13 @@ static int fsl_qspi_write_reg(struct spi |
||
538 | { |
||
539 | struct fsl_qspi *q = nor->priv; |
||
540 | int ret; |
||
541 | + u32 to = 0; |
||
542 | + |
||
543 | + if (opcode == SPINOR_OP_SPANSION_WRAR) |
||
544 | + u8tou32(&to, nor->cmd_buf, 4); |
||
545 | |||
546 | if (!buf) { |
||
547 | - ret = fsl_qspi_runcmd(q, opcode, 0, 1); |
||
548 | + ret = fsl_qspi_runcmd(q, opcode, to, 1); |
||
549 | if (ret) |
||
550 | return ret; |
||
551 | |||
552 | @@ -859,7 +1052,7 @@ static int fsl_qspi_write_reg(struct spi |
||
553 | |||
554 | } else if (len > 0) { |
||
555 | ret = fsl_qspi_nor_write(q, nor, opcode, 0, |
||
556 | - (u32 *)buf, len); |
||
557 | + buf, len); |
||
558 | if (ret > 0) |
||
559 | return 0; |
||
560 | } else { |
||
561 | @@ -875,7 +1068,7 @@ static ssize_t fsl_qspi_write(struct spi |
||
562 | { |
||
563 | struct fsl_qspi *q = nor->priv; |
||
564 | ssize_t ret = fsl_qspi_nor_write(q, nor, nor->program_opcode, to, |
||
565 | - (u32 *)buf, len); |
||
566 | + (u8 *)buf, len); |
||
567 | |||
568 | /* invalid the data in the AHB buffer. */ |
||
569 | fsl_qspi_invalid(q); |
||
570 | @@ -922,7 +1115,7 @@ static ssize_t fsl_qspi_read(struct spi_ |
||
571 | len); |
||
572 | |||
573 | /* Read out the data directly from the AHB buffer.*/ |
||
574 | - memcpy(buf, q->ahb_addr + q->chip_base_addr + from - q->memmap_offs, |
||
575 | + memcpy_toio(buf, q->ahb_addr + q->chip_base_addr + from - q->memmap_offs, |
||
576 | len); |
||
577 | |||
578 | return len; |
||
579 | @@ -980,6 +1173,8 @@ static int fsl_qspi_probe(struct platfor |
||
580 | struct spi_nor *nor; |
||
581 | struct mtd_info *mtd; |
||
582 | int ret, i = 0; |
||
583 | + int find_node; |
||
584 | + enum read_mode mode = SPI_NOR_QUAD; |
||
585 | |||
586 | q = devm_kzalloc(dev, sizeof(*q), GFP_KERNEL); |
||
587 | if (!q) |
||
588 | @@ -1027,6 +1222,12 @@ static int fsl_qspi_probe(struct platfor |
||
589 | goto clk_failed; |
||
590 | } |
||
591 | |||
592 | + /* find ddrsmp value */ |
||
593 | + ret = of_property_read_u32(dev->of_node, "fsl,ddr-sampling-point", |
||
594 | + &q->ddr_smp); |
||
595 | + if (ret) |
||
596 | + q->ddr_smp = 0; |
||
597 | + |
||
598 | /* find the irq */ |
||
599 | ret = platform_get_irq(pdev, 0); |
||
600 | if (ret < 0) { |
||
601 | @@ -1050,6 +1251,7 @@ static int fsl_qspi_probe(struct platfor |
||
602 | |||
603 | mutex_init(&q->lock); |
||
604 | |||
605 | + find_node = 0; |
||
606 | /* iterate the subnodes. */ |
||
607 | for_each_available_child_of_node(dev->of_node, np) { |
||
608 | /* skip the holes */ |
||
609 | @@ -1076,18 +1278,25 @@ static int fsl_qspi_probe(struct platfor |
||
610 | ret = of_property_read_u32(np, "spi-max-frequency", |
||
611 | &q->clk_rate); |
||
612 | if (ret < 0) |
||
613 | - goto mutex_failed; |
||
614 | + continue; |
||
615 | |||
616 | /* set the chip address for READID */ |
||
617 | fsl_qspi_set_base_addr(q, nor); |
||
618 | |||
619 | - ret = spi_nor_scan(nor, NULL, SPI_NOR_QUAD); |
||
620 | + ret = of_property_read_bool(np, "m25p,fast-read"); |
||
621 | + mode = (ret) ? SPI_NOR_FAST : SPI_NOR_QUAD; |
||
622 | + /* Can we enable the DDR Quad Read? */ |
||
623 | + ret = of_property_read_bool(np, "ddr-quad-read"); |
||
624 | if (ret) |
||
625 | - goto mutex_failed; |
||
626 | + mode = SPI_NOR_DDR_QUAD; |
||
627 | + |
||
628 | + ret = spi_nor_scan(nor, NULL, mode); |
||
629 | + if (ret) |
||
630 | + continue; |
||
631 | |||
632 | ret = mtd_device_register(mtd, NULL, 0); |
||
633 | if (ret) |
||
634 | - goto mutex_failed; |
||
635 | + continue; |
||
636 | |||
637 | /* Set the correct NOR size now. */ |
||
638 | if (q->nor_size == 0) { |
||
639 | @@ -1110,8 +1319,12 @@ static int fsl_qspi_probe(struct platfor |
||
640 | nor->page_size = q->devtype_data->txfifo; |
||
641 | |||
642 | i++; |
||
643 | + find_node++; |
||
644 | } |
||
645 | |||
646 | + if (find_node == 0) |
||
647 | + goto mutex_failed; |
||
648 | + |
||
649 | /* finish the rest init. */ |
||
650 | ret = fsl_qspi_nor_setup_last(q); |
||
651 | if (ret) |
||
652 | --- a/drivers/mtd/spi-nor/spi-nor.c |
||
653 | +++ b/drivers/mtd/spi-nor/spi-nor.c |
||
654 | @@ -40,6 +40,13 @@ |
||
655 | #define SPI_NOR_MAX_ID_LEN 6 |
||
656 | #define SPI_NOR_MAX_ADDR_WIDTH 4 |
||
657 | |||
658 | +#define SPI_NOR_MICRON_WRITE_ENABLE 0x7f |
||
659 | +/* Added for S25FS-S family flash */ |
||
660 | +#define SPINOR_CONFIG_REG3_OFFSET 0x800004 |
||
661 | +#define CR3V_4KB_ERASE_UNABLE 0x8 |
||
662 | +#define SPINOR_S25FS_FAMILY_ID 0x81 |
||
663 | + |
||
664 | + |
||
665 | struct flash_info { |
||
666 | char *name; |
||
667 | |||
668 | @@ -68,7 +75,8 @@ struct flash_info { |
||
669 | #define SECT_4K_PMC BIT(4) /* SPINOR_OP_BE_4K_PMC works uniformly */ |
||
670 | #define SPI_NOR_DUAL_READ BIT(5) /* Flash supports Dual Read */ |
||
671 | #define SPI_NOR_QUAD_READ BIT(6) /* Flash supports Quad Read */ |
||
672 | -#define USE_FSR BIT(7) /* use flag status register */ |
||
673 | +#define USE_FSR BIT(13) /* use flag status register */ |
||
674 | +#define SPI_NOR_DDR_QUAD_READ BIT(7) /* Flash supports DDR Quad Read */ |
||
675 | #define SPI_NOR_HAS_LOCK BIT(8) /* Flash supports lock/unlock via SR */ |
||
676 | #define SPI_NOR_HAS_TB BIT(9) /* |
||
677 | * Flash SR has Top/Bottom (TB) protect |
||
678 | @@ -85,9 +93,11 @@ struct flash_info { |
||
679 | * Use dedicated 4byte address op codes |
||
680 | * to support memory size above 128Mib. |
||
681 | */ |
||
682 | +#define NO_CHIP_ERASE BIT(12) /* Chip does not support chip erase */ |
||
683 | }; |
||
684 | |||
685 | #define JEDEC_MFR(info) ((info)->id[0]) |
||
686 | +#define EXT_ID(info) ((info)->id[5]) |
||
687 | |||
688 | static const struct flash_info *spi_nor_match_id(const char *name); |
||
689 | |||
690 | @@ -132,7 +142,7 @@ static int read_fsr(struct spi_nor *nor) |
||
691 | /* |
||
692 | * Read configuration register, returning its value in the |
||
693 | * location. Return the configuration register value. |
||
694 | - * Returns negative if error occured. |
||
695 | + * Returns negative if error occurred. |
||
696 | */ |
||
697 | static int read_cr(struct spi_nor *nor) |
||
698 | { |
||
699 | @@ -160,6 +170,8 @@ static inline int spi_nor_read_dummy_cyc |
||
700 | case SPI_NOR_DUAL: |
||
701 | case SPI_NOR_QUAD: |
||
702 | return 8; |
||
703 | + case SPI_NOR_DDR_QUAD: |
||
704 | + return 6; |
||
705 | case SPI_NOR_NORMAL: |
||
706 | return 0; |
||
707 | } |
||
708 | @@ -961,6 +973,8 @@ static const struct flash_info spi_nor_i |
||
709 | |||
710 | /* ESMT */ |
||
711 | { "f25l32pa", INFO(0x8c2016, 0, 64 * 1024, 64, SECT_4K | SPI_NOR_HAS_LOCK) }, |
||
712 | + { "f25l32qa", INFO(0x8c4116, 0, 64 * 1024, 64, SECT_4K | SPI_NOR_HAS_LOCK) }, |
||
713 | + { "f25l64qa", INFO(0x8c4117, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_HAS_LOCK) }, |
||
714 | |||
715 | /* Everspin */ |
||
716 | { "mr25h256", CAT25_INFO( 32 * 1024, 1, 256, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) }, |
||
717 | @@ -1014,12 +1028,15 @@ static const struct flash_info spi_nor_i |
||
718 | { "mx25l3205d", INFO(0xc22016, 0, 64 * 1024, 64, SECT_4K) }, |
||
719 | { "mx25l3255e", INFO(0xc29e16, 0, 64 * 1024, 64, SECT_4K) }, |
||
720 | { "mx25l6405d", INFO(0xc22017, 0, 64 * 1024, 128, SECT_4K) }, |
||
721 | + { "mx25u2033e", INFO(0xc22532, 0, 64 * 1024, 4, SECT_4K) }, |
||
722 | + { "mx25u4035", INFO(0xc22533, 0, 64 * 1024, 8, SECT_4K) }, |
||
723 | + { "mx25u8035", INFO(0xc22534, 0, 64 * 1024, 16, SECT_4K) }, |
||
724 | { "mx25u3235f", INFO(0xc22536, 0, 64 * 1024, 64, 0) }, |
||
725 | { "mx25u6435f", INFO(0xc22537, 0, 64 * 1024, 128, SECT_4K) }, |
||
726 | { "mx25l12805d", INFO(0xc22018, 0, 64 * 1024, 256, 0) }, |
||
727 | { "mx25l12855e", INFO(0xc22618, 0, 64 * 1024, 256, 0) }, |
||
728 | { "mx25l25635e", INFO(0xc22019, 0, 64 * 1024, 512, 0) }, |
||
729 | - { "mx25u25635f", INFO(0xc22539, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_4B_OPCODES) }, |
||
730 | + { "mx25u25635f", INFO(0xc22539, 0, 64 * 1024, 512, SECT_4K) }, |
||
731 | { "mx25l25655e", INFO(0xc22619, 0, 64 * 1024, 512, 0) }, |
||
732 | { "mx66l51235l", INFO(0xc2201a, 0, 64 * 1024, 1024, SPI_NOR_QUAD_READ) }, |
||
733 | { "mx66l1g55g", INFO(0xc2261b, 0, 64 * 1024, 2048, SPI_NOR_QUAD_READ) }, |
||
734 | @@ -1033,10 +1050,11 @@ static const struct flash_info spi_nor_i |
||
735 | { "n25q128a11", INFO(0x20bb18, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_QUAD_READ) }, |
||
736 | { "n25q128a13", INFO(0x20ba18, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_QUAD_READ) }, |
||
737 | { "n25q256a", INFO(0x20ba19, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_QUAD_READ) }, |
||
738 | + { "n25q256ax1", INFO(0x20bb19, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_QUAD_READ) }, |
||
739 | { "n25q512a", INFO(0x20bb20, 0, 64 * 1024, 1024, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) }, |
||
740 | { "n25q512ax3", INFO(0x20ba20, 0, 64 * 1024, 1024, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) }, |
||
741 | - { "n25q00", INFO(0x20ba21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) }, |
||
742 | - { "n25q00a", INFO(0x20bb21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) }, |
||
743 | + { "n25q00", INFO(0x20ba21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) }, |
||
744 | + { "n25q00a", INFO(0x20bb21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) }, |
||
745 | |||
746 | /* PMC */ |
||
747 | { "pm25lv512", INFO(0, 0, 32 * 1024, 2, SECT_4K_PMC) }, |
||
748 | @@ -1054,8 +1072,11 @@ static const struct flash_info spi_nor_i |
||
749 | { "s70fl01gs", INFO(0x010221, 0x4d00, 256 * 1024, 256, 0) }, |
||
750 | { "s25sl12800", INFO(0x012018, 0x0300, 256 * 1024, 64, 0) }, |
||
751 | { "s25sl12801", INFO(0x012018, 0x0301, 64 * 1024, 256, 0) }, |
||
752 | - { "s25fl128s", INFO6(0x012018, 0x4d0180, 64 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, |
||
753 | + { "s25fs256s1", INFO6(0x010219, 0x4d0181, 64 * 1024, 512, 0)}, |
||
754 | + { "s25fl128s", INFO6(0x012018, 0x4d0180, 64 * 1024, 256, SPI_NOR_QUAD_READ |
||
755 | + | SPI_NOR_DDR_QUAD_READ) }, |
||
756 | { "s25fl129p0", INFO(0x012018, 0x4d00, 256 * 1024, 64, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, |
||
757 | + { "s25fs512s", INFO6(0x010220, 0x4d0081, 256 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)}, |
||
758 | { "s25fl129p1", INFO(0x012018, 0x4d01, 64 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, |
||
759 | { "s25sl004a", INFO(0x010212, 0, 64 * 1024, 8, 0) }, |
||
760 | { "s25sl008a", INFO(0x010213, 0, 64 * 1024, 16, 0) }, |
||
761 | @@ -1130,6 +1151,9 @@ static const struct flash_info spi_nor_i |
||
762 | { "w25x80", INFO(0xef3014, 0, 64 * 1024, 16, SECT_4K) }, |
||
763 | { "w25x16", INFO(0xef3015, 0, 64 * 1024, 32, SECT_4K) }, |
||
764 | { "w25x32", INFO(0xef3016, 0, 64 * 1024, 64, SECT_4K) }, |
||
765 | + { "w25q20cl", INFO(0xef4012, 0, 64 * 1024, 4, SECT_4K) }, |
||
766 | + { "w25q20bw", INFO(0xef5012, 0, 64 * 1024, 4, SECT_4K) }, |
||
767 | + { "w25q20ew", INFO(0xef6012, 0, 64 * 1024, 4, SECT_4K) }, |
||
768 | { "w25q32", INFO(0xef4016, 0, 64 * 1024, 64, SECT_4K) }, |
||
769 | { |
||
770 | "w25q32dw", INFO(0xef6016, 0, 64 * 1024, 64, |
||
771 | @@ -1196,6 +1220,53 @@ static const struct flash_info *spi_nor_ |
||
772 | id[0], id[1], id[2]); |
||
773 | return ERR_PTR(-ENODEV); |
||
774 | } |
||
775 | +/* |
||
776 | + * The S25FS-S family physical sectors may be configured as a |
||
777 | + * hybrid combination of eight 4-kB parameter sectors |
||
778 | + * at the top or bottom of the address space with all |
||
779 | + * but one of the remaining sectors being uniform size. |
||
780 | + * The Parameter Sector Erase commands (20h or 21h) must |
||
781 | + * be used to erase the 4-kB parameter sectors individually. |
||
782 | + * The Sector (uniform sector) Erase commands (D8h or DCh) |
||
783 | + * must be used to erase any of the remaining |
||
784 | + * sectors, including the portion of highest or lowest address |
||
785 | + * sector that is not overlaid by the parameter sectors. |
||
786 | + * The uniform sector erase command has no effect on parameter sectors. |
||
787 | + */ |
||
788 | +static int spansion_s25fs_disable_4kb_erase(struct spi_nor *nor) |
||
789 | +{ |
||
790 | + struct fsl_qspi *q; |
||
791 | + u32 cr3v_addr = SPINOR_CONFIG_REG3_OFFSET; |
||
792 | + u8 cr3v = 0x0; |
||
793 | + int ret = 0x0; |
||
794 | + |
||
795 | + q = nor->priv; |
||
796 | + |
||
797 | + nor->cmd_buf[2] = cr3v_addr >> 16; |
||
798 | + nor->cmd_buf[1] = cr3v_addr >> 8; |
||
799 | + nor->cmd_buf[0] = cr3v_addr >> 0; |
||
800 | + |
||
801 | + ret = nor->read_reg(nor, SPINOR_OP_SPANSION_RDAR, &cr3v, 1); |
||
802 | + if (ret) |
||
803 | + return ret; |
||
804 | + if (cr3v & CR3V_4KB_ERASE_UNABLE) |
||
805 | + return 0; |
||
806 | + ret = nor->write_reg(nor, SPINOR_OP_WREN, NULL, 0); |
||
807 | + if (ret) |
||
808 | + return ret; |
||
809 | + cr3v = CR3V_4KB_ERASE_UNABLE; |
||
810 | + nor->program_opcode = SPINOR_OP_SPANSION_WRAR; |
||
811 | + nor->write(nor, cr3v_addr, 1, &cr3v); |
||
812 | + |
||
813 | + ret = nor->read_reg(nor, SPINOR_OP_SPANSION_RDAR, &cr3v, 1); |
||
814 | + if (ret) |
||
815 | + return ret; |
||
816 | + if (!(cr3v & CR3V_4KB_ERASE_UNABLE)) |
||
817 | + return -EPERM; |
||
818 | + |
||
819 | + return 0; |
||
820 | +} |
||
821 | + |
||
822 | |||
823 | static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len, |
||
824 | size_t *retlen, u_char *buf) |
||
825 | @@ -1415,7 +1486,7 @@ static int macronix_quad_enable(struct s |
||
826 | * Write status Register and configuration register with 2 bytes |
||
827 | * The first byte will be written to the status register, while the |
||
828 | * second byte will be written to the configuration register. |
||
829 | - * Return negative if error occured. |
||
830 | + * Return negative if error occurred. |
||
831 | */ |
||
832 | static int write_sr_cr(struct spi_nor *nor, u16 val) |
||
833 | { |
||
834 | @@ -1463,6 +1534,24 @@ static int spansion_quad_enable(struct s |
||
835 | return 0; |
||
836 | } |
||
837 | |||
838 | +static int set_ddr_quad_mode(struct spi_nor *nor, const struct flash_info *info) |
||
839 | +{ |
||
840 | + int status; |
||
841 | + |
||
842 | + switch (JEDEC_MFR(info)) { |
||
843 | + case SNOR_MFR_SPANSION: |
||
844 | + status = spansion_quad_enable(nor); |
||
845 | + if (status) { |
||
846 | + dev_err(nor->dev, "Spansion DDR quad-read not enabled\n"); |
||
847 | + return status; |
||
848 | + } |
||
849 | + return status; |
||
850 | + default: |
||
851 | + return -EINVAL; |
||
852 | + } |
||
853 | +} |
||
854 | + |
||
855 | + |
||
856 | static int set_quad_mode(struct spi_nor *nor, const struct flash_info *info) |
||
857 | { |
||
858 | int status; |
||
859 | @@ -1609,9 +1698,25 @@ int spi_nor_scan(struct spi_nor *nor, co |
||
860 | write_sr(nor, 0); |
||
861 | spi_nor_wait_till_ready(nor); |
||
862 | } |
||
863 | + if (JEDEC_MFR(info) == SNOR_MFR_MICRON) { |
||
864 | + ret = read_sr(nor); |
||
865 | + ret &= SPI_NOR_MICRON_WRITE_ENABLE; |
||
866 | + |
||
867 | + write_enable(nor); |
||
868 | + write_sr(nor, ret); |
||
869 | + } |
||
870 | + |
||
871 | + if (EXT_ID(info) == SPINOR_S25FS_FAMILY_ID) { |
||
872 | + ret = spansion_s25fs_disable_4kb_erase(nor); |
||
873 | + if (ret) |
||
874 | + return ret; |
||
875 | + } |
||
876 | + |
||
877 | |||
878 | if (!mtd->name) |
||
879 | mtd->name = dev_name(dev); |
||
880 | + if (info->name) |
||
881 | + nor->vendor = info->name; |
||
882 | mtd->priv = nor; |
||
883 | mtd->type = MTD_NORFLASH; |
||
884 | mtd->writesize = 1; |
||
885 | @@ -1645,6 +1750,8 @@ int spi_nor_scan(struct spi_nor *nor, co |
||
886 | nor->flags |= SNOR_F_USE_FSR; |
||
887 | if (info->flags & SPI_NOR_HAS_TB) |
||
888 | nor->flags |= SNOR_F_HAS_SR_TB; |
||
889 | + if (info->flags & NO_CHIP_ERASE) |
||
890 | + nor->flags |= SNOR_F_NO_OP_CHIP_ERASE; |
||
891 | |||
892 | #ifdef CONFIG_MTD_SPI_NOR_USE_4K_SECTORS |
||
893 | /* prefer "small sector" erase if possible */ |
||
894 | @@ -1684,9 +1791,15 @@ int spi_nor_scan(struct spi_nor *nor, co |
||
895 | /* Some devices cannot do fast-read, no matter what DT tells us */ |
||
896 | if (info->flags & SPI_NOR_NO_FR) |
||
897 | nor->flash_read = SPI_NOR_NORMAL; |
||
898 | - |
||
899 | - /* Quad/Dual-read mode takes precedence over fast/normal */ |
||
900 | - if (mode == SPI_NOR_QUAD && info->flags & SPI_NOR_QUAD_READ) { |
||
901 | + /* DDR Quad/Quad/Dual-read mode takes precedence over fast/normal */ |
||
902 | + if (mode == SPI_NOR_DDR_QUAD && info->flags & SPI_NOR_DDR_QUAD_READ) { |
||
903 | + ret = set_ddr_quad_mode(nor, info); |
||
904 | + if (ret) { |
||
905 | + dev_err(dev, "DDR quad mode not supported\n"); |
||
906 | + return ret; |
||
907 | + } |
||
908 | + nor->flash_read = SPI_NOR_DDR_QUAD; |
||
909 | + } else if (mode == SPI_NOR_QUAD && info->flags & SPI_NOR_QUAD_READ) { |
||
910 | ret = set_quad_mode(nor, info); |
||
911 | if (ret) { |
||
912 | dev_err(dev, "quad mode not supported\n"); |
||
913 | @@ -1699,6 +1812,9 @@ int spi_nor_scan(struct spi_nor *nor, co |
||
914 | |||
915 | /* Default commands */ |
||
916 | switch (nor->flash_read) { |
||
917 | + case SPI_NOR_DDR_QUAD: |
||
918 | + nor->read_opcode = SPINOR_OP_READ4_1_4_4_D; |
||
919 | + break; |
||
920 | case SPI_NOR_QUAD: |
||
921 | nor->read_opcode = SPINOR_OP_READ_1_1_4; |
||
922 | break; |
||
923 | --- a/include/linux/mtd/spi-nor.h |
||
924 | +++ b/include/linux/mtd/spi-nor.h |
||
925 | @@ -31,10 +31,10 @@ |
||
926 | |||
927 | /* |
||
928 | * Note on opcode nomenclature: some opcodes have a format like |
||
929 | - * SPINOR_OP_FUNCTION{4,}_x_y_z. The numbers x, y, and z stand for the number |
||
930 | + * SPINOR_OP_FUNCTION{4,}_x_y_z{_D}. The numbers x, y,and z stand for the number |
||
931 | * of I/O lines used for the opcode, address, and data (respectively). The |
||
932 | * FUNCTION has an optional suffix of '4', to represent an opcode which |
||
933 | - * requires a 4-byte (32-bit) address. |
||
934 | + * requires a 4-byte (32-bit) address. The suffix of 'D' stands for the |
||
935 | */ |
||
936 | |||
937 | /* Flash opcodes. */ |
||
938 | @@ -46,7 +46,9 @@ |
||
939 | #define SPINOR_OP_READ_1_1_2 0x3b /* Read data bytes (Dual Output SPI) */ |
||
940 | #define SPINOR_OP_READ_1_2_2 0xbb /* Read data bytes (Dual I/O SPI) */ |
||
941 | #define SPINOR_OP_READ_1_1_4 0x6b /* Read data bytes (Quad Output SPI) */ |
||
942 | +#define SPINOR_OP_READ_1_4_4_D 0xed /* Read data bytes (DDR Quad SPI) */ |
||
943 | #define SPINOR_OP_READ_1_4_4 0xeb /* Read data bytes (Quad I/O SPI) */ |
||
944 | +#define SPINOR_OP_READ4_1_4_4_D 0xee /* Read data bytes (DDR Quad SPI) */ |
||
945 | #define SPINOR_OP_PP 0x02 /* Page program (up to 256 bytes) */ |
||
946 | #define SPINOR_OP_PP_1_1_4 0x32 /* Quad page program */ |
||
947 | #define SPINOR_OP_PP_1_4_4 0x38 /* Quad page program */ |
||
948 | @@ -62,9 +64,11 @@ |
||
949 | /* 4-byte address opcodes - used on Spansion and some Macronix flashes. */ |
||
950 | #define SPINOR_OP_READ_4B 0x13 /* Read data bytes (low frequency) */ |
||
951 | #define SPINOR_OP_READ_FAST_4B 0x0c /* Read data bytes (high frequency) */ |
||
952 | +#define SPINOR_OP_READ4_FAST 0x0c /* Read data bytes (high frequency) */ |
||
953 | #define SPINOR_OP_READ_1_1_2_4B 0x3c /* Read data bytes (Dual Output SPI) */ |
||
954 | #define SPINOR_OP_READ_1_2_2_4B 0xbc /* Read data bytes (Dual I/O SPI) */ |
||
955 | #define SPINOR_OP_READ_1_1_4_4B 0x6c /* Read data bytes (Quad Output SPI) */ |
||
956 | +#define SPINOR_OP_READ4_1_1_4 0x6c /* Read data bytes (Quad SPI) */ |
||
957 | #define SPINOR_OP_READ_1_4_4_4B 0xec /* Read data bytes (Quad I/O SPI) */ |
||
958 | #define SPINOR_OP_PP_4B 0x12 /* Page program (up to 256 bytes) */ |
||
959 | #define SPINOR_OP_PP_1_1_4_4B 0x34 /* Quad page program */ |
||
960 | @@ -94,6 +98,10 @@ |
||
961 | /* Used for Spansion flashes only. */ |
||
962 | #define SPINOR_OP_BRWR 0x17 /* Bank register write */ |
||
963 | |||
964 | +/* Used for Spansion S25FS-S family flash only. */ |
||
965 | +#define SPINOR_OP_SPANSION_RDAR 0x65 /* Read any device register */ |
||
966 | +#define SPINOR_OP_SPANSION_WRAR 0x71 /* Write any device register */ |
||
967 | + |
||
968 | /* Used for Micron flashes only. */ |
||
969 | #define SPINOR_OP_RD_EVCR 0x65 /* Read EVCR register */ |
||
970 | #define SPINOR_OP_WD_EVCR 0x61 /* Write EVCR register */ |
||
971 | @@ -124,6 +132,7 @@ enum read_mode { |
||
972 | SPI_NOR_FAST, |
||
973 | SPI_NOR_DUAL, |
||
974 | SPI_NOR_QUAD, |
||
975 | + SPI_NOR_DDR_QUAD, |
||
976 | }; |
||
977 | |||
978 | #define SPI_NOR_MAX_CMD_SIZE 8 |
||
979 | @@ -189,6 +198,7 @@ struct spi_nor { |
||
980 | bool sst_write_second; |
||
981 | u32 flags; |
||
982 | u8 cmd_buf[SPI_NOR_MAX_CMD_SIZE]; |
||
983 | + char *vendor; |
||
984 | |||
985 | int (*prepare)(struct spi_nor *nor, enum spi_nor_ops ops); |
||
986 | void (*unprepare)(struct spi_nor *nor, enum spi_nor_ops ops); |