1
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
37
38
42
43
47
48
57
58
80
81
82
83
84
87
88
89
90
91
92
93
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
149
150
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
196
197
198
199
200
201
202
203
204
205
206
207
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
258
261
264
267
270
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
305
306
307
309
310
311
314
317
320
323
326
329
330
331
332
333
336
339
342
345
348
351
352
353
354
355
356
362
363
364
365
366
367
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
401
404
407
410
413
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
440
441
442
444
445
446
447
448
449
450
451
452
453
454
455
456
457
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
/* ... */
#include <stdbool.h>
#include <assert.h>
#include "string.h"
#include "sdkconfig.h"
#include "esp_err.h"
#include "esp_log.h"
#include "esp_rom_gpio.h"
#include "esp_rom_efuse.h"
#include "esp32/rom/spi_flash.h"
#include "esp32/rom/cache.h"
#include "soc/gpio_periph.h"
#include "soc/efuse_reg.h"
#include "soc/spi_reg.h"
#include "soc/dport_reg.h"
#include "soc/soc_caps.h"
#include "soc/soc_pins.h"
#include "soc/chip_revision.h"
#include "hal/efuse_hal.h"
#include "hal/gpio_hal.h"
#include "flash_qio_mode.h"
#include "bootloader_common.h"
#include "bootloader_flash_config.h"
#include "bootloader_flash_priv.h"
#include "bootloader_init.h"24 includes
#define FLASH_CLK_IO MSPI_IOMUX_PIN_NUM_CLK
#define FLASH_CS_IO MSPI_IOMUX_PIN_NUM_CS0
#define FLASH_SPIQ_IO MSPI_IOMUX_PIN_NUM_MISO
#define FLASH_SPID_IO MSPI_IOMUX_PIN_NUM_MOSI
#define FLASH_SPIWP_IO MSPI_IOMUX_PIN_NUM_WP
#define FLASH_SPIHD_IO MSPI_IOMUX_PIN_NUM_HD6 defines
void bootloader_flash_update_id(void)
{
g_rom_flashchip.device_id = bootloader_read_flash_id();
}{ ... }
void bootloader_flash_update_size(uint32_t size)
{
g_rom_flashchip.chip_size = size;
}{ ... }
void IRAM_ATTR bootloader_flash_cs_timing_config(void)
{
SET_PERI_REG_MASK(SPI_USER_REG(0), SPI_CS_HOLD_M | SPI_CS_SETUP_M);
SET_PERI_REG_BITS(SPI_CTRL2_REG(0), SPI_HOLD_TIME_V, 1, SPI_HOLD_TIME_S);
SET_PERI_REG_BITS(SPI_CTRL2_REG(0), SPI_SETUP_TIME_V, 0, SPI_SETUP_TIME_S);
SET_PERI_REG_MASK(SPI_USER_REG(1), SPI_CS_HOLD_M | SPI_CS_SETUP_M);
SET_PERI_REG_BITS(SPI_CTRL2_REG(1), SPI_HOLD_TIME_V, 1, SPI_HOLD_TIME_S);
SET_PERI_REG_BITS(SPI_CTRL2_REG(1), SPI_SETUP_TIME_V, 0, SPI_SETUP_TIME_S);
}{ ... }
void IRAM_ATTR bootloader_flash_clock_config(const esp_image_header_t* pfhdr)
{
uint32_t spi_clk_div = 0;
switch (pfhdr->spi_speed) {
case ESP_IMAGE_SPI_SPEED_DIV_1:
spi_clk_div = 1;
break;...
case ESP_IMAGE_SPI_SPEED_DIV_2:
spi_clk_div = 2;
break;...
case ESP_IMAGE_SPI_SPEED_DIV_3:
spi_clk_div = 3;
break;...
case ESP_IMAGE_SPI_SPEED_DIV_4:
spi_clk_div = 4;
break;...
default:
break;...
}{...}
esp_rom_spiflash_config_clk(spi_clk_div, 0);
esp_rom_spiflash_config_clk(spi_clk_div, 1);
}{ ... }
void IRAM_ATTR bootloader_flash_gpio_config(const esp_image_header_t* pfhdr)
{
uint32_t drv = 2;
if (pfhdr->spi_speed == ESP_IMAGE_SPI_SPEED_DIV_1) {
drv = 3;
}{...}
uint32_t pkg_ver = bootloader_common_get_chip_ver_pkg();
if (pkg_ver == EFUSE_RD_CHIP_VER_PKG_ESP32D2WDQ5 ||
pkg_ver == EFUSE_RD_CHIP_VER_PKG_ESP32U4WDH ||
pkg_ver == EFUSE_RD_CHIP_VER_PKG_ESP32PICOD4 ||
pkg_ver == EFUSE_RD_CHIP_VER_PKG_ESP32PICOV302) {
gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_SD_CLK_U, FUNC_SD_CLK_SPICLK);
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CLK_U, FUN_DRV, drv, FUN_DRV_S);
}{...} else {
const uint32_t spiconfig = esp_rom_efuse_get_flash_gpio_info();
if (spiconfig == ESP_ROM_EFUSE_FLASH_DEFAULT_SPI) {
esp_rom_gpio_connect_out_signal(FLASH_CS_IO, SPICS0_OUT_IDX, 0, 0);
esp_rom_gpio_connect_out_signal(FLASH_SPIQ_IO, SPIQ_OUT_IDX, 0, 0);
esp_rom_gpio_connect_in_signal(FLASH_SPIQ_IO, SPIQ_IN_IDX, 0);
esp_rom_gpio_connect_out_signal(FLASH_SPID_IO, SPID_OUT_IDX, 0, 0);
esp_rom_gpio_connect_in_signal(FLASH_SPID_IO, SPID_IN_IDX, 0);
esp_rom_gpio_connect_out_signal(FLASH_SPIWP_IO, SPIWP_OUT_IDX, 0, 0);
esp_rom_gpio_connect_in_signal(FLASH_SPIWP_IO, SPIWP_IN_IDX, 0);
esp_rom_gpio_connect_out_signal(FLASH_SPIHD_IO, SPIHD_OUT_IDX, 0, 0);
esp_rom_gpio_connect_in_signal(FLASH_SPIHD_IO, SPIHD_IN_IDX, 0);
gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_SD_DATA0_U, PIN_FUNC_GPIO);
gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_SD_DATA1_U, PIN_FUNC_GPIO);
gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_SD_DATA2_U, PIN_FUNC_GPIO);
gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_SD_DATA3_U, PIN_FUNC_GPIO);
gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_SD_CMD_U, PIN_FUNC_GPIO);
gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_SD_CLK_U, FUNC_SD_CLK_SPICLK);
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CLK_U, FUN_DRV, drv, FUN_DRV_S);
uint32_t flash_id = g_rom_flashchip.device_id;
if (flash_id == FLASH_ID_GD25LQ32C) {
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_DATA0_U, FUN_DRV, 3, FUN_DRV_S);
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_DATA1_U, FUN_DRV, 3, FUN_DRV_S);
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_DATA2_U, FUN_DRV, 3, FUN_DRV_S);
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_DATA3_U, FUN_DRV, 3, FUN_DRV_S);
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CMD_U, FUN_DRV, 3, FUN_DRV_S);
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CLK_U, FUN_DRV, 3, FUN_DRV_S);
}{...}
}{...}
}{...}
}{ ... }
void IRAM_ATTR bootloader_flash_dummy_config(const esp_image_header_t* pfhdr)
{
int spi_cache_dummy = 0;
uint32_t modebit = READ_PERI_REG(SPI_CTRL_REG(0));
if (modebit & SPI_FASTRD_MODE) {
if (modebit & SPI_FREAD_QIO) {
spi_cache_dummy = SPI0_R_QIO_DUMMY_CYCLELEN;
}{...} else if (modebit & SPI_FREAD_DIO) {
spi_cache_dummy = SPI0_R_DIO_DUMMY_CYCLELEN;
SET_PERI_REG_BITS(SPI_USER1_REG(0), SPI_USR_ADDR_BITLEN_V, SPI0_R_DIO_ADDR_BITSLEN, SPI_USR_ADDR_BITLEN_S);
}{...} else if(modebit & (SPI_FREAD_QUAD | SPI_FREAD_DUAL)) {
spi_cache_dummy = SPI0_R_FAST_DUMMY_CYCLELEN;
}{...}
}{...}
switch (pfhdr->spi_speed) {
case ESP_IMAGE_SPI_SPEED_DIV_1:
g_rom_spiflash_dummy_len_plus[0] = ESP_ROM_SPIFLASH_DUMMY_LEN_PLUS_80M;
g_rom_spiflash_dummy_len_plus[1] = ESP_ROM_SPIFLASH_DUMMY_LEN_PLUS_80M;
break;...
case ESP_IMAGE_SPI_SPEED_DIV_2:
g_rom_spiflash_dummy_len_plus[0] = ESP_ROM_SPIFLASH_DUMMY_LEN_PLUS_40M;
g_rom_spiflash_dummy_len_plus[1] = ESP_ROM_SPIFLASH_DUMMY_LEN_PLUS_40M;
break;...
case ESP_IMAGE_SPI_SPEED_DIV_3:
case ESP_IMAGE_SPI_SPEED_DIV_4:
g_rom_spiflash_dummy_len_plus[0] = ESP_ROM_SPIFLASH_DUMMY_LEN_PLUS_20M;
g_rom_spiflash_dummy_len_plus[1] = ESP_ROM_SPIFLASH_DUMMY_LEN_PLUS_20M;
break;...
default:
break;...
}{...}
SET_PERI_REG_BITS(SPI_USER1_REG(0), SPI_USR_DUMMY_CYCLELEN_V, spi_cache_dummy + g_rom_spiflash_dummy_len_plus[0],
SPI_USR_DUMMY_CYCLELEN_S);
}{ ... }
#define ESP32_D2WD_WP_GPIO 7
#define ESP32_PICO_V3_GPIO 18
int bootloader_flash_get_wp_pin(void)
{
#if CONFIG_BOOTLOADER_SPI_CUSTOM_WP_PIN
return CONFIG_BOOTLOADER_SPI_WP_PIN;
#elif CONFIG_SPIRAM_CUSTOM_SPIWP_SD3_PIN
return CONFIG_SPIRAM_SPIWP_SD3_PIN;
#else
switch(bootloader_common_get_chip_ver_pkg()) {
case EFUSE_RD_CHIP_VER_PKG_ESP32U4WDH:
case EFUSE_RD_CHIP_VER_PKG_ESP32D2WDQ5:
return ESP32_D2WD_WP_GPIO;...
case EFUSE_RD_CHIP_VER_PKG_ESP32PICOD4:
return !ESP_CHIP_REV_ABOVE(efuse_hal_chip_revision(), 300) ? ESP32_D2WD_WP_GPIO : ESP32_PICO_V3_GPIO;...
case EFUSE_RD_CHIP_VER_PKG_ESP32PICOV302:
return ESP32_PICO_V3_GPIO;...
default:
return MSPI_IOMUX_PIN_NUM_WP;...
}{...}
#endif/* ... */
}{ ... }
static const char *TAG = "boot.esp32";
void bootloader_configure_spi_pins(int drv)
{
uint32_t pkg_ver = bootloader_common_get_chip_ver_pkg();
if (pkg_ver == EFUSE_RD_CHIP_VER_PKG_ESP32D2WDQ5 ||
pkg_ver == EFUSE_RD_CHIP_VER_PKG_ESP32U4WDH ||
pkg_ver == EFUSE_RD_CHIP_VER_PKG_ESP32PICOD4 ||
pkg_ver == EFUSE_RD_CHIP_VER_PKG_ESP32PICOV302) {
gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_SD_CLK_U, FUNC_SD_CLK_SPICLK);
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CLK_U, FUN_DRV, drv, FUN_DRV_S);
}{...} else {
const uint32_t spiconfig = esp_rom_efuse_get_flash_gpio_info();
if (spiconfig == ESP_ROM_EFUSE_FLASH_DEFAULT_SPI) {
esp_rom_gpio_connect_out_signal(FLASH_CS_IO, SPICS0_OUT_IDX, 0, 0);
esp_rom_gpio_connect_out_signal(FLASH_SPIQ_IO, SPIQ_OUT_IDX, 0, 0);
esp_rom_gpio_connect_in_signal(FLASH_SPIQ_IO, SPIQ_IN_IDX, 0);
esp_rom_gpio_connect_out_signal(FLASH_SPID_IO, SPID_OUT_IDX, 0, 0);
esp_rom_gpio_connect_in_signal(FLASH_SPID_IO, SPID_IN_IDX, 0);
esp_rom_gpio_connect_out_signal(FLASH_SPIWP_IO, SPIWP_OUT_IDX, 0, 0);
esp_rom_gpio_connect_in_signal(FLASH_SPIWP_IO, SPIWP_IN_IDX, 0);
esp_rom_gpio_connect_out_signal(FLASH_SPIHD_IO, SPIHD_OUT_IDX, 0, 0);
esp_rom_gpio_connect_in_signal(FLASH_SPIHD_IO, SPIHD_IN_IDX, 0);
gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_SD_DATA0_U, PIN_FUNC_GPIO);
gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_SD_DATA1_U, PIN_FUNC_GPIO);
gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_SD_DATA2_U, PIN_FUNC_GPIO);
gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_SD_DATA3_U, PIN_FUNC_GPIO);
gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_SD_CMD_U, PIN_FUNC_GPIO);
gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_SD_CLK_U, FUNC_SD_CLK_SPICLK);
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CLK_U, FUN_DRV, drv, FUN_DRV_S);
#if CONFIG_SPIRAM_TYPE_ESPPSRAM32 || CONFIG_SPIRAM_TYPE_ESPPSRAM64
uint32_t flash_id = g_rom_flashchip.device_id;
if (flash_id == FLASH_ID_GD25LQ32C) {
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_DATA0_U, FUN_DRV, 3, FUN_DRV_S);
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_DATA1_U, FUN_DRV, 3, FUN_DRV_S);
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_DATA2_U, FUN_DRV, 3, FUN_DRV_S);
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_DATA3_U, FUN_DRV, 3, FUN_DRV_S);
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CMD_U, FUN_DRV, 3, FUN_DRV_S);
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CLK_U, FUN_DRV, 3, FUN_DRV_S);
}{...}
#endif/* ... */
}{...}
}{...}
}{ ... }
static void update_flash_config(const esp_image_header_t *bootloader_hdr)
{
uint32_t size;
switch (bootloader_hdr->spi_size) {
case ESP_IMAGE_FLASH_SIZE_1MB:
size = 1;
break;...
case ESP_IMAGE_FLASH_SIZE_2MB:
size = 2;
break;...
case ESP_IMAGE_FLASH_SIZE_4MB:
size = 4;
break;...
case ESP_IMAGE_FLASH_SIZE_8MB:
size = 8;
break;...
case ESP_IMAGE_FLASH_SIZE_16MB:
size = 16;
break;...
default:
size = 2;...
}{...}
esp_rom_spiflash_config_param(g_rom_flashchip.device_id, size * 0x100000, 0x10000, 0x1000, 0x100, 0xffff);
}{ ... }
static void print_flash_info(const esp_image_header_t *bootloader_hdr)
{
ESP_EARLY_LOGD(TAG, "magic %02x", bootloader_hdr->magic);
ESP_EARLY_LOGD(TAG, "segments %02x", bootloader_hdr->segment_count);
ESP_EARLY_LOGD(TAG, "spi_mode %02x", bootloader_hdr->spi_mode);
ESP_EARLY_LOGD(TAG, "spi_speed %02x", bootloader_hdr->spi_speed);
ESP_EARLY_LOGD(TAG, "spi_size %02x", bootloader_hdr->spi_size);
const char *str;
switch (bootloader_hdr->spi_speed) {
case ESP_IMAGE_SPI_SPEED_DIV_2:
str = "40MHz";
break;...
case ESP_IMAGE_SPI_SPEED_DIV_3:
str = "26.7MHz";
break;...
case ESP_IMAGE_SPI_SPEED_DIV_4:
str = "20MHz";
break;...
case ESP_IMAGE_SPI_SPEED_DIV_1:
str = "80MHz";
break;...
default:
str = "20MHz";
break;...
}{...}
ESP_EARLY_LOGI(TAG, "SPI Speed : %s", str);
/* ... */
esp_rom_spiflash_read_mode_t spi_mode = bootloader_flash_get_spi_mode();
switch (spi_mode) {
case ESP_ROM_SPIFLASH_QIO_MODE:
str = "QIO";
break;...
case ESP_ROM_SPIFLASH_QOUT_MODE:
str = "QOUT";
break;...
case ESP_ROM_SPIFLASH_DIO_MODE:
str = "DIO";
break;...
case ESP_ROM_SPIFLASH_DOUT_MODE:
str = "DOUT";
break;...
case ESP_ROM_SPIFLASH_FASTRD_MODE:
str = "FAST READ";
break;...
default:
str = "SLOW READ";
break;...
}{...}
ESP_EARLY_LOGI(TAG, "SPI Mode : %s", str);
switch (bootloader_hdr->spi_size) {
case ESP_IMAGE_FLASH_SIZE_1MB:
str = "1MB";
break;...
case ESP_IMAGE_FLASH_SIZE_2MB:
str = "2MB";
break;...
case ESP_IMAGE_FLASH_SIZE_4MB:
str = "4MB";
break;...
case ESP_IMAGE_FLASH_SIZE_8MB:
str = "8MB";
break;...
case ESP_IMAGE_FLASH_SIZE_16MB:
str = "16MB";
break;...
default:
str = "2MB";
break;...
}{...}
ESP_EARLY_LOGI(TAG, "SPI Flash Size : %s", str);
}{ ... }
static void IRAM_ATTR bootloader_init_flash_configure(void)
{
bootloader_flash_gpio_config(&bootloader_image_hdr);
bootloader_flash_dummy_config(&bootloader_image_hdr);
bootloader_flash_cs_timing_config();
}{ ... }
esp_err_t bootloader_init_spi_flash(void)
{
bootloader_init_flash_configure();
#ifndef CONFIG_SPI_FLASH_ROM_DRIVER_PATCH
const uint32_t spiconfig = esp_rom_efuse_get_flash_gpio_info();
if (spiconfig != ESP_ROM_EFUSE_FLASH_DEFAULT_SPI && spiconfig != ESP_ROM_EFUSE_FLASH_DEFAULT_HSPI) {
ESP_EARLY_LOGE(TAG, "SPI flash pins are overridden. Enable CONFIG_SPI_FLASH_ROM_DRIVER_PATCH in menuconfig");
return ESP_FAIL;
}{...}
#endif/* ... */
bootloader_flash_unlock();
#if CONFIG_ESPTOOLPY_FLASHMODE_QIO || CONFIG_ESPTOOLPY_FLASHMODE_QOUT
bootloader_enable_qio_mode();
#endif
print_flash_info(&bootloader_image_hdr);
Cache_Read_Disable(0);
update_flash_config(&bootloader_image_hdr);
Cache_Flush(0);
Cache_Read_Enable(0);
bootloader_enable_wp();
return ESP_OK;
}{ ... }
#if CONFIG_APP_BUILD_TYPE_RAM && !CONFIG_APP_BUILD_TYPE_PURE_RAM_APP
static void bootloader_flash_set_spi_mode(const esp_image_header_t* pfhdr)
{
esp_rom_spiflash_read_mode_t mode;
switch(pfhdr->spi_mode) {
case ESP_IMAGE_SPI_MODE_QIO:
mode = ESP_ROM_SPIFLASH_QIO_MODE;
break;...
case ESP_IMAGE_SPI_MODE_QOUT:
mode = ESP_ROM_SPIFLASH_QOUT_MODE;
break;...
case ESP_IMAGE_SPI_MODE_DIO:
mode = ESP_ROM_SPIFLASH_DIO_MODE;
break;...
case ESP_IMAGE_SPI_MODE_FAST_READ:
mode = ESP_ROM_SPIFLASH_FASTRD_MODE;
break;...
case ESP_IMAGE_SPI_MODE_SLOW_READ:
mode = ESP_ROM_SPIFLASH_SLOWRD_MODE;
break;...
default:
mode = ESP_ROM_SPIFLASH_DIO_MODE;...
}{...}
esp_rom_spiflash_config_readmode(mode);
}{...}
void bootloader_flash_hardware_init(void)
{
esp_rom_spiflash_attach(esp_rom_efuse_get_flash_gpio_info(), false);
Cache_Read_Disable(0);
#if !CONFIG_FREERTOS_UNICORE
Cache_Read_Disable(1);
#endif
Cache_Flush(0);
#if !CONFIG_FREERTOS_UNICORE
Cache_Flush(1);
#endif
mmu_init(0);
#if !CONFIG_FREERTOS_UNICORE
/* ... */
DPORT_REG_SET_BIT(DPORT_APP_CACHE_CTRL1_REG, DPORT_APP_CACHE_MMU_IA_CLR);
mmu_init(1);
DPORT_REG_CLR_BIT(DPORT_APP_CACHE_CTRL1_REG, DPORT_APP_CACHE_MMU_IA_CLR);/* ... */
#endif
/* ... */
DPORT_REG_CLR_BIT(DPORT_PRO_CACHE_CTRL1_REG, DPORT_PRO_CACHE_MASK_DROM0);
#if !CONFIG_FREERTOS_UNICORE
DPORT_REG_CLR_BIT(DPORT_APP_CACHE_CTRL1_REG, DPORT_APP_CACHE_MASK_DROM0);
#endif
bootloader_flash_update_id();
esp_err_t ret = bootloader_flash_xmc_startup();
assert(ret == ESP_OK);
esp_image_header_t WORD_ALIGNED_ATTR hdr = {
.spi_mode = ESP_IMAGE_SPI_MODE_DIO,
.spi_speed = ESP_IMAGE_SPI_SPEED_DIV_2,
.spi_size = ESP_IMAGE_FLASH_SIZE_2MB,
}{...};
bootloader_flash_set_spi_mode(&hdr);
bootloader_flash_clock_config(&hdr);
bootloader_flash_gpio_config(&hdr);
bootloader_flash_dummy_config(&hdr);
bootloader_flash_cs_timing_config();
bootloader_flash_unlock();
Cache_Read_Disable(0);
update_flash_config(&hdr);
Cache_Flush(0);
Cache_Read_Enable(0);
bootloader_enable_wp();
}{...}
/* ... */#endif