bootloader_start.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596
  1. // Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #include <string.h>
  15. #include <stdint.h>
  16. #include <limits.h>
  17. #include "esp_attr.h"
  18. #include "esp_log.h"
  19. #include "rom/cache.h"
  20. #include "rom/ets_sys.h"
  21. #include "rom/spi_flash.h"
  22. #include "rom/crc.h"
  23. #include "rom/rtc.h"
  24. #include "soc/soc.h"
  25. #include "soc/cpu.h"
  26. #include "soc/dport_reg.h"
  27. #include "soc/io_mux_reg.h"
  28. #include "soc/efuse_reg.h"
  29. #include "soc/rtc_cntl_reg.h"
  30. #include "soc/timer_group_reg.h"
  31. #include "sdkconfig.h"
  32. #include "bootloader_config.h"
  33. extern int _bss_start;
  34. extern int _bss_end;
  35. static const char* TAG = "boot";
  36. /*
  37. We arrive here after the bootloader finished loading the program from flash. The hardware is mostly uninitialized,
  38. flash cache is down and the app CPU is in reset. We do have a stack, so we can do the initialization in C.
  39. */
  40. // TODO: make a nice header file for ROM functions instead of adding externs all over the place
  41. extern void Cache_Flush(int);
  42. void bootloader_main();
  43. void unpack_load_app(const esp_partition_pos_t *app_node);
  44. void print_flash_info(const esp_image_header_t* pfhdr);
  45. void IRAM_ATTR set_cache_and_start_app(uint32_t drom_addr,
  46. uint32_t drom_load_addr,
  47. uint32_t drom_size,
  48. uint32_t irom_addr,
  49. uint32_t irom_load_addr,
  50. uint32_t irom_size,
  51. uint32_t entry_addr);
  52. static void update_flash_config(const esp_image_header_t* pfhdr);
  53. void IRAM_ATTR call_start_cpu0()
  54. {
  55. cpu_configure_region_protection();
  56. //Clear bss
  57. memset(&_bss_start, 0, (&_bss_end - &_bss_start) * sizeof(_bss_start));
  58. /* completely reset MMU for both CPUs
  59. (in case serial bootloader was running) */
  60. Cache_Read_Disable(0);
  61. Cache_Read_Disable(1);
  62. Cache_Flush(0);
  63. Cache_Flush(1);
  64. mmu_init(0);
  65. REG_SET_BIT(DPORT_APP_CACHE_CTRL1_REG, DPORT_APP_CACHE_MMU_IA_CLR);
  66. mmu_init(1);
  67. REG_CLR_BIT(DPORT_APP_CACHE_CTRL1_REG, DPORT_APP_CACHE_MMU_IA_CLR);
  68. /* (above steps probably unnecessary for most serial bootloader
  69. usage, all that's absolutely needed is that we unmask DROM0
  70. cache on the following two lines - normal ROM boot exits with
  71. DROM0 cache unmasked, but serial bootloader exits with it
  72. masked. However can't hurt to be thorough and reset
  73. everything.)
  74. The lines which manipulate DPORT_APP_CACHE_MMU_IA_CLR bit are
  75. necessary to work around a hardware bug.
  76. */
  77. REG_CLR_BIT(DPORT_PRO_CACHE_CTRL1_REG, DPORT_PRO_CACHE_MASK_DROM0);
  78. REG_CLR_BIT(DPORT_APP_CACHE_CTRL1_REG, DPORT_APP_CACHE_MASK_DROM0);
  79. bootloader_main();
  80. }
  81. /**
  82. * @function : get_bin_len
  83. * @description: get bin's length
  84. *
  85. * @inputs: pos bin locate address in flash
  86. * @return: uint32 length of bin,if bin MAGIC error return 0
  87. */
  88. uint32_t get_bin_len(uint32_t pos)
  89. {
  90. uint32_t len = 8 + 16;
  91. uint8_t i;
  92. ESP_LOGD(TAG, "pos %d %x",pos,*(uint8_t *)pos);
  93. if(0xE9 != *(uint8_t *)pos) {
  94. return 0;
  95. }
  96. for (i = 0; i < *(uint8_t *)(pos + 1); i++) {
  97. len += *(uint32_t *)(pos + len + 4) + 8;
  98. }
  99. if (len % 16 != 0) {
  100. len = (len / 16 + 1) * 16;
  101. } else {
  102. len += 16;
  103. }
  104. ESP_LOGD(TAG, "bin length = %d", len);
  105. return len;
  106. }
  107. /**
  108. * @function : boot_cache_redirect
  109. * @description: Configure several pages in flash map so that `size` bytes
  110. * starting at `pos` are mapped to 0x3f400000.
  111. * This sets up mapping only for PRO CPU.
  112. *
  113. * @inputs: pos address in flash
  114. * size size of the area to map, in bytes
  115. */
  116. void boot_cache_redirect( uint32_t pos, size_t size )
  117. {
  118. uint32_t pos_aligned = pos & 0xffff0000;
  119. uint32_t count = (size + 0xffff) / 0x10000;
  120. Cache_Read_Disable( 0 );
  121. Cache_Flush( 0 );
  122. ESP_LOGD(TAG, "mmu set paddr=%08x count=%d", pos_aligned, count );
  123. cache_flash_mmu_set( 0, 0, 0x3f400000, pos_aligned, 64, count );
  124. Cache_Read_Enable( 0 );
  125. }
  126. /**
  127. * @function : load_partition_table
  128. * @description: Parse partition table, get useful data such as location of
  129. * OTA info sector, factory app sector, and test app sector.
  130. *
  131. * @inputs: bs bootloader state structure used to save the data
  132. * addr address of partition table in flash
  133. * @return: return true, if the partition table is loaded (and MD5 checksum is valid)
  134. *
  135. */
  136. bool load_partition_table(bootloader_state_t* bs, uint32_t addr)
  137. {
  138. esp_partition_info_t partition;
  139. uint32_t end = addr + 0x1000;
  140. int index = 0;
  141. char *partition_usage;
  142. ESP_LOGI(TAG, "Partition Table:");
  143. ESP_LOGI(TAG, "## Label Usage Type ST Offset Length");
  144. while (addr < end) {
  145. ESP_LOGD(TAG, "load partition table entry from %x(%08x)", addr, MEM_CACHE(addr));
  146. memcpy(&partition, MEM_CACHE(addr), sizeof(partition));
  147. ESP_LOGD(TAG, "type=%x subtype=%x", partition.type, partition.subtype);
  148. partition_usage = "unknown";
  149. if (partition.magic == ESP_PARTITION_MAGIC) { /* valid partition definition */
  150. switch(partition.type) {
  151. case PART_TYPE_APP: /* app partition */
  152. switch(partition.subtype) {
  153. case PART_SUBTYPE_FACTORY: /* factory binary */
  154. bs->factory = partition.pos;
  155. partition_usage = "factory app";
  156. break;
  157. case PART_SUBTYPE_TEST: /* test binary */
  158. bs->test = partition.pos;
  159. partition_usage = "test app";
  160. break;
  161. default:
  162. /* OTA binary */
  163. if ((partition.subtype & ~PART_SUBTYPE_OTA_MASK) == PART_SUBTYPE_OTA_FLAG) {
  164. bs->ota[partition.subtype & PART_SUBTYPE_OTA_MASK] = partition.pos;
  165. ++bs->app_count;
  166. partition_usage = "OTA app";
  167. }
  168. else {
  169. partition_usage = "Unknown app";
  170. }
  171. break;
  172. }
  173. break; /* PART_TYPE_APP */
  174. case PART_TYPE_DATA: /* data partition */
  175. switch(partition.subtype) {
  176. case PART_SUBTYPE_DATA_OTA: /* ota data */
  177. bs->ota_info = partition.pos;
  178. partition_usage = "OTA data";
  179. break;
  180. case PART_SUBTYPE_DATA_RF:
  181. partition_usage = "RF data";
  182. break;
  183. case PART_SUBTYPE_DATA_WIFI:
  184. partition_usage = "WiFi data";
  185. break;
  186. default:
  187. partition_usage = "Unknown data";
  188. break;
  189. }
  190. break; /* PARTITION_USAGE_DATA */
  191. default: /* other partition type */
  192. break;
  193. }
  194. }
  195. /* invalid partition magic number */
  196. else {
  197. break; /* todo: validate md5 */
  198. }
  199. /* print partition type info */
  200. ESP_LOGI(TAG, "%2d %-16s %-16s %02x %02x %08x %08x", index, partition.label, partition_usage,
  201. partition.type, partition.subtype,
  202. partition.pos.offset, partition.pos.size);
  203. index++;
  204. addr += sizeof(partition);
  205. }
  206. ESP_LOGI(TAG,"End of partition table");
  207. return true;
  208. }
  209. static uint32_t ota_select_crc(const esp_ota_select_entry_t *s)
  210. {
  211. return crc32_le(UINT32_MAX, (uint8_t*)&s->ota_seq, 4);
  212. }
  213. static bool ota_select_valid(const esp_ota_select_entry_t *s)
  214. {
  215. return s->ota_seq != UINT32_MAX && s->crc == ota_select_crc(s);
  216. }
  217. /**
  218. * @function : bootloader_main
  219. * @description: entry function of 2nd bootloader
  220. *
  221. * @inputs: void
  222. */
  223. void bootloader_main()
  224. {
  225. ESP_LOGI(TAG, "Espressif ESP32 2nd stage bootloader v. %s", BOOT_VERSION);
  226. esp_image_header_t fhdr;
  227. bootloader_state_t bs;
  228. SpiFlashOpResult spiRet1,spiRet2;
  229. esp_ota_select_entry_t sa,sb;
  230. memset(&bs, 0, sizeof(bs));
  231. ESP_LOGI(TAG, "compile time " __TIME__ );
  232. /* disable watch dog here */
  233. REG_CLR_BIT( RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_FLASHBOOT_MOD_EN );
  234. REG_CLR_BIT( TIMG_WDTCONFIG0_REG(0), TIMG_WDT_FLASHBOOT_MOD_EN );
  235. SPIUnlock();
  236. /*register first sector in drom0 page 0 */
  237. boot_cache_redirect( 0, 0x5000 );
  238. memcpy((unsigned int *) &fhdr, MEM_CACHE(0x1000), sizeof(esp_image_header_t) );
  239. print_flash_info(&fhdr);
  240. update_flash_config(&fhdr);
  241. if (!load_partition_table(&bs, ESP_PARTITION_TABLE_ADDR)) {
  242. ESP_LOGE(TAG, "load partition table error!");
  243. return;
  244. }
  245. esp_partition_pos_t load_part_pos;
  246. if (bs.ota_info.offset != 0) { // check if partition table has OTA info partition
  247. //ESP_LOGE("OTA info sector handling is not implemented");
  248. boot_cache_redirect(bs.ota_info.offset, bs.ota_info.size );
  249. memcpy(&sa,MEM_CACHE(bs.ota_info.offset & 0x0000ffff),sizeof(sa));
  250. memcpy(&sb,MEM_CACHE((bs.ota_info.offset + 0x1000)&0x0000ffff) ,sizeof(sb));
  251. if(sa.ota_seq == 0xFFFFFFFF && sb.ota_seq == 0xFFFFFFFF) {
  252. // init status flash
  253. load_part_pos = bs.ota[0];
  254. sa.ota_seq = 0x01;
  255. sa.crc = ota_select_crc(&sa);
  256. sb.ota_seq = 0x00;
  257. sb.crc = ota_select_crc(&sb);
  258. Cache_Read_Disable(0);
  259. spiRet1 = SPIEraseSector(bs.ota_info.offset/0x1000);
  260. spiRet2 = SPIEraseSector(bs.ota_info.offset/0x1000+1);
  261. if (spiRet1 != SPI_FLASH_RESULT_OK || spiRet2 != SPI_FLASH_RESULT_OK ) {
  262. ESP_LOGE(TAG, SPI_ERROR_LOG);
  263. return;
  264. }
  265. spiRet1 = SPIWrite(bs.ota_info.offset,(uint32_t *)&sa,sizeof(esp_ota_select_entry_t));
  266. spiRet2 = SPIWrite(bs.ota_info.offset + 0x1000,(uint32_t *)&sb,sizeof(esp_ota_select_entry_t));
  267. if (spiRet1 != SPI_FLASH_RESULT_OK || spiRet2 != SPI_FLASH_RESULT_OK ) {
  268. ESP_LOGE(TAG, SPI_ERROR_LOG);
  269. return;
  270. }
  271. Cache_Read_Enable(0);
  272. //TODO:write data in ota info
  273. } else {
  274. if(ota_select_valid(&sa) && ota_select_valid(&sb)) {
  275. load_part_pos = bs.ota[(((sa.ota_seq > sb.ota_seq)?sa.ota_seq:sb.ota_seq) - 1)%bs.app_count];
  276. }else if(ota_select_valid(&sa)) {
  277. load_part_pos = bs.ota[(sa.ota_seq - 1) % bs.app_count];
  278. }else if(ota_select_valid(&sb)) {
  279. load_part_pos = bs.ota[(sb.ota_seq - 1) % bs.app_count];
  280. }else {
  281. ESP_LOGE(TAG, "ota data partition info error");
  282. return;
  283. }
  284. }
  285. } else if (bs.factory.offset != 0) { // otherwise, look for factory app partition
  286. load_part_pos = bs.factory;
  287. } else if (bs.test.offset != 0) { // otherwise, look for test app parition
  288. load_part_pos = bs.test;
  289. } else { // nothing to load, bail out
  290. ESP_LOGE(TAG, "nothing to load");
  291. return;
  292. }
  293. ESP_LOGI(TAG, "Loading app partition at offset %08x", load_part_pos);
  294. if(fhdr.secure_boot_flag == 0x01) {
  295. /* protect the 2nd_boot */
  296. if(false == secure_boot()){
  297. ESP_LOGE(TAG, "secure boot failed");
  298. return;
  299. }
  300. }
  301. if(fhdr.encrypt_flag == 0x01) {
  302. /* encrypt flash */
  303. if (false == flash_encrypt(&bs)) {
  304. ESP_LOGE(TAG, "flash encrypt failed");
  305. return;
  306. }
  307. }
  308. // copy sections to RAM, set up caches, and start application
  309. unpack_load_app(&load_part_pos);
  310. }
  311. void unpack_load_app(const esp_partition_pos_t* partition)
  312. {
  313. boot_cache_redirect(partition->offset, partition->size);
  314. uint32_t pos = 0;
  315. esp_image_header_t image_header;
  316. memcpy(&image_header, MEM_CACHE(pos), sizeof(image_header));
  317. pos += sizeof(image_header);
  318. uint32_t drom_addr = 0;
  319. uint32_t drom_load_addr = 0;
  320. uint32_t drom_size = 0;
  321. uint32_t irom_addr = 0;
  322. uint32_t irom_load_addr = 0;
  323. uint32_t irom_size = 0;
  324. /* Reload the RTC memory sections whenever a non-deepsleep reset
  325. is occurring */
  326. bool load_rtc_memory = rtc_get_reset_reason(0) != DEEPSLEEP_RESET;
  327. ESP_LOGD(TAG, "bin_header: %u %u %u %u %08x", image_header.magic,
  328. image_header.blocks,
  329. image_header.spi_mode,
  330. image_header.spi_size,
  331. (unsigned)image_header.entry_addr);
  332. for (uint32_t section_index = 0;
  333. section_index < image_header.blocks;
  334. ++section_index) {
  335. esp_image_section_header_t section_header = {0};
  336. memcpy(&section_header, MEM_CACHE(pos), sizeof(section_header));
  337. pos += sizeof(section_header);
  338. const uint32_t address = section_header.load_addr;
  339. bool load = true;
  340. bool map = false;
  341. if (address == 0x00000000) { // padding, ignore block
  342. load = false;
  343. }
  344. if (address == 0x00000004) {
  345. load = false; // md5 checksum block
  346. // TODO: actually check md5
  347. }
  348. if (address >= DROM_LOW && address < DROM_HIGH) {
  349. ESP_LOGD(TAG, "found drom section, map from %08x to %08x", pos,
  350. section_header.load_addr);
  351. drom_addr = partition->offset + pos - sizeof(section_header);
  352. drom_load_addr = section_header.load_addr;
  353. drom_size = section_header.data_len + sizeof(section_header);
  354. load = false;
  355. map = true;
  356. }
  357. if (address >= IROM_LOW && address < IROM_HIGH) {
  358. ESP_LOGD(TAG, "found irom section, map from %08x to %08x", pos,
  359. section_header.load_addr);
  360. irom_addr = partition->offset + pos - sizeof(section_header);
  361. irom_load_addr = section_header.load_addr;
  362. irom_size = section_header.data_len + sizeof(section_header);
  363. load = false;
  364. map = true;
  365. }
  366. if (!load_rtc_memory && address >= RTC_IRAM_LOW && address < RTC_IRAM_HIGH) {
  367. ESP_LOGD(TAG, "Skipping RTC code section at %08x\n", pos);
  368. load = false;
  369. }
  370. if (!load_rtc_memory && address >= RTC_DATA_LOW && address < RTC_DATA_HIGH) {
  371. ESP_LOGD(TAG, "Skipping RTC data section at %08x\n", pos);
  372. load = false;
  373. }
  374. ESP_LOGI(TAG, "section %d: paddr=0x%08x vaddr=0x%08x size=0x%05x (%6d) %s", section_index, pos,
  375. section_header.load_addr, section_header.data_len, section_header.data_len, (load)?"load":(map)?"map":"");
  376. if (!load) {
  377. pos += section_header.data_len;
  378. continue;
  379. }
  380. memcpy((void*) section_header.load_addr, MEM_CACHE(pos), section_header.data_len);
  381. pos += section_header.data_len;
  382. }
  383. set_cache_and_start_app(drom_addr,
  384. drom_load_addr,
  385. drom_size,
  386. irom_addr,
  387. irom_load_addr,
  388. irom_size,
  389. image_header.entry_addr);
  390. }
  391. void IRAM_ATTR set_cache_and_start_app(
  392. uint32_t drom_addr,
  393. uint32_t drom_load_addr,
  394. uint32_t drom_size,
  395. uint32_t irom_addr,
  396. uint32_t irom_load_addr,
  397. uint32_t irom_size,
  398. uint32_t entry_addr)
  399. {
  400. ESP_LOGD(TAG, "configure drom and irom and start");
  401. Cache_Read_Disable( 0 );
  402. Cache_Read_Disable( 1 );
  403. Cache_Flush( 0 );
  404. Cache_Flush( 1 );
  405. uint32_t drom_page_count = (drom_size + 64*1024 - 1) / (64*1024); // round up to 64k
  406. ESP_LOGV(TAG, "d mmu set paddr=%08x vaddr=%08x size=%d n=%d", drom_addr & 0xffff0000, drom_load_addr & 0xffff0000, drom_size, drom_page_count );
  407. int rc = cache_flash_mmu_set( 0, 0, drom_load_addr & 0xffff0000, drom_addr & 0xffff0000, 64, drom_page_count );
  408. ESP_LOGV(TAG, "rc=%d", rc );
  409. rc = cache_flash_mmu_set( 1, 0, drom_load_addr & 0xffff0000, drom_addr & 0xffff0000, 64, drom_page_count );
  410. ESP_LOGV(TAG, "rc=%d", rc );
  411. uint32_t irom_page_count = (irom_size + 64*1024 - 1) / (64*1024); // round up to 64k
  412. ESP_LOGV(TAG, "i mmu set paddr=%08x vaddr=%08x size=%d n=%d", irom_addr & 0xffff0000, irom_load_addr & 0xffff0000, irom_size, irom_page_count );
  413. rc = cache_flash_mmu_set( 0, 0, irom_load_addr & 0xffff0000, irom_addr & 0xffff0000, 64, irom_page_count );
  414. ESP_LOGV(TAG, "rc=%d", rc );
  415. rc = cache_flash_mmu_set( 1, 0, irom_load_addr & 0xffff0000, irom_addr & 0xffff0000, 64, irom_page_count );
  416. ESP_LOGV(TAG, "rc=%d", rc );
  417. REG_CLR_BIT( DPORT_PRO_CACHE_CTRL1_REG, (DPORT_PRO_CACHE_MASK_IRAM0) | (DPORT_PRO_CACHE_MASK_IRAM1 & 0) | (DPORT_PRO_CACHE_MASK_IROM0 & 0) | DPORT_PRO_CACHE_MASK_DROM0 | DPORT_PRO_CACHE_MASK_DRAM1 );
  418. REG_CLR_BIT( DPORT_APP_CACHE_CTRL1_REG, (DPORT_APP_CACHE_MASK_IRAM0) | (DPORT_APP_CACHE_MASK_IRAM1 & 0) | (DPORT_APP_CACHE_MASK_IROM0 & 0) | DPORT_APP_CACHE_MASK_DROM0 | DPORT_APP_CACHE_MASK_DRAM1 );
  419. Cache_Read_Enable( 0 );
  420. Cache_Read_Enable( 1 );
  421. ESP_LOGD(TAG, "start: 0x%08x", entry_addr);
  422. typedef void (*entry_t)(void);
  423. entry_t entry = ((entry_t) entry_addr);
  424. // TODO: we have used quite a bit of stack at this point.
  425. // use "movsp" instruction to reset stack back to where ROM stack starts.
  426. (*entry)();
  427. }
  428. static void update_flash_config(const esp_image_header_t* pfhdr)
  429. {
  430. uint32_t size;
  431. switch(pfhdr->spi_size) {
  432. case ESP_IMAGE_FLASH_SIZE_1MB:
  433. size = 1;
  434. break;
  435. case ESP_IMAGE_FLASH_SIZE_2MB:
  436. size = 2;
  437. break;
  438. case ESP_IMAGE_FLASH_SIZE_4MB:
  439. size = 4;
  440. break;
  441. case ESP_IMAGE_FLASH_SIZE_8MB:
  442. size = 8;
  443. break;
  444. case ESP_IMAGE_FLASH_SIZE_16MB:
  445. size = 16;
  446. break;
  447. default:
  448. size = 2;
  449. }
  450. Cache_Read_Disable( 0 );
  451. // Set flash chip size
  452. SPIParamCfg(g_rom_flashchip.deviceId, size * 0x100000, 0x10000, 0x1000, 0x100, 0xffff);
  453. // TODO: set mode
  454. // TODO: set frequency
  455. Cache_Flush(0);
  456. Cache_Read_Enable( 0 );
  457. }
  458. void print_flash_info(const esp_image_header_t* phdr)
  459. {
  460. #if (BOOT_LOG_LEVEL >= BOOT_LOG_LEVEL_NOTICE)
  461. ESP_LOGD(TAG, "magic %02x", phdr->magic );
  462. ESP_LOGD(TAG, "blocks %02x", phdr->blocks );
  463. ESP_LOGD(TAG, "spi_mode %02x", phdr->spi_mode );
  464. ESP_LOGD(TAG, "spi_speed %02x", phdr->spi_speed );
  465. ESP_LOGD(TAG, "spi_size %02x", phdr->spi_size );
  466. const char* str;
  467. switch ( phdr->spi_speed ) {
  468. case ESP_IMAGE_SPI_SPEED_40M:
  469. str = "40MHz";
  470. break;
  471. case ESP_IMAGE_SPI_SPEED_26M:
  472. str = "26.7MHz";
  473. break;
  474. case ESP_IMAGE_SPI_SPEED_20M:
  475. str = "20MHz";
  476. break;
  477. case ESP_IMAGE_SPI_SPEED_80M:
  478. str = "80MHz";
  479. break;
  480. default:
  481. str = "20MHz";
  482. break;
  483. }
  484. ESP_LOGI(TAG, "SPI Speed : %s", str );
  485. switch ( phdr->spi_mode ) {
  486. case ESP_IMAGE_SPI_MODE_QIO:
  487. str = "QIO";
  488. break;
  489. case ESP_IMAGE_SPI_MODE_QOUT:
  490. str = "QOUT";
  491. break;
  492. case ESP_IMAGE_SPI_MODE_DIO:
  493. str = "DIO";
  494. break;
  495. case ESP_IMAGE_SPI_MODE_DOUT:
  496. str = "DOUT";
  497. break;
  498. case ESP_IMAGE_SPI_MODE_FAST_READ:
  499. str = "FAST READ";
  500. break;
  501. case ESP_IMAGE_SPI_MODE_SLOW_READ:
  502. str = "SLOW READ";
  503. break;
  504. default:
  505. str = "DIO";
  506. break;
  507. }
  508. ESP_LOGI(TAG, "SPI Mode : %s", str );
  509. switch ( phdr->spi_size ) {
  510. case ESP_IMAGE_FLASH_SIZE_1MB:
  511. str = "1MB";
  512. break;
  513. case ESP_IMAGE_FLASH_SIZE_2MB:
  514. str = "2MB";
  515. break;
  516. case ESP_IMAGE_FLASH_SIZE_4MB:
  517. str = "4MB";
  518. break;
  519. case ESP_IMAGE_FLASH_SIZE_8MB:
  520. str = "8MB";
  521. break;
  522. case ESP_IMAGE_FLASH_SIZE_16MB:
  523. str = "16MB";
  524. break;
  525. default:
  526. str = "2MB";
  527. break;
  528. }
  529. ESP_LOGI(TAG, "SPI Flash Size : %s", str );
  530. #endif
  531. }