summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSheng-Liang Song <ssl@chromium.org>2015-02-14 14:29:52 -0800
committerChromeOS Commit Bot <chromeos-commit-bot@chromium.org>2015-02-20 08:33:08 +0000
commit036482b6b84b3c216bb83e3627ced560fd3da822 (patch)
tree6bae878e7ce82e61b776f87c6b0f4565da52bfeb
parent279e2c6386e24dbbe8d9d8ad83556f065b4b1a20 (diff)
downloadchrome-ec-036482b6b84b3c216bb83e3627ced560fd3da822.tar.gz
EC: Support firmware updater to auto select a battery fw image
Auto select a battery firmware image based on the current "battery info." sprintf(auto_image_name,"/lib/firmware/battery/maker.%04X.hwid.%04X.bin" maker_id, hardware_id); BUG=chrome-os-partner:24741 BRANCH=glimmer TEST=Verified Simplo Battery Update on glimmer Change-Id: Ie6b2f797a4629fdde3a45e9a6a83c4568655db7a Signed-off-by: Sheng-Liang Song <ssl@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/250130 Reviewed-by: Shawn N <shawnn@chromium.org>
-rw-r--r--util/ec_sb_firmware_update.c324
-rw-r--r--util/ec_sb_firmware_update.h41
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