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