xref: /nrf52832-nimble/rt-thread/components/drivers/spi/sfud/src/sfud.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-2018, 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: serial flash operate functions by SFUD lib.
26*10465441SEvalZero  * Created on: 2016-04-23
27*10465441SEvalZero  */
28*10465441SEvalZero 
29*10465441SEvalZero #include "../inc/sfud.h"
30*10465441SEvalZero #include <string.h>
31*10465441SEvalZero 
32*10465441SEvalZero /* send dummy data for read data */
33*10465441SEvalZero #define DUMMY_DATA                               0xFF
34*10465441SEvalZero 
35*10465441SEvalZero #ifndef SFUD_FLASH_DEVICE_TABLE
36*10465441SEvalZero #error "Please configure the flash device information table in (in sfud_cfg.h)."
37*10465441SEvalZero #endif
38*10465441SEvalZero 
39*10465441SEvalZero /* user configured flash device information table */
40*10465441SEvalZero static sfud_flash flash_table[] = SFUD_FLASH_DEVICE_TABLE;
41*10465441SEvalZero /* supported manufacturer information table */
42*10465441SEvalZero static const sfud_mf mf_table[] = SFUD_MF_TABLE;
43*10465441SEvalZero 
44*10465441SEvalZero #ifdef SFUD_USING_FLASH_INFO_TABLE
45*10465441SEvalZero /* supported flash chip information table */
46*10465441SEvalZero static const sfud_flash_chip flash_chip_table[] = SFUD_FLASH_CHIP_TABLE;
47*10465441SEvalZero #endif
48*10465441SEvalZero 
49*10465441SEvalZero #ifdef SFUD_USING_QSPI
50*10465441SEvalZero /**
51*10465441SEvalZero  * flash read data mode
52*10465441SEvalZero  */
53*10465441SEvalZero enum sfud_qspi_read_mode {
54*10465441SEvalZero     NORMAL_SPI_READ = 1 << 0,               /**< mormal spi read mode */
55*10465441SEvalZero     DUAL_OUTPUT = 1 << 1,                   /**< qspi fast read dual output */
56*10465441SEvalZero     DUAL_IO = 1 << 2,                       /**< qspi fast read dual input/output */
57*10465441SEvalZero     QUAD_OUTPUT = 1 << 3,                   /**< qspi fast read quad output */
58*10465441SEvalZero     QUAD_IO = 1 << 4,                       /**< qspi fast read quad input/output */
59*10465441SEvalZero };
60*10465441SEvalZero 
61*10465441SEvalZero /* QSPI flash chip's extended information table */
62*10465441SEvalZero static const sfud_qspi_flash_ext_info qspi_flash_ext_info_table[] = SFUD_FLASH_EXT_INFO_TABLE;
63*10465441SEvalZero #endif /* SFUD_USING_QSPI */
64*10465441SEvalZero 
65*10465441SEvalZero static sfud_err software_init(const sfud_flash *flash);
66*10465441SEvalZero static sfud_err hardware_init(sfud_flash *flash);
67*10465441SEvalZero static sfud_err page256_or_1_byte_write(const sfud_flash *flash, uint32_t addr, size_t size, uint16_t write_gran,
68*10465441SEvalZero         const uint8_t *data);
69*10465441SEvalZero static sfud_err aai_write(const sfud_flash *flash, uint32_t addr, size_t size, const uint8_t *data);
70*10465441SEvalZero static sfud_err wait_busy(const sfud_flash *flash);
71*10465441SEvalZero static sfud_err reset(const sfud_flash *flash);
72*10465441SEvalZero static sfud_err read_jedec_id(sfud_flash *flash);
73*10465441SEvalZero static sfud_err set_write_enabled(const sfud_flash *flash, bool enabled);
74*10465441SEvalZero static sfud_err set_4_byte_address_mode(sfud_flash *flash, bool enabled);
75*10465441SEvalZero static void make_adress_byte_array(const sfud_flash *flash, uint32_t addr, uint8_t *array);
76*10465441SEvalZero 
77*10465441SEvalZero /* ../port/sfup_port.c */
78*10465441SEvalZero extern void sfud_log_debug(const char *file, const long line, const char *format, ...);
79*10465441SEvalZero extern void sfud_log_info(const char *format, ...);
80*10465441SEvalZero 
81*10465441SEvalZero /**
82*10465441SEvalZero  * SFUD initialize by flash device
83*10465441SEvalZero  *
84*10465441SEvalZero  * @param flash flash device
85*10465441SEvalZero  *
86*10465441SEvalZero  * @return result
87*10465441SEvalZero  */
sfud_device_init(sfud_flash * flash)88*10465441SEvalZero sfud_err sfud_device_init(sfud_flash *flash) {
89*10465441SEvalZero     sfud_err result = SFUD_SUCCESS;
90*10465441SEvalZero 
91*10465441SEvalZero     /* hardware initialize */
92*10465441SEvalZero     result = hardware_init(flash);
93*10465441SEvalZero     if (result == SFUD_SUCCESS) {
94*10465441SEvalZero         result = software_init(flash);
95*10465441SEvalZero     }
96*10465441SEvalZero     if (result == SFUD_SUCCESS) {
97*10465441SEvalZero         flash->init_ok = true;
98*10465441SEvalZero         SFUD_INFO("%s flash device is initialize success.", flash->name);
99*10465441SEvalZero     } else {
100*10465441SEvalZero         flash->init_ok = false;
101*10465441SEvalZero         SFUD_INFO("Error: %s flash device is initialize fail.", flash->name);
102*10465441SEvalZero     }
103*10465441SEvalZero 
104*10465441SEvalZero     return result;
105*10465441SEvalZero }
106*10465441SEvalZero 
107*10465441SEvalZero /**
108*10465441SEvalZero  * SFUD library initialize.
109*10465441SEvalZero  *
110*10465441SEvalZero  * @return result
111*10465441SEvalZero  */
sfud_init(void)112*10465441SEvalZero sfud_err sfud_init(void) {
113*10465441SEvalZero     sfud_err cur_flash_result = SFUD_SUCCESS, all_flash_result = SFUD_SUCCESS;
114*10465441SEvalZero     size_t i;
115*10465441SEvalZero 
116*10465441SEvalZero     SFUD_DEBUG("Start initialize Serial Flash Universal Driver(SFUD) V%s.", SFUD_SW_VERSION);
117*10465441SEvalZero     SFUD_DEBUG("You can get the latest version on https://github.com/armink/SFUD .");
118*10465441SEvalZero     /* initialize all flash device in flash device table */
119*10465441SEvalZero     for (i = 0; i < sizeof(flash_table) / sizeof(sfud_flash); i++) {
120*10465441SEvalZero         /* initialize flash device index of flash device information table */
121*10465441SEvalZero         flash_table[i].index = i;
122*10465441SEvalZero         cur_flash_result = sfud_device_init(&flash_table[i]);
123*10465441SEvalZero 
124*10465441SEvalZero         if (cur_flash_result != SFUD_SUCCESS) {
125*10465441SEvalZero             all_flash_result = cur_flash_result;
126*10465441SEvalZero         }
127*10465441SEvalZero     }
128*10465441SEvalZero 
129*10465441SEvalZero     return all_flash_result;
130*10465441SEvalZero }
131*10465441SEvalZero 
132*10465441SEvalZero /**
133*10465441SEvalZero  * get flash device by its index which in the flash information table
134*10465441SEvalZero  *
135*10465441SEvalZero  * @param index the index which in the flash information table  @see flash_table
136*10465441SEvalZero  *
137*10465441SEvalZero  * @return flash device
138*10465441SEvalZero  */
sfud_get_device(size_t index)139*10465441SEvalZero sfud_flash *sfud_get_device(size_t index) {
140*10465441SEvalZero     if (index < sfud_get_device_num()) {
141*10465441SEvalZero         return &flash_table[index];
142*10465441SEvalZero     } else {
143*10465441SEvalZero         return NULL;
144*10465441SEvalZero     }
145*10465441SEvalZero }
146*10465441SEvalZero 
147*10465441SEvalZero /**
148*10465441SEvalZero  * get flash device total number on flash device information table  @see flash_table
149*10465441SEvalZero  *
150*10465441SEvalZero  * @return flash device total number
151*10465441SEvalZero  */
sfud_get_device_num(void)152*10465441SEvalZero size_t sfud_get_device_num(void) {
153*10465441SEvalZero     return sizeof(flash_table) / sizeof(sfud_flash);
154*10465441SEvalZero }
155*10465441SEvalZero 
156*10465441SEvalZero /**
157*10465441SEvalZero  * get flash device information table  @see flash_table
158*10465441SEvalZero  *
159*10465441SEvalZero  * @return flash device table pointer
160*10465441SEvalZero  */
sfud_get_device_table(void)161*10465441SEvalZero const sfud_flash *sfud_get_device_table(void) {
162*10465441SEvalZero     return flash_table;
163*10465441SEvalZero }
164*10465441SEvalZero 
165*10465441SEvalZero #ifdef SFUD_USING_QSPI
qspi_set_read_cmd_format(sfud_flash * flash,uint8_t ins,uint8_t ins_lines,uint8_t addr_lines,uint8_t dummy_cycles,uint8_t data_lines)166*10465441SEvalZero static void qspi_set_read_cmd_format(sfud_flash *flash, uint8_t ins, uint8_t ins_lines, uint8_t addr_lines,
167*10465441SEvalZero         uint8_t dummy_cycles, uint8_t data_lines) {
168*10465441SEvalZero     /* if medium size greater than 16Mb, use 4-Byte address, instruction should be added one */
169*10465441SEvalZero     if (flash->chip.capacity <= 0x1000000) {
170*10465441SEvalZero         flash->read_cmd_format.instruction = ins;
171*10465441SEvalZero         flash->read_cmd_format.address_size = 24;
172*10465441SEvalZero     } else {
173*10465441SEvalZero         flash->read_cmd_format.instruction = ins + 1;
174*10465441SEvalZero         flash->read_cmd_format.address_size = 32;
175*10465441SEvalZero     }
176*10465441SEvalZero 
177*10465441SEvalZero     flash->read_cmd_format.instruction_lines = ins_lines;
178*10465441SEvalZero     flash->read_cmd_format.address_lines = addr_lines;
179*10465441SEvalZero     flash->read_cmd_format.alternate_bytes_lines = 0;
180*10465441SEvalZero     flash->read_cmd_format.dummy_cycles = dummy_cycles;
181*10465441SEvalZero     flash->read_cmd_format.data_lines = data_lines;
182*10465441SEvalZero }
183*10465441SEvalZero 
184*10465441SEvalZero /**
185*10465441SEvalZero  * Enbale the fast read mode in QSPI flash mode. Default read mode is normal SPI mode.
186*10465441SEvalZero  *
187*10465441SEvalZero  * it will find the appropriate fast-read instruction to replace the read instruction(0x03)
188*10465441SEvalZero  * fast-read instruction @see SFUD_FLASH_EXT_INFO_TABLE
189*10465441SEvalZero  *
190*10465441SEvalZero  * @note When Flash is in QSPI mode, the method must be called after sfud_device_init().
191*10465441SEvalZero  *
192*10465441SEvalZero  * @param flash flash device
193*10465441SEvalZero  * @param data_line_width the data lines max width which QSPI bus supported, such as 1, 2, 4
194*10465441SEvalZero  *
195*10465441SEvalZero  * @return result
196*10465441SEvalZero  */
sfud_qspi_fast_read_enable(sfud_flash * flash,uint8_t data_line_width)197*10465441SEvalZero sfud_err sfud_qspi_fast_read_enable(sfud_flash *flash, uint8_t data_line_width) {
198*10465441SEvalZero     size_t i = 0;
199*10465441SEvalZero     uint8_t read_mode = NORMAL_SPI_READ;
200*10465441SEvalZero     sfud_err result = SFUD_SUCCESS;
201*10465441SEvalZero 
202*10465441SEvalZero     SFUD_ASSERT(flash);
203*10465441SEvalZero     SFUD_ASSERT(data_line_width == 1 || data_line_width == 2 || data_line_width == 4);
204*10465441SEvalZero 
205*10465441SEvalZero     /* get read_mode, If don't found, the default is SFUD_QSPI_NORMAL_SPI_READ */
206*10465441SEvalZero     for (i = 0; i < sizeof(qspi_flash_ext_info_table) / sizeof(sfud_qspi_flash_ext_info); i++) {
207*10465441SEvalZero         if ((qspi_flash_ext_info_table[i].mf_id == flash->chip.mf_id)
208*10465441SEvalZero                 && (qspi_flash_ext_info_table[i].type_id == flash->chip.type_id)
209*10465441SEvalZero                 && (qspi_flash_ext_info_table[i].capacity_id == flash->chip.capacity_id)) {
210*10465441SEvalZero             read_mode = qspi_flash_ext_info_table[i].read_mode;
211*10465441SEvalZero         }
212*10465441SEvalZero     }
213*10465441SEvalZero 
214*10465441SEvalZero     /* determine qspi supports which read mode and set read_cmd_format struct */
215*10465441SEvalZero     switch (data_line_width) {
216*10465441SEvalZero     case 1:
217*10465441SEvalZero         qspi_set_read_cmd_format(flash, SFUD_CMD_READ_DATA, 1, 1, 0, 1);
218*10465441SEvalZero         break;
219*10465441SEvalZero     case 2:
220*10465441SEvalZero         if (read_mode & DUAL_IO) {
221*10465441SEvalZero             qspi_set_read_cmd_format(flash, SFUD_CMD_DUAL_IO_READ_DATA, 1, 2, 8, 2);
222*10465441SEvalZero         } else if (read_mode & DUAL_OUTPUT) {
223*10465441SEvalZero             qspi_set_read_cmd_format(flash, SFUD_CMD_DUAL_OUTPUT_READ_DATA, 1, 1, 8, 2);
224*10465441SEvalZero         } else {
225*10465441SEvalZero             qspi_set_read_cmd_format(flash, SFUD_CMD_READ_DATA, 1, 1, 0, 1);
226*10465441SEvalZero         }
227*10465441SEvalZero         break;
228*10465441SEvalZero     case 4:
229*10465441SEvalZero         if (read_mode & QUAD_IO) {
230*10465441SEvalZero             qspi_set_read_cmd_format(flash, SFUD_CMD_QUAD_IO_READ_DATA, 1, 4, 6, 4);
231*10465441SEvalZero         } else if (read_mode & QUAD_OUTPUT) {
232*10465441SEvalZero             qspi_set_read_cmd_format(flash, SFUD_CMD_QUAD_OUTPUT_READ_DATA, 1, 1, 8, 4);
233*10465441SEvalZero         } else {
234*10465441SEvalZero             qspi_set_read_cmd_format(flash, SFUD_CMD_READ_DATA, 1, 1, 0, 1);
235*10465441SEvalZero         }
236*10465441SEvalZero         break;
237*10465441SEvalZero     }
238*10465441SEvalZero 
239*10465441SEvalZero     return result;
240*10465441SEvalZero }
241*10465441SEvalZero #endif /* SFUD_USING_QSPI */
242*10465441SEvalZero 
243*10465441SEvalZero /**
244*10465441SEvalZero  * hardware initialize
245*10465441SEvalZero  */
hardware_init(sfud_flash * flash)246*10465441SEvalZero static sfud_err hardware_init(sfud_flash *flash) {
247*10465441SEvalZero     extern sfud_err sfud_spi_port_init(sfud_flash * flash);
248*10465441SEvalZero 
249*10465441SEvalZero     sfud_err result = SFUD_SUCCESS;
250*10465441SEvalZero     size_t i;
251*10465441SEvalZero 
252*10465441SEvalZero     SFUD_ASSERT(flash);
253*10465441SEvalZero 
254*10465441SEvalZero     result = sfud_spi_port_init(flash);
255*10465441SEvalZero     if (result != SFUD_SUCCESS) {
256*10465441SEvalZero         return result;
257*10465441SEvalZero     }
258*10465441SEvalZero 
259*10465441SEvalZero #ifdef SFUD_USING_QSPI
260*10465441SEvalZero     /* set default read instruction */
261*10465441SEvalZero     flash->read_cmd_format.instruction = SFUD_CMD_READ_DATA;
262*10465441SEvalZero #endif /* SFUD_USING_QSPI */
263*10465441SEvalZero 
264*10465441SEvalZero     /* SPI write read function must be initialize */
265*10465441SEvalZero     SFUD_ASSERT(flash->spi.wr);
266*10465441SEvalZero     /* if the user don't configure flash chip information then using SFDP parameter or static flash parameter table */
267*10465441SEvalZero     if (flash->chip.capacity == 0 || flash->chip.write_mode == 0 || flash->chip.erase_gran == 0
268*10465441SEvalZero             || flash->chip.erase_gran_cmd == 0) {
269*10465441SEvalZero         /* read JEDEC ID include manufacturer ID, memory type ID and flash capacity ID */
270*10465441SEvalZero         result = read_jedec_id(flash);
271*10465441SEvalZero         if (result != SFUD_SUCCESS) {
272*10465441SEvalZero             return result;
273*10465441SEvalZero         }
274*10465441SEvalZero 
275*10465441SEvalZero #ifdef SFUD_USING_SFDP
276*10465441SEvalZero         extern bool sfud_read_sfdp(sfud_flash *flash);
277*10465441SEvalZero         /* read SFDP parameters */
278*10465441SEvalZero         if (sfud_read_sfdp(flash)) {
279*10465441SEvalZero             flash->chip.name = NULL;
280*10465441SEvalZero             flash->chip.capacity = flash->sfdp.capacity;
281*10465441SEvalZero             /* only 1 byte or 256 bytes write mode for SFDP */
282*10465441SEvalZero             if (flash->sfdp.write_gran == 1) {
283*10465441SEvalZero                 flash->chip.write_mode = SFUD_WM_BYTE;
284*10465441SEvalZero             } else {
285*10465441SEvalZero                 flash->chip.write_mode = SFUD_WM_PAGE_256B;
286*10465441SEvalZero             }
287*10465441SEvalZero             /* find the the smallest erase sector size for eraser. then will use this size for erase granularity */
288*10465441SEvalZero             flash->chip.erase_gran = flash->sfdp.eraser[0].size;
289*10465441SEvalZero             flash->chip.erase_gran_cmd = flash->sfdp.eraser[0].cmd;
290*10465441SEvalZero             for (i = 1; i < SFUD_SFDP_ERASE_TYPE_MAX_NUM; i++) {
291*10465441SEvalZero                 if (flash->sfdp.eraser[i].size != 0 && flash->chip.erase_gran > flash->sfdp.eraser[i].size) {
292*10465441SEvalZero                     flash->chip.erase_gran = flash->sfdp.eraser[i].size;
293*10465441SEvalZero                     flash->chip.erase_gran_cmd = flash->sfdp.eraser[i].cmd;
294*10465441SEvalZero                 }
295*10465441SEvalZero             }
296*10465441SEvalZero         } else {
297*10465441SEvalZero #endif
298*10465441SEvalZero 
299*10465441SEvalZero #ifdef SFUD_USING_FLASH_INFO_TABLE
300*10465441SEvalZero             /* read SFDP parameters failed then using SFUD library provided static parameter */
301*10465441SEvalZero             for (i = 0; i < sizeof(flash_chip_table) / sizeof(sfud_flash_chip); i++) {
302*10465441SEvalZero                 if ((flash_chip_table[i].mf_id == flash->chip.mf_id)
303*10465441SEvalZero                         && (flash_chip_table[i].type_id == flash->chip.type_id)
304*10465441SEvalZero                         && (flash_chip_table[i].capacity_id == flash->chip.capacity_id)) {
305*10465441SEvalZero                     flash->chip.name = flash_chip_table[i].name;
306*10465441SEvalZero                     flash->chip.capacity = flash_chip_table[i].capacity;
307*10465441SEvalZero                     flash->chip.write_mode = flash_chip_table[i].write_mode;
308*10465441SEvalZero                     flash->chip.erase_gran = flash_chip_table[i].erase_gran;
309*10465441SEvalZero                     flash->chip.erase_gran_cmd = flash_chip_table[i].erase_gran_cmd;
310*10465441SEvalZero                     break;
311*10465441SEvalZero                 }
312*10465441SEvalZero             }
313*10465441SEvalZero #endif
314*10465441SEvalZero 
315*10465441SEvalZero #ifdef SFUD_USING_SFDP
316*10465441SEvalZero         }
317*10465441SEvalZero #endif
318*10465441SEvalZero 
319*10465441SEvalZero     }
320*10465441SEvalZero 
321*10465441SEvalZero     if (flash->chip.capacity == 0 || flash->chip.write_mode == 0 || flash->chip.erase_gran == 0
322*10465441SEvalZero             || flash->chip.erase_gran_cmd == 0) {
323*10465441SEvalZero         SFUD_INFO("Warning: This flash device is not found or not support.");
324*10465441SEvalZero         return SFUD_ERR_NOT_FOUND;
325*10465441SEvalZero     } else {
326*10465441SEvalZero         const char *flash_mf_name = NULL;
327*10465441SEvalZero         /* find the manufacturer information */
328*10465441SEvalZero         for (i = 0; i < sizeof(mf_table) / sizeof(sfud_mf); i++) {
329*10465441SEvalZero             if (mf_table[i].id == flash->chip.mf_id) {
330*10465441SEvalZero                 flash_mf_name = mf_table[i].name;
331*10465441SEvalZero                 break;
332*10465441SEvalZero             }
333*10465441SEvalZero         }
334*10465441SEvalZero         /* print manufacturer and flash chip name */
335*10465441SEvalZero         if (flash_mf_name && flash->chip.name) {
336*10465441SEvalZero             SFUD_INFO("Find a %s %s flash chip. Size is %ld bytes.", flash_mf_name, flash->chip.name,
337*10465441SEvalZero                     flash->chip.capacity);
338*10465441SEvalZero         } else if (flash_mf_name) {
339*10465441SEvalZero             SFUD_INFO("Find a %s flash chip. Size is %ld bytes.", flash_mf_name, flash->chip.capacity);
340*10465441SEvalZero         } else {
341*10465441SEvalZero             SFUD_INFO("Find a flash chip. Size is %ld bytes.", flash->chip.capacity);
342*10465441SEvalZero         }
343*10465441SEvalZero     }
344*10465441SEvalZero 
345*10465441SEvalZero     /* reset flash device */
346*10465441SEvalZero     result = reset(flash);
347*10465441SEvalZero     if (result != SFUD_SUCCESS) {
348*10465441SEvalZero         return result;
349*10465441SEvalZero     }
350*10465441SEvalZero 
351*10465441SEvalZero     /* I found when the flash write mode is supported AAI mode. The flash all blocks is protected,
352*10465441SEvalZero      * so need change the flash status to unprotected before write and erase operate. */
353*10465441SEvalZero     if (flash->chip.write_mode & SFUD_WM_AAI) {
354*10465441SEvalZero         result = sfud_write_status(flash, true, 0x00);
355*10465441SEvalZero         if (result != SFUD_SUCCESS) {
356*10465441SEvalZero             return result;
357*10465441SEvalZero         }
358*10465441SEvalZero     }
359*10465441SEvalZero 
360*10465441SEvalZero     /* if the flash is large than 16MB (256Mb) then enter in 4-Byte addressing mode */
361*10465441SEvalZero     if (flash->chip.capacity > (1L << 24)) {
362*10465441SEvalZero         result = set_4_byte_address_mode(flash, true);
363*10465441SEvalZero     } else {
364*10465441SEvalZero         flash->addr_in_4_byte = false;
365*10465441SEvalZero     }
366*10465441SEvalZero 
367*10465441SEvalZero     return result;
368*10465441SEvalZero }
369*10465441SEvalZero 
370*10465441SEvalZero /**
371*10465441SEvalZero  * software initialize
372*10465441SEvalZero  *
373*10465441SEvalZero  * @param flash flash device
374*10465441SEvalZero  *
375*10465441SEvalZero  * @return result
376*10465441SEvalZero  */
software_init(const sfud_flash * flash)377*10465441SEvalZero static sfud_err software_init(const sfud_flash *flash) {
378*10465441SEvalZero     sfud_err result = SFUD_SUCCESS;
379*10465441SEvalZero 
380*10465441SEvalZero     SFUD_ASSERT(flash);
381*10465441SEvalZero 
382*10465441SEvalZero     return result;
383*10465441SEvalZero }
384*10465441SEvalZero 
385*10465441SEvalZero /**
386*10465441SEvalZero  * read flash data
387*10465441SEvalZero  *
388*10465441SEvalZero  * @param flash flash device
389*10465441SEvalZero  * @param addr start address
390*10465441SEvalZero  * @param size read size
391*10465441SEvalZero  * @param data read data pointer
392*10465441SEvalZero  *
393*10465441SEvalZero  * @return result
394*10465441SEvalZero  */
sfud_read(const sfud_flash * flash,uint32_t addr,size_t size,uint8_t * data)395*10465441SEvalZero sfud_err sfud_read(const sfud_flash *flash, uint32_t addr, size_t size, uint8_t *data) {
396*10465441SEvalZero     sfud_err result = SFUD_SUCCESS;
397*10465441SEvalZero     const sfud_spi *spi = &flash->spi;
398*10465441SEvalZero     uint8_t cmd_data[5], cmd_size;
399*10465441SEvalZero 
400*10465441SEvalZero     SFUD_ASSERT(flash);
401*10465441SEvalZero     SFUD_ASSERT(data);
402*10465441SEvalZero     /* must be call this function after initialize OK */
403*10465441SEvalZero     SFUD_ASSERT(flash->init_ok);
404*10465441SEvalZero     /* check the flash address bound */
405*10465441SEvalZero     if (addr + size > flash->chip.capacity) {
406*10465441SEvalZero         SFUD_INFO("Error: Flash address is out of bound.");
407*10465441SEvalZero         return SFUD_ERR_ADDR_OUT_OF_BOUND;
408*10465441SEvalZero     }
409*10465441SEvalZero     /* lock SPI */
410*10465441SEvalZero     if (spi->lock) {
411*10465441SEvalZero         spi->lock(spi);
412*10465441SEvalZero     }
413*10465441SEvalZero 
414*10465441SEvalZero     result = wait_busy(flash);
415*10465441SEvalZero 
416*10465441SEvalZero     if (result == SFUD_SUCCESS) {
417*10465441SEvalZero #ifdef SFUD_USING_QSPI
418*10465441SEvalZero         if (flash->read_cmd_format.instruction != SFUD_CMD_READ_DATA) {
419*10465441SEvalZero             result = spi->qspi_read(spi, addr, (sfud_qspi_read_cmd_format *)&flash->read_cmd_format, data, size);
420*10465441SEvalZero         } else
421*10465441SEvalZero #endif
422*10465441SEvalZero         {
423*10465441SEvalZero             cmd_data[0] = SFUD_CMD_READ_DATA;
424*10465441SEvalZero             make_adress_byte_array(flash, addr, &cmd_data[1]);
425*10465441SEvalZero             cmd_size = flash->addr_in_4_byte ? 5 : 4;
426*10465441SEvalZero             result = spi->wr(spi, cmd_data, cmd_size, data, size);
427*10465441SEvalZero         }
428*10465441SEvalZero     }
429*10465441SEvalZero     /* unlock SPI */
430*10465441SEvalZero     if (spi->unlock) {
431*10465441SEvalZero         spi->unlock(spi);
432*10465441SEvalZero     }
433*10465441SEvalZero 
434*10465441SEvalZero     return result;
435*10465441SEvalZero }
436*10465441SEvalZero 
437*10465441SEvalZero /**
438*10465441SEvalZero  * erase all flash data
439*10465441SEvalZero  *
440*10465441SEvalZero  * @param flash flash device
441*10465441SEvalZero  *
442*10465441SEvalZero  * @return result
443*10465441SEvalZero  */
sfud_chip_erase(const sfud_flash * flash)444*10465441SEvalZero sfud_err sfud_chip_erase(const sfud_flash *flash) {
445*10465441SEvalZero     sfud_err result = SFUD_SUCCESS;
446*10465441SEvalZero     const sfud_spi *spi = &flash->spi;
447*10465441SEvalZero     uint8_t cmd_data[4];
448*10465441SEvalZero 
449*10465441SEvalZero     SFUD_ASSERT(flash);
450*10465441SEvalZero     /* must be call this function after initialize OK */
451*10465441SEvalZero     SFUD_ASSERT(flash->init_ok);
452*10465441SEvalZero     /* lock SPI */
453*10465441SEvalZero     if (spi->lock) {
454*10465441SEvalZero         spi->lock(spi);
455*10465441SEvalZero     }
456*10465441SEvalZero 
457*10465441SEvalZero     /* set the flash write enable */
458*10465441SEvalZero     result = set_write_enabled(flash, true);
459*10465441SEvalZero     if (result != SFUD_SUCCESS) {
460*10465441SEvalZero         goto __exit;
461*10465441SEvalZero     }
462*10465441SEvalZero 
463*10465441SEvalZero     cmd_data[0] = SFUD_CMD_ERASE_CHIP;
464*10465441SEvalZero     /* dual-buffer write, like AT45DB series flash chip erase operate is different for other flash */
465*10465441SEvalZero     if (flash->chip.write_mode & SFUD_WM_DUAL_BUFFER) {
466*10465441SEvalZero         cmd_data[1] = 0x94;
467*10465441SEvalZero         cmd_data[2] = 0x80;
468*10465441SEvalZero         cmd_data[3] = 0x9A;
469*10465441SEvalZero         result = spi->wr(spi, cmd_data, 4, NULL, 0);
470*10465441SEvalZero     } else {
471*10465441SEvalZero         result = spi->wr(spi, cmd_data, 1, NULL, 0);
472*10465441SEvalZero     }
473*10465441SEvalZero     if (result != SFUD_SUCCESS) {
474*10465441SEvalZero         SFUD_INFO("Error: Flash chip erase SPI communicate error.");
475*10465441SEvalZero         goto __exit;
476*10465441SEvalZero     }
477*10465441SEvalZero     result = wait_busy(flash);
478*10465441SEvalZero 
479*10465441SEvalZero __exit:
480*10465441SEvalZero     /* set the flash write disable */
481*10465441SEvalZero     set_write_enabled(flash, false);
482*10465441SEvalZero     /* unlock SPI */
483*10465441SEvalZero     if (spi->unlock) {
484*10465441SEvalZero         spi->unlock(spi);
485*10465441SEvalZero     }
486*10465441SEvalZero 
487*10465441SEvalZero     return result;
488*10465441SEvalZero }
489*10465441SEvalZero 
490*10465441SEvalZero /**
491*10465441SEvalZero  * erase flash data
492*10465441SEvalZero  *
493*10465441SEvalZero  * @note It will erase align by erase granularity.
494*10465441SEvalZero  *
495*10465441SEvalZero  * @param flash flash device
496*10465441SEvalZero  * @param addr start address
497*10465441SEvalZero  * @param size erase size
498*10465441SEvalZero  *
499*10465441SEvalZero  * @return result
500*10465441SEvalZero  */
sfud_erase(const sfud_flash * flash,uint32_t addr,size_t size)501*10465441SEvalZero sfud_err sfud_erase(const sfud_flash *flash, uint32_t addr, size_t size) {
502*10465441SEvalZero     extern size_t sfud_sfdp_get_suitable_eraser(const sfud_flash *flash, uint32_t addr, size_t erase_size);
503*10465441SEvalZero 
504*10465441SEvalZero     sfud_err result = SFUD_SUCCESS;
505*10465441SEvalZero     const sfud_spi *spi = &flash->spi;
506*10465441SEvalZero     uint8_t cmd_data[5], cmd_size, cur_erase_cmd;
507*10465441SEvalZero     size_t cur_erase_size;
508*10465441SEvalZero 
509*10465441SEvalZero     SFUD_ASSERT(flash);
510*10465441SEvalZero     /* must be call this function after initialize OK */
511*10465441SEvalZero     SFUD_ASSERT(flash->init_ok);
512*10465441SEvalZero     /* check the flash address bound */
513*10465441SEvalZero     if (addr + size > flash->chip.capacity) {
514*10465441SEvalZero         SFUD_INFO("Error: Flash address is out of bound.");
515*10465441SEvalZero         return SFUD_ERR_ADDR_OUT_OF_BOUND;
516*10465441SEvalZero     }
517*10465441SEvalZero 
518*10465441SEvalZero     if (addr == 0 && size == flash->chip.capacity) {
519*10465441SEvalZero         return sfud_chip_erase(flash);
520*10465441SEvalZero     }
521*10465441SEvalZero 
522*10465441SEvalZero     /* lock SPI */
523*10465441SEvalZero     if (spi->lock) {
524*10465441SEvalZero         spi->lock(spi);
525*10465441SEvalZero     }
526*10465441SEvalZero 
527*10465441SEvalZero     /* loop erase operate. erase unit is erase granularity */
528*10465441SEvalZero     while (size) {
529*10465441SEvalZero         /* if this flash is support SFDP parameter, then used SFDP parameter supplies eraser */
530*10465441SEvalZero #ifdef SFUD_USING_SFDP
531*10465441SEvalZero         size_t eraser_index;
532*10465441SEvalZero         if (flash->sfdp.available) {
533*10465441SEvalZero             /* get the suitable eraser for erase process from SFDP parameter */
534*10465441SEvalZero             eraser_index = sfud_sfdp_get_suitable_eraser(flash, addr, size);
535*10465441SEvalZero             cur_erase_cmd = flash->sfdp.eraser[eraser_index].cmd;
536*10465441SEvalZero             cur_erase_size = flash->sfdp.eraser[eraser_index].size;
537*10465441SEvalZero         } else {
538*10465441SEvalZero #else
539*10465441SEvalZero         {
540*10465441SEvalZero #endif
541*10465441SEvalZero             cur_erase_cmd = flash->chip.erase_gran_cmd;
542*10465441SEvalZero             cur_erase_size = flash->chip.erase_gran;
543*10465441SEvalZero         }
544*10465441SEvalZero         /* set the flash write enable */
545*10465441SEvalZero         result = set_write_enabled(flash, true);
546*10465441SEvalZero         if (result != SFUD_SUCCESS) {
547*10465441SEvalZero             goto __exit;
548*10465441SEvalZero         }
549*10465441SEvalZero 
550*10465441SEvalZero         cmd_data[0] = cur_erase_cmd;
551*10465441SEvalZero         make_adress_byte_array(flash, addr, &cmd_data[1]);
552*10465441SEvalZero         cmd_size = flash->addr_in_4_byte ? 5 : 4;
553*10465441SEvalZero         result = spi->wr(spi, cmd_data, cmd_size, NULL, 0);
554*10465441SEvalZero         if (result != SFUD_SUCCESS) {
555*10465441SEvalZero             SFUD_INFO("Error: Flash erase SPI communicate error.");
556*10465441SEvalZero             goto __exit;
557*10465441SEvalZero         }
558*10465441SEvalZero         result = wait_busy(flash);
559*10465441SEvalZero         if (result != SFUD_SUCCESS) {
560*10465441SEvalZero             goto __exit;
561*10465441SEvalZero         }
562*10465441SEvalZero         /* make erase align and calculate next erase address */
563*10465441SEvalZero         if (addr % cur_erase_size != 0) {
564*10465441SEvalZero             if (size > cur_erase_size - (addr % cur_erase_size)) {
565*10465441SEvalZero                 size -= cur_erase_size - (addr % cur_erase_size);
566*10465441SEvalZero                 addr += cur_erase_size - (addr % cur_erase_size);
567*10465441SEvalZero             } else {
568*10465441SEvalZero                 goto __exit;
569*10465441SEvalZero             }
570*10465441SEvalZero         } else {
571*10465441SEvalZero             if (size > cur_erase_size) {
572*10465441SEvalZero                 size -= cur_erase_size;
573*10465441SEvalZero                 addr += cur_erase_size;
574*10465441SEvalZero             } else {
575*10465441SEvalZero                 goto __exit;
576*10465441SEvalZero             }
577*10465441SEvalZero         }
578*10465441SEvalZero     }
579*10465441SEvalZero 
580*10465441SEvalZero __exit:
581*10465441SEvalZero     /* set the flash write disable */
582*10465441SEvalZero     set_write_enabled(flash, false);
583*10465441SEvalZero     /* unlock SPI */
584*10465441SEvalZero     if (spi->unlock) {
585*10465441SEvalZero         spi->unlock(spi);
586*10465441SEvalZero     }
587*10465441SEvalZero 
588*10465441SEvalZero     return result;
589*10465441SEvalZero }
590*10465441SEvalZero 
591*10465441SEvalZero /**
592*10465441SEvalZero  * write flash data (no erase operate) for write 1 to 256 bytes per page mode or byte write mode
593*10465441SEvalZero  *
594*10465441SEvalZero  * @param flash flash device
595*10465441SEvalZero  * @param addr start address
596*10465441SEvalZero  * @param size write size
597*10465441SEvalZero  * @param write_gran write granularity bytes, only support 1 or 256
598*10465441SEvalZero  * @param data write data
599*10465441SEvalZero  *
600*10465441SEvalZero  * @return result
601*10465441SEvalZero  */
602*10465441SEvalZero static sfud_err page256_or_1_byte_write(const sfud_flash *flash, uint32_t addr, size_t size, uint16_t write_gran,
603*10465441SEvalZero         const uint8_t *data) {
604*10465441SEvalZero     sfud_err result = SFUD_SUCCESS;
605*10465441SEvalZero     const sfud_spi *spi = &flash->spi;
606*10465441SEvalZero     static uint8_t cmd_data[5 + SFUD_WRITE_MAX_PAGE_SIZE];
607*10465441SEvalZero     uint8_t cmd_size;
608*10465441SEvalZero     size_t data_size;
609*10465441SEvalZero 
610*10465441SEvalZero     SFUD_ASSERT(flash);
611*10465441SEvalZero     /* only support 1 or 256 */
612*10465441SEvalZero     SFUD_ASSERT(write_gran == 1 || write_gran == 256);
613*10465441SEvalZero     /* must be call this function after initialize OK */
614*10465441SEvalZero     SFUD_ASSERT(flash->init_ok);
615*10465441SEvalZero     /* check the flash address bound */
616*10465441SEvalZero     if (addr + size > flash->chip.capacity) {
617*10465441SEvalZero         SFUD_INFO("Error: Flash address is out of bound.");
618*10465441SEvalZero         return SFUD_ERR_ADDR_OUT_OF_BOUND;
619*10465441SEvalZero     }
620*10465441SEvalZero     /* lock SPI */
621*10465441SEvalZero     if (spi->lock) {
622*10465441SEvalZero         spi->lock(spi);
623*10465441SEvalZero     }
624*10465441SEvalZero 
625*10465441SEvalZero     /* loop write operate. write unit is write granularity */
626*10465441SEvalZero     while (size) {
627*10465441SEvalZero         /* set the flash write enable */
628*10465441SEvalZero         result = set_write_enabled(flash, true);
629*10465441SEvalZero         if (result != SFUD_SUCCESS) {
630*10465441SEvalZero             goto __exit;
631*10465441SEvalZero         }
632*10465441SEvalZero         cmd_data[0] = SFUD_CMD_PAGE_PROGRAM;
633*10465441SEvalZero         make_adress_byte_array(flash, addr, &cmd_data[1]);
634*10465441SEvalZero         cmd_size = flash->addr_in_4_byte ? 5 : 4;
635*10465441SEvalZero 
636*10465441SEvalZero         /* make write align and calculate next write address */
637*10465441SEvalZero         if (addr % write_gran != 0) {
638*10465441SEvalZero             if (size > write_gran - (addr % write_gran)) {
639*10465441SEvalZero                 data_size = write_gran - (addr % write_gran);
640*10465441SEvalZero             } else {
641*10465441SEvalZero                 data_size = size;
642*10465441SEvalZero             }
643*10465441SEvalZero         } else {
644*10465441SEvalZero             if (size > write_gran) {
645*10465441SEvalZero                 data_size = write_gran;
646*10465441SEvalZero             } else {
647*10465441SEvalZero                 data_size = size;
648*10465441SEvalZero             }
649*10465441SEvalZero         }
650*10465441SEvalZero         size -= data_size;
651*10465441SEvalZero         addr += data_size;
652*10465441SEvalZero 
653*10465441SEvalZero         memcpy(&cmd_data[cmd_size], data, data_size);
654*10465441SEvalZero 
655*10465441SEvalZero         result = spi->wr(spi, cmd_data, cmd_size + data_size, NULL, 0);
656*10465441SEvalZero         if (result != SFUD_SUCCESS) {
657*10465441SEvalZero             SFUD_INFO("Error: Flash write SPI communicate error.");
658*10465441SEvalZero             goto __exit;
659*10465441SEvalZero         }
660*10465441SEvalZero         result = wait_busy(flash);
661*10465441SEvalZero         if (result != SFUD_SUCCESS) {
662*10465441SEvalZero             goto __exit;
663*10465441SEvalZero         }
664*10465441SEvalZero         data += data_size;
665*10465441SEvalZero     }
666*10465441SEvalZero 
667*10465441SEvalZero __exit:
668*10465441SEvalZero     /* set the flash write disable */
669*10465441SEvalZero     set_write_enabled(flash, false);
670*10465441SEvalZero     /* unlock SPI */
671*10465441SEvalZero     if (spi->unlock) {
672*10465441SEvalZero         spi->unlock(spi);
673*10465441SEvalZero     }
674*10465441SEvalZero 
675*10465441SEvalZero     return result;
676*10465441SEvalZero }
677*10465441SEvalZero 
678*10465441SEvalZero /**
679*10465441SEvalZero  * write flash data (no erase operate) for auto address increment mode
680*10465441SEvalZero  *
681*10465441SEvalZero  * If the address is odd number, it will place one 0xFF before the start of data for protect the old data.
682*10465441SEvalZero  * If the latest remain size is 1, it will append one 0xFF at the end of data for protect the old data.
683*10465441SEvalZero  *
684*10465441SEvalZero  * @param flash flash device
685*10465441SEvalZero  * @param addr start address
686*10465441SEvalZero  * @param size write size
687*10465441SEvalZero  * @param data write data
688*10465441SEvalZero  *
689*10465441SEvalZero  * @return result
690*10465441SEvalZero  */
691*10465441SEvalZero static sfud_err aai_write(const sfud_flash *flash, uint32_t addr, size_t size, const uint8_t *data) {
692*10465441SEvalZero     sfud_err result = SFUD_SUCCESS;
693*10465441SEvalZero     const sfud_spi *spi = &flash->spi;
694*10465441SEvalZero     uint8_t cmd_data[6], cmd_size;
695*10465441SEvalZero     bool first_write = true;
696*10465441SEvalZero 
697*10465441SEvalZero     SFUD_ASSERT(flash);
698*10465441SEvalZero     SFUD_ASSERT(flash->init_ok);
699*10465441SEvalZero     /* check the flash address bound */
700*10465441SEvalZero     if (addr + size > flash->chip.capacity) {
701*10465441SEvalZero         SFUD_INFO("Error: Flash address is out of bound.");
702*10465441SEvalZero         return SFUD_ERR_ADDR_OUT_OF_BOUND;
703*10465441SEvalZero     }
704*10465441SEvalZero     /* lock SPI */
705*10465441SEvalZero     if (spi->lock) {
706*10465441SEvalZero         spi->lock(spi);
707*10465441SEvalZero     }
708*10465441SEvalZero     /* The address must be even for AAI write mode. So it must write one byte first when address is odd. */
709*10465441SEvalZero     if (addr % 2 != 0) {
710*10465441SEvalZero         result = page256_or_1_byte_write(flash, addr++, 1, 1, data++);
711*10465441SEvalZero         if (result != SFUD_SUCCESS) {
712*10465441SEvalZero             goto __exit;
713*10465441SEvalZero         }
714*10465441SEvalZero         size--;
715*10465441SEvalZero     }
716*10465441SEvalZero     /* set the flash write enable */
717*10465441SEvalZero     result = set_write_enabled(flash, true);
718*10465441SEvalZero     if (result != SFUD_SUCCESS) {
719*10465441SEvalZero         goto __exit;
720*10465441SEvalZero     }
721*10465441SEvalZero     /* loop write operate. */
722*10465441SEvalZero     cmd_data[0] = SFUD_CMD_AAI_WORD_PROGRAM;
723*10465441SEvalZero     while (size >= 2) {
724*10465441SEvalZero         if (first_write) {
725*10465441SEvalZero             make_adress_byte_array(flash, addr, &cmd_data[1]);
726*10465441SEvalZero             cmd_size = flash->addr_in_4_byte ? 5 : 4;
727*10465441SEvalZero             cmd_data[cmd_size] = *data;
728*10465441SEvalZero             cmd_data[cmd_size + 1] = *(data + 1);
729*10465441SEvalZero             first_write = false;
730*10465441SEvalZero         } else {
731*10465441SEvalZero             cmd_size = 1;
732*10465441SEvalZero             cmd_data[1] = *data;
733*10465441SEvalZero             cmd_data[2] = *(data + 1);
734*10465441SEvalZero         }
735*10465441SEvalZero 
736*10465441SEvalZero         result = spi->wr(spi, cmd_data, cmd_size + 2, NULL, 0);
737*10465441SEvalZero         if (result != SFUD_SUCCESS) {
738*10465441SEvalZero             SFUD_INFO("Error: Flash write SPI communicate error.");
739*10465441SEvalZero             goto __exit;
740*10465441SEvalZero         }
741*10465441SEvalZero 
742*10465441SEvalZero         result = wait_busy(flash);
743*10465441SEvalZero         if (result != SFUD_SUCCESS) {
744*10465441SEvalZero             goto __exit;
745*10465441SEvalZero         }
746*10465441SEvalZero 
747*10465441SEvalZero         size -= 2;
748*10465441SEvalZero         addr += 2;
749*10465441SEvalZero         data += 2;
750*10465441SEvalZero     }
751*10465441SEvalZero     /* set the flash write disable for exit AAI mode */
752*10465441SEvalZero     result = set_write_enabled(flash, false);
753*10465441SEvalZero     /* write last one byte data when origin write size is odd */
754*10465441SEvalZero     if (result == SFUD_SUCCESS && size == 1) {
755*10465441SEvalZero         result = page256_or_1_byte_write(flash, addr, 1, 1, data);
756*10465441SEvalZero     }
757*10465441SEvalZero 
758*10465441SEvalZero __exit:
759*10465441SEvalZero     if (result != SFUD_SUCCESS) {
760*10465441SEvalZero         set_write_enabled(flash, false);
761*10465441SEvalZero     }
762*10465441SEvalZero     /* unlock SPI */
763*10465441SEvalZero     if (spi->unlock) {
764*10465441SEvalZero         spi->unlock(spi);
765*10465441SEvalZero     }
766*10465441SEvalZero 
767*10465441SEvalZero     return result;
768*10465441SEvalZero }
769*10465441SEvalZero 
770*10465441SEvalZero /**
771*10465441SEvalZero  * write flash data (no erase operate)
772*10465441SEvalZero  *
773*10465441SEvalZero  * @param flash flash device
774*10465441SEvalZero  * @param addr start address
775*10465441SEvalZero  * @param size write size
776*10465441SEvalZero  * @param data write data
777*10465441SEvalZero  *
778*10465441SEvalZero  * @return result
779*10465441SEvalZero  */
780*10465441SEvalZero sfud_err sfud_write(const sfud_flash *flash, uint32_t addr, size_t size, const uint8_t *data) {
781*10465441SEvalZero     sfud_err result = SFUD_SUCCESS;
782*10465441SEvalZero 
783*10465441SEvalZero     if (flash->chip.write_mode & SFUD_WM_PAGE_256B) {
784*10465441SEvalZero         result = page256_or_1_byte_write(flash, addr, size, 256, data);
785*10465441SEvalZero     } else if (flash->chip.write_mode & SFUD_WM_AAI) {
786*10465441SEvalZero         result = aai_write(flash, addr, size, data);
787*10465441SEvalZero     } else if (flash->chip.write_mode & SFUD_WM_DUAL_BUFFER) {
788*10465441SEvalZero         //TODO dual-buffer write mode
789*10465441SEvalZero     }
790*10465441SEvalZero 
791*10465441SEvalZero     return result;
792*10465441SEvalZero }
793*10465441SEvalZero 
794*10465441SEvalZero /**
795*10465441SEvalZero  * erase and write flash data
796*10465441SEvalZero  *
797*10465441SEvalZero  * @param flash flash device
798*10465441SEvalZero  * @param addr start address
799*10465441SEvalZero  * @param size write size
800*10465441SEvalZero  * @param data write data
801*10465441SEvalZero  *
802*10465441SEvalZero  * @return result
803*10465441SEvalZero  */
804*10465441SEvalZero sfud_err sfud_erase_write(const sfud_flash *flash, uint32_t addr, size_t size, const uint8_t *data) {
805*10465441SEvalZero     sfud_err result = SFUD_SUCCESS;
806*10465441SEvalZero 
807*10465441SEvalZero     result = sfud_erase(flash, addr, size);
808*10465441SEvalZero 
809*10465441SEvalZero     if (result == SFUD_SUCCESS) {
810*10465441SEvalZero         result = sfud_write(flash, addr, size, data);
811*10465441SEvalZero     }
812*10465441SEvalZero 
813*10465441SEvalZero     return result;
814*10465441SEvalZero }
815*10465441SEvalZero 
816*10465441SEvalZero static sfud_err reset(const sfud_flash *flash) {
817*10465441SEvalZero     sfud_err result = SFUD_SUCCESS;
818*10465441SEvalZero     const sfud_spi *spi = &flash->spi;
819*10465441SEvalZero     uint8_t cmd_data[2];
820*10465441SEvalZero 
821*10465441SEvalZero     SFUD_ASSERT(flash);
822*10465441SEvalZero 
823*10465441SEvalZero     cmd_data[0] = SFUD_CMD_ENABLE_RESET;
824*10465441SEvalZero     result = spi->wr(spi, cmd_data, 1, NULL, 0);
825*10465441SEvalZero     if (result == SFUD_SUCCESS) {
826*10465441SEvalZero         result = wait_busy(flash);
827*10465441SEvalZero     } else {
828*10465441SEvalZero         SFUD_INFO("Error: Flash device reset failed.");
829*10465441SEvalZero         return result;
830*10465441SEvalZero     }
831*10465441SEvalZero 
832*10465441SEvalZero     cmd_data[1] = SFUD_CMD_RESET;
833*10465441SEvalZero     result = spi->wr(spi, &cmd_data[1], 1, NULL, 0);
834*10465441SEvalZero 
835*10465441SEvalZero     if (result == SFUD_SUCCESS) {
836*10465441SEvalZero         result = wait_busy(flash);
837*10465441SEvalZero     }
838*10465441SEvalZero 
839*10465441SEvalZero     if (result == SFUD_SUCCESS) {
840*10465441SEvalZero         SFUD_DEBUG("Flash device reset success.");
841*10465441SEvalZero     } else {
842*10465441SEvalZero         SFUD_INFO("Error: Flash device reset failed.");
843*10465441SEvalZero     }
844*10465441SEvalZero 
845*10465441SEvalZero     return result;
846*10465441SEvalZero }
847*10465441SEvalZero 
848*10465441SEvalZero static sfud_err read_jedec_id(sfud_flash *flash) {
849*10465441SEvalZero     sfud_err result = SFUD_SUCCESS;
850*10465441SEvalZero     const sfud_spi *spi = &flash->spi;
851*10465441SEvalZero     uint8_t cmd_data[1], recv_data[3];
852*10465441SEvalZero 
853*10465441SEvalZero     SFUD_ASSERT(flash);
854*10465441SEvalZero 
855*10465441SEvalZero     cmd_data[0] = SFUD_CMD_JEDEC_ID;
856*10465441SEvalZero     result = spi->wr(spi, cmd_data, sizeof(cmd_data), recv_data, sizeof(recv_data));
857*10465441SEvalZero     if (result == SFUD_SUCCESS) {
858*10465441SEvalZero         flash->chip.mf_id = recv_data[0];
859*10465441SEvalZero         flash->chip.type_id = recv_data[1];
860*10465441SEvalZero         flash->chip.capacity_id = recv_data[2];
861*10465441SEvalZero         SFUD_DEBUG("The flash device manufacturer ID is 0x%02X, memory type ID is 0x%02X, capacity ID is 0x%02X.",
862*10465441SEvalZero                 flash->chip.mf_id, flash->chip.type_id, flash->chip.capacity_id);
863*10465441SEvalZero     } else {
864*10465441SEvalZero         SFUD_INFO("Error: Read flash device JEDEC ID error.");
865*10465441SEvalZero     }
866*10465441SEvalZero 
867*10465441SEvalZero     return result;
868*10465441SEvalZero }
869*10465441SEvalZero 
870*10465441SEvalZero /**
871*10465441SEvalZero  * set the flash write enable or write disable
872*10465441SEvalZero  *
873*10465441SEvalZero  * @param flash flash device
874*10465441SEvalZero  * @param enabled true: enable  false: disable
875*10465441SEvalZero  *
876*10465441SEvalZero  * @return result
877*10465441SEvalZero  */
878*10465441SEvalZero static sfud_err set_write_enabled(const sfud_flash *flash, bool enabled) {
879*10465441SEvalZero     sfud_err result = SFUD_SUCCESS;
880*10465441SEvalZero     uint8_t cmd, register_status;
881*10465441SEvalZero 
882*10465441SEvalZero     SFUD_ASSERT(flash);
883*10465441SEvalZero 
884*10465441SEvalZero     if (enabled) {
885*10465441SEvalZero         cmd = SFUD_CMD_WRITE_ENABLE;
886*10465441SEvalZero     } else {
887*10465441SEvalZero         cmd = SFUD_CMD_WRITE_DISABLE;
888*10465441SEvalZero     }
889*10465441SEvalZero 
890*10465441SEvalZero     result = flash->spi.wr(&flash->spi, &cmd, 1, NULL, 0);
891*10465441SEvalZero 
892*10465441SEvalZero     if (result == SFUD_SUCCESS) {
893*10465441SEvalZero         result = sfud_read_status(flash, &register_status);
894*10465441SEvalZero     }
895*10465441SEvalZero 
896*10465441SEvalZero     if (result == SFUD_SUCCESS) {
897*10465441SEvalZero         if (enabled && (register_status & SFUD_STATUS_REGISTER_WEL) == 0) {
898*10465441SEvalZero             SFUD_INFO("Error: Can't enable write status.");
899*10465441SEvalZero             return SFUD_ERR_WRITE;
900*10465441SEvalZero         } else if (!enabled && (register_status & SFUD_STATUS_REGISTER_WEL) == 1) {
901*10465441SEvalZero             SFUD_INFO("Error: Can't disable write status.");
902*10465441SEvalZero             return SFUD_ERR_WRITE;
903*10465441SEvalZero         }
904*10465441SEvalZero     }
905*10465441SEvalZero 
906*10465441SEvalZero     return result;
907*10465441SEvalZero }
908*10465441SEvalZero 
909*10465441SEvalZero /**
910*10465441SEvalZero  * enable or disable 4-Byte addressing for flash
911*10465441SEvalZero  *
912*10465441SEvalZero  * @note The 4-Byte addressing just supported for the flash capacity which is large then 16MB (256Mb).
913*10465441SEvalZero  *
914*10465441SEvalZero  * @param flash flash device
915*10465441SEvalZero  * @param enabled true: enable   false: disable
916*10465441SEvalZero  *
917*10465441SEvalZero  * @return result
918*10465441SEvalZero  */
919*10465441SEvalZero static sfud_err set_4_byte_address_mode(sfud_flash *flash, bool enabled) {
920*10465441SEvalZero     sfud_err result = SFUD_SUCCESS;
921*10465441SEvalZero     uint8_t cmd;
922*10465441SEvalZero 
923*10465441SEvalZero     SFUD_ASSERT(flash);
924*10465441SEvalZero 
925*10465441SEvalZero     /* set the flash write enable */
926*10465441SEvalZero     result = set_write_enabled(flash, true);
927*10465441SEvalZero     if (result != SFUD_SUCCESS) {
928*10465441SEvalZero         return result;
929*10465441SEvalZero     }
930*10465441SEvalZero 
931*10465441SEvalZero     if (enabled) {
932*10465441SEvalZero         cmd = SFUD_CMD_ENTER_4B_ADDRESS_MODE;
933*10465441SEvalZero     } else {
934*10465441SEvalZero         cmd = SFUD_CMD_EXIT_4B_ADDRESS_MODE;
935*10465441SEvalZero     }
936*10465441SEvalZero 
937*10465441SEvalZero     result = flash->spi.wr(&flash->spi, &cmd, 1, NULL, 0);
938*10465441SEvalZero 
939*10465441SEvalZero     if (result == SFUD_SUCCESS) {
940*10465441SEvalZero         flash->addr_in_4_byte = enabled ? true : false;
941*10465441SEvalZero         SFUD_DEBUG("%s 4-Byte addressing mode success.", enabled ? "Enter" : "Exit");
942*10465441SEvalZero     } else {
943*10465441SEvalZero         SFUD_INFO("Error: %s 4-Byte addressing mode failed.", enabled ? "Enter" : "Exit");
944*10465441SEvalZero     }
945*10465441SEvalZero 
946*10465441SEvalZero     return result;
947*10465441SEvalZero }
948*10465441SEvalZero 
949*10465441SEvalZero /**
950*10465441SEvalZero  * read flash register status
951*10465441SEvalZero  *
952*10465441SEvalZero  * @param flash flash device
953*10465441SEvalZero  * @param status register status
954*10465441SEvalZero  *
955*10465441SEvalZero  * @return result
956*10465441SEvalZero  */
957*10465441SEvalZero sfud_err sfud_read_status(const sfud_flash *flash, uint8_t *status) {
958*10465441SEvalZero     uint8_t cmd = SFUD_CMD_READ_STATUS_REGISTER;
959*10465441SEvalZero 
960*10465441SEvalZero     SFUD_ASSERT(flash);
961*10465441SEvalZero     SFUD_ASSERT(status);
962*10465441SEvalZero 
963*10465441SEvalZero     return flash->spi.wr(&flash->spi, &cmd, 1, status, 1);
964*10465441SEvalZero }
965*10465441SEvalZero 
966*10465441SEvalZero static sfud_err wait_busy(const sfud_flash *flash) {
967*10465441SEvalZero     sfud_err result = SFUD_SUCCESS;
968*10465441SEvalZero     uint8_t status;
969*10465441SEvalZero     size_t retry_times = flash->retry.times;
970*10465441SEvalZero 
971*10465441SEvalZero     SFUD_ASSERT(flash);
972*10465441SEvalZero 
973*10465441SEvalZero     while (true) {
974*10465441SEvalZero         result = sfud_read_status(flash, &status);
975*10465441SEvalZero         if (result == SFUD_SUCCESS && ((status & SFUD_STATUS_REGISTER_BUSY)) == 0) {
976*10465441SEvalZero             break;
977*10465441SEvalZero         }
978*10465441SEvalZero         /* retry counts */
979*10465441SEvalZero         SFUD_RETRY_PROCESS(flash->retry.delay, retry_times, result);
980*10465441SEvalZero     }
981*10465441SEvalZero 
982*10465441SEvalZero     if (result != SFUD_SUCCESS || ((status & SFUD_STATUS_REGISTER_BUSY)) != 0) {
983*10465441SEvalZero         SFUD_INFO("Error: Flash wait busy has an error.");
984*10465441SEvalZero     }
985*10465441SEvalZero 
986*10465441SEvalZero     return result;
987*10465441SEvalZero }
988*10465441SEvalZero 
989*10465441SEvalZero static void make_adress_byte_array(const sfud_flash *flash, uint32_t addr, uint8_t *array) {
990*10465441SEvalZero     uint8_t len, i;
991*10465441SEvalZero 
992*10465441SEvalZero     SFUD_ASSERT(flash);
993*10465441SEvalZero     SFUD_ASSERT(array);
994*10465441SEvalZero 
995*10465441SEvalZero     len = flash->addr_in_4_byte ? 4 : 3;
996*10465441SEvalZero 
997*10465441SEvalZero     for (i = 0; i < len; i++) {
998*10465441SEvalZero         array[i] = (addr >> ((len - (i + 1)) * 8)) & 0xFF;
999*10465441SEvalZero     }
1000*10465441SEvalZero }
1001*10465441SEvalZero 
1002*10465441SEvalZero /**
1003*10465441SEvalZero  * write status register
1004*10465441SEvalZero  *
1005*10465441SEvalZero  * @param flash flash device
1006*10465441SEvalZero  * @param is_volatile true: volatile mode, false: non-volatile mode
1007*10465441SEvalZero  * @param status register status
1008*10465441SEvalZero  *
1009*10465441SEvalZero  * @return result
1010*10465441SEvalZero  */
1011*10465441SEvalZero sfud_err sfud_write_status(const sfud_flash *flash, bool is_volatile, uint8_t status) {
1012*10465441SEvalZero     sfud_err result = SFUD_SUCCESS;
1013*10465441SEvalZero     const sfud_spi *spi = &flash->spi;
1014*10465441SEvalZero     uint8_t cmd_data[2];
1015*10465441SEvalZero 
1016*10465441SEvalZero     SFUD_ASSERT(flash);
1017*10465441SEvalZero 
1018*10465441SEvalZero     if (is_volatile) {
1019*10465441SEvalZero         cmd_data[0] = SFUD_VOLATILE_SR_WRITE_ENABLE;
1020*10465441SEvalZero         result = spi->wr(spi, cmd_data, 1, NULL, 0);
1021*10465441SEvalZero     } else {
1022*10465441SEvalZero         result = set_write_enabled(flash, true);
1023*10465441SEvalZero     }
1024*10465441SEvalZero 
1025*10465441SEvalZero     if (result == SFUD_SUCCESS) {
1026*10465441SEvalZero         cmd_data[0] = SFUD_CMD_WRITE_STATUS_REGISTER;
1027*10465441SEvalZero         cmd_data[1] = status;
1028*10465441SEvalZero         result = spi->wr(spi, cmd_data, 2, NULL, 0);
1029*10465441SEvalZero     }
1030*10465441SEvalZero 
1031*10465441SEvalZero     if (result != SFUD_SUCCESS) {
1032*10465441SEvalZero         SFUD_INFO("Error: Write_status register failed.");
1033*10465441SEvalZero     }
1034*10465441SEvalZero 
1035*10465441SEvalZero     return result;
1036*10465441SEvalZero }
1037