#include "common.h" #include "boardinfo_esp.h" #include #include #include #include /* For esp_flash_app_disable_protect() */ #include #define BOARDINFO_ADDR 0 /* Flash address on ESP */ static const union board_info_block *board_info_flash; struct board_info DRAM_ATTR board_info; static spi_flash_mmap_handle_t board_info_handle; static const union board_info_block *board_info_map(void) { if (!board_info_flash) { const void *bifp; if (spi_flash_mmap(BOARDINFO_ADDR, BOARDINFO_SIZE, SPI_FLASH_MMAP_DATA, &bifp, &board_info_handle) == ESP_OK) board_info_flash = bifp; } return board_info_flash; } static void board_info_unmap(void) { if (board_info_flash) { spi_flash_munmap(board_info_handle); board_info_flash = NULL; board_info_handle = 0; } } /* Returns 1 if the flash was modified, 0 if unmodified, -1 on error */ int board_info_init(void) { int err = -1; uint32_t crc, bif_crc; const union board_info_block *bif; bif = board_info_map(); if (!bif) goto unmapped; if (bif->i.magic[0] != BOARDINFO_MAGIC_1 || bif->i.magic[1] != BOARDINFO_MAGIC_2 || bif->i.len < 16 || bif->i.len > BOARDINFO_SIZE || board_info.version_str[sizeof board_info.version_str - 1]) goto bad; memcpy(&board_info, bif, sizeof board_info); bif_crc = board_info.crc; board_info.crc = 0; crc = crc32_le(0, (const uint8_t *)&board_info, 16); crc = crc32_le(crc, &bif->b[16], bif->i.len - 16); board_info.crc = bif_crc; if (crc != bif_crc) { printf("[PCB] Bad board_info crc %08x calculated %08x\n", bif_crc, crc); goto bad; } printf("[PCB] Board ID/version: %s\n", board_info.version_str); err = 0; goto done; bad: if (!memcmp(board_info_flash->b, "MAX80 ", 6) && strnlen(board_info_flash->b, sizeof board_info.version_str) < sizeof board_info.version_str) { /* * Contains board version string but nothing else; this * is allowed to simplify the initial programming. * Convert it to a proper structure and write it back. */ printf("[PCB] updating board information block in flash\n"); return board_info_set((const char *)board_info_flash->b); } unmapped: printf("WARNING: no board ID/version string set in flash\n"); board_info.len = 0; done: if (board_info.len < sizeof board_info) memset((char *)&board_info + board_info.len, 0, sizeof board_info - board_info.len); board_info_unmap(); return err; } static int board_info_generate(const char *board_id_string) { memset(&board_info, 0, sizeof board_info); board_info.magic[0] = BOARDINFO_MAGIC_1; board_info.magic[1] = BOARDINFO_MAGIC_2; board_info.len = sizeof board_info; strncpy(board_info.version_str, board_id_string, sizeof board_info.version_str - 1); memcpy(board_info.mac[0], efuse_default_mac, 6); board_info.crc = crc32_le(0, (const uint8_t *)&board_info, sizeof board_info); return 0; /* For tailcalling convenience */ } /* Must be in IRAM to allow flash operations */ static int __noinline IRAM_ATTR board_info_update_flash(void) { esp_err_t err; int rv = -1; /* The board_info table is in protected memory */ err = esp_flash_app_disable_protect(true); if (err) { printf("board_info_set: failed to unprotect flash (err 0x%x)\n", err); goto err1; } err = esp_flash_erase_region(NULL, BOARDINFO_ADDR, BOARDINFO_SIZE); if (err) { printf("board_info_set: failed to erase board info flash region (err 0x%x)\n", err); goto err2; } err = esp_flash_write(NULL, &board_info, BOARDINFO_ADDR, sizeof board_info); if (err) { printf("board_info_set: failed to write board info flash region (err 0x%x)\n", err); goto err2; } rv = 0; err2: esp_flash_app_disable_protect(false); err1: return rv; } int board_info_set(const char *board_id_string) { const union board_info_block *bif; board_info_generate(board_id_string); bif = board_info_map(); if (!bif) return -1; /* Could not map board info */ bool unchanged = !memcmp(bif, &board_info, sizeof board_info); board_info_unmap(); if (unchanged) return 0; /* Not modified, so don't reflash */ return board_info_update_flash(); }