arch/arm/rtl8721dx: add shared Ameba watchdog driver

Add a NuttX watchdog lower-half for the Ameba KM4 non-secure system
watchdog (WDG2), registered as /dev/watchdog0.  The fwlib WDG API is
ROM-resident, so no board.mk change is needed.

The hardware cannot be stopped once enabled, so stop() is emulated via
the early interrupt (EI) auto-refreshing the counter, and capture()
delivers a pre-timeout callback through the same EI.  The EI has a
three-part timing contract, all handled here: it must be armed with
EIMOD=ENABLE at WDG_Init, its EIE gate only takes effect after
WDG_Enable, and -- because the EI is level-based -- a pure capture path
must mask EIE after the one-shot callback to avoid re-entrant storming
while the reset is pending.  The EI flag is cleared twice per the slow
WDG clock.

Per-chip base address and IRQ live in ameba_wdg_chip.h so the shared
driver needs no change to port to another Ameba IC.

Verified on pke8721daf: timeout reset (BOOT REASON WDG2), stop()
suppressing the reset, and capture() firing ~EICNT ms before the reset.

Assisted-by: Claude <noreply@anthropic.com>
Signed-off-by: dechao_gong <dechao_gong@realsil.com.cn>
This commit is contained in:
dechao_gong 2026-07-21 11:33:59 +08:00 committed by Xiang Xiao
parent 6a71c89380
commit a25fbba5a5
14 changed files with 912 additions and 1 deletions

View file

@ -47,6 +47,8 @@ Supported in this NuttX port:
on the SDK fwlib register layer
* On-chip RTC exposed as a ``/dev/rtc0`` date/time character device with
alarm support, driven directly on the SDK fwlib register layer
* On-chip watchdog exposed as a ``/dev/watchdog0`` character device, driven
directly on the SDK fwlib register layer
Buttons and LEDs
================
@ -186,6 +188,17 @@ NSH ``date`` command, and arm a one-shot wakeup with the example::
nsh> date -s "Jun 16 12:00:00 2026" # set the RTC
nsh> alarm 10 # fire an alarm in 10 seconds
wdg
---
Minimal NSH with the on-chip watchdog driver and the ``wdog`` example
enabled (no Wi-Fi). The watchdog is registered at ``/dev/watchdog0`` from the
board bring-up (``boards/arm/rtl8721dx/pke8721daf/src/rtl8721dx_wdg.c``); it
has no board wiring (it is an internal timer). Exercise it with the example,
which opens the device, sets a timeout, and pings it::
nsh> wdog # run the watchdog example
Wi-Fi
=====

View file

@ -134,4 +134,19 @@ config AMEBA_RTC
day-of-year (no month/day register); the driver bridges that to the
NuttX month/day calendar with the libc UTC calendar routines.
config AMEBA_WDG
bool "Watchdog"
default n
select WATCHDOG
---help---
Expose the Ameba system watchdog as a NuttX watchdog at
/dev/watchdog0 (start/stop/keepalive/settimeout, plus a capture
pre-timeout callback). The timeout is programmed directly in
milliseconds.
The driver (arch/arm/src/common/ameba/ameba_wdg.c) sits on the SDK
fwlib WDG register layer. The hardware cannot be halted once
enabled, so stop() arms the WDG early interrupt and refreshes the
counter from its handler to inhibit the reset.
endmenu # Ameba Peripheral Support

View file

@ -0,0 +1,576 @@
/****************************************************************************
* arch/arm/src/common/ameba/ameba_wdg.c
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
/* NuttX watchdog lower half for the Realtek Ameba system watchdog. It
* exposes the on-chip WDG as a NuttX watchdog at /dev/watchdog0 with the
* usual start/stop/keepalive/getstatus/settimeout methods, plus capture
* (a pre-timeout "early interrupt" callback).
*
* The WDG is driven through the SDK fwlib WDG API. Those routines are
* marked _LONG_CALL_ and are resolved from ROM (they appear in the fwlib
* ROM symbol table), so -- like the UART/SPI drivers -- nothing extra is
* added to the board build. Each call takes a WDG_TypeDef * register base;
* the base and the interrupt vector are the only chip-specific facts and
* live in the per-chip ameba_wdg_chip.h. To keep the vendor headers out of
* the NuttX include world the few fwlib symbols, constants and structures
* used here are declared locally (layout-compatible mirrors) rather than
* pulled in from the SDK <ameba_wdg.h>.
*
* Hardware note (the "one catch"): the Ameba system WDG can be enabled but
* it *cannot be stopped by software* -- the fwlib exposes WDG_Enable() with
* no WDG_Cmd(DISABLE) counterpart in ROM, and the vendor HAL asserts on
* stop. To honour the NuttX stop() contract we instead arm the WDG early
* interrupt and refresh the counter from its handler, so the timer keeps
* running but can never reach the reset threshold -- an effective "stop".
* The same early interrupt backs capture(): when a user handler is
* registered it is called at the pre-timeout point instead.
*/
#include <nuttx/config.h>
#include <sys/types.h>
#include <stdint.h>
#include <stdbool.h>
#include <errno.h>
#include <debug.h>
#include <nuttx/irq.h>
#include <nuttx/arch.h>
#include <nuttx/clock.h>
#include <nuttx/spinlock.h>
#include <nuttx/timers/watchdog.h>
#include "ameba_wdg.h"
#include "ameba_wdg_chip.h"
#ifdef CONFIG_WATCHDOG
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* "state" argument for the fwlib enable/disable style APIs. */
#define AMEBA_DISABLE 0x0
#define AMEBA_ENABLE 0x1
/* fwlib WDG_CR interrupt bits (from the SDK ameba_wdg.h; identical on every
* current Ameba chip): early-interrupt enable and its write-1-to-clear flag.
*/
#define AMEBA_WDG_BIT_EIE ((uint32_t)1 << 16) /* early int enable */
#define AMEBA_WDG_BIT_EIC ((uint32_t)1 << 17) /* early int clear */
/* WDG timeout is a 16-bit millisecond count; the early interrupt fires this
* many milliseconds before the timeout. Match the vendor HAL: 100ms of head
* room, or half the timeout when that is under 100ms (at least 1ms).
*/
#define AMEBA_WDG_TIMEOUT_MAX 65535u
#define AMEBA_WDG_DEFAULT_MS 5000u
#define AMEBA_WDG_EICNT(ms) ((ms) > 100 ? 100 : (((ms) + 1) >> 1))
/* The chip header hands us the register base as a plain address. */
#define AMEBA_WDG ((struct ameba_wdg_dev_s *)AMEBA_WDG_BASE)
/****************************************************************************
* Private Types
****************************************************************************/
/* Layout-compatible mirrors of the fwlib WDG structures (same field order
* and types); passed by address to the fwlib WDG API. The register block is
* only ever touched through the fwlib, so it is an opaque base here -- this
* driver never dereferences any field below, it only hands the base pointer
* to the ROM routines. That is what keeps it chip-neutral: amebasmart's
* WDG_TypeDef has no 0x010 "dummy" register (only 4 words), but since the
* field is never read the extra word is harmless padding on that chip.
*/
/* WDG_TypeDef */
struct ameba_wdg_dev_s
{
volatile uint32_t mkeyr; /* 0x000 magic key register */
volatile uint32_t cr; /* 0x004 control register */
volatile uint32_t rlr; /* 0x008 reload register */
volatile uint32_t winr; /* 0x00C window register */
volatile uint32_t dummy; /* 0x010 (absent on amebasmart) */
};
/* WDG_InitTypeDef */
struct ameba_wdg_init_s
{
uint16_t window; /* feed-protect window */
uint16_t timeout; /* timeout count, in ms */
uint16_t eicnt; /* early-interrupt threshold */
uint16_t eimod; /* early-interrupt enable */
};
/* This is the private watchdog lower-half state. It must be cast-compatible
* with struct watchdog_lowerhalf_s (the ops pointer is first).
*/
struct ameba_wdg_lowerhalf_s
{
const struct watchdog_ops_s *ops; /* Lower-half operations vtable */
spinlock_t lock; /* Protects the state below */
uint32_t timeout; /* The last programmed timeout (ms) */
clock_t lastreset; /* systime of the last (re)start/feed */
bool configured; /* WDG_Init has run at least once */
bool started; /* Counting towards a reset */
bool autofeed; /* stop(): EI handler refreshes to inhibit
* the reset (the WDG cannot be halted) */
xcpt_t handler; /* capture() pre-timeout callback */
};
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
/* SDK fwlib WDG API (resolved from ROM). Each call takes the WDG register
* base; none of them need the vendor headers.
*/
extern void WDG_StructInit(struct ameba_wdg_init_s *init);
extern void WDG_Init(struct ameba_wdg_dev_s *wdg,
struct ameba_wdg_init_s *init);
extern void WDG_Enable(struct ameba_wdg_dev_s *wdg);
extern void WDG_Timeout(struct ameba_wdg_dev_s *wdg, uint32_t timeout);
extern void WDG_Refresh(struct ameba_wdg_dev_s *wdg);
extern void WDG_INTConfig(struct ameba_wdg_dev_s *wdg, uint32_t wdg_it,
uint32_t newstate);
extern void WDG_ClearINT(struct ameba_wdg_dev_s *wdg, uint32_t intrbit);
static int ameba_wdg_interrupt(int irq, void *context, void *arg);
/* Watchdog lower-half operations. */
static int ameba_wdg_start(struct watchdog_lowerhalf_s *lower);
static int ameba_wdg_stop(struct watchdog_lowerhalf_s *lower);
static int ameba_wdg_keepalive(struct watchdog_lowerhalf_s *lower);
static int ameba_wdg_getstatus(struct watchdog_lowerhalf_s *lower,
struct watchdog_status_s *status);
static int ameba_wdg_settimeout(struct watchdog_lowerhalf_s *lower,
uint32_t timeout);
static xcpt_t ameba_wdg_capture(struct watchdog_lowerhalf_s *lower,
xcpt_t handler);
/****************************************************************************
* Private Data
****************************************************************************/
static const struct watchdog_ops_s g_wdg_ops =
{
.start = ameba_wdg_start,
.stop = ameba_wdg_stop,
.keepalive = ameba_wdg_keepalive,
.getstatus = ameba_wdg_getstatus,
.settimeout = ameba_wdg_settimeout,
.capture = ameba_wdg_capture,
.ioctl = NULL,
};
static struct ameba_wdg_lowerhalf_s g_wdg_lowerhalf =
{
.ops = &g_wdg_ops,
.lock = SP_UNLOCKED,
};
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: ameba_wdg_hwinit
*
* Description:
* Program the fwlib WDG for a timeout (in ms) with the early interrupt
* configured but left masked. Only valid before the WDG is enabled; once
* running, settimeout() uses WDG_Timeout() instead.
*
****************************************************************************/
static void ameba_wdg_hwinit(struct ameba_wdg_lowerhalf_s *priv,
uint32_t timeout)
{
struct ameba_wdg_init_s init;
WDG_StructInit(&init);
init.timeout = (uint16_t)timeout;
init.eicnt = (uint16_t)AMEBA_WDG_EICNT(timeout);
/* The early-interrupt channel (and its EICNT threshold) is only actually
* armed by WDG_Init when EIMOD is enabled -- the vendor HAL always inits
* with EIMOD=ENABLE when it wants the EI. So arm it here, then gate the
* delivery off with the EIE bit; stop()/capture() flip EIE at run time
* (which is valid after WDG_Enable) without ever re-initialising.
*/
init.eimod = AMEBA_ENABLE;
WDG_Init(AMEBA_WDG, &init);
WDG_INTConfig(AMEBA_WDG, AMEBA_WDG_BIT_EIE, AMEBA_DISABLE);
priv->timeout = timeout;
priv->configured = true;
}
/****************************************************************************
* Name: ameba_wdg_ei
*
* Description:
* Enable or disable delivery of the early interrupt via the CR EIE bit.
* The IRQ itself is attached once in ameba_wdg_initialize(); the NVIC line
* stays enabled and this bit gates whether the WDG actually raises it.
* Called with the driver lock held.
*
****************************************************************************/
static void ameba_wdg_ei(bool enable)
{
/* Clear a possibly-pending flag before (un)masking. The WDG runs off a
* slow clock, so the vendor examples clear the EI flag twice.
*/
WDG_ClearINT(AMEBA_WDG, AMEBA_WDG_BIT_EIC);
WDG_ClearINT(AMEBA_WDG, AMEBA_WDG_BIT_EIC);
WDG_INTConfig(AMEBA_WDG, AMEBA_WDG_BIT_EIE,
enable ? AMEBA_ENABLE : AMEBA_DISABLE);
}
/****************************************************************************
* Name: ameba_wdg_interrupt
*
* Description:
* WDG early-interrupt handler, fired AMEBA_WDG_EICNT() ms before the reset
* threshold. A registered capture handler gets first refusal; otherwise,
* when a stop() has requested it, the counter is refreshed to inhibit the
* reset (the hardware cannot be halted any other way).
*
****************************************************************************/
static int ameba_wdg_interrupt(int irq, void *context, void *arg)
{
struct ameba_wdg_lowerhalf_s *priv =
(struct ameba_wdg_lowerhalf_s *)arg;
if (priv->handler != NULL)
{
priv->handler(irq, context, arg);
}
if (priv->autofeed)
{
/* stop() asked us to keep the counter fed so the reset never lands. */
WDG_Refresh(AMEBA_WDG);
}
else if (priv->handler != NULL)
{
/* Pure capture: the handler has had its pre-timeout notification and
* we deliberately do NOT feed, so the reset must follow. The EI is
* level-based -- with the counter left past the EI threshold it would
* re-assert the moment EIC is cleared and storm the CPU, starving
* everything else until the reset. Mask EIE so this fires exactly
* once and the WDG runs cleanly on to the timeout reset.
*/
WDG_INTConfig(AMEBA_WDG, AMEBA_WDG_BIT_EIE, AMEBA_DISABLE);
}
/* Clear the EI flag twice -- the WDG's slow clock can miss a single
* write-1-to-clear, which would re-enter this handler immediately.
*/
WDG_ClearINT(AMEBA_WDG, AMEBA_WDG_BIT_EIC);
WDG_ClearINT(AMEBA_WDG, AMEBA_WDG_BIT_EIC);
return OK;
}
/****************************************************************************
* Name: ameba_wdg_start
*
* Description:
* Start (enable) the watchdog timer.
*
****************************************************************************/
static int ameba_wdg_start(struct watchdog_lowerhalf_s *lower)
{
struct ameba_wdg_lowerhalf_s *priv =
(struct ameba_wdg_lowerhalf_s *)lower;
irqstate_t flags;
flags = spin_lock_irqsave(&priv->lock);
/* If start() precedes any settimeout(), come up on a sane default. */
if (!priv->configured)
{
ameba_wdg_hwinit(priv, AMEBA_WDG_DEFAULT_MS);
}
/* A restart clears any prior stop() auto-feed. */
priv->autofeed = false;
WDG_Enable(AMEBA_WDG);
/* hwinit() leaves the EI gated off, so re-open it here iff a capture
* handler is registered (capture() may have run before this start()).
* The EIE bit only takes effect after WDG_Enable(), so this must run
* *after* the enable above -- gating it earlier is silently ignored.
*/
ameba_wdg_ei(priv->handler != NULL);
priv->started = true;
priv->lastreset = clock_systime_ticks();
spin_unlock_irqrestore(&priv->lock, flags);
return OK;
}
/****************************************************************************
* Name: ameba_wdg_stop
*
* Description:
* Stop the watchdog timer. The Ameba WDG cannot actually be halted once
* enabled, so this arms the early interrupt to refresh the counter
* forever, which prevents the reset from ever being reached.
*
****************************************************************************/
static int ameba_wdg_stop(struct watchdog_lowerhalf_s *lower)
{
struct ameba_wdg_lowerhalf_s *priv =
(struct ameba_wdg_lowerhalf_s *)lower;
irqstate_t flags;
flags = spin_lock_irqsave(&priv->lock);
if (priv->started)
{
/* Hardware cannot be disabled; inhibit the reset via the early
* interrupt (unless a capture handler is already driving it).
*/
priv->autofeed = true;
if (priv->handler == NULL)
{
ameba_wdg_ei(true);
}
WDG_Refresh(AMEBA_WDG);
priv->started = false;
}
spin_unlock_irqrestore(&priv->lock, flags);
return OK;
}
/****************************************************************************
* Name: ameba_wdg_keepalive
*
* Description:
* Reset ("feed") the watchdog timer.
*
****************************************************************************/
static int ameba_wdg_keepalive(struct watchdog_lowerhalf_s *lower)
{
struct ameba_wdg_lowerhalf_s *priv =
(struct ameba_wdg_lowerhalf_s *)lower;
irqstate_t flags;
flags = spin_lock_irqsave(&priv->lock);
WDG_Refresh(AMEBA_WDG);
priv->lastreset = clock_systime_ticks();
spin_unlock_irqrestore(&priv->lock, flags);
return OK;
}
/****************************************************************************
* Name: ameba_wdg_getstatus
*
* Description:
* Return the current watchdog timer status.
*
****************************************************************************/
static int ameba_wdg_getstatus(struct watchdog_lowerhalf_s *lower,
struct watchdog_status_s *status)
{
struct ameba_wdg_lowerhalf_s *priv =
(struct ameba_wdg_lowerhalf_s *)lower;
irqstate_t flags;
uint32_t elapsed;
flags = spin_lock_irqsave(&priv->lock);
status->flags = 0;
if (priv->started)
{
status->flags |= WDFLAGS_ACTIVE;
}
if (priv->handler != NULL)
{
status->flags |= WDFLAGS_CAPTURE;
}
else if (!priv->autofeed)
{
status->flags |= WDFLAGS_RESET;
}
status->timeout = priv->timeout;
/* Time left = timeout - time since the last feed/start (clamped at 0). */
elapsed = TICK2MSEC(clock_systime_ticks() - priv->lastreset);
status->timeleft = (elapsed >= priv->timeout) ? 0 :
(priv->timeout - elapsed);
spin_unlock_irqrestore(&priv->lock, flags);
return OK;
}
/****************************************************************************
* Name: ameba_wdg_settimeout
*
* Description:
* Set a new timeout value (in milliseconds) and reset the watchdog.
*
****************************************************************************/
static int ameba_wdg_settimeout(struct watchdog_lowerhalf_s *lower,
uint32_t timeout)
{
struct ameba_wdg_lowerhalf_s *priv =
(struct ameba_wdg_lowerhalf_s *)lower;
irqstate_t flags;
if (timeout == 0 || timeout > AMEBA_WDG_TIMEOUT_MAX)
{
return -EINVAL;
}
flags = spin_lock_irqsave(&priv->lock);
if (priv->started)
{
/* Already counting: RLR reconfiguration is not allowed, so use the
* fwlib run-time timeout update and re-feed.
*/
WDG_Timeout(AMEBA_WDG, timeout);
WDG_Refresh(AMEBA_WDG);
priv->timeout = timeout;
}
else
{
ameba_wdg_hwinit(priv, timeout);
}
priv->lastreset = clock_systime_ticks();
spin_unlock_irqrestore(&priv->lock, flags);
return OK;
}
/****************************************************************************
* Name: ameba_wdg_capture
*
* Description:
* Register a pre-timeout ("early interrupt") handler in place of the reset
* behaviour, or restore the reset behaviour when handler is NULL. Returns
* the previous handler.
*
****************************************************************************/
static xcpt_t ameba_wdg_capture(struct watchdog_lowerhalf_s *lower,
xcpt_t handler)
{
struct ameba_wdg_lowerhalf_s *priv =
(struct ameba_wdg_lowerhalf_s *)lower;
irqstate_t flags;
xcpt_t oldhandler;
flags = spin_lock_irqsave(&priv->lock);
oldhandler = priv->handler;
priv->handler = handler;
/* Keep the early interrupt on while either a capture handler or a stop()
* auto-feed needs it; otherwise mask it and let the WDG reset on timeout.
*/
ameba_wdg_ei(handler != NULL || priv->autofeed);
spin_unlock_irqrestore(&priv->lock, flags);
return oldhandler;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: ameba_wdg_initialize
****************************************************************************/
int ameba_wdg_initialize(void)
{
struct ameba_wdg_lowerhalf_s *priv = &g_wdg_lowerhalf;
/* Attach the early interrupt once. The NVIC line stays enabled for the
* lifetime of the driver; the CR EIE bit (flipped by stop()/capture()) is
* what actually gates whether the WDG raises it, and it comes up masked.
*/
irq_attach(AMEBA_WDG_IRQ, ameba_wdg_interrupt, priv);
up_enable_irq(AMEBA_WDG_IRQ);
/* Register the watchdog in the stopped state; nothing counts until the
* application programs a timeout and starts it.
*/
if (watchdog_register(CONFIG_WATCHDOG_DEVPATH,
(struct watchdog_lowerhalf_s *)priv) == NULL)
{
up_disable_irq(AMEBA_WDG_IRQ);
irq_detach(AMEBA_WDG_IRQ);
return -ENODEV;
}
return OK;
}
#endif /* CONFIG_WATCHDOG */

View file

@ -0,0 +1,70 @@
/****************************************************************************
* arch/arm/src/common/ameba/ameba_wdg.h
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
#ifndef __ARCH_ARM_SRC_COMMON_AMEBA_AMEBA_WDG_H
#define __ARCH_ARM_SRC_COMMON_AMEBA_AMEBA_WDG_H
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
#ifdef __cplusplus
#define EXTERN extern "C"
extern "C"
{
#else
#define EXTERN extern
#endif
/****************************************************************************
* Name: ameba_wdg_initialize
*
* Description:
* Instantiate the Ameba watchdog lower half and bind it to the NuttX
* watchdog character driver at CONFIG_WATCHDOG_DEVPATH ("/dev/watchdog0"
* by default). General usage:
*
* #include "ameba_wdg.h"
* ameba_wdg_initialize();
*
* The watchdog is registered in the stopped state (nothing counts until
* the application issues WDIOC_SETTIMEOUT + WDIOC_START).
*
* Returned Value:
* Zero (OK) on success; a negated errno value on failure.
*
****************************************************************************/
int ameba_wdg_initialize(void);
#undef EXTERN
#ifdef __cplusplus
}
#endif
#endif /* __ARCH_ARM_SRC_COMMON_AMEBA_AMEBA_WDG_H */

View file

@ -68,6 +68,10 @@ if(CONFIG_AMEBA_RTC)
list(APPEND SRCS ${AMEBA_COMMON}/ameba_rtc.c)
endif()
if(CONFIG_AMEBA_WDG)
list(APPEND SRCS ${AMEBA_COMMON}/ameba_wdg.c)
endif()
target_include_directories(arch PRIVATE ${AMEBA_COMMON})
target_sources(arch PRIVATE ${SRCS})

View file

@ -78,6 +78,10 @@ ifeq ($(CONFIG_AMEBA_RTC),y)
CHIP_CSRCS += ameba_rtc.c
endif
ifeq ($(CONFIG_AMEBA_WDG),y)
CHIP_CSRCS += ameba_wdg.c
endif
############################################################################
# Realtek RTL8721Dx SDK integration
#

View file

@ -0,0 +1,77 @@
/****************************************************************************
* arch/arm/src/rtl8721dx/ameba_wdg_chip.h
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
#ifndef __ARCH_ARM_SRC_RTL8721DX_AMEBA_WDG_CHIP_H
#define __ARCH_ARM_SRC_RTL8721DX_AMEBA_WDG_CHIP_H
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <nuttx/irq.h>
#include <stdint.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* Per-chip watchdog wiring for RTL8721DX (amebadplus). The shared driver
* (arch/arm/src/common/ameba/ameba_wdg.c) includes this header to learn
* which watchdog instance to drive and its interrupt line. A port to
* another Ameba chip supplies a same-named header on the chip include path;
* the shared driver is never edited -- it reads only the two macros below.
*
* The Ameba SoCs carry several watchdog instances (an always-on IWDG plus
* one "system" WDG per CPU, each with a secure and a non-secure alias).
* This NuttX port runs on the KM4 core, and -- matching the vendor HAL
* wdt_api.c, which selects KM4_NS_WDG_DEV / KM4_NS_WDG_IRQ for
* CONFIG_ARM_CORE_CM4 -- we drive the KM4 non-secure system watchdog. As
* with the I2C/SPI drivers the non-secure register alias (0x41xxxxxx) is the
* one actually reachable from this core, so that is the base used here.
*
* BOTH the base address and the interrupt vector are chip-specific. The WDG
* register block, structures, magic keys and the ms-based timeout are the
* same on every current Ameba chip, so they live in the shared driver; only
* the two values below move per chip (verified against each SoC's
* hal_platform.h and ameba_vector_table.h):
*
* chip KM4/CPU non-secure system WDG base NuttX IRQ
* ----------- ----------------------------------- ---------------------
* amebadplus WDG2_REG_BASE 0x41008D80 KM4_NS_WDG_IRQ = 65
* amebalite WDG2_REG_BASE 0x4101F040 (see its vector table)
* amebasmart WDG2_REG_BASE 0x41000440 (see its vector table)
* amebagreen2 WDG2_REG_BASE 0x4080AD80 CPU0_NS_WDG_IRQ = 69
* RTL8720F WDG2_REG_BASE 0x40801D80 KM4NS_WDG_IRQ = 49
*
* A new chip only edits this header: AMEBA_WDG_BASE is the register base of
* its non-secure system WDG (cast to the fwlib WDG_TypeDef * by the shared
* driver) and AMEBA_WDG_IRQ carries the NuttX IRQ number of that WDG's
* early-interrupt line -- see the ADC/RTC chip headers for the same
* data-driven, never-computed pattern.
*/
#define AMEBA_WDG_BASE 0x41008d80ul
#define AMEBA_WDG_IRQ RTL8721DX_IRQ_KM4_NS_WDG
#endif /* __ARCH_ARM_SRC_RTL8721DX_AMEBA_WDG_CHIP_H */

View file

@ -0,0 +1,47 @@
#
# 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_AMEBA_WDG=y
CONFIG_ARCH="arm"
CONFIG_ARCH_BOARD="pke8721daf"
CONFIG_ARCH_BOARD_PKE8721DAF=y
CONFIG_ARCH_CHIP="rtl8721dx"
CONFIG_ARCH_CHIP_RTL8721DX=y
CONFIG_ARCH_INTERRUPTSTACK=2048
CONFIG_ARCH_STACKDUMP=y
CONFIG_ARMV8M_SYSTICK=y
CONFIG_BUILTIN=y
CONFIG_DEBUG_ASSERTIONS=y
CONFIG_DEBUG_FEATURES=y
CONFIG_DEBUG_FULLOPT=y
CONFIG_DEBUG_SYMBOLS=y
CONFIG_DEFAULT_TASK_STACKSIZE=4096
CONFIG_EXAMPLES_HELLO=y
CONFIG_EXAMPLES_WATCHDOG=y
CONFIG_FS_PROCFS=y
CONFIG_FS_TMPFS=y
CONFIG_IDLETHREAD_STACKSIZE=4096
CONFIG_INIT_ENTRYPOINT="nsh_main"
CONFIG_LIBC_MEMFD_ERROR=y
CONFIG_MM_DEFAULT_ALIGNMENT=32
CONFIG_NSH_BUILTIN_APPS=y
CONFIG_NSH_FILEIOSIZE=512
CONFIG_NSH_READLINE=y
CONFIG_PREALLOC_TIMERS=4
CONFIG_RAM_SIZE=294912
CONFIG_RAM_START=0x20020000
CONFIG_RR_INTERVAL=200
CONFIG_RTL8721DX_FLASH_FS=y
CONFIG_SCHED_HPWORK=y
CONFIG_SCHED_HPWORKPRIORITY=192
CONFIG_SCHED_LPWORK=y
CONFIG_STACK_COLORATION=y
CONFIG_SYSTEM_NSH=y
CONFIG_SYSTEM_NSH_STACKSIZE=2500
CONFIG_TIMER=y
CONFIG_TIMER_ARCH=y
CONFIG_USEC_PER_TICK=1000

View file

@ -50,6 +50,10 @@ if(CONFIG_AMEBA_RTC)
list(APPEND SRCS rtl8721dx_rtc.c)
endif()
if(CONFIG_AMEBA_WDG)
list(APPEND SRCS rtl8721dx_wdg.c)
endif()
target_sources(board PRIVATE ${SRCS})
if(CONFIG_AMEBA_GPIO
@ -58,7 +62,8 @@ if(CONFIG_AMEBA_GPIO
OR CONFIG_AMEBA_SPI
OR CONFIG_AMEBA_PWM
OR CONFIG_AMEBA_ADC
OR CONFIG_AMEBA_RTC)
OR CONFIG_AMEBA_RTC
OR CONFIG_AMEBA_WDG)
# The board pin/UART tables pull in the shared driver's public headers from
# arch/arm/src/common/ameba/, not on the default board include path.
target_include_directories(board

View file

@ -87,4 +87,13 @@ CSRCS += rtl8721dx_rtc.c
CFLAGS += ${INCDIR_PREFIX}$(TOPDIR)$(DELIM)arch$(DELIM)arm$(DELIM)src$(DELIM)common$(DELIM)ameba
endif
ifeq ($(CONFIG_AMEBA_WDG),y)
CSRCS += rtl8721dx_wdg.c
# The board WDG bring-up pulls in the shared driver's public header from
# arch/arm/src/common/ameba/, which is not on the default board include path.
CFLAGS += ${INCDIR_PREFIX}$(TOPDIR)$(DELIM)arch$(DELIM)arm$(DELIM)src$(DELIM)common$(DELIM)ameba
endif
include $(TOPDIR)/boards/Board.mk

View file

@ -178,6 +178,16 @@ int rtl8721dx_bringup(void)
}
#endif
#ifdef CONFIG_AMEBA_WDG
/* Register the board's watchdog at /dev/watchdog0. */
ret = rtl8721dx_wdg_initialize();
if (ret < 0)
{
syslog(LOG_ERR, "ERROR: rtl8721dx_wdg_initialize failed: %d\n", ret);
}
#endif
/* Install the inter-core HW IPC-semaphore RTOS hooks LAST -- after all the
* flash / WHC bring-up above, and just before this (board_late_initialize)
* path returns and nx_start() hands off to the init task.

View file

@ -160,6 +160,19 @@ int rtl8721dx_adc_initialize(void);
int rtl8721dx_rtc_initialize(void);
#endif
#ifdef CONFIG_AMEBA_WDG
/****************************************************************************
* Name: rtl8721dx_wdg_initialize
*
* Description:
* Register the board's watchdog at /dev/watchdog0
* (boards/arm/rtl8721dx/pke8721daf/src/rtl8721dx_wdg.c).
*
****************************************************************************/
int rtl8721dx_wdg_initialize(void);
#endif
#ifdef CONFIG_RTL8721DX_FLASH_FS
/****************************************************************************
* Name: ameba_flash_fs_initialize

View file

@ -0,0 +1,67 @@
/****************************************************************************
* boards/arm/rtl8721dx/pke8721daf/src/rtl8721dx_wdg.c
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <syslog.h>
#include <errno.h>
#include "ameba_wdg.h"
#include "rtl8721dx_pke8721daf.h"
#ifdef CONFIG_AMEBA_WDG
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: rtl8721dx_wdg_initialize
*
* Description:
* Register the on-chip watchdog at /dev/watchdog0. The WDG has no board
* wiring (it is an internal timer), so this simply defers to the shared
* driver.
*
****************************************************************************/
int rtl8721dx_wdg_initialize(void)
{
int ret;
ret = ameba_wdg_initialize();
if (ret < 0)
{
syslog(LOG_ERR,
"ERROR: ameba_wdg_initialize(/dev/watchdog0) failed: %d\n",
ret);
return ret;
}
return OK;
}
#endif /* CONFIG_AMEBA_WDG */

View file

@ -299,6 +299,7 @@ static const char *g_white_prefix[] =
"SYSTIMER_",
"SYS_PLL_", /* SYS_PLL_ClkGet — RTL8720F SPI ip_clk query */
"UART_",
"WDG_", /* WDG_Init, WDG_Refresh, WDG_INTConfig, etc. */
"SystemCoreClock", /* SystemCoreClock, SystemCoreClockUpdate */
"cmse_", /* ARM CMSE TrustZone intrinsics (arm_cmse.h) */
"MQTTErrors", /* apps/tools/netutils/mqttc/MQTT-C/include/mqtt.h */