xtensa/esp32s2: Add xtwdt and rwdt support

This commit is contained in:
Eren Terzioglu 2023-11-27 14:12:45 +03:00 committed by Xiang Xiao
parent 26b7de0f34
commit c15392d9b7
13 changed files with 741 additions and 126 deletions

View File

@ -330,3 +330,21 @@ the ``Device Drivers -> CAN Driver Support -> CAN loopback mode`` option and run
TSEG2: 4 TSEG2: 4
SJW: 3 SJW: 3
ID: 1 DLC: 1 ID: 1 DLC: 1
watchdog
--------
This config test the watchdog timers. It includes the 2 MWDTs,
adds driver support, registers the WDTs as devices and includes the watchdog
example.
To test it, just run the following::
nsh> wdog -i /dev/watchdogx
Where x is the watchdog instance.
To test the XTWDT(/dev/watchdog3) an interrupt handler needs to be
implemented because XTWDT does not have system reset feature. To implement
an interrupt handler `WDIOC_CAPTURE` command can be used. When interrupt
rises, XTAL32K clock can be restored with `WDIOC_RSTCLK` command.

View File

@ -394,3 +394,8 @@ To test it, just run the following::
nsh> wdog -i /dev/watchdogx nsh> wdog -i /dev/watchdogx
Where x is the watchdog instance. Where x is the watchdog instance.
To test the XTWDT(/dev/watchdog3) an interrupt handler needs to be
implemented because XTWDT does not have system reset feature. To implement
an interrupt handler `WDIOC_CAPTURE` command can be used. When interrupt
rises, XTAL32K clock can be restored with `WDIOC_RSTCLK` command.

View File

@ -420,6 +420,28 @@ config ESP32S2_RWDT
to have the RTC module reset, please, use the Timers' Module WDTs. to have the RTC module reset, please, use the Timers' Module WDTs.
They will only reset Main System. They will only reset Main System.
config ESP32S2_XTWDT
bool "XTAL32K Watchdog Timer"
depends on ESP32S2_RTC_CLK_EXT_OSC || ESP32S2_RTC_CLK_EXT_XTAL
default n
select ESP32S2_WDT
select ESP32S2_RTCIO_IRQ
---help---
Includes XTWDT. This watchdog timer monitors the status of the
external 32 kHz crystal oscillator (XTAL32K). When XTAL32K_CLK works
as the clock source of RTC_SLOW_CLK and it stops oscillating, the
XTAL32K watchdog timer first switches to BACKUP32K_CLK derived from
RC_SLOW_CLK (if ESP32S2_XTWDT_BACKUP_CLK_ENABLE) and, then, generates
an interrupt that could be captured by WDIOC_CAPTURE.
config ESP32S2_XTWDT_BACKUP_CLK_ENABLE
bool "Automatically switch to BACKUP32K_CLK when timer expires"
depends on ESP32S2_XTWDT
default y
---help---
Enable this to automatically switch to BACKUP32K_CLK as the source of
RTC_SLOW_CLK when the watchdog timer expires.
config ESP32S2_RTC config ESP32S2_RTC
bool "Real Time Clock (RTC)" bool "Real Time Clock (RTC)"
default y default y

View File

@ -131,23 +131,32 @@
#define RTC_DISABLE_ROM_LOG ((1 << 0) | (1 << 16)) #define RTC_DISABLE_ROM_LOG ((1 << 0) | (1 << 16))
#define RTC_SLEEP_PD_DIG BIT(0) /* Deep sleep (power down digital domain) */ #define RTC_SLEEP_PD_DIG BIT(0) /* Deep sleep (power down
* digital domain) */
#define RTC_SLEEP_PD_RTC_PERIPH BIT(1) /* Power down RTC peripherals */ #define RTC_SLEEP_PD_RTC_PERIPH BIT(1) /* Power down RTC peripherals */
#define RTC_SLEEP_PD_RTC_SLOW_MEM BIT(2) /* Power down RTC SLOW memory */ #define RTC_SLEEP_PD_RTC_SLOW_MEM BIT(2) /* Power down RTC SLOW memory */
#define RTC_SLEEP_PD_RTC_FAST_MEM BIT(3) /* Power down RTC FAST memory */ #define RTC_SLEEP_PD_RTC_FAST_MEM BIT(3) /* Power down RTC FAST memory */
#define RTC_SLEEP_PD_RTC_MEM_FOLLOW_CPU BIT(4) /* RTC FAST and SLOW memories are automatically powered up and down along with the CPU */ #define RTC_SLEEP_PD_RTC_MEM_FOLLOW_CPU BIT(4) /* RTC FAST and SLOW memories
#define RTC_SLEEP_PD_VDDSDIO BIT(5) /* Power down VDDSDIO regulator */ * are automatically powered
* up and down along with the
* CPU */
#define RTC_SLEEP_PD_VDDSDIO BIT(5) /* Power down VDDSDIO
* regulator */
#define RTC_SLEEP_PD_WIFI BIT(6) /* Power down WIFI */ #define RTC_SLEEP_PD_WIFI BIT(6) /* Power down WIFI */
#define RTC_SLEEP_PD_INT_8M BIT(7) /* Power down Internal 8M oscillator */ #define RTC_SLEEP_PD_INT_8M BIT(7) /* Power down Internal 8M
* oscillator */
#define RTC_SLEEP_PD_XTAL BIT(8) /* Power down main XTAL */ #define RTC_SLEEP_PD_XTAL BIT(8) /* Power down main XTAL */
/* These flags are not power domains, but will affect some sleep parameters */ /* These flags are not power domains, but will affect some sleep parameters */
#define RTC_SLEEP_DIG_USE_8M BIT(16) #define RTC_SLEEP_DIG_USE_8M BIT(16)
#define RTC_SLEEP_USE_ADC_TESEN_MONITOR BIT(17) #define RTC_SLEEP_USE_ADC_TESEN_MONITOR BIT(17)
#define RTC_SLEEP_NO_ULTRA_LOW BIT(18) /* Avoid using ultra low power in deep sleep, #define RTC_SLEEP_NO_ULTRA_LOW BIT(18) /* Avoid using ultra low
* in which RTCIO cannot be used as input, * power in deep sleep, in
* and RTCMEM can't work under high temperature */ * which RTCIO cannot be used
* as input, and RTCMEM can't
* work under high
* temperature */
#define is_dslp(pd_flags) ((pd_flags) & RTC_SLEEP_PD_DIG) #define is_dslp(pd_flags) ((pd_flags) & RTC_SLEEP_PD_DIG)
@ -173,14 +182,14 @@
* Valid if RTC_CNTL_DBG_ATTEN is 0. * Valid if RTC_CNTL_DBG_ATTEN is 0.
*/ */
#define RTC_CNTL_DBIAS_0V90 0 /* sleep dig_dbias & rtc_dbias */ #define RTC_CNTL_DBIAS_0V90 0 /* Sleep dig_dbias & rtc_dbias */
#define RTC_CNTL_DBIAS_0V95 1 /* digital voltage */ #define RTC_CNTL_DBIAS_0V95 1 /* Digital voltage */
#define RTC_CNTL_DBIAS_1V00 2 #define RTC_CNTL_DBIAS_1V00 2
#define RTC_CNTL_DBIAS_1V05 3 #define RTC_CNTL_DBIAS_1V05 3
#define RTC_CNTL_DBIAS_1V10 4 #define RTC_CNTL_DBIAS_1V10 4
#define RTC_CNTL_DBIAS_1V15 5 #define RTC_CNTL_DBIAS_1V15 5
#define RTC_CNTL_DBIAS_1V20 6 #define RTC_CNTL_DBIAS_1V20 6
#define RTC_CNTL_DBIAS_1V25 7 /* voltage is about 1.34v in fact */ #define RTC_CNTL_DBIAS_1V25 7 /* Voltage is about 1.34v in fact */
/* Default initializer for esp32s2_rtc_sleep_config_t /* Default initializer for esp32s2_rtc_sleep_config_t
* This initializer sets all fields to "reasonable" values * This initializer sets all fields to "reasonable" values
@ -265,10 +274,12 @@
/* RTC Memory & Store Register usage */ /* RTC Memory & Store Register usage */
#define RTC_SLOW_CLK_CAL_REG RTC_CNTL_STORE1_REG /* RTC_SLOW_CLK calibration value */ #define RTC_SLOW_CLK_CAL_REG RTC_CNTL_STORE1_REG /* RTC_SLOW_CLK
* calibration value */
#define RTC_BOOT_TIME_LOW_REG RTC_CNTL_STORE2_REG /* Boot time, low word */ #define RTC_BOOT_TIME_LOW_REG RTC_CNTL_STORE2_REG /* Boot time, low word */
#define RTC_BOOT_TIME_HIGH_REG RTC_CNTL_STORE3_REG /* Boot time, high word */ #define RTC_BOOT_TIME_HIGH_REG RTC_CNTL_STORE3_REG /* Boot time, high word */
#define RTC_XTAL_FREQ_REG RTC_CNTL_STORE4_REG /* External XTAL frequency */ #define RTC_XTAL_FREQ_REG RTC_CNTL_STORE4_REG /* External XTAL
* frequency */
#define RTC_APB_FREQ_REG RTC_CNTL_STORE5_REG /* APB bus frequency */ #define RTC_APB_FREQ_REG RTC_CNTL_STORE5_REG /* APB bus frequency */
#define RTC_ENTRY_ADDR_REG RTC_CNTL_STORE6_REG /* FAST_RTC_MEMORY_ENTRY */ #define RTC_ENTRY_ADDR_REG RTC_CNTL_STORE6_REG /* FAST_RTC_MEMORY_ENTRY */
#define RTC_RESET_CAUSE_REG RTC_CNTL_STORE6_REG #define RTC_RESET_CAUSE_REG RTC_CNTL_STORE6_REG
@ -282,45 +293,63 @@
struct esp32s2_rtc_priv_s struct esp32s2_rtc_priv_s
{ {
uint32_t ck8m_wait : 8; /* Number of rtc_fast_clk cycles to wait for 8M clock to be ready */ uint32_t ck8m_wait : 8; /* Number of rtc_fast_clk cycles to wait
uint32_t xtal_wait : 8; /* Number of rtc_fast_clk cycles to wait for XTAL clock to be ready */ * for 8M clock to be ready */
uint32_t pll_wait : 8; /* Number of rtc_fast_clk cycles to wait for PLL to be ready */ uint32_t xtal_wait : 8; /* Number of rtc_fast_clk cycles to wait
uint32_t clkctl_init : 1; /* Perform clock control related initialization */ * for XTAL clock to be ready */
uint32_t pwrctl_init : 1; /* Perform power control related initialization */ uint32_t pll_wait : 8; /* Number of rtc_fast_clk cycles to wait
* for PLL to be ready */
uint32_t clkctl_init : 1; /* Perform clock control related
* initialization */
uint32_t pwrctl_init : 1; /* Perform power control related
* initialization */
uint32_t rtc_dboost_fpd : 1; /* Force power down RTC_DBOOST */ uint32_t rtc_dboost_fpd : 1; /* Force power down RTC_DBOOST */
uint32_t xtal_fpu : 1; uint32_t xtal_fpu : 1;
uint32_t bbpll_fpu : 1; uint32_t bbpll_fpu : 1;
uint32_t cpu_waiti_clk_gate : 1; uint32_t cpu_waiti_clk_gate : 1;
uint32_t cali_ocode : 1; /* Calibrate Ocode to make bangap voltage more precise. */ uint32_t cali_ocode : 1; /* Calibrate Ocode to make bangap voltage
* more precise. */
}; };
/* sleep configuration for rtc_sleep_init function */ /* sleep configuration for rtc_sleep_init function */
struct esp32s2_rtc_sleep_config_s struct esp32s2_rtc_sleep_config_s
{ {
uint32_t lslp_mem_inf_fpu : 1; /* force normal voltage in sleep mode (digital domain memory) */ uint32_t lslp_mem_inf_fpu : 1; /* Force normal voltage in sleep mode
uint32_t rtc_mem_inf_follow_cpu : 1; /* keep low voltage in sleep mode (even if ULP/touch is used) */ * (digital domain memory) */
uint32_t rtc_fastmem_pd_en : 1; /* power down RTC fast memory */ uint32_t rtc_mem_inf_follow_cpu : 1; /* Keep low voltage in sleep mode
uint32_t rtc_slowmem_pd_en : 1; /* power down RTC slow memory */ * (even if ULP/touch is used) */
uint32_t rtc_peri_pd_en : 1; /* power down RTC peripherals */ uint32_t rtc_fastmem_pd_en : 1; /* Power down RTC fast memory */
uint32_t wifi_pd_en : 1; /* power down WiFi */ uint32_t rtc_slowmem_pd_en : 1; /* Power down RTC slow memory */
uint32_t rtc_peri_pd_en : 1; /* Power down RTC peripherals */
uint32_t wifi_pd_en : 1; /* Power down WiFi */
uint32_t int_8m_pd_en : 1; /* Power down Internal 8M oscillator */ uint32_t int_8m_pd_en : 1; /* Power down Internal 8M oscillator */
uint32_t deep_slp : 1; /* power down digital domain */ uint32_t deep_slp : 1; /* Power down digital domain */
uint32_t wdt_flashboot_mod_en : 1; /* enable WDT flashboot mode */ uint32_t wdt_flashboot_mod_en : 1; /* Enable WDT flashboot mode */
uint32_t dig_dbias_wak : 3; /* set bias for digital domain, in active mode */ uint32_t dig_dbias_wak : 3; /* Set bias for digital domain,
uint32_t dig_dbias_slp : 3; /* set bias for digital domain, in sleep mode */ * in active mode */
uint32_t rtc_dbias_wak : 3; /* set bias for RTC domain, in active mode */ uint32_t dig_dbias_slp : 3; /* Set bias for digital domain,
uint32_t rtc_dbias_slp : 3; /* set bias for RTC domain, in sleep mode */ * in sleep mode */
uint32_t bias_sleep_monitor : 1; /* circuit control parameter, in monitor mode */ uint32_t rtc_dbias_wak : 3; /* Set bias for RTC domain,
uint32_t dbg_atten_slp : 4; /* voltage parameter, in sleep mode */ * in active mode */
uint32_t bias_sleep_slp : 1; /* circuit control parameter, in sleep mode */ uint32_t rtc_dbias_slp : 3; /* Set bias for RTC domain,
uint32_t pd_cur_monitor : 1; /* circuit control parameter, in monitor mode */ * in sleep mode */
uint32_t pd_cur_slp : 1; /* circuit control parameter, in sleep mode */ uint32_t bias_sleep_monitor : 1; /* Circuit control parameter,
uint32_t vddsdio_pd_en : 1; /* power down VDDSDIO regulator */ * in monitor mode */
uint32_t xtal_fpu : 1; /* keep main XTAL powered up in sleep */ uint32_t dbg_atten_slp : 4; /* Voltage parameter, in sleep mode */
uint32_t rtc_regulator_fpu : 1; /* keep rtc regulator powered up in sleep */ uint32_t bias_sleep_slp : 1; /* Circuit control parameter,
uint32_t deep_slp_reject : 1; /* enable deep sleep reject */ * in sleep mode */
uint32_t light_slp_reject : 1; /* enable light sleep reject */ uint32_t pd_cur_monitor : 1; /* Circuit control parameter,
* in monitor mode */
uint32_t pd_cur_slp : 1; /* Circuit control parameter,
* in sleep mode */
uint32_t vddsdio_pd_en : 1; /* Power down VDDSDIO regulator */
uint32_t xtal_fpu : 1; /* Keep main XTAL powered up in
* sleep */
uint32_t rtc_regulator_fpu : 1; /* Keep rtc regulator powered up
* in sleep */
uint32_t deep_slp_reject : 1; /* Enable deep sleep reject */
uint32_t light_slp_reject : 1; /* Enable light sleep reject */
}; };
/* Power down flags for rtc_sleep_pd function */ /* Power down flags for rtc_sleep_pd function */
@ -329,7 +358,8 @@ struct esp32s2_rtc_sleep_pd_config_s
{ {
uint32_t dig_fpu : 1; /* Set to 1 to power down digital part in sleep */ uint32_t dig_fpu : 1; /* Set to 1 to power down digital part in sleep */
uint32_t rtc_fpu : 1; /* Set to 1 to power down RTC memories in sleep */ uint32_t rtc_fpu : 1; /* Set to 1 to power down RTC memories in sleep */
uint32_t cpu_fpu : 1; /* Set to 1 to power down digital memories and CPU in sleep */ uint32_t cpu_fpu : 1; /* Set to 1 to power down digital memories
* and CPU in sleep */
uint32_t i2s_fpu : 1; /* Set to 1 to power down I2S in sleep */ uint32_t i2s_fpu : 1; /* Set to 1 to power down I2S in sleep */
uint32_t bb_fpu : 1; /* Set to 1 to power down Wi-Fi in sleep */ uint32_t bb_fpu : 1; /* Set to 1 to power down Wi-Fi in sleep */
uint32_t nrx_fpu : 1; /* Set to 1 to power down Wi-Fi in sleep */ uint32_t nrx_fpu : 1; /* Set to 1 to power down Wi-Fi in sleep */
@ -341,7 +371,8 @@ struct alm_cbinfo_s
{ {
struct rt_timer_s *alarm_hdl; /* Timer id point to here */ struct rt_timer_s *alarm_hdl; /* Timer id point to here */
volatile alm_callback_t ac_cb; /* Client callback function */ volatile alm_callback_t ac_cb; /* Client callback function */
volatile void *ac_arg; /* Argument to pass with the callback function */ volatile void *ac_arg; /* Argument to pass with the
* callback function */
uint64_t deadline_us; uint64_t deadline_us;
uint8_t index; uint8_t index;
}; };
@ -600,7 +631,7 @@ static uint32_t IRAM_ATTR esp32s2_rtc_clk_cal_internal(
if (cal_clk == RTC_CAL_32K_XTAL || slow_freq == RTC_SLOW_FREQ_32K_XTAL) if (cal_clk == RTC_CAL_32K_XTAL || slow_freq == RTC_SLOW_FREQ_32K_XTAL)
{ {
expected_freq = 32768; /* standard 32KHz XTAL */ expected_freq = 32768; /* Standard 32KHz XTAL */
} }
else if (cal_clk == RTC_CAL_8MD256 || slow_freq == RTC_SLOW_FREQ_8MD256) else if (cal_clk == RTC_CAL_8MD256 || slow_freq == RTC_SLOW_FREQ_8MD256)
{ {
@ -650,6 +681,20 @@ static uint32_t IRAM_ATTR esp32s2_rtc_clk_cal_internal(
return cal_val; return cal_val;
} }
/****************************************************************************
* Name: esp32s2_wait_dig_dbias_valid
*
* Description:
* Wait digtial dbias valid
*
* Input Parameters:
* rtc_cycles - RTC count
*
* Returned Value:
* None
*
****************************************************************************/
static void esp32s2_wait_dig_dbias_valid(uint64_t rtc_cycles) static void esp32s2_wait_dig_dbias_valid(uint64_t rtc_cycles)
{ {
int slow_clk_freq = esp32s2_rtc_clk_slow_freq_get(); int slow_clk_freq = esp32s2_rtc_clk_slow_freq_get();
@ -792,7 +837,7 @@ static void IRAM_ATTR esp32s2_rtc_clk_8m_enable(bool clk_8m_en, bool d256_en)
{ {
modifyreg32(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M, 0); modifyreg32(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ENB_CK8M, 0);
/* no need to wait once enabled by software */ /* No need to wait once enabled by software */
REG_SET_FIELD(RTC_CNTL_TIMER1_REG, RTC_CNTL_CK8M_WAIT, 1); REG_SET_FIELD(RTC_CNTL_TIMER1_REG, RTC_CNTL_CK8M_WAIT, 1);
if (d256_en) if (d256_en)
@ -1070,14 +1115,15 @@ static void esp32s2_rtc_calibrate_ocode(void)
uint64_t max_delay_time_us = 10000; uint64_t max_delay_time_us = 10000;
struct esp32s2_cpu_freq_config_s freq_config; struct esp32s2_cpu_freq_config_s freq_config;
/* Bandgap output voltage is not precise when calibrate o-code by hardware /* Band gap output voltage is sometimes not precise when calibrating
* sometimes, so need software o-code calibration (must turn off PLL). * the o-code by hardware, so we need a software o-code calibration
* (must turn off PLL).
* Method: * Method:
* 1. read current cpu config, save in old_config * 1. Read current cpu config, save in old_config
* 2. switch cpu to xtal because PLL will be closed when o-code calibration * 2. Switch cpu to xtal because PLL will be closed when o-code calibration
* 3. begin o-code calibration * 3. Begin o-code calibration
* 4. wait o-code calibration done flag or timeout * 4. Wait o-code calibration done flag or timeout
* 5. set cpu to old-config * 5. Set cpu to old-config
*/ */
enum esp32s2_rtc_slow_freq_e slow_clk_freq = enum esp32s2_rtc_slow_freq_e slow_clk_freq =
@ -1129,6 +1175,20 @@ static void esp32s2_rtc_calibrate_ocode(void)
* Public Functions * Public Functions
****************************************************************************/ ****************************************************************************/
/****************************************************************************
* Name: esp32s2_rtc_clk_slow_freq_get_hz
*
* Description:
* Get the approximate frequency of RTC_SLOW_CLK, in Hz
*
* Input Parameters:
* None
*
* Returned Value:
* RTC_SLOW_CLK frequency, in Hz
*
****************************************************************************/
static int IRAM_ATTR esp32s2_rtc_clk_slow_freq_get(void) static int IRAM_ATTR esp32s2_rtc_clk_slow_freq_get(void)
{ {
return REG_GET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ANA_CLK_RTC_SEL); return REG_GET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ANA_CLK_RTC_SEL);
@ -1224,7 +1284,7 @@ enum esp32s2_rtc_slow_freq_e IRAM_ATTR esp32s2_rtc_get_slow_clk(void)
* *
* Input Parameters: * Input Parameters:
* cal_clk - clock to be measured * cal_clk - clock to be measured
* slowclk_cycles - number of slow clock cycles to average * slowclk_cycles - number of slow clock cycles what is to be averaged
* *
* Returned Value: * Returned Value:
* Average slow clock period in microseconds, Q13.19 fixed point format * Average slow clock period in microseconds, Q13.19 fixed point format
@ -1436,12 +1496,12 @@ void IRAM_ATTR esp32s2_rtc_init(void)
/* Moved from rtc sleep to rtc init to save sleep function running time */ /* Moved from rtc sleep to rtc init to save sleep function running time */
/* set shortest possible sleep time limit */ /* Set shortest possible sleep time limit */
REG_SET_FIELD(RTC_CNTL_TIMER5_REG, RTC_CNTL_MIN_SLP_VAL, REG_SET_FIELD(RTC_CNTL_TIMER5_REG, RTC_CNTL_MIN_SLP_VAL,
RTC_CNTL_MIN_SLP_VAL_MIN); RTC_CNTL_MIN_SLP_VAL_MIN);
/* set wifi timer */ /* Set wifi timer */
REG_SET_FIELD(RTC_CNTL_TIMER3_REG, RTC_CNTL_WIFI_POWERUP_TIMER, 1); REG_SET_FIELD(RTC_CNTL_TIMER3_REG, RTC_CNTL_WIFI_POWERUP_TIMER, 1);
REG_SET_FIELD(RTC_CNTL_TIMER3_REG, RTC_CNTL_WIFI_WAIT_TIMER, 1); REG_SET_FIELD(RTC_CNTL_TIMER3_REG, RTC_CNTL_WIFI_WAIT_TIMER, 1);
@ -1455,27 +1515,27 @@ void IRAM_ATTR esp32s2_rtc_init(void)
if (cfg.clkctl_init) if (cfg.clkctl_init)
{ {
/* clear CMMU clock force on */ /* Clear CMMU clock force on */
modifyreg32(EXTMEM_PRO_CACHE_MMU_POWER_CTRL_REG, modifyreg32(EXTMEM_PRO_CACHE_MMU_POWER_CTRL_REG,
EXTMEM_PRO_CACHE_MMU_MEM_FORCE_ON, 0); EXTMEM_PRO_CACHE_MMU_MEM_FORCE_ON, 0);
/* clear rom clock force on */ /* Clear rom clock force on */
REG_SET_FIELD(SYSTEM_ROM_CTRL_0_REG, SYSTEM_ROM_FO, 0); REG_SET_FIELD(SYSTEM_ROM_CTRL_0_REG, SYSTEM_ROM_FO, 0);
/* clear tag clock force on */ /* Clear tag clock force on */
REG_SET_FIELD(SYSTEM_SRAM_CTRL_0_REG, SYSTEM_SRAM_FO, 0); REG_SET_FIELD(SYSTEM_SRAM_CTRL_0_REG, SYSTEM_SRAM_FO, 0);
/* clear tag clock force on */ /* Clear tag clock force on */
modifyreg32(EXTMEM_PRO_DCACHE_TAG_POWER_CTRL_REG, modifyreg32(EXTMEM_PRO_DCACHE_TAG_POWER_CTRL_REG,
EXTMEM_PRO_DCACHE_TAG_MEM_FORCE_ON, 0); EXTMEM_PRO_DCACHE_TAG_MEM_FORCE_ON, 0);
modifyreg32(EXTMEM_PRO_ICACHE_TAG_POWER_CTRL_REG, modifyreg32(EXTMEM_PRO_ICACHE_TAG_POWER_CTRL_REG,
EXTMEM_PRO_ICACHE_TAG_MEM_FORCE_ON, 0); EXTMEM_PRO_ICACHE_TAG_MEM_FORCE_ON, 0);
/* clear register clock force on */ /* Clear register clock force on */
modifyreg32(SPI_MEM_CLOCK_GATE_REG(0), SPI_MEM_CLK_EN, 0); modifyreg32(SPI_MEM_CLOCK_GATE_REG(0), SPI_MEM_CLK_EN, 0);
modifyreg32(SPI_MEM_CLOCK_GATE_REG(1), SPI_MEM_CLK_EN, 0); modifyreg32(SPI_MEM_CLOCK_GATE_REG(1), SPI_MEM_CLK_EN, 0);
@ -1540,7 +1600,7 @@ void IRAM_ATTR esp32s2_rtc_init(void)
modifyreg32(RTC_CNTL_REG, RTC_CNTL_DBOOST_FORCE_PD, 0); modifyreg32(RTC_CNTL_REG, RTC_CNTL_DBOOST_FORCE_PD, 0);
} }
/* cancel digital pu force */ /* Cancel digital pu force */
modifyreg32(RTC_CNTL_PWC_REG, RTC_CNTL_SLOWMEM_FORCE_PU | modifyreg32(RTC_CNTL_PWC_REG, RTC_CNTL_SLOWMEM_FORCE_PU |
RTC_CNTL_FASTMEM_FORCE_PU, 0); RTC_CNTL_FASTMEM_FORCE_PU, 0);
@ -1572,7 +1632,7 @@ void IRAM_ATTR esp32s2_rtc_init(void)
modifyreg32(RTC_CNTL_PWC_REG, RTC_CNTL_FORCE_NOISO, 0); modifyreg32(RTC_CNTL_PWC_REG, RTC_CNTL_FORCE_NOISO, 0);
/* cancel digital PADS force no iso */ /* Cancel digital PADS force no iso */
if (cfg.cpu_waiti_clk_gate) if (cfg.cpu_waiti_clk_gate)
{ {
@ -1753,11 +1813,39 @@ void IRAM_ATTR esp32s2_rtc_wait_for_slow_cycle(void)
} }
} }
/****************************************************************************
* Name: esp32s2_rtc_clk_apb_freq_update
*
* Description:
* Store new APB frequency value into RTC_APB_FREQ_REG
*
* Input Parameters:
* apb_freq - New APB frequency, in Hz
*
* Returned Value:
* None
*
****************************************************************************/
void esp32s2_rtc_clk_apb_freq_update(uint32_t apb_freq) void esp32s2_rtc_clk_apb_freq_update(uint32_t apb_freq)
{ {
g_apb_freq = apb_freq; g_apb_freq = apb_freq;
} }
/****************************************************************************
* Name: esp32s2_rtc_clk_apb_freq_get
*
* Description:
* Get the current stored APB frequency
*
* Input Parameters:
* None
*
* Returned Value:
* The APB frequency value, in Hz.
*
****************************************************************************/
uint32_t esp32s2_rtc_clk_apb_freq_get(void) uint32_t esp32s2_rtc_clk_apb_freq_get(void)
{ {
return g_apb_freq; return g_apb_freq;
@ -2014,7 +2102,7 @@ void IRAM_ATTR esp32s2_rtc_sleep_init(uint32_t flags)
REG_SET_BIT(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_FORCE_PU); REG_SET_BIT(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_FORCE_PU);
} }
/* enable VDDSDIO control by state machine */ /* Enable VDDSDIO control by state machine */
modifyreg32(RTC_CNTL_SDIO_CONF_REG, RTC_CNTL_SDIO_FORCE, 0); modifyreg32(RTC_CNTL_SDIO_CONF_REG, RTC_CNTL_SDIO_FORCE, 0);
REG_SET_FIELD(RTC_CNTL_SDIO_CONF_REG, RTC_CNTL_SDIO_REG_PD_EN, REG_SET_FIELD(RTC_CNTL_SDIO_CONF_REG, RTC_CNTL_SDIO_REG_PD_EN,
@ -2067,7 +2155,7 @@ int IRAM_ATTR esp32s2_rtc_sleep_start(uint32_t wakeup_opt,
modifyreg32(RTC_CNTL_INT_CLR_RTC_REG, 0, modifyreg32(RTC_CNTL_INT_CLR_RTC_REG, 0,
RTC_CNTL_SLP_REJECT_INT_CLR | RTC_CNTL_SLP_WAKEUP_INT_CLR); RTC_CNTL_SLP_REJECT_INT_CLR | RTC_CNTL_SLP_WAKEUP_INT_CLR);
/* restore DBG_ATTEN to the default value */ /* Restore DBG_ATTEN to the default value */
REG_SET_FIELD(RTC_CNTL_BIAS_CONF_REG, RTC_CNTL_DBG_ATTEN_DEEP_SLP, REG_SET_FIELD(RTC_CNTL_BIAS_CONF_REG, RTC_CNTL_DBG_ATTEN_DEEP_SLP,
RTC_CNTL_DBG_ATTEN_LIGHTSLEEP_DEFAULT); RTC_CNTL_DBG_ATTEN_LIGHTSLEEP_DEFAULT);

View File

@ -96,7 +96,8 @@ enum esp32s2_rtc_slow_freq_e
{ {
RTC_SLOW_FREQ_RTC = 0, /* Internal 150 kHz RC oscillator */ RTC_SLOW_FREQ_RTC = 0, /* Internal 150 kHz RC oscillator */
RTC_SLOW_FREQ_32K_XTAL = 1, /* External 32 kHz XTAL */ RTC_SLOW_FREQ_32K_XTAL = 1, /* External 32 kHz XTAL */
RTC_SLOW_FREQ_8MD256 = 2, /* Internal 8 MHz RC oscillator, divided by 256 */ RTC_SLOW_FREQ_8MD256 = 2, /* Internal 8 MHz RC oscillator, divided
* by 256 */
}; };
/* RTC FAST_CLK frequency values */ /* RTC FAST_CLK frequency values */
@ -241,7 +242,7 @@ enum esp32s2_rtc_slow_freq_e esp32s2_rtc_get_slow_clk(void);
* *
* Input Parameters: * Input Parameters:
* cal_clk - clock to be measured * cal_clk - clock to be measured
* slowclk_cycles - number of slow clock cycles to average * slowclk_cycles - number of slow clock cycles what is to be averaged
* *
* Returned Value: * Returned Value:
* Average slow clock period in microseconds, Q13.19 fixed point format * Average slow clock period in microseconds, Q13.19 fixed point format

View File

@ -32,28 +32,44 @@
#include "xtensa.h" #include "xtensa.h"
#include "esp32s2_irq.h" #include "esp32s2_irq.h"
#include "esp32s2_rtc_gpio.h" #include "esp32s2_rtc_gpio.h"
#include "esp32s2_rtc.h"
#include "esp32s2_wdt.h" #include "esp32s2_wdt.h"
#include "hardware/esp32s2_efuse.h" #include "hardware/esp32s2_efuse.h"
#include "hardware/esp32s2_rtccntl.h" #include "hardware/esp32s2_rtccntl.h"
#include "hardware/esp32s2_tim.h" #include "hardware/esp32s2_tim.h"
#ifdef CONFIG_ESP32S2_RWDT
# error "RWDT not yet supported due to missing RTC driver!"
#endif
/**************************************************************************** /****************************************************************************
* Pre-processor Definitions * Pre-processor Definitions
****************************************************************************/ ****************************************************************************/
/* Helpers for converting from Q13.19 fixed-point format to float */
#define N 19
#define Q_TO_FLOAT(x) ((float)x/(float)(1<<N))
/* Check whether the provided device is a RTC Watchdog Timer */ /* Check whether the provided device is a RTC Watchdog Timer */
#define IS_RWDT(dev) (((struct esp32s2_wdt_priv_s *)(dev))->base == \ #define IS_RWDT(dev) (((struct esp32s2_wdt_priv_s *)dev)->type == RTC)
RTC_CNTL_OPTIONS0_REG)
/* Check whether the provided device is a Main Watchdog Timer */
#define IS_MWDT(dev) (((struct esp32s2_wdt_priv_s *)dev)->type == TIMER)
/* Check whether the provided device is a XTAL32K Watchdog Timer */
#define IS_XTWDT(dev) (((struct esp32s2_wdt_priv_s *)dev)->type == XTAL32K)
/**************************************************************************** /****************************************************************************
* Private Types * Private Types
****************************************************************************/ ****************************************************************************/
enum wdt_peripheral_e
{
RTC,
TIMER,
XTAL32K,
};
struct esp32s2_wdt_priv_s struct esp32s2_wdt_priv_s
{ {
struct esp32s2_wdt_ops_s *ops; struct esp32s2_wdt_ops_s *ops;
@ -62,8 +78,15 @@ struct esp32s2_wdt_priv_s
uint8_t irq; /* Interrupt ID */ uint8_t irq; /* Interrupt ID */
int32_t cpuint; /* CPU interrupt assigned to this WDT */ int32_t cpuint; /* CPU interrupt assigned to this WDT */
bool inuse; /* Flag indicating if this WDT is in use */ bool inuse; /* Flag indicating if this WDT is in use */
enum wdt_peripheral_e type; /* Type of the WDT Peripheral */
}; };
/****************************************************************************
* External Functions
****************************************************************************/
extern void esp_rom_delay_us(uint32_t us);
/**************************************************************************** /****************************************************************************
* Private Function Prototypes * Private Function Prototypes
****************************************************************************/ ****************************************************************************/
@ -96,6 +119,8 @@ static int32_t wdt_setisr(struct esp32s2_wdt_dev_s *dev,
static void wdt_enableint(struct esp32s2_wdt_dev_s *dev); static void wdt_enableint(struct esp32s2_wdt_dev_s *dev);
static void wdt_disableint(struct esp32s2_wdt_dev_s *dev); static void wdt_disableint(struct esp32s2_wdt_dev_s *dev);
static void wdt_ackint(struct esp32s2_wdt_dev_s *dev); static void wdt_ackint(struct esp32s2_wdt_dev_s *dev);
static uint16_t wdt_rtc_clk(struct esp32s2_wdt_dev_s *dev);
static void wdt_rstclk(struct esp32s2_wdt_dev_s *dev);
/**************************************************************************** /****************************************************************************
* Private Data * Private Data
@ -103,7 +128,7 @@ static void wdt_ackint(struct esp32s2_wdt_dev_s *dev);
/* ESP32-S2 WDT ops */ /* ESP32-S2 WDT ops */
struct esp32s2_wdt_ops_s esp32s2_mwdt_ops = struct esp32s2_wdt_ops_s esp32s2_wdt_ops =
{ {
.start = wdt_start, .start = wdt_start,
.stop = wdt_stop, .stop = wdt_stop,
@ -113,63 +138,63 @@ struct esp32s2_wdt_ops_s esp32s2_mwdt_ops =
.settimeout = wdt_settimeout, .settimeout = wdt_settimeout,
.feed = wdt_feed, .feed = wdt_feed,
.stg_conf = wdt_config_stage, .stg_conf = wdt_config_stage,
.rtc_clk = NULL, .rtc_clk = wdt_rtc_clk,
.setisr = wdt_setisr,
.enableint = wdt_enableint,
.disableint = wdt_disableint,
.ackint = wdt_ackint,
};
struct esp32s2_wdt_ops_s esp32s2_rwdt_ops =
{
.start = wdt_start,
.stop = wdt_stop,
.enablewp = wdt_enablewp,
.disablewp = wdt_disablewp,
.pre = NULL,
.settimeout = wdt_settimeout,
.feed = wdt_feed,
.stg_conf = wdt_config_stage,
.rtc_clk = NULL,
.setisr = wdt_setisr, .setisr = wdt_setisr,
.enableint = wdt_enableint, .enableint = wdt_enableint,
.disableint = wdt_disableint, .disableint = wdt_disableint,
.ackint = wdt_ackint, .ackint = wdt_ackint,
.rstclk = wdt_rstclk,
}; };
#ifdef CONFIG_ESP32S2_MWDT0 #ifdef CONFIG_ESP32S2_MWDT0
struct esp32s2_wdt_priv_s g_esp32s2_mwdt0_priv = struct esp32s2_wdt_priv_s g_esp32s2_mwdt0_priv =
{ {
.ops = &esp32s2_mwdt_ops, .ops = &esp32s2_wdt_ops,
.base = TIMG_T0CONFIG_REG(0), .base = TIMG_T0CONFIG_REG(0),
.periph = ESP32S2_PERIPH_TG_WDT_LEVEL, .periph = ESP32S2_PERIPH_TG_WDT_LEVEL,
.irq = ESP32S2_IRQ_TG_WDT_LEVEL, .irq = ESP32S2_IRQ_TG_WDT_LEVEL,
.cpuint = -ENOMEM, .cpuint = -ENOMEM,
.inuse = false, .inuse = false,
.type = TIMER,
}; };
#endif #endif
#ifdef CONFIG_ESP32S2_MWDT1 #ifdef CONFIG_ESP32S2_MWDT1
struct esp32s2_wdt_priv_s g_esp32s2_mwdt1_priv = struct esp32s2_wdt_priv_s g_esp32s2_mwdt1_priv =
{ {
.ops = &esp32s2_mwdt_ops, .ops = &esp32s2_wdt_ops,
.base = TIMG_T0CONFIG_REG(1), .base = TIMG_T0CONFIG_REG(1),
.periph = ESP32S2_PERIPH_TG1_WDT_LEVEL, .periph = ESP32S2_PERIPH_TG1_WDT_LEVEL,
.irq = ESP32S2_IRQ_TG1_WDT_LEVEL, .irq = ESP32S2_IRQ_TG1_WDT_LEVEL,
.cpuint = -ENOMEM, .cpuint = -ENOMEM,
.inuse = false, .inuse = false,
.type = TIMER,
}; };
#endif #endif
#ifdef CONFIG_ESP32S2_RWDT #ifdef CONFIG_ESP32S2_RWDT
struct esp32s2_wdt_priv_s g_esp32s2_rwdt_priv = struct esp32s2_wdt_priv_s g_esp32s2_rwdt_priv =
{ {
.ops = &esp32s2_rwdt_ops, .ops = &esp32s2_wdt_ops,
.base = RTC_CNTL_OPTIONS0_REG, .base = RTC_CNTL_OPTIONS0_REG,
.periph = ESP32S2_PERIPH_RTC_CORE, .periph = ESP32S2_PERIPH_RTC_CORE,
.irq = ESP32S2_IRQ_RTC_WDT, .irq = ESP32S2_IRQ_RTC_WDT,
.cpuint = -ENOMEM, .cpuint = -ENOMEM,
.inuse = false, .inuse = false,
.type = RTC,
};
#endif
#ifdef CONFIG_ESP32S2_XTWDT
struct esp32s2_wdt_priv_s g_esp32s2_xtwdt_priv =
{
.ops = &esp32s2_wdt_ops,
.base = RTC_CNTL_OPTIONS0_REG,
.periph = ESP32S2_PERIPH_RTC_CORE,
.irq = ESP32S2_IRQ_RTC_XTAL32K_DEAD,
.cpuint = -ENOMEM,
.inuse = false,
.type = XTAL32K,
}; };
#endif #endif
@ -262,10 +287,18 @@ static void wdt_start(struct esp32s2_wdt_dev_s *dev)
{ {
wdt_modifyreg32(dev, RWDT_CONFIG0_OFFSET, 0, RTC_CNTL_WDT_EN); wdt_modifyreg32(dev, RWDT_CONFIG0_OFFSET, 0, RTC_CNTL_WDT_EN);
} }
else else if (IS_MWDT(dev))
{ {
wdt_modifyreg32(dev, MWDT_CONFIG0_OFFSET, 0, TIMG_WDT_EN); wdt_modifyreg32(dev, MWDT_CONFIG0_OFFSET, 0, TIMG_WDT_EN);
} }
else
{
wdt_modifyreg32(dev, XTWDT_CONFIG0_OFFSET, 0, RTC_CNTL_XTAL32K_WDT_EN);
#ifdef CONFIG_ESP32S2_XTWDT_BACKUP_CLK_ENABLE
wdt_modifyreg32(dev, XTWDT_CONFIG0_OFFSET,
0, RTC_CNTL_XTAL32K_AUTO_BACKUP);
#endif
}
} }
/**************************************************************************** /****************************************************************************
@ -303,7 +336,7 @@ static int32_t wdt_config_stage(struct esp32s2_wdt_dev_s *dev,
wdt_modifyreg32(dev, RWDT_CONFIG0_OFFSET, RTC_CNTL_WDT_STG0_M, wdt_modifyreg32(dev, RWDT_CONFIG0_OFFSET, RTC_CNTL_WDT_STG0_M,
mask); mask);
} }
else else if (IS_MWDT(dev))
{ {
mask = (uint32_t)cfg << TIMG_WDT_STG0_S; mask = (uint32_t)cfg << TIMG_WDT_STG0_S;
wdt_modifyreg32(dev, MWDT_CONFIG0_OFFSET, TIMG_WDT_STG0_M, mask); wdt_modifyreg32(dev, MWDT_CONFIG0_OFFSET, TIMG_WDT_STG0_M, mask);
@ -319,7 +352,7 @@ static int32_t wdt_config_stage(struct esp32s2_wdt_dev_s *dev,
wdt_modifyreg32(dev, RWDT_CONFIG0_OFFSET, RTC_CNTL_WDT_STG1_M, wdt_modifyreg32(dev, RWDT_CONFIG0_OFFSET, RTC_CNTL_WDT_STG1_M,
mask); mask);
} }
else else if (IS_MWDT(dev))
{ {
mask = (uint32_t)cfg << TIMG_WDT_STG1_S; mask = (uint32_t)cfg << TIMG_WDT_STG1_S;
wdt_modifyreg32(dev, MWDT_CONFIG0_OFFSET, TIMG_WDT_STG1_M, mask); wdt_modifyreg32(dev, MWDT_CONFIG0_OFFSET, TIMG_WDT_STG1_M, mask);
@ -335,7 +368,7 @@ static int32_t wdt_config_stage(struct esp32s2_wdt_dev_s *dev,
wdt_modifyreg32(dev, RWDT_CONFIG0_OFFSET, RTC_CNTL_WDT_STG2_M, wdt_modifyreg32(dev, RWDT_CONFIG0_OFFSET, RTC_CNTL_WDT_STG2_M,
mask); mask);
} }
else else if (IS_MWDT(dev))
{ {
mask = (uint32_t)cfg << TIMG_WDT_STG2_S; mask = (uint32_t)cfg << TIMG_WDT_STG2_S;
wdt_modifyreg32(dev, MWDT_CONFIG0_OFFSET, TIMG_WDT_STG2_M, mask); wdt_modifyreg32(dev, MWDT_CONFIG0_OFFSET, TIMG_WDT_STG2_M, mask);
@ -351,7 +384,7 @@ static int32_t wdt_config_stage(struct esp32s2_wdt_dev_s *dev,
wdt_modifyreg32(dev, RWDT_CONFIG0_OFFSET, RTC_CNTL_WDT_STG3_M, wdt_modifyreg32(dev, RWDT_CONFIG0_OFFSET, RTC_CNTL_WDT_STG3_M,
mask); mask);
} }
else else if (IS_MWDT(dev))
{ {
mask = (uint32_t)cfg << TIMG_WDT_STG3_S; mask = (uint32_t)cfg << TIMG_WDT_STG3_S;
wdt_modifyreg32(dev, MWDT_CONFIG0_OFFSET, TIMG_WDT_STG3_M, mask); wdt_modifyreg32(dev, MWDT_CONFIG0_OFFSET, TIMG_WDT_STG3_M, mask);
@ -388,10 +421,14 @@ static void wdt_stop(struct esp32s2_wdt_dev_s *dev)
{ {
wdt_modifyreg32(dev, RWDT_CONFIG0_OFFSET, RTC_CNTL_WDT_EN, 0); wdt_modifyreg32(dev, RWDT_CONFIG0_OFFSET, RTC_CNTL_WDT_EN, 0);
} }
else else if (IS_MWDT(dev))
{ {
wdt_modifyreg32(dev, MWDT_CONFIG0_OFFSET, TIMG_WDT_EN, 0); wdt_modifyreg32(dev, MWDT_CONFIG0_OFFSET, TIMG_WDT_EN, 0);
} }
else
{
wdt_modifyreg32(dev, XTWDT_CONFIG0_OFFSET, RTC_CNTL_XTAL32K_WDT_EN, 0);
}
} }
/**************************************************************************** /****************************************************************************
@ -417,7 +454,7 @@ static void wdt_enablewp(struct esp32s2_wdt_dev_s *dev)
{ {
wdt_putreg(dev, RWDT_WP_REG, 0); wdt_putreg(dev, RWDT_WP_REG, 0);
} }
else else if (IS_MWDT(dev))
{ {
wdt_putreg(dev, MWDT_WP_REG, 0); wdt_putreg(dev, MWDT_WP_REG, 0);
} }
@ -446,7 +483,7 @@ static void wdt_disablewp(struct esp32s2_wdt_dev_s *dev)
{ {
wdt_putreg(dev, RWDT_WP_REG, RTC_CNTL_WDT_WKEY_VALUE); wdt_putreg(dev, RWDT_WP_REG, RTC_CNTL_WDT_WKEY_VALUE);
} }
else else if (IS_MWDT(dev))
{ {
wdt_putreg(dev, MWDT_WP_REG, TIMG_WDT_WKEY_VALUE); wdt_putreg(dev, MWDT_WP_REG, TIMG_WDT_WKEY_VALUE);
} }
@ -469,12 +506,23 @@ static void wdt_disablewp(struct esp32s2_wdt_dev_s *dev)
static void wdt_pre(struct esp32s2_wdt_dev_s *dev, uint16_t pre) static void wdt_pre(struct esp32s2_wdt_dev_s *dev, uint16_t pre)
{ {
uint32_t mask = (uint32_t)pre << TIMG_WDT_CLK_PRESCALER_S; uint32_t mask = 0;
DEBUGASSERT(dev != NULL); DEBUGASSERT(dev != NULL);
wdt_modifyreg32(dev, MWDT_CLK_PRESCALE_OFFSET, TIMG_WDT_CLK_PRESCALER_M, if (IS_MWDT(dev))
mask); {
mask = (uint32_t)pre << TIMG_WDT_CLK_PRESCALER_S;
wdt_modifyreg32(dev, MWDT_CLK_PRESCALE_OFFSET,
TIMG_WDT_CLK_PRESCALER_M, mask);
}
#ifdef CONFIG_ESP32S2_XTWDT_BACKUP_CLK_ENABLE
else if (IS_XTWDT(dev))
{
mask = (uint32_t)pre;
wdt_modifyreg32(dev, XTWDT_CLK_PRESCALE_OFFSET,
RTC_CNTL_XTAL32K_CLK_FACTOR_M, mask);
}
#endif
} }
/**************************************************************************** /****************************************************************************
@ -499,6 +547,14 @@ static int32_t wdt_settimeout(struct esp32s2_wdt_dev_s *dev, uint32_t value,
{ {
DEBUGASSERT(dev != NULL); DEBUGASSERT(dev != NULL);
if (IS_XTWDT(dev))
{
value = value << RTC_CNTL_XTAL32K_WDT_TIMEOUT_S;
wdt_modifyreg32(dev, XTWDT_TIMEOUT_OFFSET,
RTC_CNTL_XTAL32K_WDT_TIMEOUT_M, value);
return OK;
}
switch (stage) switch (stage)
{ {
case ESP32S2_WDT_STAGE0: case ESP32S2_WDT_STAGE0:
@ -515,7 +571,7 @@ static int32_t wdt_settimeout(struct esp32s2_wdt_dev_s *dev, uint32_t value,
value = value >> (delay + 1); value = value >> (delay + 1);
wdt_putreg(dev, RWDT_STAGE0_TIMEOUT_OFFSET, value); wdt_putreg(dev, RWDT_STAGE0_TIMEOUT_OFFSET, value);
} }
else else if (IS_MWDT(dev))
{ {
wdt_putreg(dev, MWDT_STAGE0_TIMEOUT_OFFSET, value); wdt_putreg(dev, MWDT_STAGE0_TIMEOUT_OFFSET, value);
} }
@ -528,7 +584,7 @@ static int32_t wdt_settimeout(struct esp32s2_wdt_dev_s *dev, uint32_t value,
{ {
wdt_putreg(dev, RWDT_STAGE1_TIMEOUT_OFFSET, value); wdt_putreg(dev, RWDT_STAGE1_TIMEOUT_OFFSET, value);
} }
else else if (IS_MWDT(dev))
{ {
wdt_putreg(dev, MWDT_STAGE1_TIMEOUT_OFFSET, value); wdt_putreg(dev, MWDT_STAGE1_TIMEOUT_OFFSET, value);
} }
@ -541,7 +597,7 @@ static int32_t wdt_settimeout(struct esp32s2_wdt_dev_s *dev, uint32_t value,
{ {
wdt_putreg(dev, RWDT_STAGE2_TIMEOUT_OFFSET, value); wdt_putreg(dev, RWDT_STAGE2_TIMEOUT_OFFSET, value);
} }
else else if (IS_MWDT(dev))
{ {
wdt_putreg(dev, MWDT_STAGE2_TIMEOUT_OFFSET, value); wdt_putreg(dev, MWDT_STAGE2_TIMEOUT_OFFSET, value);
} }
@ -554,7 +610,7 @@ static int32_t wdt_settimeout(struct esp32s2_wdt_dev_s *dev, uint32_t value,
{ {
wdt_putreg(dev, RWDT_STAGE3_TIMEOUT_OFFSET, value); wdt_putreg(dev, RWDT_STAGE3_TIMEOUT_OFFSET, value);
} }
else else if (IS_MWDT(dev))
{ {
wdt_putreg(dev, MWDT_STAGE3_TIMEOUT_OFFSET, value); wdt_putreg(dev, MWDT_STAGE3_TIMEOUT_OFFSET, value);
} }
@ -591,12 +647,76 @@ static void wdt_feed(struct esp32s2_wdt_dev_s *dev)
{ {
wdt_modifyreg32(dev, RWDT_FEED_OFFSET, 0, RTC_CNTL_WDT_FEED); wdt_modifyreg32(dev, RWDT_FEED_OFFSET, 0, RTC_CNTL_WDT_FEED);
} }
else else if (IS_MWDT(dev))
{ {
wdt_putreg(dev, MWDT_FEED_OFFSET, TIMG_WDT_FEED); wdt_putreg(dev, MWDT_FEED_OFFSET, TIMG_WDT_FEED);
} }
} }
/****************************************************************************
* Name: wdt_rtc_clk
*
* Description:
* Check the RTC clock source and return the necessary cycles to complete
* 1 ms.
*
* Parameters:
* dev - Pointer to the driver state structure.
*
* Returned Values:
* Number of cycles to complete 1 ms.
*
****************************************************************************/
static uint16_t wdt_rtc_clk(struct esp32s2_wdt_dev_s *dev)
{
enum esp32s2_rtc_slow_freq_e slow_clk_rtc;
uint32_t period_13q19;
float period;
float cycles_ms;
uint16_t cycles_ms_int;
/* Calibration map: Maps each RTC SLOW_CLK source to the number
* used to calibrate this source.
*/
static const enum esp32s2_rtc_cal_sel_e cal_map[] =
{
RTC_CAL_RTC_MUX,
RTC_CAL_32K_XTAL,
RTC_CAL_8MD256
};
DEBUGASSERT(dev);
/* Check which clock is sourcing the slow_clk_rtc */
slow_clk_rtc = esp32s2_rtc_get_slow_clk();
/* Get the slow_clk_rtc period in us in Q13.19 fixed point format */
period_13q19 = esp32s2_rtc_clk_cal(cal_map[slow_clk_rtc],
SLOW_CLK_CAL_CYCLES);
/* Assert no error happened during the calibration */
DEBUGASSERT(period_13q19 != 0);
/* Convert from Q13.19 format to float */
period = Q_TO_FLOAT(period_13q19);
/* Get the number of cycles necessary to count 1 ms */
cycles_ms = 1000.0 / period;
/* Get the integer number of cycles */
cycles_ms_int = (uint16_t)cycles_ms;
return cycles_ms_int;
}
/**************************************************************************** /****************************************************************************
* Name: wdt_setisr * Name: wdt_setisr
* *
@ -635,8 +755,9 @@ static int32_t wdt_setisr(struct esp32s2_wdt_dev_s *dev, xcpt_t handler,
if (wdt->cpuint >= 0) if (wdt->cpuint >= 0)
{ {
#ifdef CONFIG_ESP32S2_RWDT #if defined(CONFIG_ESP32S2_RWDT) || defined(CONFIG_ESP32S2_XTWDT)
if (wdt->irq == ESP32S2_IRQ_RTC_WDT) if (wdt->irq == ESP32S2_IRQ_RTC_WDT ||
wdt->irq == ESP32S2_IRQ_RTC_XTAL32K_DEAD)
{ {
esp32s2_rtcioirqdisable(wdt->irq); esp32s2_rtcioirqdisable(wdt->irq);
irq_detach(wdt->irq); irq_detach(wdt->irq);
@ -663,8 +784,9 @@ static int32_t wdt_setisr(struct esp32s2_wdt_dev_s *dev, xcpt_t handler,
{ {
/* Set up to receive peripheral interrupts on the current CPU */ /* Set up to receive peripheral interrupts on the current CPU */
#ifdef CONFIG_ESP32S2_RWDT #if defined(CONFIG_ESP32S2_RWDT) || defined(CONFIG_ESP32S2_XTWDT)
if (wdt->irq == ESP32S2_IRQ_RTC_WDT) if (wdt->irq == ESP32S2_IRQ_RTC_WDT ||
wdt->irq == ESP32S2_IRQ_RTC_XTAL32K_DEAD)
{ {
ret = irq_attach(wdt->irq, handler, arg); ret = irq_attach(wdt->irq, handler, arg);
@ -728,10 +850,15 @@ static void wdt_enableint(struct esp32s2_wdt_dev_s *dev)
{ {
wdt_modifyreg32(dev, RWDT_INT_ENA_REG_OFFSET, 0, RTC_CNTL_WDT_INT_ENA); wdt_modifyreg32(dev, RWDT_INT_ENA_REG_OFFSET, 0, RTC_CNTL_WDT_INT_ENA);
} }
else else if (IS_MWDT(dev))
{ {
wdt_modifyreg32(dev, MWDT_INT_ENA_REG_OFFSET, 0, TIMG_WDT_INT_ENA); wdt_modifyreg32(dev, MWDT_INT_ENA_REG_OFFSET, 0, TIMG_WDT_INT_ENA);
} }
else
{
wdt_modifyreg32(dev, XTWDT_INT_ENA_REG_OFFSET, 0,
RTC_CNTL_XTAL32K_DEAD_INT_ENA);
}
} }
/**************************************************************************** /****************************************************************************
@ -753,10 +880,15 @@ static void wdt_disableint(struct esp32s2_wdt_dev_s *dev)
{ {
wdt_modifyreg32(dev, RWDT_INT_ENA_REG_OFFSET, RTC_CNTL_WDT_INT_ENA, 0); wdt_modifyreg32(dev, RWDT_INT_ENA_REG_OFFSET, RTC_CNTL_WDT_INT_ENA, 0);
} }
else else if (IS_MWDT(dev))
{ {
wdt_modifyreg32(dev, MWDT_INT_ENA_REG_OFFSET, TIMG_WDT_INT_ENA, 0); wdt_modifyreg32(dev, MWDT_INT_ENA_REG_OFFSET, TIMG_WDT_INT_ENA, 0);
} }
else
{
wdt_modifyreg32(dev, XTWDT_INT_ENA_REG_OFFSET,
RTC_CNTL_XTAL32K_DEAD_INT_ENA, 0);
}
} }
/**************************************************************************** /****************************************************************************
@ -778,10 +910,49 @@ static void wdt_ackint(struct esp32s2_wdt_dev_s *dev)
{ {
wdt_putreg(dev, RWDT_INT_CLR_REG_OFFSET, RTC_CNTL_WDT_INT_CLR); wdt_putreg(dev, RWDT_INT_CLR_REG_OFFSET, RTC_CNTL_WDT_INT_CLR);
} }
else else if (IS_MWDT(dev))
{ {
wdt_putreg(dev, MWDT_INT_CLR_REG_OFFSET, TIMG_WDT_INT_CLR); wdt_putreg(dev, MWDT_INT_CLR_REG_OFFSET, TIMG_WDT_INT_CLR);
} }
else
{
wdt_putreg(dev, MWDT_INT_CLR_REG_OFFSET,
RTC_CNTL_XTAL32K_DEAD_INT_CLR);
}
}
/****************************************************************************
* Name: wdt_rstclk
*
* Description:
* Restores the xtal32k clock.
*
* Parameters:
* dev - Pointer to the driver state structure.
*
****************************************************************************/
static void wdt_rstclk(struct esp32s2_wdt_dev_s *dev)
{
DEBUGASSERT(dev != NULL);
struct esp32s2_wdt_priv_s *wdt = (struct esp32s2_wdt_priv_s *)dev;
if (IS_XTWDT(dev))
{
wdt->ops->stop(dev);
wdt_modifyreg32(dev, XTWDT_CONFIG0_OFFSET, RTC_CNTL_XPD_XTAL_32K, 0);
wdt_modifyreg32(dev, XTWDT_CONFIG0_OFFSET, 0, RTC_CNTL_XPD_XTAL_32K);
/* Needs some time after switching to 32khz XTAL
* before turning on WDT again
*/
esp_rom_delay_us(300);
wdt->ops->start(dev);
}
} }
/**************************************************************************** /****************************************************************************
@ -834,6 +1005,15 @@ struct esp32s2_wdt_dev_s *esp32s2_wdt_init(enum esp32s2_wdt_inst_e wdt_id)
break; break;
} }
#endif
#ifdef CONFIG_ESP32S2_XTWDT
case ESP32S2_WDT_XTWDT:
{
wdt = &g_esp32s2_xtwdt_priv;
break;
}
#endif #endif
default: default:
@ -928,7 +1108,7 @@ bool esp32s2_wdt_is_running(struct esp32s2_wdt_dev_s *dev)
return true; return true;
} }
} }
else else if (IS_MWDT(dev))
{ {
status = wdt_getreg(dev, MWDT_CONFIG0_OFFSET); status = wdt_getreg(dev, MWDT_CONFIG0_OFFSET);
if ((status & TIMG_WDT_EN) == TIMG_WDT_EN) if ((status & TIMG_WDT_EN) == TIMG_WDT_EN)
@ -936,6 +1116,14 @@ bool esp32s2_wdt_is_running(struct esp32s2_wdt_dev_s *dev)
return true; return true;
} }
} }
else
{
status = wdt_getreg(dev, XTWDT_CONFIG0_OFFSET);
if ((status & RTC_CNTL_XTAL32K_WDT_EN) == RTC_CNTL_XTAL32K_WDT_EN)
{
return true;
}
}
return false; return false;
} }

View File

@ -35,6 +35,23 @@
* Pre-processor Definitions * Pre-processor Definitions
****************************************************************************/ ****************************************************************************/
/* IOCTL Commands ***********************************************************/
/* The watchdog driver uses a standard character driver framework. However,
* since the watchdog driver is a device control interface and not a data
* transfer interface, the majority of the functionality is implemented in
* driver ioctl calls.
*
* See nuttx/timers/watchdog.h for the IOCTLs handled by the upper half.
*
* These are detected and handled by the "lower half" watchdog timer driver.
*
* WDIOC_RSTCLK - Restores the xtal32k clock
* Argument: Ignored
*/
#define WDIOC_RSTCLK _WDIOC(0x032)
/* Helpers ******************************************************************/ /* Helpers ******************************************************************/
#define ESP32S2_WDT_START(d) ((d)->ops->start(d)) #define ESP32S2_WDT_START(d) ((d)->ops->start(d))
@ -42,14 +59,17 @@
#define ESP32S2_WDT_LOCK(d) ((d)->ops->enablewp(d)) #define ESP32S2_WDT_LOCK(d) ((d)->ops->enablewp(d))
#define ESP32S2_WDT_UNLOCK(d) ((d)->ops->disablewp(d)) #define ESP32S2_WDT_UNLOCK(d) ((d)->ops->disablewp(d))
#define ESP32S2_MWDT_PRE(d, v) ((d)->ops->pre(d, v)) #define ESP32S2_MWDT_PRE(d, v) ((d)->ops->pre(d, v))
#define ESP32S2_XTWDT_PRE(d, v) ((d)->ops->pre(d, v))
#define ESP32S2_WDT_STO(d, v, s) ((d)->ops->settimeout(d, v, s)) #define ESP32S2_WDT_STO(d, v, s) ((d)->ops->settimeout(d, v, s))
#define ESP32S2_WDT_FEED(d) ((d)->ops->feed(d)) #define ESP32S2_WDT_FEED(d) ((d)->ops->feed(d))
#define ESP32S2_WDT_STG_CONF(d, s, c) ((d)->ops->stg_conf(d, s, c)) #define ESP32S2_WDT_STG_CONF(d, s, c) ((d)->ops->stg_conf(d, s, c))
#define ESP32S2_RWDT_CLK(d) ((d)->ops->rtc_clk(d)) #define ESP32S2_RWDT_CLK(d) ((d)->ops->rtc_clk(d))
#define ESP32S2_XTWDT_CLK(d) ((d)->ops->rtc_clk(d))
#define ESP32S2_WDT_SETISR(d, hnd, arg) ((d)->ops->setisr(d, hnd, arg)) #define ESP32S2_WDT_SETISR(d, hnd, arg) ((d)->ops->setisr(d, hnd, arg))
#define ESP32S2_WDT_ENABLEINT(d) ((d)->ops->enableint(d)) #define ESP32S2_WDT_ENABLEINT(d) ((d)->ops->enableint(d))
#define ESP32S2_WDT_DISABLEINT(d) ((d)->ops->disableint(d)) #define ESP32S2_WDT_DISABLEINT(d) ((d)->ops->disableint(d))
#define ESP32S2_WDT_ACKINT(d) ((d)->ops->ackint(d)) #define ESP32S2_WDT_ACKINT(d) ((d)->ops->ackint(d))
#define ESP32S2_XTWDT_RST_CLK(d) ((d)->ops->rstclk(d))
/**************************************************************************** /****************************************************************************
* Public Types * Public Types
@ -61,7 +81,8 @@ enum esp32s2_wdt_inst_e
{ {
ESP32S2_WDT_MWDT0 = 0, /* Main System Watchdog Timer (MWDT) of Timer Group 0 */ ESP32S2_WDT_MWDT0 = 0, /* Main System Watchdog Timer (MWDT) of Timer Group 0 */
ESP32S2_WDT_MWDT1, /* Main System Watchdog Timer (MWDT) of Timer Group 1 */ ESP32S2_WDT_MWDT1, /* Main System Watchdog Timer (MWDT) of Timer Group 1 */
ESP32S2_WDT_RWDT /* RTC Watchdog Timer (RWDT) */ ESP32S2_WDT_RWDT, /* RTC Watchdog Timer (RWDT) */
ESP32S2_WDT_XTWDT /* XTAL32K Watchdog Timer (XTWDT) */
}; };
/* Stages of a Watchdog Timer. A WDT has 4 stages. */ /* Stages of a Watchdog Timer. A WDT has 4 stages. */
@ -134,6 +155,7 @@ struct esp32s2_wdt_ops_s
void (*enableint)(struct esp32s2_wdt_dev_s *dev); void (*enableint)(struct esp32s2_wdt_dev_s *dev);
void (*disableint)(struct esp32s2_wdt_dev_s *dev); void (*disableint)(struct esp32s2_wdt_dev_s *dev);
void (*ackint)(struct esp32s2_wdt_dev_s *dev); void (*ackint)(struct esp32s2_wdt_dev_s *dev);
void (*rstclk)(struct esp32s2_wdt_dev_s *dev);
}; };
/**************************************************************************** /****************************************************************************

View File

@ -37,6 +37,7 @@
#include "xtensa.h" #include "xtensa.h"
#include "esp32s2_wdt.h" #include "esp32s2_wdt.h"
#include "esp32s2_rtc.h"
#include "esp32s2_wdt_lowerhalf.h" #include "esp32s2_wdt_lowerhalf.h"
#include "hardware/esp32s2_soc.h" #include "hardware/esp32s2_soc.h"
@ -68,6 +69,24 @@
#define RWDT_FULL_STAGE (UINT32_MAX) #define RWDT_FULL_STAGE (UINT32_MAX)
/* XTWDT clock period in nanoseconds */
#define XTWDT_CLK_PERIOD_NS (30)
/* Maximum number of cycles supported for a XTWDT stage timeout */
#define XTWDT_FULL_STAGE (UINT8_MAX)
/* Number of cycles for RTC_SLOW_CLK calibration */
#define XT_WDT_CLK_CAL_CYCLES (500)
/* Maximum number of divisor components
* according to the frequency of RC_SLOW_CLK
*/
#define XT_WDT_DIV_COMP_N_MAX 8
/**************************************************************************** /****************************************************************************
* Private Types * Private Types
****************************************************************************/ ****************************************************************************/
@ -75,7 +94,8 @@
enum wdt_peripheral_e enum wdt_peripheral_e
{ {
RTC, RTC,
TIMER TIMER,
XTAL32K,
}; };
/* This structure provides the private representation of the "lower-half" /* This structure provides the private representation of the "lower-half"
@ -114,6 +134,12 @@ static int wdt_lh_settimeout(struct watchdog_lowerhalf_s *lower,
uint32_t timeout); uint32_t timeout);
static xcpt_t wdt_lh_capture(struct watchdog_lowerhalf_s *lower, static xcpt_t wdt_lh_capture(struct watchdog_lowerhalf_s *lower,
xcpt_t handler); xcpt_t handler);
static int wdt_lh_ioctl(struct watchdog_lowerhalf_s *lower, int cmd,
unsigned long arg);
#ifdef CONFIG_ESP32S2_XTWDT_BACKUP_CLK_ENABLE
static uint32_t wdt_lh_xt_calculate(uint32_t rtc_clk_frequency_khz);
static uint32_t wdt_lh_clk_freq_cal(uint32_t rtc_clk_period_us);
#endif
/**************************************************************************** /****************************************************************************
* Private Data * Private Data
@ -129,7 +155,7 @@ static const struct watchdog_ops_s g_esp32s2_wdg_ops =
.getstatus = wdt_lh_getstatus, .getstatus = wdt_lh_getstatus,
.settimeout = wdt_lh_settimeout, .settimeout = wdt_lh_settimeout,
.capture = wdt_lh_capture, .capture = wdt_lh_capture,
.ioctl = NULL .ioctl = wdt_lh_ioctl,
}; };
#ifdef CONFIG_ESP32S2_MWDT0 #ifdef CONFIG_ESP32S2_MWDT0
@ -159,6 +185,15 @@ static struct esp32s2_wdt_lowerhalf_s g_esp32s2_rwdt_lowerhalf =
}; };
#endif #endif
#ifdef CONFIG_ESP32S2_XTWDT
/* XTWDT lower-half */
static struct esp32s2_wdt_lowerhalf_s g_esp32s2_xtwdt_lowerhalf =
{
.ops = &g_esp32s2_wdg_ops,
};
#endif
/**************************************************************************** /****************************************************************************
* Name: wdt_lh_start * Name: wdt_lh_start
* *
@ -216,7 +251,7 @@ static int wdt_lh_start(struct watchdog_lowerhalf_s *lower)
ESP32S2_WDT_STG_CONF(priv->wdt, ESP32S2_WDT_STAGE0, ESP32S2_WDT_STG_CONF(priv->wdt, ESP32S2_WDT_STAGE0,
ESP32S2_WDT_STAGE_ACTION_RESET_SYSTEM); ESP32S2_WDT_STAGE_ACTION_RESET_SYSTEM);
} }
else else if (priv->peripheral == RTC)
{ {
ESP32S2_WDT_STG_CONF(priv->wdt, ESP32S2_WDT_STAGE0, ESP32S2_WDT_STG_CONF(priv->wdt, ESP32S2_WDT_STAGE0,
ESP32S2_WDT_STAGE_ACTION_RESET_RTC); ESP32S2_WDT_STAGE_ACTION_RESET_RTC);
@ -433,6 +468,8 @@ static int wdt_lh_settimeout(struct watchdog_lowerhalf_s *lower,
(struct esp32s2_wdt_lowerhalf_s *)lower; (struct esp32s2_wdt_lowerhalf_s *)lower;
uint16_t rtc_cycles = 0; uint16_t rtc_cycles = 0;
uint32_t rtc_ms_max = 0; uint32_t rtc_ms_max = 0;
uint16_t xtal32k_cycles = 0;
uint32_t xtal32k_ms_max = 0;
wdinfo("Entry: timeout=%" PRIu32 "\n", timeout); wdinfo("Entry: timeout=%" PRIu32 "\n", timeout);
DEBUGASSERT(priv); DEBUGASSERT(priv);
@ -466,7 +503,7 @@ static int wdt_lh_settimeout(struct watchdog_lowerhalf_s *lower,
/* Watchdog from RTC Module */ /* Watchdog from RTC Module */
else else if (priv->peripheral == RTC)
{ {
rtc_cycles = ESP32S2_RWDT_CLK(priv->wdt); rtc_cycles = ESP32S2_RWDT_CLK(priv->wdt);
rtc_ms_max = (RWDT_FULL_STAGE / (uint32_t)rtc_cycles); rtc_ms_max = (RWDT_FULL_STAGE / (uint32_t)rtc_cycles);
@ -486,6 +523,28 @@ static int wdt_lh_settimeout(struct watchdog_lowerhalf_s *lower,
} }
} }
/* Watchdog from XTAL32K Module */
else
{
xtal32k_cycles = XTWDT_CLK_PERIOD_NS;
xtal32k_ms_max = (XTWDT_FULL_STAGE * NSEC_PER_USEC / xtal32k_cycles);
/* Is this timeout a valid value for RTC WDT? */
if (timeout == 0 || timeout > xtal32k_ms_max)
{
wderr("Cannot represent timeout=%" PRIu32 " > %" PRIu32 "\n",
timeout, rtc_ms_max);
return -ERANGE;
}
else
{
timeout = timeout * xtal32k_cycles;
ESP32S2_WDT_STO(priv->wdt, timeout, ESP32S2_WDT_STAGE0);
}
}
/* Reset the wdt */ /* Reset the wdt */
ESP32S2_WDT_FEED(priv->wdt); ESP32S2_WDT_FEED(priv->wdt);
@ -588,7 +647,7 @@ static xcpt_t wdt_lh_capture(struct watchdog_lowerhalf_s *lower,
ESP32S2_WDT_STG_CONF(priv->wdt, ESP32S2_WDT_STAGE0, ESP32S2_WDT_STG_CONF(priv->wdt, ESP32S2_WDT_STAGE0,
ESP32S2_WDT_STAGE_ACTION_RESET_SYSTEM); ESP32S2_WDT_STAGE_ACTION_RESET_SYSTEM);
} }
else else if (priv->peripheral == RTC)
{ {
ESP32S2_WDT_STG_CONF(priv->wdt, ESP32S2_WDT_STAGE0, ESP32S2_WDT_STG_CONF(priv->wdt, ESP32S2_WDT_STAGE0,
ESP32S2_WDT_STAGE_ACTION_RESET_RTC); ESP32S2_WDT_STAGE_ACTION_RESET_RTC);
@ -600,6 +659,47 @@ static xcpt_t wdt_lh_capture(struct watchdog_lowerhalf_s *lower,
return oldhandler; return oldhandler;
} }
/****************************************************************************
* Name: wdt_lh_ioctl
*
* Description:
* Any ioctl commands that are not recognized by the "upper-half" driver
* are forwarded to the lower half driver through this method.
*
* Input Parameters:
* lower - A pointer the publicly visible representation of the
* "lower-half" driver state structure.
* cmd - Command number to process.
* arg - Argument that sent to the command.
*
* Returned Value:
* OK if success or a negative value if fail.
*
****************************************************************************/
static int wdt_lh_ioctl(struct watchdog_lowerhalf_s *lower, int cmd,
unsigned long arg)
{
struct esp32s2_wdt_lowerhalf_s *priv =
(struct esp32s2_wdt_lowerhalf_s *)lower;
wdinfo("ioctl Call: cmd=0x%x arg=0x%lx", cmd, arg);
/* Process the IOCTL command */
switch (cmd)
{
case WDIOC_RSTCLK:
ESP32S2_XTWDT_RST_CLK(priv->wdt);
break;
default:
return -ENOTTY;
}
return OK;
}
/* Interrupt handling *******************************************************/ /* Interrupt handling *******************************************************/
static int wdt_handler(int irq, void *context, void *arg) static int wdt_handler(int irq, void *context, void *arg)
@ -622,6 +722,81 @@ static int wdt_handler(int irq, void *context, void *arg)
return OK; return OK;
} }
/****************************************************************************
* Name: wdt_lh_xt_calculate
*
* Description:
* Calculate the actual frequency of RC_SLOW_CLK to calibrate the backup
* RTC_SLOW_CLK. This is necessary to compensate for clock deviations.
*
* Input Parameters:
* rtc_clk_frequency_khz - Frequency of RTC SLOW CLK in khz
*
* Returned Values:
* The divisor of BACKUP32K_CLK used to calibrate the RTC_SLOW_CLK
* according to the actual frequency of the RC_SLOW_CLK.
*
****************************************************************************/
#ifdef CONFIG_ESP32S2_XTWDT_BACKUP_CLK_ENABLE
static uint32_t wdt_lh_xt_calculate(uint32_t rtc_clk_frequency_khz)
{
uint32_t xtal32k_clk_factor = 0;
uint8_t divisor_comps[XT_WDT_DIV_COMP_N_MAX];
uint8_t M = ((rtc_clk_frequency_khz / 32) / 2);
uint32_t S = ((4 * rtc_clk_frequency_khz) / 32);
memset(divisor_comps, M, XT_WDT_DIV_COMP_N_MAX);
/* Calculate how far we are away from satisfying S = SUM(x_n) */
uint8_t off = S - XT_WDT_DIV_COMP_N_MAX * M;
/* Offset should never be this big */
ASSERT(off <= XT_WDT_DIV_COMP_N_MAX);
for (int i = 0; i < XT_WDT_DIV_COMP_N_MAX; i++)
{
if (off)
{
divisor_comps[i]++;
off--;
}
/* Sum up all divisors */
xtal32k_clk_factor |= (divisor_comps[i] << 4 * i);
}
return xtal32k_clk_factor;
}
/****************************************************************************
* Name: wdt_lh_clk_freq_cal
*
* Description:
* Calculate the clock frequency from period in microseconds.
*
* Input Parameters:
* rtc_clk_period_us - Average slow clock period in microseconds.
*
* Returned Values:
* Frequency of the clock in Hz.
*
****************************************************************************/
static uint32_t wdt_lh_clk_freq_cal(uint32_t rtc_clk_period_us)
{
if (rtc_clk_period_us == 0)
{
return 0;
}
return 1000000ULL * (1 << RTC_CLK_CAL_FRACT) / rtc_clk_period_us;
}
#endif
/**************************************************************************** /****************************************************************************
* Public Functions * Public Functions
****************************************************************************/ ****************************************************************************/
@ -680,6 +855,15 @@ int esp32s2_wdt_initialize(const char *devpath, enum esp32s2_wdt_inst_e wdt)
} }
#endif #endif
#ifdef CONFIG_ESP32S2_XTWDT
case ESP32S2_WDT_XTWDT:
{
lower = &g_esp32s2_xtwdt_lowerhalf;
lower->peripheral = XTAL32K;
break;
}
#endif
default: default:
{ {
ret = -ENODEV; ret = -ENODEV;
@ -712,6 +896,26 @@ int esp32s2_wdt_initialize(const char *devpath, enum esp32s2_wdt_inst_e wdt)
ESP32S2_MWDT_PRE(lower->wdt, MWDT_CLK_PRESCALER_VALUE); ESP32S2_MWDT_PRE(lower->wdt, MWDT_CLK_PRESCALER_VALUE);
} }
/* Configure auto backup clock when XTAL32K fails */
#ifdef CONFIG_ESP32S2_XTWDT_BACKUP_CLK_ENABLE
if (lower->peripheral == XTAL32K)
{
/* Estimate frequency of internal RTC oscillator */
uint32_t rtc_clk_period_us =
esp32s2_rtc_clk_cal(RTC_CAL_INTERNAL_OSC, XT_WDT_CLK_CAL_CYCLES);
uint32_t rtc_clk_frequency_khz = wdt_lh_clk_freq_cal(rtc_clk_period_us)
/ 1000;
uint32_t xtal32k_clk_factor =
wdt_lh_xt_calculate(rtc_clk_frequency_khz);
ESP32S2_XTWDT_PRE(lower->wdt, xtal32k_clk_factor);
}
#endif
ESP32S2_WDT_LOCK(lower->wdt); ESP32S2_WDT_LOCK(lower->wdt);
/* Register the watchdog driver as /dev/watchdogX. If the registration goes /* Register the watchdog driver as /dev/watchdogX. If the registration goes

View File

@ -34,6 +34,7 @@
/* Offset relative to each watchdog timer instance memory base */ /* Offset relative to each watchdog timer instance memory base */
#define RWDT_CONFIG0_OFFSET 0x0094 #define RWDT_CONFIG0_OFFSET 0x0094
#define XTWDT_CONFIG0_OFFSET 0x0060
/* RWDT */ /* RWDT */
@ -46,6 +47,12 @@
#define RWDT_INT_ENA_REG_OFFSET 0x0040 #define RWDT_INT_ENA_REG_OFFSET 0x0040
#define RWDT_INT_CLR_REG_OFFSET 0x004c #define RWDT_INT_CLR_REG_OFFSET 0x004c
/* XTWDT */
#define XTWDT_TIMEOUT_OFFSET 0x00f4
#define XTWDT_CLK_PRESCALE_OFFSET 0x00f0
#define XTWDT_INT_ENA_REG_OFFSET 0x0040
/* The value that needs to be written to RTC_CNTL_WDT_WKEY to /* The value that needs to be written to RTC_CNTL_WDT_WKEY to
* write-enable the wdt registers * write-enable the wdt registers
*/ */

View File

@ -215,6 +215,7 @@ PROVIDE ( dummy_len_plus = 0x3ffffd54 );
PROVIDE ( Enable_QMode = 0x40016690 ); PROVIDE ( Enable_QMode = 0x40016690 );
PROVIDE ( esp_crc8 = 0x40011a78 ); PROVIDE ( esp_crc8 = 0x40011a78 );
PROVIDE ( esp_rom_config_pad_power_select = 0x40016e58 ); PROVIDE ( esp_rom_config_pad_power_select = 0x40016e58 );
PROVIDE ( esp_rom_delay_us = ets_delay_us );
PROVIDE ( esp_rom_opiflash_cache_mode_config = 0x40016754 ); PROVIDE ( esp_rom_opiflash_cache_mode_config = 0x40016754 );
PROVIDE ( esp_rom_opiflash_exec_cmd = 0x40017e30 ); PROVIDE ( esp_rom_opiflash_exec_cmd = 0x40017e30 );
PROVIDE ( esp_rom_opiflash_exit_continuous_read_mode = 0x40017ee8 ); PROVIDE ( esp_rom_opiflash_exit_continuous_read_mode = 0x40017ee8 );

View File

@ -31,8 +31,6 @@
#include "esp32s2_wdt_lowerhalf.h" #include "esp32s2_wdt_lowerhalf.h"
#include "esp32s2_wdt.h" #include "esp32s2_wdt.h"
#include "esp32s2-saola-1.h"
/**************************************************************************** /****************************************************************************
* Pre-processor Definitions * Pre-processor Definitions
****************************************************************************/ ****************************************************************************/
@ -84,6 +82,15 @@ int board_wdt_init(void)
} }
#endif /* CONFIG_ESP32S2_RWDT */ #endif /* CONFIG_ESP32S2_RWDT */
#ifdef CONFIG_ESP32S2_XTWDT
ret = esp32s2_wdt_initialize("/dev/watchdog3", ESP32S2_WDT_XTWDT);
if (ret < 0)
{
syslog(LOG_ERR, "Failed to initialize XTWDT: %d\n", ret);
return ret;
}
#endif /* CONFIG_ESP32S2_XTWDT */
return ret; return ret;
} }

View File

@ -0,0 +1,51 @@
#
# This file is autogenerated: PLEASE DO NOT EDIT IT.
#
# You can use "make menuconfig" to make any modifications to the installed .config file.
# You can then do "make savedefconfig" to generate a new defconfig file that includes your
# modifications.
#
# CONFIG_ARCH_LEDS is not set
# CONFIG_NSH_ARGCAT is not set
# CONFIG_NSH_CMDOPT_HEXDUMP is not set
CONFIG_ARCH="xtensa"
CONFIG_ARCH_BOARD="esp32s2-kaluga-1"
CONFIG_ARCH_BOARD_COMMON=y
CONFIG_ARCH_BOARD_ESP32S2_KALUGA_1=y
CONFIG_ARCH_CHIP="esp32s2"
CONFIG_ARCH_CHIP_ESP32S2=y
CONFIG_ARCH_CHIP_ESP32S2WROVER=y
CONFIG_ARCH_STACKDUMP=y
CONFIG_ARCH_XTENSA=y
CONFIG_BOARD_LOOPSPERMSEC=16717
CONFIG_BUILTIN=y
CONFIG_DEBUG_FULLOPT=y
CONFIG_DEBUG_SYMBOLS=y
CONFIG_ESP32S2_MWDT0=y
CONFIG_ESP32S2_MWDT1=y
CONFIG_ESP32S2_RWDT=y
CONFIG_ESP32S2_UART0=y
CONFIG_EXAMPLES_WATCHDOG=y
CONFIG_FS_PROCFS=y
CONFIG_HAVE_CXX=y
CONFIG_HAVE_CXXINITIALIZE=y
CONFIG_IDLETHREAD_STACKSIZE=3072
CONFIG_INIT_ENTRYPOINT="nsh_main"
CONFIG_INTELHEX_BINARY=y
CONFIG_NSH_ARCHINIT=y
CONFIG_NSH_BUILTIN_APPS=y
CONFIG_NSH_FILEIOSIZE=512
CONFIG_NSH_LINELEN=64
CONFIG_NSH_READLINE=y
CONFIG_PREALLOC_TIMERS=4
CONFIG_RAM_SIZE=114688
CONFIG_RAM_START=0x20000000
CONFIG_RR_INTERVAL=200
CONFIG_SCHED_WAITPID=y
CONFIG_START_DAY=6
CONFIG_START_MONTH=12
CONFIG_START_YEAR=2011
CONFIG_SYSLOG_BUFFER=y
CONFIG_SYSTEM_NSH=y
CONFIG_UART0_SERIAL_CONSOLE=y
CONFIG_WATCHDOG=y

View File

@ -23,6 +23,7 @@ CONFIG_DEBUG_FULLOPT=y
CONFIG_DEBUG_SYMBOLS=y CONFIG_DEBUG_SYMBOLS=y
CONFIG_ESP32S2_MWDT0=y CONFIG_ESP32S2_MWDT0=y
CONFIG_ESP32S2_MWDT1=y CONFIG_ESP32S2_MWDT1=y
CONFIG_ESP32S2_RWDT=y
CONFIG_ESP32S2_UART0=y CONFIG_ESP32S2_UART0=y
CONFIG_EXAMPLES_WATCHDOG=y CONFIG_EXAMPLES_WATCHDOG=y
CONFIG_FS_PROCFS=y CONFIG_FS_PROCFS=y