mirror of
https://github.com/pine64/blisp.git
synced 2025-01-22 05:30:18 +00:00
Merge branch 'master' into write
This commit is contained in:
commit
4609916981
3
.gitignore
vendored
3
.gitignore
vendored
@ -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/
|
||||
|
@ -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
21
LICENSE
Normal 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
140
README.md
@ -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
|
||||
|
@ -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
|
@ -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
173
include/blisp_struct.h
Normal 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
22
include/blisp_util.h
Normal 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
|
162
lib/blisp.c
162
lib/blisp.c
@ -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;
|
||||
|
10
lib/chip/blisp_chip_bl60x.c
Normal file
10
lib/chip/blisp_chip_bl60x.c
Normal 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,
|
||||
};
|
@ -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,
|
||||
};
|
||||
|
@ -10,3 +10,6 @@ target_link_libraries(blisp PRIVATE
|
||||
argtable3
|
||||
libblisp_static)
|
||||
|
||||
if(WIN32)
|
||||
target_link_libraries(blisp PRIVATE Setupapi.lib)
|
||||
endif()
|
@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#ifndef BLISP_CMD_H
|
||||
#define BLISP_CMD_H
|
||||
|
||||
|
@ -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");
|
||||
|
@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include "argtable3.h"
|
||||
#include "cmd.h"
|
||||
#include <stdbool.h>
|
||||
|
Loading…
Reference in New Issue
Block a user