mirror of
https://github.com/apache/nuttx.git
synced 2026-05-28 11:56:10 +08:00
xtensa/esp32s3: Add XTWDT support
This commit is contained in:
committed by
Alan Carvalho de Assis
parent
d63034994e
commit
4033018a72
@@ -372,6 +372,22 @@ To test it, just run ``rand`` to get 32 randomly generated bytes::
|
|||||||
0000 98 b9 66 a2 a2 c0 a2 ae 09 70 93 d1 b5 91 86 c8 ..f......p......
|
0000 98 b9 66 a2 a2 c0 a2 ae 09 70 93 d1 b5 91 86 c8 ..f......p......
|
||||||
0010 8f 0e 0b 04 29 64 21 72 01 92 7c a2 27 60 6f 90 ....)d!r..|.'`o.
|
0010 8f 0e 0b 04 29 64 21 72 01 92 7c a2 27 60 6f 90 ....)d!r..|.'`o.
|
||||||
|
|
||||||
|
rtc
|
||||||
|
---
|
||||||
|
|
||||||
|
This configuration demonstrates the use of the RTC driver through alarms.
|
||||||
|
You can set an alarm, check its progress and receive a notification after it expires::
|
||||||
|
|
||||||
|
nsh> alarm 10
|
||||||
|
alarm_daemon started
|
||||||
|
alarm_daemon: Running
|
||||||
|
Opening /dev/rtc0
|
||||||
|
Alarm 0 set in 10 seconds
|
||||||
|
nsh> alarm -r
|
||||||
|
Opening /dev/rtc0
|
||||||
|
Alarm 0 is active with 10 seconds to expiration
|
||||||
|
nsh> alarm_daemon: alarm 0 received
|
||||||
|
|
||||||
smp
|
smp
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -534,3 +550,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.
|
||||||
|
|||||||
@@ -1153,7 +1153,7 @@ void esp32_rtc_clk_set(void)
|
|||||||
enum esp32_rtc_fast_freq_e fast_freq = RTC_FAST_FREQ_8M;
|
enum esp32_rtc_fast_freq_e fast_freq = RTC_FAST_FREQ_8M;
|
||||||
enum esp32_slow_clk_sel_e slow_clk = SLOW_CLK_150K;
|
enum esp32_slow_clk_sel_e slow_clk = SLOW_CLK_150K;
|
||||||
|
|
||||||
#if defined(CONFIG_ESP32_RTC_CLK_SRC_EXT_CRYS)
|
#if defined(CONFIG_ESP32_RTC_CLK_SRC_EXT_XTAL)
|
||||||
slow_clk = SLOW_CLK_32K_XTAL;
|
slow_clk = SLOW_CLK_32K_XTAL;
|
||||||
#elif defined(CONFIG_ESP32_RTC_CLK_SRC_EXT_OSC)
|
#elif defined(CONFIG_ESP32_RTC_CLK_SRC_EXT_OSC)
|
||||||
slow_clk = SLOW_CLK_32K_EXT_OSC;
|
slow_clk = SLOW_CLK_32K_EXT_OSC;
|
||||||
|
|||||||
@@ -703,6 +703,28 @@ config ESP32S3_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 ESP32S3_XTWDT
|
||||||
|
bool "XTAL32K Watchdog Timer"
|
||||||
|
depends on ESP32S3_RTC_CLK_EXT_OSC || ESP32S3_RTC_CLK_EXT_XTAL
|
||||||
|
default n
|
||||||
|
select ESP32S3_WDT
|
||||||
|
select ESP32S3_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 ESP32S3_XTWDT_BACKUP_CLK_ENABLE) and, then, generates
|
||||||
|
an interrupt that could be captured by WDIOC_CAPTURE.
|
||||||
|
|
||||||
|
config ESP32S3_XTWDT_BACKUP_CLK_ENABLE
|
||||||
|
bool "Automatically switch to BACKUP32K_CLK when timer expires"
|
||||||
|
depends on ESP32S3_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 ESP32S3_RT_TIMER
|
config ESP32S3_RT_TIMER
|
||||||
bool "Real-Time Timer"
|
bool "Real-Time Timer"
|
||||||
default n
|
default n
|
||||||
@@ -1523,6 +1545,50 @@ config ESP32S3_FREERUN
|
|||||||
|
|
||||||
endmenu # Timer/Counter Configuration
|
endmenu # Timer/Counter Configuration
|
||||||
|
|
||||||
|
menu "RTC Configuration"
|
||||||
|
depends on ESP32S3_RTC
|
||||||
|
|
||||||
|
choice ESP32S3_RTC_CLK_SRC
|
||||||
|
prompt "RTC clock source"
|
||||||
|
default ESP32S3_RTC_CLK_INT_RC
|
||||||
|
---help---
|
||||||
|
Choose which clock is used as RTC clock source.
|
||||||
|
|
||||||
|
- "Internal 150kHz oscillator" option provides lowest deep sleep current
|
||||||
|
consumption, and does not require extra external components. However
|
||||||
|
frequency stability with respect to temperature is poor, so time may
|
||||||
|
drift in deep/light sleep modes.
|
||||||
|
- "External 32kHz crystal" provides better frequency stability, at the
|
||||||
|
expense of slightly higher (1uA) deep sleep current consumption.
|
||||||
|
- "External 32kHz oscillator" allows using 32kHz clock generated by an
|
||||||
|
external circuit. In this case, external clock signal must be connected
|
||||||
|
to 32K_XN pin. Amplitude should be <1.2V in case of sine wave signal,
|
||||||
|
and <1V in case of square wave signal. Common mode voltage should be
|
||||||
|
0.1 < Vcm < 0.5Vamp, where Vamp is the signal amplitude.
|
||||||
|
Additionally, 1nF capacitor must be connected between 32K_XP pin and
|
||||||
|
ground. 32K_XP pin can not be used as a GPIO in this case.
|
||||||
|
- "Internal 8.5MHz oscillator divided by 256" option results in higher
|
||||||
|
deep sleep current (by 5uA) but has better frequency stability than
|
||||||
|
the internal 150kHz oscillator. It does not require external components.
|
||||||
|
|
||||||
|
config ESP32S3_RTC_CLK_INT_RC
|
||||||
|
bool "Internal 150kHz RC oscillator"
|
||||||
|
|
||||||
|
config ESP32S3_RTC_CLK_EXT_XTAL
|
||||||
|
bool "External 32kHz crystal"
|
||||||
|
select ESP_SYSTEM_RTC_EXT_XTAL
|
||||||
|
|
||||||
|
config ESP32S3_RTC_CLK_EXT_OSC
|
||||||
|
bool "External 32kHz oscillator at 32K_XN pin"
|
||||||
|
select ESP_SYSTEM_RTC_EXT_XTAL
|
||||||
|
|
||||||
|
config ESP32S3_RTC_CLK_INT_8MD256
|
||||||
|
bool "Internal 8.5MHz oscillator, divided by 256 (~33kHz)"
|
||||||
|
|
||||||
|
endchoice
|
||||||
|
endmenu # "RTC Configuration"
|
||||||
|
|
||||||
|
|
||||||
menu "Real-Time Timer Configuration"
|
menu "Real-Time Timer Configuration"
|
||||||
depends on ESP32S3_RT_TIMER
|
depends on ESP32S3_RT_TIMER
|
||||||
|
|
||||||
|
|||||||
@@ -1465,11 +1465,11 @@ void esp32s3_rtc_clk_set(void)
|
|||||||
enum esp32s3_rtc_fast_freq_e fast_freq = RTC_FAST_FREQ_8M;
|
enum esp32s3_rtc_fast_freq_e fast_freq = RTC_FAST_FREQ_8M;
|
||||||
enum esp32s3_slow_clk_sel_e slow_clk = SLOW_CLK_150K;
|
enum esp32s3_slow_clk_sel_e slow_clk = SLOW_CLK_150K;
|
||||||
|
|
||||||
#if defined(CONFIG_ESP32_RTC_CLK_SRC_EXT_CRYS)
|
#if defined(CONFIG_ESP32S3_RTC_CLK_EXT_XTAL)
|
||||||
slow_clk = SLOW_CLK_32K_XTAL;
|
slow_clk = SLOW_CLK_32K_XTAL;
|
||||||
#elif defined(CONFIG_ESP32_RTC_CLK_SRC_EXT_OSC)
|
#elif defined(CONFIG_ESP32S3_RTC_CLK_EXT_OSC)
|
||||||
slow_clk = SLOW_CLK_32K_EXT_OSC;
|
slow_clk = SLOW_CLK_32K_EXT_OSC;
|
||||||
#elif defined(CONFIG_ESP32_RTC_CLK_SRC_INT_8MD256)
|
#elif defined(CONFIG_ESP32S3_RTC_CLK_INT_8MD256)
|
||||||
slow_clk = SLOW_CLK_8MD256;
|
slow_clk = SLOW_CLK_8MD256;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -34,7 +34,7 @@
|
|||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Name: esp32_rtc_driverinit
|
* Name: esp32s3_rtc_driverinit
|
||||||
*
|
*
|
||||||
* Description:
|
* Description:
|
||||||
* Bind the configuration timer to a timer lower half instance and register
|
* Bind the configuration timer to a timer lower half instance and register
|
||||||
@@ -49,7 +49,7 @@
|
|||||||
*
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
int esp32_rtc_driverinit(void);
|
int esp32s3_rtc_driverinit(void);
|
||||||
|
|
||||||
#endif /* CONFIG_RTC_DRIVER */
|
#endif /* CONFIG_RTC_DRIVER */
|
||||||
|
|
||||||
|
|||||||
@@ -50,13 +50,27 @@
|
|||||||
|
|
||||||
/* 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 esp32s3_wdt_priv_s *)dev)->base == \
|
#define IS_RWDT(dev) (((struct esp32s3_wdt_priv_s *)dev)->type == RTC)
|
||||||
RTC_CNTL_RTC_OPTIONS0_REG)
|
|
||||||
|
/* Check whether the provided device is a Main Watchdog Timer */
|
||||||
|
|
||||||
|
#define IS_MWDT(dev) (((struct esp32s3_wdt_priv_s *)dev)->type == TIMER)
|
||||||
|
|
||||||
|
/* Check whether the provided device is a XTAL32K Watchdog Timer */
|
||||||
|
|
||||||
|
#define IS_XTWDT(dev) (((struct esp32s3_wdt_priv_s *)dev)->type == XTAL32K)
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Private Types
|
* Private Types
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
|
enum wdt_peripheral_e
|
||||||
|
{
|
||||||
|
RTC,
|
||||||
|
TIMER,
|
||||||
|
XTAL32K,
|
||||||
|
};
|
||||||
|
|
||||||
struct esp32s3_wdt_priv_s
|
struct esp32s3_wdt_priv_s
|
||||||
{
|
{
|
||||||
struct esp32s3_wdt_ops_s *ops;
|
struct esp32s3_wdt_ops_s *ops;
|
||||||
@@ -66,8 +80,15 @@ struct esp32s3_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
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
@@ -101,6 +122,7 @@ static void wdt_enableint(struct esp32s3_wdt_dev_s *dev);
|
|||||||
static void wdt_disableint(struct esp32s3_wdt_dev_s *dev);
|
static void wdt_disableint(struct esp32s3_wdt_dev_s *dev);
|
||||||
static void wdt_ackint(struct esp32s3_wdt_dev_s *dev);
|
static void wdt_ackint(struct esp32s3_wdt_dev_s *dev);
|
||||||
static uint16_t wdt_rtc_clk(struct esp32s3_wdt_dev_s *dev);
|
static uint16_t wdt_rtc_clk(struct esp32s3_wdt_dev_s *dev);
|
||||||
|
static void wdt_rstclk(struct esp32s3_wdt_dev_s *dev);
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Private Data
|
* Private Data
|
||||||
@@ -108,7 +130,7 @@ static uint16_t wdt_rtc_clk(struct esp32s3_wdt_dev_s *dev);
|
|||||||
|
|
||||||
/* ESP32-S3 WDT ops */
|
/* ESP32-S3 WDT ops */
|
||||||
|
|
||||||
struct esp32s3_wdt_ops_s esp32s3_mwdt_ops =
|
struct esp32s3_wdt_ops_s esp32s3_wdt_ops =
|
||||||
{
|
{
|
||||||
.start = wdt_start,
|
.start = wdt_start,
|
||||||
.stop = wdt_stop,
|
.stop = wdt_stop,
|
||||||
@@ -118,63 +140,63 @@ struct esp32s3_wdt_ops_s esp32s3_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,
|
|
||||||
.setisr = wdt_setisr,
|
|
||||||
.enableint = wdt_enableint,
|
|
||||||
.disableint = wdt_disableint,
|
|
||||||
.ackint = wdt_ackint,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct esp32s3_wdt_ops_s esp32s3_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 = wdt_rtc_clk,
|
.rtc_clk = wdt_rtc_clk,
|
||||||
.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_ESP32S3_MWDT0
|
#ifdef CONFIG_ESP32S3_MWDT0
|
||||||
struct esp32s3_wdt_priv_s g_esp32s3_mwdt0_priv =
|
struct esp32s3_wdt_priv_s g_esp32s3_mwdt0_priv =
|
||||||
{
|
{
|
||||||
.ops = &esp32s3_mwdt_ops,
|
.ops = &esp32s3_wdt_ops,
|
||||||
.base = TIMG_T0CONFIG_REG(0),
|
.base = TIMG_T0CONFIG_REG(0),
|
||||||
.periph = ESP32S3_PERIPH_TG_WDT_LEVEL,
|
.periph = ESP32S3_PERIPH_TG_WDT_LEVEL,
|
||||||
.irq = ESP32S3_IRQ_TG_WDT_LEVEL,
|
.irq = ESP32S3_IRQ_TG_WDT_LEVEL,
|
||||||
.cpuint = -ENOMEM,
|
.cpuint = -ENOMEM,
|
||||||
.inuse = false,
|
.inuse = false,
|
||||||
|
.type = TIMER,
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_ESP32S3_MWDT1
|
#ifdef CONFIG_ESP32S3_MWDT1
|
||||||
struct esp32s3_wdt_priv_s g_esp32s3_mwdt1_priv =
|
struct esp32s3_wdt_priv_s g_esp32s3_mwdt1_priv =
|
||||||
{
|
{
|
||||||
.ops = &esp32s3_mwdt_ops,
|
.ops = &esp32s3_wdt_ops,
|
||||||
.base = TIMG_T0CONFIG_REG(1),
|
.base = TIMG_T0CONFIG_REG(1),
|
||||||
.periph = ESP32S3_PERIPH_TG1_WDT_LEVEL,
|
.periph = ESP32S3_PERIPH_TG1_WDT_LEVEL,
|
||||||
.irq = ESP32S3_IRQ_TG1_WDT_LEVEL,
|
.irq = ESP32S3_IRQ_TG1_WDT_LEVEL,
|
||||||
.cpuint = -ENOMEM,
|
.cpuint = -ENOMEM,
|
||||||
.inuse = false,
|
.inuse = false,
|
||||||
|
.type = TIMER,
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_ESP32S3_RWDT
|
#ifdef CONFIG_ESP32S3_RWDT
|
||||||
struct esp32s3_wdt_priv_s g_esp32s3_rwdt_priv =
|
struct esp32s3_wdt_priv_s g_esp32s3_rwdt_priv =
|
||||||
{
|
{
|
||||||
.ops = &esp32s3_rwdt_ops,
|
.ops = &esp32s3_wdt_ops,
|
||||||
.base = RTC_CNTL_RTC_OPTIONS0_REG,
|
.base = RTC_CNTL_RTC_OPTIONS0_REG,
|
||||||
.periph = ESP32S3_PERIPH_RTC_CORE,
|
.periph = ESP32S3_PERIPH_RTC_CORE,
|
||||||
.irq = ESP32S3_IRQ_RTC_WDT,
|
.irq = ESP32S3_IRQ_RTC_WDT,
|
||||||
.cpuint = -ENOMEM,
|
.cpuint = -ENOMEM,
|
||||||
.inuse = false,
|
.inuse = false,
|
||||||
|
.type = RTC,
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_ESP32S3_XTWDT
|
||||||
|
struct esp32s3_wdt_priv_s g_esp32s3_xtwdt_priv =
|
||||||
|
{
|
||||||
|
.ops = &esp32s3_wdt_ops,
|
||||||
|
.base = RTC_CNTL_RTC_OPTIONS0_REG,
|
||||||
|
.periph = ESP32S3_PERIPH_RTC_CORE,
|
||||||
|
.irq = ESP32S3_IRQ_RTC_XTAL32K_DEAD,
|
||||||
|
.cpuint = -ENOMEM,
|
||||||
|
.inuse = false,
|
||||||
|
.type = XTAL32K,
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -267,10 +289,18 @@ static void wdt_start(struct esp32s3_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_ESP32S3_XTWDT_BACKUP_CLK_ENABLE
|
||||||
|
wdt_modifyreg32(dev, XTWDT_CONFIG0_OFFSET,
|
||||||
|
0, RTC_CNTL_XTAL32K_AUTO_BACKUP);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
@@ -308,7 +338,7 @@ static int32_t wdt_config_stage(struct esp32s3_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);
|
||||||
@@ -324,7 +354,7 @@ static int32_t wdt_config_stage(struct esp32s3_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);
|
||||||
@@ -340,7 +370,7 @@ static int32_t wdt_config_stage(struct esp32s3_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);
|
||||||
@@ -356,7 +386,7 @@ static int32_t wdt_config_stage(struct esp32s3_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);
|
||||||
@@ -393,10 +423,14 @@ static void wdt_stop(struct esp32s3_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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
@@ -422,7 +456,7 @@ static void wdt_enablewp(struct esp32s3_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);
|
||||||
}
|
}
|
||||||
@@ -451,7 +485,7 @@ static void wdt_disablewp(struct esp32s3_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);
|
||||||
}
|
}
|
||||||
@@ -474,12 +508,23 @@ static void wdt_disablewp(struct esp32s3_wdt_dev_s *dev)
|
|||||||
|
|
||||||
static void wdt_pre(struct esp32s3_wdt_dev_s *dev, uint16_t pre)
|
static void wdt_pre(struct esp32s3_wdt_dev_s *dev, uint16_t pre)
|
||||||
{
|
{
|
||||||
uint32_t mask = (uint32_t)pre << TIMG_WDT_CLK_PRESCALE_S;
|
uint32_t mask = 0;
|
||||||
|
|
||||||
DEBUGASSERT(dev != NULL);
|
DEBUGASSERT(dev != NULL);
|
||||||
|
|
||||||
wdt_modifyreg32(dev, MWDT_CLK_PRESCALE_OFFSET, TIMG_WDT_CLK_PRESCALE_M,
|
if (IS_MWDT(dev))
|
||||||
mask);
|
{
|
||||||
|
mask = (uint32_t)pre << TIMG_WDT_CLK_PRESCALE_S;
|
||||||
|
wdt_modifyreg32(dev, MWDT_CLK_PRESCALE_OFFSET, TIMG_WDT_CLK_PRESCALE_M,
|
||||||
|
mask);
|
||||||
|
}
|
||||||
|
#ifdef CONFIG_ESP32S3_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
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
@@ -504,6 +549,14 @@ static int32_t wdt_settimeout(struct esp32s3_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 ESP32S3_WDT_STAGE0:
|
case ESP32S3_WDT_STAGE0:
|
||||||
@@ -596,7 +649,7 @@ static void wdt_feed(struct esp32s3_wdt_dev_s *dev)
|
|||||||
{
|
{
|
||||||
wdt_modifyreg32(dev, RWDT_FEED_OFFSET, 0, RTC_CNTL_RTC_WDT_FEED);
|
wdt_modifyreg32(dev, RWDT_FEED_OFFSET, 0, RTC_CNTL_RTC_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);
|
||||||
}
|
}
|
||||||
@@ -704,8 +757,9 @@ static int32_t wdt_setisr(struct esp32s3_wdt_dev_s *dev, xcpt_t handler,
|
|||||||
|
|
||||||
if (wdt->cpuint >= 0)
|
if (wdt->cpuint >= 0)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_ESP32S3_RWDT
|
#if defined(CONFIG_ESP32S3_RWDT) || defined(CONFIG_ESP32S3_XTWDT)
|
||||||
if (wdt->irq == ESP32S3_IRQ_RTC_WDT)
|
if (wdt->irq == ESP32S3_IRQ_RTC_WDT ||
|
||||||
|
wdt->irq == ESP32S3_IRQ_RTC_XTAL32K_DEAD)
|
||||||
{
|
{
|
||||||
esp32s3_rtcioirqdisable(wdt->irq);
|
esp32s3_rtcioirqdisable(wdt->irq);
|
||||||
irq_detach(wdt->irq);
|
irq_detach(wdt->irq);
|
||||||
@@ -732,8 +786,9 @@ static int32_t wdt_setisr(struct esp32s3_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_ESP32S3_RWDT
|
#if defined(CONFIG_ESP32S3_RWDT) || defined(CONFIG_ESP32S3_XTWDT)
|
||||||
if (wdt->irq == ESP32S3_IRQ_RTC_WDT)
|
if (wdt->irq == ESP32S3_IRQ_RTC_WDT ||
|
||||||
|
wdt->irq == ESP32S3_IRQ_RTC_XTAL32K_DEAD)
|
||||||
{
|
{
|
||||||
ret = irq_attach(wdt->irq, handler, arg);
|
ret = irq_attach(wdt->irq, handler, arg);
|
||||||
|
|
||||||
@@ -799,10 +854,15 @@ static void wdt_enableint(struct esp32s3_wdt_dev_s *dev)
|
|||||||
wdt_modifyreg32(dev, RWDT_INT_ENA_REG_OFFSET, 0,
|
wdt_modifyreg32(dev, RWDT_INT_ENA_REG_OFFSET, 0,
|
||||||
RTC_CNTL_RTC_WDT_INT_ENA);
|
RTC_CNTL_RTC_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_RTC_XTAL32K_DEAD_INT_ENA);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
@@ -825,10 +885,15 @@ static void wdt_disableint(struct esp32s3_wdt_dev_s *dev)
|
|||||||
wdt_modifyreg32(dev, RWDT_INT_ENA_REG_OFFSET, RTC_CNTL_RTC_WDT_INT_ENA,
|
wdt_modifyreg32(dev, RWDT_INT_ENA_REG_OFFSET, RTC_CNTL_RTC_WDT_INT_ENA,
|
||||||
0);
|
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_RTC_XTAL32K_DEAD_INT_ENA, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
@@ -850,10 +915,49 @@ static void wdt_ackint(struct esp32s3_wdt_dev_s *dev)
|
|||||||
{
|
{
|
||||||
wdt_putreg(dev, RWDT_INT_CLR_REG_OFFSET, RTC_CNTL_RTC_WDT_INT_CLR);
|
wdt_putreg(dev, RWDT_INT_CLR_REG_OFFSET, RTC_CNTL_RTC_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_RTC_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 esp32s3_wdt_dev_s *dev)
|
||||||
|
{
|
||||||
|
DEBUGASSERT(dev != NULL);
|
||||||
|
|
||||||
|
struct esp32s3_wdt_priv_s *wdt = (struct esp32s3_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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
@@ -906,6 +1010,15 @@ struct esp32s3_wdt_dev_s *esp32s3_wdt_init(enum esp32s3_wdt_inst_e wdt_id)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_ESP32S3_XTWDT
|
||||||
|
case ESP32S3_WDT_XTWDT:
|
||||||
|
{
|
||||||
|
wdt = &g_esp32s3_xtwdt_priv;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@@ -1000,7 +1113,7 @@ bool esp32s3_wdt_is_running(struct esp32s3_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)
|
||||||
@@ -1008,6 +1121,14 @@ bool esp32s3_wdt_is_running(struct esp32s3_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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 ESP32S3_WDT_START(d) ((d)->ops->start(d))
|
#define ESP32S3_WDT_START(d) ((d)->ops->start(d))
|
||||||
@@ -42,14 +59,17 @@
|
|||||||
#define ESP32S3_WDT_LOCK(d) ((d)->ops->enablewp(d))
|
#define ESP32S3_WDT_LOCK(d) ((d)->ops->enablewp(d))
|
||||||
#define ESP32S3_WDT_UNLOCK(d) ((d)->ops->disablewp(d))
|
#define ESP32S3_WDT_UNLOCK(d) ((d)->ops->disablewp(d))
|
||||||
#define ESP32S3_MWDT_PRE(d, v) ((d)->ops->pre(d, v))
|
#define ESP32S3_MWDT_PRE(d, v) ((d)->ops->pre(d, v))
|
||||||
|
#define ESP32S3_XTWDT_PRE(d, v) ((d)->ops->pre(d, v))
|
||||||
#define ESP32S3_WDT_STO(d, v, s) ((d)->ops->settimeout(d, v, s))
|
#define ESP32S3_WDT_STO(d, v, s) ((d)->ops->settimeout(d, v, s))
|
||||||
#define ESP32S3_WDT_FEED(d) ((d)->ops->feed(d))
|
#define ESP32S3_WDT_FEED(d) ((d)->ops->feed(d))
|
||||||
#define ESP32S3_WDT_STG_CONF(d, s, c) ((d)->ops->stg_conf(d, s, c))
|
#define ESP32S3_WDT_STG_CONF(d, s, c) ((d)->ops->stg_conf(d, s, c))
|
||||||
#define ESP32S3_RWDT_CLK(d) ((d)->ops->rtc_clk(d))
|
#define ESP32S3_RWDT_CLK(d) ((d)->ops->rtc_clk(d))
|
||||||
|
#define ESP32S3_XTWDT_CLK(d) ((d)->ops->rtc_clk(d))
|
||||||
#define ESP32S3_WDT_SETISR(d, hnd, arg) ((d)->ops->setisr(d, hnd, arg))
|
#define ESP32S3_WDT_SETISR(d, hnd, arg) ((d)->ops->setisr(d, hnd, arg))
|
||||||
#define ESP32S3_WDT_ENABLEINT(d) ((d)->ops->enableint(d))
|
#define ESP32S3_WDT_ENABLEINT(d) ((d)->ops->enableint(d))
|
||||||
#define ESP32S3_WDT_DISABLEINT(d) ((d)->ops->disableint(d))
|
#define ESP32S3_WDT_DISABLEINT(d) ((d)->ops->disableint(d))
|
||||||
#define ESP32S3_WDT_ACKINT(d) ((d)->ops->ackint(d))
|
#define ESP32S3_WDT_ACKINT(d) ((d)->ops->ackint(d))
|
||||||
|
#define ESP32S3_XTWDT_RST_CLK(d) ((d)->ops->rstclk(d))
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Public Types
|
* Public Types
|
||||||
@@ -61,7 +81,8 @@ enum esp32s3_wdt_inst_e
|
|||||||
{
|
{
|
||||||
ESP32S3_WDT_MWDT0 = 0, /* Main System Watchdog Timer (MWDT) of Timer Group 0 */
|
ESP32S3_WDT_MWDT0 = 0, /* Main System Watchdog Timer (MWDT) of Timer Group 0 */
|
||||||
ESP32S3_WDT_MWDT1, /* Main System Watchdog Timer (MWDT) of Timer Group 1 */
|
ESP32S3_WDT_MWDT1, /* Main System Watchdog Timer (MWDT) of Timer Group 1 */
|
||||||
ESP32S3_WDT_RWDT /* RTC Watchdog Timer (RWDT) */
|
ESP32S3_WDT_RWDT, /* RTC Watchdog Timer (RWDT) */
|
||||||
|
ESP32S3_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. */
|
||||||
@@ -135,6 +156,7 @@ struct esp32s3_wdt_ops_s
|
|||||||
void (*enableint)(struct esp32s3_wdt_dev_s *dev);
|
void (*enableint)(struct esp32s3_wdt_dev_s *dev);
|
||||||
void (*disableint)(struct esp32s3_wdt_dev_s *dev);
|
void (*disableint)(struct esp32s3_wdt_dev_s *dev);
|
||||||
void (*ackint)(struct esp32s3_wdt_dev_s *dev);
|
void (*ackint)(struct esp32s3_wdt_dev_s *dev);
|
||||||
|
void (*rstclk)(struct esp32s3_wdt_dev_s *dev);
|
||||||
};
|
};
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
|
|||||||
@@ -38,6 +38,7 @@
|
|||||||
|
|
||||||
#include "xtensa.h"
|
#include "xtensa.h"
|
||||||
#include "esp32s3_wdt.h"
|
#include "esp32s3_wdt.h"
|
||||||
|
#include "esp32s3_rtc.h"
|
||||||
#include "esp32s3_wdt_lowerhalf.h"
|
#include "esp32s3_wdt_lowerhalf.h"
|
||||||
#include "hardware/esp32s3_soc.h"
|
#include "hardware/esp32s3_soc.h"
|
||||||
|
|
||||||
@@ -69,6 +70,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
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
@@ -77,6 +96,7 @@ 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"
|
||||||
@@ -116,6 +136,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_ESP32S3_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
|
||||||
@@ -131,7 +157,7 @@ static const struct watchdog_ops_s g_esp32s3_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_ESP32S3_MWDT0
|
#ifdef CONFIG_ESP32S3_MWDT0
|
||||||
@@ -161,6 +187,15 @@ static struct esp32s3_wdt_lowerhalf_s g_esp32s3_rwdt_lowerhalf =
|
|||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_ESP32S3_XTWDT
|
||||||
|
/* XTWDT lower-half */
|
||||||
|
|
||||||
|
static struct esp32s3_wdt_lowerhalf_s g_esp32s3_xtwdt_lowerhalf =
|
||||||
|
{
|
||||||
|
.ops = &g_esp32s3_wdg_ops,
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Name: wdt_lh_start
|
* Name: wdt_lh_start
|
||||||
*
|
*
|
||||||
@@ -217,7 +252,7 @@ static int wdt_lh_start(struct watchdog_lowerhalf_s *lower)
|
|||||||
ESP32S3_WDT_STG_CONF(priv->wdt, ESP32S3_WDT_STAGE0,
|
ESP32S3_WDT_STG_CONF(priv->wdt, ESP32S3_WDT_STAGE0,
|
||||||
ESP32S3_WDT_STAGE_ACTION_RESET_SYSTEM);
|
ESP32S3_WDT_STAGE_ACTION_RESET_SYSTEM);
|
||||||
}
|
}
|
||||||
else
|
else if (priv->peripheral == RTC)
|
||||||
{
|
{
|
||||||
ESP32S3_WDT_STG_CONF(priv->wdt, ESP32S3_WDT_STAGE0,
|
ESP32S3_WDT_STG_CONF(priv->wdt, ESP32S3_WDT_STAGE0,
|
||||||
ESP32S3_WDT_STAGE_ACTION_RESET_RTC);
|
ESP32S3_WDT_STAGE_ACTION_RESET_RTC);
|
||||||
@@ -434,6 +469,8 @@ static int wdt_lh_settimeout(struct watchdog_lowerhalf_s *lower,
|
|||||||
(struct esp32s3_wdt_lowerhalf_s *)lower;
|
(struct esp32s3_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);
|
||||||
@@ -467,7 +504,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 = ESP32S3_RWDT_CLK(priv->wdt);
|
rtc_cycles = ESP32S3_RWDT_CLK(priv->wdt);
|
||||||
rtc_ms_max = (RWDT_FULL_STAGE / (uint32_t)rtc_cycles);
|
rtc_ms_max = (RWDT_FULL_STAGE / (uint32_t)rtc_cycles);
|
||||||
@@ -487,6 +524,29 @@ 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
|
||||||
|
/ (uint32_t)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;
|
||||||
|
ESP32S3_WDT_STO(priv->wdt, timeout, ESP32S3_WDT_STAGE0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Reset the wdt */
|
/* Reset the wdt */
|
||||||
|
|
||||||
ESP32S3_WDT_FEED(priv->wdt);
|
ESP32S3_WDT_FEED(priv->wdt);
|
||||||
@@ -589,7 +649,7 @@ static xcpt_t wdt_lh_capture(struct watchdog_lowerhalf_s *lower,
|
|||||||
ESP32S3_WDT_STG_CONF(priv->wdt, ESP32S3_WDT_STAGE0,
|
ESP32S3_WDT_STG_CONF(priv->wdt, ESP32S3_WDT_STAGE0,
|
||||||
ESP32S3_WDT_STAGE_ACTION_RESET_SYSTEM);
|
ESP32S3_WDT_STAGE_ACTION_RESET_SYSTEM);
|
||||||
}
|
}
|
||||||
else
|
else if (priv->peripheral == RTC)
|
||||||
{
|
{
|
||||||
ESP32S3_WDT_STG_CONF(priv->wdt, ESP32S3_WDT_STAGE0,
|
ESP32S3_WDT_STG_CONF(priv->wdt, ESP32S3_WDT_STAGE0,
|
||||||
ESP32S3_WDT_STAGE_ACTION_RESET_RTC);
|
ESP32S3_WDT_STAGE_ACTION_RESET_RTC);
|
||||||
@@ -601,6 +661,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 esp32s3_wdt_lowerhalf_s *priv =
|
||||||
|
(struct esp32s3_wdt_lowerhalf_s *)lower;
|
||||||
|
|
||||||
|
wdinfo("ioctl Call: cmd=0x%x arg=0x%lx", cmd, arg);
|
||||||
|
|
||||||
|
/* Process the IOCTL command */
|
||||||
|
|
||||||
|
switch (cmd)
|
||||||
|
{
|
||||||
|
case WDIOC_RSTCLK:
|
||||||
|
ESP32S3_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 +723,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_ESP32S3_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 +856,15 @@ int esp32s3_wdt_initialize(const char *devpath, enum esp32s3_wdt_inst_e wdt)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_ESP32S3_XTWDT
|
||||||
|
case ESP32S3_WDT_XTWDT:
|
||||||
|
{
|
||||||
|
lower = &g_esp32s3_xtwdt_lowerhalf;
|
||||||
|
lower->peripheral = XTAL32K;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
ret = -ENODEV;
|
ret = -ENODEV;
|
||||||
@@ -712,6 +897,26 @@ int esp32s3_wdt_initialize(const char *devpath, enum esp32s3_wdt_inst_e wdt)
|
|||||||
ESP32S3_MWDT_PRE(lower->wdt, MWDT_CLK_PRESCALER_VALUE);
|
ESP32S3_MWDT_PRE(lower->wdt, MWDT_CLK_PRESCALER_VALUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Configure auto backup clock when XTAL32K fails */
|
||||||
|
|
||||||
|
#ifdef CONFIG_ESP32S3_XTWDT_BACKUP_CLK_ENABLE
|
||||||
|
if (lower->peripheral == XTAL32K)
|
||||||
|
{
|
||||||
|
/* Estimate frequency of internal RTC oscillator */
|
||||||
|
|
||||||
|
uint32_t rtc_clk_period_us =
|
||||||
|
esp32s3_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);
|
||||||
|
|
||||||
|
ESP32S3_XTWDT_PRE(lower->wdt, xtal32k_clk_factor);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
ESP32S3_WDT_LOCK(lower->wdt);
|
ESP32S3_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
|
||||||
|
|||||||
@@ -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 0x0098
|
#define RWDT_CONFIG0_OFFSET 0x0098
|
||||||
|
#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 0x00f8
|
||||||
|
#define XTWDT_CLK_PRESCALE_OFFSET 0x00f4
|
||||||
|
#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
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -82,6 +82,15 @@ int board_wdt_init(void)
|
|||||||
}
|
}
|
||||||
#endif /* CONFIG_ESP32S3_RWDT */
|
#endif /* CONFIG_ESP32S3_RWDT */
|
||||||
|
|
||||||
|
#ifdef CONFIG_ESP32S3_XTWDT
|
||||||
|
ret = esp32s3_wdt_initialize("/dev/watchdog3", ESP32S3_WDT_XTWDT);
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
syslog(LOG_ERR, "Failed to initialize XTWDT: %d\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_ESP32S3_XTWDT */
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user