Skip to content

Commit 8128703

Browse files
committed
drivers: eeprom: Introduce BFLB Efuse driver
This introduces a driver used to access bouffalolab efuses via eeprom API Signed-off-by: Camille BAUD <[email protected]>
1 parent 1a97893 commit 8128703

File tree

5 files changed

+272
-0
lines changed

5 files changed

+272
-0
lines changed

drivers/eeprom/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,5 @@ zephyr_library_sources_ifdef(CONFIG_EEPROM_AT2X_EMUL eeprom_at2x_emul.c)
2828
zephyr_library_sources_ifdef(CONFIG_EEPROM_MB85RCXX eeprom_mb85rcxx.c)
2929

3030
zephyr_library_sources_ifdef(CONFIG_EEPROM_MB85RSXX eeprom_mb85rsxx.c)
31+
32+
zephyr_library_sources_ifdef(CONFIG_EFUSE_BFLB efuse_bflb.c)

drivers/eeprom/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ source "drivers/eeprom/Kconfig.tmp11x"
100100
source "drivers/eeprom/Kconfig.xec"
101101
source "drivers/eeprom/Kconfig.mb85rcxx"
102102
source "drivers/eeprom/Kconfig.mb85rsxx"
103+
source "drivers/eeprom/Kconfig.bflb"
103104

104105
config EEPROM_SIMULATOR
105106
bool "Simulated EEPROM driver"

drivers/eeprom/Kconfig.bflb

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Copyright (c) 2024-2025 MASSDRIVER EI (massdriver.space)
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
config EFUSE_BFLB
5+
bool "Bouffalolab EFUSEs driver"
6+
default y
7+
depends on DT_HAS_BFLB_EFUSE_ENABLED
8+
help
9+
Enable accessing internal Efuses via EEPROM API for Bouffalolab platforms.

drivers/eeprom/efuse_bflb.c

Lines changed: 243 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,243 @@
1+
/*
2+
* Copyright (c) 2024-2025 MASSDRIVER EI (massdriver.space)
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#define DT_DRV_COMPAT bflb_efuse
8+
9+
#include <zephyr/drivers/eeprom.h>
10+
#include <zephyr/kernel.h>
11+
12+
#include <zephyr/logging/log.h>
13+
LOG_MODULE_REGISTER(efuse_bflb, CONFIG_EEPROM_LOG_LEVEL);
14+
15+
#include <bouffalolab/bl60x/bflb_soc.h>
16+
#include <bouffalolab/bl60x/hbn_reg.h>
17+
#include <bouffalolab/bl60x/ef_ctrl_reg.h>
18+
#include <bouffalolab/bl60x/extra_defines.h>
19+
20+
#ifndef EF_CTRL_DFT_TIMEOUT_VAL
21+
#define EF_CTRL_DFT_TIMEOUT_VAL 320*1000
22+
#endif
23+
#define EF_CTRL_EFUSE_CTRL_PROTECT (0xbf << 8)
24+
#define EF_CTRL_OP_MODE_AUTO 0
25+
#define EF_CTRL_PARA_DFT 0
26+
27+
struct efuse_bflb_data {
28+
uint8_t cache[DT_INST_PROP(0, size)];
29+
bool cached;
30+
};
31+
32+
struct efuse_bflb_config {
33+
uint32_t addr;
34+
size_t size;
35+
};
36+
37+
38+
static void system_clock_settle(void)
39+
{
40+
__asm__ volatile (".rept 15 ; nop ; .endr");
41+
}
42+
43+
/* 32 Mhz Oscillator: 0
44+
* crystal: 1
45+
* PLL and 32M: 2
46+
* PLL and crystal: 3
47+
*/
48+
static void system_set_root_clock(uint32_t clock)
49+
{
50+
uint32_t tmp = 0;
51+
52+
/* invalid value, fallback to internal 32M */
53+
if (clock < 0 || clock > 3) {
54+
clock = 0;
55+
}
56+
tmp = sys_read32(HBN_BASE + HBN_GLB_OFFSET);
57+
tmp = (tmp & HBN_ROOT_CLK_SEL_UMSK) | (clock << HBN_ROOT_CLK_SEL_POS);
58+
sys_write32(tmp, HBN_BASE + HBN_GLB_OFFSET);
59+
60+
system_clock_settle();
61+
}
62+
63+
static void system_clock_delay_32M_ms(uint32_t ms)
64+
{
65+
uint32_t count = 0;
66+
67+
do {
68+
__asm__ volatile (".rept 32 ; nop ; .endr");
69+
count++;
70+
} while (count < ms);
71+
}
72+
73+
static uint32_t is_pds_busy(const struct device *dev)
74+
{
75+
uint32_t tmp = 0;
76+
const struct efuse_bflb_config *config = dev->config;
77+
78+
tmp = sys_read32(config->addr + EF_CTRL_EF_IF_CTRL_0_OFFSET);
79+
if (tmp & EF_CTRL_EF_IF_0_BUSY_MSK) {
80+
return 1;
81+
}
82+
return 0;
83+
}
84+
85+
/* /!\ only use when running on 32Mhz Oscillator Clock
86+
* (system_set_root_clock(0);
87+
* system_set_root_clock_dividers(0, 0);
88+
* sys_write32(32 * 1000 * 1000, CORECLOCKREGISTER);)
89+
* Only Use with IRQs off
90+
* returns 0 when error
91+
*/
92+
static void system_efuse_read(const struct device *dev)
93+
{
94+
const struct efuse_bflb_config *config = dev->config;
95+
uint32_t tmp = 0;
96+
uint32_t *pefuse_start = (uint32_t *)(config->addr);
97+
uint32_t timeout = 0;
98+
99+
do {
100+
system_clock_delay_32M_ms(1);
101+
timeout++;
102+
} while (timeout < EF_CTRL_DFT_TIMEOUT_VAL && is_pds_busy(dev) > 0);
103+
104+
/* do a 'ahb clock' setup */
105+
tmp = EF_CTRL_EFUSE_CTRL_PROTECT |
106+
(EF_CTRL_OP_MODE_AUTO << EF_CTRL_EF_IF_0_MANUAL_EN_POS) |
107+
(EF_CTRL_PARA_DFT << EF_CTRL_EF_IF_0_CYC_MODIFY_POS) |
108+
(EF_CTRL_SAHB_CLK << EF_CTRL_EF_CLK_SAHB_DATA_SEL_POS) |
109+
(1 << EF_CTRL_EF_IF_AUTO_RD_EN_POS) |
110+
(0 << EF_CTRL_EF_IF_POR_DIG_POS) |
111+
(1 << EF_CTRL_EF_IF_0_INT_CLR_POS) |
112+
(0 << EF_CTRL_EF_IF_0_RW_POS) |
113+
(0 << EF_CTRL_EF_IF_0_TRIG_POS);
114+
115+
sys_write32(tmp, config->addr + EF_CTRL_EF_IF_CTRL_0_OFFSET);
116+
system_clock_settle();
117+
118+
/* clear PDS cache registry */
119+
for (uint32_t i = 0; i < config->size / 4; i++) {
120+
pefuse_start[i] = 0;
121+
}
122+
123+
/* Load efuse region0 */
124+
/* not ahb clock setup */
125+
tmp = EF_CTRL_EFUSE_CTRL_PROTECT |
126+
(EF_CTRL_OP_MODE_AUTO << EF_CTRL_EF_IF_0_MANUAL_EN_POS) |
127+
(EF_CTRL_PARA_DFT << EF_CTRL_EF_IF_0_CYC_MODIFY_POS) |
128+
(EF_CTRL_EF_CLK << EF_CTRL_EF_CLK_SAHB_DATA_SEL_POS) |
129+
(1 << EF_CTRL_EF_IF_AUTO_RD_EN_POS) |
130+
(0 << EF_CTRL_EF_IF_POR_DIG_POS) |
131+
(1 << EF_CTRL_EF_IF_0_INT_CLR_POS) |
132+
(0 << EF_CTRL_EF_IF_0_RW_POS) |
133+
(0 << EF_CTRL_EF_IF_0_TRIG_POS);
134+
sys_write32(tmp, config->addr + EF_CTRL_EF_IF_CTRL_0_OFFSET);
135+
136+
/* trigger read */
137+
tmp = EF_CTRL_EFUSE_CTRL_PROTECT |
138+
(EF_CTRL_OP_MODE_AUTO << EF_CTRL_EF_IF_0_MANUAL_EN_POS) |
139+
(EF_CTRL_PARA_DFT << EF_CTRL_EF_IF_0_CYC_MODIFY_POS) |
140+
(EF_CTRL_EF_CLK << EF_CTRL_EF_CLK_SAHB_DATA_SEL_POS) |
141+
(1 << EF_CTRL_EF_IF_AUTO_RD_EN_POS) |
142+
(0 << EF_CTRL_EF_IF_POR_DIG_POS) |
143+
(1 << EF_CTRL_EF_IF_0_INT_CLR_POS) |
144+
(0 << EF_CTRL_EF_IF_0_RW_POS) |
145+
(1 << EF_CTRL_EF_IF_0_TRIG_POS);
146+
sys_write32(tmp, config->addr + EF_CTRL_EF_IF_CTRL_0_OFFSET);
147+
system_clock_delay_32M_ms(5);
148+
149+
/* wait for read to complete */
150+
do {
151+
system_clock_delay_32M_ms(1);
152+
tmp = sys_read32(config->addr + EF_CTRL_EF_IF_CTRL_0_OFFSET);
153+
} while ((tmp & EF_CTRL_EF_IF_0_BUSY_MSK) ||
154+
!(tmp && EF_CTRL_EF_IF_0_AUTOLOAD_DONE_MSK));
155+
156+
/* do a 'ahb clock' setup */
157+
tmp = EF_CTRL_EFUSE_CTRL_PROTECT |
158+
(EF_CTRL_OP_MODE_AUTO << EF_CTRL_EF_IF_0_MANUAL_EN_POS) |
159+
(EF_CTRL_PARA_DFT << EF_CTRL_EF_IF_0_CYC_MODIFY_POS) |
160+
(EF_CTRL_SAHB_CLK << EF_CTRL_EF_CLK_SAHB_DATA_SEL_POS) |
161+
(1 << EF_CTRL_EF_IF_AUTO_RD_EN_POS) |
162+
(0 << EF_CTRL_EF_IF_POR_DIG_POS) |
163+
(1 << EF_CTRL_EF_IF_0_INT_CLR_POS) |
164+
(0 << EF_CTRL_EF_IF_0_RW_POS) |
165+
(0 << EF_CTRL_EF_IF_0_TRIG_POS);
166+
167+
sys_write32(tmp, config->addr + EF_CTRL_EF_IF_CTRL_0_OFFSET);
168+
}
169+
170+
static void efuse_bflb_cache(const struct device *dev)
171+
{
172+
struct efuse_bflb_data *data = dev->data;
173+
const struct efuse_bflb_config *config = dev->config;
174+
uint32_t tmp = 0;
175+
uint8_t old_clock_root;
176+
177+
tmp = sys_read32(HBN_BASE + HBN_GLB_OFFSET);
178+
old_clock_root = (tmp & HBN_ROOT_CLK_SEL_MSK) >> HBN_ROOT_CLK_SEL_POS;
179+
180+
system_set_root_clock(0);
181+
system_clock_settle();
182+
183+
system_efuse_read(dev);
184+
/* reads *must* be 32-bits aligned AND does not work with the method memcpy uses */
185+
for (int i = 0; i < config->size / sizeof(uint32_t); i++) {
186+
tmp = sys_read32(config->addr + i * 4);
187+
data->cache[i * sizeof(uint32_t) + 3] = (tmp & 0xFF000000) >> 24;
188+
data->cache[i * sizeof(uint32_t) + 2] = (tmp & 0x00FF0000) >> 16;
189+
data->cache[i * sizeof(uint32_t) + 1] = (tmp & 0x0000FF00) >> 8;
190+
data->cache[i * sizeof(uint32_t) + 0] = (tmp & 0x000000FF);
191+
}
192+
193+
system_set_root_clock(old_clock_root);
194+
system_clock_settle();
195+
data->cached = true;
196+
}
197+
198+
static int efuse_bflb_read(const struct device *dev, off_t offset,
199+
void *buf,
200+
size_t len)
201+
{
202+
struct efuse_bflb_data *data = dev->data;
203+
204+
if (!data->cached) {
205+
efuse_bflb_cache(dev);
206+
}
207+
208+
memcpy(buf, data->cache + offset, len);
209+
return 0;
210+
}
211+
212+
static int efuse_bflb_write(const struct device *dev, off_t offset,
213+
const void *buf, size_t len)
214+
{
215+
return -ENOTSUP;
216+
}
217+
218+
static size_t efuse_bflb_size(const struct device *dev)
219+
{
220+
const struct efuse_bflb_config *config = dev->config;
221+
222+
return config->size;
223+
}
224+
225+
static const struct eeprom_driver_api efuse_bflb_api = {
226+
.read = efuse_bflb_read,
227+
.write = efuse_bflb_write,
228+
.size = efuse_bflb_size,
229+
};
230+
231+
static const struct efuse_bflb_config efuse_config = {
232+
.addr = DT_INST_REG_ADDR(0),
233+
.size = DT_INST_PROP(0, size),
234+
};
235+
236+
static struct efuse_bflb_data efuse_data = {
237+
.cached = false,
238+
.cache = {0},
239+
};
240+
241+
242+
DEVICE_DT_INST_DEFINE(0, NULL, NULL, &efuse_data, &efuse_config, PRE_KERNEL_1,
243+
CONFIG_EEPROM_INIT_PRIORITY, &efuse_bflb_api);

dts/bindings/mtd/bflb,efuse.yaml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Copyright (c) 2024 MASSDRIVER EI (massdriver.space)
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
description: BouffaloLab Efuse Driver
5+
6+
compatible: "bflb,efuse"
7+
8+
include: eeprom-base.yaml
9+
10+
properties:
11+
reg:
12+
required: true
13+
14+
size:
15+
required: true
16+
type: int
17+
description: size of efuse storage (bytes)

0 commit comments

Comments
 (0)