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