diff --git a/core/embed/projects/prodtest/main.c b/core/embed/projects/prodtest/main.c index 5a3f4f0367..b29cebb4ec 100644 --- a/core/embed/projects/prodtest/main.c +++ b/core/embed/projects/prodtest/main.c @@ -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"); diff --git a/core/embed/sys/powerctl/stwlc38/stwlc38.c b/core/embed/sys/powerctl/stwlc38/stwlc38.c index 8c0a8b87d1..92d684bf1f 100644 --- a/core/embed/sys/powerctl/stwlc38/stwlc38.c +++ b/core/embed/sys/powerctl/stwlc38/stwlc38.c @@ -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, ®); 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, ®); - 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 diff --git a/core/embed/sys/powerctl/stwlc38/stwlc38.h b/core/embed/sys/powerctl/stwlc38/stwlc38.h index ce8b69525b..5aed0cb062 100644 --- a/core/embed/sys/powerctl/stwlc38/stwlc38.h +++ b/core/embed/sys/powerctl/stwlc38/stwlc38.h @@ -22,73 +22,22 @@ #include -/* 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 { diff --git a/core/embed/sys/powerctl/stwlc38/stwlc38_defs.h b/core/embed/sys/powerctl/stwlc38/stwlc38_defs.h index a537362f46..096c1f510b 100644 --- a/core/embed/sys/powerctl/stwlc38/stwlc38_defs.h +++ b/core/embed/sys/powerctl/stwlc38/stwlc38_defs.h @@ -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