xref: /aosp_15_r20/external/arm-trusted-firmware/drivers/brcm/ocotp.c (revision 54fd6939e177f8ff529b10183254802c76df6d08)
1*54fd6939SJiyong Park /*
2*54fd6939SJiyong Park  * Copyright (c) 2017 - 2020, Broadcom
3*54fd6939SJiyong Park  *
4*54fd6939SJiyong Park  * SPDX-License-Identifier: BSD-3-Clause
5*54fd6939SJiyong Park  */
6*54fd6939SJiyong Park 
7*54fd6939SJiyong Park #include <stdint.h>
8*54fd6939SJiyong Park 
9*54fd6939SJiyong Park #include <common/debug.h>
10*54fd6939SJiyong Park #include <drivers/delay_timer.h>
11*54fd6939SJiyong Park #include <lib/mmio.h>
12*54fd6939SJiyong Park 
13*54fd6939SJiyong Park #include <ocotp.h>
14*54fd6939SJiyong Park #include <platform_def.h>
15*54fd6939SJiyong Park 
16*54fd6939SJiyong Park #define OTP_MAP 2
17*54fd6939SJiyong Park #define OTP_NUM_WORDS 2048
18*54fd6939SJiyong Park /*
19*54fd6939SJiyong Park  * # of tries for OTP Status. The time to execute a command varies. The slowest
20*54fd6939SJiyong Park  * commands are writes which also vary based on the # of bits turned on. Writing
21*54fd6939SJiyong Park  * 0xffffffff takes ~3800 us.
22*54fd6939SJiyong Park  */
23*54fd6939SJiyong Park #define OTPC_RETRIES_US                 5000
24*54fd6939SJiyong Park 
25*54fd6939SJiyong Park /* Sequence to enable OTP program */
26*54fd6939SJiyong Park #define OTPC_PROG_EN_SEQ             { 0xf, 0x4, 0x8, 0xd }
27*54fd6939SJiyong Park 
28*54fd6939SJiyong Park /* OTPC Commands */
29*54fd6939SJiyong Park #define OTPC_CMD_READ                0x0
30*54fd6939SJiyong Park #define OTPC_CMD_OTP_PROG_ENABLE     0x2
31*54fd6939SJiyong Park #define OTPC_CMD_OTP_PROG_DISABLE    0x3
32*54fd6939SJiyong Park #define OTPC_CMD_PROGRAM             0x8
33*54fd6939SJiyong Park #define OTPC_CMD_ECC                 0x10
34*54fd6939SJiyong Park #define OTPC_ECC_ADDR                0x1A
35*54fd6939SJiyong Park #define OTPC_ECC_VAL                 0x00EC0000
36*54fd6939SJiyong Park 
37*54fd6939SJiyong Park /* OTPC Status Bits */
38*54fd6939SJiyong Park #define OTPC_STAT_CMD_DONE           BIT(1)
39*54fd6939SJiyong Park #define OTPC_STAT_PROG_OK            BIT(2)
40*54fd6939SJiyong Park 
41*54fd6939SJiyong Park /* OTPC register definition */
42*54fd6939SJiyong Park #define OTPC_MODE_REG_OFFSET         0x0
43*54fd6939SJiyong Park #define OTPC_MODE_REG_OTPC_MODE      0
44*54fd6939SJiyong Park #define OTPC_COMMAND_OFFSET          0x4
45*54fd6939SJiyong Park #define OTPC_COMMAND_COMMAND_WIDTH   6
46*54fd6939SJiyong Park #define OTPC_CMD_START_OFFSET        0x8
47*54fd6939SJiyong Park #define OTPC_CMD_START_START         0
48*54fd6939SJiyong Park #define OTPC_CPU_STATUS_OFFSET       0xc
49*54fd6939SJiyong Park #define OTPC_CPUADDR_REG_OFFSET      0x28
50*54fd6939SJiyong Park #define OTPC_CPUADDR_REG_OTPC_CPU_ADDRESS_WIDTH 16
51*54fd6939SJiyong Park #define OTPC_CPU_WRITE_REG_OFFSET    0x2c
52*54fd6939SJiyong Park 
53*54fd6939SJiyong Park #define OTPC_CMD_MASK  (BIT(OTPC_COMMAND_COMMAND_WIDTH) - 1)
54*54fd6939SJiyong Park #define OTPC_ADDR_MASK (BIT(OTPC_CPUADDR_REG_OTPC_CPU_ADDRESS_WIDTH) - 1)
55*54fd6939SJiyong Park 
56*54fd6939SJiyong Park #define OTPC_MODE_REG			OCOTP_REGS_BASE
57*54fd6939SJiyong Park 
58*54fd6939SJiyong Park struct chip_otp_cfg {
59*54fd6939SJiyong Park 	uint32_t base;
60*54fd6939SJiyong Park 	uint32_t num_words;
61*54fd6939SJiyong Park };
62*54fd6939SJiyong Park 
63*54fd6939SJiyong Park struct chip_otp_cfg ocotp_cfg = {
64*54fd6939SJiyong Park 	.base = OTPC_MODE_REG,
65*54fd6939SJiyong Park 	.num_words = 2048,
66*54fd6939SJiyong Park };
67*54fd6939SJiyong Park 
68*54fd6939SJiyong Park struct otpc_priv {
69*54fd6939SJiyong Park 	uint32_t base;
70*54fd6939SJiyong Park 	struct otpc_map *map;
71*54fd6939SJiyong Park 	int size;
72*54fd6939SJiyong Park 	int state;
73*54fd6939SJiyong Park };
74*54fd6939SJiyong Park 
75*54fd6939SJiyong Park struct otpc_priv otpc_info;
76*54fd6939SJiyong Park 
set_command(uint32_t base,uint32_t command)77*54fd6939SJiyong Park static inline void set_command(uint32_t base, uint32_t command)
78*54fd6939SJiyong Park {
79*54fd6939SJiyong Park 	mmio_write_32(base + OTPC_COMMAND_OFFSET, command & OTPC_CMD_MASK);
80*54fd6939SJiyong Park }
81*54fd6939SJiyong Park 
set_cpu_address(uint32_t base,uint32_t addr)82*54fd6939SJiyong Park static inline void set_cpu_address(uint32_t base, uint32_t addr)
83*54fd6939SJiyong Park {
84*54fd6939SJiyong Park 	mmio_write_32(base + OTPC_CPUADDR_REG_OFFSET, addr & OTPC_ADDR_MASK);
85*54fd6939SJiyong Park }
86*54fd6939SJiyong Park 
set_start_bit(uint32_t base)87*54fd6939SJiyong Park static inline void set_start_bit(uint32_t base)
88*54fd6939SJiyong Park {
89*54fd6939SJiyong Park 	mmio_write_32(base + OTPC_CMD_START_OFFSET, 1 << OTPC_CMD_START_START);
90*54fd6939SJiyong Park }
91*54fd6939SJiyong Park 
reset_start_bit(uint32_t base)92*54fd6939SJiyong Park static inline void reset_start_bit(uint32_t base)
93*54fd6939SJiyong Park {
94*54fd6939SJiyong Park 	mmio_write_32(base + OTPC_CMD_START_OFFSET, 0);
95*54fd6939SJiyong Park }
96*54fd6939SJiyong Park 
write_cpu_data(uint32_t base,uint32_t value)97*54fd6939SJiyong Park static inline void write_cpu_data(uint32_t base, uint32_t value)
98*54fd6939SJiyong Park {
99*54fd6939SJiyong Park 	mmio_write_32(base + OTPC_CPU_WRITE_REG_OFFSET, value);
100*54fd6939SJiyong Park }
101*54fd6939SJiyong Park 
poll_cpu_status(uint32_t base,uint32_t value)102*54fd6939SJiyong Park static int poll_cpu_status(uint32_t base, uint32_t value)
103*54fd6939SJiyong Park {
104*54fd6939SJiyong Park 	uint32_t status;
105*54fd6939SJiyong Park 	uint32_t retries;
106*54fd6939SJiyong Park 
107*54fd6939SJiyong Park 	for (retries = 0; retries < OTPC_RETRIES_US; retries++) {
108*54fd6939SJiyong Park 		status = mmio_read_32(base + OTPC_CPU_STATUS_OFFSET);
109*54fd6939SJiyong Park 		if (status & value)
110*54fd6939SJiyong Park 			break;
111*54fd6939SJiyong Park 		udelay(1);
112*54fd6939SJiyong Park 	}
113*54fd6939SJiyong Park 	if (retries == OTPC_RETRIES_US)
114*54fd6939SJiyong Park 		return -1;
115*54fd6939SJiyong Park 
116*54fd6939SJiyong Park 	return 0;
117*54fd6939SJiyong Park }
118*54fd6939SJiyong Park 
bcm_otpc_ecc(uint32_t enable)119*54fd6939SJiyong Park static int bcm_otpc_ecc(uint32_t enable)
120*54fd6939SJiyong Park {
121*54fd6939SJiyong Park 	struct otpc_priv *priv = &otpc_info;
122*54fd6939SJiyong Park 	int ret;
123*54fd6939SJiyong Park 
124*54fd6939SJiyong Park 	set_command(priv->base, OTPC_CMD_ECC);
125*54fd6939SJiyong Park 	set_cpu_address(priv->base, OTPC_ECC_ADDR);
126*54fd6939SJiyong Park 
127*54fd6939SJiyong Park 	if (!enable)
128*54fd6939SJiyong Park 		write_cpu_data(priv->base, OTPC_ECC_VAL);
129*54fd6939SJiyong Park 	else
130*54fd6939SJiyong Park 		write_cpu_data(priv->base, ~OTPC_ECC_VAL);
131*54fd6939SJiyong Park 
132*54fd6939SJiyong Park 	set_start_bit(priv->base);
133*54fd6939SJiyong Park 	ret = poll_cpu_status(priv->base, OTPC_STAT_CMD_DONE);
134*54fd6939SJiyong Park 	if (ret) {
135*54fd6939SJiyong Park 		ERROR("otp ecc op error: 0x%x", ret);
136*54fd6939SJiyong Park 		return -1;
137*54fd6939SJiyong Park 	}
138*54fd6939SJiyong Park 	reset_start_bit(priv->base);
139*54fd6939SJiyong Park 
140*54fd6939SJiyong Park 	return 0;
141*54fd6939SJiyong Park }
142*54fd6939SJiyong Park 
143*54fd6939SJiyong Park /*
144*54fd6939SJiyong Park  * bcm_otpc_read read otp data in the size of 8 byte rows.
145*54fd6939SJiyong Park  * bytes has to be the multiple of 8.
146*54fd6939SJiyong Park  * return -1 in error case, return read bytes in success.
147*54fd6939SJiyong Park  */
bcm_otpc_read(unsigned int offset,void * val,uint32_t bytes,uint32_t ecc_flag)148*54fd6939SJiyong Park int bcm_otpc_read(unsigned int offset, void *val, uint32_t bytes,
149*54fd6939SJiyong Park 		  uint32_t ecc_flag)
150*54fd6939SJiyong Park {
151*54fd6939SJiyong Park 	struct otpc_priv *priv = &otpc_info;
152*54fd6939SJiyong Park 	uint32_t *buf = val;
153*54fd6939SJiyong Park 	uint32_t bytes_read;
154*54fd6939SJiyong Park 	uint32_t address = offset / priv->map->word_size;
155*54fd6939SJiyong Park 	int i, ret;
156*54fd6939SJiyong Park 
157*54fd6939SJiyong Park 	if (!priv->state) {
158*54fd6939SJiyong Park 		ERROR("OCOTP read failed\n");
159*54fd6939SJiyong Park 		return -1;
160*54fd6939SJiyong Park 	}
161*54fd6939SJiyong Park 
162*54fd6939SJiyong Park 	bcm_otpc_ecc(ecc_flag);
163*54fd6939SJiyong Park 
164*54fd6939SJiyong Park 	for (bytes_read = 0; (bytes_read + priv->map->word_size) <= bytes;) {
165*54fd6939SJiyong Park 		set_command(priv->base, OTPC_CMD_READ);
166*54fd6939SJiyong Park 		set_cpu_address(priv->base, address++);
167*54fd6939SJiyong Park 		set_start_bit(priv->base);
168*54fd6939SJiyong Park 		ret = poll_cpu_status(priv->base, OTPC_STAT_CMD_DONE);
169*54fd6939SJiyong Park 		if (ret) {
170*54fd6939SJiyong Park 			ERROR("otp read error: 0x%x", ret);
171*54fd6939SJiyong Park 			return -1;
172*54fd6939SJiyong Park 		}
173*54fd6939SJiyong Park 
174*54fd6939SJiyong Park 		for (i = 0; i < priv->map->otpc_row_size; i++) {
175*54fd6939SJiyong Park 			*buf++ = mmio_read_32(priv->base +
176*54fd6939SJiyong Park 					priv->map->data_r_offset[i]);
177*54fd6939SJiyong Park 			bytes_read += sizeof(*buf);
178*54fd6939SJiyong Park 		}
179*54fd6939SJiyong Park 
180*54fd6939SJiyong Park 		reset_start_bit(priv->base);
181*54fd6939SJiyong Park 	}
182*54fd6939SJiyong Park 
183*54fd6939SJiyong Park 	return bytes_read;
184*54fd6939SJiyong Park }
185*54fd6939SJiyong Park 
bcm_otpc_init(struct otpc_map * map)186*54fd6939SJiyong Park int bcm_otpc_init(struct otpc_map *map)
187*54fd6939SJiyong Park {
188*54fd6939SJiyong Park 	struct otpc_priv *priv;
189*54fd6939SJiyong Park 
190*54fd6939SJiyong Park 	priv = &otpc_info;
191*54fd6939SJiyong Park 	priv->base = ocotp_cfg.base;
192*54fd6939SJiyong Park 	priv->map = map;
193*54fd6939SJiyong Park 
194*54fd6939SJiyong Park 	priv->size = 4 * ocotp_cfg.num_words;
195*54fd6939SJiyong Park 
196*54fd6939SJiyong Park 	/* Enable CPU access to OTPC. */
197*54fd6939SJiyong Park 	mmio_setbits_32(priv->base + OTPC_MODE_REG_OFFSET,
198*54fd6939SJiyong Park 			BIT(OTPC_MODE_REG_OTPC_MODE));
199*54fd6939SJiyong Park 	reset_start_bit(priv->base);
200*54fd6939SJiyong Park 	priv->state = 1;
201*54fd6939SJiyong Park 	VERBOSE("OTPC Initialization done\n");
202*54fd6939SJiyong Park 
203*54fd6939SJiyong Park 	return 0;
204*54fd6939SJiyong Park }
205