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
set_command(uint32_t base,uint32_t command)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
set_cpu_address(uint32_t base,uint32_t addr)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
set_start_bit(uint32_t base)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
reset_start_bit(uint32_t base)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
write_cpu_data(uint32_t base,uint32_t value)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
poll_cpu_status(uint32_t base,uint32_t value)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
bcm_otpc_ecc(uint32_t enable)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 */
bcm_otpc_read(unsigned int offset,void * val,uint32_t bytes,uint32_t ecc_flag)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
bcm_otpc_init(struct otpc_map * map)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