diff --git a/bootloaders/eboot/eboot.c b/bootloaders/eboot/eboot.c index c7cf285c0b..39b14307a6 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" #include extern unsigned char _gzip_dict; @@ -189,6 +190,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 int main() { @@ -211,9 +234,48 @@ int main() if (cmd.action == ACTION_COPY_RAW) { ets_putc('c'); ets_putc('p'); ets_putc(':'); + +#ifdef XMC_SUPPORT + // save the flash access speed registers + uint32_t spi0clk = SPI0CLK; + uint32_t spi0c = SPI0C; + + uint32_t vendor = 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; + } + } + } +#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; diff --git a/bootloaders/eboot/eboot.elf b/bootloaders/eboot/eboot.elf index 0d862f6a9f..bbd4452c0e 100755 Binary files a/bootloaders/eboot/eboot.elf and b/bootloaders/eboot/eboot.elf differ diff --git a/bootloaders/eboot/spi_vendors.h b/bootloaders/eboot/spi_vendors.h new file mode 100644 index 0000000000..484ac7ee86 --- /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 db29ec599c..dc9e069d9d 100644 --- a/cores/esp8266/Esp.cpp +++ b/cores/esp8266/Esp.cpp @@ -404,6 +404,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 @@ -423,6 +425,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 01327747ef..a8fff36515 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/core_esp8266_flash_quirks.cpp b/cores/esp8266/core_esp8266_flash_quirks.cpp new file mode 100644 index 0000000000..7128fcfe2d --- /dev/null +++ b/cores/esp8266/core_esp8266_flash_quirks.cpp @@ -0,0 +1,85 @@ +/* + 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 + +namespace experimental { + +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 + } + } + } +} + +} // namespace experimental + +#ifdef __cplusplus +} +#endif diff --git a/cores/esp8266/core_esp8266_main.cpp b/cores/esp8266/core_esp8266_main.cpp index 0ec4f1f3b9..2d84362347 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 @@ -334,6 +335,8 @@ extern "C" void user_init(void) { initVariant(); + experimental::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..0d05c6d3e8 --- /dev/null +++ b/cores/esp8266/flash_quirks.h @@ -0,0 +1,42 @@ +/* + 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" + +namespace experimental { + +void initFlashQuirks(); + +} // namespace experimental + +#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 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