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   */