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