1 /*
2 * SPDX-FileCopyrightText: 2019-2025 SiFli Technologies(Nanjing) Co., Ltd
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include "bf0_hal.h"
8
9 /** @addtogroup BF0_HAL_Driver
10 * @{
11 */
12
13 /** @defgroup EFUSE EFUSE
14 * @brief EFUSE HAL module driver
15 * @{
16 */
17
18 #if (defined(HAL_EFUSE_MODULE_ENABLED))||defined(_SIFLI_DOXYGEN_)
19
20 #define EFUSE_PGM_THPCK_NS (20)
21 #define EFUSE_PGM_TCKHP_US (10)
22 #define EFUSE_RD_TIM_NS (500)
23 #define EFUSE_PCLK_LIMIT (120000000)
24
25
HAL_EFUSE_Init(void)26 HAL_StatusTypeDef HAL_EFUSE_Init(void)
27 {
28 uint32_t pclk;
29 uint32_t pgm_tckhp;
30 uint32_t pgm_thpck;
31 uint32_t rd_thrck;
32 uint32_t pgm_tckhp_ns;
33
34 pclk = HAL_RCC_GetPCLKFreq(CORE_ID_HCPU, true);
35 if (pclk > EFUSE_PCLK_LIMIT)
36 {
37 return HAL_ERROR;
38 }
39
40 pgm_thpck = (uint64_t)EFUSE_PGM_THPCK_NS * pclk / (1000 * 1000000) + 1;
41 pgm_thpck = MAKE_REG_VAL(pgm_thpck, EFUSEC_TIMR_THPCK_Msk, EFUSEC_TIMR_THPCK_Pos);
42 if (pgm_thpck > EFUSEC_TIMR_THPCK)
43 {
44 return HAL_ERROR;
45 }
46
47 pgm_tckhp = ((uint64_t)EFUSE_PGM_TCKHP_US * pclk + 500000) / 1000000;
48 pgm_tckhp_ns = (uint64_t)pgm_tckhp * 1000000 * 1000 / pclk;
49 if (pgm_tckhp_ns > 11000)
50 {
51 pgm_tckhp -= 1;
52 }
53 else if (pgm_tckhp_ns < 9000)
54 {
55 pgm_tckhp += 1;
56 }
57 pgm_tckhp = MAKE_REG_VAL(pgm_tckhp, EFUSEC_TIMR_TCKHP_Msk, EFUSEC_TIMR_TCKHP_Pos);
58 if (pgm_tckhp > EFUSEC_TIMR_TCKHP)
59 {
60 return HAL_ERROR;
61 }
62
63 rd_thrck = (uint64_t)EFUSE_RD_TIM_NS * pclk / (1000 * 1000000) + 1;
64 rd_thrck = MAKE_REG_VAL(rd_thrck, EFUSEC_TIMR_THRCK_Msk, EFUSEC_TIMR_THRCK_Pos);
65 if (rd_thrck > EFUSEC_TIMR_THRCK)
66 {
67 return HAL_ERROR;
68 }
69
70 hwp_efusec->TIMR = pgm_thpck | pgm_tckhp | rd_thrck;
71
72 return HAL_OK;
73 }
74
HAL_EFUSE_ConfigBypass(bool enabled)75 void HAL_EFUSE_ConfigBypass(bool enabled)
76 {
77 HAL_ASSERT(0);
78 }
79
80
HAL_EFUSE_Write(uint16_t bit_offset,uint8_t * data,int32_t size)81 int32_t HAL_EFUSE_Write(uint16_t bit_offset, uint8_t *data, int32_t size)
82 {
83 uint32_t ready = 0;
84 int byte_off = (bit_offset >> 3) % HAL_EFUSE_BANK_SIZE;
85 int bank = (bit_offset >> 8);
86 volatile uint32_t *pg_reg = (volatile uint32_t *) & (hwp_efusec->PGM_DATA0);
87 uint32_t timeout;
88 uint32_t i;
89 uint32_t word_size;
90
91 // Should be less than a bank, and do not accross bank
92 if ((size > HAL_EFUSE_BANK_SIZE)
93 || ((byte_off + size) > HAL_EFUSE_BANK_SIZE)
94 || (size & 3) //multiple of 4
95 || (bit_offset & 31)) //offset is 32bits aligned
96 {
97 return 0;
98 }
99
100 /* clear PGM_DATA to avoid programming unexpected bit */
101 for (i = 0; i < 8; i++)
102 {
103 pg_reg[i] = 0;
104 }
105
106 #if defined(SF32LB55X) || defined(SF32LB58X)
107 // TODO: Check for 54x
108
109 /* Change HPSYS LDO VERF */
110 uint32_t org = READ_REG(hwp_pmuc->LDO_CR);
111 org &= PMUC_LDO_CR_HPSYS_LDO_VREF_Msk;
112 org >>= PMUC_LDO_CR_HPSYS_LDO_VREF_Pos;
113 uint32_t value = org + 3;
114 if (value > 0xf)
115 value = 0xf;
116 MODIFY_REG(hwp_pmuc->LDO_CR, PMUC_LDO_CR_HPSYS_LDO_VREF_Msk, value << PMUC_LDO_CR_HPSYS_LDO_VREF_Pos);
117 #else
118 uint32_t org = READ_REG(hwp_pmuc->HPSYS_LDO);
119 org &= PMUC_HPSYS_LDO_VREF_Msk;
120 org >>= PMUC_HPSYS_LDO_VREF_Pos;
121 uint32_t value = org + 3;
122 if (value > 0xf)
123 value = 0xf;
124 MODIFY_REG(hwp_pmuc->HPSYS_LDO, PMUC_HPSYS_LDO_VREF_Msk, value << PMUC_HPSYS_LDO_VREF_Pos);
125 #endif
126
127 #ifndef SF32LB52X
128 /* Enable BGR if it has not been enabled,
129 it may have been enabled by other module,
130 don't disable it as other module may need it */
131 hwp_tsen->BGR |= TSEN_BGR_EN;
132 /* delay 50us, then enable LDO */
133 HAL_Delay_us(50);
134 #else
135 MODIFY_REG(hwp_hpsys_cfg->ANAU_CR, HPSYS_CFG_ANAU_CR_EFUSE_VDD_PD, HPSYS_CFG_ANAU_CR_EFUSE_VDD_EN);
136 #endif
137
138 hwp_efusec->ANACR |= EFUSEC_ANACR_LDO_EN;
139 /* delay 50us, then starting programming */
140 HAL_Delay_us(50);
141
142 /* select bank and enable PGM mode */
143 hwp_efusec->CR = (bank << EFUSEC_CR_BANKSEL_Pos) | (1 << EFUSEC_CR_MODE_Pos);
144
145 pg_reg += (byte_off >> 2);
146 word_size = size >> 2;
147 for (i = 0; i < word_size; i++)
148 {
149 pg_reg[i] = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
150 data += 4;
151 }
152 /* start program */
153 hwp_efusec->CR |= EFUSEC_CR_EN;
154 /* minimum: 10us one bit
155 * here: 10ms one bit for 48MHz clock
156 */
157 timeout = (uint32_t)size * 8 * 480000;
158 while (((hwp_efusec->SR & EFUSEC_SR_DONE) == 0) && (ready < timeout))
159 ready++;
160 hwp_efusec->SR |= EFUSEC_SR_DONE;
161
162 if (ready >= timeout)
163 {
164 size = 0;
165 }
166
167 hwp_efusec->ANACR &= ~EFUSEC_ANACR_LDO_EN;
168
169 #if defined(SF32LB55X) || defined(SF32LB58X)
170 /* Recover LDO VREF value*/
171 MODIFY_REG(hwp_pmuc->LDO_CR, PMUC_LDO_CR_HPSYS_LDO_VREF_Msk, org << PMUC_LDO_CR_HPSYS_LDO_VREF_Pos);
172 #else
173 MODIFY_REG(hwp_pmuc->HPSYS_LDO, PMUC_HPSYS_LDO_VREF_Msk, org << PMUC_HPSYS_LDO_VREF_Pos);
174 #endif
175
176 #ifdef SF32LB52X
177 MODIFY_REG(hwp_hpsys_cfg->ANAU_CR, HPSYS_CFG_ANAU_CR_EFUSE_VDD_EN, HPSYS_CFG_ANAU_CR_EFUSE_VDD_PD);
178 #endif
179 return size;
180 }
181
HAL_EFUSE_Read(uint16_t bit_offset,uint8_t * data,int size)182 int32_t HAL_EFUSE_Read(uint16_t bit_offset, uint8_t *data, int size)
183 {
184 uint32_t ready = 0;
185 int byte_off = (bit_offset >> 3) % HAL_EFUSE_BANK_SIZE;
186 int bank = (bit_offset >> 8);
187 uint32_t timeout;
188 volatile uint32_t *rd_reg = (volatile uint32_t *) & (hwp_efusec->BANK0_DATA0);
189 uint32_t i;
190 uint32_t word_size;
191 uint32_t val;
192
193 if ((size > HAL_EFUSE_BANK_SIZE)
194 || ((byte_off + size) > HAL_EFUSE_BANK_SIZE) // Should be less than a bank, and do not accross bank
195 || (size & 3) //multiple of 4
196 || (bit_offset & 31)) //offset is 32bits aligned
197 {
198 return 0;
199 }
200
201 #if defined(SF32LB55X)||defined(SF32LB58X)
202 /* Change HPSYS LDO VERF */
203 uint32_t org = READ_REG(hwp_pmuc->LDO_CR);
204 org &= PMUC_LDO_CR_HPSYS_LDO_VREF_Msk;
205 org >>= PMUC_LDO_CR_HPSYS_LDO_VREF_Pos;
206 uint32_t value = org + 3;
207 if (value > 0xf)
208 value = 0xf;
209 if (value < 0xe)
210 value = 0xe;
211 MODIFY_REG(hwp_pmuc->LDO_CR, PMUC_LDO_CR_HPSYS_LDO_VREF_Msk, value << PMUC_LDO_CR_HPSYS_LDO_VREF_Pos);
212 #elif defined (SF32LB56X)
213 uint32_t org = READ_REG(hwp_pmuc->HPSYS_LDO);
214 org &= PMUC_HPSYS_LDO_VREF_Msk;
215 org >>= PMUC_HPSYS_LDO_VREF_Pos;
216 uint32_t value = org + 3;
217 if (value > 0xf)
218 value = 0xf;
219 if (value < 0xe)
220 value = 0xe;
221 MODIFY_REG(hwp_pmuc->HPSYS_LDO, PMUC_HPSYS_LDO_VREF_Msk, value << PMUC_HPSYS_LDO_VREF_Pos);
222 #elif defined (SF32LB52X)
223 uint32_t org = READ_REG(hwp_pmuc->HPSYS_VOUT);
224 uint32_t value = org + 3;
225 if (value > 0xf)
226 value = 0xf;
227 if (value < 0xe)
228 value = 0xe;
229 hwp_pmuc->HPSYS_VOUT = value;
230 HAL_Delay_us(20);
231 #endif
232 //HAL_Delay_us(20);
233 /* select bank and enable READ mode */
234 hwp_efusec->CR = (bank << EFUSEC_CR_BANKSEL_Pos);
235 /* start read */
236 hwp_efusec->CR |= EFUSEC_CR_EN;
237 /* mininum: two cycle one bit
238 * here: 1ms one bit for 48MHz clock
239 */
240 timeout = (uint32_t)size * 8 * 48000;
241 while (((hwp_efusec->SR & EFUSEC_SR_DONE) == 0) && (ready < timeout))
242 ready++;
243
244 hwp_efusec->SR |= EFUSEC_SR_DONE;
245
246 if (ready >= timeout)
247 {
248 /* Recover LDO VREF value*/
249 #if defined(SF32LB55X)||defined(SF32LB58X)
250 MODIFY_REG(hwp_pmuc->LDO_CR, PMUC_LDO_CR_HPSYS_LDO_VREF_Msk, org << PMUC_LDO_CR_HPSYS_LDO_VREF_Pos);
251 #elif defined(SF32LB52X)
252 hwp_pmuc->HPSYS_VOUT = org;
253 #else
254 MODIFY_REG(hwp_pmuc->HPSYS_LDO, PMUC_HPSYS_LDO_VREF_Msk, org << PMUC_HPSYS_LDO_VREF_Pos);
255 #endif
256 return 0;
257 }
258 rd_reg += (bank << 3); // Each bank has 8 registers.
259 rd_reg += (byte_off >> 2);
260 word_size = size >> 2;
261 for (i = 0; i < word_size; i++)
262 {
263 val = rd_reg[i];
264 data[0] = val & 0xFF;
265 data[1] = (val >> 8) & 0xFF;
266 data[2] = (val >> 16) & 0xFF;
267 data[3] = (val >> 24) & 0xFF;
268 data += 4;
269 }
270
271 #if defined(SF32LB55X)||defined(SF32LB58X)
272 /* Recover LDO VREF value*/
273 MODIFY_REG(hwp_pmuc->LDO_CR, PMUC_LDO_CR_HPSYS_LDO_VREF_Msk, org << PMUC_LDO_CR_HPSYS_LDO_VREF_Pos);
274 #elif defined(SF32LB52X)
275 hwp_pmuc->HPSYS_VOUT = org;
276 #else
277 MODIFY_REG(hwp_pmuc->HPSYS_LDO, PMUC_HPSYS_LDO_VREF_Msk, org << PMUC_HPSYS_LDO_VREF_Pos);
278 #endif
279 return size;
280 }
281
282 #endif /* HAL_EFUSE_MODULE_ENABLED */
283
284
285 /**
286 * @}
287 */
288
289 /**
290 * @}
291 */