mirror of
https://github.com/apache/nuttx.git
synced 2026-10-02 19:58:01 +00:00
arm/nrf54l: add GRTC and tickless scheduling
arm/nrf54l: add GRTC and tickless scheduling Assisted-by: Codex:GPT-6 Signed-off-by: raiden00pl <raiden00@railab.me>
This commit is contained in:
parent
04d2c9013c
commit
0942bae6ef
10 changed files with 1321 additions and 4 deletions
|
|
@ -4,7 +4,7 @@ Nordic nRF54L
|
|||
|
||||
The nRF54L series from Nordic Semiconductor is based on an ARM Cortex-M33
|
||||
application core. NuttX supports nRF54L15 and nRF54LM20A/B as standalone
|
||||
secure images, with a 128 MHz CPU clock and SysTick scheduling.
|
||||
secure images, with a 128 MHz CPU clock and SysTick or GRTC scheduling.
|
||||
|
||||
Peripheral Support
|
||||
==================
|
||||
|
|
@ -16,7 +16,7 @@ Peripheral Support Notes
|
|||
========== ======= =====================================
|
||||
GPIO Yes
|
||||
GPIOTE No
|
||||
GRTC No
|
||||
GRTC Yes Counter and tickless scheduling
|
||||
PWM No
|
||||
QDEC No
|
||||
RADIO No
|
||||
|
|
@ -35,6 +35,15 @@ GPIO
|
|||
|
||||
Pins can be configured and operated using ``nrf54l_gpio_*`` functions.
|
||||
|
||||
GRTC
|
||||
----
|
||||
|
||||
``nrf54l_grtc_init(0)`` provides access to the 52-bit, 1 MHz system counter
|
||||
and twelve compare channels. ``CONFIG_NRF54L_SYSTIMER_GRTC`` reserves the
|
||||
instance and compare channel zero for tickless scheduling. The GRTC is timed
|
||||
by LFCLK, so the LFCLK source selected with ``CONFIG_NRF54L_USE_LFCLK``
|
||||
determines the long-term accuracy of the system time.
|
||||
|
||||
TIMER
|
||||
-----
|
||||
|
||||
|
|
@ -59,6 +68,7 @@ being transmitted or DMA error recovery is in progress.
|
|||
Power Management
|
||||
================
|
||||
|
||||
With SysTick selected, the CPU remains awake so its clock keeps running.
|
||||
The idle loop uses ``WFI`` when GRTC provides tickless scheduling. With
|
||||
SysTick selected, the CPU remains awake so its clock keeps running.
|
||||
``CONFIG_PM`` initializes the NuttX power management framework. System OFF
|
||||
is not supported.
|
||||
|
|
|
|||
|
|
@ -33,6 +33,12 @@ set(SRCS
|
|||
if(CONFIG_NRF54L_SYSTIMER_SYSTICK)
|
||||
list(APPEND SRCS nrf54l_systick.c)
|
||||
endif()
|
||||
if(CONFIG_NRF54L_GRTC)
|
||||
list(APPEND SRCS nrf54l_grtc.c)
|
||||
endif()
|
||||
if(CONFIG_NRF54L_SYSTIMER_GRTC)
|
||||
list(APPEND SRCS nrf54l_tickless_grtc.c)
|
||||
endif()
|
||||
if(CONFIG_NRF54L_UART)
|
||||
list(APPEND SRCS nrf54l_serial.c)
|
||||
endif()
|
||||
|
|
|
|||
|
|
@ -135,8 +135,37 @@ config NRF54L_TIMER6
|
|||
select NRF54L_TIMER
|
||||
default n
|
||||
|
||||
config NRF54L_GRTC
|
||||
bool "GRTC"
|
||||
default n
|
||||
|
||||
endmenu # nRF54L Peripheral Selection
|
||||
|
||||
config NRF54L_USE_LFCLK
|
||||
bool "Enable LFCLK"
|
||||
default n
|
||||
---help---
|
||||
Enable low-frequency clock.
|
||||
|
||||
if NRF54L_USE_LFCLK
|
||||
|
||||
choice
|
||||
prompt "LFCLK source"
|
||||
default NRF54L_LFCLK_XTAL
|
||||
|
||||
config NRF54L_LFCLK_XTAL
|
||||
bool "External 32.768Khz crystal"
|
||||
|
||||
config NRF54L_LFCLK_RC
|
||||
bool "Internal RC oscillator"
|
||||
|
||||
config NRF54L_LFCLK_SYNTH
|
||||
bool "Synthesized from HFCLK"
|
||||
|
||||
endchoice # LFCLK source
|
||||
|
||||
endif # NRF54L_USE_LFCLK
|
||||
|
||||
menu "System Timer"
|
||||
|
||||
choice
|
||||
|
|
@ -149,6 +178,16 @@ config NRF54L_SYSTIMER_SYSTICK
|
|||
select TIMER_ARCH
|
||||
select ARMV8M_SYSTICK
|
||||
|
||||
config NRF54L_SYSTIMER_GRTC
|
||||
bool "GRTC"
|
||||
select NRF54L_GRTC
|
||||
select ARCH_HAVE_TICKLESS
|
||||
select SCHED_TICKLESS
|
||||
select SCHED_TICKLESS_ALARM
|
||||
select NRF54L_USE_LFCLK
|
||||
---help---
|
||||
Use GRTC timer in tickless mode.
|
||||
|
||||
endchoice # System Timer Source
|
||||
|
||||
endmenu # System Timer
|
||||
|
|
|
|||
|
|
@ -30,6 +30,14 @@ ifeq ($(CONFIG_NRF54L_SYSTIMER_SYSTICK),y)
|
|||
CHIP_CSRCS += nrf54l_systick.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_NRF54L_GRTC),y)
|
||||
CHIP_CSRCS += nrf54l_grtc.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_NRF54L_SYSTIMER_GRTC),y)
|
||||
CHIP_CSRCS += nrf54l_tickless_grtc.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_NRF54L_UART),y)
|
||||
CHIP_CSRCS += nrf54l_serial.c
|
||||
endif
|
||||
|
|
|
|||
181
arch/arm/src/nrf54l/hardware/nrf54l_grtc.h
Normal file
181
arch/arm/src/nrf54l/hardware/nrf54l_grtc.h
Normal file
|
|
@ -0,0 +1,181 @@
|
|||
/****************************************************************************
|
||||
* arch/arm/src/nrf54l/hardware/nrf54l_grtc.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_NRF54L_HARDWARE_NRF54L_GRTC_H
|
||||
#define __ARCH_ARM_SRC_NRF54L_HARDWARE_NRF54L_GRTC_H
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
#include "hardware/nrf54l_memorymap.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/* Register offsets *********************************************************/
|
||||
|
||||
#define NRF54L_GRTC_TASKS_CAPTURE_OFFSET(n) (0x0000 + 4 * (n)) /* Capture counter */
|
||||
#define NRF54L_GRTC_TASKS_START_OFFSET 0x0060 /* Start counter */
|
||||
#define NRF54L_GRTC_TASKS_STOP_OFFSET 0x0064 /* Stop counter */
|
||||
#define NRF54L_GRTC_TASKS_CLEAR_OFFSET 0x0068 /* Clear counter */
|
||||
#define NRF54L_GRTC_TASKS_PWMSTART_OFFSET 0x006c /* Start PWM */
|
||||
#define NRF54L_GRTC_TASKS_PWMSTOP_OFFSET 0x0070 /* Stop PWM */
|
||||
#define NRF54L_GRTC_SUBSCRIBE_CAPTURE_OFFSET(n) (0x0080 + 4 * (n)) /* Capture subscription */
|
||||
#define NRF54L_GRTC_EVENTS_COMPARE_OFFSET(n) (0x0100 + 4 * (n)) /* Compare match */
|
||||
#define NRF54L_GRTC_EVENTS_RTCOMPARESYNC_OFFSET 0x0164 /* LF timer synchronized */
|
||||
#define NRF54L_GRTC_EVENTS_PWMPERIODEND_OFFSET 0x016c /* PWM period ended */
|
||||
#define NRF54L_GRTC_EVENTS_PWMREADY_OFFSET 0x0174 /* PWM ready */
|
||||
#define NRF54L_GRTC_EVENTS_CLKOUTREADY_OFFSET 0x0178 /* Clock output ready */
|
||||
#define NRF54L_GRTC_PUBLISH_COMPARE_OFFSET(n) (0x0180 + 4 * (n)) /* Compare publication */
|
||||
#define NRF54L_GRTC_PUBLISH_PWMREADY_OFFSET 0x01f4 /* PWM ready publication */
|
||||
#define NRF54L_GRTC_PUBLISH_CLKOUTREADY_OFFSET 0x01f8 /* Clock ready publication */
|
||||
#define NRF54L_GRTC_SHORTS_OFFSET 0x0200 /* Local shortcuts */
|
||||
#define NRF54L_GRTC_INTEN_OFFSET(n) (0x0300 + 16 * (n)) /* Interrupt enable */
|
||||
#define NRF54L_GRTC_INTENSET_OFFSET(n) (0x0304 + 16 * (n)) /* Enable interrupt */
|
||||
#define NRF54L_GRTC_INTENCLR_OFFSET(n) (0x0308 + 16 * (n)) /* Disable interrupt */
|
||||
#define NRF54L_GRTC_INTPEND_OFFSET(n) (0x030c + 16 * (n)) /* Pending interrupts */
|
||||
#define NRF54L_GRTC_EVTEN_OFFSET 0x0400 /* Event routing */
|
||||
#define NRF54L_GRTC_EVTENSET_OFFSET 0x0404 /* Enable routing */
|
||||
#define NRF54L_GRTC_EVTENCLR_OFFSET 0x0408 /* Disable routing */
|
||||
#define NRF54L_GRTC_MODE_OFFSET 0x0510 /* Counter mode */
|
||||
#define NRF54L_GRTC_CCL_OFFSET(n) (0x0520 + 16 * (n)) /* Compare low word */
|
||||
#define NRF54L_GRTC_CCH_OFFSET(n) (0x0524 + 16 * (n)) /* Compare high word */
|
||||
#define NRF54L_GRTC_CCADD_OFFSET(n) (0x0528 + 16 * (n)) /* Add to compare */
|
||||
#define NRF54L_GRTC_CCEN_OFFSET(n) (0x052c + 16 * (n)) /* Compare enable */
|
||||
#define NRF54L_GRTC_TIMEOUT_OFFSET 0x06a4 /* SYSCOUNTER sleep timeout */
|
||||
#define NRF54L_GRTC_INTERVAL_OFFSET 0x06a8 /* CC0 increment */
|
||||
#define NRF54L_GRTC_WAKETIME_OFFSET 0x06ac /* Wakeup time */
|
||||
#define NRF54L_GRTC_STATUS_LFTIMER_OFFSET 0x06b0 /* LF timer status */
|
||||
#define NRF54L_GRTC_STATUS_PWM_OFFSET 0x06b4 /* PWM status */
|
||||
#define NRF54L_GRTC_STATUS_CLKOUT_OFFSET 0x06b8 /* Clock output status */
|
||||
#define NRF54L_GRTC_PWMCONFIG_OFFSET 0x0710 /* PWM configuration */
|
||||
#define NRF54L_GRTC_CLKOUT_OFFSET 0x0714 /* Clock output configuration */
|
||||
#define NRF54L_GRTC_CLKCFG_OFFSET 0x0718 /* Clock configuration */
|
||||
#define NRF54L_GRTC_SYSCOUNTERL_OFFSET(n) (0x0720 + 16 * (n)) /* Counter low word */
|
||||
#define NRF54L_GRTC_SYSCOUNTERH_OFFSET(n) (0x0724 + 16 * (n)) /* Counter high word */
|
||||
#define NRF54L_GRTC_SYSCOUNTER_ACTIVE_OFFSET(n) (0x0728 + 16 * (n)) /* Keep counter active */
|
||||
|
||||
/* Register bit definitions *************************************************/
|
||||
|
||||
/* Tasks and events */
|
||||
|
||||
#define GRTC_TASKS_CAPTURE (1 << 0)
|
||||
#define GRTC_TASKS_START (1 << 0)
|
||||
#define GRTC_TASKS_STOP (1 << 0)
|
||||
#define GRTC_TASKS_CLEAR (1 << 0)
|
||||
#define GRTC_TASKS_PWMSTART (1 << 0)
|
||||
#define GRTC_TASKS_PWMSTOP (1 << 0)
|
||||
#define GRTC_EVENTS_COMPARE (1 << 0)
|
||||
#define GRTC_EVENTS_RTCOMPARESYNC (1 << 0)
|
||||
#define GRTC_EVENTS_PWMPERIODEND (1 << 0)
|
||||
#define GRTC_EVENTS_PWMREADY (1 << 0)
|
||||
#define GRTC_EVENTS_CLKOUTREADY (1 << 0)
|
||||
|
||||
/* SUBSCRIBE and PUBLISH registers */
|
||||
|
||||
#define GRTC_SUBSCRIBE_CHIDX_SHIFT (0)
|
||||
#define GRTC_SUBSCRIBE_CHIDX_MASK (0xff << GRTC_SUBSCRIBE_CHIDX_SHIFT)
|
||||
#define GRTC_SUBSCRIBE_EN (1 << 31)
|
||||
#define GRTC_PUBLISH_CHIDX_SHIFT (0)
|
||||
#define GRTC_PUBLISH_CHIDX_MASK (0xff << GRTC_PUBLISH_CHIDX_SHIFT)
|
||||
#define GRTC_PUBLISH_EN (1 << 31)
|
||||
|
||||
/* SHORTS register */
|
||||
|
||||
#define GRTC_SHORTS_RTCOMPARE_CLEAR (1 << 0)
|
||||
|
||||
/* INTEN, INTENSET, INTENCLR and INTPEND registers */
|
||||
|
||||
#define GRTC_INT_COMPARE(n) (1 << (n))
|
||||
#define GRTC_INT_RTCOMPARESYNC (1 << 25)
|
||||
#define GRTC_INT_PWMPERIODEND (1 << 27)
|
||||
#define GRTC_INT_PWMREADY (1 << 29)
|
||||
#define GRTC_INT_CLKOUTREADY (1 << 30)
|
||||
|
||||
/* EVTEN, EVTENSET and EVTENCLR registers */
|
||||
|
||||
#define GRTC_EVTEN_PWMPERIODEND (1 << 27)
|
||||
|
||||
/* MODE register */
|
||||
|
||||
#define GRTC_MODE_AUTOEN (1 << 0)
|
||||
#define GRTC_MODE_SYSCOUNTEREN (1 << 1)
|
||||
|
||||
/* CC registers */
|
||||
|
||||
#define GRTC_CCL_MASK (0xffffffff)
|
||||
#define GRTC_CCH_MASK (0x000fffff)
|
||||
#define GRTC_CCADD_VALUE_MASK (0x7fffffff)
|
||||
#define GRTC_CCADD_REFERENCE_CC (1 << 31)
|
||||
#define GRTC_CCEN_ACTIVE (1 << 0)
|
||||
#if defined(CONFIG_ARCH_CHIP_NRF54LM20A) || defined(CONFIG_ARCH_CHIP_NRF54LM20B)
|
||||
# define GRTC_CCEN_PASTCC (1 << 1)
|
||||
#endif
|
||||
|
||||
/* TIMEOUT, INTERVAL and WAKETIME registers */
|
||||
|
||||
#define GRTC_TIMEOUT_MASK (0xffff)
|
||||
#define GRTC_INTERVAL_MASK (0xffff)
|
||||
#define GRTC_WAKETIME_MASK (0xff)
|
||||
|
||||
/* STATUS registers */
|
||||
|
||||
#define GRTC_STATUS_LFTIMER_READY (1 << 0)
|
||||
#define GRTC_STATUS_PWM_READY (1 << 0)
|
||||
#define GRTC_STATUS_CLKOUT_READY (1 << 0)
|
||||
|
||||
/* PWMCONFIG register */
|
||||
|
||||
#define GRTC_PWMCONFIG_PERIOD_MASK (0xff)
|
||||
|
||||
/* CLKOUT register */
|
||||
|
||||
#define GRTC_CLKOUT_CLK32K (1 << 0)
|
||||
#define GRTC_CLKOUT_CLKFAST (1 << 1)
|
||||
|
||||
/* CLKCFG register */
|
||||
|
||||
#define GRTC_CLKCFG_CLKFASTDIV_SHIFT (0)
|
||||
#define GRTC_CLKCFG_CLKFASTDIV_MASK (0xff << GRTC_CLKCFG_CLKFASTDIV_SHIFT)
|
||||
#define GRTC_CLKCFG_CLKFASTDIV(n) ((n) << GRTC_CLKCFG_CLKFASTDIV_SHIFT)
|
||||
#define GRTC_CLKCFG_CLKSEL_SHIFT (16)
|
||||
#define GRTC_CLKCFG_CLKSEL_MASK (3 << GRTC_CLKCFG_CLKSEL_SHIFT)
|
||||
#define GRTC_CLKCFG_CLKSEL_LFXO (0 << GRTC_CLKCFG_CLKSEL_SHIFT)
|
||||
#define GRTC_CLKCFG_CLKSEL_LFCLK (1 << GRTC_CLKCFG_CLKSEL_SHIFT)
|
||||
#define GRTC_CLKCFG_CLKSEL_LFLPRC (2 << GRTC_CLKCFG_CLKSEL_SHIFT)
|
||||
|
||||
/* SYSCOUNTER registers */
|
||||
|
||||
#define GRTC_SYSCOUNTERL_MASK (0xffffffff)
|
||||
#define GRTC_SYSCOUNTERH_MASK (0x000fffff)
|
||||
#if defined(CONFIG_ARCH_CHIP_NRF54LM20A) || defined(CONFIG_ARCH_CHIP_NRF54LM20B)
|
||||
# define GRTC_SYSCOUNTERH_LOADED (1 << 29)
|
||||
#endif
|
||||
#define GRTC_SYSCOUNTERH_BUSY (1 << 30)
|
||||
#define GRTC_SYSCOUNTERH_OVERFLOW (1 << 31)
|
||||
#define GRTC_SYSCOUNTER_ACTIVE (1 << 0)
|
||||
#define GRTC_COUNTER_MAX (0x000fffffffffffffull)
|
||||
|
||||
#endif /* __ARCH_ARM_SRC_NRF54L_HARDWARE_NRF54L_GRTC_H */
|
||||
|
|
@ -156,6 +156,32 @@ void nrf54l_clockconfig(void)
|
|||
PANIC();
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NRF54L_USE_LFCLK
|
||||
/* Initialize LFCLK */
|
||||
|
||||
#if defined(CONFIG_NRF54L_LFCLK_XTAL)
|
||||
putreg32(CLOCK_LFCLK_SRC_SRC_LFXO, NRF54L_CLOCK_LFCLK_SRC);
|
||||
#elif defined(CONFIG_NRF54L_LFCLK_SYNTH)
|
||||
putreg32(CLOCK_LFCLK_SRC_SRC_LFSYNT, NRF54L_CLOCK_LFCLK_SRC);
|
||||
#else
|
||||
putreg32(CLOCK_LFCLK_SRC_SRC_LFRC, NRF54L_CLOCK_LFCLK_SRC);
|
||||
#endif
|
||||
|
||||
/* Trigger LFCLK start */
|
||||
|
||||
putreg32(0x0, NRF54L_CLOCK_EVENTS_LFCLKSTARTED);
|
||||
putreg32(0x1, NRF54L_CLOCK_TASKS_LFCLKSTART);
|
||||
|
||||
while (!getreg32(NRF54L_CLOCK_EVENTS_LFCLKSTARTED))
|
||||
{
|
||||
/* Wait for LFCLK to be running */
|
||||
}
|
||||
|
||||
#if defined(CONFIG_NRF54L_LFCLK_RC)
|
||||
/* TODO: calibrate LFCLK RC oscillator */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_ARCH_CHIP_NRF54L15
|
||||
for (i = 0; i < 10000000 && getreg32(NRF54L_KMU_STATUS) == 1; i++)
|
||||
{
|
||||
|
|
|
|||
618
arch/arm/src/nrf54l/nrf54l_grtc.c
Normal file
618
arch/arm/src/nrf54l/nrf54l_grtc.c
Normal file
|
|
@ -0,0 +1,618 @@
|
|||
/****************************************************************************
|
||||
* arch/arm/src/nrf54l/nrf54l_grtc.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 <assert.h>
|
||||
#include <nuttx/debug.h>
|
||||
|
||||
#include <nuttx/arch.h>
|
||||
#include <nuttx/irq.h>
|
||||
|
||||
#include "arm_internal.h"
|
||||
#include "hardware/nrf54l_grtc.h"
|
||||
|
||||
#include "nrf54l_grtc.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Private Types
|
||||
****************************************************************************/
|
||||
|
||||
struct nrf54l_grtc_priv_s
|
||||
{
|
||||
struct nrf54l_grtc_ops_s *ops;
|
||||
uint32_t base;
|
||||
uint32_t irq;
|
||||
uint8_t chan;
|
||||
bool inuse;
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
/* GRTC registers access ****************************************************/
|
||||
|
||||
static uint32_t nrf54l_grtc_getreg(struct nrf54l_grtc_dev_s *dev,
|
||||
uint32_t offset);
|
||||
static void nrf54l_grtc_putreg(struct nrf54l_grtc_dev_s *dev,
|
||||
uint32_t offset,
|
||||
uint32_t value);
|
||||
|
||||
/* GRTC helpers *************************************************************/
|
||||
|
||||
static uint32_t nrf54l_grtc_irq2reg(struct nrf54l_grtc_dev_s *dev,
|
||||
uint8_t s);
|
||||
static void nrf54l_grtc_waitready(struct nrf54l_grtc_dev_s *dev);
|
||||
|
||||
/* GRTC operations **********************************************************/
|
||||
|
||||
static int nrf54l_grtc_start(struct nrf54l_grtc_dev_s *dev);
|
||||
static int nrf54l_grtc_stop(struct nrf54l_grtc_dev_s *dev);
|
||||
static int nrf54l_grtc_clear(struct nrf54l_grtc_dev_s *dev);
|
||||
static int nrf54l_grtc_getcounter(struct nrf54l_grtc_dev_s *dev,
|
||||
uint64_t *cc);
|
||||
static int nrf54l_grtc_setcc(struct nrf54l_grtc_dev_s *dev, uint8_t i,
|
||||
uint64_t cc);
|
||||
static int nrf54l_grtc_getcc(struct nrf54l_grtc_dev_s *dev, uint8_t i,
|
||||
uint64_t *cc);
|
||||
static int nrf54l_grtc_disablecc(struct nrf54l_grtc_dev_s *dev, uint8_t i);
|
||||
static int nrf54l_grtc_setisr(struct nrf54l_grtc_dev_s *dev, xcpt_t handler,
|
||||
void * arg);
|
||||
static int nrf54l_grtc_enableint(struct nrf54l_grtc_dev_s *dev, uint8_t s);
|
||||
static int nrf54l_grtc_disableint(struct nrf54l_grtc_dev_s *dev, uint8_t s);
|
||||
static int nrf54l_grtc_checkint(struct nrf54l_grtc_dev_s *dev, uint8_t s);
|
||||
static int nrf54l_grtc_ackint(struct nrf54l_grtc_dev_s *dev, uint8_t s);
|
||||
static uint32_t nrf54l_grtc_getbase(struct nrf54l_grtc_dev_s *dev);
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
/* NRF54L GRTC ops */
|
||||
|
||||
struct nrf54l_grtc_ops_s nrf54l_grtc_ops =
|
||||
{
|
||||
.start = nrf54l_grtc_start,
|
||||
.stop = nrf54l_grtc_stop,
|
||||
.clear = nrf54l_grtc_clear,
|
||||
.getcounter = nrf54l_grtc_getcounter,
|
||||
.setcc = nrf54l_grtc_setcc,
|
||||
.getcc = nrf54l_grtc_getcc,
|
||||
.disablecc = nrf54l_grtc_disablecc,
|
||||
.setisr = nrf54l_grtc_setisr,
|
||||
.enableint = nrf54l_grtc_enableint,
|
||||
.disableint = nrf54l_grtc_disableint,
|
||||
.checkint = nrf54l_grtc_checkint,
|
||||
.ackint = nrf54l_grtc_ackint,
|
||||
.getbase = nrf54l_grtc_getbase,
|
||||
};
|
||||
|
||||
/* GRTC */
|
||||
|
||||
struct nrf54l_grtc_priv_s g_nrf54l_grtc_priv =
|
||||
{
|
||||
.ops = &nrf54l_grtc_ops,
|
||||
.base = NRF54L_GRTC_BASE,
|
||||
.irq = NRF54L_IRQ_GRTC_0,
|
||||
.chan = 12,
|
||||
.inuse = false,
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: nrf54l_grtc_getreg
|
||||
*
|
||||
* Description:
|
||||
* Get a 32-bit register value by offset
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static uint32_t nrf54l_grtc_getreg(struct nrf54l_grtc_dev_s *dev,
|
||||
uint32_t offset)
|
||||
{
|
||||
DEBUGASSERT(dev);
|
||||
|
||||
return getreg32(((struct nrf54l_grtc_priv_s *)dev)->base + offset);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: nrf54l_grtc_putreg
|
||||
*
|
||||
* Description:
|
||||
* Put a 32-bit register value by offset
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void nrf54l_grtc_putreg(struct nrf54l_grtc_dev_s *dev,
|
||||
uint32_t offset,
|
||||
uint32_t value)
|
||||
{
|
||||
DEBUGASSERT(dev);
|
||||
|
||||
putreg32(value, ((struct nrf54l_grtc_priv_s *)dev)->base + offset);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: nrf54l_grtc_irq2reg
|
||||
*
|
||||
* Description:
|
||||
* Get the value of the interrupt register corresponding to the given
|
||||
* interrupt source
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static uint32_t nrf54l_grtc_irq2reg(struct nrf54l_grtc_dev_s *dev,
|
||||
uint8_t s)
|
||||
{
|
||||
struct nrf54l_grtc_priv_s *grtc = (struct nrf54l_grtc_priv_s *)dev;
|
||||
uint32_t regval = 0;
|
||||
|
||||
if (s < grtc->chan)
|
||||
{
|
||||
regval = GRTC_INT_COMPARE(s);
|
||||
}
|
||||
else
|
||||
{
|
||||
rtcerr("ERROR: unsupported IRQ source %d\n", s);
|
||||
}
|
||||
|
||||
return regval;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: nrf54l_grtc_waitready
|
||||
*
|
||||
* Description:
|
||||
* Wait until the low-frequency timer has completed the previous task
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void nrf54l_grtc_waitready(struct nrf54l_grtc_dev_s *dev)
|
||||
{
|
||||
while ((nrf54l_grtc_getreg(dev, NRF54L_GRTC_STATUS_LFTIMER_OFFSET) &
|
||||
GRTC_STATUS_LFTIMER_READY) == 0)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: nrf54l_grtc_start
|
||||
****************************************************************************/
|
||||
|
||||
static int nrf54l_grtc_start(struct nrf54l_grtc_dev_s *dev)
|
||||
{
|
||||
uint64_t counter;
|
||||
|
||||
DEBUGASSERT(dev);
|
||||
|
||||
nrf54l_grtc_waitready(dev);
|
||||
nrf54l_grtc_putreg(dev, NRF54L_GRTC_TASKS_START_OFFSET, GRTC_TASKS_START);
|
||||
nrf54l_grtc_putreg(dev, NRF54L_GRTC_MODE_OFFSET, GRTC_MODE_SYSCOUNTEREN);
|
||||
nrf54l_grtc_putreg(dev, NRF54L_GRTC_SYSCOUNTER_ACTIVE_OFFSET(0),
|
||||
GRTC_SYSCOUNTER_ACTIVE);
|
||||
|
||||
/* Reading the low word initiates synchronization of the snapshot */
|
||||
|
||||
nrf54l_grtc_getcounter(dev, &counter);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: nrf54l_grtc_stop
|
||||
****************************************************************************/
|
||||
|
||||
static int nrf54l_grtc_stop(struct nrf54l_grtc_dev_s *dev)
|
||||
{
|
||||
DEBUGASSERT(dev);
|
||||
|
||||
nrf54l_grtc_putreg(dev, NRF54L_GRTC_SYSCOUNTER_ACTIVE_OFFSET(0), 0);
|
||||
nrf54l_grtc_putreg(dev, NRF54L_GRTC_MODE_OFFSET, 0);
|
||||
nrf54l_grtc_waitready(dev);
|
||||
nrf54l_grtc_putreg(dev, NRF54L_GRTC_TASKS_STOP_OFFSET, GRTC_TASKS_STOP);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: nrf54l_grtc_clear
|
||||
****************************************************************************/
|
||||
|
||||
static int nrf54l_grtc_clear(struct nrf54l_grtc_dev_s *dev)
|
||||
{
|
||||
DEBUGASSERT(dev);
|
||||
|
||||
nrf54l_grtc_waitready(dev);
|
||||
nrf54l_grtc_putreg(dev, NRF54L_GRTC_TASKS_CLEAR_OFFSET, GRTC_TASKS_CLEAR);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: nrf54l_grtc_getcounter
|
||||
****************************************************************************/
|
||||
|
||||
static int nrf54l_grtc_getcounter(struct nrf54l_grtc_dev_s *dev,
|
||||
uint64_t *ctr)
|
||||
{
|
||||
irqstate_t flags;
|
||||
uint32_t low;
|
||||
uint32_t high;
|
||||
|
||||
DEBUGASSERT(dev);
|
||||
DEBUGASSERT(ctr);
|
||||
|
||||
/* The low word read snapshots the high word. Retry when synchronization
|
||||
* is busy or the low word rolled over between the reads.
|
||||
*/
|
||||
|
||||
flags = enter_critical_section();
|
||||
|
||||
do
|
||||
{
|
||||
low = nrf54l_grtc_getreg(dev, NRF54L_GRTC_SYSCOUNTERL_OFFSET(0));
|
||||
high = nrf54l_grtc_getreg(dev, NRF54L_GRTC_SYSCOUNTERH_OFFSET(0));
|
||||
}
|
||||
while ((high & (GRTC_SYSCOUNTERH_BUSY | GRTC_SYSCOUNTERH_OVERFLOW)) != 0);
|
||||
|
||||
leave_critical_section(flags);
|
||||
|
||||
*ctr = ((uint64_t)(high & GRTC_SYSCOUNTERH_MASK) << 32) | low;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: nrf54l_grtc_setcc
|
||||
****************************************************************************/
|
||||
|
||||
static int nrf54l_grtc_setcc(struct nrf54l_grtc_dev_s *dev, uint8_t i,
|
||||
uint64_t cc)
|
||||
{
|
||||
struct nrf54l_grtc_priv_s *grtc = NULL;
|
||||
irqstate_t flags;
|
||||
int ret = OK;
|
||||
|
||||
DEBUGASSERT(dev);
|
||||
|
||||
grtc = (struct nrf54l_grtc_priv_s *)dev;
|
||||
|
||||
/* Is the channel supported? */
|
||||
|
||||
if (i >= grtc->chan || cc > GRTC_COUNTER_MAX)
|
||||
{
|
||||
rtcerr("ERROR: unsupported GRTC channel %d\n", i);
|
||||
ret = -EINVAL;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
/* The channel must be disabled while the two words are written */
|
||||
|
||||
flags = enter_critical_section();
|
||||
|
||||
nrf54l_grtc_putreg(dev, NRF54L_GRTC_CCEN_OFFSET(i), 0);
|
||||
nrf54l_grtc_putreg(dev, NRF54L_GRTC_CCL_OFFSET(i), (uint32_t)cc);
|
||||
nrf54l_grtc_putreg(dev, NRF54L_GRTC_CCH_OFFSET(i), (uint32_t)(cc >> 32));
|
||||
nrf54l_grtc_putreg(dev, NRF54L_GRTC_CCEN_OFFSET(i), GRTC_CCEN_ACTIVE);
|
||||
|
||||
leave_critical_section(flags);
|
||||
|
||||
errout:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: nrf54l_grtc_getcc
|
||||
****************************************************************************/
|
||||
|
||||
static int nrf54l_grtc_getcc(struct nrf54l_grtc_dev_s *dev, uint8_t i,
|
||||
uint64_t *cc)
|
||||
{
|
||||
struct nrf54l_grtc_priv_s *grtc = NULL;
|
||||
uint32_t high;
|
||||
int ret = OK;
|
||||
|
||||
DEBUGASSERT(dev);
|
||||
DEBUGASSERT(cc);
|
||||
|
||||
grtc = (struct nrf54l_grtc_priv_s *)dev;
|
||||
|
||||
/* Is the channel supported? */
|
||||
|
||||
if (i >= grtc->chan)
|
||||
{
|
||||
rtcerr("ERROR: unsupported GRTC channel %d\n", i);
|
||||
ret = -EINVAL;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
high = nrf54l_grtc_getreg(dev, NRF54L_GRTC_CCH_OFFSET(i));
|
||||
*cc = ((uint64_t)(high & GRTC_CCH_MASK) << 32) |
|
||||
nrf54l_grtc_getreg(dev, NRF54L_GRTC_CCL_OFFSET(i));
|
||||
|
||||
errout:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: nrf54l_grtc_disablecc
|
||||
****************************************************************************/
|
||||
|
||||
static int nrf54l_grtc_disablecc(struct nrf54l_grtc_dev_s *dev, uint8_t i)
|
||||
{
|
||||
struct nrf54l_grtc_priv_s *grtc = NULL;
|
||||
int ret = OK;
|
||||
|
||||
DEBUGASSERT(dev);
|
||||
|
||||
grtc = (struct nrf54l_grtc_priv_s *)dev;
|
||||
|
||||
/* Is the channel supported? */
|
||||
|
||||
if (i >= grtc->chan)
|
||||
{
|
||||
rtcerr("ERROR: unsupported GRTC channel %d\n", i);
|
||||
ret = -EINVAL;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
nrf54l_grtc_putreg(dev, NRF54L_GRTC_CCEN_OFFSET(i), 0);
|
||||
|
||||
errout:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: nrf54l_grtc_setisr
|
||||
****************************************************************************/
|
||||
|
||||
static int nrf54l_grtc_setisr(struct nrf54l_grtc_dev_s *dev, xcpt_t handler,
|
||||
void *arg)
|
||||
{
|
||||
struct nrf54l_grtc_priv_s *grtc = NULL;
|
||||
int ret = OK;
|
||||
|
||||
DEBUGASSERT(dev);
|
||||
|
||||
grtc = (struct nrf54l_grtc_priv_s *)dev;
|
||||
|
||||
/* Disable interrupt when callback is removed */
|
||||
|
||||
if (!handler)
|
||||
{
|
||||
up_disable_irq(grtc->irq);
|
||||
irq_detach(grtc->irq);
|
||||
ret = OK;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
/* Otherwise set callback and enable interrupt */
|
||||
|
||||
irq_attach(grtc->irq, handler, arg);
|
||||
up_enable_irq(grtc->irq);
|
||||
|
||||
errout:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: nrf54l_grtc_enableint
|
||||
****************************************************************************/
|
||||
|
||||
static int nrf54l_grtc_enableint(struct nrf54l_grtc_dev_s *dev, uint8_t s)
|
||||
{
|
||||
uint32_t regval = 0;
|
||||
int ret = OK;
|
||||
|
||||
DEBUGASSERT(dev);
|
||||
|
||||
/* Get register value for given interrupt source */
|
||||
|
||||
regval = nrf54l_grtc_irq2reg(dev, s);
|
||||
if (regval == 0)
|
||||
{
|
||||
ret = -EINVAL;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
nrf54l_grtc_putreg(dev, NRF54L_GRTC_INTENSET_OFFSET(0), regval);
|
||||
|
||||
errout:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: nrf54l_grtc_disableint
|
||||
****************************************************************************/
|
||||
|
||||
static int nrf54l_grtc_disableint(struct nrf54l_grtc_dev_s *dev, uint8_t s)
|
||||
{
|
||||
uint32_t regval = 0;
|
||||
int ret = OK;
|
||||
|
||||
DEBUGASSERT(dev);
|
||||
|
||||
/* Get register value for given interrupt source */
|
||||
|
||||
regval = nrf54l_grtc_irq2reg(dev, s);
|
||||
if (regval == 0)
|
||||
{
|
||||
ret = -EINVAL;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
nrf54l_grtc_putreg(dev, NRF54L_GRTC_INTENCLR_OFFSET(0), regval);
|
||||
|
||||
errout:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: nrf54l_grtc_checkint
|
||||
****************************************************************************/
|
||||
|
||||
static int nrf54l_grtc_checkint(struct nrf54l_grtc_dev_s *dev, uint8_t s)
|
||||
{
|
||||
struct nrf54l_grtc_priv_s *grtc = (struct nrf54l_grtc_priv_s *)dev;
|
||||
int ret = 0;
|
||||
|
||||
DEBUGASSERT(dev);
|
||||
|
||||
if (s >= grtc->chan)
|
||||
{
|
||||
rtcerr("ERROR: unsupported IRQ source %d\n", s);
|
||||
ret = -EINVAL;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
ret = nrf54l_grtc_getreg(dev, NRF54L_GRTC_EVENTS_COMPARE_OFFSET(s));
|
||||
|
||||
errout:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: nrf54l_grtc_ackint
|
||||
****************************************************************************/
|
||||
|
||||
static int nrf54l_grtc_ackint(struct nrf54l_grtc_dev_s *dev, uint8_t s)
|
||||
{
|
||||
struct nrf54l_grtc_priv_s *grtc = (struct nrf54l_grtc_priv_s *)dev;
|
||||
int ret = 0;
|
||||
|
||||
DEBUGASSERT(dev);
|
||||
|
||||
if (s >= grtc->chan)
|
||||
{
|
||||
rtcerr("ERROR: unsupported IRQ source %d\n", s);
|
||||
ret = -EINVAL;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
nrf54l_grtc_putreg(dev, NRF54L_GRTC_EVENTS_COMPARE_OFFSET(s), 0);
|
||||
|
||||
errout:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: nrf54l_grtc_getbase
|
||||
****************************************************************************/
|
||||
|
||||
static uint32_t nrf54l_grtc_getbase(struct nrf54l_grtc_dev_s *dev)
|
||||
{
|
||||
struct nrf54l_grtc_priv_s *grtc = (struct nrf54l_grtc_priv_s *)dev;
|
||||
|
||||
DEBUGASSERT(dev);
|
||||
|
||||
return grtc->base;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: nrf54l_grtc_init
|
||||
*
|
||||
* Description:
|
||||
* Initialize GRTC device
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
struct nrf54l_grtc_dev_s *nrf54l_grtc_init(int grtc)
|
||||
{
|
||||
struct nrf54l_grtc_priv_s *priv = NULL;
|
||||
uint32_t regval;
|
||||
|
||||
/* Get GRTC instance */
|
||||
|
||||
switch (grtc)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
priv = &g_nrf54l_grtc_priv;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
rtcerr("ERROR: unsupported GRTC %d\n", grtc);
|
||||
goto errout;
|
||||
}
|
||||
}
|
||||
|
||||
if (priv->inuse != false)
|
||||
{
|
||||
/* GRTC already in use */
|
||||
|
||||
priv = NULL;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
priv->inuse = true;
|
||||
|
||||
/* Clock the LF timer from LFCLK. This register is not affected by a
|
||||
* system reset so it is always configured here.
|
||||
*/
|
||||
|
||||
regval = getreg32(priv->base + NRF54L_GRTC_CLKCFG_OFFSET);
|
||||
regval &= ~GRTC_CLKCFG_CLKSEL_MASK;
|
||||
regval |= GRTC_CLKCFG_CLKSEL_LFCLK;
|
||||
putreg32(regval, priv->base + NRF54L_GRTC_CLKCFG_OFFSET);
|
||||
|
||||
errout:
|
||||
return (struct nrf54l_grtc_dev_s *)priv;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: nrf54l_grtc_deinit
|
||||
*
|
||||
* Description:
|
||||
* Deinit GRTC device
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int nrf54l_grtc_deinit(struct nrf54l_grtc_dev_s *dev)
|
||||
{
|
||||
struct nrf54l_grtc_priv_s *grtc = NULL;
|
||||
|
||||
DEBUGASSERT(dev);
|
||||
|
||||
grtc = (struct nrf54l_grtc_priv_s *)dev;
|
||||
|
||||
grtc->inuse = false;
|
||||
|
||||
return OK;
|
||||
}
|
||||
140
arch/arm/src/nrf54l/nrf54l_grtc.h
Normal file
140
arch/arm/src/nrf54l/nrf54l_grtc.h
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
/****************************************************************************
|
||||
* arch/arm/src/nrf54l/nrf54l_grtc.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_NRF54L_NRF54L_GRTC_H
|
||||
#define __ARCH_ARM_SRC_NRF54L_NRF54L_GRTC_H
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <nuttx/irq.h>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/* Helpers ******************************************************************/
|
||||
|
||||
#define NRF54L_GRTC_START(d) ((d)->ops->start(d))
|
||||
#define NRF54L_GRTC_STOP(d) ((d)->ops->stop(d))
|
||||
#define NRF54L_GRTC_CLEAR(d) ((d)->ops->clear(d))
|
||||
#define NRF54L_GRTC_GETCOUNTER(d, c) ((d)->ops->getcounter(d, c))
|
||||
#define NRF54L_GRTC_SETCC(d, i, cc) ((d)->ops->setcc(d, i, cc))
|
||||
#define NRF54L_GRTC_GETCC(d, i, cc) ((d)->ops->getcc(d, i, cc))
|
||||
#define NRF54L_GRTC_DISABLECC(d, i) ((d)->ops->disablecc(d, i))
|
||||
#define NRF54L_GRTC_SETISR(d, hnd, arg) ((d)->ops->setisr(d, hnd, arg))
|
||||
#define NRF54L_GRTC_ENABLEINT(d, s) ((d)->ops->enableint(d, s))
|
||||
#define NRF54L_GRTC_DISABLEINT(d, s) ((d)->ops->disableint(d, s))
|
||||
#define NRF54L_GRTC_CHECKINT(d, s) ((d)->ops->checkint(d, s))
|
||||
#define NRF54L_GRTC_ACKINT(d, s) ((d)->ops->ackint(d, s))
|
||||
#define NRF54L_GRTC_GETBASE(d) ((d)->ops->getbase(d))
|
||||
|
||||
/****************************************************************************
|
||||
* Public Types
|
||||
****************************************************************************/
|
||||
|
||||
/* GRTC CC index */
|
||||
|
||||
enum nrf54l_grtc_cc_e
|
||||
{
|
||||
NRF54L_GRTC_CC0 = 0,
|
||||
NRF54L_GRTC_CC1 = 1,
|
||||
NRF54L_GRTC_CC2 = 2,
|
||||
NRF54L_GRTC_CC3 = 3,
|
||||
NRF54L_GRTC_CC4 = 4,
|
||||
NRF54L_GRTC_CC5 = 5,
|
||||
NRF54L_GRTC_CC6 = 6,
|
||||
NRF54L_GRTC_CC7 = 7,
|
||||
NRF54L_GRTC_CC8 = 8,
|
||||
NRF54L_GRTC_CC9 = 9,
|
||||
NRF54L_GRTC_CC10 = 10,
|
||||
NRF54L_GRTC_CC11 = 11,
|
||||
};
|
||||
|
||||
/* GRTC Interrupts/Events */
|
||||
|
||||
enum nrf54l_grtc_evt_e
|
||||
{
|
||||
NRF54L_GRTC_EVT_COMPARE0 = 0,
|
||||
NRF54L_GRTC_EVT_COMPARE1 = 1,
|
||||
NRF54L_GRTC_EVT_COMPARE2 = 2,
|
||||
NRF54L_GRTC_EVT_COMPARE3 = 3,
|
||||
NRF54L_GRTC_EVT_COMPARE4 = 4,
|
||||
NRF54L_GRTC_EVT_COMPARE5 = 5,
|
||||
NRF54L_GRTC_EVT_COMPARE6 = 6,
|
||||
NRF54L_GRTC_EVT_COMPARE7 = 7,
|
||||
NRF54L_GRTC_EVT_COMPARE8 = 8,
|
||||
NRF54L_GRTC_EVT_COMPARE9 = 9,
|
||||
NRF54L_GRTC_EVT_COMPARE10 = 10,
|
||||
NRF54L_GRTC_EVT_COMPARE11 = 11,
|
||||
};
|
||||
|
||||
/* NRF54L GRTC device */
|
||||
|
||||
struct nrf54l_grtc_dev_s
|
||||
{
|
||||
struct nrf54l_grtc_ops_s *ops;
|
||||
};
|
||||
|
||||
/* NRF54L GRTC ops */
|
||||
|
||||
struct nrf54l_grtc_ops_s
|
||||
{
|
||||
/* GRTC tasks */
|
||||
|
||||
int (*start)(struct nrf54l_grtc_dev_s *dev);
|
||||
int (*stop)(struct nrf54l_grtc_dev_s *dev);
|
||||
int (*clear)(struct nrf54l_grtc_dev_s *dev);
|
||||
|
||||
/* GRTC operations */
|
||||
|
||||
int (*getcounter)(struct nrf54l_grtc_dev_s *dev, uint64_t *cc);
|
||||
int (*setcc)(struct nrf54l_grtc_dev_s *dev, uint8_t i, uint64_t cc);
|
||||
int (*getcc)(struct nrf54l_grtc_dev_s *dev, uint8_t i, uint64_t *cc);
|
||||
int (*disablecc)(struct nrf54l_grtc_dev_s *dev, uint8_t i);
|
||||
|
||||
/* GRTC interrupts */
|
||||
|
||||
int (*setisr)(struct nrf54l_grtc_dev_s *dev, xcpt_t handler, void *arg);
|
||||
int (*enableint)(struct nrf54l_grtc_dev_s *dev, uint8_t source);
|
||||
int (*disableint)(struct nrf54l_grtc_dev_s *dev, uint8_t source);
|
||||
int (*checkint)(struct nrf54l_grtc_dev_s *dev, uint8_t source);
|
||||
int (*ackint)(struct nrf54l_grtc_dev_s *dev, uint8_t source);
|
||||
|
||||
/* Utility */
|
||||
|
||||
uint32_t (*getbase)(struct nrf54l_grtc_dev_s *dev);
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Public Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
struct nrf54l_grtc_dev_s *nrf54l_grtc_init(int grtc);
|
||||
int nrf54l_grtc_deinit(struct nrf54l_grtc_dev_s *dev);
|
||||
|
||||
#endif /* __ARCH_ARM_SRC_NRF54L_NRF54L_GRTC_H */
|
||||
|
|
@ -83,9 +83,16 @@ void up_idle(void)
|
|||
nxsched_process_timer();
|
||||
#else
|
||||
|
||||
/* The SysTick's clock will only tick when the CPU is
|
||||
/* Sleep until an interrupt occurs to save power
|
||||
*
|
||||
* The SysTick's clock will only tick when the CPU is
|
||||
* running (not in WFE/WFI) or when the system is in debug interface mode.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_NRF54L_SYSTIMER_GRTC
|
||||
BEGIN_IDLE();
|
||||
asm("WFI");
|
||||
END_IDLE();
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
|
|
|||
282
arch/arm/src/nrf54l/nrf54l_tickless_grtc.c
Normal file
282
arch/arm/src/nrf54l/nrf54l_tickless_grtc.c
Normal file
|
|
@ -0,0 +1,282 @@
|
|||
/****************************************************************************
|
||||
* arch/arm/src/nrf54l/nrf54l_tickless_grtc.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 <sys/types.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <nuttx/debug.h>
|
||||
|
||||
#include <nuttx/arch.h>
|
||||
|
||||
#include "arm_internal.h"
|
||||
#include "hardware/nrf54l_grtc.h"
|
||||
#include "nrf54l_grtc.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/* Check configuration */
|
||||
|
||||
#ifdef CONFIG_TIMER_ARCH
|
||||
# error CONFIG_TIMER_ARCH must be not set
|
||||
#endif
|
||||
|
||||
/* The SYSCOUNTER runs at 1MHz so the counter value is in microseconds.
|
||||
* The compare value must be ahead of the counter for the event to fire,
|
||||
* so a small margin covers the register writes.
|
||||
*/
|
||||
|
||||
#define NRF54L_GRTC_ALARM_MARGIN (10)
|
||||
|
||||
/****************************************************************************
|
||||
* Private Types
|
||||
****************************************************************************/
|
||||
|
||||
struct nrf54l_tickless_dev_s
|
||||
{
|
||||
struct nrf54l_grtc_dev_s *grtc; /* nrf54l GRTC driver */
|
||||
bool alarm_set; /* is the alarm set? */
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
static int grtc_handler(int irq, void *context, void *arg);
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
struct nrf54l_tickless_dev_s g_tickless_dev;
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
static inline void grtc_counter_to_ts(uint64_t counter, struct timespec *now)
|
||||
{
|
||||
now->tv_sec = counter / USEC_PER_SEC;
|
||||
now->tv_nsec = (counter % USEC_PER_SEC) * NSEC_PER_USEC;
|
||||
}
|
||||
|
||||
static void grtc_prepare_alarm(uint64_t target)
|
||||
{
|
||||
uint64_t counter;
|
||||
|
||||
/* Set CC to the desired value. If the alarm is already due, the CC is
|
||||
* moved ahead of the counter so that the COMPARE event is guaranteed
|
||||
* to fire. We repeat this until the CC is ahead of the counter or
|
||||
* the event has already fired (as the counter may change in between).
|
||||
*/
|
||||
|
||||
for (; ; )
|
||||
{
|
||||
NRF54L_GRTC_GETCOUNTER(g_tickless_dev.grtc, &counter);
|
||||
if (target <= counter + NRF54L_GRTC_ALARM_MARGIN)
|
||||
{
|
||||
target = counter + NRF54L_GRTC_ALARM_MARGIN;
|
||||
}
|
||||
|
||||
NRF54L_GRTC_SETCC(g_tickless_dev.grtc, NRF54L_GRTC_CC0, target);
|
||||
|
||||
NRF54L_GRTC_GETCOUNTER(g_tickless_dev.grtc, &counter);
|
||||
if (target > counter ||
|
||||
NRF54L_GRTC_CHECKINT(g_tickless_dev.grtc,
|
||||
NRF54L_GRTC_EVT_COMPARE0))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Enable interrupt */
|
||||
|
||||
NRF54L_GRTC_ENABLEINT(g_tickless_dev.grtc, NRF54L_GRTC_EVT_COMPARE0);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: grtc_cancel_ack
|
||||
****************************************************************************/
|
||||
|
||||
static void grtc_cancel_ack(void)
|
||||
{
|
||||
irqstate_t flags;
|
||||
|
||||
flags = enter_critical_section();
|
||||
|
||||
NRF54L_GRTC_DISABLEINT(g_tickless_dev.grtc, NRF54L_GRTC_EVT_COMPARE0);
|
||||
NRF54L_GRTC_DISABLECC(g_tickless_dev.grtc, NRF54L_GRTC_CC0);
|
||||
NRF54L_GRTC_ACKINT(g_tickless_dev.grtc, NRF54L_GRTC_EVT_COMPARE0);
|
||||
g_tickless_dev.alarm_set = false;
|
||||
|
||||
leave_critical_section(flags);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: grtc_handler
|
||||
****************************************************************************/
|
||||
|
||||
static int grtc_handler(int irq, void *context, void *arg)
|
||||
{
|
||||
irqstate_t flags;
|
||||
|
||||
flags = enter_critical_section();
|
||||
|
||||
/* if the compare event fired */
|
||||
|
||||
if (NRF54L_GRTC_CHECKINT(g_tickless_dev.grtc, NRF54L_GRTC_EVT_COMPARE0))
|
||||
{
|
||||
/* cancel the alarm and ack the event */
|
||||
|
||||
grtc_cancel_ack();
|
||||
|
||||
/* let scheduler now of alarm firing */
|
||||
|
||||
nxsched_process_timer();
|
||||
}
|
||||
|
||||
leave_critical_section(flags);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: up_alarm_cancel
|
||||
****************************************************************************/
|
||||
|
||||
int up_alarm_cancel(struct timespec *ts)
|
||||
{
|
||||
uint64_t counter;
|
||||
irqstate_t flags;
|
||||
|
||||
flags = enter_critical_section();
|
||||
|
||||
NRF54L_GRTC_DISABLEINT(g_tickless_dev.grtc, NRF54L_GRTC_EVT_COMPARE0);
|
||||
NRF54L_GRTC_GETCOUNTER(g_tickless_dev.grtc, &counter);
|
||||
|
||||
NRF54L_GRTC_DISABLECC(g_tickless_dev.grtc, NRF54L_GRTC_CC0);
|
||||
NRF54L_GRTC_ACKINT(g_tickless_dev.grtc, NRF54L_GRTC_EVT_COMPARE0);
|
||||
g_tickless_dev.alarm_set = false;
|
||||
|
||||
leave_critical_section(flags);
|
||||
|
||||
grtc_counter_to_ts(counter, ts);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: up_alarm_start
|
||||
****************************************************************************/
|
||||
|
||||
int up_alarm_start(const struct timespec *ts)
|
||||
{
|
||||
uint64_t target;
|
||||
irqstate_t flags;
|
||||
|
||||
flags = enter_critical_section();
|
||||
|
||||
/* remember the alarm time */
|
||||
|
||||
g_tickless_dev.alarm_set = true;
|
||||
|
||||
/* Round up so the alarm never fires before the requested time. Clamp
|
||||
* to the counter range, the alarm is reevaluated before it can expire.
|
||||
*/
|
||||
|
||||
if (ts->tv_sec >= (GRTC_COUNTER_MAX / USEC_PER_SEC))
|
||||
{
|
||||
target = GRTC_COUNTER_MAX;
|
||||
}
|
||||
else
|
||||
{
|
||||
target = (uint64_t)ts->tv_sec * USEC_PER_SEC +
|
||||
(ts->tv_nsec + NSEC_PER_USEC - 1) / NSEC_PER_USEC;
|
||||
}
|
||||
|
||||
grtc_prepare_alarm(target);
|
||||
|
||||
leave_critical_section(flags);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: up_timer_gettime
|
||||
****************************************************************************/
|
||||
|
||||
int up_timer_gettime(struct timespec *ts)
|
||||
{
|
||||
uint64_t counter;
|
||||
irqstate_t flags;
|
||||
|
||||
flags = enter_critical_section();
|
||||
|
||||
NRF54L_GRTC_GETCOUNTER(g_tickless_dev.grtc, &counter);
|
||||
grtc_counter_to_ts(counter, ts);
|
||||
|
||||
leave_critical_section(flags);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: up_timer_initialize
|
||||
****************************************************************************/
|
||||
|
||||
void up_timer_initialize(void)
|
||||
{
|
||||
memset(&g_tickless_dev, 0, sizeof(struct nrf54l_tickless_dev_s));
|
||||
|
||||
g_tickless_dev.grtc = nrf54l_grtc_init(0);
|
||||
|
||||
/* Ensure we have support for the GRTC instance */
|
||||
|
||||
ASSERT(g_tickless_dev.grtc);
|
||||
|
||||
/* Configure ISR */
|
||||
|
||||
NRF54L_GRTC_SETISR(g_tickless_dev.grtc, grtc_handler, NULL);
|
||||
|
||||
/* Start counting */
|
||||
|
||||
NRF54L_GRTC_CLEAR(g_tickless_dev.grtc);
|
||||
NRF54L_GRTC_ACKINT(g_tickless_dev.grtc, NRF54L_GRTC_EVT_COMPARE0);
|
||||
NRF54L_GRTC_START(g_tickless_dev.grtc);
|
||||
|
||||
/* kick off alarm scheduling */
|
||||
|
||||
nxsched_process_timer();
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue