1*54fd6939SJiyong Park /*
2*54fd6939SJiyong Park * Copyright (c) 2016-2020, Broadcom
3*54fd6939SJiyong Park *
4*54fd6939SJiyong Park * SPDX-License-Identifier: BSD-3-Clause
5*54fd6939SJiyong Park */
6*54fd6939SJiyong Park
7*54fd6939SJiyong Park #include <string.h>
8*54fd6939SJiyong Park
9*54fd6939SJiyong Park #include <common/debug.h>
10*54fd6939SJiyong Park #include <lib/mmio.h>
11*54fd6939SJiyong Park #include <sotp.h>
12*54fd6939SJiyong Park
13*54fd6939SJiyong Park #include <platform_def.h>
14*54fd6939SJiyong Park #include <platform_sotp.h>
15*54fd6939SJiyong Park
16*54fd6939SJiyong Park #ifdef USE_SOFT_SOTP
17*54fd6939SJiyong Park extern uint64_t soft_sotp[];
18*54fd6939SJiyong Park #endif
19*54fd6939SJiyong Park
20*54fd6939SJiyong Park #define SOTP_PROG_CONTROL (SOTP_REGS_OTP_BASE + 0x0000)
21*54fd6939SJiyong Park #define SOTP_PROG_CONTROL__OTP_CPU_MODE_EN 15
22*54fd6939SJiyong Park #define SOTP_PROG_CONTROL__OTP_DISABLE_ECC 9
23*54fd6939SJiyong Park #define SOTP_PROG_CONTROL__OTP_ECC_WREN 8
24*54fd6939SJiyong Park
25*54fd6939SJiyong Park #define SOTP_WRDATA_0 (SOTP_REGS_OTP_BASE + 0x0004)
26*54fd6939SJiyong Park #define SOTP_WRDATA_1 (SOTP_REGS_OTP_BASE + 0x0008)
27*54fd6939SJiyong Park
28*54fd6939SJiyong Park #define SOTP_ADDR (SOTP_REGS_OTP_BASE + 0x000c)
29*54fd6939SJiyong Park #define SOTP_ADDR__OTP_ROW_ADDR_R 6
30*54fd6939SJiyong Park #define SOTP_ADDR_MASK 0x3FF
31*54fd6939SJiyong Park
32*54fd6939SJiyong Park #define SOTP_CTRL_0 (SOTP_REGS_OTP_BASE + 0x0010)
33*54fd6939SJiyong Park #define SOTP_CTRL_0__START 0
34*54fd6939SJiyong Park #define SOTP_CTRL_0__OTP_CMD 1
35*54fd6939SJiyong Park
36*54fd6939SJiyong Park #define SOTP_STATUS_0 (SOTP_REGS_OTP_BASE + 0x0018)
37*54fd6939SJiyong Park #define SOTP_STATUS__FDONE 3
38*54fd6939SJiyong Park
39*54fd6939SJiyong Park #define SOTP_STATUS_1 (SOTP_REGS_OTP_BASE + 0x001c)
40*54fd6939SJiyong Park #define SOTP_STATUS_1__CMD_DONE 1
41*54fd6939SJiyong Park #define SOTP_STATUS_1__ECC_DET 17
42*54fd6939SJiyong Park
43*54fd6939SJiyong Park #define SOTP_RDDATA_0 (SOTP_REGS_OTP_BASE + 0x0020)
44*54fd6939SJiyong Park #define SOTP_RDDATA_1 (SOTP_REGS_OTP_BASE + 0x0024)
45*54fd6939SJiyong Park
46*54fd6939SJiyong Park #define SOTP_READ 0
47*54fd6939SJiyong Park
48*54fd6939SJiyong Park #define SOTP_PROG_WORD 10
49*54fd6939SJiyong Park #define SOTP_STATUS__PROGOK 2
50*54fd6939SJiyong Park #define SOTP_PROG_ENABLE 2
51*54fd6939SJiyong Park
52*54fd6939SJiyong Park #define SOTP_ROW_DATA_MASK 0xffffffff
53*54fd6939SJiyong Park #define SOTP_ECC_ERR_BITS_MASK 0x1ff00000000
54*54fd6939SJiyong Park
55*54fd6939SJiyong Park #define SOTP_CHIP_CTRL_SW_OVERRIDE_CHIP_STATES 4
56*54fd6939SJiyong Park #define SOTP_CHIP_CTRL_SW_MANU_PROG 5
57*54fd6939SJiyong Park #define SOTP_CHIP_CTRL_SW_CID_PROG 6
58*54fd6939SJiyong Park #define SOTP_CHIP_CTRL_SW_AB_DEVICE 8
59*54fd6939SJiyong Park #define SOTP_CHIP_CTRL_SW_AB_DEV_MODE 9
60*54fd6939SJiyong Park #define CHIP_STATE_UNPROGRAMMED 0x1
61*54fd6939SJiyong Park #define CHIP_STATE_UNASSIGNED 0x2
62*54fd6939SJiyong Park
sotp_mem_read(uint32_t offset,uint32_t sotp_add_ecc)63*54fd6939SJiyong Park uint64_t sotp_mem_read(uint32_t offset, uint32_t sotp_add_ecc)
64*54fd6939SJiyong Park {
65*54fd6939SJiyong Park #ifdef USE_SOFT_SOTP
66*54fd6939SJiyong Park (void)sotp_add_ecc;
67*54fd6939SJiyong Park
68*54fd6939SJiyong Park return soft_sotp[offset];
69*54fd6939SJiyong Park #else
70*54fd6939SJiyong Park uint64_t read_data = 0;
71*54fd6939SJiyong Park uint64_t read_data1 = 0;
72*54fd6939SJiyong Park uint64_t read_data2 = 0;
73*54fd6939SJiyong Park
74*54fd6939SJiyong Park /* Check for FDONE status */
75*54fd6939SJiyong Park while ((mmio_read_32(SOTP_STATUS_0) & BIT(SOTP_STATUS__FDONE)) !=
76*54fd6939SJiyong Park BIT(SOTP_STATUS__FDONE))
77*54fd6939SJiyong Park ;
78*54fd6939SJiyong Park
79*54fd6939SJiyong Park /* Enable OTP access by CPU */
80*54fd6939SJiyong Park mmio_setbits_32(SOTP_PROG_CONTROL,
81*54fd6939SJiyong Park BIT(SOTP_PROG_CONTROL__OTP_CPU_MODE_EN));
82*54fd6939SJiyong Park
83*54fd6939SJiyong Park if (sotp_add_ecc == 1) {
84*54fd6939SJiyong Park mmio_clrbits_32(SOTP_PROG_CONTROL,
85*54fd6939SJiyong Park BIT(SOTP_PROG_CONTROL__OTP_DISABLE_ECC));
86*54fd6939SJiyong Park }
87*54fd6939SJiyong Park
88*54fd6939SJiyong Park if (sotp_add_ecc == 0) {
89*54fd6939SJiyong Park mmio_setbits_32(SOTP_PROG_CONTROL,
90*54fd6939SJiyong Park BIT(SOTP_PROG_CONTROL__OTP_DISABLE_ECC));
91*54fd6939SJiyong Park }
92*54fd6939SJiyong Park
93*54fd6939SJiyong Park mmio_write_32(SOTP_ADDR,
94*54fd6939SJiyong Park ((offset & SOTP_ADDR_MASK) << SOTP_ADDR__OTP_ROW_ADDR_R));
95*54fd6939SJiyong Park mmio_write_32(SOTP_CTRL_0, (SOTP_READ << SOTP_CTRL_0__OTP_CMD));
96*54fd6939SJiyong Park
97*54fd6939SJiyong Park /* Start bit to tell SOTP to send command to the OTP controller */
98*54fd6939SJiyong Park mmio_setbits_32(SOTP_CTRL_0, BIT(SOTP_CTRL_0__START));
99*54fd6939SJiyong Park
100*54fd6939SJiyong Park /* Wait for SOTP command done to be set */
101*54fd6939SJiyong Park while ((mmio_read_32(SOTP_STATUS_1) & BIT(SOTP_STATUS_1__CMD_DONE)) !=
102*54fd6939SJiyong Park BIT(SOTP_STATUS_1__CMD_DONE))
103*54fd6939SJiyong Park ;
104*54fd6939SJiyong Park
105*54fd6939SJiyong Park /* Clr Start bit after command done */
106*54fd6939SJiyong Park mmio_clrbits_32(SOTP_CTRL_0, BIT(SOTP_CTRL_0__START));
107*54fd6939SJiyong Park
108*54fd6939SJiyong Park if ((offset > SOTP_DEVICE_SECURE_CFG3_ROW) &&
109*54fd6939SJiyong Park (mmio_read_32(SOTP_STATUS_1) & BIT(SOTP_STATUS_1__ECC_DET))) {
110*54fd6939SJiyong Park ERROR("SOTP ECC ERROR Detected row offset %d\n", offset);
111*54fd6939SJiyong Park read_data = SOTP_ECC_ERR_DETECT;
112*54fd6939SJiyong Park } else {
113*54fd6939SJiyong Park read_data1 = (uint64_t)mmio_read_32(SOTP_RDDATA_0);
114*54fd6939SJiyong Park read_data1 = read_data1 & 0xFFFFFFFF;
115*54fd6939SJiyong Park read_data2 = (uint64_t)mmio_read_32(SOTP_RDDATA_1);
116*54fd6939SJiyong Park read_data2 = (read_data2 & 0x1ff) << 32;
117*54fd6939SJiyong Park read_data = read_data1 | read_data2;
118*54fd6939SJiyong Park }
119*54fd6939SJiyong Park
120*54fd6939SJiyong Park /* Command done is cleared */
121*54fd6939SJiyong Park mmio_setbits_32(SOTP_STATUS_1, BIT(SOTP_STATUS_1__CMD_DONE));
122*54fd6939SJiyong Park
123*54fd6939SJiyong Park /* disable OTP access by CPU */
124*54fd6939SJiyong Park mmio_clrbits_32(SOTP_PROG_CONTROL,
125*54fd6939SJiyong Park BIT(SOTP_PROG_CONTROL__OTP_CPU_MODE_EN));
126*54fd6939SJiyong Park
127*54fd6939SJiyong Park return read_data;
128*54fd6939SJiyong Park #endif
129*54fd6939SJiyong Park }
130*54fd6939SJiyong Park
sotp_mem_write(uint32_t addr,uint32_t sotp_add_ecc,uint64_t wdata)131*54fd6939SJiyong Park void sotp_mem_write(uint32_t addr, uint32_t sotp_add_ecc, uint64_t wdata)
132*54fd6939SJiyong Park {
133*54fd6939SJiyong Park #ifdef USE_SOFT_SOTP
134*54fd6939SJiyong Park (void)sotp_add_ecc;
135*54fd6939SJiyong Park
136*54fd6939SJiyong Park soft_sotp[addr] = wdata;
137*54fd6939SJiyong Park #else
138*54fd6939SJiyong Park uint32_t loop;
139*54fd6939SJiyong Park uint8_t prog_array[4] = { 0x0F, 0x04, 0x08, 0x0D };
140*54fd6939SJiyong Park
141*54fd6939SJiyong Park uint32_t chip_state_default =
142*54fd6939SJiyong Park (CHIP_STATE_UNASSIGNED|CHIP_STATE_UNPROGRAMMED);
143*54fd6939SJiyong Park uint32_t chip_state = mmio_read_32(SOTP_REGS_SOTP_CHIP_STATES);
144*54fd6939SJiyong Park uint32_t chip_ctrl_default = 0;
145*54fd6939SJiyong Park
146*54fd6939SJiyong Park /*
147*54fd6939SJiyong Park * The override settings is required to allow the customer to program
148*54fd6939SJiyong Park * the application specific keys into SOTP, before the conversion to
149*54fd6939SJiyong Park * one of the AB modes.
150*54fd6939SJiyong Park * At the end of write operation, the chip ctrl settings will restored
151*54fd6939SJiyong Park * to the state prior to write call
152*54fd6939SJiyong Park */
153*54fd6939SJiyong Park if (chip_state & chip_state_default) {
154*54fd6939SJiyong Park uint32_t chip_ctrl;
155*54fd6939SJiyong Park
156*54fd6939SJiyong Park chip_ctrl_default = mmio_read_32(SOTP_CHIP_CTRL);
157*54fd6939SJiyong Park INFO("SOTP: enable special prog mode\n");
158*54fd6939SJiyong Park
159*54fd6939SJiyong Park chip_ctrl = BIT(SOTP_CHIP_CTRL_SW_OVERRIDE_CHIP_STATES) |
160*54fd6939SJiyong Park BIT(SOTP_CHIP_CTRL_SW_MANU_PROG) |
161*54fd6939SJiyong Park BIT(SOTP_CHIP_CTRL_SW_CID_PROG) |
162*54fd6939SJiyong Park BIT(SOTP_CHIP_CTRL_SW_AB_DEVICE);
163*54fd6939SJiyong Park mmio_write_32(SOTP_CHIP_CTRL, chip_ctrl);
164*54fd6939SJiyong Park }
165*54fd6939SJiyong Park
166*54fd6939SJiyong Park /* Check for FDONE status */
167*54fd6939SJiyong Park while ((mmio_read_32(SOTP_STATUS_0) & BIT(SOTP_STATUS__FDONE)) !=
168*54fd6939SJiyong Park BIT(SOTP_STATUS__FDONE))
169*54fd6939SJiyong Park ;
170*54fd6939SJiyong Park
171*54fd6939SJiyong Park /* Enable OTP acces by CPU */
172*54fd6939SJiyong Park mmio_setbits_32(SOTP_PROG_CONTROL,
173*54fd6939SJiyong Park BIT(SOTP_PROG_CONTROL__OTP_CPU_MODE_EN));
174*54fd6939SJiyong Park
175*54fd6939SJiyong Park if (addr > SOTP_DEVICE_SECURE_CFG3_ROW) {
176*54fd6939SJiyong Park if (sotp_add_ecc == 0) {
177*54fd6939SJiyong Park mmio_clrbits_32(SOTP_PROG_CONTROL,
178*54fd6939SJiyong Park BIT(SOTP_PROG_CONTROL__OTP_ECC_WREN));
179*54fd6939SJiyong Park }
180*54fd6939SJiyong Park if (sotp_add_ecc == 1) {
181*54fd6939SJiyong Park mmio_setbits_32(SOTP_PROG_CONTROL,
182*54fd6939SJiyong Park BIT(SOTP_PROG_CONTROL__OTP_ECC_WREN));
183*54fd6939SJiyong Park }
184*54fd6939SJiyong Park } else {
185*54fd6939SJiyong Park mmio_clrbits_32(SOTP_PROG_CONTROL,
186*54fd6939SJiyong Park BIT(SOTP_PROG_CONTROL__OTP_ECC_WREN));
187*54fd6939SJiyong Park }
188*54fd6939SJiyong Park
189*54fd6939SJiyong Park mmio_write_32(SOTP_CTRL_0, (SOTP_PROG_ENABLE << 1));
190*54fd6939SJiyong Park
191*54fd6939SJiyong Park /*
192*54fd6939SJiyong Park * In order to avoid unintentional writes / programming of the OTP
193*54fd6939SJiyong Park * array, the OTP Controller must be put into programming mode before
194*54fd6939SJiyong Park * it will accept program commands. This is done by writing 0xF, 0x4,
195*54fd6939SJiyong Park * 0x8, 0xD with program commands prior to starting the actual
196*54fd6939SJiyong Park * programming sequence
197*54fd6939SJiyong Park */
198*54fd6939SJiyong Park for (loop = 0; loop < 4; loop++) {
199*54fd6939SJiyong Park mmio_write_32(SOTP_WRDATA_0, prog_array[loop]);
200*54fd6939SJiyong Park
201*54fd6939SJiyong Park /*
202*54fd6939SJiyong Park * Start bit to tell SOTP to send command to the OTP controller
203*54fd6939SJiyong Park */
204*54fd6939SJiyong Park mmio_setbits_32(SOTP_CTRL_0, BIT(SOTP_CTRL_0__START));
205*54fd6939SJiyong Park
206*54fd6939SJiyong Park /* Wait for SOTP command done to <-- be set */
207*54fd6939SJiyong Park while ((mmio_read_32(SOTP_STATUS_1) &
208*54fd6939SJiyong Park BIT(SOTP_STATUS_1__CMD_DONE)) !=
209*54fd6939SJiyong Park BIT(SOTP_STATUS_1__CMD_DONE))
210*54fd6939SJiyong Park ;
211*54fd6939SJiyong Park
212*54fd6939SJiyong Park /* Command done is cleared w1c */
213*54fd6939SJiyong Park mmio_setbits_32(SOTP_STATUS_1, BIT(SOTP_STATUS_1__CMD_DONE));
214*54fd6939SJiyong Park
215*54fd6939SJiyong Park /* Clr Start bit after command done */
216*54fd6939SJiyong Park mmio_clrbits_32(SOTP_CTRL_0, BIT(SOTP_CTRL_0__START));
217*54fd6939SJiyong Park }
218*54fd6939SJiyong Park
219*54fd6939SJiyong Park /* Check for PROGOK */
220*54fd6939SJiyong Park while ((mmio_read_32(SOTP_STATUS_0) & 0x4) != BIT(SOTP_STATUS__PROGOK))
221*54fd6939SJiyong Park ;
222*54fd6939SJiyong Park
223*54fd6939SJiyong Park /* Set 10 bit row address */
224*54fd6939SJiyong Park mmio_write_32(SOTP_ADDR,
225*54fd6939SJiyong Park ((addr & SOTP_ADDR_MASK) << SOTP_ADDR__OTP_ROW_ADDR_R));
226*54fd6939SJiyong Park
227*54fd6939SJiyong Park /* Set SOTP Row data */
228*54fd6939SJiyong Park mmio_write_32(SOTP_WRDATA_0, (wdata & SOTP_ROW_DATA_MASK));
229*54fd6939SJiyong Park
230*54fd6939SJiyong Park /* Set SOTP ECC and error bits */
231*54fd6939SJiyong Park mmio_write_32(SOTP_WRDATA_1, ((wdata & SOTP_ECC_ERR_BITS_MASK) >> 32));
232*54fd6939SJiyong Park
233*54fd6939SJiyong Park /* Set prog_word command */
234*54fd6939SJiyong Park mmio_write_32(SOTP_CTRL_0, (SOTP_PROG_WORD << 1));
235*54fd6939SJiyong Park
236*54fd6939SJiyong Park /* Start bit to tell SOTP to send command to the OTP controller */
237*54fd6939SJiyong Park mmio_setbits_32(SOTP_CTRL_0, BIT(SOTP_CTRL_0__START));
238*54fd6939SJiyong Park
239*54fd6939SJiyong Park /* Wait for SOTP command done to be set */
240*54fd6939SJiyong Park while ((mmio_read_32(SOTP_STATUS_1) & BIT(SOTP_STATUS_1__CMD_DONE)) !=
241*54fd6939SJiyong Park BIT(SOTP_STATUS_1__CMD_DONE))
242*54fd6939SJiyong Park ;
243*54fd6939SJiyong Park
244*54fd6939SJiyong Park /* Command done is cleared w1c */
245*54fd6939SJiyong Park mmio_setbits_32(SOTP_STATUS_1, BIT(SOTP_STATUS_1__CMD_DONE));
246*54fd6939SJiyong Park
247*54fd6939SJiyong Park /* disable OTP acces by CPU */
248*54fd6939SJiyong Park mmio_clrbits_32(SOTP_PROG_CONTROL,
249*54fd6939SJiyong Park BIT(SOTP_PROG_CONTROL__OTP_CPU_MODE_EN));
250*54fd6939SJiyong Park
251*54fd6939SJiyong Park /* Clr Start bit after command done */
252*54fd6939SJiyong Park mmio_clrbits_32(SOTP_CTRL_0, BIT(SOTP_CTRL_0__START));
253*54fd6939SJiyong Park
254*54fd6939SJiyong Park if (chip_state & chip_state_default)
255*54fd6939SJiyong Park mmio_write_32(SOTP_CHIP_CTRL, chip_ctrl_default);
256*54fd6939SJiyong Park
257*54fd6939SJiyong Park #endif
258*54fd6939SJiyong Park }
259*54fd6939SJiyong Park
sotp_read_key(uint8_t * key,size_t keysize,int start_row,int end_row)260*54fd6939SJiyong Park int sotp_read_key(uint8_t *key, size_t keysize, int start_row, int end_row)
261*54fd6939SJiyong Park {
262*54fd6939SJiyong Park int row;
263*54fd6939SJiyong Park uint32_t status = 0;
264*54fd6939SJiyong Park uint32_t status2 = 0xFFFFFFFF;
265*54fd6939SJiyong Park uint64_t row_data;
266*54fd6939SJiyong Park uint32_t data;
267*54fd6939SJiyong Park uint32_t *temp_key = (uint32_t *)key;
268*54fd6939SJiyong Park
269*54fd6939SJiyong Park row = start_row;
270*54fd6939SJiyong Park while ((keysize > 0) && (row <= end_row)) {
271*54fd6939SJiyong Park row_data = sotp_mem_read(row, SOTP_ROW_ECC);
272*54fd6939SJiyong Park if (!(row_data & (SOTP_ECC_ERR_DETECT | SOTP_FAIL_BITS))) {
273*54fd6939SJiyong Park memcpy(temp_key++, &row_data, sizeof(uint32_t));
274*54fd6939SJiyong Park keysize -= sizeof(uint32_t);
275*54fd6939SJiyong Park data = (uint32_t)(row_data & SOTP_ROW_DATA_MASK);
276*54fd6939SJiyong Park status |= data;
277*54fd6939SJiyong Park status2 &= data;
278*54fd6939SJiyong Park }
279*54fd6939SJiyong Park row++;
280*54fd6939SJiyong Park }
281*54fd6939SJiyong Park
282*54fd6939SJiyong Park if ((status2 == 0xFFFFFFFF) || (status == 0) || (row > end_row))
283*54fd6939SJiyong Park return -1;
284*54fd6939SJiyong Park
285*54fd6939SJiyong Park return 0;
286*54fd6939SJiyong Park }
287*54fd6939SJiyong Park
sotp_key_erased(void)288*54fd6939SJiyong Park int sotp_key_erased(void)
289*54fd6939SJiyong Park {
290*54fd6939SJiyong Park uint64_t row_data;
291*54fd6939SJiyong Park int status = 0;
292*54fd6939SJiyong Park
293*54fd6939SJiyong Park row_data = sotp_mem_read(SOTP_DEVICE_SECURE_CFG0_ROW, 0);
294*54fd6939SJiyong Park if (row_data & SOTP_DEVICE_SECURE_CFG0_OTP_ERASED_MASK)
295*54fd6939SJiyong Park status = 1;
296*54fd6939SJiyong Park
297*54fd6939SJiyong Park else if (mmio_read_32(SOTP_REGS_SOTP_CHIP_STATES) &
298*54fd6939SJiyong Park SOTP_REGS_SOTP_CHIP_STATES_OTP_ERASED_MASK)
299*54fd6939SJiyong Park status = 1;
300*54fd6939SJiyong Park
301*54fd6939SJiyong Park return status;
302*54fd6939SJiyong Park }
303*54fd6939SJiyong Park
304*54fd6939SJiyong Park /*
305*54fd6939SJiyong Park * This function optimise the SOTP redundancy
306*54fd6939SJiyong Park * by considering the 00- zero and 01,10,11 - one
307*54fd6939SJiyong Park */
sotp_redundancy_reduction(uint32_t sotp_row_data)308*54fd6939SJiyong Park uint32_t sotp_redundancy_reduction(uint32_t sotp_row_data)
309*54fd6939SJiyong Park {
310*54fd6939SJiyong Park uint32_t opt_data;
311*54fd6939SJiyong Park uint32_t opt_loop;
312*54fd6939SJiyong Park uint32_t temp_data;
313*54fd6939SJiyong Park
314*54fd6939SJiyong Park opt_data = 0;
315*54fd6939SJiyong Park
316*54fd6939SJiyong Park for (opt_loop = 0; opt_loop < 16; opt_loop = opt_loop + 1) {
317*54fd6939SJiyong Park temp_data = ((sotp_row_data >> (opt_loop * 2)) & 0x3);
318*54fd6939SJiyong Park
319*54fd6939SJiyong Park if (temp_data != 0x0)
320*54fd6939SJiyong Park opt_data = (opt_data | (1 << opt_loop));
321*54fd6939SJiyong Park }
322*54fd6939SJiyong Park return opt_data;
323*54fd6939SJiyong Park }
324