-
Notifications
You must be signed in to change notification settings - Fork 3
initial SPI flash #9
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
👋 Hello antmak, we appreciate your contribution to this project! Click to see more instructions ...
Review and merge process you can expect ...
|
Just a comment regarding SPI flash functions: at least on newer chips (S3/C3 and later), I would recommend calling the newer esp_flash driver instead of the legacy ROM functions. There are several advantages:
Depending on the specific chip, esp_flash ROM driver requires some patches, but it's easy to find what needs to be patched by looking at the ROM patches in esp-idf. For older chips, perhaps bundling the entire esp_flash driver into the stub is not such a bad option, need to check the code size... |
f2b9b85
to
09816f4
Compare
ac58159
to
887f7f0
Compare
src/esp32/src/flash.c
Outdated
uint32_t strapping = REG_READ(GPIO_STRAP_REG); | ||
/* If GPIO1 (U0TXD) is pulled low and flash pin configuration is not set in efuse, assume | ||
* HSPI flash mode (same as normal boot) */ | ||
if (spiconfig == 0 && (strapping & 0x1c) == 0x08) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know we are copying this lines somewhere else, but it would be nice to know what is this magic numbers meaning? 0x1c, 0x8.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, strap stuff is something that will still need putting order. It was just moved from the original stub
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
updated in target_flash.c, please let me know if it is not clear
c67a222
to
6327072
Compare
Looks like a good idea. As far as I see implementation of https://github.com/espressif/openocd-esp32/blob/master/contrib/loaders/flash/espressif/esp32c3/stub_flasher_chip.c#L346 is almost equal to esp_flash_read_encrypted. So
To simplify development I'd implement base simple flash functionality (read, write, erase, w/o encryption) with ROM functions at first. After we have it working and all related tests passed we can try to switch to esp_flash driver. Base API for the driver and ROM functions are very similar: // ROM funcs
esp_rom_spiflash_result_t esp_rom_spiflash_erase_chip(void);
esp_rom_spiflash_result_t esp_rom_spiflash_erase_area(uint32_t start_addr, uint32_t area_len);
esp_rom_spiflash_result_t esp_rom_spiflash_read(uint32_t src_addr, uint32_t *dest, int32_t len);
esp_rom_spiflash_result_t esp_rom_spiflash_write(uint32_t dest_addr, const uint32_t *src, int32_t len);
// flash driver
esp_err_t esp_flash_erase_chip(esp_flash_t *chip);
esp_err_t esp_flash_erase_region(esp_flash_t *chip, uint32_t start, uint32_t len);
esp_err_t esp_flash_read(esp_flash_t *chip, void *buffer, uint32_t address, uint32_t length);
esp_err_t esp_flash_write(esp_flash_t *chip, const void *buffer, uint32_t address, uint32_t length); So migration at that point seems to be smooth. We can switch to the driver for ESP32 (the oldest chip) and evaluate difference in size. Of course, that will the diff for base API only. @erhankur WDYT? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree with @erhankur suggestion to implement functionality enough for OpenOCD command flash info
(or special test command) for each target and print size, manufacturer id or something useful.
Also do cleanups and re-organize identical code to be reusable.
src/esp32/src/flash.c
Outdated
extern uint32_t ets_efuse_get_spiconfig(void); | ||
extern void esp_rom_spiflash_attach(uint32_t ishspi, bool legacy); | ||
extern esp_rom_spiflash_chip_t g_rom_flashchip; | ||
extern uint8_t g_rom_spiflash_dummy_len_plus[]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These definitions are used for all chips. So seems to be reasonable t move them to one header file like it is done in IDF.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Made the common code a bit different way, ptal
src/esp32c6/src/flash.c
Outdated
#define g_rom_flashchip (rom_spiflash_legacy_data->chip) | ||
#define g_rom_spiflash_dummy_len_plus (rom_spiflash_legacy_data->dummy_len_plus) | ||
|
||
__attribute__((unused)) static inline uint32_t device_id_from_spi_rdid() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have the same implementation for C3. Can be moved to common file
__attribute__((unused)) static inline uint32_t device_id_from_spi_rdid()
{
WRITE_PERI_REG(SPI_MEM_W0_REG(1), 0);
WRITE_PERI_REG(SPI_MEM_CMD_REG(1), SPI_MEM_FLASH_RDID);
while (READ_PERI_REG(SPI_MEM_CMD_REG(1)) != 0)
;
uint32_t rdid = READ_PERI_REG(SPI_MEM_W0_REG(1)) & 0xffffff;
return ((rdid & 0xff) << 16) | (rdid & 0xff00) | ((rdid & 0xff0000) >> 16);;
}
__attribute__((unused)) static inline uint32_t device_id_from_rom()
{
// Sets the correct g_rom_flashchip.device_id from SPI_MEM_FLASH_RDID in ROM code
esp_rom_spi_flash_update_id();
return g_rom_flashchip.device_id;
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yep, fixed it according to the design
@gerekon As we discussed internally, it may be best to write |
3ed8878
to
96d57d4
Compare
#define PERIPHS_SPI_FLASH_BITS_RDID SPI_MEM_FLASH_RDID | ||
|
||
// If we have many defines here, we'll move the common code to common/soc_impl_xxx.h, | ||
// then include it here |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TODO: comply the design, make a couple of common headers
@antmak now this PR looks big enough to review carefully. How can we split it to smaller parts? For example; And I would like to discuss structure change reason in one PR. (Maybe in seperate one or in the PR you really need that changes) |
|
Agree with @erhankur. We agreed to use So for those chips you do not need uint32_t flash_id = stub_target_flash_get_flash_id();
uint32_t flash_size = flash_id_to_flash_size(flash_id); instead you need
For ESP32 and ESP32-S2 that function should be implemented in stub. For newer chips it is implemented in ROM.
As far as I understand @igrr suggestion above is to try to pull in the
As a first step in this PR I would pull that driver to some special sub-dir in the lib (maybe via stub_lib_err_t stub_lib_flash_init(void **state)
{
esp_flash_t chip;
uint32_t flash_size;
STUB_LOG_TRACE();
// WARNING: Calling `esp_flash_init` from IDF esp_flash driver as is
// when app is already running can be dangerous, so we may need to
// call special version of init function at runtime
esp_err_t err = esp_flash_init(&chip)
if (err != ESP_OK) {
STUB_LOGE("Failed to init flash %d!\n", err);
return STUB_LIB_FAIL;
}
err = esp_flash_get_size(&chip, &flash_size);
if (err != ESP_OK) {
STUB_LOGE("Failed to get flash size %d!\n", err);
return STUB_LIB_FAIL;
}
STUB_LOG_TRACEF("Flash size: %d MB\n", flash_size / (1024 * 1024));
return STUB_LIB_OK;
} @erhankur WDYT? Especially the call to And regarding pulling |
Looks like For base flash operations I think we can start with |
My bad. Calling // ets_efuse_read_op();
// uint32_t spiconfig = ets_efuse_get_spiconfig();
// uint32_t strapping = REG_READ(GPIO_STRAP_REG);
/* If GPIO1 (U0TXD) is pulled low and flash pin configuration is not set in efuse, assume
* HSPI flash mode (same as normal boot) */
// if (spiconfig == 0 && (strapping & 0x1c) == 0x08)
// spiconfig = 1; /* HSPI flash mode */
// check if bootloader already attached flash
// if ((READ_PERI_REG(SPI_CACHE_FCTRL_REG(0)) & SPI_CACHE_FLASH_USR_CMD) == 0) {
// STUB_LOGI("Attach spi flash...\n");
// esp_rom_spiflash_attach(spiconfig, 0);
// } else {
// do some runtime magic here
//WRITE_PERI_REG(SPI_CTRL_REG(1), 0x208000);
//WRITE_PERI_REG(SPI_CLOCK_REG(1), 0x3043);
//g_rom_spiflash_dummy_len_plus[1] = 0;
// }
// the code above is what stub_target_flash_init() should do (just an example).
// Currently it is done partially.
stub_target_flash_init();
// Init driver
esp_err_t err = esp_flash_init(&chip)
if (err != ESP_OK) {
STUB_LOGE("Failed to init flash %d!\n", err);
return STUB_LIB_FAIL;
}
err = esp_flash_get_size(&chip, &flash_size);
if (err != ESP_OK) {
STUB_LOGE("Failed to get flash size %d!\n", err);
return STUB_LIB_FAIL;
}
STUB_LOG_TRACEF("Flash size: %d MB\n", flash_size / (1024 * 1024)); |
In the current stub code, we attach the flash if it hasn't been attached yet. If the flash is already attached, I would expect not to call any initialization related code and to run with the existing settings. We can try that. But when it comes to the cache, things get more complex. The stub code needs to know the cache settings (e.g., page size) and work with those settings to use the MMU properly. Before implementing cache support in the stub, we also need to consider how to handle IDF-configurable settings. Anyway, this is a topic for another PR. I am OK, we can handle runtime support in the next PRs, but not too late. From my experience, the most critical parts; runtime init and PSRAM need to be addressed early on. (I assume big sizes will not be a problem with the new esp_flash APIs). The rest, such as read/write/erase, is relatively straightforward. |
Yes we agreed to do with esp_flash_xxx wrappers around ROM functions first. |
* SPDX-License-Identifier: Apache-2.0 OR MIT | ||
*/ | ||
|
||
#include <log.h> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I do not think we have ever supported ESP8266 in OpenOCD.
*/ | ||
extern void esp_rom_spiflash_attach(uint32_t spiconfig, bool legacy); | ||
|
||
inline static |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Contents of this file are the same as for include/target/impl/flash_init_no_spiconfig.h
. What is the purpose oh having them?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is not good style to have function implementations in headers files. Please avoid this. Otherwise every change in such functions will trigger rebuild for all files which include such header.
I do not see a big sense to have this as inline and be in headers.
* @param legacy: Deprecated compatibility API value, must be false | ||
* | ||
*/ | ||
extern void esp_rom_spiflash_attach(uint32_t spiconfig, bool legacy); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you have this externs in several files? In this case It would be better to put ROM functions declarations to header file and include it.
* EFUSE_SPICONFIG_RET_SPIQ, EFUSE_SPICONFIG_RET_SPID, EFUSE_SPICONFIG_RET_SPICS0, EFUSE_SPICONFIG_RET_SPIHD macros. | ||
* WP pin (for quad I/O modes) is not saved in efuse and not returned by this function. | ||
*/ | ||
extern uint32_t ets_efuse_get_spiconfig(void); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is also candidate to be in ROM functions header file. Please have a look at IDF. This function is declared in header file of esp_rom
component.
extern esp_rom_spiflash_chip_t g_rom_flashchip; | ||
|
||
inline static | ||
const esp_rom_spiflash_chip_t *flash_impl_get_config_from_rom_old(void) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we really need separate headers for this functions?
How about have it like macro and keep it with flash_impl_get_config_from_rom
and other similar ROM related staff in one header?
* @brief Sets the correct flash_id in the flash config from SPI_MEM_FLASH_RDID in ROM code | ||
* | ||
*/ | ||
extern void esp_rom_spi_flash_update_id(void); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
candidate to be mnoved to ROM header
(Proposes the design for discussion.)
TODO: