From 94e3c196654ad89031fa675436919c477d1028ca Mon Sep 17 00:00:00 2001 From: dragonmux Date: Mon, 13 Feb 2023 21:19:35 +0000 Subject: [PATCH 01/14] jtag_devs: Added the ESP32-C3's IDCode to the devices table --- src/target/jtag_devs.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/target/jtag_devs.c b/src/target/jtag_devs.c index 8c3342b23cd..e76fab337a3 100644 --- a/src/target/jtag_devs.c +++ b/src/target/jtag_devs.c @@ -410,6 +410,14 @@ const jtag_dev_descr_s dev_descr[] = { .idmask = 0x0fffffffU, #if ENABLE_DEBUG == 1 .descr = "RISC-V debug v0.13.", +#endif + .handler = riscv_jtag_dtm_handler, + }, + { + .idcode = 0x00005c25U, + .idmask = 0x0fffffffU, +#if ENABLE_DEBUG == 1 + .descr = "RISC-V debug v0.13.", #endif .handler = riscv_jtag_dtm_handler, }, From 600bd24b641fc0a4c29e149cb40874a783bd0405 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Mon, 13 Feb 2023 21:21:14 +0000 Subject: [PATCH 02/14] jep106: Added the manufacturer code for Espressif --- src/target/jep106.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/target/jep106.h b/src/target/jep106.h index f9225067151..e1b13ad7398 100644 --- a/src/target/jep106.h +++ b/src/target/jep106.h @@ -69,6 +69,7 @@ #define JEP106_MANUFACTURER_RENESAS 0x423U /* Renesas */ #define JEP106_MANUFACTURER_WCH 0x72aU /* "Nanjing Yihuo Technology", used by CH579 */ #define JEP106_MANUFACTURER_XILINX 0x309U /* Xilinx - Technically 0x049, but they use Ikanos Communications' code */ +#define JEP106_MANUFACTURER_ESPRESSIF 0xc12U /* Espressif */ /* * This JEP code should belong to "Andes Technology Corporation", but is used on RISC-V by GigaDevice, * so in the unlikely event we need to support chips by them, here be dragons. From d819115517e1d616daa675b806ef99f7b0b62ba2 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Tue, 14 Feb 2023 11:27:48 +0000 Subject: [PATCH 03/14] jtag_devs: Added IR quirks for the ESP32-C3 --- src/target/jtag_devs.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/target/jtag_devs.c b/src/target/jtag_devs.c index e76fab337a3..03cec383d36 100644 --- a/src/target/jtag_devs.c +++ b/src/target/jtag_devs.c @@ -420,6 +420,11 @@ const jtag_dev_descr_s dev_descr[] = { .descr = "RISC-V debug v0.13.", #endif .handler = riscv_jtag_dtm_handler, + .ir_quirks = + { + .ir_length = 5, + .ir_value = 0x0005U, + }, }, #endif #if defined(ENABLE_CORTEXAR) // && defined(ENABLE_SITARA) From 41ac94634cf842679b655a194e2abe1943366b61 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Thu, 16 Nov 2023 05:03:59 +0000 Subject: [PATCH 04/14] esp32c3: Implemented support for preparing the device (switching off the WDTs) for more reliable discovery --- meson_options.txt | 1 + src/Makefile | 1 + src/target/esp32c3.c | 114 ++++++++++++++++++++++++++++++++++++++ src/target/meson.build | 7 +++ src/target/riscv_debug.c | 6 ++ src/target/target_probe.c | 5 ++ src/target/target_probe.h | 1 + 7 files changed, 135 insertions(+) create mode 100644 src/target/esp32c3.c diff --git a/meson_options.txt b/meson_options.txt index 4509803fe27..d1e7c7bc004 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -34,6 +34,7 @@ option( 'at32f4', 'ch579', 'efm', + 'esp32', 'hc32', 'lpc', 'nrf', diff --git a/src/Makefile b/src/Makefile index d44b9c18806..17eb3e403a0 100644 --- a/src/Makefile +++ b/src/Makefile @@ -141,6 +141,7 @@ endif ifeq ($(ENABLE_RISCV), 1) CFLAGS += -DENABLE_RISCV=1 SRC += \ + esp32c3.c \ riscv32.c \ riscv64.c \ riscv_debug.c \ diff --git a/src/target/esp32c3.c b/src/target/esp32c3.c new file mode 100644 index 00000000000..8dcd4acc4d0 --- /dev/null +++ b/src/target/esp32c3.c @@ -0,0 +1,114 @@ +/* + * This file is part of the Black Magic Debug project. + * + * Copyright (C) 2023 1BitSquared + * Written by Rachel Mant + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "general.h" +#include "target_internal.h" +#include "target_probe.h" +#include "riscv_debug.h" +#include "jep106.h" + +#define ESP32_C3_ARCH_ID 0x80000001U +#define ESP32_C3_IMPL_ID 0x00000001U + +#define ESP32_C3_RTC_BASE 0x60008000U +#define ESP32_C3_RTC_WDT_CONFIG0 (ESP32_C3_RTC_BASE + 0x090U) +#define ESP32_C3_RTC_WDT_FEED (ESP32_C3_RTC_BASE + 0x0a4U) +#define ESP32_C3_RTC_WDT_WRITE_PROT (ESP32_C3_RTC_BASE + 0x0a8U) +#define ESP32_C3_RTC_SWD_CONFIG (ESP32_C3_RTC_BASE + 0x0acU) +#define ESP32_C3_RTC_SWD_WRITE_PROT (ESP32_C3_RTC_BASE + 0x0b0U) + +#define ESP32_C3_WDT_WRITE_PROT_KEY 0x50d83aa1U +#define ESP32_C3_RTC_SWD_WRITE_PROT_KEY 0x8f1d312aU +#define ESP32_C3_RTC_SWD_CONFIG_DISABLE 0x40000002U +#define ESP32_C3_RTC_SWD_CONFIG_FEED 0x60000002U + +#define ESP32_C3_TIMG0_BASE 0x6001f000U +#define ESP32_C3_TIMG0_WDT_CONFIG0 (ESP32_C3_TIMG0_BASE + 0x048U) +#define ESP32_C3_TIMG0_WDT_FEED (ESP32_C3_TIMG0_BASE + 0x060U) +#define ESP32_C3_TIMG0_WDT_WRITE_PROT (ESP32_C3_TIMG0_BASE + 0x064U) + +#define ESP32_C3_TIMG1_BASE 0x60020000U +#define ESP32_C3_TIMG1_WDT_CONFIG0 (ESP32_C3_TIMG1_BASE + 0x048U) +#define ESP32_C3_TIMG1_WDT_FEED (ESP32_C3_TIMG1_BASE + 0x060U) +#define ESP32_C3_TIMG1_WDT_WRITE_PROT (ESP32_C3_TIMG1_BASE + 0x064U) + +typedef struct esp32c3_priv { + uint32_t wdt_config[4]; +} esp32c3_priv_s; + +static void esp32c3_disable_wdts(target_s *target); + +/* Make an ESP32-C3 ready for probe operations having identified one */ +bool esp32c3_target_prepare(target_s *const target) +{ + const riscv_hart_s *const hart = riscv_hart_struct(target); + /* Seems that the best we can do is check the marchid and mimplid register values */ + if (target->designer_code != JEP106_MANUFACTURER_ESPRESSIF || hart->archid != ESP32_C3_ARCH_ID || + hart->implid != ESP32_C3_IMPL_ID) + return false; + + /* Allocate the private structure here so we can store the WDT states */ + esp32c3_priv_s *const priv = calloc(1, sizeof(esp32c3_priv_s)); + if (!priv) { /* calloc failed: heap exhaustion */ + DEBUG_ERROR("calloc: failed in %s\n", __func__); + return false; + } + target->target_storage = priv; + /* Prepare the target for memory IO */ + target->mem_read = riscv32_mem_read; + target->mem_write = riscv32_mem_write; + /* Now disable the WDTs so the stop causing problems ready for discovering trigger slots, etc */ + esp32c3_disable_wdts(target); + return true; +} + +static void esp32c3_disable_wdts(target_s *const target) +{ + esp32c3_priv_s *const priv = (esp32c3_priv_s *)target->target_storage; + /* Disable Timer Group 0's WDT */ + target_mem32_write32(target, ESP32_C3_TIMG0_WDT_WRITE_PROT, ESP32_C3_WDT_WRITE_PROT_KEY); + priv->wdt_config[0] = target_mem32_read32(target, ESP32_C3_TIMG0_WDT_CONFIG0); + target_mem32_write32(target, ESP32_C3_TIMG0_WDT_CONFIG0, 0U); + /* Disable Timer Group 1's WDT */ + target_mem32_write32(target, ESP32_C3_TIMG1_WDT_WRITE_PROT, ESP32_C3_WDT_WRITE_PROT_KEY); + priv->wdt_config[1] = target_mem32_read32(target, ESP32_C3_TIMG1_WDT_CONFIG0); + target_mem32_write32(target, ESP32_C3_TIMG1_WDT_CONFIG0, 0U); + /* Disable the RTC WDT */ + target_mem32_write32(target, ESP32_C3_RTC_WDT_WRITE_PROT, ESP32_C3_WDT_WRITE_PROT_KEY); + priv->wdt_config[2] = target_mem32_read32(target, ESP32_C3_RTC_WDT_CONFIG0); + target_mem32_write32(target, ESP32_C3_RTC_WDT_CONFIG0, 0U); + /* Disable the "super" WDT */ + target_mem32_write32(target, ESP32_C3_RTC_SWD_WRITE_PROT, ESP32_C3_RTC_SWD_WRITE_PROT_KEY); + priv->wdt_config[3] = target_mem32_read32(target, ESP32_C3_RTC_SWD_CONFIG); + target_mem32_write32(target, ESP32_C3_RTC_SWD_CONFIG, ESP32_C3_RTC_SWD_CONFIG_DISABLE); +} diff --git a/src/target/meson.build b/src/target/meson.build index 84e1e9c94e1..3072ac9aacf 100644 --- a/src/target/meson.build +++ b/src/target/meson.build @@ -77,6 +77,7 @@ if is_firmware_build 'apollo3': 'Ambiq Apollo3 parts', 'ch579': 'CH579', 'efm': 'Energy Micro parts', + 'esp32': 'Espressif parts', 'hc32': 'HC32 parts', 'lpc': 'LPC series parts', 'nrf': 'nRF series parts', @@ -173,6 +174,11 @@ target_efm = declare_dependency( dependencies: target_cortexm, ) +target_esp32 = declare_dependency( + sources: files('esp32c3.c'), + dependencies: target_riscv32, +) + target_hc32 = declare_dependency( sources: files('hc32l110.c'), dependencies: target_cortexm, @@ -334,6 +340,7 @@ libbmd_target_deps = [ target_at32f4, target_ch579, target_efm, + target_esp32, target_hc32, target_lpc, target_nrf, diff --git a/src/target/riscv_debug.c b/src/target/riscv_debug.c index b191afc6abf..86d1988eea9 100644 --- a/src/target/riscv_debug.c +++ b/src/target/riscv_debug.c @@ -429,6 +429,12 @@ static bool riscv_hart_init(riscv_hart_s *const hart) target->designer_code = hart->vendorid ? hart->vendorid : hart->dbg_module->dmi_bus->designer_code; target->cpuid = hart->archid; + /* + * Now we've identified the target, and before we can do things like trigger discovery + * we need to first run any target-specific setup (eg, halting the WDTs on the ESP32-C3) + * so the next steps won't get screwed up by them. + */ + esp32c3_target_prepare(target); /* Now we're in a safe environment, leasurely read out the triggers, etc. */ riscv_hart_discover_triggers(hart); diff --git a/src/target/target_probe.c b/src/target/target_probe.c index bebb18f16ed..5152b6fa1a9 100644 --- a/src/target/target_probe.c +++ b/src/target/target_probe.c @@ -152,5 +152,10 @@ TARGET_PROBE_WEAK_NOP(stm32wb0_probe) TARGET_PROBE_WEAK_NOP(zynq7_probe) LPC55_DP_PREPARE_WEAK_NOP(lpc55_dp_prepare) +/* + * This isn't actually a probe routine, but it shares its signature with them, + * so uses the same no-op stub because we can get away with that. + */ +TARGET_PROBE_WEAK_NOP(esp32c3_target_prepare) #endif /* _WIN32 */ diff --git a/src/target/target_probe.h b/src/target/target_probe.h index 19d58024818..5af796ef838 100644 --- a/src/target/target_probe.h +++ b/src/target/target_probe.h @@ -103,5 +103,6 @@ bool stm32wb0_probe(target_s *target); bool zynq7_probe(target_s *target); void lpc55_dp_prepare(adiv5_debug_port_s *dp); +bool esp32c3_target_prepare(target_s *target); #endif /* TARGET_TARGET_PROBE_H */ From 4444dd0199f88354e522b9c47bd21e6ebcfb82ac Mon Sep 17 00:00:00 2001 From: dragonmux Date: Tue, 28 Mar 2023 04:06:07 +0100 Subject: [PATCH 05/14] esp32c3: Implemented discovery of and memory maps for the RAM of the ESP32-C3 --- src/target/esp32c3.c | 27 +++++++++++++++++++++++++++ src/target/riscv32.c | 3 +++ src/target/target_probe.c | 1 + src/target/target_probe.h | 1 + 4 files changed, 32 insertions(+) diff --git a/src/target/esp32c3.c b/src/target/esp32c3.c index 8dcd4acc4d0..dedd4c03722 100644 --- a/src/target/esp32c3.c +++ b/src/target/esp32c3.c @@ -40,6 +40,15 @@ #define ESP32_C3_ARCH_ID 0x80000001U #define ESP32_C3_IMPL_ID 0x00000001U +#define ESP32_C3_DBUS_SRAM1_BASE 0x3fc80000U +#define ESP32_C3_DBUS_SRAM1_SIZE 0x00060000U +#define ESP32_C3_IBUS_SRAM0_BASE 0x4037c000U +#define ESP32_C3_IBUS_SRAM0_SIZE 0x00004000U +#define ESP32_C3_IBUS_SRAM1_BASE 0x40380000U +#define ESP32_C3_IBUS_SRAM1_SIZE 0x00060000U +#define ESP32_C3_RTC_SRAM_BASE 0x50000000U +#define ESP32_C3_RTC_SRAM_SIZE 0x00002000U + #define ESP32_C3_RTC_BASE 0x60008000U #define ESP32_C3_RTC_WDT_CONFIG0 (ESP32_C3_RTC_BASE + 0x090U) #define ESP32_C3_RTC_WDT_FEED (ESP32_C3_RTC_BASE + 0x0a4U) @@ -92,6 +101,24 @@ bool esp32c3_target_prepare(target_s *const target) return true; } +bool esp32c3_probe(target_s *const target) +{ + const riscv_hart_s *const hart = riscv_hart_struct(target); + /* Seems that the best we can do is check the marchid and mimplid register values */ + if (hart->archid != ESP32_C3_ARCH_ID || hart->implid != ESP32_C3_IMPL_ID) + return false; + + target->driver = "ESP32-C3"; + + /* Establish the target RAM mappings */ + target_add_ram32(target, ESP32_C3_IBUS_SRAM0_BASE, ESP32_C3_IBUS_SRAM0_SIZE); + target_add_ram32(target, ESP32_C3_IBUS_SRAM1_BASE, ESP32_C3_IBUS_SRAM1_SIZE); + target_add_ram32(target, ESP32_C3_DBUS_SRAM1_BASE, ESP32_C3_DBUS_SRAM1_SIZE); + target_add_ram32(target, ESP32_C3_RTC_SRAM_BASE, ESP32_C3_RTC_SRAM_SIZE); + + return true; +} + static void esp32c3_disable_wdts(target_s *const target) { esp32c3_priv_s *const priv = (esp32c3_priv_s *)target->target_storage; diff --git a/src/target/riscv32.c b/src/target/riscv32.c index 196dbdf89b3..13393c96c36 100644 --- a/src/target/riscv32.c +++ b/src/target/riscv32.c @@ -96,6 +96,9 @@ bool riscv32_probe(target_s *const target) case JEP106_MANUFACTURER_RV_GIGADEVICE: PROBE(gd32vf1_probe); break; + case JEP106_MANUFACTURER_ESPRESSIF: + PROBE(esp32c3_probe); + break; } #if PC_HOSTED == 0 diff --git a/src/target/target_probe.c b/src/target/target_probe.c index 5152b6fa1a9..e19a73c2f69 100644 --- a/src/target/target_probe.c +++ b/src/target/target_probe.c @@ -150,6 +150,7 @@ TARGET_PROBE_WEAK_NOP(stm32mp15_ca7_probe) TARGET_PROBE_WEAK_NOP(stm32mp15_cm4_probe) TARGET_PROBE_WEAK_NOP(stm32wb0_probe) TARGET_PROBE_WEAK_NOP(zynq7_probe) +TARGET_PROBE_WEAK_NOP(esp32c3_probe) LPC55_DP_PREPARE_WEAK_NOP(lpc55_dp_prepare) /* diff --git a/src/target/target_probe.h b/src/target/target_probe.h index 5af796ef838..37874b27985 100644 --- a/src/target/target_probe.h +++ b/src/target/target_probe.h @@ -101,6 +101,7 @@ bool stm32mp15_ca7_probe(target_s *target); bool stm32mp15_cm4_probe(target_s *target); bool stm32wb0_probe(target_s *target); bool zynq7_probe(target_s *target); +bool esp32c3_probe(target_s *target); void lpc55_dp_prepare(adiv5_debug_port_s *dp); bool esp32c3_target_prepare(target_s *target); From 21a3ed1c88c67b0218143758c5c9ecf84fb9551d Mon Sep 17 00:00:00 2001 From: dragonmux Date: Sat, 1 Apr 2023 04:18:26 +0100 Subject: [PATCH 06/14] esp32c3: Implemented support for restoring the WDTs and customised halt/resume functions to take care of them properly --- src/target/esp32c3.c | 47 ++++++++++++++++++++++++++++++++++++++++ src/target/riscv_debug.c | 9 +++----- src/target/riscv_debug.h | 4 ++++ 3 files changed, 54 insertions(+), 6 deletions(-) diff --git a/src/target/esp32c3.c b/src/target/esp32c3.c index dedd4c03722..17aafc4d0c6 100644 --- a/src/target/esp32c3.c +++ b/src/target/esp32c3.c @@ -76,6 +76,10 @@ typedef struct esp32c3_priv { } esp32c3_priv_s; static void esp32c3_disable_wdts(target_s *target); +static void esp32c3_restore_wdts(target_s *target); +static void esp32c3_halt_request(target_s *target); +static void esp32c3_halt_resume(target_s *target, bool step); +static target_halt_reason_e esp32c3_halt_poll(target_s *target, target_addr32_t *watch); /* Make an ESP32-C3 ready for probe operations having identified one */ bool esp32c3_target_prepare(target_s *const target) @@ -110,6 +114,11 @@ bool esp32c3_probe(target_s *const target) target->driver = "ESP32-C3"; + /* We have to provide our own halt/resume functions to take care of the WDTs as they cause Problems */ + target->halt_request = esp32c3_halt_request; + target->halt_resume = esp32c3_halt_resume; + target->halt_poll = esp32c3_halt_poll; + /* Establish the target RAM mappings */ target_add_ram32(target, ESP32_C3_IBUS_SRAM0_BASE, ESP32_C3_IBUS_SRAM0_SIZE); target_add_ram32(target, ESP32_C3_IBUS_SRAM1_BASE, ESP32_C3_IBUS_SRAM1_SIZE); @@ -139,3 +148,41 @@ static void esp32c3_disable_wdts(target_s *const target) priv->wdt_config[3] = target_mem32_read32(target, ESP32_C3_RTC_SWD_CONFIG); target_mem32_write32(target, ESP32_C3_RTC_SWD_CONFIG, ESP32_C3_RTC_SWD_CONFIG_DISABLE); } + +static void esp32c3_restore_wdts(target_s *const target) +{ + esp32c3_priv_s *const priv = (esp32c3_priv_s *)target->target_storage; + /* Restore Timger Group 0's WDT */ + target_mem32_write32(target, ESP32_C3_TIMG0_WDT_CONFIG0, priv->wdt_config[0]); + target_mem32_write32(target, ESP32_C3_TIMG0_WDT_WRITE_PROT, 0U); + /* Restore Timger Group 1's WDT */ + target_mem32_write32(target, ESP32_C3_TIMG1_WDT_CONFIG0, priv->wdt_config[1]); + target_mem32_write32(target, ESP32_C3_TIMG1_WDT_WRITE_PROT, 0U); + /* Restore the RTC WDT */ + target_mem32_write32(target, ESP32_C3_RTC_WDT_CONFIG0, priv->wdt_config[2]); + target_mem32_write32(target, ESP32_C3_RTC_WDT_WRITE_PROT, 0U); + /* Restore the "super" WDT */ + target_mem32_write32(target, ESP32_C3_RTC_SWD_CONFIG, priv->wdt_config[2]); + target_mem32_write32(target, ESP32_C3_RTC_SWD_WRITE_PROT, 0U); +} + +static void esp32c3_halt_request(target_s *const target) +{ + riscv_halt_request(target); + esp32c3_disable_wdts(target); +} + +static void esp32c3_halt_resume(target_s *const target, const bool step) +{ + if (!step) + esp32c3_restore_wdts(target); + riscv_halt_resume(target, step); +} + +static target_halt_reason_e esp32c3_halt_poll(target_s *const target, target_addr32_t *const watch) +{ + const target_halt_reason_e reason = riscv_halt_poll(target, watch); + if (reason == TARGET_HALT_BREAKPOINT) + esp32c3_disable_wdts(target); + return reason; +} diff --git a/src/target/riscv_debug.c b/src/target/riscv_debug.c index 86d1988eea9..d7b67843a3c 100644 --- a/src/target/riscv_debug.c +++ b/src/target/riscv_debug.c @@ -261,9 +261,6 @@ static void riscv_hart_memory_access_type(riscv_hart_s *hart); static const char *riscv_target_description(target_s *target); static bool riscv_check_error(target_s *target); -static void riscv_halt_request(target_s *target); -static void riscv_halt_resume(target_s *target, bool step); -static target_halt_reason_e riscv_halt_poll(target_s *target, target_addr_t *watch); static void riscv_reset(target_s *target); void riscv_dmi_init(riscv_dmi_s *const dmi) @@ -857,7 +854,7 @@ static bool riscv_dm_poll_state(riscv_dm_s *const dbg_module, const uint32_t sta return true; } -static void riscv_halt_request(target_s *const target) +void riscv_halt_request(target_s *const target) { riscv_hart_s *const hart = riscv_hart_struct(target); /* Request the hart to halt */ @@ -870,7 +867,7 @@ static void riscv_halt_request(target_s *const target) (void)riscv_dm_write(hart->dbg_module, RV_DM_CONTROL, hart->hartsel); } -static void riscv_halt_resume(target_s *target, const bool step) +void riscv_halt_resume(target_s *const target, const bool step) { riscv_hart_s *const hart = riscv_hart_struct(target); /* Configure the debug controller for single-stepping as appropriate */ @@ -895,7 +892,7 @@ static void riscv_halt_resume(target_s *target, const bool step) (void)riscv_dm_write(hart->dbg_module, RV_DM_CONTROL, hart->hartsel); } -static target_halt_reason_e riscv_halt_poll(target_s *const target, target_addr_t *const watch) +target_halt_reason_e riscv_halt_poll(target_s *const target, target_addr_t *const watch) { (void)watch; riscv_hart_s *const hart = riscv_hart_struct(target); diff --git a/src/target/riscv_debug.h b/src/target/riscv_debug.h index 5ad9818d71a..4327309de1e 100644 --- a/src/target/riscv_debug.h +++ b/src/target/riscv_debug.h @@ -252,6 +252,10 @@ uint8_t riscv_mem_access_width(const riscv_hart_s *hart, target_addr_t address, void riscv32_unpack_data(void *dest, uint32_t data, uint8_t access_width); uint32_t riscv32_pack_data(const void *src, uint8_t access_width); +void riscv_halt_request(target_s *target); +void riscv_halt_resume(target_s *target, bool step); +target_halt_reason_e riscv_halt_poll(target_s *target, target_addr_t *watch); + void riscv32_mem_read(target_s *target, void *dest, target_addr64_t src, size_t len); void riscv32_mem_write(target_s *target, target_addr64_t dest, const void *src, size_t len); From 7a387612a20d0a39147e5d1c337082f376061589 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Fri, 17 Nov 2023 09:46:38 +0000 Subject: [PATCH 07/14] esp32c3: Implemented support for performing SPI reads and reading out the JEDEC ID of the SPI Flash --- src/target/esp32c3.c | 128 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) diff --git a/src/target/esp32c3.c b/src/target/esp32c3.c index 17aafc4d0c6..324b916dee7 100644 --- a/src/target/esp32c3.c +++ b/src/target/esp32c3.c @@ -35,6 +35,8 @@ #include "target_internal.h" #include "target_probe.h" #include "riscv_debug.h" +#include "spi.h" +#include "sfdp.h" #include "jep106.h" #define ESP32_C3_ARCH_ID 0x80000001U @@ -49,6 +51,40 @@ #define ESP32_C3_RTC_SRAM_BASE 0x50000000U #define ESP32_C3_RTC_SRAM_SIZE 0x00002000U +#define ESP32_C3_SPI1_BASE 0x60002000U +#define ESP32_C3_SPI1_CMD (ESP32_C3_SPI1_BASE + 0x000U) +#define ESP32_C3_SPI1_ADDR (ESP32_C3_SPI1_BASE + 0x004U) +#define ESP32_C3_SPI1_USER0 (ESP32_C3_SPI1_BASE + 0x018U) +#define ESP32_C3_SPI1_USER1 (ESP32_C3_SPI1_BASE + 0x01cU) +#define ESP32_C3_SPI1_USER2 (ESP32_C3_SPI1_BASE + 0x020U) +#define ESP32_C3_SPI1_DATA_OUT_LEN (ESP32_C3_SPI1_BASE + 0x024U) +#define ESP32_C3_SPI1_DATA_IN_LEN (ESP32_C3_SPI1_BASE + 0x028U) +#define ESP32_C3_SPI1_MISC (ESP32_C3_SPI1_BASE + 0x034U) +#define ESP32_C3_SPI1_DATA (ESP32_C3_SPI1_BASE + 0x058U) + +/* These define the various stages of a SPI transaction that we can choose to enable */ +#define ESP32_C3_SPI_CMD_EXEC_XFER 0x00040000U +#define ESP32_C3_SPI_USER0_CMD 0x80000000U +#define ESP32_C3_SPI_USER0_ADDR 0x40000000U +#define ESP32_C3_SPI_USER0_DUMMY 0x20000000U +#define ESP32_C3_SPI_USER0_DATA_IN 0x10000000U +#define ESP32_C3_SPI_USER0_DATA_OUT 0x08000000U +#define ESP32_C3_SPI_MISC_CS_HOLD 0x00000400U + +/* These define the various bit ranges used to store the cycle counts for the enabled stages */ +#define ESP32_C3_SPI_USER2_CMD_LEN_MASK 0xf0000000U +#define ESP32_C3_SPI_USER2_CMD_LEN_SHIFT 28U +#define ESP32_C3_SPI_USER2_CMD_LEN(x) \ + ((((x) - 1U) << ESP32_C3_SPI_USER2_CMD_LEN_SHIFT) & ESP32_C3_SPI_USER2_CMD_LEN_MASK) +#define ESP32_C3_SPI_USER1_ADDR_LEN_MASK 0xfc000000U +#define ESP32_C3_SPI_USER1_ADDR_LEN_SHIFT 26U +#define ESP32_C3_SPI_USER1_ADDR_LEN(x) \ + ((((x) - 1U) << ESP32_C3_SPI_USER1_ADDR_LEN_SHIFT) & ESP32_C3_SPI_USER1_ADDR_LEN_MASK) +#define ESP32_C3_SPI_USER1_DUMMY_LEN_MASK 0x0000003fU +#define ESP32_C3_SPI_USER1_DUMMY_LEN(x) (((x) - 1U) & ESP32_C3_SPI_USER1_DUMMY_LEN_MASK) +#define ESP32_C3_SPI_DATA_BIT_LEN_MASK 0x000003ffU +#define ESP32_C3_SPI_DATA_BIT_LEN(x) ((((x) * 8U) - 1U) & ESP32_C3_SPI_DATA_BIT_LEN_MASK) + #define ESP32_C3_RTC_BASE 0x60008000U #define ESP32_C3_RTC_WDT_CONFIG0 (ESP32_C3_RTC_BASE + 0x090U) #define ESP32_C3_RTC_WDT_FEED (ESP32_C3_RTC_BASE + 0x0a4U) @@ -81,6 +117,8 @@ static void esp32c3_halt_request(target_s *target); static void esp32c3_halt_resume(target_s *target, bool step); static target_halt_reason_e esp32c3_halt_poll(target_s *target, target_addr32_t *watch); +static void esp32c3_spi_read(target_s *target, uint16_t command, target_addr32_t address, void *buffer, size_t length); + /* Make an ESP32-C3 ready for probe operations having identified one */ bool esp32c3_target_prepare(target_s *const target) { @@ -125,6 +163,15 @@ bool esp32c3_probe(target_s *const target) target_add_ram32(target, ESP32_C3_DBUS_SRAM1_BASE, ESP32_C3_DBUS_SRAM1_SIZE); target_add_ram32(target, ESP32_C3_RTC_SRAM_BASE, ESP32_C3_RTC_SRAM_SIZE); + /* Establish the target Flash mappings */ + spi_flash_id_s flash_id; + esp32c3_spi_read(target, SPI_FLASH_CMD_READ_JEDEC_ID, 0, &flash_id, sizeof(flash_id)); + /* If we read out valid Flash information, set up a region for it */ + if (flash_id.manufacturer != 0xffU && flash_id.type != 0xffU && flash_id.capacity != 0xffU) { + const uint32_t capacity = 1U << flash_id.capacity; + DEBUG_INFO("SPI Flash: mfr = %02x, type = %02x, capacity = %08" PRIx32 "\n", flash_id.manufacturer, + flash_id.type, capacity); + } return true; } @@ -186,3 +233,84 @@ static target_halt_reason_e esp32c3_halt_poll(target_s *const target, target_add esp32c3_disable_wdts(target); return reason; } + +static uint32_t esp32c3_spi_config( + target_s *const target, const uint16_t command, const target_addr32_t address, size_t length) +{ + uint32_t enabled_stages = ESP32_C3_SPI_USER0_CMD; + uint32_t user1_value = 0; + + /* Set up the command phase */ + const uint8_t spi_command = command & SPI_FLASH_OPCODE_MASK; + target_mem32_write32(target, ESP32_C3_SPI1_USER2, ESP32_C3_SPI_USER2_CMD_LEN(8) | spi_command); + + /* Configure the address to send */ + if ((command & SPI_FLASH_OPCODE_MODE_MASK) == SPI_FLASH_OPCODE_3B_ADDR) { + enabled_stages |= ESP32_C3_SPI_USER0_ADDR; + target_mem32_write32(target, ESP32_C3_SPI1_ADDR, address); + user1_value |= ESP32_C3_SPI_USER1_ADDR_LEN(24U); + } + + /* Configure the number of dummy cycles required */ + if (command & SPI_FLASH_DUMMY_MASK) { + enabled_stages |= ESP32_C3_SPI_USER0_DUMMY; + uint8_t dummy_cycles = (command & SPI_FLASH_DUMMY_MASK) >> SPI_FLASH_DUMMY_SHIFT; + user1_value |= ESP32_C3_SPI_USER1_DUMMY_LEN(dummy_cycles * 8U); + } + + /* Configure the data phase */ + if (length) { + if (command & SPI_FLASH_DATA_OUT) + enabled_stages |= ESP32_C3_SPI_USER0_DATA_OUT; + else + enabled_stages |= ESP32_C3_SPI_USER0_DATA_IN; + } + + /* Now we've defined all the information needed for user0 and user1, send it */ + target_mem32_write32(target, ESP32_C3_SPI1_USER1, user1_value); + return enabled_stages; +} + +static void esp32c3_spi_wait_complete(target_s *const target) +{ + /* Now trigger the configured transaction */ + target_mem32_write32(target, ESP32_C3_SPI1_CMD, ESP32_C3_SPI_CMD_EXEC_XFER); + /* And wait for the transaction to complete */ + while (target_mem32_read32(target, ESP32_C3_SPI1_CMD) & ESP32_C3_SPI_CMD_EXEC_XFER) + continue; +} + +static void esp32c3_spi_read( + target_s *const target, const uint16_t command, const target_addr32_t address, void *const buffer, size_t length) +{ + /* Start by setting up the common components of the transaction */ + const uint32_t enabled_stages = esp32c3_spi_config(target, command, address, length); + uint8_t *const data = (uint8_t *)buffer; + const uint32_t misc_reg = target_mem32_read32(target, ESP32_C3_SPI1_MISC) & ~ESP32_C3_SPI_MISC_CS_HOLD; + /* + * The transfer has to proceed in no more than 64 bytes at a time because that's + * how many data registers are available in the SPI peripheral + */ + for (size_t offset = 0U; offset < length; offset += 64U) { + const uint32_t amount = MIN(length - offset, 64U); + /* Tell the controller how many bytes we want received in this transaction */ + target_mem32_write32(target, ESP32_C3_SPI1_DATA_IN_LEN, ESP32_C3_SPI_DATA_BIT_LEN(amount)); + /* Configure which transaction stages to use */ + if (offset) + target_mem32_write32(target, ESP32_C3_SPI1_USER0, ESP32_C3_SPI_USER0_DATA_IN); + else + target_mem32_write32(target, ESP32_C3_SPI1_USER0, enabled_stages); + + /* On the final transfer, clear the chip select hold bit, otherwise set it */ + if (length - offset == amount) + target_mem32_write32(target, ESP32_C3_SPI1_MISC, misc_reg); + else + target_mem32_write32(target, ESP32_C3_SPI1_MISC, misc_reg | ESP32_C3_SPI_MISC_CS_HOLD); + + /* Run the transaction */ + esp32c3_spi_wait_complete(target); + + /* Extract and unpack the received data */ + target_mem32_read(target, data + offset, ESP32_C3_SPI1_DATA, amount); + } +} From 9da5071164acd1af4df56cbb32a24c56de36189e Mon Sep 17 00:00:00 2001 From: dragonmux Date: Fri, 17 Nov 2023 23:36:50 +0000 Subject: [PATCH 08/14] esp32c3: Implemented support for performing SPI writes, running commands and added the SPI Flash region mapping --- src/target/esp32c3.c | 55 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/src/target/esp32c3.c b/src/target/esp32c3.c index 324b916dee7..dc52b32ef83 100644 --- a/src/target/esp32c3.c +++ b/src/target/esp32c3.c @@ -51,6 +51,9 @@ #define ESP32_C3_RTC_SRAM_BASE 0x50000000U #define ESP32_C3_RTC_SRAM_SIZE 0x00002000U +#define ESP32_C3_IBUS_FLASH_BASE 0x42000000U +#define ESP32_C3_IBUS_FLASH_SIZE 0x00800000U + #define ESP32_C3_SPI1_BASE 0x60002000U #define ESP32_C3_SPI1_CMD (ESP32_C3_SPI1_BASE + 0x000U) #define ESP32_C3_SPI1_ADDR (ESP32_C3_SPI1_BASE + 0x004U) @@ -118,6 +121,9 @@ static void esp32c3_halt_resume(target_s *target, bool step); static target_halt_reason_e esp32c3_halt_poll(target_s *target, target_addr32_t *watch); static void esp32c3_spi_read(target_s *target, uint16_t command, target_addr32_t address, void *buffer, size_t length); +static void esp32c3_spi_write( + target_s *target, uint16_t command, target_addr32_t address, const void *buffer, size_t length); +static void esp32c3_spi_run_command(target_s *target, uint16_t command, target_addr32_t address); /* Make an ESP32-C3 ready for probe operations having identified one */ bool esp32c3_target_prepare(target_s *const target) @@ -171,6 +177,10 @@ bool esp32c3_probe(target_s *const target) const uint32_t capacity = 1U << flash_id.capacity; DEBUG_INFO("SPI Flash: mfr = %02x, type = %02x, capacity = %08" PRIx32 "\n", flash_id.manufacturer, flash_id.type, capacity); + spi_flash_s *const flash = bmp_spi_add_flash( + target, ESP32_C3_IBUS_FLASH_BASE, capacity, esp32c3_spi_read, esp32c3_spi_write, esp32c3_spi_run_command); + /* Adjust the resulting capacity to not exceed the available memory mapping window size */ + flash->flash.length = MIN(flash->flash.length, ESP32_C3_IBUS_FLASH_SIZE); } return true; } @@ -314,3 +324,48 @@ static void esp32c3_spi_read( target_mem32_read(target, data + offset, ESP32_C3_SPI1_DATA, amount); } } + +static void esp32c3_spi_write(target_s *const target, const uint16_t command, const target_addr32_t address, + const void *const buffer, const size_t length) +{ + /* Start by setting up the common components of the transaction */ + const uint32_t enabled_stages = esp32c3_spi_config(target, command, address, length); + const uint8_t *const data = (const uint8_t *)buffer; + const uint32_t misc_reg = target_mem32_read32(target, ESP32_C3_SPI1_MISC) & ~ESP32_C3_SPI_MISC_CS_HOLD; + + /* + * The transfer has to proceed in no more than 64 bytes at a time because that's + * how many data registers are available in the SPI peripheral + */ + for (size_t offset = 0U; offset < length; offset += 64U) { + const uint32_t amount = MIN(length - offset, 64U); + /* Tell the controller how many bytes we want sent in this transaction */ + target_mem32_write32(target, ESP32_C3_SPI1_DATA_OUT_LEN, ESP32_C3_SPI_DATA_BIT_LEN(amount)); + /* Configure which transaction stages to use */ + if (offset) + target_mem32_write32(target, ESP32_C3_SPI1_USER0, ESP32_C3_SPI_USER0_DATA_OUT); + else + target_mem32_write32(target, ESP32_C3_SPI1_USER0, enabled_stages); + + /* On the final transfer, clear the chip select hold bit, otherwise set it */ + if (length - offset == amount) + target_mem32_write32(target, ESP32_C3_SPI1_MISC, misc_reg); + else + target_mem32_write32(target, ESP32_C3_SPI1_MISC, misc_reg | ESP32_C3_SPI_MISC_CS_HOLD); + + /* Pack and stage the data to transmit */ + target_mem32_write(target, ESP32_C3_SPI1_DATA, data + offset, amount); + + /* Run the transaction */ + esp32c3_spi_wait_complete(target); + } +} + +static void esp32c3_spi_run_command(target_s *const target, const uint16_t command, const target_addr_t address) +{ + /* Start by setting up the common components of the transaction */ + const uint32_t enabled_stages = esp32c3_spi_config(target, command, address, 0U); + /* Write the stages to execute and run the transaction */ + target_mem32_write32(target, ESP32_C3_SPI1_USER0, enabled_stages); + esp32c3_spi_wait_complete(target); +} From 836af915e4127ba9ad3f714713b17b1d33805609 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Fri, 17 Nov 2023 23:37:11 +0000 Subject: [PATCH 09/14] esp32c3: Enabled mass erase --- src/target/esp32c3.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/target/esp32c3.c b/src/target/esp32c3.c index dc52b32ef83..9622a298d8c 100644 --- a/src/target/esp32c3.c +++ b/src/target/esp32c3.c @@ -162,6 +162,8 @@ bool esp32c3_probe(target_s *const target) target->halt_request = esp32c3_halt_request; target->halt_resume = esp32c3_halt_resume; target->halt_poll = esp32c3_halt_poll; + /* Provide an implementation of the mass erase command */ + target->mass_erase = bmp_spi_mass_erase; /* Establish the target RAM mappings */ target_add_ram32(target, ESP32_C3_IBUS_SRAM0_BASE, ESP32_C3_IBUS_SRAM0_SIZE); From f7e932e88af18d9a147f863803bff56b4e251232 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Sat, 1 Apr 2023 17:48:46 +0100 Subject: [PATCH 10/14] esp32c3: Implemented Flash write --- src/target/esp32c3.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/target/esp32c3.c b/src/target/esp32c3.c index 9622a298d8c..1420982a4f4 100644 --- a/src/target/esp32c3.c +++ b/src/target/esp32c3.c @@ -125,6 +125,8 @@ static void esp32c3_spi_write( target_s *target, uint16_t command, target_addr32_t address, const void *buffer, size_t length); static void esp32c3_spi_run_command(target_s *target, uint16_t command, target_addr32_t address); +static bool esp32c3_spi_flash_write(target_flash_s *flash, target_addr32_t dest, const void *src, size_t length); + /* Make an ESP32-C3 ready for probe operations having identified one */ bool esp32c3_target_prepare(target_s *const target) { @@ -183,6 +185,8 @@ bool esp32c3_probe(target_s *const target) target, ESP32_C3_IBUS_FLASH_BASE, capacity, esp32c3_spi_read, esp32c3_spi_write, esp32c3_spi_run_command); /* Adjust the resulting capacity to not exceed the available memory mapping window size */ flash->flash.length = MIN(flash->flash.length, ESP32_C3_IBUS_FLASH_SIZE); + /* Adjust over to our slightly modified versions of the Flash routines */ + flash->flash.write = esp32c3_spi_flash_write; } return true; } @@ -363,6 +367,13 @@ static void esp32c3_spi_write(target_s *const target, const uint16_t command, co } } +static inline uint8_t esp32c3_spi_read_status(target_s *const target) +{ + uint8_t status = 0; + esp32c3_spi_read(target, SPI_FLASH_CMD_READ_STATUS, 0, &status, sizeof(status)); + return status; +} + static void esp32c3_spi_run_command(target_s *const target, const uint16_t command, const target_addr_t address) { /* Start by setting up the common components of the transaction */ @@ -371,3 +382,23 @@ static void esp32c3_spi_run_command(target_s *const target, const uint16_t comma target_mem32_write32(target, ESP32_C3_SPI1_USER0, enabled_stages); esp32c3_spi_wait_complete(target); } + +static bool esp32c3_spi_flash_write( + target_flash_s *const flash, const target_addr32_t dest, const void *const src, const size_t length) +{ + target_s *const target = flash->t; + const spi_flash_s *const spi_flash = (spi_flash_s *)flash; + const target_addr_t begin = dest - flash->start; + const char *const buffer = (const char *)src; + for (size_t offset = 0; offset < length; offset += spi_flash->page_size) { + esp32c3_spi_run_command(target, SPI_FLASH_CMD_WRITE_ENABLE, 0U); + if (!(esp32c3_spi_read_status(target) & SPI_FLASH_STATUS_WRITE_ENABLED)) + return false; + + const size_t amount = MIN(length - offset, spi_flash->page_size); + esp32c3_spi_write(target, SPI_FLASH_CMD_PAGE_PROGRAM, begin + offset, buffer + offset, amount); + while (esp32c3_spi_read_status(target) & SPI_FLASH_STATUS_BUSY) + continue; + } + return true; +} From 81269215cd856bf028ba29053bf065836d49117f Mon Sep 17 00:00:00 2001 From: dragonmux Date: Sun, 2 Apr 2023 16:11:00 +0100 Subject: [PATCH 11/14] esp32c3: Added handling for correctly entering Flash mode --- src/target/esp32c3.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/target/esp32c3.c b/src/target/esp32c3.c index 1420982a4f4..cea9cac3900 100644 --- a/src/target/esp32c3.c +++ b/src/target/esp32c3.c @@ -125,6 +125,7 @@ static void esp32c3_spi_write( target_s *target, uint16_t command, target_addr32_t address, const void *buffer, size_t length); static void esp32c3_spi_run_command(target_s *target, uint16_t command, target_addr32_t address); +static bool esp32c3_enter_flash_mode(target_s *target); static bool esp32c3_spi_flash_write(target_flash_s *flash, target_addr32_t dest, const void *src, size_t length); /* Make an ESP32-C3 ready for probe operations having identified one */ @@ -166,6 +167,8 @@ bool esp32c3_probe(target_s *const target) target->halt_poll = esp32c3_halt_poll; /* Provide an implementation of the mass erase command */ target->mass_erase = bmp_spi_mass_erase; + /* Special care must be taken during Flash programming */ + target->enter_flash_mode = esp32c3_enter_flash_mode; /* Establish the target RAM mappings */ target_add_ram32(target, ESP32_C3_IBUS_SRAM0_BASE, ESP32_C3_IBUS_SRAM0_SIZE); @@ -383,6 +386,12 @@ static void esp32c3_spi_run_command(target_s *const target, const uint16_t comma esp32c3_spi_wait_complete(target); } +static bool esp32c3_enter_flash_mode(target_s *const target) +{ + esp32c3_disable_wdts(target); + return true; +} + static bool esp32c3_spi_flash_write( target_flash_s *const flash, const target_addr32_t dest, const void *const src, const size_t length) { From 6747601bb63b6803e703154a55042e97e83e54f9 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Mon, 3 Apr 2023 21:24:15 +0100 Subject: [PATCH 12/14] esp32c3: Implemented i-cache invalidation and reload for post-completion of Flash operations --- src/target/esp32c3.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/target/esp32c3.c b/src/target/esp32c3.c index cea9cac3900..2c0596b9ca0 100644 --- a/src/target/esp32c3.c +++ b/src/target/esp32c3.c @@ -110,6 +110,19 @@ #define ESP32_C3_TIMG1_WDT_FEED (ESP32_C3_TIMG1_BASE + 0x060U) #define ESP32_C3_TIMG1_WDT_WRITE_PROT (ESP32_C3_TIMG1_BASE + 0x064U) +#define ESP32_C3_EXTMEM_BASE 0x600c4000U +#define ESP32_C3_EXTMEM_ICACHE_SYNC_CTRL (ESP32_C3_EXTMEM_BASE + 0x028U) +#define ESP32_C3_EXTMEM_ICACHE_SYNC_ADDR (ESP32_C3_EXTMEM_BASE + 0x02cU) +#define ESP32_C3_EXTMEM_ICACHE_SYNC_SIZE (ESP32_C3_EXTMEM_BASE + 0x030U) +#define ESP32_C3_EXTMEM_ICACHE_PRELOAD_CTRL (ESP32_C3_EXTMEM_BASE + 0x034U) +#define ESP32_C3_EXTMEM_ICACHE_PRELOAD_ADDR (ESP32_C3_EXTMEM_BASE + 0x038U) +#define ESP32_C3_EXTMEM_ICACHE_PRELOAD_SIZE (ESP32_C3_EXTMEM_BASE + 0x03cU) + +#define ESP32_C3_EXTMEM_ICACHE_INVALIDATE 0x00000001U +#define ESP32_C3_EXTMEM_ICACHE_SYNC_DONE 0x00000002U +#define ESP32_C3_EXTMEM_ICACHE_PRELOAD 0x00000001U +#define ESP32_C3_EXTMEM_ICACHE_PRELOAD_DONE 0x00000002U + typedef struct esp32c3_priv { uint32_t wdt_config[4]; } esp32c3_priv_s; @@ -126,6 +139,7 @@ static void esp32c3_spi_write( static void esp32c3_spi_run_command(target_s *target, uint16_t command, target_addr32_t address); static bool esp32c3_enter_flash_mode(target_s *target); +static bool esp32c3_exit_flash_mode(target_s *target); static bool esp32c3_spi_flash_write(target_flash_s *flash, target_addr32_t dest, const void *src, size_t length); /* Make an ESP32-C3 ready for probe operations having identified one */ @@ -169,6 +183,7 @@ bool esp32c3_probe(target_s *const target) target->mass_erase = bmp_spi_mass_erase; /* Special care must be taken during Flash programming */ target->enter_flash_mode = esp32c3_enter_flash_mode; + target->exit_flash_mode = esp32c3_exit_flash_mode; /* Establish the target RAM mappings */ target_add_ram32(target, ESP32_C3_IBUS_SRAM0_BASE, ESP32_C3_IBUS_SRAM0_SIZE); @@ -392,6 +407,19 @@ static bool esp32c3_enter_flash_mode(target_s *const target) return true; } +static bool esp32c3_exit_flash_mode(target_s *const target) +{ + /* Invalidate the i-cache for the required length */ + target_mem32_write32(target, ESP32_C3_EXTMEM_ICACHE_SYNC_ADDR, ESP32_C3_IBUS_FLASH_BASE); + target_mem32_write32(target, ESP32_C3_EXTMEM_ICACHE_SYNC_SIZE, target->flash->length); + target_mem32_write32(target, ESP32_C3_EXTMEM_ICACHE_SYNC_CTRL, ESP32_C3_EXTMEM_ICACHE_INVALIDATE); + /* Wait for invalidation to complete */ + while (!(target_mem32_read32(target, ESP32_C3_EXTMEM_ICACHE_SYNC_CTRL) & ESP32_C3_EXTMEM_ICACHE_SYNC_DONE)) + continue; + target_reset(target); + return true; +} + static bool esp32c3_spi_flash_write( target_flash_s *const flash, const target_addr32_t dest, const void *const src, const size_t length) { From 85601436f80328fda7c0d6a330ef16ca9353f300 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Fri, 7 Apr 2023 00:00:09 +0100 Subject: [PATCH 13/14] esp32c3: Hacky patch to make Flash write almost work correctly at the loss of a huge amount of speed (25% the speed) --- src/target/esp32c3.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/target/esp32c3.c b/src/target/esp32c3.c index 2c0596b9ca0..2437355da4e 100644 --- a/src/target/esp32c3.c +++ b/src/target/esp32c3.c @@ -424,15 +424,15 @@ static bool esp32c3_spi_flash_write( target_flash_s *const flash, const target_addr32_t dest, const void *const src, const size_t length) { target_s *const target = flash->t; - const spi_flash_s *const spi_flash = (spi_flash_s *)flash; + // const spi_flash_s *const spi_flash = (spi_flash_s *)flash; const target_addr_t begin = dest - flash->start; const char *const buffer = (const char *)src; - for (size_t offset = 0; offset < length; offset += spi_flash->page_size) { + for (size_t offset = 0; offset < length; offset += 64U) { esp32c3_spi_run_command(target, SPI_FLASH_CMD_WRITE_ENABLE, 0U); if (!(esp32c3_spi_read_status(target) & SPI_FLASH_STATUS_WRITE_ENABLED)) return false; - const size_t amount = MIN(length - offset, spi_flash->page_size); + const size_t amount = MIN(length - offset, 64U); esp32c3_spi_write(target, SPI_FLASH_CMD_PAGE_PROGRAM, begin + offset, buffer + offset, amount); while (esp32c3_spi_read_status(target) & SPI_FLASH_STATUS_BUSY) continue; From fe7a8a2bcef081c0379517c57cb85b0d19f595f7 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Mon, 27 Nov 2023 01:29:11 +0000 Subject: [PATCH 14/14] esp32c3: Implemented a custom memory read routine that directly reads the SPI Flash to solve the access problem --- src/target/esp32c3.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/target/esp32c3.c b/src/target/esp32c3.c index 2437355da4e..d960c619c3d 100644 --- a/src/target/esp32c3.c +++ b/src/target/esp32c3.c @@ -138,6 +138,7 @@ static void esp32c3_spi_write( target_s *target, uint16_t command, target_addr32_t address, const void *buffer, size_t length); static void esp32c3_spi_run_command(target_s *target, uint16_t command, target_addr32_t address); +static void esp32c3_mem_read(target_s *target, void *dest, target_addr64_t src, size_t len); static bool esp32c3_enter_flash_mode(target_s *target); static bool esp32c3_exit_flash_mode(target_s *target); static bool esp32c3_spi_flash_write(target_flash_s *flash, target_addr32_t dest, const void *src, size_t length); @@ -205,6 +206,8 @@ bool esp32c3_probe(target_s *const target) flash->flash.length = MIN(flash->flash.length, ESP32_C3_IBUS_FLASH_SIZE); /* Adjust over to our slightly modified versions of the Flash routines */ flash->flash.write = esp32c3_spi_flash_write; + + target->mem_read = esp32c3_mem_read; } return true; } @@ -420,6 +423,18 @@ static bool esp32c3_exit_flash_mode(target_s *const target) return true; } +static void esp32c3_mem_read(target_s *const target, void *const dest, const target_addr64_t src, const size_t len) +{ + /* If the read is somewhere inside Flash, we have to special-case it */ + if (src >= target->flash->start && src < target->flash->start + target->flash->length) + /* Reach entirely past the I-Cache system and read the SPI Flash directly using a standard read command */ + esp32c3_spi_read(target, SPI_FLASH_OPCODE_3B_ADDR | SPI_FLASH_DUMMY_LEN(0U) | SPI_FLASH_OPCODE(0x03U), + src - target->flash->start, dest, len); + else + /* Otherwise delegate to the normal RISC-V 32 memory read routine */ + riscv32_mem_read(target, dest, src, len); +} + static bool esp32c3_spi_flash_write( target_flash_s *const flash, const target_addr32_t dest, const void *const src, const size_t length) {