-
Notifications
You must be signed in to change notification settings - Fork 7.8k
drivers: syscon: bflb efuses #89108
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
drivers: syscon: bflb efuses #89108
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
# Copyright (c) 2024-2025 MASSDRIVER EI (massdriver.space) | ||
# SPDX-License-Identifier: Apache-2.0 | ||
|
||
config SYSCON_BFLB_EFUSE | ||
bool "Bouffalolab EFUSEs driver" | ||
default y | ||
depends on DT_HAS_BFLB_EFUSE_ENABLED | ||
help | ||
E-Fuse access via SYSCON API for Bouffalolab platforms. |
Original file line number | Diff line number | Diff line change | ||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,248 @@ | ||||||||||||||||
/* | ||||||||||||||||
* Copyright (c) 2025 MASSDRIVER EI (massdriver.space) | ||||||||||||||||
* | ||||||||||||||||
* SPDX-License-Identifier: Apache-2.0 | ||||||||||||||||
*/ | ||||||||||||||||
|
||||||||||||||||
#define DT_DRV_COMPAT bflb_efuse | ||||||||||||||||
|
||||||||||||||||
#include <zephyr/drivers/syscon.h> | ||||||||||||||||
#include <zephyr/kernel.h> | ||||||||||||||||
|
||||||||||||||||
#include <zephyr/logging/log.h> | ||||||||||||||||
LOG_MODULE_REGISTER(efuse_bflb, CONFIG_SYSCON_LOG_LEVEL); | ||||||||||||||||
|
||||||||||||||||
#include <bouffalolab/bl60x/bflb_soc.h> | ||||||||||||||||
#include <bouffalolab/bl60x/hbn_reg.h> | ||||||||||||||||
#include <bouffalolab/bl60x/ef_ctrl_reg.h> | ||||||||||||||||
#include <bouffalolab/bl60x/extra_defines.h> | ||||||||||||||||
|
||||||||||||||||
struct efuse_bflb_data { | ||||||||||||||||
uint8_t cache[DT_INST_PROP(0, size)]; | ||||||||||||||||
bool cached; | ||||||||||||||||
}; | ||||||||||||||||
|
||||||||||||||||
struct efuse_bflb_config { | ||||||||||||||||
uintptr_t addr; | ||||||||||||||||
size_t size; | ||||||||||||||||
}; | ||||||||||||||||
|
||||||||||||||||
static inline void efuse_bflb_clock_settle(void) | ||||||||||||||||
{ | ||||||||||||||||
__asm__ volatile (".rept 15 ; nop ; .endr"); | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
/* 32 Mhz Oscillator: 0 | ||||||||||||||||
* crystal: 1 | ||||||||||||||||
* PLL and 32M: 2 | ||||||||||||||||
* PLL and crystal: 3 | ||||||||||||||||
*/ | ||||||||||||||||
static void efuse_bflb_set_root_clock(uint32_t clock) | ||||||||||||||||
{ | ||||||||||||||||
uint32_t tmp; | ||||||||||||||||
|
||||||||||||||||
/* invalid value, fallback to internal 32M */ | ||||||||||||||||
if (clock > 3) { | ||||||||||||||||
clock = 0; | ||||||||||||||||
} | ||||||||||||||||
Comment on lines
+44
to
+47
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. then this would naturally be:
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. See clock driver comment |
||||||||||||||||
tmp = sys_read32(HBN_BASE + HBN_GLB_OFFSET); | ||||||||||||||||
tmp = (tmp & HBN_ROOT_CLK_SEL_UMSK) | (clock << HBN_ROOT_CLK_SEL_POS); | ||||||||||||||||
sys_write32(tmp, HBN_BASE + HBN_GLB_OFFSET); | ||||||||||||||||
|
||||||||||||||||
efuse_bflb_clock_settle(); | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
static void efuse_bflb_clock_delay_32M_ms(uint32_t ms) | ||||||||||||||||
{ | ||||||||||||||||
uint32_t count = 0; | ||||||||||||||||
|
||||||||||||||||
do { | ||||||||||||||||
__asm__ volatile (".rept 32 ; nop ; .endr"); | ||||||||||||||||
count++; | ||||||||||||||||
} while (count < ms); | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
static uint32_t efuse_bflb_is_pds_busy(const struct device *dev) | ||||||||||||||||
{ | ||||||||||||||||
uint32_t tmp; | ||||||||||||||||
const struct efuse_bflb_config *config = dev->config; | ||||||||||||||||
|
||||||||||||||||
tmp = sys_read32(config->addr + EF_CTRL_EF_IF_CTRL_0_OFFSET); | ||||||||||||||||
if (tmp & EF_CTRL_EF_IF_0_BUSY_MSK) { | ||||||||||||||||
return 1; | ||||||||||||||||
} | ||||||||||||||||
return 0; | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
/* /!\ only use when running on 32Mhz Oscillator Clock | ||||||||||||||||
* (system_set_root_clock(0); | ||||||||||||||||
* system_set_root_clock_dividers(0, 0); | ||||||||||||||||
* sys_write32(32 * 1000 * 1000, CORECLOCKREGISTER);) | ||||||||||||||||
* Only Use with IRQs off | ||||||||||||||||
* returns 0 when error | ||||||||||||||||
*/ | ||||||||||||||||
static void efuse_bflb_efuse_read(const struct device *dev) | ||||||||||||||||
{ | ||||||||||||||||
const struct efuse_bflb_config *config = dev->config; | ||||||||||||||||
uint32_t tmp; | ||||||||||||||||
uint32_t *pefuse_start = (uint32_t *)(config->addr); | ||||||||||||||||
uint32_t timeout = 0; | ||||||||||||||||
|
||||||||||||||||
do { | ||||||||||||||||
efuse_bflb_clock_delay_32M_ms(1); | ||||||||||||||||
timeout++; | ||||||||||||||||
} while (timeout < EF_CTRL_DFT_TIMEOUT_VAL && efuse_bflb_is_pds_busy(dev) > 0); | ||||||||||||||||
|
||||||||||||||||
/* do a 'ahb clock' setup */ | ||||||||||||||||
tmp = EF_CTRL_EFUSE_CTRL_PROTECT | ||||||||||||||||
| (EF_CTRL_OP_MODE_AUTO << EF_CTRL_EF_IF_0_MANUAL_EN_POS) | ||||||||||||||||
| (EF_CTRL_PARA_DFT << EF_CTRL_EF_IF_0_CYC_MODIFY_POS) | ||||||||||||||||
#if defined(CONFIG_SOC_SERIES_BL60X) | ||||||||||||||||
| (EF_CTRL_SAHB_CLK << EF_CTRL_EF_CLK_SAHB_DATA_SEL_POS) | ||||||||||||||||
#endif | ||||||||||||||||
| (1 << EF_CTRL_EF_IF_AUTO_RD_EN_POS) | ||||||||||||||||
| (0 << EF_CTRL_EF_IF_POR_DIG_POS) | ||||||||||||||||
| (1 << EF_CTRL_EF_IF_0_INT_CLR_POS) | ||||||||||||||||
| (0 << EF_CTRL_EF_IF_0_RW_POS) | ||||||||||||||||
| (0 << EF_CTRL_EF_IF_0_TRIG_POS); | ||||||||||||||||
|
||||||||||||||||
sys_write32(tmp, config->addr + EF_CTRL_EF_IF_CTRL_0_OFFSET); | ||||||||||||||||
efuse_bflb_clock_settle(); | ||||||||||||||||
|
||||||||||||||||
/* clear PDS cache registry */ | ||||||||||||||||
for (uint32_t i = 0; i < config->size / 4; i++) { | ||||||||||||||||
pefuse_start[i] = 0; | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
/* Load efuse region0 */ | ||||||||||||||||
/* not ahb clock setup */ | ||||||||||||||||
tmp = EF_CTRL_EFUSE_CTRL_PROTECT | ||||||||||||||||
| (EF_CTRL_OP_MODE_AUTO << EF_CTRL_EF_IF_0_MANUAL_EN_POS) | ||||||||||||||||
| (EF_CTRL_PARA_DFT << EF_CTRL_EF_IF_0_CYC_MODIFY_POS) | ||||||||||||||||
#if defined(CONFIG_SOC_SERIES_BL60X) | ||||||||||||||||
| (EF_CTRL_EF_CLK << EF_CTRL_EF_CLK_SAHB_DATA_SEL_POS) | ||||||||||||||||
#endif | ||||||||||||||||
| (1 << EF_CTRL_EF_IF_AUTO_RD_EN_POS) | ||||||||||||||||
| (0 << EF_CTRL_EF_IF_POR_DIG_POS) | ||||||||||||||||
| (1 << EF_CTRL_EF_IF_0_INT_CLR_POS) | ||||||||||||||||
| (0 << EF_CTRL_EF_IF_0_RW_POS) | ||||||||||||||||
| (0 << EF_CTRL_EF_IF_0_TRIG_POS); | ||||||||||||||||
sys_write32(tmp, config->addr + EF_CTRL_EF_IF_CTRL_0_OFFSET); | ||||||||||||||||
|
||||||||||||||||
/* trigger read */ | ||||||||||||||||
tmp = EF_CTRL_EFUSE_CTRL_PROTECT | ||||||||||||||||
| (EF_CTRL_OP_MODE_AUTO << EF_CTRL_EF_IF_0_MANUAL_EN_POS) | ||||||||||||||||
| (EF_CTRL_PARA_DFT << EF_CTRL_EF_IF_0_CYC_MODIFY_POS) | ||||||||||||||||
#if defined(CONFIG_SOC_SERIES_BL60X) | ||||||||||||||||
| (EF_CTRL_EF_CLK << EF_CTRL_EF_CLK_SAHB_DATA_SEL_POS) | ||||||||||||||||
#endif | ||||||||||||||||
| (1 << EF_CTRL_EF_IF_AUTO_RD_EN_POS) | ||||||||||||||||
| (0 << EF_CTRL_EF_IF_POR_DIG_POS) | ||||||||||||||||
| (1 << EF_CTRL_EF_IF_0_INT_CLR_POS) | ||||||||||||||||
| (0 << EF_CTRL_EF_IF_0_RW_POS) | ||||||||||||||||
| (1 << EF_CTRL_EF_IF_0_TRIG_POS); | ||||||||||||||||
sys_write32(tmp, config->addr + EF_CTRL_EF_IF_CTRL_0_OFFSET); | ||||||||||||||||
efuse_bflb_clock_delay_32M_ms(5); | ||||||||||||||||
|
||||||||||||||||
/* wait for read to complete */ | ||||||||||||||||
do { | ||||||||||||||||
efuse_bflb_clock_delay_32M_ms(1); | ||||||||||||||||
tmp = sys_read32(config->addr + EF_CTRL_EF_IF_CTRL_0_OFFSET); | ||||||||||||||||
} while ((tmp & EF_CTRL_EF_IF_0_BUSY_MSK) || | ||||||||||||||||
!(tmp & EF_CTRL_EF_IF_0_AUTOLOAD_DONE_MSK)); | ||||||||||||||||
|
||||||||||||||||
/* do a 'ahb clock' setup */ | ||||||||||||||||
tmp = EF_CTRL_EFUSE_CTRL_PROTECT | ||||||||||||||||
| (EF_CTRL_OP_MODE_AUTO << EF_CTRL_EF_IF_0_MANUAL_EN_POS) | ||||||||||||||||
| (EF_CTRL_PARA_DFT << EF_CTRL_EF_IF_0_CYC_MODIFY_POS) | ||||||||||||||||
#if defined(CONFIG_SOC_SERIES_BL60X) | ||||||||||||||||
| (EF_CTRL_SAHB_CLK << EF_CTRL_EF_CLK_SAHB_DATA_SEL_POS) | ||||||||||||||||
#endif | ||||||||||||||||
| (1 << EF_CTRL_EF_IF_AUTO_RD_EN_POS) | ||||||||||||||||
| (0 << EF_CTRL_EF_IF_POR_DIG_POS) | ||||||||||||||||
| (1 << EF_CTRL_EF_IF_0_INT_CLR_POS) | ||||||||||||||||
| (0 << EF_CTRL_EF_IF_0_RW_POS) | ||||||||||||||||
| (0 << EF_CTRL_EF_IF_0_TRIG_POS); | ||||||||||||||||
|
||||||||||||||||
sys_write32(tmp, config->addr + EF_CTRL_EF_IF_CTRL_0_OFFSET); | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
static void efuse_bflb_cache(const struct device *dev) | ||||||||||||||||
{ | ||||||||||||||||
struct efuse_bflb_data *data = dev->data; | ||||||||||||||||
const struct efuse_bflb_config *config = dev->config; | ||||||||||||||||
uint32_t tmp; | ||||||||||||||||
uint8_t old_clock_root; | ||||||||||||||||
|
||||||||||||||||
tmp = sys_read32(HBN_BASE + HBN_GLB_OFFSET); | ||||||||||||||||
old_clock_root = (tmp & HBN_ROOT_CLK_SEL_MSK) >> HBN_ROOT_CLK_SEL_POS; | ||||||||||||||||
Comment on lines
+177
to
+178
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: we can have a matching helper
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. See clock driver comment |
||||||||||||||||
|
||||||||||||||||
efuse_bflb_set_root_clock(0); | ||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. if the enum suggestion above is adopted:
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. See clock driver comment |
||||||||||||||||
efuse_bflb_clock_settle(); | ||||||||||||||||
|
||||||||||||||||
efuse_bflb_efuse_read(dev); | ||||||||||||||||
/* reads *must* be 32-bits aligned AND does not work with the method memcpy uses */ | ||||||||||||||||
for (int i = 0; i < config->size / sizeof(uint32_t); i++) { | ||||||||||||||||
tmp = sys_read32(config->addr + i * 4); | ||||||||||||||||
data->cache[i * sizeof(uint32_t) + 3] = (tmp & 0xFF000000U) >> 24; | ||||||||||||||||
data->cache[i * sizeof(uint32_t) + 2] = (tmp & 0x00FF0000U) >> 16; | ||||||||||||||||
data->cache[i * sizeof(uint32_t) + 1] = (tmp & 0x0000FF00U) >> 8; | ||||||||||||||||
data->cache[i * sizeof(uint32_t) + 0] = (tmp & 0x000000FFU); | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
efuse_bflb_set_root_clock(old_clock_root); | ||||||||||||||||
efuse_bflb_clock_settle(); | ||||||||||||||||
data->cached = true; | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
static int efuse_bflb_read(const struct device *dev, uint16_t reg, uint32_t *val) | ||||||||||||||||
{ | ||||||||||||||||
struct efuse_bflb_data *data = dev->data; | ||||||||||||||||
|
||||||||||||||||
if (!val) { | ||||||||||||||||
return -EINVAL; | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
if (!data->cached) { | ||||||||||||||||
efuse_bflb_cache(dev); | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
*val = *((uint32_t *)&data->cache[reg]); | ||||||||||||||||
return 0; | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
static int efuse_bflb_size(const struct device *dev, size_t *size) | ||||||||||||||||
{ | ||||||||||||||||
const struct efuse_bflb_config *config = dev->config; | ||||||||||||||||
|
||||||||||||||||
*size = config->size; | ||||||||||||||||
return 0; | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
static int efuse_bflb_get_base(const struct device *dev, uintptr_t *addr) | ||||||||||||||||
{ | ||||||||||||||||
struct efuse_bflb_data *data = dev->data; | ||||||||||||||||
|
||||||||||||||||
*addr = (uintptr_t)data->cache; | ||||||||||||||||
return 0; | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
static DEVICE_API(syscon, efuse_bflb_api) = { | ||||||||||||||||
.read = efuse_bflb_read, | ||||||||||||||||
.get_size = efuse_bflb_size, | ||||||||||||||||
.get_base = efuse_bflb_get_base, | ||||||||||||||||
}; | ||||||||||||||||
|
||||||||||||||||
static const struct efuse_bflb_config efuse_config = { | ||||||||||||||||
.addr = DT_INST_REG_ADDR(0), | ||||||||||||||||
.size = DT_INST_PROP(0, size), | ||||||||||||||||
}; | ||||||||||||||||
|
||||||||||||||||
static struct efuse_bflb_data efuse_data = { | ||||||||||||||||
.cached = false, | ||||||||||||||||
.cache = {0}, | ||||||||||||||||
}; | ||||||||||||||||
|
||||||||||||||||
|
||||||||||||||||
DEVICE_DT_INST_DEFINE(0, NULL, NULL, &efuse_data, &efuse_config, POST_KERNEL, | ||||||||||||||||
CONFIG_SYSCON_INIT_PRIORITY, &efuse_bflb_api); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
# Copyright (c) 2024-2025 MASSDRIVER EI (massdriver.space) | ||
# SPDX-License-Identifier: Apache-2.0 | ||
|
||
description: BouffaloLab Efuse | ||
|
||
compatible: "bflb,efuse" | ||
nandojve marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
include: base.yaml | ||
|
||
properties: | ||
reg: | ||
required: true | ||
|
||
size: | ||
required: true | ||
type: int | ||
description: Size of efuse storage (bytes) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could have used
enum
for theseThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Clock driver with this functionality and many others (and enums/defines) is next, but it is dependant on this driver.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We shouldn't depend on upcoming PRs since they are not guaranteed, but this is reasonably commented so 🤷♂️