summaryrefslogtreecommitdiff
path: root/chip/g/factory_config.c
diff options
context:
space:
mode:
Diffstat (limited to 'chip/g/factory_config.c')
-rw-r--r--chip/g/factory_config.c167
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);