2022-11-30 12:17:30 +00:00
|
|
|
// SPDX-License-Identifier: MIT
|
2022-09-25 08:58:59 +00:00
|
|
|
#include <blisp.h>
|
2022-11-22 12:59:26 +00:00
|
|
|
#include <blisp_util.h>
|
2022-09-25 08:58:59 +00:00
|
|
|
#include <libserialport.h>
|
|
|
|
#include <stdio.h>
|
2023-01-07 10:50:51 +00:00
|
|
|
#include <stdlib.h>
|
2022-09-25 08:58:59 +00:00
|
|
|
#include <string.h>
|
2022-11-22 12:59:26 +00:00
|
|
|
|
|
|
|
#ifdef __linux__
|
|
|
|
#include <linux/serial.h>
|
|
|
|
#include <sys/ioctl.h>
|
|
|
|
#endif
|
2022-09-25 08:58:59 +00:00
|
|
|
|
2023-11-30 16:02:03 +00:00
|
|
|
#include <blisp_struct.h>
|
2023-11-30 07:43:57 +00:00
|
|
|
|
2022-11-07 09:20:38 +00:00
|
|
|
#define DEBUG
|
|
|
|
|
2023-02-06 18:47:39 +00:00
|
|
|
static void drain(struct sp_port* port) {
|
|
|
|
#if defined(__APPLE__) || defined(__FreeBSD__)
|
2023-05-08 21:39:34 +00:00
|
|
|
sp_drain(port);
|
2023-02-06 18:47:39 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2023-05-08 21:39:34 +00:00
|
|
|
blisp_return_t blisp_device_init(struct blisp_device* device,
|
|
|
|
struct blisp_chip* chip) {
|
2023-01-07 10:50:51 +00:00
|
|
|
device->chip = chip;
|
|
|
|
device->is_usb = false;
|
2023-11-30 16:02:03 +00:00
|
|
|
fill_crcs(&bl808_header);
|
2023-05-08 21:39:34 +00:00
|
|
|
return BLISP_OK;
|
2022-09-25 08:58:59 +00:00
|
|
|
}
|
|
|
|
|
2023-05-08 21:39:34 +00:00
|
|
|
blisp_return_t blisp_device_open(struct blisp_device* device,
|
|
|
|
const char* port_name) {
|
|
|
|
blisp_return_t ret;
|
2023-01-07 10:50:51 +00:00
|
|
|
struct sp_port* serial_port = NULL;
|
2022-09-25 08:58:59 +00:00
|
|
|
|
2023-01-07 10:50:51 +00:00
|
|
|
if (port_name != NULL) {
|
|
|
|
ret = sp_get_port_by_name(port_name, &serial_port);
|
|
|
|
if (ret != SP_OK) {
|
2023-01-07 12:34:33 +00:00
|
|
|
blisp_dlog("Couldn't open device, err: %d", ret);
|
|
|
|
return BLISP_ERR_CANT_OPEN_DEVICE;
|
2023-01-07 10:50:51 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (!device->chip->usb_isp_available) {
|
2023-01-07 12:34:33 +00:00
|
|
|
return BLISP_ERR_NO_AUTO_FIND_AVAILABLE;
|
2023-01-07 10:50:51 +00:00
|
|
|
}
|
|
|
|
struct sp_port** port_list;
|
|
|
|
ret = sp_list_ports(&port_list);
|
|
|
|
if (ret != SP_OK) {
|
2023-01-07 12:34:33 +00:00
|
|
|
blisp_dlog("Couldn't list ports, err: %d", ret);
|
2023-05-08 22:05:38 +00:00
|
|
|
return BLISP_ERR_DEVICE_NOT_FOUND;
|
2023-01-07 10:50:51 +00:00
|
|
|
}
|
|
|
|
for (int i = 0; port_list[i] != NULL; i++) {
|
|
|
|
struct sp_port* port = port_list[i];
|
|
|
|
|
|
|
|
int vid, pid;
|
|
|
|
sp_get_port_usb_vid_pid(port, &vid, &pid);
|
|
|
|
if (vid == 0xFFFF && pid == 0xFFFF) {
|
|
|
|
ret = sp_get_port_by_name(sp_get_port_name(port), &serial_port);
|
2022-09-25 08:58:59 +00:00
|
|
|
if (ret != SP_OK) {
|
2023-01-07 12:34:33 +00:00
|
|
|
blisp_dlog("Couldn't open device, err: %d", ret);
|
|
|
|
return BLISP_ERR_CANT_OPEN_DEVICE;
|
2022-09-25 08:58:59 +00:00
|
|
|
}
|
2023-01-07 10:50:51 +00:00
|
|
|
break;
|
|
|
|
}
|
2022-09-25 08:58:59 +00:00
|
|
|
}
|
2023-01-07 10:50:51 +00:00
|
|
|
sp_free_port_list(port_list);
|
|
|
|
if (serial_port == NULL) {
|
2023-01-07 12:34:33 +00:00
|
|
|
return BLISP_ERR_DEVICE_NOT_FOUND;
|
2022-09-25 08:58:59 +00:00
|
|
|
}
|
2023-01-07 10:50:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ret = sp_open(serial_port, SP_MODE_READ_WRITE);
|
2023-01-07 12:34:33 +00:00
|
|
|
if (ret != SP_OK) {
|
|
|
|
blisp_dlog("SP open failed: %d", ret);
|
2023-05-08 21:39:34 +00:00
|
|
|
return BLISP_ERR_CANT_OPEN_DEVICE;
|
2023-01-07 10:50:51 +00:00
|
|
|
}
|
2023-01-07 12:34:33 +00:00
|
|
|
// TODO: Handle errors in following functions, although, none of them *should*
|
|
|
|
// fail
|
2023-01-07 10:50:51 +00:00
|
|
|
sp_set_bits(serial_port, 8);
|
|
|
|
sp_set_parity(serial_port, SP_PARITY_NONE);
|
|
|
|
sp_set_stopbits(serial_port, 1);
|
|
|
|
sp_set_flowcontrol(serial_port, SP_FLOWCONTROL_NONE);
|
|
|
|
|
2023-02-06 17:55:59 +00:00
|
|
|
int vid, pid;
|
2023-01-07 10:50:51 +00:00
|
|
|
sp_get_port_usb_vid_pid(serial_port, &vid, &pid);
|
|
|
|
device->is_usb = pid == 0xFFFF;
|
2023-01-07 12:34:33 +00:00
|
|
|
// if (device->is_usb) {
|
|
|
|
// device->current_baud_rate = 2000000;
|
|
|
|
// } else {
|
2023-11-30 16:02:03 +00:00
|
|
|
if (device->chip->type == BLISP_CHIP_BL808) {
|
|
|
|
device->current_baud_rate = 2000000;
|
|
|
|
} else {
|
|
|
|
device->current_baud_rate = 460800;
|
|
|
|
}
|
2023-01-07 12:34:33 +00:00
|
|
|
// }
|
2022-11-22 12:59:26 +00:00
|
|
|
|
|
|
|
#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
|
2023-01-07 10:50:51 +00:00
|
|
|
ret = sp_set_baudrate(serial_port, device->current_baud_rate);
|
|
|
|
if (ret != SP_OK) {
|
2023-05-08 22:05:38 +00:00
|
|
|
blisp_dlog("Set baud rate failed: %d... Also hello MacOS user :)", ret);
|
|
|
|
return BLISP_ERR_API_ERROR;
|
2023-01-07 10:50:51 +00:00
|
|
|
}
|
|
|
|
device->serial_port = serial_port;
|
2022-11-08 21:06:14 +00:00
|
|
|
|
2023-01-07 12:34:33 +00:00
|
|
|
return BLISP_OK;
|
2022-09-25 08:58:59 +00:00
|
|
|
}
|
|
|
|
|
2023-05-08 21:39:34 +00:00
|
|
|
blisp_return_t blisp_send_command(struct blisp_device* device,
|
|
|
|
uint8_t command,
|
|
|
|
void* payload,
|
|
|
|
uint16_t payload_size,
|
|
|
|
bool add_checksum) {
|
2023-01-07 10:50:51 +00:00
|
|
|
int ret;
|
|
|
|
struct sp_port* serial_port = device->serial_port;
|
|
|
|
|
|
|
|
device->tx_buffer[0] = command;
|
|
|
|
device->tx_buffer[1] = 0;
|
|
|
|
device->tx_buffer[2] = payload_size & 0xFF;
|
|
|
|
device->tx_buffer[3] = (payload_size >> 8) & 0xFF;
|
|
|
|
if (add_checksum) {
|
|
|
|
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*)((uint8_t*)payload + i);
|
2022-09-25 08:58:59 +00:00
|
|
|
}
|
2023-01-07 10:50:51 +00:00
|
|
|
device->tx_buffer[1] = checksum & 0xFF;
|
|
|
|
}
|
|
|
|
if (payload_size != 0) {
|
|
|
|
memcpy(&device->tx_buffer[4], payload, payload_size);
|
|
|
|
}
|
|
|
|
ret =
|
|
|
|
sp_blocking_write(serial_port, device->tx_buffer, 4 + payload_size, 1000);
|
|
|
|
if (ret != (4 + payload_size)) {
|
2023-01-07 12:34:33 +00:00
|
|
|
blisp_dlog("Received error or not written all data: %d", ret);
|
2023-05-08 22:05:38 +00:00
|
|
|
return BLISP_ERR_API_ERROR;
|
2023-01-07 10:50:51 +00:00
|
|
|
}
|
2023-02-06 18:47:39 +00:00
|
|
|
drain(serial_port);
|
2023-01-21 13:34:46 +00:00
|
|
|
|
2023-01-07 12:34:33 +00:00
|
|
|
return BLISP_OK;
|
2022-09-25 08:58:59 +00:00
|
|
|
}
|
|
|
|
|
2023-05-08 21:39:34 +00:00
|
|
|
blisp_return_t blisp_receive_response(struct blisp_device* device,
|
|
|
|
bool expect_payload) {
|
2023-01-07 10:50:51 +00:00
|
|
|
// TODO: Check checksum
|
|
|
|
int ret;
|
2023-11-30 16:02:03 +00:00
|
|
|
uint32_t read_timeout = 1000;
|
|
|
|
if (device->chip->type == BLISP_CHIP_BL808) {
|
|
|
|
// TODO: For some reason the BL808 does not send pending ('PD') responses
|
|
|
|
// during long (i.e. erase) operations, so we must disable response
|
|
|
|
// timeouts. Further investigation is necessary.
|
|
|
|
read_timeout = 0;
|
|
|
|
}
|
|
|
|
|
2023-01-07 10:50:51 +00:00
|
|
|
struct sp_port* serial_port = device->serial_port;
|
2023-11-30 16:02:03 +00:00
|
|
|
ret = sp_blocking_read(serial_port, &device->rx_buffer[0], 2, read_timeout);
|
2023-01-07 10:50:51 +00:00
|
|
|
if (ret < 2) {
|
2023-01-07 12:34:33 +00:00
|
|
|
blisp_dlog("Failed to receive response, ret: %d", ret);
|
2023-05-08 22:05:38 +00:00
|
|
|
return BLISP_ERR_NO_RESPONSE;
|
2023-01-07 10:50:51 +00:00
|
|
|
} 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); // 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;
|
2022-09-25 08:58:59 +00:00
|
|
|
}
|
2023-01-07 10:50:51 +00:00
|
|
|
return 0;
|
|
|
|
} else if (device->rx_buffer[0] == 'P' && device->rx_buffer[1] == 'D') {
|
2023-01-07 12:34:33 +00:00
|
|
|
return BLISP_ERR_PENDING; // TODO: This might be rather positive return
|
|
|
|
// number?
|
2023-01-07 10:50:51 +00:00
|
|
|
} 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]);
|
2023-01-07 12:34:33 +00:00
|
|
|
blisp_dlog("Chip returned error: %d", device->error_code);
|
|
|
|
return BLISP_ERR_CHIP_ERR;
|
2023-01-07 10:50:51 +00:00
|
|
|
}
|
2023-01-07 12:34:33 +00:00
|
|
|
blisp_dlog("Failed to receive any response (err: %d, %d - %d)", ret,
|
|
|
|
device->rx_buffer[0], device->rx_buffer[1]);
|
2023-05-08 22:05:38 +00:00
|
|
|
return BLISP_ERR_NO_RESPONSE;
|
2022-09-25 08:58:59 +00:00
|
|
|
}
|
|
|
|
|
2023-05-08 21:39:34 +00:00
|
|
|
blisp_return_t blisp_device_handshake(struct blisp_device* device,
|
|
|
|
bool in_ef_loader) {
|
2023-01-07 10:50:51 +00:00
|
|
|
int ret;
|
2023-11-30 07:43:57 +00:00
|
|
|
bool ok = false;
|
2023-01-07 10:50:51 +00:00
|
|
|
uint8_t handshake_buffer[600];
|
|
|
|
struct sp_port* serial_port = device->serial_port;
|
|
|
|
|
|
|
|
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 (!in_ef_loader) {
|
|
|
|
if (device->is_usb) {
|
|
|
|
sp_blocking_write(serial_port, "BOUFFALOLAB5555RESET\0\0", 22, 100);
|
2023-02-06 18:47:39 +00:00
|
|
|
drain(serial_port);
|
2023-01-07 10:50:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
ret = sp_blocking_write(serial_port, handshake_buffer, bytes_count, 500);
|
2023-05-08 21:39:34 +00:00
|
|
|
// not sure about Apple part, but FreeBSD needs it
|
|
|
|
drain(serial_port);
|
2023-01-07 10:50:51 +00:00
|
|
|
if (ret < 0) {
|
2023-01-07 12:34:33 +00:00
|
|
|
blisp_dlog("Handshake write failed, ret %d", ret);
|
2023-05-08 22:05:38 +00:00
|
|
|
return BLISP_ERR_API_ERROR;
|
2023-01-07 10:50:51 +00:00
|
|
|
}
|
2022-09-25 08:58:59 +00:00
|
|
|
|
2022-11-09 19:16:08 +00:00
|
|
|
if (!in_ef_loader && !device->is_usb) {
|
2023-01-07 10:50:51 +00:00
|
|
|
sp_drain(serial_port); // Wait for write to send all data
|
|
|
|
sp_flush(serial_port, SP_BUF_INPUT); // Flush garbage out of RX
|
2022-11-09 19:16:08 +00:00
|
|
|
}
|
|
|
|
|
2023-11-30 04:48:47 +00:00
|
|
|
if (device->chip->type == BLISP_CHIP_BL808) {
|
2023-11-30 07:43:57 +00:00
|
|
|
sleep_ms(300);
|
|
|
|
const uint8_t second_handshake[] = { 0x50, 0x00, 0x08, 0x00, 0x38, 0xF0, 0x00, 0x20, 0x00, 0x00, 0x00, 0x18 };
|
|
|
|
ret = sp_blocking_write(serial_port, second_handshake, sizeof(second_handshake), 300);
|
|
|
|
if (ret < 0) {
|
|
|
|
blisp_dlog("Second handshake write failed, ret %d", ret);
|
|
|
|
return BLISP_ERR_API_ERROR;
|
|
|
|
}
|
2023-11-30 04:48:47 +00:00
|
|
|
}
|
2022-11-10 20:36:00 +00:00
|
|
|
|
2023-11-30 04:48:47 +00:00
|
|
|
ret = sp_blocking_read(serial_port, device->rx_buffer, 20, 50);
|
|
|
|
if (ret >= 2) {
|
2023-11-30 07:43:57 +00:00
|
|
|
for (uint8_t j = 0; j < (ret - 1); j++) {
|
|
|
|
if (device->rx_buffer[j] == 'O' && device->rx_buffer[j + 1] == 'K') {
|
|
|
|
ok = true;
|
2022-10-05 09:35:44 +00:00
|
|
|
}
|
2023-11-30 07:43:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!ok) {
|
|
|
|
blisp_dlog("Received no response from chip.");
|
|
|
|
return BLISP_ERR_NO_RESPONSE;
|
2022-09-25 08:58:59 +00:00
|
|
|
}
|
2023-11-30 07:43:57 +00:00
|
|
|
|
|
|
|
return BLISP_OK;
|
2023-01-07 10:50:51 +00:00
|
|
|
}
|
2022-09-25 08:58:59 +00:00
|
|
|
}
|
|
|
|
|
2023-05-08 21:39:34 +00:00
|
|
|
blisp_return_t blisp_device_get_boot_info(struct blisp_device* device,
|
|
|
|
struct blisp_boot_info* boot_info) {
|
|
|
|
blisp_return_t ret;
|
2022-09-25 08:58:59 +00:00
|
|
|
|
2023-01-07 10:50:51 +00:00
|
|
|
ret = blisp_send_command(device, 0x10, NULL, 0, false);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
2022-09-25 08:58:59 +00:00
|
|
|
|
2023-01-07 10:50:51 +00:00
|
|
|
ret = blisp_receive_response(device, true);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
2022-10-05 09:35:44 +00:00
|
|
|
|
2023-11-28 08:53:07 +00:00
|
|
|
memcpy(boot_info->boot_rom_version, &device->rx_buffer[0],
|
2023-05-08 21:39:34 +00:00
|
|
|
4); // TODO: Endianess; this may break on big endian machines
|
2022-11-10 20:36:00 +00:00
|
|
|
if (device->chip->type == BLISP_CHIP_BL70X || device->chip->type == BLISP_CHIP_BL808) { // TODO: This is only 70X related
|
2022-10-05 09:35:44 +00:00
|
|
|
memcpy(boot_info->chip_id, &device->rx_buffer[16], 8);
|
|
|
|
}
|
2022-11-10 20:36:00 +00:00
|
|
|
// TODO: BL60X, BL808
|
2023-11-28 08:53:07 +00:00
|
|
|
return BLISP_OK;
|
2022-10-05 09:35:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: Use struct instead of uint8_t*
|
2023-05-08 21:39:34 +00:00
|
|
|
blisp_return_t blisp_device_load_boot_header(struct blisp_device* device,
|
|
|
|
uint8_t* boot_header) {
|
|
|
|
blisp_return_t ret;
|
2023-01-07 10:50:51 +00:00
|
|
|
ret = blisp_send_command(device, 0x11, boot_header, 176, false);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
ret = blisp_receive_response(device, false);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
2022-10-05 09:35:44 +00:00
|
|
|
|
2023-01-07 12:34:33 +00:00
|
|
|
return BLISP_OK;
|
2022-10-05 09:35:44 +00:00
|
|
|
}
|
|
|
|
|
2023-05-08 21:39:34 +00:00
|
|
|
blisp_return_t blisp_device_load_segment_header(
|
2023-01-07 10:50:51 +00:00
|
|
|
struct blisp_device* device,
|
|
|
|
struct blisp_segment_header* segment_header) {
|
2023-05-08 21:39:34 +00:00
|
|
|
blisp_return_t ret;
|
2023-01-07 10:50:51 +00:00
|
|
|
ret = blisp_send_command(device, 0x17, segment_header, 16, false);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
ret = blisp_receive_response(device, true); // TODO: Handle response
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
2022-10-05 09:35:44 +00:00
|
|
|
|
2023-01-07 12:34:33 +00:00
|
|
|
return BLISP_OK;
|
2022-10-05 09:35:44 +00:00
|
|
|
}
|
|
|
|
|
2023-05-08 21:39:34 +00:00
|
|
|
blisp_return_t blisp_device_load_segment_data(struct blisp_device* device,
|
|
|
|
uint8_t* segment_data,
|
|
|
|
uint32_t segment_data_length) {
|
|
|
|
blisp_return_t ret;
|
2023-01-07 10:50:51 +00:00
|
|
|
ret = blisp_send_command(device, 0x18, segment_data, segment_data_length,
|
|
|
|
false);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
ret = blisp_receive_response(device, false);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
2022-10-05 09:35:44 +00:00
|
|
|
|
2023-01-07 12:34:33 +00:00
|
|
|
return BLISP_OK;
|
2022-10-05 09:35:44 +00:00
|
|
|
}
|
|
|
|
|
2023-05-08 21:39:34 +00:00
|
|
|
blisp_return_t blisp_device_check_image(struct blisp_device* device) {
|
|
|
|
blisp_return_t ret;
|
2023-01-07 10:50:51 +00:00
|
|
|
ret = blisp_send_command(device, 0x19, NULL, 0, false);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
ret = blisp_receive_response(device, false);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
2022-10-05 09:35:44 +00:00
|
|
|
|
2023-01-07 12:34:33 +00:00
|
|
|
return BLISP_OK;
|
2022-10-05 09:35:44 +00:00
|
|
|
}
|
|
|
|
|
2023-05-08 21:39:34 +00:00
|
|
|
blisp_return_t blisp_device_write_memory(struct blisp_device* device,
|
|
|
|
uint32_t address,
|
|
|
|
uint32_t value,
|
|
|
|
bool wait_for_res) {
|
|
|
|
blisp_return_t ret;
|
2023-01-07 10:50:51 +00:00
|
|
|
uint8_t payload[8];
|
|
|
|
*(uint32_t*)(payload) = address;
|
|
|
|
*(uint32_t*)(payload + 4) = value; // TODO: Endianness
|
|
|
|
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;
|
|
|
|
}
|
2022-10-05 09:35:44 +00:00
|
|
|
|
2023-01-07 12:34:33 +00:00
|
|
|
return BLISP_OK;
|
2022-10-05 09:35:44 +00:00
|
|
|
}
|
|
|
|
|
2023-05-08 21:39:34 +00:00
|
|
|
blisp_return_t blisp_device_run_image(struct blisp_device* device) {
|
|
|
|
blisp_return_t ret;
|
2023-01-07 10:50:51 +00:00
|
|
|
|
|
|
|
if (device->chip->type == BLISP_CHIP_BL70X) { // ERRATA
|
|
|
|
ret = blisp_device_write_memory(device, 0x4000F100, 0x4E424845, true);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
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, false);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
2023-01-07 12:34:33 +00:00
|
|
|
return BLISP_OK;
|
2023-01-07 10:50:51 +00:00
|
|
|
}
|
2022-10-05 09:35:44 +00:00
|
|
|
|
2023-01-07 10:50:51 +00:00
|
|
|
ret = blisp_send_command(device, 0x1A, NULL, 0, false);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
ret = blisp_receive_response(device, false);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
2022-09-25 08:58:59 +00:00
|
|
|
|
2023-01-07 12:34:33 +00:00
|
|
|
return BLISP_OK;
|
2022-09-25 08:58:59 +00:00
|
|
|
}
|
|
|
|
|
2023-05-08 21:39:34 +00:00
|
|
|
blisp_return_t blisp_device_flash_erase(struct blisp_device* device,
|
|
|
|
uint32_t start_address,
|
|
|
|
uint32_t end_address) {
|
2023-01-07 10:50:51 +00:00
|
|
|
uint8_t payload[8];
|
|
|
|
*(uint32_t*)(payload + 0) = start_address;
|
|
|
|
*(uint32_t*)(payload + 4) = end_address;
|
2022-11-08 18:35:51 +00:00
|
|
|
|
2023-05-08 21:39:34 +00:00
|
|
|
blisp_return_t ret = blisp_send_command(device, 0x30, payload, 8, true);
|
2023-11-30 16:02:03 +00:00
|
|
|
if (ret != BLISP_OK)
|
2023-01-07 10:50:51 +00:00
|
|
|
return ret;
|
|
|
|
do {
|
|
|
|
ret = blisp_receive_response(device, false);
|
2023-01-07 12:34:33 +00:00
|
|
|
} while (ret == BLISP_ERR_PENDING);
|
2022-11-08 18:35:51 +00:00
|
|
|
|
2023-11-30 16:02:03 +00:00
|
|
|
return ret;
|
2022-11-08 18:35:51 +00:00
|
|
|
}
|
|
|
|
|
2023-05-08 21:39:34 +00:00
|
|
|
blisp_return_t blisp_device_flash_write(struct blisp_device* device,
|
|
|
|
uint32_t start_address,
|
|
|
|
uint8_t* payload,
|
|
|
|
uint32_t payload_size) {
|
2023-01-07 10:50:51 +00:00
|
|
|
// TODO: Add max payload size (8184?)
|
2023-01-07 12:34:33 +00:00
|
|
|
// TODO: Don't use malloc + add check
|
2023-01-07 10:50:51 +00:00
|
|
|
|
2023-01-07 12:34:33 +00:00
|
|
|
uint8_t* buffer = malloc(4 + payload_size);
|
2023-01-07 10:50:51 +00:00
|
|
|
*((uint32_t*)(buffer)) = start_address;
|
|
|
|
memcpy(buffer + 4, payload, payload_size);
|
2023-05-08 21:39:34 +00:00
|
|
|
blisp_return_t ret =
|
|
|
|
blisp_send_command(device, 0x31, buffer, payload_size + 4, true);
|
2023-01-07 10:50:51 +00:00
|
|
|
if (ret < 0)
|
|
|
|
goto exit1;
|
|
|
|
ret = blisp_receive_response(device, false);
|
2022-11-08 18:35:51 +00:00
|
|
|
exit1:
|
2023-01-07 10:50:51 +00:00
|
|
|
free(buffer);
|
|
|
|
return ret;
|
2022-11-08 18:35:51 +00:00
|
|
|
}
|
|
|
|
|
2023-05-08 21:39:34 +00:00
|
|
|
blisp_return_t blisp_device_program_check(struct blisp_device* device) {
|
2023-01-07 10:50:51 +00:00
|
|
|
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;
|
2022-11-08 18:35:51 +00:00
|
|
|
|
2023-05-08 21:39:34 +00:00
|
|
|
return BLISP_OK;
|
2022-11-08 18:35:51 +00:00
|
|
|
}
|
|
|
|
|
2023-05-08 21:39:34 +00:00
|
|
|
blisp_return_t blisp_device_reset(struct blisp_device* device) {
|
|
|
|
blisp_return_t ret = blisp_send_command(device, 0x21, NULL, 0, true);
|
2023-01-07 10:50:51 +00:00
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
ret = blisp_receive_response(device, false);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
2022-11-08 18:35:51 +00:00
|
|
|
|
2023-01-07 12:34:33 +00:00
|
|
|
return BLISP_OK;
|
2022-11-08 18:35:51 +00:00
|
|
|
}
|
|
|
|
|
2023-01-07 10:50:51 +00:00
|
|
|
void blisp_device_close(struct blisp_device* device) {
|
|
|
|
struct sp_port* serial_port = device->serial_port;
|
|
|
|
sp_close(serial_port);
|
2023-11-28 08:53:07 +00:00
|
|
|
}
|
2023-11-30 07:43:57 +00:00
|
|
|
|
|
|
|
blisp_return_t bl808_load_clock_para(struct blisp_device* device,
|
|
|
|
bool irq_en, uint32_t baudrate) {
|
|
|
|
// XXX: this may be a good place to increase the baudrate for subsequent comms
|
2023-11-30 16:02:03 +00:00
|
|
|
const uint32_t clock_para_size = sizeof(struct bl808_boot_clk_cfg_t);
|
2023-11-30 07:43:57 +00:00
|
|
|
const uint32_t payload_size = 8 + clock_para_size;
|
|
|
|
uint8_t payload[payload_size] = {};
|
|
|
|
|
|
|
|
uint32_t irq_enable = irq_en ? 1 : 0;
|
|
|
|
memcpy(&payload[0], &irq_enable, 4);
|
|
|
|
memcpy(&payload[4], &baudrate, 4);
|
2023-11-30 16:02:03 +00:00
|
|
|
memcpy(&payload[8], &bl808_header.clk_cfg, clock_para_size);
|
2023-11-30 07:43:57 +00:00
|
|
|
|
|
|
|
blisp_return_t ret = blisp_send_command(device, 0x22, payload, payload_size, true);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
ret = blisp_receive_response(device, false);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
return BLISP_OK;
|
|
|
|
}
|
2023-11-30 16:02:03 +00:00
|
|
|
|
|
|
|
blisp_return_t bl808_load_flash_para(struct blisp_device* device) {
|
|
|
|
// TODO: I don't understand why these parameters are the way they are,
|
|
|
|
// but at least they are labeled. Also, flash_io_mode and flash_clk_delay
|
|
|
|
// seem to be duplicated in the main spi_flash_cfg_t struct?
|
|
|
|
uint8_t flash_pin = 0x4;
|
|
|
|
uint8_t flash_clk_cfg = 0x41;
|
|
|
|
uint8_t flash_io_mode = 0x01;
|
|
|
|
uint8_t flash_clk_delay = 0;
|
|
|
|
|
|
|
|
// Yes, these values are (slightly) different to the ones in blisp_chip_bl808.c
|
|
|
|
struct bl808_spi_flash_cfg_t cfg = {0};
|
|
|
|
cfg.ioMode = 0x04;
|
|
|
|
cfg.cReadSupport = 0x01;
|
|
|
|
cfg.clkDelay = 0;
|
|
|
|
cfg.clkInvert = 0;
|
|
|
|
cfg.resetEnCmd = 0x66;
|
|
|
|
cfg.resetCmd = 0x99;
|
|
|
|
cfg.resetCreadCmd = 0xff;
|
|
|
|
cfg.resetCreadCmdSize = 0x03;
|
|
|
|
cfg.jedecIdCmd = 0x9f;
|
|
|
|
cfg.jedecIdCmdDmyClk = 0;
|
|
|
|
cfg.enter32BitsAddrCmd = 0xb7;
|
|
|
|
cfg.exit32BitsAddrCmd = 0xe9;
|
|
|
|
cfg.sectorSize = 0x04;
|
|
|
|
cfg.mid = 0xef;
|
|
|
|
cfg.pageSize = 0x100;
|
|
|
|
cfg.chipEraseCmd = 0xc7;
|
|
|
|
cfg.sectorEraseCmd = 0x20;
|
|
|
|
cfg.blk32EraseCmd = 0x52;
|
|
|
|
cfg.blk64EraseCmd = 0xd8;
|
|
|
|
cfg.writeEnableCmd = 0x06;
|
|
|
|
cfg.pageProgramCmd = 0x02;
|
|
|
|
cfg.qpageProgramCmd = 0x32;
|
|
|
|
cfg.qppAddrMode = 0;
|
|
|
|
cfg.fastReadCmd = 0x0b;
|
|
|
|
cfg.frDmyClk = 0x01;
|
|
|
|
cfg.qpiFastReadCmd = 0x0b;
|
|
|
|
cfg.qpiFrDmyClk = 0x01;
|
|
|
|
cfg.fastReadDoCmd = 0x3b;
|
|
|
|
cfg.frDoDmyClk = 0x01;
|
|
|
|
cfg.fastReadDioCmd = 0xbb;
|
|
|
|
cfg.frDioDmyClk = 0;
|
|
|
|
cfg.fastReadQoCmd = 0x6b;
|
|
|
|
cfg.frQoDmyClk = 0x01;
|
|
|
|
cfg.fastReadQioCmd = 0xeb;
|
|
|
|
cfg.frQioDmyClk = 0x02;
|
|
|
|
cfg.qpiFastReadQioCmd = 0xeb;
|
|
|
|
cfg.qpiFrQioDmyClk = 0x02;
|
|
|
|
cfg.qpiPageProgramCmd = 0x02;
|
|
|
|
cfg.writeVregEnableCmd = 0x50;
|
|
|
|
cfg.wrEnableIndex = 0;
|
|
|
|
cfg.qeIndex = 0x01;
|
|
|
|
cfg.busyIndex = 0;
|
|
|
|
cfg.wrEnableBit = 0x01;
|
|
|
|
cfg.qeBit = 0x01;
|
|
|
|
cfg.busyBit = 0;
|
|
|
|
cfg.wrEnableWriteRegLen = 0x02;
|
|
|
|
cfg.wrEnableReadRegLen = 0x01;
|
|
|
|
cfg.qeWriteRegLen = 0x01;
|
|
|
|
cfg.qeReadRegLen = 0x01;
|
|
|
|
cfg.releasePowerDown = 0xab;
|
|
|
|
cfg.busyReadRegLen = 0x01;
|
|
|
|
cfg.readRegCmd[0] = 0x05;
|
|
|
|
cfg.readRegCmd[1] = 0x35;
|
|
|
|
cfg.readRegCmd[2] = 0;
|
|
|
|
cfg.readRegCmd[3] = 0;
|
|
|
|
cfg.writeRegCmd[0] = 0x01;
|
|
|
|
cfg.writeRegCmd[1] = 0x31;
|
|
|
|
cfg.writeRegCmd[2] = 0;
|
|
|
|
cfg.writeRegCmd[3] = 0;
|
|
|
|
cfg.enterQpi = 0x38;
|
|
|
|
cfg.exitQpi = 0xff;
|
|
|
|
cfg.cReadMode = 0xa0;
|
|
|
|
cfg.cRExit = 0xff;
|
|
|
|
cfg.burstWrapCmd = 0x77;
|
|
|
|
cfg.burstWrapCmdDmyClk = 0x03;
|
|
|
|
cfg.burstWrapDataMode = 0x02;
|
|
|
|
cfg.burstWrapData = 0x40;
|
|
|
|
cfg.deBurstWrapCmd = 0x77;
|
|
|
|
cfg.deBurstWrapCmdDmyClk = 0x03;
|
|
|
|
cfg.deBurstWrapDataMode = 0x02;
|
|
|
|
cfg.deBurstWrapData = 0xf0;
|
|
|
|
cfg.timeEsector = 0x12c;
|
|
|
|
cfg.timeE32k = 0x4b0;
|
|
|
|
cfg.timeE64k = 0x4b0;
|
|
|
|
cfg.timePagePgm = 0x05;
|
|
|
|
cfg.timeCe = 0x80e8;
|
|
|
|
cfg.pdDelay = 0x03;
|
|
|
|
cfg.qeData = 0;
|
|
|
|
|
|
|
|
const uint32_t payload_size = 4 + sizeof(struct bl808_spi_flash_cfg_t);
|
|
|
|
uint8_t payload[payload_size] = {};
|
|
|
|
payload[0] = flash_pin;
|
|
|
|
payload[1] = flash_clk_cfg;
|
|
|
|
payload[2] = flash_io_mode;
|
|
|
|
payload[3] = flash_clk_delay;
|
|
|
|
memcpy(&payload[4], &cfg, sizeof(struct bl808_spi_flash_cfg_t));
|
|
|
|
|
|
|
|
blisp_return_t ret = blisp_send_command(device, 0x3b, payload, payload_size, true);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
ret = blisp_receive_response(device, false);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
return BLISP_OK;
|
|
|
|
}
|