1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2025-01-05 04:50:57 +00:00

fixup! feat(core/prodtest): Add stwlc38 update from host feature [no changelog]

This commit is contained in:
kopecdav 2025-01-02 16:55:13 +01:00
parent e3845a6420
commit 19dba060c6
4 changed files with 213 additions and 148 deletions

View File

@ -972,14 +972,14 @@ void test_wpc(const char *args) {
stwlc38_init();
if (strcmp(args, "UPDATE") == 0) {
vcp_println("Trying to update WLC32 ... ");
vcp_println("Trying to update STWLC38 ... ");
uint32_t update_time_ms = systick_ms();
bool status = stwlc38_patch_and_config();
update_time_ms = systick_ms() - update_time_ms;
if (status == false) {
vcp_println("Some problem occured");
vcp_println("ERROR # Some problem occured");
} else {
vcp_println("WPC update completed {%d ms}", update_time_ms);
vcp_println("OK");

View File

@ -149,13 +149,15 @@ static i2c_status_t stwlc38_write_hw_register(i2c_bus_t *i2c_bus,
static i2c_status_t stwlc38_read_fw_register(i2c_bus_t *i2c_bus,
uint16_t address, uint8_t *data);
static i2c_status_t stwlc38_write_n_bytes(i2c_bus_t *i2c_bus, uint16_t address,
uint8_t *data, uint16_t size);
uint8_t *data, size_t size);
static i2c_status_t stwlc38_read_n_bytes(i2c_bus_t *i2c_bus, uint16_t address,
uint8_t *data, uint16_t size);
static int32_t stwlc38_nvm_write_sector(i2c_bus_t *i2c_bus, const uint8_t *data,
int32_t len, uint8_t sec_idx);
static int32_t stwlc38_nvm_write_bulk(i2c_bus_t *i2c_bus, const uint8_t *data,
int32_t len, uint8_t sec_idx);
uint8_t *data, size_t size);
static i2c_status_t stwlc38_nvm_write_sector(i2c_bus_t *i2c_bus,
const uint8_t *data, size_t size,
uint8_t sec_idx);
static i2c_status_t stwlc38_nvm_write_bulk(i2c_bus_t *i2c_bus,
const uint8_t *data, size_t size,
uint8_t sec_idx);
bool stwlc38_patch_and_config() {
stwlc38_driver_t *drv = &g_stwlc38_driver;
@ -180,9 +182,13 @@ bool stwlc38_patch_and_config() {
// Reset and disable NVM loading
status =
stwlc38_write_fw_register(drv->i2c_bus, STWLC38_FWREG_SYS_CMD_REG, 0x40);
if (status != I2C_STATUS_OK) {
return false;
}
systick_delay_ms(STWLC38_RESET_DELAY_MS);
// Check op mode again
status =
stwlc38_read_fw_register(drv->i2c_bus, STWLC38_FWREG_OP_MODE_REG, &reg);
if (status != I2C_STATUS_OK) {
@ -201,19 +207,20 @@ bool stwlc38_patch_and_config() {
}
// Write patch to NVM
int32_t ret = stwlc38_nvm_write_bulk(drv->i2c_bus, patch_data, NVM_PATCH_SIZE,
STWLC38_NVM_PATCH_START_SECTOR_INDEX);
if (ret) {
status = stwlc38_nvm_write_bulk(drv->i2c_bus, patch_data, NVM_PATCH_SIZE,
STWLC38_NVM_PATCH_START_SECTOR_INDEX);
if (status != I2C_STATUS_OK) {
return false;
}
// Write config to NVM
ret = stwlc38_nvm_write_bulk(drv->i2c_bus, cfg_data, NVM_CFG_SIZE,
STWLC38_NVM_CFG_START_SECTOR_INDEX);
if (ret) {
status = stwlc38_nvm_write_bulk(drv->i2c_bus, cfg_data, NVM_CFG_SIZE,
STWLC38_NVM_CFG_START_SECTOR_INDEX);
if (status != I2C_STATUS_OK) {
return false;
}
// Reset stwlc38
status =
stwlc38_write_hw_register(drv->i2c_bus, STWLC38_HWREG_RESET_REG, 0x01);
if (status != I2C_STATUS_OK) {
@ -571,17 +578,18 @@ static i2c_status_t stwlc38_write_fw_register(i2c_bus_t *i2c_bus,
i2c_status_t status;
i2c_op_t op[] = {
{.flags = I2C_FLAG_TX | I2C_FLAG_EMBED | I2C_FLAG_START | I2C_FLAG_STOP,
.size = 3,
.data = {(address) >> 8, (address) & 0xFF, value}},
{
.flags = I2C_FLAG_TX | I2C_FLAG_EMBED,
.size = 3,
.data = {(address) >> 8, (address) & 0xFF, value},
},
};
i2c_packet_t i2c_pkt = {.address = STWLC38_I2C_ADDRESS,
.context = NULL,
.callback = NULL,
.timeout = 0,
.ops = (i2c_op_t *)&op,
.op_count = 1};
i2c_packet_t i2c_pkt = {
.address = STWLC38_I2C_ADDRESS,
.ops = (i2c_op_t *)&op,
.op_count = ARRAY_LENGTH(op),
};
status = i2c_bus_submit_and_wait(i2c_bus, &i2c_pkt);
@ -591,17 +599,23 @@ static i2c_status_t stwlc38_write_fw_register(i2c_bus_t *i2c_bus,
static i2c_status_t stwlc38_read_fw_register(i2c_bus_t *i2c_bus,
uint16_t address, uint8_t *data) {
i2c_op_t op[] = {
{.flags = I2C_FLAG_TX | I2C_FLAG_EMBED | I2C_FLAG_START,
.size = 2,
.data = {address >> 8, address & 0xFF}},
{.flags = I2C_FLAG_RX | I2C_FLAG_STOP, .size = 1, .ptr = data}};
{
.flags = I2C_FLAG_TX | I2C_FLAG_EMBED,
.size = 2,
.data = {address >> 8, address & 0xFF},
},
{
.flags = I2C_FLAG_RX,
.size = 1,
.ptr = data,
},
};
i2c_packet_t i2c_pkt = {.address = STWLC38_I2C_ADDRESS,
.context = NULL,
.callback = NULL,
.timeout = 0,
.ops = (i2c_op_t *)&op,
.op_count = 2};
i2c_packet_t i2c_pkt = {
.address = STWLC38_I2C_ADDRESS,
.ops = (i2c_op_t *)&op,
.op_count = ARRAY_LENGTH(op),
};
i2c_status_t status = i2c_bus_submit_and_wait(i2c_bus, &i2c_pkt);
@ -610,67 +624,88 @@ static i2c_status_t stwlc38_read_fw_register(i2c_bus_t *i2c_bus,
static i2c_status_t stwlc38_write_hw_register(i2c_bus_t *i2c_bus,
uint32_t address, uint8_t value) {
i2c_op_t op[] = {{.flags = I2C_FLAG_TX | I2C_FLAG_EMBED | I2C_FLAG_START,
.size = 4,
.data = {(STWLC38_HWREG_CUT_ID_REG && 0xFF000000) >> 24,
(STWLC38_HWREG_CUT_ID_REG && 0x00FF0000) >> 16,
(STWLC38_HWREG_CUT_ID_REG && 0x0000FF00) >> 8,
(STWLC38_HWREG_CUT_ID_REG && 0x0000FF00) >> 8}},
{.flags = I2C_FLAG_TX | I2C_FLAG_EMBED | I2C_FLAG_STOP,
.size = 1,
.data = {value}}};
i2c_op_t op[] = {
{
.flags = I2C_FLAG_TX | I2C_FLAG_EMBED,
.size = 4,
.data =
{
(STWLC38_HWREG_CUT_ID_REG && 0xFF000000) >> 24,
(STWLC38_HWREG_CUT_ID_REG && 0x00FF0000) >> 16,
(STWLC38_HWREG_CUT_ID_REG && 0x0000FF00) >> 8,
(STWLC38_HWREG_CUT_ID_REG && 0x000000FF),
},
},
{
.flags = I2C_FLAG_TX | I2C_FLAG_EMBED,
.size = 1,
.data = {value},
},
};
i2c_packet_t i2c_pkt = {.address = STWLC38_I2C_ADDRESS,
.context = NULL,
.callback = NULL,
.timeout = 0,
.ops = (i2c_op_t *)&op,
.op_count = 2};
i2c_packet_t i2c_pkt = {
.address = STWLC38_I2C_ADDRESS,
.ops = (i2c_op_t *)&op,
.op_count = ARRAY_LENGTH(op),
};
i2c_status_t status = i2c_bus_submit_and_wait(i2c_bus, &i2c_pkt);
return status;
}
static i2c_status_t stwlc38_write_n_bytes(i2c_bus_t *i2c_bus, uint16_t address,
uint8_t *data, uint16_t len) {
uint8_t *data, size_t size) {
i2c_op_t op[] = {
{.flags = I2C_FLAG_TX | I2C_FLAG_EMBED | I2C_FLAG_START,
.size = 2,
.data = {(address) >> 8, (address) & 0xFF}},
{.flags = I2C_FLAG_TX | I2C_FLAG_STOP, .size = len, .ptr = data}};
{
.flags = I2C_FLAG_TX | I2C_FLAG_EMBED,
.size = 2,
.data = {(address) >> 8, (address) & 0xFF},
},
{
.flags = I2C_FLAG_TX,
.size = size,
.ptr = data,
},
};
i2c_packet_t i2c_pkt = {.address = STWLC38_I2C_ADDRESS,
.context = NULL,
.callback = NULL,
.timeout = 0,
.ops = (i2c_op_t *)&op,
.op_count = 2};
i2c_packet_t i2c_pkt = {
.address = STWLC38_I2C_ADDRESS,
.ops = (i2c_op_t *)&op,
.op_count = ARRAY_LENGTH(op),
};
i2c_status_t status = i2c_bus_submit_and_wait(i2c_bus, &i2c_pkt);
return status;
}
static i2c_status_t stwlc38_read_n_bytes(i2c_bus_t *i2c_bus, uint16_t address,
uint8_t *data, uint16_t len) {
uint8_t *data, size_t size) {
i2c_op_t op[] = {
{.flags = I2C_FLAG_TX | I2C_FLAG_EMBED | I2C_FLAG_START,
.size = 2,
.data = {(address) >> 8, (address) & 0xFF}},
{.flags = I2C_FLAG_RX | I2C_FLAG_STOP, .size = len, .ptr = data}};
{
.flags = I2C_FLAG_TX | I2C_FLAG_EMBED,
.size = 2,
.data = {(address) >> 8, (address) & 0xFF},
},
{
.flags = I2C_FLAG_RX,
.size = (uint16_t) size,
.ptr = data,
},
};
i2c_packet_t i2c_pkt = {.address = STWLC38_I2C_ADDRESS,
.context = NULL,
.callback = NULL,
.timeout = 0,
.ops = (i2c_op_t *)&op,
.op_count = 2};
i2c_packet_t i2c_pkt = {
.address = STWLC38_I2C_ADDRESS,
.ops = (i2c_op_t *)&op,
.op_count = ARRAY_LENGTH(op),
};
i2c_status_t status = i2c_bus_submit_and_wait(i2c_bus, &i2c_pkt);
return status;
}
static int32_t stwlc38_nvm_write_sector(i2c_bus_t *i2c_bus, const uint8_t *data,
int32_t len, uint8_t sec_idx) {
static i2c_status_t stwlc38_nvm_write_sector(i2c_bus_t *i2c_bus,
const uint8_t *data, size_t size,
uint8_t sec_idx) {
int32_t ret;
int32_t i;
int32_t timeout = 1;
@ -678,37 +713,58 @@ static int32_t stwlc38_nvm_write_sector(i2c_bus_t *i2c_bus, const uint8_t *data,
ret = stwlc38_write_fw_register(i2c_bus, STWLC38_FWREG_NVM_SEC_IDX_REG,
sec_idx);
ret |= stwlc38_write_fw_register(i2c_bus, STWLC38_FWREG_SYS_CMD_REG, 0x10);
if (ret != I2C_STATUS_OK) {
return ret;
}
int16_t remaining = (int16_t)len;
ret = stwlc38_write_fw_register(i2c_bus, STWLC38_FWREG_SYS_CMD_REG, 0x10);
if (ret != I2C_STATUS_OK) {
return ret;
}
size_t remaining = size;
int8_t chunk = 0;
while (remaining > 0) {
if (remaining > STWLC38_MAX_WRITE_CHUNK) {
ret |= stwlc38_write_n_bytes(
ret = stwlc38_write_n_bytes(
i2c_bus,
STWLC38_FWREG_AUX_DATA_00_REG + chunk * STWLC38_MAX_WRITE_CHUNK,
((uint8_t *)(data)) + chunk * STWLC38_MAX_WRITE_CHUNK,
STWLC38_MAX_WRITE_CHUNK);
if (ret != I2C_STATUS_OK) {
return ret;
}
remaining -= STWLC38_MAX_WRITE_CHUNK;
} else {
ret |= stwlc38_write_n_bytes(
ret = stwlc38_write_n_bytes(
i2c_bus,
STWLC38_FWREG_AUX_DATA_00_REG + chunk * STWLC38_MAX_WRITE_CHUNK,
((uint8_t *)data) + chunk * STWLC38_MAX_WRITE_CHUNK, remaining);
if (ret != I2C_STATUS_OK) {
return ret;
}
break;
}
chunk++;
}
ret |= stwlc38_write_fw_register(i2c_bus, STWLC38_FWREG_SYS_CMD_REG, 0x04);
if (ret) return ret;
ret = stwlc38_write_fw_register(i2c_bus, STWLC38_FWREG_SYS_CMD_REG, 0x04);
if (ret != I2C_STATUS_OK) {
return ret;
}
for (i = 0; i < STWLC38_NVM_WRITE_TIMEOUT; i++) {
systick_delay_ms(STWLC38_NVM_WRITE_INTERVAL_MS);
ret = stwlc38_read_fw_register(i2c_bus, STWLC38_FWREG_SYS_CMD_REG, &reg);
if (ret) return ret;
if (ret != I2C_STATUS_OK) {
return ret;
}
if ((reg & 0x04) == 0) {
timeout = 0;
break;
@ -716,13 +772,18 @@ static int32_t stwlc38_nvm_write_sector(i2c_bus_t *i2c_bus, const uint8_t *data,
}
ret = stwlc38_write_fw_register(i2c_bus, STWLC38_FWREG_SYS_CMD_REG, 0x20);
return timeout == 0 ? ret : STWLC38_ERR_TIMEOUT;
if (ret != I2C_STATUS_OK) {
return ret;
}
return timeout ? I2C_STATUS_TIMEOUT : I2C_STATUS_OK;
}
static int32_t stwlc38_nvm_write_bulk(i2c_bus_t *i2c_bus, const uint8_t *data,
int32_t len, uint8_t sec_idx) {
static i2c_status_t stwlc38_nvm_write_bulk(i2c_bus_t *i2c_bus,
const uint8_t *data, size_t size,
uint8_t sec_idx) {
int32_t ret;
int32_t remaining = len;
size_t remaining = size;
int32_t to_write_now = 0;
int32_t written_already = 0;
@ -733,13 +794,16 @@ static int32_t stwlc38_nvm_write_bulk(i2c_bus_t *i2c_bus, const uint8_t *data,
ret = stwlc38_nvm_write_sector(i2c_bus, data + written_already,
to_write_now, sec_idx);
if (ret) return ret;
if (ret != I2C_STATUS_OK) {
return ret;
}
remaining -= to_write_now;
written_already += to_write_now;
sec_idx++;
}
return 0;
return I2C_STATUS_OK;
}
#endif // KERNEL_MODE

View File

@ -22,73 +22,22 @@
#include <trezor_types.h>
/* Common_Definitions */
#define STWLC38_MAX_READ_CHUNK 500U
#define STWLC38_MAX_WRITE_CHUNK 250U
#define STWLC38_LOG_SIZE 1024U
#define STWLC38_GENERAL_POLLING_MS 50U
#define STWLC38_GENERAL_TIMEOUT 100U
#define STWLC38_RESET_DELAY_MS 50U
/* NVM Definitions */
#define STWLC38_NVM_WRITE_INTERVAL_MS 1U
#define STWLC38_NVM_WRITE_TIMEOUT 20U
#define STWLC38_NVM_UPDATE_MAX_RETRY 3U
#define STWLC38_NVM_SECTOR_BYTE_SIZE 256U
#define STWLC38_NVM_PATCH_START_SECTOR_INDEX 0U
#define STWLC38_NVM_CFG_START_SECTOR_INDEX 126U
#define STWLC38_NVM_PATCH_TOTAL_SECTOR 126U
#define STWLC38_NVM_CFG_TOTAL_SECTOR 2U
#define STWLC38_NVM_PATCH_SIZE \
(STWLC38_NVM_PATCH_TOTAL_SECTOR * STWLC38_NVM_SECTOR_BYTE_SIZE)
#define STWLC38_NVM_CFG_SIZE \
(STWLC38_NVM_CFG_TOTAL_SECTOR * STWLC38_NVM_SECTOR_BYTE_SIZE)
/* HW Registers */
#define STWLC38_OPCODE_WRITE 0xFA
#define STWLC38_OPCODE_SIZE 1U
#define STWLC38_HWREG_CUT_ID_REG 0x2001C002U
#define STWLC38_HWREG_RESET_REG 0x2001F200U
/* FW Registers */
#define STWLC38_FWREG_CHIP_ID_REG 0x0000U
#define STWLC38_FWREG_OP_MODE_REG 0x000EU
#define STWLC38_FWREG_DEVICE_ID_REG 0x0010U
#define STWLC38_FWREG_SYS_CMD_REG 0x0020U
#define STWLC38_FWREG_NVM_PWD_REG 0x0022U
#define STWLC38_FWREG_NVM_SEC_IDX_REG 0x0024U
#define STWLC38_FWREG_SYS_ERR_REG 0x002CU
#define STWLC38_FWREG_AUX_DATA_00_REG 0x0180U
#define STWLC38_OK 0x0U
#define STWLC38_ERR_BUS_W 0x80000000U
#define STWLC38_ERR_BUS_WR 0x80000001U
#define STWLC38_ERR_ALLOC_MEM 0x80000002U
#define STWLC38_ERR_INVALID_PARAM 0x80000003U
#define STWLC38_ERR_TIMEOUT 0x80000004U
#define STWLC38_ERR_INVALID_OP_MODE 0x80000005U
#define STWLC38_ERR_INVALID_CHIP_ID 0x80000006U
#define STWLC38_ERR_NVM_ID_MISMATCH 0x80000007U
#define STWLC38_ERR_NVM_DATA_CORRUPTED 0x80000008U
enum stwlc38_op_mode {
typedef enum {
OP_MODE_SA = 1,
OP_MODE_RX = 2,
OP_MODE_TX = 3,
};
} stwlc38_op_mode_t;
typedef struct {
uint16_t chip_id; // Chip ID
uint8_t chip_rev; // Chip Revision
uint8_t cust_id; // Customer ID
uint16_t rom_id; // ROM ID
uint16_t patch_id; // Patch ID
uint16_t cfg_id; // Config ID
uint16_t pe_id; // Production ID
uint8_t op_mode; // Operation mode
uint8_t device_id[16]; // Device ID
uint16_t chip_id; // Chip ID
uint8_t chip_rev; // Chip Revision
uint8_t cust_id; // Customer ID
uint16_t rom_id; // ROM ID
uint16_t patch_id; // Patch ID
uint16_t cfg_id; // Config ID
uint16_t pe_id; // Production ID
stwlc38_op_mode_t op_mode; // Operation mode
uint8_t device_id[16]; // Device ID
union {
uint32_t sys_err; // System error
struct {

View File

@ -44,4 +44,56 @@
#define STWLC38_REG_RXINT_STATUS1 0x8D
#define STWLC38_REG_RXINT_STATUS2 0x8E
// Common_Definitions
#define STWLC38_MAX_READ_CHUNK 500U
#define STWLC38_MAX_WRITE_CHUNK 250U
#define STWLC38_LOG_SIZE 1024U
#define STWLC38_GENERAL_POLLING_MS 50U
#define STWLC38_GENERAL_TIMEOUT 100U
#define STWLC38_RESET_DELAY_MS 50U
// NVM Definitions
#define STWLC38_NVM_WRITE_INTERVAL_MS 1U
#define STWLC38_NVM_WRITE_TIMEOUT 20U
#define STWLC38_NVM_UPDATE_MAX_RETRY 3U
#define STWLC38_NVM_SECTOR_BYTE_SIZE 256U
#define STWLC38_NVM_PATCH_START_SECTOR_INDEX 0U
#define STWLC38_NVM_CFG_START_SECTOR_INDEX 126U
#define STWLC38_NVM_PATCH_TOTAL_SECTOR 126U
#define STWLC38_NVM_CFG_TOTAL_SECTOR 2U
#define STWLC38_NVM_PATCH_SIZE \
(STWLC38_NVM_PATCH_TOTAL_SECTOR * STWLC38_NVM_SECTOR_BYTE_SIZE)
#define STWLC38_NVM_CFG_SIZE \
(STWLC38_NVM_CFG_TOTAL_SECTOR * STWLC38_NVM_SECTOR_BYTE_SIZE)
// HW Registers
#define STWLC38_OPCODE_WRITE 0xFA
#define STWLC38_OPCODE_SIZE 1U
#define STWLC38_HWREG_CUT_ID_REG 0x2001C002U
#define STWLC38_HWREG_RESET_REG 0x2001F200U
// FW Registers
#define STWLC38_FWREG_CHIP_ID_REG 0x0000U
#define STWLC38_FWREG_OP_MODE_REG 0x000EU
#define STWLC38_FWREG_DEVICE_ID_REG 0x0010U
#define STWLC38_FWREG_SYS_CMD_REG 0x0020U
#define STWLC38_FWREG_NVM_PWD_REG 0x0022U
#define STWLC38_FWREG_NVM_SEC_IDX_REG 0x0024U
#define STWLC38_FWREG_SYS_ERR_REG 0x002CU
#define STWLC38_FWREG_AUX_DATA_00_REG 0x0180U
// STWLC38 driver error codes
#define STWLC38_OK 0x0U
#define STWLC38_ERR_BUS_W 0x80000000U
#define STWLC38_ERR_BUS_WR 0x80000001U
#define STWLC38_ERR_ALLOC_MEM 0x80000002U
#define STWLC38_ERR_INVALID_PARAM 0x80000003U
#define STWLC38_ERR_TIMEOUT 0x80000004U
#define STWLC38_ERR_INVALID_OP_MODE 0x80000005U
#define STWLC38_ERR_INVALID_CHIP_ID 0x80000006U
#define STWLC38_ERR_NVM_ID_MISMATCH 0x80000007U
#define STWLC38_ERR_NVM_DATA_CORRUPTED 0x80000008U
#endif // TREZORHAL_STWLC38_DEFS_H