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