From 6634415b8bc35697f283353c0dd5926fdc37def3 Mon Sep 17 00:00:00 2001 From: Mike Nix Date: Fri, 8 Nov 2019 08:42:30 +0800 Subject: [PATCH 1/8] Move the spi vendor list from Esp.h to its own header in eboot. --- bootloaders/eboot/spi_vendors.h | 63 +++++++++++++++++++++++++++++++++ cores/esp8266/Esp.cpp | 6 ++++ cores/esp8266/Esp.h | 38 +------------------- cores/esp8266/spi_vendors.h | 40 +++++++++++++++++++++ 4 files changed, 110 insertions(+), 37 deletions(-) create mode 100644 bootloaders/eboot/spi_vendors.h create mode 100644 cores/esp8266/spi_vendors.h diff --git a/bootloaders/eboot/spi_vendors.h b/bootloaders/eboot/spi_vendors.h new file mode 100644 index 0000000000..a364d4c08d --- /dev/null +++ b/bootloaders/eboot/spi_vendors.h @@ -0,0 +1,63 @@ +/* + spi_vendors.h - Vendor IDs for SPI chips + Copyright (c) 2019 Mike Nix. All rights reserved. + This file is part of the esp8266 core for Arduino environment. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef SPI_VENDORS_H +#define SPI_VENDORS_H + +// Vendor IDs taken from Flashrom project +// https://review.coreboot.org/cgit/flashrom.git/tree/flashchips.h?h=1.0.x +// Moved here from ../../cores/esp8266/Esp.h +typedef enum { + SPI_FLASH_VENDOR_ALLIANCE = 0x52, /* Alliance Semiconductor */ + SPI_FLASH_VENDOR_AMD = 0x01, /* AMD */ + SPI_FLASH_VENDOR_AMIC = 0x37, /* AMIC */ + SPI_FLASH_VENDOR_ATMEL = 0x1F, /* Atmel (now used by Adesto) */ + SPI_FLASH_VENDOR_BRIGHT = 0xAD, /* Bright Microelectronics */ + SPI_FLASH_VENDOR_CATALYST = 0x31, /* Catalyst */ + SPI_FLASH_VENDOR_EON = 0x1C, /* EON Silicon Devices, missing 0x7F prefix */ + SPI_FLASH_VENDOR_ESMT = 0x8C, /* Elite Semiconductor Memory Technology (ESMT) / EFST Elite Flash Storage */ + SPI_FLASH_VENDOR_EXCEL = 0x4A, /* ESI, missing 0x7F prefix */ + SPI_FLASH_VENDOR_FIDELIX = 0xF8, /* Fidelix */ + SPI_FLASH_VENDOR_FUJITSU = 0x04, /* Fujitsu */ + SPI_FLASH_VENDOR_GIGADEVICE = 0xC8, /* GigaDevice */ + SPI_FLASH_VENDOR_HYUNDAI = 0xAD, /* Hyundai */ + SPI_FLASH_VENDOR_INTEL = 0x89, /* Intel */ + SPI_FLASH_VENDOR_ISSI = 0xD5, /* ISSI Integrated Silicon Solutions, see also PMC. */ + SPI_FLASH_VENDOR_MACRONIX = 0xC2, /* Macronix (MX) */ + SPI_FLASH_VENDOR_NANTRONICS = 0xD5, /* Nantronics, missing prefix */ + SPI_FLASH_VENDOR_PMC = 0x9D, /* PMC, missing 0x7F prefix */ + SPI_FLASH_VENDOR_PUYA = 0x85, /* Puya semiconductor (shanghai) co. ltd */ + SPI_FLASH_VENDOR_SANYO = 0x62, /* Sanyo */ + SPI_FLASH_VENDOR_SHARP = 0xB0, /* Sharp */ + SPI_FLASH_VENDOR_SPANSION = 0x01, /* Spansion, same ID as AMD */ + SPI_FLASH_VENDOR_SST = 0xBF, /* SST */ + SPI_FLASH_VENDOR_ST = 0x20, /* ST / SGS/Thomson / Numonyx (later acquired by Micron) */ + SPI_FLASH_VENDOR_SYNCMOS_MVC = 0x40, /* SyncMOS (SM) and Mosel Vitelic Corporation (MVC) */ + SPI_FLASH_VENDOR_TENX = 0x5E, /* Tenx Technologies */ + SPI_FLASH_VENDOR_TI = 0x97, /* Texas Instruments */ + SPI_FLASH_VENDOR_TI_OLD = 0x01, /* TI chips from last century */ + SPI_FLASH_VENDOR_WINBOND = 0xDA, /* Winbond */ + SPI_FLASH_VENDOR_WINBOND_NEX = 0xEF, /* Winbond (ex Nexcom) serial flashes */ + SPI_FLASH_VENDOR_XMC = 0x20, /* Wuhan Xinxin Semiconductor Manufacturing Corp */ + + SPI_FLASH_VENDOR_UNKNOWN = 0xFF +} SPI_FLASH_VENDOR_t; + +#endif // __SPI_VENDORS_H__ diff --git a/cores/esp8266/Esp.cpp b/cores/esp8266/Esp.cpp index 29222d6df5..241ec26af1 100644 --- a/cores/esp8266/Esp.cpp +++ b/cores/esp8266/Esp.cpp @@ -405,6 +405,8 @@ uint32_t EspClass::getFlashChipSizeByChipId(void) { return (64_kB); // Winbond + case 0x1840EF: // W25Q128 + return (16_MB); case 0x1640EF: // W25Q32 return (4_MB); case 0x1540EF: // W25Q16 @@ -424,6 +426,10 @@ uint32_t EspClass::getFlashChipSizeByChipId(void) { case 0x1340E0: // BG25Q40 return (512_kB); + // XMC - Wuhan Xinxin Semiconductor Manufacturing Corp + case 0x164020: // XM25QH32B + return (4_MB); + default: return 0; } diff --git a/cores/esp8266/Esp.h b/cores/esp8266/Esp.h index 726633d613..48c8353738 100644 --- a/cores/esp8266/Esp.h +++ b/cores/esp8266/Esp.h @@ -22,43 +22,7 @@ #define ESP_H #include - -// Vendor IDs taken from Flashrom project -// https://review.coreboot.org/cgit/flashrom.git/tree/flashchips.h?h=1.0.x -typedef enum { - SPI_FLASH_VENDOR_ALLIANCE = 0x52, /* Alliance Semiconductor */ - SPI_FLASH_VENDOR_AMD = 0x01, /* AMD */ - SPI_FLASH_VENDOR_AMIC = 0x37, /* AMIC */ - SPI_FLASH_VENDOR_ATMEL = 0x1F, /* Atmel (now used by Adesto) */ - SPI_FLASH_VENDOR_BRIGHT = 0xAD, /* Bright Microelectronics */ - SPI_FLASH_VENDOR_CATALYST = 0x31, /* Catalyst */ - SPI_FLASH_VENDOR_EON = 0x1C, /* EON Silicon Devices, missing 0x7F prefix */ - SPI_FLASH_VENDOR_ESMT = 0x8C, /* Elite Semiconductor Memory Technology (ESMT) / EFST Elite Flash Storage */ - SPI_FLASH_VENDOR_EXCEL = 0x4A, /* ESI, missing 0x7F prefix */ - SPI_FLASH_VENDOR_FIDELIX = 0xF8, /* Fidelix */ - SPI_FLASH_VENDOR_FUJITSU = 0x04, /* Fujitsu */ - SPI_FLASH_VENDOR_GIGADEVICE = 0xC8, /* GigaDevice */ - SPI_FLASH_VENDOR_HYUNDAI = 0xAD, /* Hyundai */ - SPI_FLASH_VENDOR_INTEL = 0x89, /* Intel */ - SPI_FLASH_VENDOR_ISSI = 0xD5, /* ISSI Integrated Silicon Solutions, see also PMC. */ - SPI_FLASH_VENDOR_MACRONIX = 0xC2, /* Macronix (MX) */ - SPI_FLASH_VENDOR_NANTRONICS = 0xD5, /* Nantronics, missing prefix */ - SPI_FLASH_VENDOR_PMC = 0x9D, /* PMC, missing 0x7F prefix */ - SPI_FLASH_VENDOR_PUYA = 0x85, /* Puya semiconductor (shanghai) co. ltd */ - SPI_FLASH_VENDOR_SANYO = 0x62, /* Sanyo */ - SPI_FLASH_VENDOR_SHARP = 0xB0, /* Sharp */ - SPI_FLASH_VENDOR_SPANSION = 0x01, /* Spansion, same ID as AMD */ - SPI_FLASH_VENDOR_SST = 0xBF, /* SST */ - SPI_FLASH_VENDOR_ST = 0x20, /* ST / SGS/Thomson / Numonyx (later acquired by Micron) */ - SPI_FLASH_VENDOR_SYNCMOS_MVC = 0x40, /* SyncMOS (SM) and Mosel Vitelic Corporation (MVC) */ - SPI_FLASH_VENDOR_TENX = 0x5E, /* Tenx Technologies */ - SPI_FLASH_VENDOR_TI = 0x97, /* Texas Instruments */ - SPI_FLASH_VENDOR_TI_OLD = 0x01, /* TI chips from last century */ - SPI_FLASH_VENDOR_WINBOND = 0xDA, /* Winbond */ - SPI_FLASH_VENDOR_WINBOND_NEX = 0xEF, /* Winbond (ex Nexcom) serial flashes */ - - SPI_FLASH_VENDOR_UNKNOWN = 0xFF -} SPI_FLASH_VENDOR_t; +#include "spi_vendors.h" /** * AVR macros for WDT managment diff --git a/cores/esp8266/spi_vendors.h b/cores/esp8266/spi_vendors.h new file mode 100644 index 0000000000..b656f4cb5b --- /dev/null +++ b/cores/esp8266/spi_vendors.h @@ -0,0 +1,40 @@ +/* + spi_vendors.h - Vendor IDs for SPI chips + Copyright (c) 2019 Mike Nix. All rights reserved. + This file is part of the esp8266 core for Arduino environment. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef SPI_VENDORS_H +#define SPI_VENDORS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Definitions are placed in eboot. Include them here rather than duplicate them. + * Also, prefer to have eboot standalone as much as possible and have the core depend on it + * rather than have eboot depend on the core. + */ +#include <../../bootloaders/eboot/spi_vendors.h> + + +#ifdef __cplusplus +} +#endif + + +#endif // SPI_VENDORS_H From 46578fed5010bb1ff235a3138de3181120d47b05 Mon Sep 17 00:00:00 2001 From: Mike Nix Date: Fri, 8 Nov 2019 08:58:07 +0800 Subject: [PATCH 2/8] Fix ifdef issue with spi_vendors.h --- bootloaders/eboot/spi_vendors.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bootloaders/eboot/spi_vendors.h b/bootloaders/eboot/spi_vendors.h index a364d4c08d..484ac7ee86 100644 --- a/bootloaders/eboot/spi_vendors.h +++ b/bootloaders/eboot/spi_vendors.h @@ -18,8 +18,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef SPI_VENDORS_H -#define SPI_VENDORS_H +#ifndef __SPI_VENDORS_H__ +#define __SPI_VENDORS_H__ // Vendor IDs taken from Flashrom project // https://review.coreboot.org/cgit/flashrom.git/tree/flashchips.h?h=1.0.x From d49a4ec8654fc3401e07e98486e8caeaa58e2cfd Mon Sep 17 00:00:00 2001 From: Mike Nix Date: Fri, 8 Nov 2019 10:15:35 +0800 Subject: [PATCH 3/8] Add initFlashQuirks() for any chip specific flash initialization. Called from user_init(). --- cores/esp8266/core_esp8266_flash_quirks.cpp | 81 +++++++++++++++++++++ cores/esp8266/core_esp8266_main.cpp | 3 + cores/esp8266/flash_quirks.h | 38 ++++++++++ cores/esp8266/spi_flash_defs.h | 44 +++++++++++ 4 files changed, 166 insertions(+) create mode 100644 cores/esp8266/core_esp8266_flash_quirks.cpp create mode 100644 cores/esp8266/flash_quirks.h create mode 100644 cores/esp8266/spi_flash_defs.h diff --git a/cores/esp8266/core_esp8266_flash_quirks.cpp b/cores/esp8266/core_esp8266_flash_quirks.cpp new file mode 100644 index 0000000000..f93cdc9122 --- /dev/null +++ b/cores/esp8266/core_esp8266_flash_quirks.cpp @@ -0,0 +1,81 @@ +/* + flash_quirks.cpp - Chip specific flash init + Copyright (c) 2019 Mike Nix. All rights reserved. + This file is part of the esp8266 core for Arduino environment. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include "spi_flash.h" + +#include "spi_utils.h" +#include "flash_quirks.h" + +#ifdef __cplusplus +extern "C" { +#endif + +static int get_flash_mhz() { + // FIXME: copied from Esp.cpp - we really should define the magic values + uint32_t data; + uint8_t * bytes = (uint8_t *) &data; + // read first 4 byte (magic byte + flash config) + if(spi_flash_read(0x0000, &data, 4) == SPI_FLASH_RESULT_OK) { + switch (bytes[3] & 0x0F) { + case 0x0: // 40 MHz + return 40; + case 0x1: // 26 MHz + return 26; + case 0x2: // 20 MHz + return 20; + case 0xf: // 80 MHz + return 80; + default: // fail? + return 0; + } + } + return 0; +} + +/* initFlashQuirks() + * Do any chip-specific initialization to improve performance and reliability. + */ +void initFlashQuirks() { + using namespace experimental; + uint32_t vendor = spi_flash_get_id() & 0x000000ff; + + switch (vendor) { + case SPI_FLASH_VENDOR_XMC: + uint32_t SR3, newSR3; + if (SPI0Command(SPI_FLASH_CMD_RSR3, &SR3, 0, 8)==SPI_RESULT_OK) { // read SR3 + newSR3=SR3; + if (get_flash_mhz()>26) { // >26Mhz? + // Set the output drive to 100% + newSR3 &= ~(SPI_FLASH_SR3_XMC_DRV_MASK << SPI_FLASH_SR3_XMC_DRV_S); + newSR3 |= (SPI_FLASH_SR3_XMC_DRV_100 << SPI_FLASH_SR3_XMC_DRV_S); + } + if (newSR3 != SR3) { // only write if changed + if (SPI0Command(SPI_FLASH_CMD_WEVSR,NULL,0,0)==SPI_RESULT_OK) // write enable volatile SR + SPI0Command(SPI_FLASH_CMD_WSR3,&newSR3,8,0); // write to SR3 + SPI0Command(SPI_FLASH_CMD_WRDI,NULL,0,0); // write disable - probably not needed + } + } + } +} + +#ifdef __cplusplus +} +#endif diff --git a/cores/esp8266/core_esp8266_main.cpp b/cores/esp8266/core_esp8266_main.cpp index 61c07da909..5509d3e78a 100644 --- a/cores/esp8266/core_esp8266_main.cpp +++ b/cores/esp8266/core_esp8266_main.cpp @@ -34,6 +34,7 @@ extern "C" { } #include #include "gdb_hooks.h" +#include "flash_quirks.h" #define LOOP_TASK_PRIORITY 1 #define LOOP_QUEUE_SIZE 1 @@ -314,6 +315,8 @@ extern "C" void user_init(void) { initVariant(); + initFlashQuirks(); // Chip specific flash init. + cont_init(g_pcont); preinit(); // Prior to C++ Dynamic Init (not related to above init() ). Meant to be user redefinable. diff --git a/cores/esp8266/flash_quirks.h b/cores/esp8266/flash_quirks.h new file mode 100644 index 0000000000..a441d61db2 --- /dev/null +++ b/cores/esp8266/flash_quirks.h @@ -0,0 +1,38 @@ +/* + flash_quirks.h + Copyright (c) 2019 Mike Nix. All rights reserved. + This file is part of the esp8266 core for Arduino environment. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef FLASH_QUIRKS_H +#define FLASH_QUIRKS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "spi_vendors.h" +#include "spi_flash_defs.h" + +void initFlashQuirks(); + +#ifdef __cplusplus +} +#endif + + +#endif // FLASH_QUIRKS_H diff --git a/cores/esp8266/spi_flash_defs.h b/cores/esp8266/spi_flash_defs.h new file mode 100644 index 0000000000..b749fc4c2e --- /dev/null +++ b/cores/esp8266/spi_flash_defs.h @@ -0,0 +1,44 @@ +/* + spi_flash_defs.h - SPI Flash chip commands and status registers + Copyright (c) 2019 Mike Nix. All rights reserved. + This file is part of the esp8266 core for Arduino environment. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef SPI_FLASH_DEFS_H +#define SPI_FLASH_DEFS_H + +// Flash chip Status Register 3: Vendor XMC Output Drive levels +#define SPI_FLASH_SR3_XMC_DRV_25 1 +#define SPI_FLASH_SR3_XMC_DRV_50 0 +#define SPI_FLASH_SR3_XMC_DRV_75 2 +#define SPI_FLASH_SR3_XMC_DRV_100 3 + +#define SPI_FLASH_SR3_XMC_DRV_S 5 +#define SPI_FLASH_SR3_XMC_DRV_MASK 0x03 + +// Flash Chip commands +#define SPI_FLASH_CMD_RSR1 0x05 //Read Flash Status Register... +#define SPI_FLASH_CMD_RSR2 0x35 +#define SPI_FLASH_CMD_RSR3 0x15 +#define SPI_FLASH_CMD_WSR1 0x01 //Write Flash Status Register... +#define SPI_FLASH_CMD_WSR2 0x31 +#define SPI_FLASH_CMD_WSR3 0x11 +#define SPI_FLASH_CMD_WEVSR 0x50 //Write Enable Volatile Status Registers +#define SPI_FLASH_CMD_WREN 0x06 //Write Enable +#define SPI_FLASH_CMD_WRDI 0x04 //Write Disable + +#endif // SPI_FLASH_DEFS_H From fc5013f902c5c95d3d477ebbf4d864ebe0ed24f3 Mon Sep 17 00:00:00 2001 From: Mike Nix Date: Sat, 9 Nov 2019 11:58:20 +0800 Subject: [PATCH 4/8] namespace experimental for initFlashQuirks() --- cores/esp8266/core_esp8266_flash_quirks.cpp | 4 ++++ cores/esp8266/core_esp8266_main.cpp | 2 +- cores/esp8266/flash_quirks.h | 4 ++++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/cores/esp8266/core_esp8266_flash_quirks.cpp b/cores/esp8266/core_esp8266_flash_quirks.cpp index f93cdc9122..7128fcfe2d 100644 --- a/cores/esp8266/core_esp8266_flash_quirks.cpp +++ b/cores/esp8266/core_esp8266_flash_quirks.cpp @@ -28,6 +28,8 @@ extern "C" { #endif +namespace experimental { + static int get_flash_mhz() { // FIXME: copied from Esp.cpp - we really should define the magic values uint32_t data; @@ -76,6 +78,8 @@ void initFlashQuirks() { } } +} // namespace experimental + #ifdef __cplusplus } #endif diff --git a/cores/esp8266/core_esp8266_main.cpp b/cores/esp8266/core_esp8266_main.cpp index bbfa14fff4..0aec3bc398 100644 --- a/cores/esp8266/core_esp8266_main.cpp +++ b/cores/esp8266/core_esp8266_main.cpp @@ -318,7 +318,7 @@ extern "C" void user_init(void) { initVariant(); - initFlashQuirks(); // Chip specific flash init. + experimental::initFlashQuirks(); // Chip specific flash init. cont_init(g_pcont); diff --git a/cores/esp8266/flash_quirks.h b/cores/esp8266/flash_quirks.h index a441d61db2..0d05c6d3e8 100644 --- a/cores/esp8266/flash_quirks.h +++ b/cores/esp8266/flash_quirks.h @@ -28,8 +28,12 @@ extern "C" { #include "spi_vendors.h" #include "spi_flash_defs.h" +namespace experimental { + void initFlashQuirks(); +} // namespace experimental + #ifdef __cplusplus } #endif From 4dc15eafdebec8cb2d796f57220cf7dfd5403c9f Mon Sep 17 00:00:00 2001 From: Mike Nix Date: Fri, 22 Nov 2019 06:17:48 +0800 Subject: [PATCH 5/8] Slow down flash access during eboot firmware copy Part 1 - still some work to do --- bootloaders/eboot/eboot.c | 41 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/bootloaders/eboot/eboot.c b/bootloaders/eboot/eboot.c index 69bc692e97..cd7800ce82 100644 --- a/bootloaders/eboot/eboot.c +++ b/bootloaders/eboot/eboot.c @@ -12,6 +12,7 @@ #include #include "flash.h" #include "eboot_command.h" +#include "spi_vendors.h" #define SWRST do { (*((volatile uint32_t*) 0x60000700)) |= 0x80000000; } while(0); @@ -145,9 +146,49 @@ void main() if (cmd.action == ACTION_COPY_RAW) { ets_putc('c'); ets_putc('p'); ets_putc(':'); + +#define ESP8266_REG(addr) *((volatile uint32_t *)(0x60000000+(addr))) +#define SPI0CLK ESP8266_REG(0x218) +#define SPI0C ESP8266_REG(0x208) + + // save the flash access speed registers + uint32_t spi0clk = SPI0CLK; + uint32_t spi0c = SPI0C; + + uint32_t vendor = 0;//spi_flash_get_id() & 0x000000ff; + if (vendor == SPI_FLASH_VENDOR_XMC) { + uint32_t flashinfo=0; + if (SPIRead(0, &flashinfo, 4)) { + // failed to read the configured flash speed. + // Do not change anything, + } else { + // select an appropriate flash speed + // Register values are those used by ROM + switch ((flashinfo >> 24) & 0x0f) { + case 0x0: // 40MHz, slow to 20 + case 0x1: // 26MHz, slow to 20 + SPI0CLK = 0x00003043; + SPI0C = 0x00EAA313; + break; + case 0x2: // 20MHz, no change + break; + case 0xf: // 80MHz, slow to 26 + SPI0CLK = 0x00002002; + SPI0C = 0x00EAA202; + break; + default: + break; + } + } + } ets_wdt_disable(); res = copy_raw(cmd.args[0], cmd.args[1], cmd.args[2]); ets_wdt_enable(); + + // restore the saved flash access speed registers + SPI0CLK = spi0clk; + SPI0C = spi0c; + ets_putc('0'+res); ets_putc('\n'); if (res == 0) { cmd.action = ACTION_LOAD_APP; From 61c0a3304bbf8ece01fe56f62af00826420560db Mon Sep 17 00:00:00 2001 From: Mike Nix Date: Sat, 23 Nov 2019 06:26:59 +0800 Subject: [PATCH 6/8] Slow down flash access during eboot firmware copy on XMC chips Part 2 - Identify the chip type. Note: there may still be issues with the access speed change. This is very much experimental. --- bootloaders/eboot/eboot.c | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/bootloaders/eboot/eboot.c b/bootloaders/eboot/eboot.c index 7759308246..54b8942429 100644 --- a/bootloaders/eboot/eboot.c +++ b/bootloaders/eboot/eboot.c @@ -124,7 +124,28 @@ int copy_raw(const uint32_t src_addr, return 0; } +#define XMC_SUPPORT +#ifdef XMC_SUPPORT +// Define a few SPI0 registers we need access to +#define ESP8266_REG(addr) *((volatile uint32_t *)(0x60000000+(addr))) +#define SPI0CMD ESP8266_REG(0x200) +#define SPI0CLK ESP8266_REG(0x218) +#define SPI0C ESP8266_REG(0x208) +#define SPI0W0 ESP8266_REG(0x240) +#define SPICMDRDID (1 << 28) + +/* spi_flash_get_id() + Returns the flash chip ID - same as the SDK function. + We need our own version as the SDK isn't available here. + */ +uint32_t __attribute__((noinline)) spi_flash_get_id() { + SPI0W0=0; + SPI0CMD=SPICMDRDID; + while (SPI0CMD) {} + return SPI0W0; +} +#endif // XMC_SUPPORT void main() { @@ -148,15 +169,12 @@ void main() if (cmd.action == ACTION_COPY_RAW) { ets_putc('c'); ets_putc('p'); ets_putc(':'); -#define ESP8266_REG(addr) *((volatile uint32_t *)(0x60000000+(addr))) -#define SPI0CLK ESP8266_REG(0x218) -#define SPI0C ESP8266_REG(0x208) - +#ifdef XMC_SUPPORT // save the flash access speed registers uint32_t spi0clk = SPI0CLK; uint32_t spi0c = SPI0C; - uint32_t vendor = 0;//spi_flash_get_id() & 0x000000ff; + uint32_t vendor = spi_flash_get_id() & 0x000000ff; if (vendor == SPI_FLASH_VENDOR_XMC) { uint32_t flashinfo=0; if (SPIRead(0, &flashinfo, 4)) { @@ -182,14 +200,16 @@ void main() } } } +#endif // XMC_SUPPORT ets_wdt_disable(); res = copy_raw(cmd.args[0], cmd.args[1], cmd.args[2]); ets_wdt_enable(); +#ifdef XMC_SUPPORT // restore the saved flash access speed registers SPI0CLK = spi0clk; SPI0C = spi0c; - +#endif ets_putc('0'+res); ets_putc('\n'); if (res == 0) { cmd.action = ACTION_LOAD_APP; From 3ff5ec5cc189aab0809b8c0bbc986c3577e6d52a Mon Sep 17 00:00:00 2001 From: Mike Nix Date: Thu, 23 Apr 2020 08:03:18 +0800 Subject: [PATCH 7/8] Commit eboot.elf --- bootloaders/eboot/eboot.elf | Bin 10376 -> 16316 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/bootloaders/eboot/eboot.elf b/bootloaders/eboot/eboot.elf index da0f8452785eb278f8a32f0ed05a0b8a67627195..2932b3a40106412f18967981f410a2124aaea4f0 100755 GIT binary patch literal 16316 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 OnLKB!aH(`A>;Df|*7v6X From a19ea69b2cf4ee1c9eeefedffa13a452218a0147 Mon Sep 17 00:00:00 2001 From: Mike Nix Date: Thu, 23 Apr 2020 08:30:27 +0800 Subject: [PATCH 8/8] Commit eboot.elf --- bootloaders/eboot/eboot.elf | Bin 16316 -> 36640 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/bootloaders/eboot/eboot.elf b/bootloaders/eboot/eboot.elf index 2932b3a40106412f18967981f410a2124aaea4f0..bbd4452c0e5b418cb3a065daba765d68d3e541f2 100755 GIT binary patch literal 36640 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 literal 16316 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 WQkT+4zS-rT+{M_RD