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, ®ister_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