diff options
-rw-r--r-- | util/ec_sb_firmware_update.c | 324 | ||||
-rw-r--r-- | util/ec_sb_firmware_update.h | 41 |
2 files changed, 221 insertions, 144 deletions
diff --git a/util/ec_sb_firmware_update.c b/util/ec_sb_firmware_update.c index 982a2e66b6..69c8d657c9 100644 --- a/util/ec_sb_firmware_update.c +++ b/util/ec_sb_firmware_update.c @@ -25,17 +25,21 @@ /* Debug EC Smart Battery Firmwarwe Update */ static int debug; -/* - * Simplo Battery: Required 10 seconds delay for 1st 10 block write - * unit in seconds - */ -static int delay_x_us = 9000000; +enum { + BEGIN_DELAY = 0, + SETUP_DELAY = 1, + WRITE_DELAY = 2, + END_DELAY = 3, + NUM_DELAYS = 4 +}; -/* - * Simplo Battery: Additional delays are required after each 32-byte write - * unit in useconds - */ -static int delay_y_us = 50000; +const char *delay_names[NUM_DELAYS] = { + "BEGIN", + "SETUP", + "WRITE", + "END" +}; +uint32_t delay_values[NUM_DELAYS]; enum fw_update_state { S0_READ_STATUS = 0, @@ -51,9 +55,10 @@ enum fw_update_state { S10_TERMINAL = 10 }; +#define MAX_FW_IMAGE_NAME_SIZE 80 struct fw_update_ctrl { int size; /* size of battery firmware image */ - char *ptr; /* current pointer to the firmware image */ + char *ptr; /* current read pointer of the firmware image */ int offset; /* current block write offset */ struct sb_fw_header *fw_img_hdr; /*pointer to firmware image header*/ struct sb_fw_update_status status; @@ -63,6 +68,7 @@ struct fw_update_ctrl { int busy_retry_cnt; int step_size; int rv; + char image_name[MAX_FW_IMAGE_NAME_SIZE]; char msg[256]; }; @@ -71,6 +77,38 @@ struct fw_update_ctrl { */ static struct fw_update_ctrl fw_update; +static int get_key_value(const char *filename, + const char *keys[], uint32_t values[], int len) +{ + char line[256]; + char cmd[80]; + int i = BEGIN_DELAY; + FILE *fp = fopen(filename, "r"); + + values[BEGIN_DELAY] = 500000; + values[SETUP_DELAY] = 9000000; + values[WRITE_DELAY] = 500000; + values[END_DELAY] = 1000000; + + if (fp == NULL) + return -1; + + while (fgets(line, sizeof(line), fp) != NULL) { + if ((line[0] < 'A') || (line[0] > 'Z')) + continue; + + sprintf(cmd, "%s=%%d", keys[i]); + sscanf(line, cmd, &values[i]); + + if (++i == NUM_DELAYS) + break; + } + + fclose(fp); + return 0; +} + + static void print_battery_firmware_image_hdr( struct sb_fw_header *hdr) { @@ -170,7 +208,7 @@ static int check_battery_firmware_ids( /* check_if_need_update_fw * @return 1 (true) if need; 0 (false) if not. */ -static int check_if_need_update_fw( +static int check_if_valid_fw( struct sb_fw_header *hdr, struct sb_fw_update_info *info) { @@ -178,11 +216,59 @@ static int check_if_need_update_fw( && check_battery_firmware_ids(hdr, info) - && check_battery_firmware_image_version(hdr, info) - && check_battery_firmware_image_checksum(hdr); } +/* check_if_need_update_fw + * @return 1 (true) if need; 0 (false) if not. + */ +static int check_if_need_update_fw( + struct sb_fw_header *hdr, + struct sb_fw_update_info *info) +{ + return check_battery_firmware_image_version(hdr, info); +} + +static void log_msg(struct fw_update_ctrl *fw_update, + enum fw_update_state state, const char *msg) +{ + sprintf(fw_update->msg, + "Battery Firmware Updater State:%d %s", state, msg); +} + + +static char *read_fw_image(struct fw_update_ctrl *fw_update) +{ + int size; + char *buf; + fw_update->size = 0; + fw_update->ptr = NULL; + fw_update->fw_img_hdr = (struct sb_fw_header *)NULL; + + /* Read the input file */ + buf = read_file(fw_update->image_name, &size); + if (!buf) + return NULL; + + fw_update->size = size; + fw_update->ptr = buf; + fw_update->fw_img_hdr = (struct sb_fw_header *)buf; + if (debug) + print_battery_firmware_image_hdr(fw_update->fw_img_hdr); + + if (fw_update->fw_img_hdr->fw_binary_offset >= fw_update->size || + fw_update->size < 256) { + fprintf(stderr, + "Load Firmware Image[%s] Error offset:%d size:%d\n", + fw_update->image_name, + fw_update->fw_img_hdr->fw_binary_offset, + fw_update->size); + free(buf); + return NULL; + } + return buf; +} + static int get_status(struct sb_fw_update_status *status) { int rv = EC_RES_SUCCESS; @@ -200,11 +286,9 @@ static int get_status(struct sb_fw_update_status *status) resp, SB_FW_UPDATE_CMD_STATUS_SIZE); } while ((rv < 0) && (i++ < 3)); - if (rv < 0) { - fprintf(stderr, - "Firmware Update Get Status Error\n"); + if (rv < 0) return -EC_RES_ERROR; - } + memcpy(status, resp->status.data, SB_FW_UPDATE_CMD_STATUS_SIZE); return EC_RES_SUCCESS; } @@ -284,8 +368,7 @@ static enum fw_update_state s0_read_status(struct fw_update_ctrl *fw_update) { if (fw_update->busy_retry_cnt == 0) { fw_update->rv = -1; - sprintf(fw_update->msg, - "Firmware Udpate interface busy retry error!\n"); + log_msg(fw_update, S0_READ_STATUS, "Busy"); return S10_TERMINAL; } @@ -294,8 +377,7 @@ static enum fw_update_state s0_read_status(struct fw_update_ctrl *fw_update) fw_update->rv = get_status(&fw_update->status); if (fw_update->rv) { fw_update->rv = -1; - sprintf(fw_update->msg, - "Firmware Udpate interface protected!\n"); + log_msg(fw_update, S0_READ_STATUS, "Protected"); return S10_TERMINAL; } @@ -304,13 +386,13 @@ static enum fw_update_state s0_read_status(struct fw_update_ctrl *fw_update) if (!((fw_update->status.abnormal_condition == 0) && (fw_update->status.fw_update_supported == 1))) { - sprintf(fw_update->msg, - "Firmware Udpate is not supported!\n"); + log_msg(fw_update, S0_READ_STATUS, "Unsupported"); return S10_TERMINAL; } - if (fw_update->status.busy) + if (fw_update->status.busy) { + usleep(1000000); return S0_READ_STATUS; - else + } else return S1_READ_INFO; } @@ -320,8 +402,7 @@ static enum fw_update_state s1_read_battery_info( int rv; if (fw_update->err_retry_cnt == 0) { fw_update->rv = -1; - sprintf(fw_update->msg, - "Firmware Udpate interface busy retry error!\n"); + log_msg(fw_update, S1_READ_INFO, "Retry Error"); return S10_TERMINAL; } @@ -330,6 +411,29 @@ static enum fw_update_state s1_read_battery_info( rv = get_info(&fw_update->info); if (rv) { fw_update->rv = -1; + log_msg(fw_update, S1_READ_INFO, "Interface Error"); + return S10_TERMINAL; + } + + sprintf(fw_update->image_name, + "/lib/firmware/battery/maker.%04X.hwid.%04X.cfg", + fw_update->info.maker_id, + fw_update->info.hardware_id); + if (-1 == get_key_value(fw_update->image_name, + delay_names, delay_values, NUM_DELAYS)) { + fw_update->rv = 0; + log_msg(fw_update, S1_READ_INFO, "Open Config File"); + return S10_TERMINAL; + } + + sprintf(fw_update->image_name, + "/lib/firmware/battery/maker.%04X.hwid.%04X.bin", + fw_update->info.maker_id, + fw_update->info.hardware_id); + + if (NULL == read_fw_image(fw_update)) { + fw_update->rv = 0; + log_msg(fw_update, S1_READ_INFO, "Open Image File"); return S10_TERMINAL; } @@ -339,15 +443,25 @@ static enum fw_update_state s1_read_battery_info( rv = get_status(&fw_update->status); if (rv) { fw_update->rv = -1; + log_msg(fw_update, S1_READ_INFO, "Interface Error"); return S10_TERMINAL; } - rv = check_if_need_update_fw(fw_update->fw_img_hdr, &fw_update->info); + rv = check_if_valid_fw(fw_update->fw_img_hdr, &fw_update->info); if (rv == 0) { - printf("ERROR:Battery firmware is not valid!\n"); print_info(&fw_update->info); print_battery_firmware_image_hdr(fw_update->fw_img_hdr); fw_update->rv = EC_RES_INVALID_PARAM; + log_msg(fw_update, S1_READ_INFO, "Invalid Firmware"); + return S10_TERMINAL; + } + + rv = check_if_need_update_fw(fw_update->fw_img_hdr, &fw_update->info); + if (rv == 0) { + print_info(&fw_update->info); + print_battery_firmware_image_hdr(fw_update->fw_img_hdr); + fw_update->rv = 0; + log_msg(fw_update, S1_READ_INFO, "Latest Firmware"); return S10_TERMINAL; } return S2_WRITE_PREPARE; @@ -356,10 +470,10 @@ static enum fw_update_state s1_read_battery_info( static enum fw_update_state s2_write_prepare(struct fw_update_ctrl *fw_update) { int rv; - DPRINTF("cmd.0x35 write word 0x1000\n"); rv = send_subcmd(EC_SB_FW_UPDATE_PREPARE); if (rv) { fw_update->rv = -1; + log_msg(fw_update, S2_WRITE_PREPARE, "Interface Error"); return S10_TERMINAL; } return S3_READ_STATUS; @@ -371,6 +485,7 @@ static enum fw_update_state s3_read_status(struct fw_update_ctrl *fw_update) rv = get_status(&fw_update->status); if (rv) { fw_update->rv = -1; + log_msg(fw_update, S3_READ_STATUS, "Interface Error"); return S10_TERMINAL; } return S4_WRITE_UPDATE; @@ -380,13 +495,13 @@ static enum fw_update_state s3_read_status(struct fw_update_ctrl *fw_update) static enum fw_update_state s4_write_update(struct fw_update_ctrl *fw_update) { int rv; - DPRINTF("cmd.0x35 write word 0xF000\n"); rv = send_subcmd(EC_SB_FW_UPDATE_BEGIN); if (rv) { fw_update->rv = -1; + log_msg(fw_update, S4_WRITE_UPDATE, "Interface Error"); return S10_TERMINAL; } - usleep(500000); + usleep(delay_values[BEGIN_DELAY]); return S5_READ_STATUS; } @@ -395,6 +510,7 @@ static enum fw_update_state s5_read_status(struct fw_update_ctrl *fw_update) int rv = get_status(&fw_update->status); if (rv) { fw_update->rv = -1; + log_msg(fw_update, S5_READ_STATUS, "Interface Error"); return S10_TERMINAL; } if (fw_update->status.fw_update_mode == 0) @@ -429,6 +545,7 @@ static enum fw_update_state s6_write_block(struct fw_update_ctrl *fw_update) if (fw_update->fec_err_retry_cnt == 0) { fw_update->rv = -1; + log_msg(fw_update, S6_WRITE_BLOCK, "FEC Retry Error"); return S10_TERMINAL; } fw_update->fec_err_retry_cnt--; @@ -436,15 +553,14 @@ static enum fw_update_state s6_write_block(struct fw_update_ctrl *fw_update) rv = write_block(fw_update->ptr+offset, bsize); if (rv) { fw_update->rv = -1; + log_msg(fw_update, S6_WRITE_BLOCK, "Interface Error"); return S10_TERMINAL; } - if (delay_x_us || delay_y_us) { - if (offset <= fw_update->step_size * 10) - usleep(delay_x_us); - else - usleep(delay_y_us); - } + if (offset <= fw_update->step_size * 10) + usleep(delay_values[SETUP_DELAY]); + else + usleep(delay_values[WRITE_DELAY]); return S7_READ_STATUS; } @@ -461,6 +577,7 @@ static enum fw_update_state s7_read_status(struct fw_update_ctrl *fw_update) dump_data(fw_update->ptr+offset, offset, bsize); print_status(&fw_update->status); fw_update->rv = -1; + log_msg(fw_update, S7_READ_STATUS, "Interface Error"); return S10_TERMINAL; } } while (fw_update->status.busy); @@ -468,32 +585,28 @@ static enum fw_update_state s7_read_status(struct fw_update_ctrl *fw_update) if (fw_update->status.fec_error) { dump_data(fw_update->ptr+offset, offset, bsize); print_status(&fw_update->status); - fw_update->rv = -1; + fw_update->rv = 0; return S6_WRITE_BLOCK; } - if (fw_update->status.fw_fatal_error) { - dump_data(fw_update->ptr+offset, offset, bsize); - print_status(&fw_update->status); - fw_update->rv = -1; - return S2_WRITE_PREPARE; - } if (fw_update->status.permanent_failure || fw_update->status.v_fail_permanent) { dump_data(fw_update->ptr+offset, offset, bsize); print_status(&fw_update->status); fw_update->rv = -1; + log_msg(fw_update, S7_READ_STATUS, "Battery Permanent Error"); return S8_WRITE_END; } if (fw_update->status.v_fail_maker_id || - fw_update->status.v_fail_hw_id || + fw_update->status.v_fail_hw_id || fw_update->status.v_fail_fw_version || - fw_update->status.fw_corrupted || + fw_update->status.fw_corrupted || fw_update->status.cmd_reject || - fw_update->status.invalid_data) { + fw_update->status.invalid_data || + fw_update->status.fw_fatal_error) { dump_data(fw_update->ptr+offset, offset, bsize); print_status(&fw_update->status); - fw_update->rv = -1; + fw_update->rv = 0; return S1_READ_INFO; } @@ -507,14 +620,16 @@ static enum fw_update_state s8_write_end(struct fw_update_ctrl *fw_update) { int rv; rv = send_subcmd(EC_SB_FW_UPDATE_END); - if (rv) { + if (rv && (0 == fw_update->rv)) { fw_update->rv = -1; - sprintf(fw_update->msg, "SB FW Update End Error\n"); - return S10_TERMINAL; + log_msg(fw_update, S8_WRITE_END, "Interface Error"); } + if (fw_update->rv) + return S10_TERMINAL; + /* Note: Sleep is required! */ - usleep(1000000); + usleep(delay_values[END_DELAY]); return S9_READ_STATUS; } @@ -525,14 +640,14 @@ static enum fw_update_state s9_read_status(struct fw_update_ctrl *fw_update) rv = get_status(&fw_update->status); if (rv) { fw_update->rv = -1; - sprintf(fw_update->msg, - "SB FW Update End get status Error: rv:%d\n", rv); + log_msg(fw_update, S9_READ_STATUS, "Interface Error"); return S10_TERMINAL; } if ((fw_update->status.fw_update_mode == 1) || (fw_update->status.busy == 1)) { return S9_READ_STATUS; } + log_msg(fw_update, S9_READ_STATUS, "Complete"); return S10_TERMINAL; } @@ -552,57 +667,31 @@ fw_state_func state_table[] = { s9_read_status }; -int ec_sb_firmware_update(const char *fw_image_name) + +/** + * Update Smart Battery Firmware + * + * @param fw_update struct fw_update_ctrl + * + * @return 0 if success, negative if error. + */ +static int ec_sb_firmware_update(struct fw_update_ctrl *fw_update) { enum fw_update_state state; - int size; - char *buf; - - fw_update.err_retry_cnt = SB_FW_UPDATE_ERROR_RETRY_CNT; - fw_update.fec_err_retry_cnt = SB_FW_UPDATE_FEC_ERROR_RETRY_CNT; - fw_update.busy_retry_cnt = SB_FW_UPDATE_BUSY_ERROR_RETRY_CNT; - fw_update.step_size = SB_FW_UPDATE_CMD_WRITE_BLOCK_SIZE; - - /* Read the input file */ - DPRINTF("\n\n==> Read File:%s\n", fw_image_name); - buf = read_file(fw_image_name, &size); - if (!buf) { - fprintf(stderr, - "Firmware Update: Load Firmware Image[%s] Error\n", - fw_image_name); - return -1; - } - fw_update.size = size; - fw_update.ptr = buf; - fw_update.fw_img_hdr = (struct sb_fw_header *)buf; - if (debug) - print_battery_firmware_image_hdr(fw_update.fw_img_hdr); - if (fw_update.fw_img_hdr->fw_binary_offset >= fw_update.size || - fw_update.size < 256) { - fprintf(stderr, - "Load Firmware Image[%s] Error offset:%d size:%d\n", - fw_image_name, - fw_update.fw_img_hdr->fw_binary_offset, - fw_update.size); - return -1; - } + fw_update->err_retry_cnt = SB_FW_UPDATE_ERROR_RETRY_CNT; + fw_update->fec_err_retry_cnt = SB_FW_UPDATE_FEC_ERROR_RETRY_CNT; + fw_update->busy_retry_cnt = SB_FW_UPDATE_BUSY_ERROR_RETRY_CNT; + fw_update->step_size = SB_FW_UPDATE_CMD_WRITE_BLOCK_SIZE; state = S0_READ_STATUS; while (state != S10_TERMINAL) - state = state_table[state](&fw_update); + state = state_table[state](fw_update); - free(buf); - if (fw_update.rv) - printf("\n\n==> Firmware:%s Update Failed:%d [%s]\n", - fw_image_name, - fw_update.rv, - fw_update.msg); - else - printf("\n\n==> Firmware:%s Update Complete.\n", - fw_image_name); + if (fw_update->fw_img_hdr) + free(fw_update->fw_img_hdr); - return fw_update.rv; + return fw_update->rv; } #define GEC_LOCK_TIMEOUT_SECS 30 /* 30 secs */ @@ -610,25 +699,22 @@ int ec_sb_firmware_update(const char *fw_image_name) int main(int argc, char *argv[]) { int rv = 0, interfaces = COMM_LPC; - const char *test = "normal"; - if (argc < 2) { + int protect = 1; + if (argc > 3) { fprintf(stderr, - "Usage: %s <fw_filename> <test> " - "[initial_tx_delay] [tx_delay] [debug]\n", argv[0]); + "Usage: %s [protect] [debug]\n" + " protect: 0 or 1\n" + " debug: 0 or 1\n", argv[0]); return -1; } - if (argc >= 3) - test = argv[2]; - - if (argc >= 4) - delay_x_us = atoi(argv[3]); - - if (argc >= 5) - delay_y_us = atoi(argv[4]); + if (argc >= 2) + protect = atoi(argv[1]); - if (argc >= 6) - debug = atoi(argv[5]); + if (argc == 3) + debug = atoi(argv[2]); + else + debug = 0; if (acquire_gec_lock(GEC_LOCK_TIMEOUT_SECS) < 0) { fprintf(stderr, "Could not acquire GEC lock.\n"); @@ -640,12 +726,16 @@ int main(int argc, char *argv[]) goto out; } - DPRINTF("fw_filename:%s\n", argv[1]); - rv = ec_sb_firmware_update(argv[1]); + rv = ec_sb_firmware_update(&fw_update); + if (rv) + printf("\n\nFirmware:%s Fail [%s]\n", + fw_update.image_name, + fw_update.msg); - /* set to protect mode if not running a fw update test */ - if (strcmp(test, "test")) + /* Update battery firmware update interface to be protected */ + if (protect) rv |= send_subcmd(EC_SB_FW_UPDATE_PROTECT); + out: release_gec_lock(); return rv; diff --git a/util/ec_sb_firmware_update.h b/util/ec_sb_firmware_update.h index 8737756cd4..7dcd6802fa 100644 --- a/util/ec_sb_firmware_update.h +++ b/util/ec_sb_firmware_update.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2014 The Chromium OS Authors. All rights reserved. +/* Copyright 2014 The Chromium OS Authors. All rights reserved. * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. * @@ -108,32 +108,19 @@ enum sb_maker_id { sb_maker_id_celxpert = 0x0006, }; -/* if permanent error:b5,b3; go to setp8 */ -#define SB_FW_UPDATE_PERMANENT_ERROR_MASK 0x0028 - -/* if firmware update fatal error:b12; go to step2 */ -#define SB_FW_UPDATE_FW_FATAL_ERROR_MASK 0x1000 -#define SB_FW_UPDATE_FW_FATAL_ERROR_RETRY_CNT 1 /* Retry Error cnt*/ - -/* if error:b11,b10,b9 b2,b1,b0; go to step1 */ -#define SB_FW_UPDATE_ERROR_MASK 0x0E07 -#define SB_FW_UPDATE_ERROR_RETRY_CNT 1 /* Retry Error cnt*/ - -/* if FEC.b13=1, go to step6 */ -#define SB_FW_UPDATE_FEC_ERROR_MASK 0x2000 /* b13 */ -#define SB_FW_UPDATE_FEC_ERROR_RETRY_CNT 1 /* b13.FEC retry cnt*/ - -/* if busy; retry 10 times */ -#define SB_FW_UPDATE_BUSY_ERROR_MASK 0x4000 /* b14 */ -#define SB_FW_UPDATE_BUSY_ERROR_RETRY_CNT 1 /* b14.busy retry cnt*/ - -/** - * Update Smart Battery Firmware - * - * @param fw_image_name firmware image name - * - * @return 0 if success, negative if error. +/* + * Ref: Common Smart Battery System Interface Specification v8.0 page 21-24. + * case 1. If permanent error:b5,b3, go to setp8. + * case 2. If error:b11,b10,b9 b2,b1,b0, go to step1. Retry < 3 times. + * case 3. If firmware update fatal error:b12, go to step2. Retry < 3 times. + * In order to simply the implementation, I merged case 2 and 3. + * If firmware update fatal error:b12, go to step1 as well. + * case 4. If error.FEC.b13=1, go to step6. Retry < 3 times. + * case 5. If battery interface is busy, retry < 10 times. + * Delay 1 second between retries. */ -int ec_sb_firmware_update(const char *fw_image_name); +#define SB_FW_UPDATE_ERROR_RETRY_CNT 2 +#define SB_FW_UPDATE_FEC_ERROR_RETRY_CNT 2 +#define SB_FW_UPDATE_BUSY_ERROR_RETRY_CNT 9 #endif |