summaryrefslogtreecommitdiff
path: root/chip/g/factory_config.c
blob: 4e30b79e8c56468e1a68d6e48c92ac7013649bae (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
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);