summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaisuke Nojiri <dnojiri@chromium.org>2018-01-12 12:52:18 -0800
committerchrome-bot <chrome-bot@chromium.org>2018-01-18 05:09:31 -0800
commitbc4b786156b3dd51de75f512d05679d5b413399b (patch)
tree830a7bcbc8b5e7d08b8b453fec4c4f1cd25ecfbe
parent5232cdd16bb2e1b15b281b0041c33c55bc9ca52d (diff)
downloadchrome-ec-bc4b786156b3dd51de75f512d05679d5b413399b.tar.gz
CBI: Add host command to set board info
This patch adds host command to write board information in EERPOM. BUG=b:70294260 BRANCH=none TEST=Run ectool cbi set <type> <value> to write BOARD_VERSION, OEM_ID, and SKU_ID. Enable WP and verify cbi set command fails. Change-Id: I39536d146313408ace666f350a107d89b331bf7a Signed-off-by: Daisuke Nojiri <dnojiri@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/865570
-rw-r--r--common/cbi.c87
-rw-r--r--include/ec_commands.h23
-rw-r--r--util/ectool.c36
3 files changed, 144 insertions, 2 deletions
diff --git a/common/cbi.c b/common/cbi.c
index b82d0375c2..41e8606487 100644
--- a/common/cbi.c
+++ b/common/cbi.c
@@ -9,12 +9,14 @@
#include "console.h"
#include "crc8.h"
#include "cros_board_info.h"
+#include "gpio.h"
#include "host_command.h"
#include "i2c.h"
#include "util.h"
#define CPRINTS(format, args...) cprints(CC_SYSTEM, "CBI " format, ## args)
+#define EEPROM_PAGE_WRITE_SIZE 16
static struct board_info bi;
/* TODO: Init it to -1. On error (I2C or bad contents), retry a read and set it
* to enum ec_error_list if it still fails. The successive calls can be
@@ -95,6 +97,38 @@ static int read_board_info(void)
return EC_SUCCESS;
}
+static int eeprom_is_write_protected(void)
+{
+ return !gpio_get_level(GPIO_WP_L);
+}
+
+static int write_board_info(void)
+{
+ uint8_t buf[sizeof(bi) + 1];
+ /* The code is only tested for ST M24C02, whose page size for a single
+ * write is 16 byte. To support different EEPROMs, you may need to
+ * craft the i2c packets accordingly. */
+ _Static_assert(sizeof(bi) <= EEPROM_PAGE_WRITE_SIZE,
+ "struct board_info exceeds page write size");
+ int rv;
+
+ if (eeprom_is_write_protected()) {
+ CPRINTS("Failed to write for WP");
+ return EC_ERROR_ACCESS_DENIED;
+ }
+
+ buf[0] = 0; /* Offset 0 */
+ memcpy(&buf[1], &bi, sizeof(bi));
+ rv = i2c_xfer(I2C_PORT_EEPROM, I2C_ADDR_EEPROM, buf,
+ sizeof(bi) + 1, NULL, 0, I2C_XFER_SINGLE);
+ if (rv) {
+ CPRINTS("Failed to write for %d", rv);
+ return rv;
+ }
+
+ return EC_SUCCESS;
+}
+
int cbi_get_board_version(uint32_t *version)
{
if (read_board_info())
@@ -154,3 +188,56 @@ static int hc_cbi_get(struct host_cmd_handler_args *args)
DECLARE_HOST_COMMAND(EC_CMD_GET_CROS_BOARD_INFO,
hc_cbi_get,
EC_VER_MASK(0));
+
+static int hc_cbi_set(struct host_cmd_handler_args *args)
+{
+ const struct __ec_align4 ec_params_set_cbi *p = args->params;
+
+ if (p->flag & CBI_SET_INIT) {
+ memset(&bi, 0, sizeof(bi));
+ memcpy(&bi.head.magic, cbi_magic, sizeof(cbi_magic));
+ initialized = 1;
+ } else {
+ if (read_board_info())
+ return EC_RES_ERROR;
+ }
+
+ switch (p->type) {
+ case CBI_DATA_BOARD_VERSION:
+ if (p->data > UINT16_MAX)
+ return EC_RES_INVALID_PARAM;
+ bi.version = p->data;
+ break;
+ case CBI_DATA_OEM_ID:
+ if (p->data > UINT8_MAX)
+ return EC_RES_INVALID_PARAM;
+ bi.oem_id = p->data;
+ break;
+ case CBI_DATA_SKU_ID:
+ if (p->data > UINT8_MAX)
+ return EC_RES_INVALID_PARAM;
+ bi.sku_id = p->data;
+ break;
+ default:
+ return EC_RES_INVALID_PARAM;
+ }
+
+ /* Whether we're modifying existing data or creating new one,
+ * we take over the format. */
+ bi.head.major_version = CBI_VERSION_MAJOR;
+ bi.head.minor_version = CBI_VERSION_MINOR;
+ bi.head.total_size = sizeof(bi);
+ bi.head.crc = cbi_crc8(&bi);
+
+ /* Skip write if client asks so. */
+ if (p->flag & CBI_SET_NO_SYNC)
+ return EC_RES_SUCCESS;
+
+ if (write_board_info())
+ return EC_RES_ERROR;
+
+ return EC_RES_SUCCESS;
+}
+DECLARE_HOST_COMMAND(EC_CMD_SET_CROS_BOARD_INFO,
+ hc_cbi_set,
+ EC_VER_MASK(0));
diff --git a/include/ec_commands.h b/include/ec_commands.h
index 23307354e1..705e54f2b1 100644
--- a/include/ec_commands.h
+++ b/include/ec_commands.h
@@ -4576,6 +4576,11 @@ struct __ec_align1 ec_params_efs_verify {
* size to determine how big it is.
*/
#define EC_CMD_GET_CROS_BOARD_INFO 0x011F
+/*
+ * Write info into Cros Board Info on EEPROM. Write fails if the board has
+ * hardware write-protect enabled.
+ */
+#define EC_CMD_SET_CROS_BOARD_INFO 0x0120
enum cbi_data_type {
/* integer types */
@@ -4591,6 +4596,24 @@ struct __ec_align4 ec_params_get_cbi {
uint32_t type; /* enum cbi_data_type */
};
+/*
+ * Flags to control write behavior.
+ *
+ * NO_SYNC: Makes EC update data in RAM but skip writing to EEPROM. It's
+ * useful when writing multiple fields in a row.
+ * INIT: Need to be set when creating a new CBI from scratch. All fields
+ * will be initialized to zero first.
+ */
+#define CBI_SET_NO_SYNC (1 << 0)
+#define CBI_SET_INIT (1 << 1)
+
+struct __ec_align1 ec_params_set_cbi {
+ uint32_t type; /* enum cbi_data_type */
+ uint8_t flag; /* CBI_SET_* */
+ uint32_t data; /* For numeric value */
+ uint8_t raw[]; /* For string and raw data */
+};
+
/*****************************************************************************/
/* The command range 0x200-0x2FF is reserved for Rotor. */
diff --git a/util/ectool.c b/util/ectool.c
index c694e83c56..4737ac91e3 100644
--- a/util/ectool.c
+++ b/util/ectool.c
@@ -60,7 +60,7 @@ const char help_str[] =
" boardversion\n"
" Prints the board version\n"
" cbi\n"
- " Get Cros Board Info\n"
+ " Get/Set Cros Board Info\n"
" chargecurrentlimit\n"
" Set the maximum battery charging current\n"
" chargecontrol\n"
@@ -6231,10 +6231,14 @@ static void cmd_cbi_help(char *cmd)
{
fprintf(stderr,
" Usage: %s get <type>\n"
+ " Usage: %s set <type> value [flag]\n"
" <type> is one of:\n"
" 0: BOARD_VERSION\n"
" 1: OEM_ID\n"
- " 2: SKU_ID\n", cmd);
+ " 2: SKU_ID\n"
+ " [flag] is combination of:\n"
+ " 01b: Skip write to EEPROM. Use for back-to-back writes\n"
+ " 10b: Set all fields to defaults first\n", cmd, cmd);
}
/*
@@ -6282,6 +6286,34 @@ static int cmd_cbi(int argc, char *argv[])
return -1;
}
return 0;
+ } else if (!strcasecmp(argv[1], "set")) {
+ struct ec_params_set_cbi p;
+ if (argc < 4) {
+ fprintf(stderr, "Invalid number of params\n");
+ cmd_cbi_help(argv[0]);
+ return -1;
+ }
+ memset(&p, 0, sizeof(p));
+ p.type = type;
+ p.data = strtol(argv[3], &e, 0);
+ if (e && *e) {
+ fprintf(stderr, "Bad value\n");
+ return -1;
+ }
+ if (argc > 4) {
+ p.flag = strtol(argv[4], &e, 0);
+ if (e && *e) {
+ fprintf(stderr, "Bad flag\n");
+ return -1;
+ }
+ }
+ rv = ec_command(EC_CMD_SET_CROS_BOARD_INFO, 0, &p, sizeof(p),
+ NULL, 0);
+ if (rv < 0) {
+ fprintf(stderr, "Error code: %d\n", rv);
+ return rv;
+ }
+ return 0;
}
fprintf(stderr, "Invalid sub command: %s\n", argv[1]);