arch/arm/rp23xx: fix watchdog, enable TICK blocks

On the RP2350, the watchdog receives its tick input from the
system-level ticks block, unlike the RP2040, where the watchdog includes
its own tick generator. Enable the TICK blocks, update the watchdog
routines.

Signed-off-by: Serg Podtynnyi <serg@podtynnyi.com>
This commit is contained in:
Serg Podtynnyi 2025-05-02 12:57:20 +07:00 committed by Xiang Xiao
parent 28abfb5fd1
commit 95cc862794
5 changed files with 188 additions and 85 deletions

View file

@ -75,4 +75,6 @@
#define RP23XX_PSM_OTP (1 << 1)
#define RP23XX_PSM_PROC_COLD (1 << 0)
#define RP23XX_PSM_WDSEL_BITS 0x01ffffff
#endif /* __ARCH_ARM_SRC_RP23XX_HARDWARE_RP23XX_PSM_H */

View file

@ -0,0 +1,92 @@
/****************************************************************************
* arch/arm/src/rp23xx/hardware/rp23xx_ticks.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_RP23XX_HARDWARE_RP23XX_TICKS_H
#define __ARCH_ARM_SRC_RP23XX_HARDWARE_RP23XX_TICKS_H
/****************************************************************************
* Included Files
****************************************************************************/
#include "hardware/rp23xx_memorymap.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* Register offsets *********************************************************/
#define RP23XX_TICKS_PROC0_CTRL_OFFSET 0x00000000
#define RP23XX_TICKS_PROC0_CYCLES_OFFSET 0x00000004
#define RP23XX_TICKS_PROC0_COUNT_OFFSET 0x00000008
#define RP23XX_TICKS_PROC1_CTRL_OFFSET 0x0000000c
#define RP23XX_TICKS_PROC1_CYCLES_OFFSET 0x00000010
#define RP23XX_TICKS_PROC1_COUNT_OFFSET 0x00000014
#define RP23XX_TICKS_TIMER0_CTRL_OFFSET 0x00000018
#define RP23XX_TICKS_TIMER0_CYCLES_OFFSET 0x0000001c
#define RP23XX_TICKS_TIMER0_COUNT_OFFSET 0x00000020
#define RP23XX_TICKS_TIMER1_CTRL_OFFSET 0x00000024
#define RP23XX_TICKS_TIMER1_CYCLES_OFFSET 0x00000028
#define RP23XX_TICKS_TIMER1_COUNT_OFFSET 0x0000002c
#define RP23XX_TICKS_WATCHDOG_CTRL_OFFSET 0x00000030
#define RP23XX_TICKS_WATCHDOG_CYCLES_OFFSET 0x00000034
#define RP23XX_TICKS_WATCHDOG_COUNT_OFFSET 0x00000038
#define RP23XX_TICKS_CTRL_OFFSET(n) ((n) * 12 + RP23XX_TICKS_PROC0_CTRL_OFFSET)
#define RP23XX_TICKS_CYCLES_OFFSET(n) ((n) * 12 + RP23XX_TICKS_PROC0_CYCLES_OFFSET)
#define RP23XX_TICKS_COUNT_OFFSET(n) ((n) * 12 + RP23XX_TICKS_PROC0_COUNT_OFFSET)
/* Register definitions *****************************************************/
#define RP23XX_TICKS_CTRL(n) (RP23XX_TICKS_BASE + RP23XX_TICKS_CTRL_OFFSET(n))
#define RP23XX_TICKS_CYCLES(n) (RP23XX_TICKS_BASE + RP23XX_TICKS_CYCLES_OFFSET(n))
#define RP23XX_TICKS_COUNT(n) (RP23XX_TICKS_BASE + RP23XX_TICKS_COUNT_OFFSET(n))
#define RP23XX_TICKS_PROC0_CTRL (RP23XX_TICKS_BASE + RP23XX_TICKS_PROC0_CTRL_OFFSET)
#define RP23XX_TICKS_PROC0_CYCLES (RP23XX_TICKS_BASE + RP23XX_TICKS_PROC0_CYCLES_OFFSET)
#define RP23XX_TICKS_PROC0_COUNT (RP23XX_TICKS_BASE + RP23XX_TICKS_PROC0_COUNT_OFFSET)
#define RP23XX_TICKS_PROC1_CTRL (RP23XX_TICKS_BASE + RP23XX_TICKS_PROC1_CTRL_OFFSET)
#define RP23XX_TICKS_PROC1_CYCLES (RP23XX_TICKS_BASE + RP23XX_TICKS_PROC1_CYCLES_OFFSET)
#define RP23XX_TICKS_PROC1_COUNT (RP23XX_TICKS_BASE + RP23XX_TICKS_PROC1_COUNT_OFFSET)
#define RP23XX_TICKS_TIMER0_CTRL (RP23XX_TICKS_BASE + RP23XX_TICKS_TIMER0_CTRL_OFFSET)
#define RP23XX_TICKS_TIMER0_CYCLES (RP23XX_TICKS_BASE + RP23XX_TICKS_TIMER0_CYCLES_OFFSET)
#define RP23XX_TICKS_TIMER0_COUNT (RP23XX_TICKS_BASE + RP23XX_TICKS_TIMER0_COUNT_OFFSET)
#define RP23XX_TICKS_TIMER1_CTRL (RP23XX_TICKS_BASE + RP23XX_TICKS_TIMER1_CTRL_OFFSET)
#define RP23XX_TICKS_TIMER1_CYCLES (RP23XX_TICKS_BASE + RP23XX_TICKS_TIMER1_CYCLES_OFFSET)
#define RP23XX_TICKS_TIMER1_COUNT (RP23XX_TICKS_BASE + RP23XX_TICKS_TIMER1_COUNT_OFFSET)
#define RP23XX_TICKS_WATCHDOG_CTRL (RP23XX_TICKS_BASE + RP23XX_TICKS_WATCHDOG_CTRL_OFFSET)
#define RP23XX_TICKS_WATCHDOG_CYCLES (RP23XX_TICKS_BASE + RP23XX_TICKS_WATCHDOG_CYCLES_OFFSET)
#define RP23XX_TICKS_WATCHDOG_COUNT (RP23XX_TICKS_BASE + RP23XX_TICKS_WATCHDOG_COUNT_OFFSET)
/* Register bit definitions *************************************************/
#define RP23XX_TICKS_WATCHDOG_CTRL_EN (1 << 0)
#endif /* __ARCH_ARM_SRC_RP23XX_HARDWARE_RP23XX_TICKS_H */

View file

@ -55,7 +55,7 @@
#include "rp23xx_pll.h"
#include "hardware/rp23xx_clocks.h"
#include "hardware/rp23xx_resets.h"
#include "hardware/rp23xx_watchdog.h"
#include "hardware/rp23xx_ticks.h"
/****************************************************************************
* Pre-processor Definitions
@ -71,6 +71,12 @@ static uint32_t rp23xx_clock_freq[RP23XX_CLOCKS_NDX_MAX];
* Private Functions
****************************************************************************/
static void tick_start(int tick, int cycles)
{
putreg32(cycles, RP23XX_TICKS_CYCLES(tick));
putreg32(RP23XX_TICKS_WATCHDOG_CTRL_EN, RP23XX_TICKS_CTRL(tick));
}
static inline bool has_glitchless_mux(int clk_index)
{
return clk_index == RP23XX_CLOCKS_NDX_SYS ||
@ -202,11 +208,6 @@ bool rp23xx_clock_configure(int clk_index,
void clocks_init(void)
{
/* Start tick in watchdog */
putreg32((BOARD_REF_FREQ / MHZ) | RP23XX_WATCHDOG_CTRL_ENABLE,
RP23XX_WATCHDOG_CTRL);
/* Disable resus that may be enabled from previous software */
putreg32(0, RP23XX_CLOCKS_CLK_SYS_RESUS_CTRL);
@ -452,6 +453,13 @@ void rp23xx_clockconfig(void)
clocks_init();
/* Configure all TICK blocks */
for (int i = 0; i < (int)RP23XX_TICK_NUM; ++i)
{
tick_start(i, (BOARD_REF_FREQ / MHZ));
}
/* Peripheral clocks should now all be running */
clrbits_reg32(RP23XX_RESETS_RESET_MASK, RP23XX_RESETS_RESET);

View file

@ -33,6 +33,8 @@
* Pre-processor Definitions
****************************************************************************/
#define RP23XX_TICK_NUM 6 /* Number of TICK blocks */
/****************************************************************************
* Public Types
****************************************************************************/

View file

@ -35,6 +35,7 @@
#include <arch/chip/watchdog.h>
#include <hardware/rp23xx_ticks.h>
#include <hardware/rp23xx_watchdog.h>
#include <hardware/rp23xx_psm.h>
@ -48,33 +49,13 @@
* Pre-processor Definitions
****************************************************************************/
#define WD_RESETS_BITS (RP23XX_PSM_RESETS \
| RP23XX_PSM_CLOCKS \
| RP23XX_PSM_PSM_READY \
| RP23XX_PSM_BUSFABRIC \
| RP23XX_PSM_ROM \
| RP23XX_PSM_BOOTRAM \
| RP23XX_PSM_SRAM0 \
| RP23XX_PSM_SRAM1 \
| RP23XX_PSM_SRAM2 \
| RP23XX_PSM_SRAM3 \
| RP23XX_PSM_SRAM4 \
| RP23XX_PSM_SRAM5 \
| RP23XX_PSM_SRAM6 \
| RP23XX_PSM_SRAM7 \
| RP23XX_PSM_SRAM8 \
| RP23XX_PSM_SRAM9 \
| RP23XX_PSM_XIP \
| RP23XX_PSM_SIO \
| RP23XX_PSM_ACCESSCTRL \
| RP23XX_PSM_PROC0 \
| RP23XX_PSM_PROC1)
#define WD_ENABLE_BITS (RP23XX_WATCHDOG_CTRL_ENABLE \
| RP23XX_WATCHDOG_CTRL_PAUSE_DBG0 \
| RP23XX_WATCHDOG_CTRL_PAUSE_DBG1 \
| RP23XX_WATCHDOG_CTRL_PAUSE_JTAG)
#define WDT_MAX_TIMEOUT (0xffffff) /* 16777215 ~ 16 sec */
/****************************************************************************
* Private Types
****************************************************************************/
@ -100,14 +81,14 @@ typedef struct rp23xx_watchdog_lowerhalf_s
/* "Lower half" driver methods **********************************************/
static int my_wdt_start (struct watchdog_lowerhalf_s *lower);
static int my_wdt_stop (struct watchdog_lowerhalf_s *lower);
static int my_wdt_keepalive (struct watchdog_lowerhalf_s *lower);
static int my_wdt_getstatus (struct watchdog_lowerhalf_s *lower,
static int rp23xx_wdt_start (struct watchdog_lowerhalf_s *lower);
static int rp23xx_wdt_stop (struct watchdog_lowerhalf_s *lower);
static int rp23xx_wdt_keepalive (struct watchdog_lowerhalf_s *lower);
static int rp23xx_wdt_getstatus (struct watchdog_lowerhalf_s *lower,
struct watchdog_status_s *status);
static int my_wdt_settimeout (struct watchdog_lowerhalf_s *lower,
static int rp23xx_wdt_settimeout (struct watchdog_lowerhalf_s *lower,
uint32_t timeout);
static int my_wdt_ioctl (struct watchdog_lowerhalf_s *lower,
static int rp23xx_wdt_ioctl (struct watchdog_lowerhalf_s *lower,
int cmd,
unsigned long arg);
@ -119,13 +100,13 @@ static int my_wdt_ioctl (struct watchdog_lowerhalf_s *lower,
static const struct watchdog_ops_s g_rp23xx_wdg_ops =
{
.start = my_wdt_start,
.stop = my_wdt_stop,
.keepalive = my_wdt_keepalive,
.getstatus = my_wdt_getstatus,
.settimeout = my_wdt_settimeout,
.start = rp23xx_wdt_start,
.stop = rp23xx_wdt_stop,
.keepalive = rp23xx_wdt_keepalive,
.getstatus = rp23xx_wdt_getstatus,
.settimeout = rp23xx_wdt_settimeout,
.capture = NULL,
.ioctl = my_wdt_ioctl,
.ioctl = rp23xx_wdt_ioctl,
};
static watchdog_lowerhalf_t g_rp23xx_watchdog_lowerhalf =
@ -138,105 +119,122 @@ static watchdog_lowerhalf_t g_rp23xx_watchdog_lowerhalf =
****************************************************************************/
/****************************************************************************
* Name: my_wdt_start
* Name: rp23xx_wdt_start
****************************************************************************/
int my_wdt_start(struct watchdog_lowerhalf_s *lower)
int rp23xx_wdt_start(struct watchdog_lowerhalf_s *lower)
{
watchdog_lowerhalf_t *priv = (watchdog_lowerhalf_t *)lower;
/* Convert millisecond input to microseconds
* Extra times 2 per errata RP23XX-E1
*/
wdinfo("Entry\n");
putreg32(priv->timeout * 2000, RP23XX_WATCHDOG_LOAD);
if (priv->started == true)
{
/* Return EBUSY to indicate that the timer was already running */
return -EBUSY;
}
putreg32(priv->timeout * USEC_PER_MSEC, RP23XX_WATCHDOG_LOAD);
putreg32(RP23XX_PSM_WDSEL_BITS & ~(RP23XX_PSM_XOSC | RP23XX_PSM_ROSC),
RP23XX_PSM_WDSEL);
modreg32(WD_ENABLE_BITS, WD_ENABLE_BITS, RP23XX_WATCHDOG_CTRL);
modreg32(WD_RESETS_BITS, WD_RESETS_BITS, RP23XX_PSM_WDSEL);
priv->started = true;
return OK;
}
/****************************************************************************
* Name: my_wdt_stop
* Name: rp23xx_wdt_stop
****************************************************************************/
int my_wdt_stop(struct watchdog_lowerhalf_s *lower)
{
modreg32(0, RP23XX_WATCHDOG_CTRL_ENABLE, RP23XX_WATCHDOG_CTRL);
return OK;
}
/****************************************************************************
* Name: my_wdt_keepalive
****************************************************************************/
int my_wdt_keepalive(struct watchdog_lowerhalf_s *lower)
int rp23xx_wdt_stop(struct watchdog_lowerhalf_s *lower)
{
watchdog_lowerhalf_t *priv = (watchdog_lowerhalf_t *)lower;
/* Convert millisecond input to microseconds
* Extra times 2 per errata RP23XX-E1
*/
wdinfo("Entry\n");
putreg32(priv->timeout * 2000, RP23XX_WATCHDOG_LOAD);
modreg32(0, RP23XX_WATCHDOG_CTRL_ENABLE, RP23XX_WATCHDOG_CTRL);
priv->started = false;
return OK;
}
/****************************************************************************
* Name: rp23xx_wdt_keepalive
****************************************************************************/
int rp23xx_wdt_keepalive(struct watchdog_lowerhalf_s *lower)
{
watchdog_lowerhalf_t *priv = (watchdog_lowerhalf_t *)lower;
wdinfo("Entry\n");
putreg32(priv->timeout * USEC_PER_MSEC, RP23XX_WATCHDOG_LOAD);
return OK;
}
/****************************************************************************
* Name: my_wdt_getstatus
* Name: rp23xx_wdt_getstatus
****************************************************************************/
int my_wdt_getstatus(struct watchdog_lowerhalf_s *lower,
int rp23xx_wdt_getstatus(struct watchdog_lowerhalf_s *lower,
struct watchdog_status_s *status)
{
watchdog_lowerhalf_t *priv = (watchdog_lowerhalf_t *)lower;
uint32_t ctrl = getreg32(RP23XX_WATCHDOG_CTRL);
wdinfo("Entry\n");
status->flags = (ctrl & RP23XX_WATCHDOG_CTRL_ENABLE) ? WDFLAGS_ACTIVE
: 0;
status->timeout = priv->timeout;
/* Convert microseconds to output microseconds.
* Extra divide by 2 per errata RP23XX-E1.
*/
status->timeleft = (ctrl & RP23XX_WATCHDOG_CTRL_TIME_MASK) / 2000;
/* WARNING: On (at least) version 2 RP23XX chips, the timeleft does
* not seem to be reliable.
*/
status->timeleft = (ctrl & RP23XX_WATCHDOG_CTRL_TIME_MASK) /
USEC_PER_MSEC;
wdinfo("Status :\n");
wdinfo(" flags : %08" PRIx32 "\n", status->flags);
wdinfo(" timeout : %" PRId32 "\n", status->timeout);
wdinfo(" timeleft : %" PRId32 "\n", status->timeleft);
return OK;
}
/****************************************************************************
* Name: my_wdt_settimeout
* Name: rp23xx_wdt_settimeout
****************************************************************************/
int my_wdt_settimeout (struct watchdog_lowerhalf_s *lower, uint32_t timeout)
int rp23xx_wdt_settimeout (struct watchdog_lowerhalf_s *lower,
uint32_t timeout)
{
watchdog_lowerhalf_t *priv = (watchdog_lowerhalf_t *)lower;
priv->timeout = timeout > (0x7fffff / 1000) ? 0x7fffff : timeout;
wdinfo("Entry: timeout=%" PRId32 "\n", timeout);
/* Convert millisecond input to microseconds
* Extra times 2 per errata RP23XX-E1
if ((timeout == 0) || (timeout > (WDT_MAX_TIMEOUT / USEC_PER_MSEC)))
{
return -EINVAL;
}
/* Load the watchdog timer. The maximum setting is 0xffffff which
* corresponds to approximately 16 seconds
*/
putreg32(priv->timeout * 2000, RP23XX_WATCHDOG_LOAD);
priv->timeout = timeout;
putreg32(priv->timeout * USEC_PER_MSEC, RP23XX_WATCHDOG_LOAD);
return OK;
}
/****************************************************************************
* Name: my_wdt_ioctl
* Name: rp23xx_wdt_ioctl
****************************************************************************/
int my_wdt_ioctl(struct watchdog_lowerhalf_s *lower,
int rp23xx_wdt_ioctl(struct watchdog_lowerhalf_s *lower,
int cmd,
unsigned long arg)
{
@ -282,6 +280,7 @@ int rp23xx_wdt_init(void)
goto errout;
}
putreg32(WDT_MAX_TIMEOUT, RP23XX_WATCHDOG_LOAD);
modreg32(0, RP23XX_WATCHDOG_CTRL_ENABLE, RP23XX_WATCHDOG_CTRL);
errout: