Hello all,
I want to discuss alternative approach for accessing flash memory using OpenOCD. All OpenOCD flash drivers work by accessing target's registers externally to execute flash-related commands. This is fine, but can be quite slow in some cases. Notorious example is "rpchf" driver which provides access to HyperFlash on Renesas RCar Gen3 boards. It is based on U-Boot RPC HF driver which is not very fast itself, because it subclasses standard CFI interface and thus working sub-optimally with RPC HF. But OpenOCD variant is even slower because it uses debugger to access MMIO registers. In my experiments it provided write speed of 500 bytes/sec which is not acceptable for any active development. So I implemented different approach which is 100 times faster (at least in my case). Basically, idea is to write simple application that is running on a target. It provides some standardized interface for accessing flash memory. For example, to write some data onto flash, debugger uploads required data into RAM and then invokes this application. Application performs all required actions and then returns control back to debugger by executing "hlt #0" instruction. You can find my implementation at [1]. It consist of "renesas_hf.c" source file that implements target-side application and "hf-flash.tcl" script that is the debugger-side counterpart. "renesas_hf.c" is built using `make` into position-independent binary which can be uploaded to any portion of SRAM. "hf-flash.tcl" right now supports 3 commands: read flash ID, erase sector(s) and write data. Let's see it's workflow by using "write" command as example. 1. During initialization "hf-flash.tcl" calculates addresses for code, stack and flash data. Then it uploads "renesas_hf.bin" into target's SRAM at calculated address. 2. To write part of a file, hf-flash.tcl script does the following: - sets x0 to base address of RPC HF controller - sets x1 to 0x3 - this is WRITE command - sets x2 to flash address - sets x3 to data size - sets x4 to data address in RAM - sets sp to calculated stack area address - sets pc to a beginning of uploaded renesas_hf.bin image - resumes execution 3. renesas_hf begins execution in _entry(uint32_t base_addr, uint32_t cmd, uint32_t addr, uint32_t len, uint8_ *data) function. As you can see it's parameters corresponds to x0-x4 registers, thanks to aarch64 C ABI. 4. renesas_hf performs actual writing. It is aware of hardware write buffer size and utilizes it optimally to make number of flash writes. 5. At end it sets x0 to return value and executes "hlt #0" instruction, which halts the target and returns control to hf-flash.tcl script. Then script can provide next chunk of file and restart the process from step 2. Because target-side tool receives 2Kb of data at a time and can access flash controller registers directly, it is working much faster. In my experiments, it writes 50Kb per second. As you can see, provided "protocol" is quite versatile and can accommodate any flash driver. In this way OpenOCD can be extended with flash drivers, without touching its source code. To sum up, I resolved my issues with HyperFlash writing. If OpenOCD community is interested, I might implement and try to upstream some more general APIs for this approach, so anyone can implement and share target-side flash drivers. [1] https://github.com/lorc/openocd/tree/renesas_hf/tools/renesas_hf -- Volodymyr Babchuk at EPAM
