1 /**************************************************************************//**
2 *
3 * @copyright (C) 2019 Nuvoton Technology Corp. All rights reserved.
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 *
7 * Change Logs:
8 * Date Author Notes
9 * 2021-1-13 Wayne First version
10 *
11 ******************************************************************************/
12
13 #include <rtthread.h>
14
15 #if defined(NU_PKG_USING_SPINAND)
16
17 #define LOG_TAG "spinand_flash"
18 #define DBG_ENABLE
19 #define DBG_SECTION_NAME LOG_TAG
20 #define DBG_LEVEL DBG_INFO
21 #define DBG_COLOR
22 #include <rtdbg.h>
23
24 #include "spinand.h"
25
26 const struct nu_spinand_info g_spinandflash_list[] =
27 {
28 /* Winbond */
29 /* Only tested */
30 {
31 0xEFAA21, 2048, 64, 0x6b, 0xff, 0xff, 0xff, 0x1, 1024, 64, 0, "Winbond 128MB: 2048+64@64@1024",
32 #if defined(RT_USING_DFS_UFFS)
33 {
34 /* For storing Seal-byte at 0x37. Need 15-Bytes */
35 0x04, 0x04, 0x14, 0x04, 0x24, 0x04, 0x34, 0x03, 0xFF, 0x00
36 },
37 {
38 /* For storing Seal-byte at 0x37 and not report latest ECC part in Spare-3 */
39 0x08, 0x08, 0x18, 0x08, 0x28, 0x08, /*0x38, 0x08,*/ 0xFF, 0x00
40 }
41 #else
42 {
43 0x04, 0x04, 0x14, 0x04, 0x24, 0x04, 0x34, 0x04, 0xFF, 0x00
44 },
45 {
46 0x08, 0x08, 0x18, 0x08, 0x28, 0x08, 0x38, 0x08, 0xFF, 0x00
47 }
48 #endif
49 },
50
51 {
52 0xEFBF22, 2048, 64, 0x6b, 0xff, 0xff, 0xff, 0x1, 2048, 64, 0, "Winbond 256MB: 2048+64@64@2048",
53 #if defined(RT_USING_DFS_UFFS)
54 {
55 /* For storing Seal-byte at 0x39. Need 15-Bytes */
56 0x08, 0x04, 0x18, 0x04, 0x28, 0x04, 0x38, 0x03, 0xFF, 0x00
57 },
58 {
59 /* For storing Seal-byte at 0x39 and not report latest ECC part in Spare-3 */
60 0x0C, 0x04, 0x1C, 0x04, 0x2C, 0x04, /*0x3C, 0x04,*/ 0xFF, 0x00
61 }
62 #else
63 {
64 0x08, 0x04, 0x18, 0x04, 0x28, 0x04, 0x38, 0x04, 0xFF, 0x00
65 },
66 {
67 0x0C, 0x04, 0x1C, 0x04, 0x2C, 0x04, 0x3C, 0x04, 0xFF, 0x00
68 }
69 #endif
70 },
71
72 {
73 /* Here, we just only define 64B for spare area, not ECC area. */
74 0xEFBA23, 2048, 64, 0x6b, 0x05, 0x01, 0x02, 0x1, 4096, 64, 0, "Winbond 512MB: 2048+128@64@4096",
75 #if defined(RT_USING_DFS_UFFS)
76 {
77 /* For storing Seal-byte at 0x39. Need 15-Bytes */
78 0x04, 0x0C, 0x14, 0x0C, 0x24, 0x0C, 0x34, 0x0B, 0xFF, 0x00
79 },
80 {
81 /* No report latest ECC part in Spare-3 */
82 0xFF, 0x00
83 }
84 #else
85 {
86 0x04, 0x0C, 0x14, 0x0C, 0x24, 0x0C, 0x34, 0x0C, 0xFF, 0x00
87 },
88 {
89 0x40, 0x40, 0xFF, 0x00
90 }
91 #endif
92 },
93
94 #if 0
95 { 0xEFAA22, 2048, 64, 0x6b, 0xff, 0xff, 0xff, 0x1, 2048, 64, 0, "Winbond 256MB: 2048+64@64@1024" },
96 { 0xEFAB21, 2048, 64, 0x6b, 0xff, 0xff, 0xff, 0x1, 1024, 64, 1, "Winbond 256MB: 2048+64@64@1024, MCP" },
97
98 /* Not test and supporting yet. */
99 /* MXIC */
100 { 0x00C212, 2048, 64, 0x6b, 0x05, 0x01, 0x40, 0x1, 1024, 64, 0, "MXIC 128MB: 2048+64@64@1024" },
101
102 /* XTX */
103 { 0x0BE20B, 2048, 64, 0x6b, 0xff, 0xff, 0xff, 0x1, 2048, 64, 0, "XTX 256MB: 2048+64@64@2048" },
104 { 0x0BF20B, 2048, 64, 0x6b, 0xff, 0xff, 0xff, 0x1, 2048, 64, 0, "XTX 256MB: 2048+64@64@2048" },
105 { 0x0BE10B, 2048, 64, 0x6b, 0xff, 0xff, 0xff, 0x1, 1024, 64, 0, "XTX 256MB: 2048+64@64@1024" },
106 { 0x0BF10B, 2048, 64, 0x6b, 0xff, 0xff, 0xff, 0x1, 1024, 64, 0, "XTX 256MB: 2048+64@64@1024" },
107
108 /* ATO */
109 { 0x9B129B, 2048, 64, 0x6b, 0x0f, 0x1f, 0x01, 0x1, 1024, 64, 0, "ATO 128MB: 2048+64@64@1024" },
110
111 /* Micro */
112 { 0x2C242C, 2048, 128, 0x6b, 0x0f, 0x1f, 0x01, 0x1, 2048, 64, 0, "Micro 256MB: 2048+128@64@2048" },
113
114 /* GigaDevice */
115 { 0xB148C8, 2048, 128, 0x6b, 0x0f, 0x1f, 0x01, 0x1, 1024, 64, 0, "GD 128MB: 2048+128@64@1024" },
116
117 /* Unknown */
118 { 0x00C8D1, 2048, 128, 0x6b, 0x0f, 0x1f, 0x01, 0x1, 1024, 64, 0, "Unknown 128MB: 2048+128@64@1024" },
119 { 0x00C851, 2048, 128, 0x6b, 0x0f, 0x1f, 0x01, 0x1, 1024, 64, 0, "Unknown 128MB: 2048+128@64@1024" },
120 { 0x98E240, 2048, 128, 0x6b, 0x0f, 0x1f, 0x01, 0x1, 1024, 64, 0, "Unknown 128MB: 2048+128@64@1024" }
121 #endif
122 };
123 #define SPINAND_LIST_ELEMENT_NUM ( sizeof(g_spinandflash_list)/sizeof(struct nu_spinand_info) )
124
125 /*
126 ========================================================
127 For 0xEFAA21 description:
128
129 Data Area(2048-Byte)
130 -----------------------------
131 |Sect-0|Sect-1|Sect-2|Sect-3|
132 |(512B)|(512B)|(512B)|(512B)|
133 -----------------------------
134
135 Spare Area(64-Byte)
136 ---------------------------------
137 |Spare-0|Spare-1|Spare-2|Spare-3|
138 | (16B) | (16B) | (16B) | (16B) |
139 ---------------------------------
140
141 ----------------- Spare-0 -------------------
142 / \
143 -------------------------------------------------
144 | BBM | UD2 | UD1 | ECC Sect-0 | ECC Spare |
145 | 0 1 | 2 3 | 4 5 6 7 | 8 9 A B C D | E F |
146 -------------------------------------------------
147 | NO ECC | ECC PROTECTED | ECC 4-D |
148
149 BBM: Bad block marker.
150 UD1: User Data 1.
151 UD2: User Data 2.
152 ECC Sect-n: ECC for sector-n.
153 ECC Spare: ECC for spare 4-D.
154
155 ---------------- Spare-1 -------------------
156 / \
157 -----------------------------------------------
158 | UD2 | UD1 | ECC Sect-1 | ECC Spare |
159 | 0 1 2 3 | 4 5 6 7 | 8 9 A B C D | E F |
160 -----------------------------------------------
161 | NO ECC | ECC PROTECTED | ECC 14-1D |
162
163 ---------------- Spare-2 -------------------
164 / \
165 -----------------------------------------------
166 | UD2 | UD1 | ECC Sect-2 | ECC Spare |
167 | 0 1 2 3 | 4 5 6 7 | 8 9 A B C D | E F |
168 -----------------------------------------------
169 | NO ECC | ECC PROTECTED | ECC 24-2D |
170
171 ---------------- Spare-3 -------------------
172 / \
173 -----------------------------------------------
174 | UD2 | UD1 | ECC Sect-3 | ECC Spare |
175 | 0 1 2 3 | 4 5 6 7 | 8 9 A B C D | E F |
176 -----------------------------------------------
177 | NO ECC | ECC PROTECTED | ECC 34-3D |
178
179 ========================================================
180
181 ========================================================
182 For 0xEFBF22 description:
183
184 Data Area(2048-Byte)
185 -----------------------------
186 |Sect-0|Sect-1|Sect-2|Sect-3|
187 |(512B)|(512B)|(512B)|(512B)|
188 -----------------------------
189
190 Spare Area(64-Byte)
191 ---------------------------------
192 |Spare-0|Spare-1|Spare-2|Spare-3|
193 | (16B) | (16B) | (16B) | (16B) |
194 ---------------------------------
195
196 ----------------- Spare-0 -------------------
197 / \
198 -----------------------------------------
199 | BBM | UD2 | UD1 | ECC UD1 |
200 | 0 1 | 2 3 4 5 6 7 | 8 9 A B | C D E F |
201 -----------------------------------------
202 | NO ECC | ECC PROTECTED |
203
204 BBM: Bad block marker.
205 UD1: User Data 1.
206 UD2: User Data 2.
207 ECC UD1: ECC for UD1.
208
209 ---------------- Spare-1 -------------------
210 / \
211 ---------------------------------------
212 | UD2 | UD1 | ECC UD1 |
213 | 0 1 2 3 4 5 6 7 | 8 9 A B | C D E F |
214 ---------------------------------------
215 | NO ECC | ECC PROTECTED |
216
217 ---------------- Spare-2 -------------------
218 / \
219 ---------------------------------------
220 | UD2 | UD1 | ECC UD1 |
221 | 0 1 2 3 4 5 6 7 | 8 9 A B | C D E F |
222 ---------------------------------------
223 | NO ECC | ECC PROTECTED |
224
225 ---------------- Spare-3 -------------------
226 / \
227 ---------------------------------------
228 | UD2 | UD1 | ECC UD1 |
229 | 0 1 2 3 4 5 6 7 | 8 9 A B | C D E F |
230 ---------------------------------------
231 | NO ECC | ECC PROTECTED |
232
233 ========================================================
234 */
235
236 rt_uint8_t spinand_flash_data_layout[SPINAND_SPARE_LAYOUT_SIZE];
237 rt_uint8_t spinand_flash_ecc_layout[SPINAND_SPARE_LAYOUT_SIZE];
238
239 static rt_err_t spinand_info_read(struct rt_qspi_device *qspi);
240
spinand_die_select(struct rt_qspi_device * qspi,uint8_t select_die)241 static rt_err_t spinand_die_select(struct rt_qspi_device *qspi, uint8_t select_die)
242 {
243 uint8_t au8Cmd[2] = { 0xC2, 0x0 };
244 au8Cmd[1] = select_die;
245
246 return nu_qspi_send(qspi, &au8Cmd[0], sizeof(au8Cmd));
247 }
248
spinand_isbusy(struct rt_qspi_device * qspi)249 static uint8_t spinand_isbusy(struct rt_qspi_device *qspi)
250 {
251 #define BUSY_CKECKING_TIMEOUT_MS 3000
252 volatile uint8_t SR = 0xFF;
253 rt_err_t result;
254 uint8_t au8Cmd[2] = { 0x0F, 0xC0 };
255
256 uint32_t u32CheckingDuration = rt_tick_from_millisecond(BUSY_CKECKING_TIMEOUT_MS);
257 uint32_t u32Start = rt_tick_get();
258
259 do
260 {
261 result = nu_qspi_send_then_recv(qspi, &au8Cmd[0], sizeof(au8Cmd), (void *)&SR, 1);
262 if (result != RT_EOK)
263 goto timeout_spinand_isbusy;
264
265 if ((rt_tick_get() - u32Start) >= u32CheckingDuration)
266 {
267 goto timeout_spinand_isbusy;
268 }
269
270 }
271 while ((SR & 0x1) != 0x00);
272
273 return 0;
274
275 timeout_spinand_isbusy:
276
277 LOG_E("Error: spinand timeout.");
278
279 return 1;
280 }
281
spinand_program_dataload(struct rt_qspi_device * qspi,uint8_t u8AddrH,uint8_t u8AddrL,uint8_t * pu8DataBuff,uint32_t u32DataCount,uint8_t * pu8SpareBuff,uint32_t u32SpareCount)282 static rt_err_t spinand_program_dataload(
283 struct rt_qspi_device *qspi,
284 uint8_t u8AddrH,
285 uint8_t u8AddrL,
286 uint8_t *pu8DataBuff,
287 uint32_t u32DataCount,
288 uint8_t *pu8SpareBuff,
289 uint32_t u32SpareCount)
290 {
291 uint8_t u8WECmd = 0x06;
292 rt_err_t result = RT_EOK;
293
294 struct rt_qspi_message qspi_messages[2] = {0};
295
296 /* 1-bit mode */
297 qspi_messages[0].instruction.content = 0x32;
298 qspi_messages[0].instruction.qspi_lines = 1;
299
300 qspi_messages[0].address.content = (u8AddrH << 8) | (u8AddrL);
301 qspi_messages[0].address.size = 2 * 8;
302 qspi_messages[0].address.qspi_lines = 1;
303
304 /* 4-bit mode */
305 qspi_messages[0].qspi_data_lines = 4;
306 qspi_messages[0].parent.cs_take = 1;
307 qspi_messages[0].parent.cs_release = 0;
308 qspi_messages[0].parent.send_buf = pu8DataBuff;
309 qspi_messages[0].parent.length = u32DataCount;
310 qspi_messages[0].parent.next = &qspi_messages[1].parent;
311
312 qspi_messages[1].qspi_data_lines = 4;
313 qspi_messages[1].parent.cs_take = 0;
314 qspi_messages[1].parent.cs_release = 1;
315 qspi_messages[1].parent.send_buf = pu8SpareBuff;
316 qspi_messages[1].parent.length = u32SpareCount;
317
318 if ((result = nu_qspi_send(qspi, &u8WECmd, sizeof(u8WECmd))) != RT_EOK)
319 goto exit_spinand_program_dataload;
320
321 result = nu_qspi_transfer_message(qspi, (struct rt_qspi_message *)&qspi_messages[0]);
322
323 exit_spinand_program_dataload:
324
325 return result;
326 }
327
spinand_status_register_read(struct rt_qspi_device * qspi,uint8_t u8SRSel)328 static uint8_t spinand_status_register_read(struct rt_qspi_device *qspi, uint8_t u8SRSel)
329 {
330 uint8_t u8SR = 0;
331 uint8_t au8Cmd[2];
332
333 switch (u8SRSel)
334 {
335 case 0x01:
336 au8Cmd[0] = 0x05;
337 au8Cmd[1] = 0xA0;
338 break;
339
340 case 0x02:
341 au8Cmd[0] = 0x0F;
342 au8Cmd[1] = 0xB0;
343 break;
344
345 case 0x03:
346 au8Cmd[0] = 0x05;
347 au8Cmd[1] = 0xC0;
348 break;
349
350 default:
351 RT_ASSERT(0);
352 break;
353 }
354
355 if (nu_qspi_send_then_recv(qspi, &au8Cmd[0], sizeof(au8Cmd), &u8SR, 1) != RT_EOK)
356 RT_ASSERT(0);
357
358 return u8SR;
359 }
360
spinand_status_register_write(struct rt_qspi_device * qspi,uint8_t u8SRSel,uint8_t u8Value)361 static rt_err_t spinand_status_register_write(struct rt_qspi_device *qspi, uint8_t u8SRSel, uint8_t u8Value)
362 {
363 rt_err_t result = RT_EOK;
364 uint8_t au8Cmd[3];
365
366 switch (u8SRSel)
367 {
368 case 0x01:
369 au8Cmd[0] = 0x01;
370 au8Cmd[1] = 0xA0;
371 break;
372
373 case 0x02:
374 au8Cmd[0] = 0x01;
375 au8Cmd[1] = 0xB0;
376 break;
377
378 case 0x03:
379 au8Cmd[0] = 0x01;
380 au8Cmd[1] = 0xC0;
381 break;
382
383 default:
384 result = -RT_EINVAL;
385 goto exit_spinand_status_register_write;
386 }
387
388 au8Cmd[2] = u8Value;
389
390 if ((result = nu_qspi_send(qspi, &au8Cmd[0], sizeof(au8Cmd))) != RT_EOK)
391 goto exit_spinand_status_register_write;
392
393 if (spinand_isbusy(qspi))
394 {
395 result = -RT_EIO;
396 goto exit_spinand_status_register_write;
397 }
398
399 exit_spinand_status_register_write:
400
401 return result;
402 }
403
spinand_program_execute(struct rt_qspi_device * qspi,uint8_t u8Addr2,uint8_t u8Addr1,uint8_t u8Addr0)404 static rt_err_t spinand_program_execute(struct rt_qspi_device *qspi, uint8_t u8Addr2, uint8_t u8Addr1, uint8_t u8Addr0)
405 {
406 rt_err_t result;
407 uint8_t au8Cmd[4], u8SR;
408
409 au8Cmd[0] = 0x10 ;
410 au8Cmd[1] = u8Addr2;
411 au8Cmd[2] = u8Addr1;
412 au8Cmd[3] = u8Addr0;
413
414 if ((result = nu_qspi_send(qspi, &au8Cmd, sizeof(au8Cmd))) != RT_EOK)
415 goto exit_spinand_program_execute;
416
417 if (spinand_isbusy(qspi))
418 {
419 result = -RT_MTD_EIO;
420 goto exit_spinand_program_execute;
421 }
422
423 u8SR = (spinand_status_register_read(SPINAND_FLASH_QSPI, 3) & 0x0C) >> 2;
424 if (u8SR == 1)
425 {
426 result = -RT_MTD_EIO;
427 LOG_E("Error write status!");
428 }
429
430 exit_spinand_program_execute:
431
432 return result;
433 }
434
spinand_normal_read(struct rt_qspi_device * qspi,uint8_t u8AddrH,uint8_t u8AddrL,uint8_t * pu8Buff,uint32_t u32Count)435 static rt_err_t spinand_normal_read(struct rt_qspi_device *qspi, uint8_t u8AddrH, uint8_t u8AddrL, uint8_t *pu8Buff, uint32_t u32Count)
436 {
437 uint8_t au8Cmd[4];
438
439 au8Cmd[0] = 0x03;
440 au8Cmd[1] = u8AddrH;
441 au8Cmd[2] = u8AddrL;
442 au8Cmd[3] = 0x00;
443
444 return nu_qspi_send_then_recv(qspi, &au8Cmd[0], sizeof(au8Cmd), pu8Buff, u32Count);
445 }
446
spinand_protect_set(struct rt_qspi_device * qspi,uint8_t u8Protect)447 static rt_err_t spinand_protect_set(struct rt_qspi_device *qspi, uint8_t u8Protect)
448 {
449 /* Read status register 1 */
450 uint8_t u8SR = spinand_status_register_read(qspi, 1);
451
452 if (u8Protect)
453 {
454 /* protect */
455 u8SR |= 0x7C;
456 }
457 else
458 {
459 /* unprotect */
460 u8SR &= 0x83;
461 }
462
463 return spinand_status_register_write(qspi, 1, u8SR);
464 }
465
spinand_program_erase_isfail(struct rt_qspi_device * qspi)466 static uint8_t spinand_program_erase_isfail(struct rt_qspi_device *qspi)
467 {
468 /* Read status register 3 */
469 uint8_t u8SR = spinand_status_register_read(qspi, 3);
470 return (u8SR & 0x0C) >> 2; /* Check P-Fail, E-Fail bit */
471 }
472
spinand_hwecc_status_get(struct rt_qspi_device * qspi)473 static uint8_t spinand_hwecc_status_get(struct rt_qspi_device *qspi)
474 {
475 /* Read status register 3 */
476 uint8_t u8SR = spinand_status_register_read(qspi, 3);
477 return (u8SR & 0x30) >> 4; /* ECC-1, ECC0 bit */
478 }
479
spinand_hwecc_set(struct rt_qspi_device * qspi,uint8_t u8Enable)480 static rt_err_t spinand_hwecc_set(struct rt_qspi_device *qspi, uint8_t u8Enable)
481 {
482 uint8_t u8SR = spinand_status_register_read(qspi, 2); // Read status register 2
483
484 if (u8Enable)
485 {
486 u8SR |= 0x10; // Enable ECC-E bit
487 }
488 else
489 {
490 u8SR &= 0xEF; // Disable ECC-E bit
491 }
492
493 return spinand_status_register_write(qspi, 2, u8SR);
494 }
495
spinand_hwecc_get(struct rt_qspi_device * qspi)496 static uint8_t spinand_hwecc_get(struct rt_qspi_device *qspi)
497 {
498 /* Read status register 2 */
499 uint8_t u8SR = spinand_status_register_read(qspi, 2);
500 return (u8SR & 0x10) >> 4;
501 }
502
spinand_read_dataload(struct rt_qspi_device * qspi,uint8_t u8Addr2,uint8_t u8Addr1,uint8_t u8Addr0)503 static rt_err_t spinand_read_dataload(struct rt_qspi_device *qspi, uint8_t u8Addr2, uint8_t u8Addr1, uint8_t u8Addr0)
504 {
505 rt_err_t result = RT_EOK;
506 uint8_t au8Cmd[4];
507 uint8_t u8SR;
508
509 au8Cmd[0] = 0x13 ;
510 au8Cmd[1] = u8Addr2;
511 au8Cmd[2] = u8Addr1;
512 au8Cmd[3] = u8Addr0;
513
514 if ((result = nu_qspi_send(qspi, &au8Cmd[0], sizeof(au8Cmd))) != RT_EOK)
515 goto exit_spinand_read_dataload;
516
517 if (spinand_isbusy(qspi))
518 {
519 result = -RT_EIO;
520 goto exit_spinand_read_dataload;
521 }
522
523 u8SR = spinand_hwecc_status_get(SPINAND_FLASH_QSPI);
524 if ((u8SR != 0x00) && (u8SR != 0x01))
525 {
526 result = -RT_MTD_EECC;
527 LOG_E("Error ECC status error[0x%x].", u8SR);
528 }
529
530 exit_spinand_read_dataload:
531
532 return result;
533 }
534
spinand_block_isbad(struct rt_qspi_device * qspi,uint32_t u32PageAddr)535 static uint8_t spinand_block_isbad(struct rt_qspi_device *qspi, uint32_t u32PageAddr)
536 {
537 rt_err_t result;
538 uint8_t read_buf;
539
540 again_spinand_block_isbad:
541
542 result = spinand_read_dataload(qspi, (u32PageAddr >> 16) & 0xFF, (u32PageAddr >> 8) & 0xFF, u32PageAddr & 0xFF); // Read the first page of a block
543 RT_ASSERT(result == RT_EOK);
544
545 result = spinand_normal_read(qspi, (SPINAND_FLASH_PAGE_SIZE >> 8) & 0xff, SPINAND_FLASH_PAGE_SIZE & 0xff, &read_buf, 1); // Read bad block mark at 0x800 update at v.1.0.8
546 RT_ASSERT(result == RT_EOK);
547
548 if (read_buf != 0xFF)
549 {
550 // update at v.1.0.7
551 return 1;
552 }
553
554 if (((u32PageAddr % (SPINAND_FLASH_PAGE_PER_BLOCK_NUM * SPINAND_FLASH_PAGE_SIZE)) == 0))
555 {
556 /* Need check second page again. */
557 u32PageAddr++;
558 goto again_spinand_block_isbad;
559 }
560
561 return 0;
562 }
563
spinand_buffermode_set(struct rt_qspi_device * qspi,uint8_t u8Enable)564 static rt_err_t spinand_buffermode_set(struct rt_qspi_device *qspi, uint8_t u8Enable)
565 {
566 uint8_t u8SR = spinand_status_register_read(qspi, 2); // Read status register 2
567
568 if (u8Enable)
569 {
570 u8SR |= 0x08; // Enable BUF bit
571 }
572 else
573 {
574 u8SR &= 0xF7; // Disable BUF bit
575 }
576 return spinand_status_register_write(qspi, 2, u8SR);
577 }
578
spinand_block_erase(struct rt_qspi_device * qspi,uint8_t u8Addr2,uint8_t u8Addr1,uint8_t u8Addr0)579 static rt_err_t spinand_block_erase(struct rt_qspi_device *qspi, uint8_t u8Addr2, uint8_t u8Addr1, uint8_t u8Addr0)
580 {
581 rt_err_t result;
582 uint8_t u8WECmd = 0x06;
583 uint8_t au8EraseCmd[4], u8SR;
584
585 au8EraseCmd[0] = 0xD8;
586 au8EraseCmd[1] = u8Addr2;
587 au8EraseCmd[2] = u8Addr1;
588 au8EraseCmd[3] = u8Addr0;
589
590 if ((result = nu_qspi_send(qspi, &u8WECmd, sizeof(u8WECmd))) != RT_EOK)
591 goto exit_spinand_block_erase;
592
593 if ((result = nu_qspi_send(qspi, &au8EraseCmd[0], sizeof(au8EraseCmd))) != RT_EOK)
594 goto exit_spinand_block_erase;
595
596 if (spinand_isbusy(qspi))
597 return -RT_EIO;
598
599 u8SR = spinand_program_erase_isfail(SPINAND_FLASH_QSPI);
600 if (u8SR != 0)
601 {
602 /* Fail to erase */
603 LOG_E("Fail to erase. Will mark it bad.");
604 result = -RT_ERROR;
605 goto exit_spinand_block_erase;
606 }
607
608 exit_spinand_block_erase:
609
610 return result;
611 }
612
spinand_block_markbad(struct rt_qspi_device * qspi,uint32_t u32PageAddr)613 static rt_err_t spinand_block_markbad(struct rt_qspi_device *qspi, uint32_t u32PageAddr)
614 {
615 rt_err_t result = RT_EOK;
616
617 uint8_t u8BadBlockMarker = 0xF0;
618
619 result = spinand_block_erase(qspi, (u32PageAddr >> 16) & 0xFF, (u32PageAddr >> 8) & 0xFF, u32PageAddr & 0xFF);
620 if (result != RT_EOK)
621 return result;
622
623 result = spinand_program_dataload(qspi, (SPINAND_FLASH_PAGE_SIZE >> 8) & 0xff, SPINAND_FLASH_PAGE_SIZE & 0xff, &u8BadBlockMarker, 1, 0, 0);
624 if (result != RT_EOK)
625 return result;
626
627 return spinand_program_execute(qspi, (u32PageAddr >> 16) & 0xFF, (u32PageAddr >> 8) & 0xFF, u32PageAddr & 0xFF);
628 }
629
spinand_read_quadoutput(struct rt_qspi_device * qspi,uint8_t u8AddrH,uint8_t u8AddrL,uint8_t * pu8DataBuff,uint32_t u32DataCount)630 static rt_err_t spinand_read_quadoutput(
631 struct rt_qspi_device *qspi,
632 uint8_t u8AddrH,
633 uint8_t u8AddrL,
634 uint8_t *pu8DataBuff,
635 uint32_t u32DataCount
636 )
637 {
638 struct rt_qspi_message qspi_messages = {0};
639
640 /* 1-bit mode */
641 qspi_messages.instruction.content = SPINAND_FLASH_QUADREAD_CMDID;
642 qspi_messages.instruction.qspi_lines = 1;
643
644 qspi_messages.address.content = (u8AddrH << 8) | (u8AddrL);
645 qspi_messages.address.size = 2 * 8;
646 qspi_messages.address.qspi_lines = 1;
647
648 qspi_messages.dummy_cycles = SPINAND_FLASH_DUMMYBYTE * 8; //In bit
649
650 /* 4-bit mode */
651 qspi_messages.qspi_data_lines = 4;
652 qspi_messages.parent.cs_take = 1;
653 qspi_messages.parent.cs_release = 1;
654 qspi_messages.parent.recv_buf = pu8DataBuff;
655 qspi_messages.parent.length = u32DataCount;
656 qspi_messages.parent.next = RT_NULL;
657
658 return nu_qspi_transfer_message(qspi, (struct rt_qspi_message *) &qspi_messages);
659 }
660
spinand_jedecid_get(struct rt_qspi_device * qspi,uint32_t * pu32ID)661 rt_err_t spinand_jedecid_get(struct rt_qspi_device *qspi, uint32_t *pu32ID)
662 {
663 uint32_t u32JedecId = 0;
664 uint32_t u32JedecId_real = 0;
665 uint8_t u8Cmd = 0x9F;
666
667 if (nu_qspi_send_then_recv(qspi, &u8Cmd, 1, &u32JedecId, 4) != RT_EOK)
668 {
669 return -RT_ERROR;
670 }
671
672 /* Reverse order. */
673 nu_set32_be((uint8_t *)&u32JedecId_real, u32JedecId);
674
675 /* Only keep 3-bytes. */
676 u32JedecId_real &= 0x00ffffff;
677
678 *pu32ID = u32JedecId_real;
679
680 return RT_EOK;
681 }
682
spinand_reset(struct rt_qspi_device * qspi)683 static rt_err_t spinand_reset(struct rt_qspi_device *qspi)
684 {
685 rt_err_t result;
686 uint8_t u8Cmd = 0xFF;
687
688 if ((result = nu_qspi_send(qspi, &u8Cmd, 1)) != RT_EOK)
689 goto exit_spinand_reset;
690
691 if (spinand_isbusy(qspi))
692 {
693 result = -RT_EIO;
694 goto exit_spinand_reset;
695 }
696
697 exit_spinand_reset:
698
699 return result;
700 }
701
spinand_flash_init(struct rt_qspi_device * qspi)702 rt_err_t spinand_flash_init(struct rt_qspi_device *qspi)
703 {
704 rt_err_t result;
705
706 if ((result = spinand_reset(qspi)) != RT_EOK)
707 goto exit_spinand_init;
708
709 if ((result = spinand_info_read(qspi)) != RT_EOK)
710 goto exit_spinand_init;
711
712 /* Un-protect */
713 if ((result = spinand_protect_set(qspi, 0)) != RT_EOK)
714 goto exit_spinand_init;
715
716 /* Enable BUF mode */
717 if ((result = spinand_buffermode_set(qspi, 1)) != RT_EOK)
718 goto exit_spinand_init;
719
720 /* Enable HWECC */
721 if ((result = spinand_hwecc_set(qspi, 1)) != RT_EOK)
722 goto exit_spinand_init;
723
724 /* Check HWECC */
725 if (!(spinand_hwecc_get(qspi)))
726 goto exit_spinand_init;
727
728 if (SPINAND_FLASH_MCP == 1)
729 {
730 /* Select die. */
731 if ((result = spinand_die_select(qspi, SPINAND_DIE_ID1)) != RT_EOK)
732 goto exit_spinand_init;
733
734 /* Unprotect */
735 if ((result = spinand_protect_set(qspi, 0)) != RT_EOK)
736 goto exit_spinand_init;
737 }
738
739 LOG_I("Enabled BUF, HWECC. Unprotected.");
740
741 exit_spinand_init:
742
743 return -result;
744 }
745
spinand_supported_flash_size(void)746 int spinand_supported_flash_size(void)
747 {
748 return SPINAND_LIST_ELEMENT_NUM;
749 }
750
spinand_info_get(int idx)751 nu_spinand_info_t spinand_info_get(int idx)
752 {
753 return (nu_spinand_info_t)&g_spinandflash_list[idx];
754 }
755
756 struct spinand_ops spinand_ops_wb =
757 {
758 .block_erase = spinand_block_erase,
759 .block_isbad = spinand_block_isbad,
760 .block_markbad = spinand_block_markbad,
761 .die_select = spinand_die_select,
762 .jedecid_get = spinand_jedecid_get,
763 .program_dataload = spinand_program_dataload,
764 .program_execute = spinand_program_execute,
765 .read_dataload = spinand_read_dataload,
766 .read_quadoutput = spinand_read_quadoutput
767 };
768
spinand_info_read(struct rt_qspi_device * qspi)769 static rt_err_t spinand_info_read(struct rt_qspi_device *qspi)
770 {
771 int i;
772 uint32_t u32JedecId = 0;
773
774 if (spinand_jedecid_get(qspi, &u32JedecId) != RT_EOK)
775 goto exit_spinand_info_read;
776
777 for (i = 0 ; i < SPINAND_LIST_ELEMENT_NUM; i++)
778 {
779 if (u32JedecId == g_spinandflash_list[i].u32JEDECID) /* Match JEDECID? */
780 {
781 rt_memcpy((void *)&spinand_flash_data_layout[0], (void *)&g_spinandflash_list[i].au8DataLayout[0], SPINAND_SPARE_LAYOUT_SIZE);
782 rt_memcpy((void *)&spinand_flash_ecc_layout[0], (void *)&g_spinandflash_list[i].au8EccLayout[0], SPINAND_SPARE_LAYOUT_SIZE);
783
784 rt_memcpy(SPINAND_FLASH_INFO, &g_spinandflash_list[i], sizeof(struct nu_spinand_info));
785 LOG_I("Found: [%08X] %s.", u32JedecId, SPINAND_FLASH_DESCRIPTION);
786
787 switch (u32JedecId & 0xff0000)
788 {
789 case 0xEF0000: /* Winbond */
790 SPINAND_FLASH_OPS = &spinand_ops_wb;
791 break;
792
793 default:
794 goto exit_spinand_info_read;
795 }
796
797 return RT_EOK;
798 }
799 }
800
801 exit_spinand_info_read:
802
803 LOG_E("Can't find the flash[%08X] in supported list.", u32JedecId);
804 return -RT_ERROR;
805 }
806
807 #endif
808