diff options
Diffstat (limited to 'chip/g/factory_config.c')
-rw-r--r-- | chip/g/factory_config.c | 167 |
1 files changed, 167 insertions, 0 deletions
diff --git a/chip/g/factory_config.c b/chip/g/factory_config.c new file mode 100644 index 0000000000..4e30b79e8c --- /dev/null +++ b/chip/g/factory_config.c @@ -0,0 +1,167 @@ +/* Copyright 2023 The ChromiumOS Authors + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "common.h" +#include "board_id.h" +#include "endian.h" +#include "extension.h" +#include "flash_info.h" +#include "system.h" +#include "util.h" + +#define CPRINTS(format, args...) cprints(CC_SYSTEM, format, ## args) +#define CPRINTF(format, args...) cprintf(CC_SYSTEM, format, ## args) + +static int factory_config_is_blank(uint64_t fc) +{ + return fc == 0; +} + +/** + * Read the INFO1 factory config value into fc. + * + * @return EC_SUCCESS or an error code in cases of various failures to read the + * flash space. + */ +static int read_factory_config(uint64_t *fc) +{ + uint32_t *fc_p; + int i; + + /* + * The factory config offset is guaranteed to be divisible by 4, and it + * is guaranteed to be aligned at 8 bytes. + */ + + fc_p = (uint32_t *)fc; + + for (i = 0; i < sizeof(*fc); i += sizeof(uint32_t)) { + int rv; + + rv = flash_physical_info_read_word + (INFO_FACTORY_CFG_OFFSET + i, fc_p); + if (rv != EC_SUCCESS) { + CPRINTF("%s: failed to read word %d, error %d\n", + __func__, i, rv); + return rv; + } + fc_p++; + } + /* The config is stored inverted. Invert the value. */ + *fc = ~(*fc); + return EC_SUCCESS; +} + +void print_factory_config(void) +{ + uint64_t fc; + int rv; + + rv = read_factory_config(&fc); + ccprintf("fc = "); + if (rv) + ccprintf("invalid (%d)\n", rv); + else + ccprintf("0x%016llx\n", fc); + ccprintf("\n"); +} + +/** + * Write the factory config into the flash INFO1 space. + * + * @param fc Pointer to the factory config to copy into info1 + * + * @return EC_SUCCESS or an error code in cases of various failures to read or + * if the space has been already initialized. + */ +static int write_factory_config(uint64_t *new_fc) +{ + uint64_t fc; + uint32_t rv; +#ifndef CR50_DEV + struct board_id id; + + /* Fail if Board ID Type is already programmed */ + if (read_board_id(&id) || !board_id_type_is_blank(&id)) + return EC_ERROR_ACCESS_DENIED; +#endif + + rv = read_factory_config(&fc); + if (rv != EC_SUCCESS) { + CPRINTS("%s: error reading cfg", __func__); + return rv; + } + + if (*new_fc == fc) { + CPRINTS("%s: ok.", __func__); + return EC_SUCCESS; + } + if (!factory_config_is_blank(fc)) { + CPRINTS("%s: factory cfg already programmed", __func__); + return EC_ERROR_ACCESS_DENIED; + } + + CPRINTS("Set FC - 0x%llx ", *new_fc); + /* The config is stored inverted. */ + *new_fc = ~(*new_fc); + + flash_info_write_enable(); + + /* Write Board ID */ + rv = flash_info_physical_write(INFO_FACTORY_CFG_OFFSET, + sizeof(*new_fc), (const char *)new_fc); + if (rv != EC_SUCCESS) + CPRINTS("%s: write failed", __func__); + + flash_info_write_disable(); + + return rv; +} + +static enum vendor_cmd_rc vc_set_factory_config(enum vendor_cmd_cc code, + void *buf, + size_t input_size, + size_t *response_size) +{ + uint64_t fc; + uint8_t *pbuf = buf; + int rv; + + *response_size = 0; + + if (input_size != INFO_FACTORY_CFG_SIZE) + return VENDOR_RC_BOGUS_ARGS; + + memcpy(&fc, pbuf, INFO_FACTORY_CFG_SIZE); + /* Convert to line representation. */ + fc = be64toh(fc); + + rv = write_factory_config(&fc); + if (rv == EC_ERROR_ACCESS_DENIED) + return VENDOR_RC_NOT_ALLOWED; + else if (rv) + return VENDOR_RC_INTERNAL_ERROR; + return VENDOR_RC_SUCCESS; +} +DECLARE_VENDOR_COMMAND(VENDOR_CC_SET_FACTORY_CONFIG, vc_set_factory_config); + +static enum vendor_cmd_rc vc_get_factory_config(enum vendor_cmd_cc code, + void *buf, + size_t input_size, + size_t *response_size) +{ + uint64_t fc; + + *response_size = 0; + if (read_factory_config(&fc)) + return VENDOR_RC_READ_FLASH_FAIL; + + fc = htobe64(fc); + memcpy(buf, &fc, sizeof(fc)); + *response_size = sizeof(fc); + + return VENDOR_RC_SUCCESS; +} +DECLARE_VENDOR_COMMAND(VENDOR_CC_GET_FACTORY_CONFIG, vc_get_factory_config); |