feat(esp32c6): auto adjust LDO voltage using pvt function

This commit is contained in:
zlq
2024-09-10 10:59:58 +08:00
parent 473b2fe27d
commit 8640b79ab8
14 changed files with 3121 additions and 2 deletions
@@ -15,6 +15,10 @@ if(NOT non_os_build)
endif()
if(NOT BOOTLOADER_BUILD AND CONFIG_ESP_ENABLE_PVT)
list(APPEND srcs "pmu_pvt.c")
endif()
add_prefix(srcs "${CMAKE_CURRENT_LIST_DIR}/" "${srcs}")
target_sources(${COMPONENT_LIB} PRIVATE "${srcs}")
@@ -96,6 +96,53 @@ set sleep_init default param
#define RTC_CNTL_PD_CUR_SLEEP_DEFAULT 1
#define RTC_CNTL_DG_VDD_DRV_B_SLP_DEFAULT 254
#if CONFIG_ESP_ENABLE_PVT
/*
set pvt default param
*/
#define PVT_CHANNEL0_SEL 34
#define PVT_CHANNEL1_SEL 38
#define PVT_CHANNEL0_CFG 0x1033e
#define PVT_CHANNEL1_CFG 0x1033e
#define PVT_CHANNEL2_CFG 0x10000
#define PVT_CMD0 0x24
#define PVT_CMD1 0x5
#define PVT_CMD2 0x427
#define PVT_TARGET 0xffff
#define PVT_CLK_DIV 1
#define PVT_EDG_MODE 1
#define PVT_DELAY_NUM_HIGH 108
#define PVT_DELAY_NUM_LOW 98
#define PVT_PUMP_CHANNEL_CODE 1
#define PVT_PUMP_BITMAP 25
#define PVT_PUMP_DRV 0
/**
* @brief Initialize PVT related parameters
*/
void pvt_auto_dbias_init(void);
/**
* @brief Enable or disable PVT functions
*
* @param enable true to enable, false to disable
*/
void pvt_func_enable(bool enable);
/**
* @brief Initialize charge pump related parameters
*/
void charge_pump_init(void);
/**
* @brief Enable or disable charge pump functions
*
* @param enable true to enable, false to disable
*/
void charge_pump_enable(bool enable);
#endif //#if CONFIG_ESP_ENABLE_PVT
/*
The follow value is used to get a reasonable rtc voltage dbias value according to digital dbias & some other value
storing in efuse (based on ATE 5k ECO3 chips)
@@ -19,6 +19,9 @@
#include "regi2c_ctrl.h"
#include "esp_private/ocode_init.h"
#include "esp_rom_sys.h"
#include "soc/rtc.h"
#include "hal/efuse_ll.h"
#include "hal/efuse_hal.h"
#include "esp_hw_log.h"
ESP_HW_LOG_ATTR_TAG(TAG, "pmu_init");
@@ -227,4 +230,20 @@ void pmu_init(void)
esp_ocode_calib_init();
}
#endif
#if CONFIG_ESP_ENABLE_PVT
/*setup pvt function*/
uint32_t blk_version = efuse_hal_blk_version();
if (blk_version >= 3) {
pvt_auto_dbias_init();
charge_pump_init();
pvt_func_enable(true);
charge_pump_enable(true);
esp_rom_delay_us(1000);
}
else {
ESP_HW_LOGW(TAG, "blk_version is less than 3, pvt function not supported in efuse.");
}
#endif
}
@@ -351,7 +351,7 @@ const pmu_hp_system_retention_param_t * pmu_hp_system_retention_param_default(pm
#define PMU_LP_SLEEP_POWER_CONFIG_DEFAULT() { \
.dig_power = { \
.mem_dslp = 1, \
.mem_dslp = 0, \
.peri_pd_en = 0, \
}, \
.clk_power = { \
@@ -0,0 +1,170 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#include <stdlib.h>
#include <esp_types.h>
#include "sdkconfig.h"
#include "esp_attr.h"
#include "soc/soc.h"
#include "soc/pmu_struct.h"
#include "soc/pvt_reg.h"
#include "soc/pmu_reg.h"
#include "soc/pcr_reg.h"
#include "hal/pmu_hal.h"
#include "pmu_param.h"
#include "esp_rom_sys.h"
#include "esp_private/esp_pmu.h"
#include "soc/regi2c_dig_reg.h"
#include "regi2c_ctrl.h"
#include "soc/rtc.h"
#include "hal/efuse_ll.h"
#include "hal/efuse_hal.h"
#include "esp_hw_log.h"
static __attribute__((unused)) const char *TAG = "pmu_pvt";
#if CONFIG_ESP_ENABLE_PVT
static uint8_t get_lp_hp_gap(void)
{
int8_t pvt_offset = 0;
uint32_t blk_version = efuse_hal_blk_version();
if (blk_version >= 3) {
uint8_t offset_read = efuse_ll_get_dbias_vol_gap();
bool offset_flag = offset_read >> 4;
uint8_t offset_value = offset_read & 0xf;
int8_t pvt_offset = 0;
if (offset_flag) {
pvt_offset = -1 * offset_value;
} else {
pvt_offset = offset_value;
}
pvt_offset = pvt_offset - 2;
assert((pvt_offset >= -15) && (pvt_offset <= 13));
if (pvt_offset < 0 ) {
pvt_offset = 16 - pvt_offset;
}
}
return pvt_offset;
}
static void set_pvt_hp_lp_gap(uint8_t value)
{
bool flag = value >> 4;
uint8_t abs_value = value & 0xf;
SET_PERI_REG_BITS(PVT_DBIAS_CMD0_REG, PVT_DBIAS_CMD0_OFFSET_FLAG, flag, PVT_DBIAS_CMD0_OFFSET_FLAG_S);
SET_PERI_REG_BITS(PVT_DBIAS_CMD0_REG, PVT_DBIAS_CMD0_OFFSET_VALUE, abs_value, PVT_DBIAS_CMD0_OFFSET_VALUE_S);
SET_PERI_REG_BITS(PVT_DBIAS_CMD1_REG, PVT_DBIAS_CMD1_OFFSET_FLAG, flag, PVT_DBIAS_CMD1_OFFSET_FLAG_S);
SET_PERI_REG_BITS(PVT_DBIAS_CMD1_REG, PVT_DBIAS_CMD1_OFFSET_VALUE, abs_value, PVT_DBIAS_CMD1_OFFSET_VALUE_S);
SET_PERI_REG_BITS(PVT_DBIAS_CMD2_REG, PVT_DBIAS_CMD2_OFFSET_FLAG, flag, PVT_DBIAS_CMD2_OFFSET_FLAG_S);
SET_PERI_REG_BITS(PVT_DBIAS_CMD2_REG, PVT_DBIAS_CMD2_OFFSET_VALUE, abs_value, PVT_DBIAS_CMD2_OFFSET_VALUE_S);
}
FORCE_INLINE_ATTR uint32_t get_pvt_hp_dbias(void)
{
return REG_GET_FIELD(PMU_HP_ACTIVE_HP_REGULATOR0_REG, PMU_HP_DBIAS_VOL);
}
FORCE_INLINE_ATTR uint32_t get_pvt_lp_dbias(void)
{
return REG_GET_FIELD(PMU_HP_ACTIVE_HP_REGULATOR0_REG, PMU_LP_DBIAS_VOL);
}
void pvt_auto_dbias_init(void)
{
uint32_t blk_version = efuse_hal_blk_version();
if (blk_version >= 3) {
SET_PERI_REG_MASK(PCR_PVT_MONITOR_CONF_REG, PCR_PVT_MONITOR_CLK_EN);
SET_PERI_REG_MASK(PCR_PVT_MONITOR_FUNC_CLK_CONF_REG, PCR_PVT_MONITOR_FUNC_CLK_EN);
/*config for dbias func*/
CLEAR_PERI_REG_MASK(PVT_DBIAS_TIMER_REG, PVT_TIMER_EN);
esp_rom_delay_us(100);
SET_PERI_REG_BITS(PVT_DBIAS_CHANNEL_SEL0_REG, PVT_DBIAS_CHANNEL0_SEL, PVT_CHANNEL0_SEL, PVT_DBIAS_CHANNEL0_SEL_S);
SET_PERI_REG_BITS(PVT_DBIAS_CHANNEL_SEL0_REG, PVT_DBIAS_CHANNEL1_SEL, PVT_CHANNEL1_SEL, PVT_DBIAS_CHANNEL1_SEL_S); // Select monitor cell ,which used to monitor PVT situation
SET_PERI_REG_BITS(PVT_DBIAS_CHANNEL0_SEL_REG, PVT_DBIAS_CHANNEL0_CFG, PVT_CHANNEL0_CFG, PVT_DBIAS_CHANNEL0_CFG_S);
SET_PERI_REG_BITS(PVT_DBIAS_CHANNEL1_SEL_REG, PVT_DBIAS_CHANNEL1_CFG, PVT_CHANNEL1_CFG, PVT_DBIAS_CHANNEL1_CFG_S);
SET_PERI_REG_BITS(PVT_DBIAS_CHANNEL2_SEL_REG, PVT_DBIAS_CHANNEL2_CFG, PVT_CHANNEL2_CFG, PVT_DBIAS_CHANNEL2_CFG_S); // Configure filter threshold for avoiding auto-dbias overly sensitive regulation
SET_PERI_REG_BITS(PVT_DBIAS_CMD0_REG, PVT_DBIAS_CMD0_PVT, PVT_CMD0, PVT_DBIAS_CMD0_PVT_S);
SET_PERI_REG_BITS(PVT_DBIAS_CMD1_REG, PVT_DBIAS_CMD1_PVT, PVT_CMD1, PVT_DBIAS_CMD1_PVT_S);
SET_PERI_REG_BITS(PVT_DBIAS_CMD2_REG, PVT_DBIAS_CMD2_PVT, PVT_CMD2, PVT_DBIAS_CMD2_PVT_S); // Configure auto-dbias adjust property, such as adjusting step
SET_PERI_REG_BITS(PVT_DBIAS_TIMER_REG, PVT_TIMER_TARGET, PVT_TARGET, PVT_TIMER_TARGET_S); // Configure auto-dbias voltage regulation cycle
SET_PERI_REG_BITS(PCR_PVT_MONITOR_FUNC_CLK_CONF_REG, PCR_PVT_MONITOR_FUNC_CLK_DIV_NUM, PVT_CLK_DIV, PCR_PVT_MONITOR_FUNC_CLK_DIV_NUM_S); //pvt function clock divider number
/*config for pvt cell: unit0; site2; vt2*/
SET_PERI_REG_MASK(PCR_PVT_MONITOR_FUNC_CLK_CONF_REG, PCR_PVT_MONITOR_FUNC_CLK_SEL); //pvt function clock source select
SET_PERI_REG_BITS(PVT_COMB_PD_SITE2_UNIT0_VT2_CONF2_REG, PVT_MONITOR_EDG_MOD_VT2_PD_SITE2_UNIT0, PVT_EDG_MODE, PVT_MONITOR_EDG_MOD_VT2_PD_SITE2_UNIT0_S); // Select edge_mode
SET_PERI_REG_BITS(PVT_COMB_PD_SITE2_UNIT0_VT2_CONF1_REG, PVT_DELAY_LIMIT_VT2_PD_SITE2_UNIT0, PVT_DELAY_NUM_HIGH, PVT_DELAY_LIMIT_VT2_PD_SITE2_UNIT0_S); // The threshold for determining whether the voltage is too high
SET_PERI_REG_BITS(PVT_COMB_PD_SITE2_UNIT1_VT2_CONF1_REG, PVT_DELAY_LIMIT_VT2_PD_SITE2_UNIT1, PVT_DELAY_NUM_LOW, PVT_DELAY_LIMIT_VT2_PD_SITE2_UNIT1_S); // The threshold for determining whether the voltage is too low
/*config lp offset for pvt func*/
uint8_t lp_hp_gap = get_lp_hp_gap();
set_pvt_hp_lp_gap(lp_hp_gap);
} else {
ESP_HW_LOGW(TAG, "blk_version is less than 3, pvt auto dbias init not supported in efuse.");
}
}
void IRAM_ATTR pvt_func_enable(bool enable)
{
uint32_t blk_version = efuse_hal_blk_version();
if (blk_version >= 3) {
if (enable) {
SET_PERI_REG_MASK(PMU_HP_ACTIVE_HP_REGULATOR0_REG, PMU_DIG_DBIAS_INIT); // start calibration @HP_CALI_DBIAS_DEFAUL
SET_PERI_REG_MASK(PCR_PVT_MONITOR_FUNC_CLK_CONF_REG, PCR_PVT_MONITOR_FUNC_CLK_EN);
SET_PERI_REG_MASK(PCR_PVT_MONITOR_CONF_REG, PCR_PVT_MONITOR_CLK_EN);
SET_PERI_REG_MASK(PVT_CLK_CFG_REG, PVT_MONITOR_CLK_PVT_EN);
SET_PERI_REG_MASK(PVT_COMB_PD_SITE2_UNIT0_VT2_CONF1_REG, PVT_MONITOR_EN_VT2_PD_SITE2_UNIT0); // enable pvt clk
esp_rom_delay_us(10);
CLEAR_PERI_REG_MASK(PMU_HP_ACTIVE_HP_REGULATOR0_REG, PMU_DIG_REGULATOR0_DBIAS_SEL); // hand over control of dbias to pvt
CLEAR_PERI_REG_MASK(PMU_HP_ACTIVE_HP_REGULATOR0_REG, PMU_DIG_DBIAS_INIT); // must clear @HP_CALI_DBIAS_DEFAULT
SET_PERI_REG_MASK(PVT_DBIAS_TIMER_REG, PVT_TIMER_EN); // enable auto dbias
} else {
uint32_t pvt_hp_dbias = get_pvt_hp_dbias();
uint32_t pvt_lp_dbias = get_pvt_lp_dbias(); // update pvt_cali_dbias
SET_PERI_REG_BITS(PMU_HP_ACTIVE_HP_REGULATOR0_REG, PMU_HP_ACTIVE_HP_REGULATOR_DBIAS, pvt_hp_dbias, PMU_HP_ACTIVE_HP_REGULATOR_DBIAS_S);
SET_PERI_REG_BITS(PMU_HP_SLEEP_LP_REGULATOR0_REG, PMU_HP_SLEEP_LP_REGULATOR_DBIAS, pvt_lp_dbias, PMU_HP_SLEEP_LP_REGULATOR_DBIAS_S);
CLEAR_PERI_REG_MASK(PVT_DBIAS_TIMER_REG, PVT_TIMER_EN); //disable auto dbias
CLEAR_PERI_REG_MASK(PVT_CLK_CFG_REG, PVT_MONITOR_CLK_PVT_EN);
SET_PERI_REG_MASK(PMU_HP_ACTIVE_HP_REGULATOR0_REG, PMU_DIG_REGULATOR0_DBIAS_SEL); // hand over control of dbias to pmu
CLEAR_PERI_REG_MASK(PCR_PVT_MONITOR_CONF_REG, PCR_PVT_MONITOR_CLK_EN);
CLEAR_PERI_REG_MASK(PCR_PVT_MONITOR_FUNC_CLK_CONF_REG, PCR_PVT_MONITOR_FUNC_CLK_EN);
}
} else {
ESP_HW_LOGD(TAG, "blk_version is less than 3, pvt enable not supported in efuse.");
}
}
void charge_pump_init(void)
{
uint32_t blk_version = efuse_hal_blk_version();
if (blk_version >= 3) {
/*config for charge pump*/
SET_PERI_REG_BITS(PVT_PMUP_CHANNEL_CFG_REG, PVT_PUMP_CHANNEL_CODE0, PVT_PUMP_CHANNEL_CODE, PVT_PUMP_CHANNEL_CODE0_S); //Set channel code
WRITE_PERI_REG(PVT_PMUP_BITMAP_LOW0_REG, (1 << PVT_PUMP_BITMAP)); // Select monitor cell for charge pump
SET_PERI_REG_BITS(PVT_PMUP_DRV_CFG_REG, PVT_PUMP_DRV0, PVT_PUMP_DRV, PVT_PUMP_DRV0_S); //Configure the charging intensity
} else {
ESP_HW_LOGW(TAG, "blk_version is less than 3, pvt charge_pump init not supported in efuse.");
}
}
void IRAM_ATTR charge_pump_enable(bool enable)
{
uint32_t blk_version = efuse_hal_blk_version();
if (blk_version >= 3) {
if (enable) {
SET_PERI_REG_MASK(PVT_PMUP_DRV_CFG_REG, PVT_PUMP_EN); // enable charge pump
} else {
CLEAR_PERI_REG_MASK(PVT_PMUP_DRV_CFG_REG, PVT_PUMP_EN); //disable charge pump
}
} else {
ESP_HW_LOGD(TAG, "blk_version is less than 3, pvt charge_pump enable not supported in efuse.");
}
}
#endif
@@ -321,6 +321,10 @@ static void pmu_sleep_analog_init(pmu_context_t *ctx, const pmu_sleep_analog_con
pmu_ll_hp_set_regulator_xpd (ctx->hal->dev, HP(SLEEP), analog->hp_sys.analog.xpd);
pmu_ll_hp_set_regulator_dbias (ctx->hal->dev, HP(SLEEP), analog->hp_sys.analog.dbias);
pmu_ll_hp_set_regulator_driver_bar (ctx->hal->dev, HP(SLEEP), analog->hp_sys.analog.drv_b);
#if CONFIG_ESP_ENABLE_PVT
uint32_t pvt_hp_dbias = GET_PERI_REG_BITS2(PMU_HP_ACTIVE_HP_REGULATOR0_REG, PMU_HP_DBIAS_VOL_V, PMU_HP_DBIAS_VOL_S);
pmu_ll_hp_set_regulator_dbias (ctx->hal->dev, HP(MODEM), pvt_hp_dbias);
#endif
pmu_ll_lp_set_dbg_atten (ctx->hal->dev, LP(SLEEP), analog->lp_sys[LP(SLEEP)].analog.dbg_atten);
pmu_ll_lp_set_current_power_off (ctx->hal->dev, LP(SLEEP), analog->lp_sys[LP(SLEEP)].analog.pd_cur);
@@ -305,7 +305,7 @@ typedef struct {
.lp_sys[PMU_MODE_LP_SLEEP] = { \
.dig_power = { \
.peri_pd_en = ((sleep_flags) & PMU_SLEEP_PD_LP_PERIPH) ? 1 : 0, \
.mem_dslp = 1 \
.mem_dslp = 0 \
}, \
.clk_power = { \
.xpd_xtal32k = ((sleep_flags) & PMU_SLEEP_PD_XTAL32K) ? 0 : 1,\
@@ -189,6 +189,10 @@ static void rtc_clk_cpu_freq_to_xtal(int cpu_freq, int div)
clk_ll_cpu_set_ls_divider(div);
clk_ll_cpu_set_src(SOC_CPU_CLK_SRC_XTAL);
esp_rom_set_cpu_ticks_per_us(cpu_freq);
#if CONFIG_ESP_ENABLE_PVT && !defined(BOOTLOADER_BUILD)
charge_pump_enable(false);
pvt_func_enable(false);
#endif
}
static void rtc_clk_cpu_freq_to_rc_fast(void)
@@ -197,6 +201,10 @@ static void rtc_clk_cpu_freq_to_rc_fast(void)
clk_ll_cpu_set_ls_divider(1);
clk_ll_cpu_set_src(SOC_CPU_CLK_SRC_RC_FAST);
esp_rom_set_cpu_ticks_per_us(20);
#if CONFIG_ESP_ENABLE_PVT && !defined(BOOTLOADER_BUILD)
charge_pump_enable(false);
pvt_func_enable(false);
#endif
}
/**
@@ -206,6 +214,10 @@ static void rtc_clk_cpu_freq_to_rc_fast(void)
*/
static void rtc_clk_cpu_freq_to_pll_mhz(int cpu_freq_mhz)
{
#if CONFIG_ESP_ENABLE_PVT && !defined(BOOTLOADER_BUILD)
pvt_func_enable(true);
charge_pump_enable(true);
#endif
clk_ll_cpu_set_hs_divider(CLK_LL_PLL_480M_FREQ_MHZ / cpu_freq_mhz);
clk_ll_cpu_set_src(SOC_CPU_CLK_SRC_PLL);
esp_rom_set_cpu_ticks_per_us(cpu_freq_mhz);
@@ -341,6 +353,10 @@ void rtc_clk_cpu_freq_set_config_fast(const rtc_cpu_freq_config_t *config)
void rtc_clk_cpu_freq_set_xtal(void)
{
rtc_clk_cpu_set_to_default_config();
#if CONFIG_ESP_ENABLE_PVT && !defined(BOOTLOADER_BUILD)
charge_pump_enable(false);
pvt_func_enable(false);
#endif
rtc_clk_bbpll_disable();
}
@@ -79,6 +79,8 @@ void rtc_clk_init(rtc_clk_config_t cfg)
uint32_t hp_cali_dbias = get_act_hp_dbias();
uint32_t lp_cali_dbias = get_act_lp_dbias();
SET_PERI_REG_MASK(PMU_HP_ACTIVE_HP_REGULATOR0_REG, PMU_DIG_REGULATOR0_DBIAS_SEL); // Hand over control of dbias to pmu
SET_PERI_REG_BITS(PMU_HP_ACTIVE_HP_REGULATOR0_REG, PMU_HP_ACTIVE_HP_REGULATOR_DBIAS, hp_cali_dbias, PMU_HP_ACTIVE_HP_REGULATOR_DBIAS_S);
SET_PERI_REG_BITS(PMU_HP_MODEM_HP_REGULATOR0_REG, PMU_HP_MODEM_HP_REGULATOR_DBIAS, hp_cali_dbias, PMU_HP_MODEM_HP_REGULATOR_DBIAS_S);
SET_PERI_REG_BITS(PMU_HP_SLEEP_LP_REGULATOR0_REG, PMU_HP_SLEEP_LP_REGULATOR_DBIAS, lp_cali_dbias, PMU_HP_SLEEP_LP_REGULATOR_DBIAS_S);
@@ -187,6 +187,10 @@ config SOC_PMU_SUPPORTED
bool
default y
config SOC_PMU_PVT_SUPPORTED
bool
default y
config SOC_PAU_SUPPORTED
bool
default y
File diff suppressed because it is too large Load Diff
@@ -69,6 +69,7 @@
#define SOC_BOD_SUPPORTED 1
#define SOC_APM_SUPPORTED 1 /*!< Support for APM peripheral */
#define SOC_PMU_SUPPORTED 1
#define SOC_PMU_PVT_SUPPORTED 1
#define SOC_PAU_SUPPORTED 1
#define SOC_LP_TIMER_SUPPORTED 1
#define SOC_LP_AON_SUPPORTED 1
@@ -77,6 +77,16 @@ extern const regdma_entries_config_t flash_spimem_regs_retention[SPIMEM_RETENTIO
#define SYSTIMER_RETENTION_LINK_LEN 19
extern const regdma_entries_config_t systimer_regs_retention[SYSTIMER_RETENTION_LINK_LEN];
/**
* @brief Provide access to pvt configuration registers retention
* context definition.
*
* This is an internal function of the sleep retention driver, and is not
* useful for external use.
*/
#define PVT_RETENTION_LINK_LEN 1
extern const regdma_entries_config_t pvt_regs_retention[PVT_RETENTION_LINK_LEN];
#ifdef __cplusplus
}
#endif
@@ -16,6 +16,7 @@
#include "soc/gpio_reg.h"
#include "soc/io_mux_reg.h"
#include "soc/interrupt_matrix_reg.h"
#include "soc/pvt_reg.h"
/* Interrupt Matrix Registers Context */
#define N_REGS_INTR_MATRIX() (((INTMTX_CORE0_CLOCK_GATE_REG - DR_REG_INTMTX_BASE) / 4) + 1)
@@ -112,3 +113,10 @@ const regdma_entries_config_t systimer_regs_retention[] = {
[18] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_SYSTIMER_LINK(0x12), SYSTIMER_INT_ENA_REG, SYSTIMER_INT_ENA_REG, 1, 0, 0), .owner = ENTRY(0) | ENTRY(2) } /* Systimer intr enable */
};
_Static_assert(ARRAY_SIZE(systimer_regs_retention) == SYSTIMER_RETENTION_LINK_LEN, "Inconsistent Systimer retention link length definitions");
/* PVT Registers Context */
#define N_REGS_PVT (((PVT_COMB_PD_SITE2_UNIT2_VT2_CONF2_REG - DR_REG_PVT_MONITOR_BASE) / 4) + 1)
const regdma_entries_config_t pvt_regs_retention[] = {
[0] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_PVT_LINK(0x00), DR_REG_PVT_MONITOR_BASE, DR_REG_PVT_MONITOR_BASE, N_REGS_PVT, 0, 0), .owner = ENTRY(0) | ENTRY(2) },
};
_Static_assert(ARRAY_SIZE(pvt_regs_retention) == PVT_RETENTION_LINK_LEN, "Inconsistent PVT retention link length definitions");