summaryrefslogtreecommitdiff
path: root/drivers/brcm/sotp.c
blob: 20c644129654316ae52d7d01daa3f1d2c03d6d2e (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
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
/*
 * Copyright (c) 2016-2020, Broadcom
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#include <string.h>

#include <common/debug.h>
#include <lib/mmio.h>
#include <sotp.h>

#include <platform_def.h>
#include <platform_sotp.h>

#ifdef USE_SOFT_SOTP
extern uint64_t soft_sotp[];
#endif

#define SOTP_PROG_CONTROL (SOTP_REGS_OTP_BASE + 0x0000)
#define SOTP_PROG_CONTROL__OTP_CPU_MODE_EN 15
#define SOTP_PROG_CONTROL__OTP_DISABLE_ECC 9
#define SOTP_PROG_CONTROL__OTP_ECC_WREN 8

#define SOTP_WRDATA_0 (SOTP_REGS_OTP_BASE + 0x0004)
#define SOTP_WRDATA_1 (SOTP_REGS_OTP_BASE + 0x0008)

#define SOTP_ADDR (SOTP_REGS_OTP_BASE + 0x000c)
#define SOTP_ADDR__OTP_ROW_ADDR_R 6
#define SOTP_ADDR_MASK 0x3FF

#define SOTP_CTRL_0 (SOTP_REGS_OTP_BASE + 0x0010)
#define SOTP_CTRL_0__START 0
#define SOTP_CTRL_0__OTP_CMD 1

#define SOTP_STATUS_0 (SOTP_REGS_OTP_BASE + 0x0018)
#define SOTP_STATUS__FDONE 3

#define SOTP_STATUS_1 (SOTP_REGS_OTP_BASE + 0x001c)
#define SOTP_STATUS_1__CMD_DONE 1
#define SOTP_STATUS_1__ECC_DET 17

#define SOTP_RDDATA_0 (SOTP_REGS_OTP_BASE + 0x0020)
#define SOTP_RDDATA_1 (SOTP_REGS_OTP_BASE + 0x0024)

#define SOTP_READ 0

#define SOTP_PROG_WORD 10
#define SOTP_STATUS__PROGOK 2
#define SOTP_PROG_ENABLE 2

#define SOTP_ROW_DATA_MASK 0xffffffff
#define SOTP_ECC_ERR_BITS_MASK 0x1ff00000000

#define SOTP_CHIP_CTRL_SW_OVERRIDE_CHIP_STATES 4
#define SOTP_CHIP_CTRL_SW_MANU_PROG 5
#define SOTP_CHIP_CTRL_SW_CID_PROG 6
#define SOTP_CHIP_CTRL_SW_AB_DEVICE 8
#define SOTP_CHIP_CTRL_SW_AB_DEV_MODE 9
#define CHIP_STATE_UNPROGRAMMED 0x1
#define CHIP_STATE_UNASSIGNED 0x2

uint64_t sotp_mem_read(uint32_t offset, uint32_t sotp_add_ecc)
{
#ifdef USE_SOFT_SOTP
	(void)sotp_add_ecc;

	return soft_sotp[offset];
#else
	uint64_t read_data = 0;
	uint64_t read_data1 = 0;
	uint64_t read_data2 = 0;

	/* Check for FDONE status */
	while ((mmio_read_32(SOTP_STATUS_0) & BIT(SOTP_STATUS__FDONE)) !=
	       BIT(SOTP_STATUS__FDONE))
		;

	/* Enable OTP access by CPU */
	mmio_setbits_32(SOTP_PROG_CONTROL,
			BIT(SOTP_PROG_CONTROL__OTP_CPU_MODE_EN));

	if (sotp_add_ecc == 1) {
		mmio_clrbits_32(SOTP_PROG_CONTROL,
				BIT(SOTP_PROG_CONTROL__OTP_DISABLE_ECC));
	}

	if (sotp_add_ecc == 0) {
		mmio_setbits_32(SOTP_PROG_CONTROL,
				BIT(SOTP_PROG_CONTROL__OTP_DISABLE_ECC));
	}

	mmio_write_32(SOTP_ADDR,
		      ((offset & SOTP_ADDR_MASK) << SOTP_ADDR__OTP_ROW_ADDR_R));
	mmio_write_32(SOTP_CTRL_0, (SOTP_READ << SOTP_CTRL_0__OTP_CMD));

	/* Start bit to tell SOTP to send command to the OTP controller */
	mmio_setbits_32(SOTP_CTRL_0, BIT(SOTP_CTRL_0__START));

	/* Wait for SOTP command done to be set */
	while ((mmio_read_32(SOTP_STATUS_1) & BIT(SOTP_STATUS_1__CMD_DONE)) !=
	      BIT(SOTP_STATUS_1__CMD_DONE))
		;

	/* Clr Start bit after command done */
	mmio_clrbits_32(SOTP_CTRL_0, BIT(SOTP_CTRL_0__START));

	if ((offset > SOTP_DEVICE_SECURE_CFG3_ROW) &&
	    (mmio_read_32(SOTP_STATUS_1) & BIT(SOTP_STATUS_1__ECC_DET))) {
		ERROR("SOTP ECC ERROR Detected row offset %d\n", offset);
		read_data = SOTP_ECC_ERR_DETECT;
	} else {
		read_data1 = (uint64_t)mmio_read_32(SOTP_RDDATA_0);
		read_data1 = read_data1 & 0xFFFFFFFF;
		read_data2 = (uint64_t)mmio_read_32(SOTP_RDDATA_1);
		read_data2 = (read_data2 & 0x1ff) << 32;
		read_data = read_data1 | read_data2;
	}

	/* Command done is cleared */
	mmio_setbits_32(SOTP_STATUS_1, BIT(SOTP_STATUS_1__CMD_DONE));

	/* disable OTP access by CPU */
	mmio_clrbits_32(SOTP_PROG_CONTROL,
			BIT(SOTP_PROG_CONTROL__OTP_CPU_MODE_EN));

	return read_data;
#endif
}

void sotp_mem_write(uint32_t addr, uint32_t sotp_add_ecc, uint64_t wdata)
{
#ifdef USE_SOFT_SOTP
	(void)sotp_add_ecc;

	soft_sotp[addr] = wdata;
#else
	uint32_t loop;
	uint8_t prog_array[4] = { 0x0F, 0x04, 0x08, 0x0D };

	uint32_t chip_state_default =
		(CHIP_STATE_UNASSIGNED|CHIP_STATE_UNPROGRAMMED);
	uint32_t chip_state = mmio_read_32(SOTP_REGS_SOTP_CHIP_STATES);
	uint32_t chip_ctrl_default = 0;

	/*
	 * The override settings is required to allow the customer to program
	 * the application specific keys into SOTP, before the conversion to
	 * one of the AB modes.
	 * At the end of write operation, the chip ctrl settings will restored
	 * to the state prior to write call
	 */
	if (chip_state & chip_state_default) {
		uint32_t chip_ctrl;

		chip_ctrl_default = mmio_read_32(SOTP_CHIP_CTRL);
		INFO("SOTP: enable special prog mode\n");

		chip_ctrl = BIT(SOTP_CHIP_CTRL_SW_OVERRIDE_CHIP_STATES) |
			    BIT(SOTP_CHIP_CTRL_SW_MANU_PROG) |
			    BIT(SOTP_CHIP_CTRL_SW_CID_PROG) |
			    BIT(SOTP_CHIP_CTRL_SW_AB_DEVICE);
		mmio_write_32(SOTP_CHIP_CTRL, chip_ctrl);
	}

	/*  Check for FDONE status */
	while ((mmio_read_32(SOTP_STATUS_0) & BIT(SOTP_STATUS__FDONE)) !=
	       BIT(SOTP_STATUS__FDONE))
		;

	/*  Enable OTP access by CPU */
	mmio_setbits_32(SOTP_PROG_CONTROL,
			BIT(SOTP_PROG_CONTROL__OTP_CPU_MODE_EN));

	if (addr > SOTP_DEVICE_SECURE_CFG3_ROW) {
		if (sotp_add_ecc == 0) {
			mmio_clrbits_32(SOTP_PROG_CONTROL,
					BIT(SOTP_PROG_CONTROL__OTP_ECC_WREN));
		}
		if (sotp_add_ecc == 1) {
			mmio_setbits_32(SOTP_PROG_CONTROL,
					BIT(SOTP_PROG_CONTROL__OTP_ECC_WREN));
		}
	} else {
		mmio_clrbits_32(SOTP_PROG_CONTROL,
				BIT(SOTP_PROG_CONTROL__OTP_ECC_WREN));
	}

	mmio_write_32(SOTP_CTRL_0, (SOTP_PROG_ENABLE << 1));

	/*
	 * In order to avoid unintentional writes / programming of the OTP
	 * array, the OTP Controller must be put into programming mode before
	 * it will accept program commands. This is done by writing 0xF, 0x4,
	 * 0x8, 0xD with program commands prior to starting the actual
	 * programming sequence
	 */
	for (loop = 0; loop < 4; loop++) {
		mmio_write_32(SOTP_WRDATA_0, prog_array[loop]);

		/*
		 * Start bit to tell SOTP to send command to the OTP controller
		 */
		mmio_setbits_32(SOTP_CTRL_0, BIT(SOTP_CTRL_0__START));

		/*  Wait for SOTP command done to <-- be set */
		while ((mmio_read_32(SOTP_STATUS_1) &
			BIT(SOTP_STATUS_1__CMD_DONE)) !=
		       BIT(SOTP_STATUS_1__CMD_DONE))
			;

		/* Command done is cleared w1c */
		mmio_setbits_32(SOTP_STATUS_1, BIT(SOTP_STATUS_1__CMD_DONE));

		/* Clr Start bit after command done */
		mmio_clrbits_32(SOTP_CTRL_0, BIT(SOTP_CTRL_0__START));
	}

	/*  Check for PROGOK */
	while ((mmio_read_32(SOTP_STATUS_0) & 0x4) != BIT(SOTP_STATUS__PROGOK))
		;

	/* Set  10 bit row address */
	mmio_write_32(SOTP_ADDR,
		      ((addr & SOTP_ADDR_MASK) << SOTP_ADDR__OTP_ROW_ADDR_R));

	/* Set SOTP Row data */
	mmio_write_32(SOTP_WRDATA_0, (wdata & SOTP_ROW_DATA_MASK));

	/* Set SOTP ECC and error bits */
	mmio_write_32(SOTP_WRDATA_1, ((wdata & SOTP_ECC_ERR_BITS_MASK) >> 32));

	/* Set prog_word command */
	mmio_write_32(SOTP_CTRL_0, (SOTP_PROG_WORD << 1));

	/*  Start bit to tell SOTP to send command to the OTP controller */
	mmio_setbits_32(SOTP_CTRL_0, BIT(SOTP_CTRL_0__START));

	/*  Wait for SOTP command done to be set */
	while ((mmio_read_32(SOTP_STATUS_1) & BIT(SOTP_STATUS_1__CMD_DONE)) !=
	       BIT(SOTP_STATUS_1__CMD_DONE))
		;

	/* Command done is cleared w1c */
	mmio_setbits_32(SOTP_STATUS_1, BIT(SOTP_STATUS_1__CMD_DONE));

	/* disable OTP access by CPU */
	mmio_clrbits_32(SOTP_PROG_CONTROL,
			BIT(SOTP_PROG_CONTROL__OTP_CPU_MODE_EN));

	/* Clr Start bit after command done */
	mmio_clrbits_32(SOTP_CTRL_0, BIT(SOTP_CTRL_0__START));

	if (chip_state & chip_state_default)
		mmio_write_32(SOTP_CHIP_CTRL, chip_ctrl_default);

#endif
}

int sotp_read_key(uint8_t *key, size_t keysize, int start_row, int end_row)
{
	int row;
	uint32_t status = 0;
	uint32_t status2 = 0xFFFFFFFF;
	uint64_t row_data;
	uint32_t data;
	uint32_t *temp_key = (uint32_t *)key;

	row = start_row;
	while ((keysize > 0) && (row <= end_row)) {
		row_data = sotp_mem_read(row, SOTP_ROW_ECC);
		if (!(row_data & (SOTP_ECC_ERR_DETECT | SOTP_FAIL_BITS))) {
			memcpy(temp_key++, &row_data, sizeof(uint32_t));
			keysize -= sizeof(uint32_t);
			data = (uint32_t)(row_data & SOTP_ROW_DATA_MASK);
			status |= data;
			status2 &= data;
		}
		row++;
	}

	if ((status2 == 0xFFFFFFFF) || (status == 0) || (row > end_row))
		return -1;

	return 0;
}

int sotp_key_erased(void)
{
	uint64_t row_data;
	int status = 0;

	row_data = sotp_mem_read(SOTP_DEVICE_SECURE_CFG0_ROW, 0);
	if (row_data & SOTP_DEVICE_SECURE_CFG0_OTP_ERASED_MASK)
		status = 1;

	else if (mmio_read_32(SOTP_REGS_SOTP_CHIP_STATES) &
			SOTP_REGS_SOTP_CHIP_STATES_OTP_ERASED_MASK)
		status = 1;

	return status;
}

/*
 * This function optimise the SOTP redundancy
 * by considering the 00- zero and 01,10,11 - one
 */
uint32_t sotp_redundancy_reduction(uint32_t sotp_row_data)
{
	uint32_t opt_data;
	uint32_t opt_loop;
	uint32_t temp_data;

	opt_data = 0;

	for (opt_loop = 0; opt_loop < 16; opt_loop = opt_loop + 1) {
		temp_data = ((sotp_row_data >> (opt_loop * 2)) & 0x3);

		if (temp_data != 0x0)
			opt_data = (opt_data | (1 << opt_loop));
	}
	return opt_data;
}