Merge branch 'master' into write

This commit is contained in:
Marek Kraus 2022-12-06 16:08:54 +01:00 committed by GitHub
commit 4609916981
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 859 additions and 86 deletions

3
.gitignore vendored
View File

@ -74,4 +74,5 @@ fabric.properties
.idea/httpRequests
# Android studio 3.1+ serialized cache file
.idea/caches/build_file_checksums.ser
.idea/caches/build_file_checksums.ser
build/

View File

@ -7,6 +7,7 @@ option(BLISP_BUILD_CLI "Build CLI Tool" OFF)
add_library(libblisp_obj OBJECT
lib/blisp.c
lib/chip/blisp_chip_bl60x.c
lib/chip/blisp_chip_bl70x.c)
target_include_directories(libblisp_obj PRIVATE ${CMAKE_SOURCE_DIR}/include/)
@ -35,6 +36,8 @@ target_sources(libblisp_obj PRIVATE
${CMAKE_SOURCE_DIR}/vendor/libserialport/serialport.c
${CMAKE_SOURCE_DIR}/vendor/libserialport/timing.c)
target_include_directories(libblisp_obj PRIVATE ${CMAKE_SOURCE_DIR}/vendor/libserialport)
if(WIN32)
target_link_libraries(libblisp_obj PRIVATE Setupapi.lib)
target_compile_definitions(libblisp_obj PRIVATE LIBSERIALPORT_MSBUILD)
@ -46,9 +49,11 @@ elseif(UNIX AND NOT APPLE)
${CMAKE_SOURCE_DIR}/vendor/libserialport/linux_termios.c)
target_compile_definitions(libblisp_obj PRIVATE
LIBSERIALPORT_ATBUILD
HAVE_TERMIOS2_SPEED
HAVE_STRUCT_TERMIOS2
HAVE_DECL_BOTHER
"SP_API=__attribute__((visibility(\"default\")))"
"SP_PRIV=__attribute__((visibility(\"hidden\")))")
target_include_directories(libblisp_obj PRIVATE ${CMAKE_SOURCE_DIR}/vendor/libserialport)
write_file(${CMAKE_SOURCE_DIR}/vendor/libserialport/config.h "// bypass errors.")
elseif(APPLE)
target_sources(libblisp_obj PRIVATE

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2022 Marek Kraus <gamelaster@outlook.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

140
README.md
View File

@ -1,17 +1,143 @@
# Bouffalo Labs ISP tool & library
Tool and library for flashing their RISC-V MCUs.
Open source tool and library for flashing Bouffalo RISC-V MCUs.
**NOTE:** Library API and `blisp` tool cli arguments are not stable yet.
# Supported MCUs
- [ ] BL602 / BL604
- [X] BL702 / BL704 / BL706
- [ ] BL606P
- [ ] BL616 / BL618
- [ ] BL808
- [x] `bl60x` - BL602 / BL604
- [x] `bl70x` - BL702 / BL704 / BL706
- [ ] `bl606p` - BL606P
- [ ] `bl61x` - BL616 / BL618
- [ ] `bl808` - BL808
# Supported Devices
- [X] [Pinecil V2](https://wiki.pine64.org/wiki/Pinecil)
# Building
## Clone repository
If you have not cloned this repository locally; check out the git repository locally by running
```bash
git clone --recursive https://github.com/pine64/blisp.git
cd blisp
```
## Build the library and command line utility
For building `blisp` command line tool, use following commands:
```bash
mkdir build && cd build
cmake -DBLISP_BUILD_CLI=ON ..
cmake --build .
```
# Usage
For BL70X, BL61X, BL808 and BL606P, connected via USB, you can use following command, which will auto-detect serial port:
```bash
blisp write --chip bl70x --reset name_of_firmware.bin
```
For BL60X, you need to specify also the serial port path:
```bash
blisp --chip bl60x --reset -p /dev/ttyUSB0 name_of_firmware.bin
```
# Updating Pinecil V2: How to build BLISP Flasher
_Note: This has been tested on x86-64. The build process also works on aarch64 and armv7._
## Linux Steps
⛔ Do not use the Pinecil DC barrel jack while updating firmware or you may destroy your PC. ⛔
1. **Linux set-up**
```
git clone --recursive https://github.com/pine64/blisp.git
cd blisp
mkdir build && cd build
cmake -DBLISP_BUILD_CLI=ON ..
cmake --build .
mkdir tools/blisp/data
mkdir -p tools/blisp/data/bl70x
```
Note: the blisp command will now be in build/tools/blisp/ folder and could later be run with flags as ` ./tools/blisp/blisp` unless you cd into that folder.
2. Get and cp or mv eflash_loader_32m.bin to bl70x folder
```
/build/tools/blisp/data/bl70x/eflash_loader_32m.bin
```
a. Download [eflash*32m.bin here](https://github.com/River-b/blisp/tree/master/eflash).
b. Move eflash*32m.bin to the build/tools/data/bl70x folder
b. Move eflash*32m.bin to the folder build/tools/data/bl70x
c. If it is a Zip, then unzip & move it.
```
unzip eflash_loader_32m.zip -d tools/blisp/data/bl70x/
```
3. **Get V2 firmware** from Github Ralim's IronOS
a. Download the newest stable [firmware release here](https://github.com/Ralim/IronOS).
b. Or download the Beta firmware [IronOS here](https://github.com/Ralim/IronOS/actions/runs/3545583488)
Scroll to the very bottom of the page and download **Pinecilv2**. This link is to [beta that has BLE and also works for EPR chargers](https://github.com/Ralim/IronOS/actions/runs/3545583488)
d. Extract **Pinecilv2.zip** and select a single language file (English = ```Pinecilv2_EN.bin```).
e. Move the Pinecilv2_EN.bin (or selected language) into the same folder as the blisp command.
```
build/tools/blisp/Pinecilv2_EN.bin
```
can delete all the rest of the Pinecilv2**.zip as it is not needed.
4. Connect Pinecil to PC/laptop: long hold [`-`] , then connect cable. Can release the [-] after about 15-20second. V2 screen should be Empty/black, if not, then repeat connection, or find another cable/port. Pinecil connects as a serial COM port.
5. If this fails, see [troubleshooting below](https://github.com/River-b/blisp/blob/master/README.md#troubleshooting).
6. If you are in the folder `blisp/build/tools/blisp/` then execute
```
sudo ./blisp write -c bl70x --reset Pinecilv2_EN.bin
```
Note: if a different language was selected, replace `Pinecilv2_**.bin` above with the chosen file name.
7. Almost done: unplug from the PC and restart V2. Hold down the minus `(-)` button to see the new version number.
8. Before making menu changes, it is recommended to first [Restore Settings to Default](https://github.com/Ralim/IronOS/blob/dev/Documentation/GettingStarted.md#settings-menu).
Simply go to Advanced settings > Restore default settings, confirm using the `(+)` button. This sets all menu items to defaults, keeps the same firmware version, and does not affect any Boot-up logo art if applicable. Setting defaults first avoids unexpected behavior due to some changes in upgrades.
9. Congradulations, and [Stay Fluxey, my friends!](https://www.reddit.com/r/PINE64official/comments/xk9vxu/most_interesting_man_in_the_world_i_dont_always/?utm_source=share&utm_medium=web2x&context=3)
## Troubleshooting
1. If the Pinecil V2 fails to connect to the PC, check the `dmesg` command output.
a. try different cable: usb-C to C is recommended over Usb-A, especially if you are having issues.
b. don't use a USB hub, directly connect to the USB port on the PC or laptop.
c. try different Usb ports (usb-c recommended). Sometimes the rear ports on a PC are better because they are directly connected to the motherboard.
d. try a different PC/laptop
2. It is important to hold down the `(-)` minus button _before_ plugging in the Usb-c cable, and do not release the button for another 15-20 seconds. Try to hold it a little longer before releasing if your computer is slow and it is not working. In rare circumstances on fussy USB ports, keep holding the `(-)` for the entire update.
3. If all of this fails, then join one of the [Live Community Chat channels linked](https://wiki.pine64.org/wiki/Pinecil#Community_links) in the Pinecil Wiki as volunteers there might be able to help.
4. Open a an new issue ticket in this Github/Blisp flasher at https://github.com/pine64/blisp/issues
5. See [Pinecil Wiki](https://wiki.pine64.org/wiki/Pinecil) for hardware information.
6. See [Github Ralim's IronOS](https://ralim.github.io/IronOS/#getting-started) for firmware/software information. This is only the Flasher that loads the firmware; all Pinecil firmware documents and menu instructions are in IronOS.
# To Do
- [ ] Another code style
- [ ] Finalize API
- [ ] SDIO and JTAG support
- [ ] SDIO and JTAG support

View File

@ -1,3 +1,4 @@
// SPDX-License-Identifier: MIT
#ifndef _LIBBLISP_H
#define _LIBBLISP_H
@ -27,16 +28,24 @@ struct blisp_boot_info {
uint8_t chip_id[8]; // TODO: BL60X only 6 bytes
};
// TODO: Refactor variable names, so all will follow same semantic, like image_run, image_check etc.
int32_t blisp_device_init(struct blisp_device* device, struct blisp_chip* chip);
int32_t blisp_device_open(struct blisp_device* device, const char* port_name);
int32_t blisp_device_handshake(struct blisp_device* device);
int32_t blisp_device_handshake(struct blisp_device* device, bool in_ef_loader);
int32_t blisp_device_get_boot_info(struct blisp_device* device, struct blisp_boot_info* boot_info);
int32_t blisp_device_load_boot_header(struct blisp_device* device, uint8_t* boot_header);
int32_t blisp_device_load_segment_header(struct blisp_device* device, struct blisp_segment_header* segment_header);
int32_t blisp_device_load_segment_data(struct blisp_device* device, uint8_t* segment_data, uint32_t segment_data_length);
int32_t blisp_device_write_memory(struct blisp_device* device, uint32_t address, uint32_t value);
int32_t blisp_device_write_memory(struct blisp_device* device,
uint32_t address, uint32_t value,
bool wait_for_res);
int32_t blisp_device_check_image(struct blisp_device* device);
int32_t blisp_device_run_image(struct blisp_device* device);
int32_t blisp_device_flash_erase(struct blisp_device* device, uint32_t start_address, uint32_t end_address);
int32_t blisp_device_flash_write(struct blisp_device* device, uint32_t start_address, uint8_t* payload, uint32_t payload_size);
int32_t blisp_device_program_check(struct blisp_device* device);
int32_t blisp_device_reset(struct blisp_device* device);
void blisp_device_close(struct blisp_device* device);
#endif

View File

@ -1,3 +1,4 @@
// SPDX-License-Identifier: MIT
#ifndef _BLISP_CHIP_H
#define _BLISP_CHIP_H
@ -5,6 +6,7 @@
#include <stdbool.h>
enum blisp_chip_type {
BLISP_CHIP_BL60X,
BLISP_CHIP_BL70X
};
@ -12,8 +14,11 @@ struct blisp_chip { // TODO: Move elsewhere?
enum blisp_chip_type type;
const char* type_str;
bool usb_isp_available;
float handshake_byte_multiplier;
const char* default_eflash_loader_xtal; // TODO: Make this selectable
};
extern struct blisp_chip blisp_chip_bl60x;
extern struct blisp_chip blisp_chip_bl70x;
#endif

173
include/blisp_struct.h Normal file
View File

@ -0,0 +1,173 @@
/*
* Some parts of this source code belongs to Bouffalo Labs
* COPYRIGHT(c) 2020 Bouffalo Lab , License: Apache
*/
#ifndef _LIBBLISP_STRUCT_H
#define _LIBBLISP_STRUCT_H
#include <stdint.h>
#include <assert.h>
#pragma pack(push, 1)
typedef struct {
uint8_t ioMode; /*!< Serail flash interface mode,bit0-3:IF mode,bit4:unwrap */
uint8_t cReadSupport; /*!< Support continuous read mode,bit0:continuous read mode support,bit1:read mode cfg */
uint8_t clkDelay; /*!< SPI clock delay,bit0-3:delay,bit4-6:pad delay */
uint8_t clkInvert; /*!< SPI clock phase invert,bit0:clck invert,bit1:rx invert,bit2-4:pad delay,bit5-7:pad delay */
uint8_t resetEnCmd; /*!< Flash enable reset command */
uint8_t resetCmd; /*!< Flash reset command */
uint8_t resetCreadCmd; /*!< Flash reset continuous read command */
uint8_t resetCreadCmdSize; /*!< Flash reset continuous read command size */
uint8_t jedecIdCmd; /*!< JEDEC ID command */
uint8_t jedecIdCmdDmyClk; /*!< JEDEC ID command dummy clock */
uint8_t qpiJedecIdCmd; /*!< QPI JEDEC ID comamnd */
uint8_t qpiJedecIdCmdDmyClk; /*!< QPI JEDEC ID command dummy clock */
uint8_t sectorSize; /*!< *1024bytes */
uint8_t mid; /*!< Manufacturer ID */
uint16_t pageSize; /*!< Page size */
uint8_t chipEraseCmd; /*!< Chip erase cmd */
uint8_t sectorEraseCmd; /*!< Sector erase command */
uint8_t blk32EraseCmd; /*!< Block 32K erase command,some Micron not support */
uint8_t blk64EraseCmd; /*!< Block 64K erase command */
uint8_t writeEnableCmd; /*!< Need before every erase or program */
uint8_t pageProgramCmd; /*!< Page program cmd */
uint8_t qpageProgramCmd; /*!< QIO page program cmd */
uint8_t qppAddrMode; /*!< QIO page program address mode */
uint8_t fastReadCmd; /*!< Fast read command */
uint8_t frDmyClk; /*!< Fast read command dummy clock */
uint8_t qpiFastReadCmd; /*!< QPI fast read command */
uint8_t qpiFrDmyClk; /*!< QPI fast read command dummy clock */
uint8_t fastReadDoCmd; /*!< Fast read dual output command */
uint8_t frDoDmyClk; /*!< Fast read dual output command dummy clock */
uint8_t fastReadDioCmd; /*!< Fast read dual io comamnd */
uint8_t frDioDmyClk; /*!< Fast read dual io command dummy clock */
uint8_t fastReadQoCmd; /*!< Fast read quad output comamnd */
uint8_t frQoDmyClk; /*!< Fast read quad output comamnd dummy clock */
uint8_t fastReadQioCmd; /*!< Fast read quad io comamnd */
uint8_t frQioDmyClk; /*!< Fast read quad io comamnd dummy clock */
uint8_t qpiFastReadQioCmd; /*!< QPI fast read quad io comamnd */
uint8_t qpiFrQioDmyClk; /*!< QPI fast read QIO dummy clock */
uint8_t qpiPageProgramCmd; /*!< QPI program command */
uint8_t writeVregEnableCmd; /*!< Enable write reg */
uint8_t wrEnableIndex; /*!< Write enable register index */
uint8_t qeIndex; /*!< Quad mode enable register index */
uint8_t busyIndex; /*!< Busy status register index */
uint8_t wrEnableBit; /*!< Write enable bit pos */
uint8_t qeBit; /*!< Quad enable bit pos */
uint8_t busyBit; /*!< Busy status bit pos */
uint8_t wrEnableWriteRegLen; /*!< Register length of write enable */
uint8_t wrEnableReadRegLen; /*!< Register length of write enable status */
uint8_t qeWriteRegLen; /*!< Register length of contain quad enable */
uint8_t qeReadRegLen; /*!< Register length of contain quad enable status */
uint8_t releasePowerDown; /*!< Release power down command */
uint8_t busyReadRegLen; /*!< Register length of contain busy status */
uint8_t readRegCmd[4]; /*!< Read register command buffer */
uint8_t writeRegCmd[4]; /*!< Write register command buffer */
uint8_t enterQpi; /*!< Enter qpi command */
uint8_t exitQpi; /*!< Exit qpi command */
uint8_t cReadMode; /*!< Config data for continuous read mode */
uint8_t cRExit; /*!< Config data for exit continuous read mode */
uint8_t burstWrapCmd; /*!< Enable burst wrap command */
uint8_t burstWrapCmdDmyClk; /*!< Enable burst wrap command dummy clock */
uint8_t burstWrapDataMode; /*!< Data and address mode for this command */
uint8_t burstWrapData; /*!< Data to enable burst wrap */
uint8_t deBurstWrapCmd; /*!< Disable burst wrap command */
uint8_t deBurstWrapCmdDmyClk; /*!< Disable burst wrap command dummy clock */
uint8_t deBurstWrapDataMode; /*!< Data and address mode for this command */
uint8_t deBurstWrapData; /*!< Data to disable burst wrap */
uint16_t timeEsector; /*!< 4K erase time */
uint16_t timeE32k; /*!< 32K erase time */
uint16_t timeE64k; /*!< 64K erase time */
uint16_t timePagePgm; /*!< Page program time */
uint16_t timeCe; /*!< Chip erase time in ms */
uint8_t pdDelay; /*!< Release power down command delay time for wake up */
uint8_t qeData; /*!< QE set data */
} SPI_Flash_Cfg_Type;
#define BFLB_BOOTROM_HASH_SIZE 256 / 8
struct boot_flash_cfg_t
{
char magiccode[4]; /*'FCFG'*/
SPI_Flash_Cfg_Type cfg;
uint32_t crc32;
};
struct sys_clk_cfg_t
{
uint8_t xtal_type;
uint8_t pll_clk;
uint8_t hclk_div;
uint8_t bclk_div;
uint8_t flash_clk_type;
uint8_t flash_clk_div;
uint8_t rsvd[2];
};
struct boot_clk_cfg_t
{
char magiccode[4]; /*'PCFG'*/
struct sys_clk_cfg_t cfg;
uint32_t crc32;
};
struct bfl_boot_header
{
char magiccode[4]; /*'BFXP'*/
uint32_t revison;
struct boot_flash_cfg_t flashCfg;
struct boot_clk_cfg_t clkCfg;
union {
struct {
uint32_t sign : 2; /* [1: 0] for sign*/
uint32_t encrypt_type : 2; /* [3: 2] for encrypt */
uint32_t key_sel : 2; /* [5: 4] for key sel in boot interface*/
uint32_t rsvd6_7 : 2; /* [7: 6] for encrypt*/
uint32_t no_segment : 1; /* [8] no segment info */
uint32_t cache_enable : 1; /* [9] for cache */
uint32_t notload_in_bootrom : 1; /* [10] not load this img in bootrom */
uint32_t aes_region_lock : 1; /* [11] aes region lock */
uint32_t cache_way_disable : 4; /* [15: 12] cache way disable info*/
uint32_t crc_ignore : 1; /* [16] ignore crc */
uint32_t hash_ignore : 1; /* [17] hash crc */
uint32_t halt_ap : 1; /* [18] halt ap */
uint32_t rsvd19_31 : 13; /* [31:19] rsvd */
} bval;
uint32_t wval;
}bootcfg ;
union {
uint32_t segment_cnt;
uint32_t img_length;
}segment_info;
uint32_t bootentry; /* entry point of the image*/
uint32_t flashoffset;
uint8_t hash[BFLB_BOOTROM_HASH_SIZE]; /*hash of the image*/
uint32_t rsv1;
uint32_t rsv2;
uint32_t crc32;
};
static_assert(sizeof(struct bfl_boot_header) == 176, "Bootheader have wrong size");
struct blflash_segment_header
{
uint32_t destaddr;
uint32_t len;
uint32_t rsvd;
uint32_t crc32;
};
static_assert(sizeof(struct blflash_segment_header) == 16, "Segment header have wrong size");
#pragma pack(pop)
#endif

22
include/blisp_util.h Normal file
View File

@ -0,0 +1,22 @@
// SPDX-License-Identifier: MIT
#ifndef _BLISP_UTIL_H
#define _BLISP_UTIL_H
#ifdef WIN32
#include <windows.h>
#else
#include <time.h>
#endif
static void sleep_ms(int milliseconds){
#ifdef WIN32
Sleep(milliseconds);
#else
struct timespec ts;
ts.tv_sec = milliseconds / 1000;
ts.tv_nsec = (milliseconds % 1000) * 1000000;
nanosleep(&ts, NULL);
#endif
}
#endif

View File

@ -1,8 +1,18 @@
// SPDX-License-Identifier: MIT
#include <blisp.h>
#include <blisp_util.h>
#include <libserialport.h>
#include <malloc.h>
#include <stdio.h>
#include <string.h>
#ifdef __linux__
#include <linux/serial.h>
#include <sys/ioctl.h>
#endif
#define DEBUG
int32_t blisp_device_init(struct blisp_device* device, struct blisp_chip* chip)
{
device->chip = chip;
@ -56,6 +66,7 @@ int32_t blisp_device_open(struct blisp_device* device, const char* port_name)
sp_set_parity(serial_port, SP_PARITY_NONE);
sp_set_stopbits(serial_port, 1);
sp_set_flowcontrol(serial_port, SP_FLOWCONTROL_NONE);
uint32_t vid, pid;
sp_get_port_usb_vid_pid(serial_port, &vid, &pid);
device->is_usb = pid == 0xFFFF;
@ -64,8 +75,22 @@ int32_t blisp_device_open(struct blisp_device* device, const char* port_name)
// } else {
device->current_baud_rate = 500000;
// }
sp_set_baudrate(serial_port, device->current_baud_rate);
#if 0
int fd;
sp_get_port_handle(serial_port, &fd);
struct serial_struct serial;
ioctl(fd, TIOCGSERIAL, &serial);
// serial.flags &= ~(ASYNC_LOW_LATENCY);
serial.flags |= ASYNC_LOW_LATENCY;
ioctl(fd, TIOCSSERIAL, &serial);
#endif
ret = sp_set_baudrate(serial_port, device->current_baud_rate);
if (ret != SP_OK) {
return -1; // TODO: Handle this
}
device->serial_port = serial_port;
return 0;
}
@ -82,7 +107,7 @@ int32_t blisp_send_command(struct blisp_device* device, uint8_t command, void* p
uint32_t checksum = 0;
checksum += device->tx_buffer[2] + device->tx_buffer[3];
for (uint16_t i = 0; i < payload_size; i++) {
checksum += *(uint8_t*)(payload + i);
checksum += *(uint8_t*)((uint8_t*)payload + i);
}
device->tx_buffer[1] = checksum & 0xFF;
}
@ -100,51 +125,76 @@ int32_t blisp_receive_response(struct blisp_device* device, bool expect_payload)
// TODO: Check checksum
int ret;
struct sp_port* serial_port = device->serial_port;
ret = sp_blocking_read(serial_port, &device->rx_buffer[0], 2, 300);
ret = sp_blocking_read(serial_port, &device->rx_buffer[0], 2, 1000);
if (ret < 2) {
return -1;
#ifdef DEBUG
fprintf(stderr, "Failed to receive response. (ret = %d)\n", ret);
#endif
return -1; // TODO: Terrible
} else if (device->rx_buffer[0] == 'O' && device->rx_buffer[1] == 'K') {
if (expect_payload) {
sp_blocking_read(serial_port, &device->rx_buffer[2], 2, 100);
sp_blocking_read(serial_port, &device->rx_buffer[2], 2, 100); // TODO: Check if really we received the data.
uint16_t data_length = (device->rx_buffer[3] << 8) | (device->rx_buffer[2]);
sp_blocking_read(serial_port, &device->rx_buffer[0], data_length, 100);
return data_length;
}
return 0;
} else if (device->rx_buffer[0] == 'P' && device->rx_buffer[1] == 'D') {
return -1;
return -3; // TODO: Terrible
} else if (device->rx_buffer[0] == 'F' && device->rx_buffer[1] == 'L') {
sp_blocking_read(serial_port, &device->rx_buffer[2], 2, 100);
device->error_code = (device->rx_buffer[3] << 8) | (device->rx_buffer[2]);
return -4; // Failed
}
#ifdef DEBUG
fprintf(stderr, "Receive response failed... (err: %d, %d - %d)\n", ret, device->rx_buffer[0], device->rx_buffer[1]);
#endif
return -1;
}
int32_t blisp_device_handshake(struct blisp_device* device)
{
int32_t
blisp_device_handshake(struct blisp_device* device, bool in_ef_loader) {
int ret;
uint8_t handshake_buffer[600];
struct sp_port* serial_port = device->serial_port;
uint32_t bytes_count = 0.003f * (float)device->current_baud_rate / 10.0f; // TODO: 0.003f is only for BL70X!
if (!in_ef_loader && !device->is_usb) {
sp_set_rts(serial_port, SP_RTS_ON);
sp_set_dtr(serial_port, SP_DTR_ON);
sleep_ms(50);
sp_set_dtr(serial_port, SP_DTR_OFF);
sleep_ms(100);
sp_set_rts(serial_port, SP_RTS_OFF);
sleep_ms(50); // Wait a bit so BootROM can init
}
uint32_t bytes_count = device->chip->handshake_byte_multiplier * (float)device->current_baud_rate / 10.0f;
if (bytes_count > 600) bytes_count = 600;
memset(handshake_buffer, 'U', bytes_count);
for (uint8_t i = 0; i < 5; i++) {
if (device->is_usb) {
sp_blocking_write(serial_port, "BOUFFALOLAB5555RESET\0\0", 22,
100);
if (!in_ef_loader) {
if (device->is_usb) {
sp_blocking_write(serial_port, "BOUFFALOLAB5555RESET\0\0", 22,
100);
}
}
ret = sp_blocking_write(serial_port, handshake_buffer, bytes_count,
100);
500);
if (ret < 0) {
return -1;
}
ret = sp_blocking_read(serial_port, device->rx_buffer, 2, 100);
if (ret == 2 && device->rx_buffer[0] == 'O' && device->rx_buffer[1] == 'K') {
return 0;
if (!in_ef_loader && !device->is_usb) {
sp_drain(serial_port); // Wait for write to send all data
sp_flush(serial_port, SP_BUF_INPUT); // Flush garbage out of RX
}
ret = sp_blocking_read(serial_port, device->rx_buffer, 2, 50);
if (ret >= 2) {
if (device->rx_buffer[0] == 'O' && device->rx_buffer[1] == 'K') {
return 0;
}
}
}
return -4; // didn't received response
@ -160,10 +210,11 @@ int32_t blisp_device_get_boot_info(struct blisp_device* device, struct blisp_boo
ret = blisp_receive_response(device, true);
if (ret < 0) return ret;
memcpy(boot_info->boot_rom_version, &device->rx_buffer[0], 4); // TODO: Endianess
if (device->chip->type == BLISP_CHIP_BL70X) {
memcpy(boot_info->boot_rom_version, &device->rx_buffer[0], 4); // TODO: Endianess
memcpy(boot_info->chip_id, &device->rx_buffer[16], 8);
}
// TODO: BL60X
return 0;
}
@ -184,7 +235,7 @@ int32_t blisp_device_load_segment_header(struct blisp_device* device, struct bli
int ret;
ret = blisp_send_command(device, 0x17, segment_header, 16, false);
if (ret < 0) return ret;
ret = blisp_receive_response(device, false);
ret = blisp_receive_response(device, true); // TODO: Handle response
if (ret < 0) return ret;
return 0;
@ -195,7 +246,7 @@ int32_t blisp_device_load_segment_data(struct blisp_device* device, uint8_t* seg
int ret;
ret = blisp_send_command(device, 0x18, segment_data, segment_data_length, false);
if (ret < 0) return ret;
ret = blisp_receive_response(device, true); // TODO: Handle response
ret = blisp_receive_response(device, false);
if (ret < 0) return ret;
return 0;
@ -212,16 +263,19 @@ int32_t blisp_device_check_image(struct blisp_device* device)
return 0;
}
int32_t blisp_device_write_memory(struct blisp_device* device, uint32_t address, uint32_t value)
{
int32_t
blisp_device_write_memory(struct blisp_device* device, uint32_t address,
uint32_t value, bool wait_for_res) {
int ret;
uint8_t payload[8];
*(uint32_t*)(payload) = address;
*(uint32_t*)(payload + 4) = value; // TODO: Endianness
ret = blisp_send_command(device, 0x50, payload, 8, false);
if (ret < 0) return ret;
ret = blisp_receive_response(device, false);
ret = blisp_send_command(device, 0x50, payload, 8, true);
if (ret < 0) return ret;
if (wait_for_res) {
ret = blisp_receive_response(device, false);
if (ret < 0) return ret;
}
return 0;
}
@ -231,13 +285,13 @@ int32_t blisp_device_run_image(struct blisp_device* device)
int ret;
if (device->chip->type == BLISP_CHIP_BL70X) { // ERRATA
ret = blisp_device_write_memory(device, 0x4000F100, 0x4E424845);
ret = blisp_device_write_memory(device, 0x4000F100, 0x4E424845, true);
if (ret < 0) return ret;
ret = blisp_device_write_memory(device, 0x4000F104, 0x22010000);
ret = blisp_device_write_memory(device, 0x4000F104, 0x22010000, true);
if (ret < 0) return ret;
// ret = blisp_device_write_memory(device, 0x40000018, 0x00000000);
// if (ret < 0) return ret;
ret = blisp_device_write_memory(device, 0x40000018, 0x00000002);
ret = blisp_device_write_memory(device, 0x40000018, 0x00000002, false);
if (ret < 0) return ret;
return 0;
}
@ -250,6 +304,58 @@ int32_t blisp_device_run_image(struct blisp_device* device)
return 0;
}
int32_t
blisp_device_flash_erase(struct blisp_device* device, uint32_t start_address, uint32_t end_address)
{
uint8_t payload[8];
*(uint32_t*)(payload + 0) = start_address;
*(uint32_t*)(payload + 4) = end_address;
int ret = blisp_send_command(device, 0x30, payload, 8, true);
if (ret < 0) return ret;
do {
ret = blisp_receive_response(device, false);
} while (ret == -3);
return 0;
}
int32_t
blisp_device_flash_write(struct blisp_device* device, uint32_t start_address, uint8_t* payload, uint32_t payload_size)
{
// TODO: Add max payload size (8184?)
uint8_t* buffer = malloc(4 + payload_size); // TODO: Don't use malloc + add check
*((uint32_t*)(buffer)) = start_address;
memcpy(buffer + 4, payload, payload_size);
int ret = blisp_send_command(device, 0x31, buffer, payload_size + 4, true);
if (ret < 0) goto exit1;
ret = blisp_receive_response(device, false);
exit1:
free(buffer);
return ret;
}
int32_t blisp_device_program_check(struct blisp_device* device)
{
int ret = blisp_send_command(device, 0x3A, NULL, 0, true);
if (ret < 0) return ret;
ret = blisp_receive_response(device, false);
if (ret < 0) return ret;
return 0;
}
int32_t blisp_device_reset(struct blisp_device* device)
{
int ret = blisp_send_command(device, 0x21, NULL, 0, true);
if (ret < 0) return ret;
ret = blisp_receive_response(device, false);
if (ret < 0) return ret;
return 0;
}
void blisp_device_close(struct blisp_device* device)
{
struct sp_port* serial_port = device->serial_port;

View File

@ -0,0 +1,10 @@
// SPDX-License-Identifier: MIT
#include "blisp.h"
struct blisp_chip blisp_chip_bl60x = {
.type = BLISP_CHIP_BL60X,
.type_str = "bl60x",
.usb_isp_available = false,
.default_eflash_loader_xtal = "40m",
.handshake_byte_multiplier = 0.006f,
};

View File

@ -1,7 +1,10 @@
// SPDX-License-Identifier: MIT
#include "blisp.h"
struct blisp_chip blisp_chip_bl70x = {
.type = BLISP_CHIP_BL70X,
.type_str = "bl70x",
.usb_isp_available = true
.usb_isp_available = true,
.default_eflash_loader_xtal = "32m",
.handshake_byte_multiplier = 0.003f,
};

View File

@ -10,3 +10,6 @@ target_link_libraries(blisp PRIVATE
argtable3
libblisp_static)
if(WIN32)
target_link_libraries(blisp PRIVATE Setupapi.lib)
endif()

View File

@ -1,3 +1,4 @@
// SPDX-License-Identifier: MIT
#ifndef BLISP_CMD_H
#define BLISP_CMD_H

View File

@ -1,11 +1,19 @@
// SPDX-License-Identifier: MIT
#include "../cmd.h"
#include "argtable3.h"
#include <blisp.h>
#include <string.h>
#include <inttypes.h>
#include "blisp_struct.h"
#ifdef __linux__
#include <unistd.h>
#include <linux/limits.h>
#elif defined(_MSC_VER)
#include <BaseTsd.h>
typedef SSIZE_T ssize_t;
#include <windows.h>
#define PATH_MAX MAX_PATH
#endif
#define REG_EXTENDED 1
@ -14,8 +22,9 @@
static struct arg_rex* cmd;
static struct arg_file* binary_to_write;
static struct arg_str* port_name, *chip_type;
static struct arg_lit* reset;
static struct arg_end* end;
static void* cmd_write_argtable[5];
static void* cmd_write_argtable[6];
#ifdef __APPLE__
// Ugh. This stuff is just so messy without C++17 or Qt...
@ -43,31 +52,189 @@ static void get_executable_path(char* buffer_out, uint32_t max_size) {
ssize_t
get_binary_folder(char* buffer, uint32_t buffer_size) {
#ifdef __linux__
readlink("/proc/self/exe", buffer, BUFSIZ); // TODO: Error handling
if (readlink("/proc/self/exe", buffer, buffer_size) <= 0) {
return -1;
}
char* pos = strrchr(buffer, '/');
pos[0] = '\0';
return pos - buffer;
#elif defined(__APPLE__)
get_executable_path(buffer, buffer_size);
char* pos = strrchr(buffer, '/');
pos[0] = '\0';
return pos - buffer;
#else
#error NOT IMPLEMENTED
WCHAR path[MAX_PATH];
GetModuleFileName(NULL, path, ARRAYSIZE(path));
if (GetModuleFileName(NULL, buffer, buffer_size) <= 0) {
return -1;
}
char* pos = strrchr(buffer, '\\');
#endif
pos[0] = '\0';
return pos - buffer;
}
void fill_up_boot_header(struct bfl_boot_header* boot_header)
{
memcpy(boot_header->magiccode, "BFNP", 4);;
boot_header->revison = 0x01;
memcpy(boot_header->flashCfg.magiccode, "FCFG", 4);
boot_header->flashCfg.cfg.ioMode = 0x11;
boot_header->flashCfg.cfg.cReadSupport = 0x00;
boot_header->flashCfg.cfg.clkDelay = 0x01;
boot_header->flashCfg.cfg.clkInvert = 0x01;
boot_header->flashCfg.cfg.resetEnCmd = 0x66;
boot_header->flashCfg.cfg.resetCmd = 0x99;
boot_header->flashCfg.cfg.resetCreadCmd = 0xFF;
boot_header->flashCfg.cfg.resetCreadCmdSize = 0x03;
boot_header->flashCfg.cfg.jedecIdCmd = 0x9F;
boot_header->flashCfg.cfg.jedecIdCmdDmyClk = 0x00;
boot_header->flashCfg.cfg.qpiJedecIdCmd = 0x9F;
boot_header->flashCfg.cfg.qpiJedecIdCmdDmyClk = 0x00;
boot_header->flashCfg.cfg.sectorSize = 0x04;
boot_header->flashCfg.cfg.mid = 0xC2;
boot_header->flashCfg.cfg.pageSize = 0x100;
boot_header->flashCfg.cfg.chipEraseCmd = 0xC7;
boot_header->flashCfg.cfg.sectorEraseCmd = 0x20;
boot_header->flashCfg.cfg.blk32EraseCmd = 0x52;
boot_header->flashCfg.cfg.blk64EraseCmd = 0xD8;
boot_header->flashCfg.cfg.writeEnableCmd = 0x06;
boot_header->flashCfg.cfg.pageProgramCmd = 0x02;
boot_header->flashCfg.cfg.qpageProgramCmd = 0x32;
boot_header->flashCfg.cfg.qppAddrMode = 0x00;
boot_header->flashCfg.cfg.fastReadCmd = 0x0B;
boot_header->flashCfg.cfg.frDmyClk = 0x01;
boot_header->flashCfg.cfg.qpiFastReadCmd = 0x0B;
boot_header->flashCfg.cfg.qpiFrDmyClk = 0x01;
boot_header->flashCfg.cfg.fastReadDoCmd = 0x3B;
boot_header->flashCfg.cfg.frDoDmyClk = 0x01;
boot_header->flashCfg.cfg.fastReadDioCmd = 0xBB;
boot_header->flashCfg.cfg.frDioDmyClk = 0x00;
boot_header->flashCfg.cfg.fastReadQoCmd = 0x6B;
boot_header->flashCfg.cfg.frQoDmyClk = 0x01;
boot_header->flashCfg.cfg.fastReadQioCmd = 0xEB;
boot_header->flashCfg.cfg.frQioDmyClk = 0x02;
boot_header->flashCfg.cfg.qpiFastReadQioCmd = 0xEB;
boot_header->flashCfg.cfg.qpiFrQioDmyClk = 0x02;
boot_header->flashCfg.cfg.qpiPageProgramCmd = 0x02;
boot_header->flashCfg.cfg.writeVregEnableCmd = 0x50;
boot_header->flashCfg.cfg.wrEnableIndex = 0x00;
boot_header->flashCfg.cfg.qeIndex = 0x01;
boot_header->flashCfg.cfg.busyIndex = 0x00;
boot_header->flashCfg.cfg.wrEnableBit = 0x01;
boot_header->flashCfg.cfg.qeBit = 0x01;
boot_header->flashCfg.cfg.busyBit = 0x00;
boot_header->flashCfg.cfg.wrEnableWriteRegLen = 0x02;
boot_header->flashCfg.cfg.wrEnableReadRegLen = 0x01;
boot_header->flashCfg.cfg.qeWriteRegLen = 0x02;
boot_header->flashCfg.cfg.qeReadRegLen = 0x01;
boot_header->flashCfg.cfg.releasePowerDown = 0xAB;
boot_header->flashCfg.cfg.busyReadRegLen = 0x01;
boot_header->flashCfg.cfg.readRegCmd[0] = 0x05;
boot_header->flashCfg.cfg.readRegCmd[1] = 0x00;
boot_header->flashCfg.cfg.readRegCmd[2] = 0x00;
boot_header->flashCfg.cfg.readRegCmd[3] = 0x00;
boot_header->flashCfg.cfg.writeRegCmd[0] = 0x01;
boot_header->flashCfg.cfg.writeRegCmd[1] = 0x00;
boot_header->flashCfg.cfg.writeRegCmd[2] = 0x00;
boot_header->flashCfg.cfg.writeRegCmd[3] = 0x00;
boot_header->flashCfg.cfg.enterQpi = 0x38;
boot_header->flashCfg.cfg.exitQpi = 0xFF;
boot_header->flashCfg.cfg.cReadMode = 0x00;
boot_header->flashCfg.cfg.cRExit = 0xFF;
boot_header->flashCfg.cfg.burstWrapCmd = 0x77;
boot_header->flashCfg.cfg.burstWrapCmdDmyClk = 0x03;
boot_header->flashCfg.cfg.burstWrapDataMode = 0x02;
boot_header->flashCfg.cfg.burstWrapData = 0x40;
boot_header->flashCfg.cfg.deBurstWrapCmd = 0x77;
boot_header->flashCfg.cfg.deBurstWrapCmdDmyClk = 0x03;
boot_header->flashCfg.cfg.deBurstWrapDataMode = 0x02;
boot_header->flashCfg.cfg.deBurstWrapData = 0xF0;
boot_header->flashCfg.cfg.timeEsector = 0x12C;
boot_header->flashCfg.cfg.timeE32k = 0x4B0;
boot_header->flashCfg.cfg.timeE64k = 0x4B0;
boot_header->flashCfg.cfg.timePagePgm = 0x05;
boot_header->flashCfg.cfg.timeCe = 0xFFFF;
boot_header->flashCfg.cfg.pdDelay = 0x14;
boot_header->flashCfg.cfg.qeData = 0x00;
boot_header->flashCfg.crc32 = 0xE43C762A;
boot_header->clkCfg.cfg.xtal_type = 0x01;
boot_header->clkCfg.cfg.pll_clk = 0x04;
boot_header->clkCfg.cfg.hclk_div = 0x00;
boot_header->clkCfg.cfg.bclk_div = 0x01;
boot_header->clkCfg.cfg.flash_clk_type = 0x03;
boot_header->clkCfg.cfg.flash_clk_div = 0x00;
boot_header->clkCfg.crc32 = 0x72127DBA;
boot_header->bootcfg.bval.sign = 0x00;
boot_header->bootcfg.bval.encrypt_type = 0x00;
boot_header->bootcfg.bval.key_sel = 0x00;
boot_header->bootcfg.bval.rsvd6_7 = 0x00;
boot_header->bootcfg.bval.no_segment = 0x01;
boot_header->bootcfg.bval.cache_enable = 0x01;
boot_header->bootcfg.bval.notload_in_bootrom = 0x00;
boot_header->bootcfg.bval.aes_region_lock = 0x00;
boot_header->bootcfg.bval.cache_way_disable = 0x00;
boot_header->bootcfg.bval.crc_ignore = 0x01;
boot_header->bootcfg.bval.hash_ignore = 0x01;
boot_header->bootcfg.bval.halt_ap = 0x00;
boot_header->bootcfg.bval.rsvd19_31 = 0x00;
boot_header->segment_info.segment_cnt = 0xCDA8;
boot_header->bootentry = 0x00;
boot_header->flashoffset = 0x2000;
boot_header->hash[0x00] = 0xEF;
boot_header->hash[0x01] = 0xBE;
boot_header->hash[0x02] = 0xAD;
boot_header->hash[0x03] = 0xDE;
boot_header->hash[0x04] = 0x00;
boot_header->hash[0x05] = 0x00;
boot_header->hash[0x06] = 0x00;
boot_header->hash[0x07] = 0x00;
boot_header->hash[0x08] = 0x00;
boot_header->hash[0x09] = 0x00;
boot_header->hash[0x0a] = 0x00;
boot_header->hash[0x0b] = 0x00;
boot_header->hash[0x0c] = 0x00;
boot_header->hash[0x0d] = 0x00;
boot_header->hash[0x0e] = 0x00;
boot_header->hash[0x0f] = 0x00;
boot_header->hash[0x10] = 0x00;
boot_header->hash[0x11] = 0x00;
boot_header->hash[0x12] = 0x00;
boot_header->hash[0x13] = 0x00;
boot_header->hash[0x14] = 0x00;
boot_header->hash[0x15] = 0x00;
boot_header->hash[0x16] = 0x00;
boot_header->hash[0x17] = 0x00;
boot_header->hash[0x18] = 0x00;
boot_header->hash[0x19] = 0x00;
boot_header->hash[0x1a] = 0x00;
boot_header->hash[0x1b] = 0x00;
boot_header->hash[0x1c] = 0x00;
boot_header->hash[0x1d] = 0x00;
boot_header->hash[0x1e] = 0x00;
boot_header->hash[0x1f] = 0x00;
boot_header->rsv1 = 0x1000;
boot_header->rsv2 = 0x2000;
boot_header->crc32 = 0xDEADBEEF;
}
void blisp_flash_firmware() {
// TODO: We support currently only BL70X
if (chip_type->count == 0 || strcmp(chip_type->sval[0], "bl70x") != 0) {
FILE* eflash_loader_file = NULL;
if (chip_type->count == 0) {
fprintf(stderr, "Chip type is invalid.\n");
return;
}
struct blisp_chip* chip = NULL;
if (strcmp(chip_type->sval[0], "bl70x") == 0) {
chip = &blisp_chip_bl70x;
} else if (strcmp(chip_type->sval[0], "bl60x") == 0) {
chip = &blisp_chip_bl60x;
} else {
fprintf(stderr, "Chip type is invalid.\n");
return;
}
struct blisp_device device;
uint32_t ret;
ret = blisp_device_init(&device, &blisp_chip_bl70x);
int32_t ret;
ret = blisp_device_init(&device, chip);
if (ret != 0) {
fprintf(stderr, "Failed to init device.\n");
return;
@ -78,7 +245,7 @@ void blisp_flash_firmware() {
return;
}
printf("Sending a handshake...");
ret = blisp_device_handshake(&device);
ret = blisp_device_handshake(&device, false);
if (ret != 0) {
fprintf(stderr, "\nFailed to handshake with device.\n");
goto exit1;
@ -90,6 +257,15 @@ void blisp_flash_firmware() {
fprintf(stderr, "\nFailed to get boot info.\n");
goto exit1;
}
if (boot_info.boot_rom_version[0] == 255 &&
boot_info.boot_rom_version[1] == 255 &&
boot_info.boot_rom_version[2] == 255 &&
boot_info.boot_rom_version[3] == 255) {
printf(" OK\nDevice already in eflash_loader.\n");
goto eflash_loader;
}
printf(" BootROM version %d.%d.%d.%d, ChipID: %02X%02X%02X%02X%02X%02X%02X%02X\n",
boot_info.boot_rom_version[0],
boot_info.boot_rom_version[1],
@ -106,12 +282,28 @@ void blisp_flash_firmware() {
char exe_path[PATH_MAX];
char eflash_loader_path[PATH_MAX];
get_binary_folder(exe_path, PATH_MAX); // TODO: Error handling
snprintf(eflash_loader_path, PATH_MAX, "%s/data/%s/eflash_loader_32m.bin", exe_path, device.chip->type_str);
FILE* eflash_loader_file = fopen(eflash_loader_path, "rb");
uint8_t eflash_loader_header[176];
fread(eflash_loader_header, 176, 1, eflash_loader_file); // TODO: Error handling
if (get_binary_folder(exe_path, PATH_MAX) <= 0) {
fprintf(stderr, "Failed to find executable path to search for the "
"eflash loader\n");
goto exit1;
}
snprintf(eflash_loader_path, PATH_MAX, "%s/data/%s/eflash_loader_%s.bin",
exe_path, device.chip->type_str,
device.chip->default_eflash_loader_xtal);
printf("Loading the eflash loader file from disk\n");
eflash_loader_file
= fopen(eflash_loader_path, "rb"); // TODO: Error handling
if (eflash_loader_file == NULL) {
fprintf(stderr,
"Could not open the eflash loader file from disk.\n"
"Does \"%s\" exist?\n",
eflash_loader_path);
goto exit1;
}
uint8_t
eflash_loader_header[176]; // TODO: Remap it to the boot header struct
fread(eflash_loader_header, 176, 1,
eflash_loader_file); // TODO: Error handling
printf("Loading eflash_loader...\n");
ret = blisp_device_load_boot_header(&device, eflash_loader_header);
@ -120,33 +312,43 @@ void blisp_flash_firmware() {
goto exit1;
}
uint32_t sent_data = 0;
uint32_t buffer_size = 0;
uint8_t buffer[4092];
{
uint32_t sent_data = 0;
uint32_t buffer_size = 0;
uint8_t buffer[4092];
// TODO: Real checking of segments count
for (uint8_t seg_index = 0; seg_index < 1; seg_index++) {
struct blisp_segment_header segment_header = {0};
fread(&segment_header, 16, 1, eflash_loader_file); // TODO: Error handling
// TODO: Real checking of segments count
for (uint8_t seg_index = 0; seg_index < 1; seg_index++) {
struct blisp_segment_header segment_header = { 0 };
fread(&segment_header, 16, 1,
eflash_loader_file); // TODO: Error handling
ret = blisp_device_load_segment_header(&device, &segment_header);
if (ret != 0) {
fprintf(stderr, "Failed to load segment header.\n");
goto exit1;
}
printf("Flashing %d. segment\n", seg_index + 1);
printf("0b / %" PRIu32 "b (0.00%%)\n", segment_header.length);
while (sent_data < segment_header.length) {
buffer_size = segment_header.length - sent_data;
if (buffer_size > 4092) {
buffer_size = 4092;
ret = blisp_device_load_segment_header(&device, &segment_header);
if (ret != 0) {
fprintf(stderr, "Failed to load segment header.\n");
goto exit1;
}
printf("Flashing %d. segment\n", seg_index + 1);
printf("0b / %" PRIu32 "b (0.00%%)\n", segment_header.length);
while (sent_data < segment_header.length) {
buffer_size = segment_header.length - sent_data;
if (buffer_size > 4092) {
buffer_size = 4092;
}
fread(buffer, buffer_size, 1, eflash_loader_file);
ret = blisp_device_load_segment_data(
&device, buffer, buffer_size); // TODO: Error handling
if (ret < 0) {
fprintf(stderr, "Failed to load segment data. (ret %d)\n", ret);
goto exit1;
}
sent_data += buffer_size;
printf("%" PRIu32 "b / %" PRIu32 "b (%.2f%%)\n", sent_data,
segment_header.length,
(((float)sent_data / (float)segment_header.length)
* 100.0f));
}
fread(buffer, buffer_size, 1, eflash_loader_file);
blisp_device_load_segment_data(&device, buffer, buffer_size); // TODO: Error handling
sent_data += buffer_size;
printf("%" PRIu32 "b / %" PRIu32 "b (%.2f%%)\n", sent_data, segment_header.length,
(((float)sent_data / (float)segment_header.length) * 100.0f));
}
}
@ -162,6 +364,90 @@ void blisp_flash_firmware() {
goto exit1;
}
printf("Sending a handshake...");
ret = blisp_device_handshake(&device, true);
if (ret != 0) {
fprintf(stderr, "\nFailed to handshake with device.\n");
goto exit1;
}
printf(" OK\n");
eflash_loader:;
FILE* firmware_file = fopen(binary_to_write->filename[0], "rb");
if (firmware_file == NULL) {
fprintf(stderr,"Failed to open firmware file \"%s\".\n", binary_to_write->filename[0]);
goto exit1;
}
fseek(firmware_file, 0, SEEK_END);
int64_t firmware_file_size = ftell(firmware_file);
rewind(firmware_file);
struct bfl_boot_header boot_header;
fill_up_boot_header(&boot_header);
const uint32_t firmware_base_address = 0x2000;
printf("Erasing flash, this might take a while...");
ret = blisp_device_flash_erase(&device, firmware_base_address,
firmware_base_address + firmware_file_size
+ 1);
if (ret != 0) {
fprintf(stderr, "\nFailed to erase flash.\n");
goto exit2;
}
ret = blisp_device_flash_erase(&device, 0x0000, sizeof(struct bfl_boot_header));
if (ret != 0) {
fprintf(stderr, "\nFailed to erase flash.\n");
goto exit2;
}
printf(" OK!\nFlashing boot header...");
ret = blisp_device_flash_write(&device, 0x0000, (uint8_t*)&boot_header, sizeof(struct bfl_boot_header));
if (ret != 0) {
fprintf(stderr, "\nFailed to write boot header.\n");
goto exit2;
}
printf(" OK!\nFlashing the firmware...\n");
{
uint32_t sent_data = 0;
uint32_t buffer_size = 0;
uint8_t buffer[8184];
printf("0b / %ldb (0.00%%)\n", firmware_file_size);
while (sent_data < firmware_file_size) {
buffer_size = firmware_file_size - sent_data;
if (buffer_size > 2052) {
buffer_size = 2052;
}
fread(buffer, buffer_size, 1, firmware_file);
ret = blisp_device_flash_write(&device, firmware_base_address + sent_data, buffer, buffer_size); // TODO: Error handling
if (ret < 0) {
fprintf(stderr, "Failed to write firmware! (ret: %d)\n", ret);
goto exit2;
}
sent_data += buffer_size;
printf("%" PRIu32 "b / %ldb (%.2f%%)\n", sent_data, firmware_file_size,
(((float)sent_data / (float)firmware_file_size) * 100.0f));
}
}
printf("Checking program...");
ret = blisp_device_program_check(&device);
if (ret != 0) {
fprintf(stderr, "\nFailed to check program.\n");
goto exit2;
}
printf("OK\n");
if (reset->count > 0) {
blisp_device_reset(&device);
printf("Resetting the chip.\n");
// TODO: It seems that GPIO peripheral is not reset after resetting the chip
}
printf("Flash complete!\n");
exit2:
if (firmware_file != NULL) fclose(firmware_file);
exit1:
if (eflash_loader_file != NULL) fclose(eflash_loader_file);
blisp_device_close(&device);
@ -174,9 +460,10 @@ cmd_write_args_init() {
cmd_write_argtable[1] = chip_type = arg_str1("c", "chip", "<chip_type>", "Chip Type (bl70x)");
cmd_write_argtable[2] = port_name
= arg_str0("p", "port", "<port_name>", "Name/Path to the Serial Port (empty for search)");
cmd_write_argtable[3] = binary_to_write
cmd_write_argtable[3] = reset = arg_lit0(NULL, "reset", "Reset chip after write");
cmd_write_argtable[4] = binary_to_write
= arg_file1(NULL, NULL, "<input>", "Binary to write");
cmd_write_argtable[4] = end = arg_end(10);
cmd_write_argtable[5] = end = arg_end(10);
if (arg_nullcheck(cmd_write_argtable) != 0) {
fprintf(stderr, "insufficient memory\n");

View File

@ -1,3 +1,4 @@
// SPDX-License-Identifier: MIT
#include "argtable3.h"
#include "cmd.h"
#include <stdbool.h>