xref: /nrf52832-nimble/rt-thread/components/drivers/spi/sfud/src/sfud_sfdp.c (revision 104654410c56c573564690304ae786df310c91fc)
1 /*
2  * This file is part of the Serial Flash Universal Driver Library.
3  *
4  * Copyright (c) 2016, Armink, <[email protected]>
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining
7  * a copy of this software and associated documentation files (the
8  * 'Software'), to deal in the Software without restriction, including
9  * without limitation the rights to use, copy, modify, merge, publish,
10  * distribute, sublicense, and/or sell copies of the Software, and to
11  * permit persons to whom the Software is furnished to do so, subject to
12  * the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be
15  * included in all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
18  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
21  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24  *
25  * Function: Analyze the SFDP (Serial Flash Discoverable Parameters) which from JESD216/A/B (V1.X) standard.
26  *           JESD216  (V1.0) document: http://www.jedec.org/sites/default/files/docs/JESD216.pdf
27  *           JESD216A (V1.5) document: http://www.jedec.org/sites/default/files/docs/JESD216A.pdf
28  *           JESD216B (V1.6) document: http://www.jedec.org/sites/default/files/docs/JESD216B.pdf
29  *
30  * Created on: 2016-05-26
31  */
32 
33 #include "../inc/sfud.h"
34 
35 /**
36  * JEDEC Standard JESD216 Terms and definitions:
37  *
38  * DWORD: Four consecutive 8-bit bytes used as the basic 32-bit building block for headers and parameter tables.
39  *
40  * Sector: The minimum granularity - size and alignment - of an area that can be erased in the data array
41  * of a flash memory device. Different areas within the address range of the data array may have a different
42  * minimum erase granularity (sector size).
43  */
44 
45 #ifdef SFUD_USING_SFDP
46 
47 /* support maximum SFDP major revision by driver */
48 #define SUPPORT_MAX_SFDP_MAJOR_REV                  1
49 /* the JEDEC basic flash parameter table length is 9 DWORDs (288-bit) on JESD216 (V1.0) initial release standard */
50 #define BASIC_TABLE_LEN                             9
51 /* the smallest eraser in SFDP eraser table */
52 #define SMALLEST_ERASER_INDEX                       0
53 /**
54  *  SFDP parameter header structure
55  */
56 typedef struct {
57     uint8_t id;                                  /**< Parameter ID LSB */
58     uint8_t minor_rev;                           /**< Parameter minor revision */
59     uint8_t major_rev;                           /**< Parameter major revision */
60     uint8_t len;                                 /**< Parameter table length(in double words) */
61     uint32_t ptp;                                /**< Parameter table 24bit pointer (byte address) */
62 } sfdp_para_header;
63 
64 static sfud_err read_sfdp_data(const sfud_flash *flash, uint32_t addr, uint8_t *read_buf, size_t size);
65 static bool read_sfdp_header(sfud_flash *flash);
66 static bool read_basic_header(const sfud_flash *flash, sfdp_para_header *basic_header);
67 static bool read_basic_table(sfud_flash *flash, sfdp_para_header *basic_header);
68 
69 /* ../port/sfup_port.c */
70 extern void sfud_log_debug(const char *file, const long line, const char *format, ...);
71 extern void sfud_log_info(const char *format, ...);
72 
73 /**
74  * Read SFDP parameter information
75  *
76  * @param flash flash device
77  *
78  * @return true: read OK
79  */
sfud_read_sfdp(sfud_flash * flash)80 bool sfud_read_sfdp(sfud_flash *flash) {
81     SFUD_ASSERT(flash);
82 
83     /* JEDEC basic flash parameter header */
84     sfdp_para_header basic_header;
85     if (read_sfdp_header(flash) && read_basic_header(flash, &basic_header)) {
86         return read_basic_table(flash, &basic_header);
87     } else {
88         SFUD_INFO("Warning: Read SFDP parameter header information failed. The %s is not support JEDEC SFDP.", flash->name);
89         return false;
90     }
91 }
92 
93 /**
94  * Read SFDP parameter header
95  *
96  * @param flash flash device
97  *
98  * @return true: read OK
99  */
read_sfdp_header(sfud_flash * flash)100 static bool read_sfdp_header(sfud_flash *flash) {
101     sfud_sfdp *sfdp = &flash->sfdp;
102     /* The SFDP header is located at address 000000h of the SFDP data structure.
103      * It identifies the SFDP Signature, the number of parameter headers, and the SFDP revision numbers. */
104     /* sfdp parameter header address */
105     uint32_t header_addr = 0;
106     /* each parameter header being 2 DWORDs (64-bit) */
107     uint8_t header[2 * 4] = { 0 };
108 
109     SFUD_ASSERT(flash);
110 
111     sfdp->available = false;
112     /* read SFDP header */
113     if (read_sfdp_data(flash, header_addr, header, sizeof(header)) != SFUD_SUCCESS) {
114         SFUD_INFO("Error: Can't read SFDP header.");
115         return false;
116     }
117     /* check SFDP header */
118     if (!(header[0] == 'S' &&
119           header[1] == 'F' &&
120           header[2] == 'D' &&
121           header[3] == 'P')) {
122         SFUD_DEBUG("Error: Check SFDP signature error. It's must be 50444653h('S' 'F' 'D' 'P').");
123         return false;
124     }
125     sfdp->minor_rev = header[4];
126     sfdp->major_rev = header[5];
127     if (sfdp->major_rev > SUPPORT_MAX_SFDP_MAJOR_REV) {
128         SFUD_INFO("Error: This reversion(V%d.%d) SFDP is not supported.", sfdp->major_rev, sfdp->minor_rev);
129         return false;
130     }
131     SFUD_DEBUG("Check SFDP header is OK. The reversion is V%d.%d, NPN is %d.", sfdp->major_rev, sfdp->minor_rev,
132             header[6]);
133 
134     return true;
135 }
136 
137 /**
138  * Read JEDEC basic parameter header
139  *
140  * @param flash flash device
141  *
142  * @return true: read OK
143  */
read_basic_header(const sfud_flash * flash,sfdp_para_header * basic_header)144 static bool read_basic_header(const sfud_flash *flash, sfdp_para_header *basic_header) {
145     /* The basic parameter header is mandatory, is defined by this standard, and starts at byte offset 08h. */
146     uint32_t header_addr = 8;
147     /* each parameter header being 2 DWORDs (64-bit) */
148     uint8_t header[2 * 4] = { 0 };
149 
150     SFUD_ASSERT(flash);
151     SFUD_ASSERT(basic_header);
152 
153     /* read JEDEC basic flash parameter header */
154     if (read_sfdp_data(flash, header_addr, header, sizeof(header)) != SFUD_SUCCESS) {
155         SFUD_INFO("Error: Can't read JEDEC basic flash parameter header.");
156         return false;
157     }
158     basic_header->id        = header[0];
159     basic_header->minor_rev = header[1];
160     basic_header->major_rev = header[2];
161     basic_header->len       = header[3];
162     basic_header->ptp       = (long)header[4] | (long)header[5] << 8 | (long)header[6] << 16;
163     /* check JEDEC basic flash parameter header */
164     if (basic_header->major_rev > SUPPORT_MAX_SFDP_MAJOR_REV) {
165         SFUD_INFO("Error: This reversion(V%d.%d) JEDEC basic flash parameter header is not supported.",
166                 basic_header->major_rev, basic_header->minor_rev);
167         return false;
168     }
169     if (basic_header->len < BASIC_TABLE_LEN) {
170         SFUD_INFO("Error: The JEDEC basic flash parameter table length (now is %d) error.", basic_header->len);
171         return false;
172     }
173     SFUD_DEBUG("Check JEDEC basic flash parameter header is OK. The table id is %d, reversion is V%d.%d,"
174             " length is %d, parameter table pointer is 0x%06lX.", basic_header->id, basic_header->major_rev,
175             basic_header->minor_rev, basic_header->len, basic_header->ptp);
176 
177     return true;
178 }
179 
180 /**
181  * Read JEDEC basic parameter table
182  *
183  * @param flash flash device
184  *
185  * @return true: read OK
186  */
read_basic_table(sfud_flash * flash,sfdp_para_header * basic_header)187 static bool read_basic_table(sfud_flash *flash, sfdp_para_header *basic_header) {
188     sfud_sfdp *sfdp = &flash->sfdp;
189     /* parameter table address */
190     uint32_t table_addr = basic_header->ptp;
191     /* parameter table */
192     uint8_t table[BASIC_TABLE_LEN * 4] = { 0 }, i, j;
193 
194     SFUD_ASSERT(flash);
195     SFUD_ASSERT(basic_header);
196 
197     /* read JEDEC basic flash parameter table */
198     if (read_sfdp_data(flash, table_addr, table, sizeof(table)) != SFUD_SUCCESS) {
199         SFUD_INFO("Warning: Can't read JEDEC basic flash parameter table.");
200         return false;
201     }
202     /* print JEDEC basic flash parameter table info */
203     SFUD_DEBUG("JEDEC basic flash parameter table info:");
204     SFUD_DEBUG("MSB-LSB  3    2    1    0");
205     for (i = 0; i < BASIC_TABLE_LEN; i++) {
206         SFUD_DEBUG("[%04d] 0x%02X 0x%02X 0x%02X 0x%02X", i + 1, table[i * 4 + 3], table[i * 4 + 2], table[i * 4 + 1],
207                 table[i * 4]);
208     }
209 
210     /* get block/sector 4 KB erase supported and command */
211     sfdp->erase_4k_cmd = table[1];
212     switch (table[0] & 0x03) {
213     case 1:
214         sfdp->erase_4k = true;
215         SFUD_DEBUG("4 KB Erase is supported throughout the device. Command is 0x%02X.", sfdp->erase_4k_cmd);
216         break;
217     case 3:
218         sfdp->erase_4k = false;
219         SFUD_DEBUG("Uniform 4 KB erase is unavailable for this device.");
220         break;
221     default:
222         SFUD_INFO("Error: Uniform 4 KB erase supported information error.");
223         return false;
224     }
225     /* get write granularity */
226     //TODO ĿǰΪ 1.0 ���ṩ�ķ�ʽ������֧�� V1.5 �����ϵķ�ʽ��ȡ page size
227     switch ((table[0] & (0x01 << 2)) >> 2) {
228     case 0:
229         sfdp->write_gran = 1;
230         SFUD_DEBUG("Write granularity is 1 byte.");
231         break;
232     case 1:
233         sfdp->write_gran = 256;
234         SFUD_DEBUG("Write granularity is 64 bytes or larger.");
235         break;
236     }
237     /* volatile status register block protect bits */
238     switch ((table[0] & (0x01 << 3)) >> 3) {
239     case 0:
240         /* Block Protect bits in device's status register are solely non-volatile or may be
241          * programmed either as volatile using the 50h instruction for write enable or non-volatile
242          * using the 06h instruction for write enable.
243          */
244         sfdp->sr_is_non_vola = true;
245         SFUD_DEBUG("Target flash status register is non-volatile.");
246         break;
247     case 1:
248         /* block protect bits in device's status register are solely volatile. */
249         sfdp->sr_is_non_vola = false;
250         SFUD_DEBUG("Block Protect bits in device's status register are solely volatile.");
251         /* write enable instruction select for writing to volatile status register */
252         switch ((table[0] & (0x01 << 4)) >> 4) {
253         case 0:
254             sfdp->vola_sr_we_cmd = SFUD_VOLATILE_SR_WRITE_ENABLE;
255             SFUD_DEBUG("Flash device requires instruction 50h as the write enable prior "
256                     "to performing a volatile write to the status register.");
257             break;
258         case 1:
259             sfdp->vola_sr_we_cmd = SFUD_CMD_WRITE_ENABLE;
260             SFUD_DEBUG("Flash device requires instruction 06h as the write enable prior "
261                     "to performing a volatile write to the status register.");
262             break;
263         }
264         break;
265     }
266     /* get address bytes, number of bytes used in addressing flash array read, write and erase. */
267     switch ((table[2] & (0x03 << 1)) >> 1) {
268     case 0:
269         sfdp->addr_3_byte = true;
270         sfdp->addr_4_byte = false;
271         SFUD_DEBUG("3-Byte only addressing.");
272         break;
273     case 1:
274         sfdp->addr_3_byte = true;
275         sfdp->addr_4_byte = true;
276         SFUD_DEBUG("3- or 4-Byte addressing.");
277         break;
278     case 2:
279         sfdp->addr_3_byte = false;
280         sfdp->addr_4_byte = true;
281         SFUD_DEBUG("4-Byte only addressing.");
282         break;
283     default:
284         sfdp->addr_3_byte = false;
285         sfdp->addr_4_byte = false;
286         SFUD_INFO("Error: Read address bytes error!");
287         return false;
288     }
289     /* get flash memory capacity */
290     uint32_t table2_temp = ((long)table[7] << 24) | ((long)table[6] << 16) | ((long)table[5] << 8) | (long)table[4];
291     switch ((table[7] & (0x01 << 7)) >> 7) {
292     case 0:
293         sfdp->capacity = 1 + (table2_temp >> 3);
294         break;
295     case 1:
296         table2_temp &= 0x7FFFFFFF;
297         if (table2_temp > sizeof(sfdp->capacity) * 8 + 3) {
298             sfdp->capacity = 0;
299             SFUD_INFO("Error: The flash capacity is grater than 32 Gb/ 4 GB! Not Supported.");
300             return false;
301         }
302         sfdp->capacity = 1L << (table2_temp - 3);
303         break;
304     }
305     SFUD_DEBUG("Capacity is %ld Bytes.", sfdp->capacity);
306     /* get erase size and erase command  */
307     for (i = 0, j = 0; i < SFUD_SFDP_ERASE_TYPE_MAX_NUM; i++) {
308         if (table[28 + 2 * i] != 0x00) {
309             sfdp->eraser[j].size = 1L << table[28 + 2 * i];
310             sfdp->eraser[j].cmd = table[28 + 2 * i + 1];
311             SFUD_DEBUG("Flash device supports %ldKB block erase. Command is 0x%02X.", sfdp->eraser[j].size / 1024,
312                     sfdp->eraser[j].cmd);
313             j++;
314         }
315     }
316     /* sort the eraser size from small to large */
317     for (i = 0, j = 0; i < SFUD_SFDP_ERASE_TYPE_MAX_NUM; i++) {
318         if (sfdp->eraser[i].size) {
319             for (j = i + 1; j < SFUD_SFDP_ERASE_TYPE_MAX_NUM; j++) {
320                 if (sfdp->eraser[j].size != 0 && sfdp->eraser[i].size > sfdp->eraser[j].size) {
321                     /* swap the small eraser */
322                     uint32_t temp_size = sfdp->eraser[i].size;
323                     uint8_t temp_cmd = sfdp->eraser[i].cmd;
324                     sfdp->eraser[i].size = sfdp->eraser[j].size;
325                     sfdp->eraser[i].cmd = sfdp->eraser[j].cmd;
326                     sfdp->eraser[j].size = temp_size;
327                     sfdp->eraser[j].cmd = temp_cmd;
328                 }
329             }
330         }
331     }
332 
333     sfdp->available = true;
334     return true;
335 }
336 
read_sfdp_data(const sfud_flash * flash,uint32_t addr,uint8_t * read_buf,size_t size)337 static sfud_err read_sfdp_data(const sfud_flash *flash, uint32_t addr, uint8_t *read_buf, size_t size) {
338     uint8_t cmd[] = {
339             SFUD_CMD_READ_SFDP_REGISTER,
340             (addr >> 16) & 0xFF,
341             (addr >> 8) & 0xFF,
342             (addr >> 0) & 0xFF,
343             SFUD_DUMMY_DATA,
344     };
345 
346     SFUD_ASSERT(flash);
347     SFUD_ASSERT(addr < 1L << 24);
348     SFUD_ASSERT(read_buf);
349     SFUD_ASSERT(flash->spi.wr);
350 
351     return flash->spi.wr(&flash->spi, cmd, sizeof(cmd), read_buf, size);
352 }
353 
354 /**
355  * get the most suitable eraser for erase process from SFDP parameter
356  *
357  * @param flash flash device
358  * @param addr start address
359  * @param erase_size will be erased size
360  *
361  * @return the eraser index of SFDP eraser table  @see sfud_sfdp.eraser[]
362  */
sfud_sfdp_get_suitable_eraser(const sfud_flash * flash,uint32_t addr,size_t erase_size)363 size_t sfud_sfdp_get_suitable_eraser(const sfud_flash *flash, uint32_t addr, size_t erase_size) {
364     size_t index = SMALLEST_ERASER_INDEX, i;
365     /* only used when flash supported SFDP */
366     SFUD_ASSERT(flash->sfdp.available);
367     /* the address isn't align by smallest eraser's size, then use the smallest eraser */
368     if (addr % flash->sfdp.eraser[SMALLEST_ERASER_INDEX].size) {
369         return SMALLEST_ERASER_INDEX;
370     }
371     /* Find the suitable eraser.
372      * The largest size eraser is at the end of eraser table.
373      * In order to decrease erase command counts, so the find process is from the end of eraser table. */
374     for (i = SFUD_SFDP_ERASE_TYPE_MAX_NUM - 1;; i--) {
375         if ((flash->sfdp.eraser[i].size != 0) && (erase_size >= flash->sfdp.eraser[i].size)
376                 && (addr % flash->sfdp.eraser[i].size == 0)) {
377             index = i;
378             break;
379         }
380         if (i == SMALLEST_ERASER_INDEX) {
381             break;
382         }
383     }
384     return index;
385 }
386 
387 #endif /* SFUD_USING_SFDP */
388