1 /*
2 * SPDX-FileCopyrightText: 2017-2021 Espressif Systems (Shanghai) CO LTD
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include "esp_efuse_utility.h"
8 #include "soc/efuse_periph.h"
9 #include "esp32/clk.h"
10 #include "esp_log.h"
11 #include "assert.h"
12 #include "sdkconfig.h"
13 #include <sys/param.h>
14
15 static const char *TAG = "efuse";
16
17 #ifdef CONFIG_EFUSE_VIRTUAL
18 extern uint32_t virt_blocks[EFUSE_BLK_MAX][COUNT_EFUSE_REG_PER_BLOCK];
19 #endif // CONFIG_EFUSE_VIRTUAL
20
21 /*Range addresses to read blocks*/
22 const esp_efuse_range_addr_t range_read_addr_blocks[] = {
23 {EFUSE_BLK0_RDATA0_REG, EFUSE_BLK0_RDATA6_REG}, // range address of EFUSE_BLK0
24 {EFUSE_BLK1_RDATA0_REG, EFUSE_BLK1_RDATA7_REG}, // range address of EFUSE_BLK1
25 {EFUSE_BLK2_RDATA0_REG, EFUSE_BLK2_RDATA7_REG}, // range address of EFUSE_BLK2
26 {EFUSE_BLK3_RDATA0_REG, EFUSE_BLK3_RDATA7_REG} // range address of EFUSE_BLK3
27 };
28
29 /*Range addresses to write blocks*/
30 const esp_efuse_range_addr_t range_write_addr_blocks[] = {
31 {EFUSE_BLK0_WDATA0_REG, EFUSE_BLK0_WDATA6_REG}, // range address of EFUSE_BLK0
32 {EFUSE_BLK1_WDATA0_REG, EFUSE_BLK1_WDATA7_REG}, // range address of EFUSE_BLK1
33 {EFUSE_BLK2_WDATA0_REG, EFUSE_BLK2_WDATA7_REG}, // range address of EFUSE_BLK2
34 {EFUSE_BLK3_WDATA0_REG, EFUSE_BLK3_WDATA7_REG} // range address of EFUSE_BLK3
35 };
36
37 #define EFUSE_CONF_WRITE 0x5A5A /* eFuse_pgm_op_ena, force no rd/wr disable. */
38 #define EFUSE_CONF_READ 0x5AA5 /* eFuse_read_op_ena, release force. */
39 #define EFUSE_CMD_PGM 0x02 /* Command to program. */
40 #define EFUSE_CMD_READ 0x01 /* Command to read. */
41
42 #ifndef CONFIG_EFUSE_VIRTUAL
43 // Update Efuse timing configuration
esp_efuse_set_timing(void)44 static esp_err_t esp_efuse_set_timing(void)
45 {
46 uint32_t apb_freq_mhz = esp_clk_apb_freq() / 1000000;
47 uint32_t clk_sel0, clk_sel1, dac_clk_div;
48 if (apb_freq_mhz <= 26) {
49 clk_sel0 = 250;
50 clk_sel1 = 255;
51 dac_clk_div = 52;
52 } else if (apb_freq_mhz <= 40) {
53 clk_sel0 = 160;
54 clk_sel1 = 255;
55 dac_clk_div = 80;
56 } else {
57 clk_sel0 = 80;
58 clk_sel1 = 128;
59 dac_clk_div = 100;
60 }
61 REG_SET_FIELD(EFUSE_DAC_CONF_REG, EFUSE_DAC_CLK_DIV, dac_clk_div);
62 REG_SET_FIELD(EFUSE_CLK_REG, EFUSE_CLK_SEL0, clk_sel0);
63 REG_SET_FIELD(EFUSE_CLK_REG, EFUSE_CLK_SEL1, clk_sel1);
64 return ESP_OK;
65 }
66 #endif // ifndef CONFIG_EFUSE_VIRTUAL
67
68 // Efuse read operation: copies data from physical efuses to efuse read registers.
esp_efuse_utility_clear_program_registers(void)69 void esp_efuse_utility_clear_program_registers(void)
70 {
71 REG_WRITE(EFUSE_CONF_REG, EFUSE_CONF_READ);
72 }
73
74 // Burn values written to the efuse write registers
esp_efuse_utility_burn_chip(void)75 void esp_efuse_utility_burn_chip(void)
76 {
77 #ifdef CONFIG_EFUSE_VIRTUAL
78 ESP_LOGW(TAG, "Virtual efuses enabled: Not really burning eFuses");
79 for (int num_block = EFUSE_BLK0; num_block < EFUSE_BLK_MAX; num_block++) {
80 esp_efuse_coding_scheme_t scheme = esp_efuse_get_coding_scheme(num_block);
81 if (scheme == EFUSE_CODING_SCHEME_3_4) {
82 uint8_t buf[COUNT_EFUSE_REG_PER_BLOCK * 4] = { 0 };
83 int i = 0;
84 for (uint32_t addr_wr_block = range_write_addr_blocks[num_block].start; addr_wr_block <= range_write_addr_blocks[num_block].end; addr_wr_block += 4, ++i) {
85 *((uint32_t*)buf + i) = REG_READ(addr_wr_block);
86 }
87 int j = 0;
88 uint32_t out_buf[COUNT_EFUSE_REG_PER_BLOCK] = { 0 };
89 for (int k = 0; k < 4; ++k, ++j) {
90 memcpy((uint8_t*)out_buf + j * 6, &buf[k * 8], 6);
91 }
92 for (int k = 0; k < COUNT_EFUSE_REG_PER_BLOCK; ++k) {
93 REG_WRITE(range_write_addr_blocks[num_block].start + k * 4, out_buf[k]);
94 }
95 }
96 int subblock = 0;
97 for (uint32_t addr_wr_block = range_write_addr_blocks[num_block].start; addr_wr_block <= range_write_addr_blocks[num_block].end; addr_wr_block += 4) {
98 virt_blocks[num_block][subblock++] |= REG_READ(addr_wr_block);
99 }
100 }
101 #ifdef CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH
102 esp_efuse_utility_write_efuses_to_flash();
103 #endif
104 #else
105 esp_efuse_set_timing();
106 // Permanently update values written to the efuse write registers
107 REG_WRITE(EFUSE_CONF_REG, EFUSE_CONF_WRITE);
108 REG_WRITE(EFUSE_CMD_REG, EFUSE_CMD_PGM);
109 while (REG_READ(EFUSE_CMD_REG) != 0) {};
110 REG_WRITE(EFUSE_CONF_REG, EFUSE_CONF_READ);
111 REG_WRITE(EFUSE_CMD_REG, EFUSE_CMD_READ);
112 while (REG_READ(EFUSE_CMD_REG) != 0) {};
113 #endif // CONFIG_EFUSE_VIRTUAL
114 esp_efuse_utility_reset();
115 }
116
esp_efuse_utility_apply_34_encoding(const uint8_t * in_bytes,uint32_t * out_words,size_t in_bytes_len)117 esp_err_t esp_efuse_utility_apply_34_encoding(const uint8_t *in_bytes, uint32_t *out_words, size_t in_bytes_len)
118 {
119 if (in_bytes == NULL || out_words == NULL || in_bytes_len % 6 != 0) {
120 return ESP_ERR_INVALID_ARG;
121 }
122
123 while (in_bytes_len > 0) {
124 uint8_t out[8];
125 uint8_t xor = 0;
126 uint8_t mul = 0;
127 for (int i = 0; i < 6; i++) {
128 xor ^= in_bytes[i];
129 mul += (i + 1) * __builtin_popcount(in_bytes[i]);
130 }
131
132 memcpy(out, in_bytes, 6); // Data bytes
133 out[6] = xor;
134 out[7] = mul;
135
136 memcpy(out_words, out, 8);
137
138 in_bytes_len -= 6;
139 in_bytes += 6;
140 out_words += 2;
141 }
142
143 return ESP_OK;
144 }
145
read_w_data_and_check_fill(esp_efuse_block_t num_block,uint32_t * buf_w_data)146 static bool read_w_data_and_check_fill(esp_efuse_block_t num_block, uint32_t *buf_w_data)
147 {
148 bool blk_is_filled = false;
149 int i = 0;
150 for (uint32_t addr_wr_block = range_write_addr_blocks[num_block].start; addr_wr_block <= range_write_addr_blocks[num_block].end; addr_wr_block += 4, ++i) {
151 buf_w_data[i] = REG_READ(addr_wr_block);
152 if (buf_w_data[i] != 0) {
153 REG_WRITE(addr_wr_block, 0);
154 blk_is_filled = true;
155 }
156 }
157 return blk_is_filled;
158 }
159
read_r_data(esp_efuse_block_t num_block,uint32_t * buf_r_data)160 static void read_r_data(esp_efuse_block_t num_block, uint32_t* buf_r_data)
161 {
162 int i = 0;
163 for (uint32_t addr_rd_block = range_read_addr_blocks[num_block].start; addr_rd_block <= range_read_addr_blocks[num_block].end; addr_rd_block += 4, ++i) {
164 buf_r_data[i] = esp_efuse_utility_read_reg(num_block, i);
165 }
166 }
167
168 // After esp_efuse_write.. functions EFUSE_BLKx_WDATAx_REG were filled is not coded values.
169 // This function reads EFUSE_BLKx_WDATAx_REG registers, applies coding scheme and writes encoded values back to EFUSE_BLKx_WDATAx_REG.
esp_efuse_utility_apply_new_coding_scheme()170 esp_err_t esp_efuse_utility_apply_new_coding_scheme()
171 {
172 uint8_t buf_w_data[COUNT_EFUSE_REG_PER_BLOCK * 4];
173 uint8_t buf_r_data[COUNT_EFUSE_REG_PER_BLOCK * 4];
174 uint32_t reg[COUNT_EFUSE_REG_PER_BLOCK];
175 // start with EFUSE_BLK1. EFUSE_BLK0 - always uses EFUSE_CODING_SCHEME_NONE.
176 for (int num_block = EFUSE_BLK1; num_block < EFUSE_BLK_MAX; num_block++) {
177 esp_efuse_coding_scheme_t scheme = esp_efuse_get_coding_scheme(num_block);
178 // check and apply a new coding scheme.
179 if (scheme != EFUSE_CODING_SCHEME_NONE) {
180 memset(buf_w_data, 0, sizeof(buf_w_data));
181 memset((uint8_t*)reg, 0, sizeof(reg));
182 if (read_w_data_and_check_fill(num_block, (uint32_t*)buf_w_data) == true) {
183 read_r_data(num_block, (uint32_t*)buf_r_data);
184 if (scheme == EFUSE_CODING_SCHEME_3_4) {
185 if (*((uint32_t*)buf_w_data + 6) != 0 || *((uint32_t*)buf_w_data + 7) != 0) {
186 return ESP_ERR_CODING;
187 }
188 for (int i = 0; i < 24; ++i) {
189 if (buf_w_data[i] != 0) {
190 int st_offset_buf = (i / 6) * 6;
191 // check that place is free.
192 for (int n = st_offset_buf; n < st_offset_buf + 6; ++n) {
193 if (buf_r_data[n] != 0) {
194 ESP_LOGE(TAG, "Bits are not empty. Write operation is forbidden.");
195 return ESP_ERR_CODING;
196 }
197 }
198
199 esp_err_t err = esp_efuse_utility_apply_34_encoding(&buf_w_data[st_offset_buf], reg, 6);
200 if (err != ESP_OK) {
201 return err;
202 }
203
204 int num_reg = (st_offset_buf / 6) * 2;
205 for (int r = 0; r < 2; r++) {
206 REG_WRITE(range_write_addr_blocks[num_block].start + (num_reg + r) * 4, reg[r]);
207 }
208 i = st_offset_buf + 5;
209 }
210 }
211 } else if (scheme == EFUSE_CODING_SCHEME_REPEAT) {
212 uint32_t* buf_32 = (uint32_t*)buf_w_data;
213 for (int i = 4; i < 8; ++i) {
214 if (*(buf_32 + i) != 0) {
215 return ESP_ERR_CODING;
216 }
217 }
218 for (int i = 0; i < 4; ++i) {
219 if (buf_32[i] != 0) {
220 REG_WRITE(range_write_addr_blocks[num_block].start + i * 4, buf_32[i]);
221 REG_WRITE(range_write_addr_blocks[num_block].start + (i + 4) * 4, buf_32[i]);
222 }
223 }
224 }
225 }
226 }
227 }
228 return ESP_OK;
229 }
230