arch/arm/ra8m1: Add GPT timer support

Add the General PWM Timer (GPT) as a generic timer, registered as
/dev/timerN through the upper-half timer driver.  GPT0-7 are 32-bit,
GPT8-13 are 16-bit, and the timeout can be changed while running.

Give each ICU event used by GPT its own enum value instead of a
__COUNTER__-based macro, since the latter can hand out a different
number at every use.

Live period changes to the same prescaler now reload through GTPBR
(the buffered period register) instead of stopping the counter,
matching Renesas's own FSP driver, and fix a hardware-confirmed bug
where an uninitialized GTPBR silently corrupted the period after the
first cycle.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Assisted-by: Claude:claude-sonnet-5
Signed-off-by: leocafonso <leocafonso@gmail.com>
This commit is contained in:
leocafonso 2026-09-30 18:35:44 -07:00 • committed by Xiang Xiao
parent 62cc75c691
commit 279e1ec458
11 changed files with 2617 additions and 47 deletions

View file

@ -180,3 +180,12 @@ libs/libc/tre-mem.c
* message using the Neighbor Discovery (ND) protocol. It then listens
PIO DUE SCHEM. PIN MAPPING SAM3X DUE SCHEM. BOARD LABEL
# instruct the gsize to generate a "*.siz" file that contains the detailed section size
# define R_GPT_GTBER_ADTTA_TRANSFER_AT_TROUGH (2 << R_GPT_GTBER_ADTTA_SHIFT) /* Transfer at trough */
# define R_GPT_GTBER_ADTTA_V11 (3 << R_GPT_GTBER_ADTTA_SHIFT) /* Transfer at both crest and trough */
# define R_GPT_GTBER_ADTTB_TRANSFER_AT_TROUGH (2 << R_GPT_GTBER_ADTTB_SHIFT) /* Transfer at trough */
# define R_GPT_GTBER_ADTTB_V11 (3 << R_GPT_GTBER_ADTTB_SHIFT) /* Transfer at both crest and trough */
# define R_GPT_GTCR_MD_V101 (5 << R_GPT_GTCR_MD_SHIFT) /* Triangle-wave PWM mode 2 (32-bit transfer at crest and trough) (single buffer or double buffer possible) */
# define R_GPT_GTCR_MD_V110 (6 << R_GPT_GTCR_MD_SHIFT) /* Triangle-wave PWM mode 3 (64-bit transfer at trough) fixed buffer operation) */
* next trough (manual 21.2.16/Table 21.5) -- the counter
* every trough, including the very first one after this start/
next trough with no gap in counting, matching the reload behavior of

View file

@ -34,7 +34,8 @@
/* Get customizations for each supported chip */
#if defined(CONFIG_ARCH_CHIP_R7FA8M1AFECAM)
# define RA_NSCI_B 6 /* SCI_B0-4, SCI_B9 (not contiguous: no SCI_B5-8) */
# define RA_NSCI_B 6 /* SCI_B0-4, SCI_B9 (not contiguous: no SCI_B5-8) */
# define RA_NGPT 8 /* GPT0-7 */
# define RA_RAM_SIZE (896*1024) /* 896Kb RAM */
# define RA_FLASH_SIZE (1024*1024) /* 1024Kb FLASH */
@ -51,7 +52,8 @@
# endif
#elif defined(CONFIG_ARCH_CHIP_R7FA8M1AFECBD)
# define RA_NSCI_B 6 /* SCI_B0-4, SCI_B9 (not contiguous: no SCI_B5-8) */
# define RA_NSCI_B 6 /* SCI_B0-4, SCI_B9 (not contiguous: no SCI_B5-8) */
# define RA_NGPT 8 /* GPT0-7 */
# define RA_RAM_SIZE (896*1024) /* 896Kb RAM */
# define RA_FLASH_SIZE (1024*1024) /* 1024Kb FLASH */
@ -68,7 +70,8 @@
# endif
#elif defined(CONFIG_ARCH_CHIP_R7FA8M1AFECFB)
# define RA_NSCI_B 6 /* SCI_B0-4, SCI_B9 (not contiguous: no SCI_B5-8) */
# define RA_NSCI_B 6 /* SCI_B0-4, SCI_B9 (not contiguous: no SCI_B5-8) */
# define RA_NGPT 8 /* GPT0-7 */
# define RA_RAM_SIZE (896*1024) /* 896Kb RAM */
# define RA_FLASH_SIZE (1024*1024) /* 1024Kb FLASH */
@ -85,7 +88,8 @@
# endif
#elif defined(CONFIG_ARCH_CHIP_R7FA8M1AFECFC)
# define RA_NSCI_B 6 /* SCI_B0-4, SCI_B9 (not contiguous: no SCI_B5-8) */
# define RA_NSCI_B 6 /* SCI_B0-4, SCI_B9 (not contiguous: no SCI_B5-8) */
# define RA_NGPT 8 /* GPT0-7 */
# define RA_RAM_SIZE (896*1024) /* 896Kb RAM */
# define RA_FLASH_SIZE (1024*1024) /* 1024Kb FLASH */
@ -103,6 +107,7 @@
#elif defined(CONFIG_ARCH_CHIP_R7FA8M1AFECFP)
# define RA_NSCI_B 6 /* SCI_B0-4, SCI_B9 (not contiguous: no SCI_B5-8) */
# define RA_NGPT 8 /* GPT0-7 */
# define RA_RAM_SIZE (896*1024) /* 896Kb RAM */
# define RA_FLASH_SIZE (1024*1024) /* 1024Kb FLASH */
@ -119,7 +124,8 @@
# endif
#elif defined(CONFIG_ARCH_CHIP_R7FA8M1AHECAM)
# define RA_NSCI_B 6 /* SCI_B0-4, SCI_B9 (not contiguous: no SCI_B5-8) */
# define RA_NSCI_B 6 /* SCI_B0-4, SCI_B9 (not contiguous: no SCI_B5-8) */
# define RA_NGPT 8 /* GPT0-7 */
# define RA_RAM_SIZE (896*1024) /* 896Kb RAM */
# define RA_FLASH_SIZE (2016*1024) /* 2016Kb FLASH */
@ -136,7 +142,8 @@
# endif
#elif defined(CONFIG_ARCH_CHIP_R7FA8M1AHECBD)
# define RA_NSCI_B 6 /* SCI_B0-4, SCI_B9 (not contiguous: no SCI_B5-8) */
# define RA_NSCI_B 6 /* SCI_B0-4, SCI_B9 (not contiguous: no SCI_B5-8) */
# define RA_NGPT 8 /* GPT0-7 */
# define RA_RAM_SIZE (896*1024) /* 896Kb RAM */
# define RA_FLASH_SIZE (2016*1024) /* 2016Kb FLASH */
@ -153,7 +160,8 @@
# endif
#elif defined(CONFIG_ARCH_CHIP_R7FA8M1AHECFB)
# define RA_NSCI_B 6 /* SCI_B0-4, SCI_B9 (not contiguous: no SCI_B5-8) */
# define RA_NSCI_B 6 /* SCI_B0-4, SCI_B9 (not contiguous: no SCI_B5-8) */
# define RA_NGPT 8 /* GPT0-7 */
# define RA_RAM_SIZE (896*1024) /* 896Kb RAM */
# define RA_FLASH_SIZE (2016*1024) /* 2016Kb FLASH */
@ -170,7 +178,8 @@
# endif
#elif defined(CONFIG_ARCH_CHIP_R7FA8M1AHECFC)
# define RA_NSCI_B 6 /* SCI_B0-4, SCI_B9 (not contiguous: no SCI_B5-8) */
# define RA_NSCI_B 6 /* SCI_B0-4, SCI_B9 (not contiguous: no SCI_B5-8) */
# define RA_NGPT 8 /* GPT0-7 */
# define RA_RAM_SIZE (896*1024) /* 896Kb RAM */
# define RA_FLASH_SIZE (2016*1024) /* 2016Kb FLASH */
@ -188,6 +197,7 @@
#elif defined(CONFIG_ARCH_CHIP_R7FA8M1AHECFP)
# define RA_NSCI_B 6 /* SCI_B0-4, SCI_B9 (not contiguous: no SCI_B5-8) */
# define RA_NGPT 8 /* GPT0-7 */
# define RA_RAM_SIZE (896*1024) /* 896Kb RAM */
# define RA_FLASH_SIZE (2016*1024) /* 2016Kb FLASH */

View file

@ -64,10 +64,6 @@
#define RA_IRQ_PENDSV (14) /* Vector 14: Pendable system service request */
#define RA_IRQ_SYSTICK (15) /* Vector 15: System tick */
/* Chip-Specific External interrupts */
#define RA_IRQ_FIRST (16) /* Vector number of the first external interrupt */
#define NR_IRQS (RA_IRQ_FIRST + RA_IRQ_NEXTINT)
/****************************************************************************

View file

@ -38,12 +38,17 @@
* Pre-processor Definitions
****************************************************************************/
/* Vector number of the first external interrupt. Defined here, ahead of
* the event enumeration below that is based on it.
*/
#define RA_IRQ_FIRST (16)
/* Total number of IRQ numbers.
*
* Every ICU IELSR slot is runtime-configurable -- any peripheral event
* can be routed to any slot -- so RA_IRQ_IELSRn below are just the raw
* vector numbers; RA_IRQ_NEXTINT is the total slot count. Both come
* directly from this chip's .rzone <processor DnumInterrupts>.
* vector numbers; RA_IRQ_NEXTINT is the total slot count.
*/
#define RA_IRQ_IELSR0 (RA_IRQ_FIRST + 0) /* 0: Event selected in the ICU.IELSR0 register */
@ -145,48 +150,116 @@
#define RA_IRQ_NEXTINT (96)
/* SCI_B interrupt events.
/* Peripheral interrupt events.
*
* The ICU routes any peripheral event to any of the IELSR slots, so the
* SCI_B events are simply given fixed slots: four per channel (receive data
* full, transmit data empty, transmit end, receive error). The numbers do
* not depend on which channels a build enables, so every file that uses
* them (ra_serial.c, ra_icu.c) sees the same value. Only RA_IRQ_IELSR0 to
* RA_IRQ_IELSR23 are used; ra_attach_icu() routes the events of the enabled
* channels to their slots.
* The ICU can route any peripheral event to any IELSR slot. Each event
* that an enabled peripheral needs is given a slot here, packed from
* RA_IRQ_FIRST in the order below, so only the events a build uses take a
* slot (the ICU has RA_IRQ_NEXTINT of them).
*
* RA8M1 has SCI_B0-4 and SCI_B9 (no SCI_B5-8), named SCI0-4 and SCI9 here.
* ra_attach_icu() (ra_icu.c) writes the matching event number to
* IELSR(<irq> - RA_IRQ_FIRST) for each of these.
*
* To give a peripheral another event (for example a GPT compare match),
* add an enumerator under its own Kconfig option and route it in
* ra_attach_icu().
*/
#define SCI0_RXI (RA_IRQ_FIRST + 0) /* Receive data full */
#define SCI0_TXI (RA_IRQ_FIRST + 1) /* Transmit data empty */
#define SCI0_TEI (RA_IRQ_FIRST + 2) /* Transmit end */
#define SCI0_ERI (RA_IRQ_FIRST + 3) /* Receive error */
#ifndef __ASSEMBLY__
enum ra_icu_event_irq_e
{
RA_IRQ_EVT_START = RA_IRQ_FIRST - 1, /* Not an IRQ: first event = FIRST */
#define SCI1_RXI (RA_IRQ_FIRST + 4) /* Receive data full */
#define SCI1_TXI (RA_IRQ_FIRST + 5) /* Transmit data empty */
#define SCI1_TEI (RA_IRQ_FIRST + 6) /* Transmit end */
#define SCI1_ERI (RA_IRQ_FIRST + 7) /* Receive error */
#ifdef CONFIG_RA_SCI0_UART
SCI0_RXI, /* Receive data full */
SCI0_TXI, /* Transmit data empty */
SCI0_TEI, /* Transmit end */
SCI0_ERI, /* Receive error */
#endif
#define SCI2_RXI (RA_IRQ_FIRST + 8) /* Receive data full */
#define SCI2_TXI (RA_IRQ_FIRST + 9) /* Transmit data empty */
#define SCI2_TEI (RA_IRQ_FIRST + 10) /* Transmit end */
#define SCI2_ERI (RA_IRQ_FIRST + 11) /* Receive error */
#ifdef CONFIG_RA_SCI1_UART
SCI1_RXI, /* Receive data full */
SCI1_TXI, /* Transmit data empty */
SCI1_TEI, /* Transmit end */
SCI1_ERI, /* Receive error */
#endif
#define SCI3_RXI (RA_IRQ_FIRST + 12) /* Receive data full */
#define SCI3_TXI (RA_IRQ_FIRST + 13) /* Transmit data empty */
#define SCI3_TEI (RA_IRQ_FIRST + 14) /* Transmit end */
#define SCI3_ERI (RA_IRQ_FIRST + 15) /* Receive error */
#ifdef CONFIG_RA_SCI2_UART
SCI2_RXI, /* Receive data full */
SCI2_TXI, /* Transmit data empty */
SCI2_TEI, /* Transmit end */
SCI2_ERI, /* Receive error */
#endif
#define SCI4_RXI (RA_IRQ_FIRST + 16) /* Receive data full */
#define SCI4_TXI (RA_IRQ_FIRST + 17) /* Transmit data empty */
#define SCI4_TEI (RA_IRQ_FIRST + 18) /* Transmit end */
#define SCI4_ERI (RA_IRQ_FIRST + 19) /* Receive error */
#ifdef CONFIG_RA_SCI3_UART
SCI3_RXI, /* Receive data full */
SCI3_TXI, /* Transmit data empty */
SCI3_TEI, /* Transmit end */
SCI3_ERI, /* Receive error */
#endif
#define SCI9_RXI (RA_IRQ_FIRST + 20) /* Receive data full */
#define SCI9_TXI (RA_IRQ_FIRST + 21) /* Transmit data empty */
#define SCI9_TEI (RA_IRQ_FIRST + 22) /* Transmit end */
#define SCI9_ERI (RA_IRQ_FIRST + 23) /* Receive error */
#ifdef CONFIG_RA_SCI4_UART
SCI4_RXI, /* Receive data full */
SCI4_TXI, /* Transmit data empty */
SCI4_TEI, /* Transmit end */
SCI4_ERI, /* Receive error */
#endif
#ifdef CONFIG_RA_SCI9_UART
SCI9_RXI, /* Receive data full */
SCI9_TXI, /* Transmit data empty */
SCI9_TEI, /* Transmit end */
SCI9_ERI, /* Receive error */
#endif
/* GPT: only the counter overflow, which is the timer expiry */
#ifdef CONFIG_RA_GPT0_GPT
GPT0_COUNTER_OVERFLOW,
#endif
#ifdef CONFIG_RA_GPT1_GPT
GPT1_COUNTER_OVERFLOW,
#endif
#ifdef CONFIG_RA_GPT2_GPT
GPT2_COUNTER_OVERFLOW,
#endif
#ifdef CONFIG_RA_GPT3_GPT
GPT3_COUNTER_OVERFLOW,
#endif
#ifdef CONFIG_RA_GPT4_GPT
GPT4_COUNTER_OVERFLOW,
#endif
#ifdef CONFIG_RA_GPT5_GPT
GPT5_COUNTER_OVERFLOW,
#endif
#ifdef CONFIG_RA_GPT6_GPT
GPT6_COUNTER_OVERFLOW,
#endif
#ifdef CONFIG_RA_GPT7_GPT
GPT7_COUNTER_OVERFLOW,
#endif
#ifdef CONFIG_RA_GPT8_GPT
GPT8_COUNTER_OVERFLOW,
#endif
#ifdef CONFIG_RA_GPT9_GPT
GPT9_COUNTER_OVERFLOW,
#endif
#ifdef CONFIG_RA_GPT10_GPT
GPT10_COUNTER_OVERFLOW,
#endif
#ifdef CONFIG_RA_GPT11_GPT
GPT11_COUNTER_OVERFLOW,
#endif
#ifdef CONFIG_RA_GPT12_GPT
GPT12_COUNTER_OVERFLOW,
#endif
#ifdef CONFIG_RA_GPT13_GPT
GPT13_COUNTER_OVERFLOW,
#endif
RA_IRQ_EVT_END /* Not an IRQ: one past the last */
};
#endif /* __ASSEMBLY__ */
/****************************************************************************
* Public Types

View file

@ -30,4 +30,8 @@ set(SRCS
ra_gpio.c
ra_allocateheap.c)
if(CONFIG_RA_GPT_TIMER)
list(APPEND SRCS ra_gpt.c)
endif()
target_sources(arch PRIVATE ${SRCS})

View file

@ -18,6 +18,20 @@ config ARCH_CHIP_R7FA8M1AFECAM
select RA_HAVE_SCI_B3
select RA_HAVE_SCI_B4
select RA_HAVE_SCI_B9
select RA_HAVE_GPT0
select RA_HAVE_GPT1
select RA_HAVE_GPT2
select RA_HAVE_GPT3
select RA_HAVE_GPT4
select RA_HAVE_GPT5
select RA_HAVE_GPT6
select RA_HAVE_GPT7
select RA_HAVE_GPT8
select RA_HAVE_GPT9
select RA_HAVE_GPT10
select RA_HAVE_GPT11
select RA_HAVE_GPT12
select RA_HAVE_GPT13
select RA8M1_FAMILY
config ARCH_CHIP_R7FA8M1AFECBD
@ -28,6 +42,20 @@ config ARCH_CHIP_R7FA8M1AFECBD
select RA_HAVE_SCI_B3
select RA_HAVE_SCI_B4
select RA_HAVE_SCI_B9
select RA_HAVE_GPT0
select RA_HAVE_GPT1
select RA_HAVE_GPT2
select RA_HAVE_GPT3
select RA_HAVE_GPT4
select RA_HAVE_GPT5
select RA_HAVE_GPT6
select RA_HAVE_GPT7
select RA_HAVE_GPT8
select RA_HAVE_GPT9
select RA_HAVE_GPT10
select RA_HAVE_GPT11
select RA_HAVE_GPT12
select RA_HAVE_GPT13
select RA8M1_FAMILY
config ARCH_CHIP_R7FA8M1AFECFB
@ -38,6 +66,20 @@ config ARCH_CHIP_R7FA8M1AFECFB
select RA_HAVE_SCI_B3
select RA_HAVE_SCI_B4
select RA_HAVE_SCI_B9
select RA_HAVE_GPT0
select RA_HAVE_GPT1
select RA_HAVE_GPT2
select RA_HAVE_GPT3
select RA_HAVE_GPT4
select RA_HAVE_GPT5
select RA_HAVE_GPT6
select RA_HAVE_GPT7
select RA_HAVE_GPT8
select RA_HAVE_GPT9
select RA_HAVE_GPT10
select RA_HAVE_GPT11
select RA_HAVE_GPT12
select RA_HAVE_GPT13
select RA8M1_FAMILY
config ARCH_CHIP_R7FA8M1AFECFC
@ -48,6 +90,20 @@ config ARCH_CHIP_R7FA8M1AFECFC
select RA_HAVE_SCI_B3
select RA_HAVE_SCI_B4
select RA_HAVE_SCI_B9
select RA_HAVE_GPT0
select RA_HAVE_GPT1
select RA_HAVE_GPT2
select RA_HAVE_GPT3
select RA_HAVE_GPT4
select RA_HAVE_GPT5
select RA_HAVE_GPT6
select RA_HAVE_GPT7
select RA_HAVE_GPT8
select RA_HAVE_GPT9
select RA_HAVE_GPT10
select RA_HAVE_GPT11
select RA_HAVE_GPT12
select RA_HAVE_GPT13
select RA8M1_FAMILY
config ARCH_CHIP_R7FA8M1AFECFP
@ -58,6 +114,20 @@ config ARCH_CHIP_R7FA8M1AFECFP
select RA_HAVE_SCI_B3
select RA_HAVE_SCI_B4
select RA_HAVE_SCI_B9
select RA_HAVE_GPT0
select RA_HAVE_GPT1
select RA_HAVE_GPT2
select RA_HAVE_GPT3
select RA_HAVE_GPT4
select RA_HAVE_GPT5
select RA_HAVE_GPT6
select RA_HAVE_GPT7
select RA_HAVE_GPT8
select RA_HAVE_GPT9
select RA_HAVE_GPT10
select RA_HAVE_GPT11
select RA_HAVE_GPT12
select RA_HAVE_GPT13
select RA8M1_FAMILY
config ARCH_CHIP_R7FA8M1AHECAM
@ -68,6 +138,20 @@ config ARCH_CHIP_R7FA8M1AHECAM
select RA_HAVE_SCI_B3
select RA_HAVE_SCI_B4
select RA_HAVE_SCI_B9
select RA_HAVE_GPT0
select RA_HAVE_GPT1
select RA_HAVE_GPT2
select RA_HAVE_GPT3
select RA_HAVE_GPT4
select RA_HAVE_GPT5
select RA_HAVE_GPT6
select RA_HAVE_GPT7
select RA_HAVE_GPT8
select RA_HAVE_GPT9
select RA_HAVE_GPT10
select RA_HAVE_GPT11
select RA_HAVE_GPT12
select RA_HAVE_GPT13
select RA8M1_FAMILY
config ARCH_CHIP_R7FA8M1AHECBD
@ -78,6 +162,20 @@ config ARCH_CHIP_R7FA8M1AHECBD
select RA_HAVE_SCI_B3
select RA_HAVE_SCI_B4
select RA_HAVE_SCI_B9
select RA_HAVE_GPT0
select RA_HAVE_GPT1
select RA_HAVE_GPT2
select RA_HAVE_GPT3
select RA_HAVE_GPT4
select RA_HAVE_GPT5
select RA_HAVE_GPT6
select RA_HAVE_GPT7
select RA_HAVE_GPT8
select RA_HAVE_GPT9
select RA_HAVE_GPT10
select RA_HAVE_GPT11
select RA_HAVE_GPT12
select RA_HAVE_GPT13
select RA8M1_FAMILY
config ARCH_CHIP_R7FA8M1AHECFB
@ -88,6 +186,20 @@ config ARCH_CHIP_R7FA8M1AHECFB
select RA_HAVE_SCI_B3
select RA_HAVE_SCI_B4
select RA_HAVE_SCI_B9
select RA_HAVE_GPT0
select RA_HAVE_GPT1
select RA_HAVE_GPT2
select RA_HAVE_GPT3
select RA_HAVE_GPT4
select RA_HAVE_GPT5
select RA_HAVE_GPT6
select RA_HAVE_GPT7
select RA_HAVE_GPT8
select RA_HAVE_GPT9
select RA_HAVE_GPT10
select RA_HAVE_GPT11
select RA_HAVE_GPT12
select RA_HAVE_GPT13
select RA8M1_FAMILY
config ARCH_CHIP_R7FA8M1AHECFC
@ -98,6 +210,20 @@ config ARCH_CHIP_R7FA8M1AHECFC
select RA_HAVE_SCI_B3
select RA_HAVE_SCI_B4
select RA_HAVE_SCI_B9
select RA_HAVE_GPT0
select RA_HAVE_GPT1
select RA_HAVE_GPT2
select RA_HAVE_GPT3
select RA_HAVE_GPT4
select RA_HAVE_GPT5
select RA_HAVE_GPT6
select RA_HAVE_GPT7
select RA_HAVE_GPT8
select RA_HAVE_GPT9
select RA_HAVE_GPT10
select RA_HAVE_GPT11
select RA_HAVE_GPT12
select RA_HAVE_GPT13
select RA8M1_FAMILY
config ARCH_CHIP_R7FA8M1AHECFP
@ -108,6 +234,20 @@ config ARCH_CHIP_R7FA8M1AHECFP
select RA_HAVE_SCI_B3
select RA_HAVE_SCI_B4
select RA_HAVE_SCI_B9
select RA_HAVE_GPT0
select RA_HAVE_GPT1
select RA_HAVE_GPT2
select RA_HAVE_GPT3
select RA_HAVE_GPT4
select RA_HAVE_GPT5
select RA_HAVE_GPT6
select RA_HAVE_GPT7
select RA_HAVE_GPT8
select RA_HAVE_GPT9
select RA_HAVE_GPT10
select RA_HAVE_GPT11
select RA_HAVE_GPT12
select RA_HAVE_GPT13
select RA8M1_FAMILY
endchoice # RA Chip Selection
@ -143,6 +283,62 @@ config RA_HAVE_SCI_B9
bool
default n
config RA_HAVE_GPT0
bool
default n
config RA_HAVE_GPT1
bool
default n
config RA_HAVE_GPT2
bool
default n
config RA_HAVE_GPT3
bool
default n
config RA_HAVE_GPT4
bool
default n
config RA_HAVE_GPT5
bool
default n
config RA_HAVE_GPT6
bool
default n
config RA_HAVE_GPT7
bool
default n
config RA_HAVE_GPT8
bool
default n
config RA_HAVE_GPT9
bool
default n
config RA_HAVE_GPT10
bool
default n
config RA_HAVE_GPT11
bool
default n
config RA_HAVE_GPT12
bool
default n
config RA_HAVE_GPT13
bool
default n
# TODO: user-facing enable options go here, one per
# RA_HAVE_* above (prompt, depends on RA_HAVE_*, select
# the driver it wires up -- see README "Kconfig draft").
@ -183,4 +379,86 @@ config RA_SCI9_UART
depends on RA_HAVE_SCI_B9
select SCI9_SERIALDRIVER
config RA_GPT_TIMER
bool "GPT timer (/dev/timerN)"
default n
select TIMER
---help---
Register enabled GPT channels as generic timers. Each enabled
channel uses one ICU slot (its overflow event).
if RA_GPT_TIMER
config RA_GPT0_GPT
bool "GPT0 (32-bit)"
default n
depends on RA_HAVE_GPT0
config RA_GPT1_GPT
bool "GPT1 (32-bit)"
default n
depends on RA_HAVE_GPT1
config RA_GPT2_GPT
bool "GPT2 (32-bit)"
default n
depends on RA_HAVE_GPT2
config RA_GPT3_GPT
bool "GPT3 (32-bit)"
default n
depends on RA_HAVE_GPT3
config RA_GPT4_GPT
bool "GPT4 (32-bit)"
default n
depends on RA_HAVE_GPT4
config RA_GPT5_GPT
bool "GPT5 (32-bit)"
default n
depends on RA_HAVE_GPT5
config RA_GPT6_GPT
bool "GPT6 (32-bit)"
default n
depends on RA_HAVE_GPT6
config RA_GPT7_GPT
bool "GPT7 (32-bit)"
default n
depends on RA_HAVE_GPT7
config RA_GPT8_GPT
bool "GPT8 (16-bit)"
default n
depends on RA_HAVE_GPT8
config RA_GPT9_GPT
bool "GPT9 (16-bit)"
default n
depends on RA_HAVE_GPT9
config RA_GPT10_GPT
bool "GPT10 (16-bit)"
default n
depends on RA_HAVE_GPT10
config RA_GPT11_GPT
bool "GPT11 (16-bit)"
default n
depends on RA_HAVE_GPT11
config RA_GPT12_GPT
bool "GPT12 (16-bit)"
default n
depends on RA_HAVE_GPT12
config RA_GPT13_GPT
bool "GPT13 (16-bit)"
default n
depends on RA_HAVE_GPT13
endif # RA_GPT_TIMER
endmenu # RA8M1 Peripheral Support

View file

@ -36,3 +36,7 @@ CHIP_CSRCS += ra_serial.c
CHIP_CSRCS += ra_lowputc.c
CHIP_CSRCS += ra_allocateheap.c
CHIP_CSRCS += ra_timerisr.c
ifeq ($(CONFIG_RA_GPT_TIMER),y)
CHIP_CSRCS += ra_gpt.c
endif

File diff suppressed because it is too large Load diff

694
arch/arm/src/ra8m1/ra_gpt.c Normal file
View file

@ -0,0 +1,694 @@
/****************************************************************************
* arch/arm/src/ra8m1/ra_gpt.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.
*
****************************************************************************/
/* GPT as a generic /dev/timerN driver (upper half: drivers/timers/timer.c).
*
* Each channel runs in saw-wave PWM mode (GTCR.MD = 0), counting up. GTCNT
* counts 0..GTPR and the overflow (GTST.TCFPO, event GPTn_OVF) is the timer
* expiry, so the period is (GTPR + 1) counts of the selected PCLKD divider.
*
* Notes from the RA8M1 User's Manual, section 21:
*
* - MD, TPCS, GTUDDTYC.UD and GTCNT must be changed only while the counter
* is stopped. GTCR.CST itself is synchronised to the count clock, so the
* counter may still tick (and raise an interrupt) after CST is cleared
* (21.10.4).
* - GTCNT must stay in 0 <= GTCNT <= GTPR (21.10.3).
* - There is no interrupt-enable bit for overflow in GTINTAD: the event is
* gated only by the ICU (IELSR routing + NVIC).
* - GTST flags are cleared by writing 0 to them (21.2.16).
* - The GPT clock is stopped after reset: clear the MSTPCRE bit first.
*/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <stdint.h>
#include <stdbool.h>
#include <errno.h>
#include <nuttx/arch.h>
#include <nuttx/irq.h>
#include <nuttx/timers/timer.h>
#include "arm_internal.h"
#include "ra_clockconfig.h"
#include "ra_icu.h"
#include "ra_gpt.h"
#include "hardware/ra8m1_gpt.h"
#include "hardware/ra8m1_memorymap.h"
#include "hardware/ra8m1_mstp.h"
#ifdef CONFIG_RA_GPT_TIMER
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* The GPT counts PCLKD (manual 21.1) */
#define GPT_CLOCK_HZ RA_PCLKD_FREQUENCY
/* Every GTST flag that is R/W*1 (TCFA-TCFPU, ADTR*F, PCF). A clear writes
* 0 to the target flag and 1 to the others (manual 21.2.16, note 1).
*/
#define GPT_GTST_W1_MASK 0x800f00ffu
/* Clock prescaler table: divider and its GTCR.TPCS[3:0] encoding */
struct ra_gpt_prescaler_s
{
uint16_t divider;
uint32_t tpcs;
};
/****************************************************************************
* Private Types
****************************************************************************/
struct ra_gpt_s
{
const struct timer_ops_s *ops; /* Must be first (timer_lowerhalf_s) */
uintptr_t base; /* Channel register base */
uint32_t mstp; /* MSTPCRE bit for this channel */
int irq; /* GPTn_OVF IRQ (ICU slot) */
uint8_t bits; /* 32 (GPT32) or 16 (GPT16) */
bool initialized; /* Clock enabled, IRQ attached */
bool started; /* Counter running */
tccb_t callback; /* Upper-half callback */
void *arg; /* Callback argument */
uint32_t timeout_us; /* Current timeout */
uint32_t divider; /* Selected PCLKD divider */
uint32_t tpcs; /* Selected GTCR.TPCS field */
uint32_t period; /* GTPR value */
};
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
static int ra_gpt_interrupt(int irq, void *context, void *arg);
static int ra_gpt_start(struct timer_lowerhalf_s *lower);
static int ra_gpt_stop(struct timer_lowerhalf_s *lower);
static int ra_gpt_getstatus(struct timer_lowerhalf_s *lower,
struct timer_status_s *status);
static int ra_gpt_settimeout(struct timer_lowerhalf_s *lower,
uint32_t timeout);
static void ra_gpt_setcallback(struct timer_lowerhalf_s *lower,
tccb_t callback, void *arg);
static int ra_gpt_maxtimeout(struct timer_lowerhalf_s *lower,
uint32_t *maxtimeout);
/****************************************************************************
* Private Data
****************************************************************************/
static const struct timer_ops_s g_ra_gpt_ops =
{
.start = ra_gpt_start,
.stop = ra_gpt_stop,
.getstatus = ra_gpt_getstatus,
.settimeout = ra_gpt_settimeout,
.setcallback = ra_gpt_setcallback,
.maxtimeout = ra_gpt_maxtimeout,
};
/* Finest divider first: the driver picks the first one whose range fits */
static const struct ra_gpt_prescaler_s g_prescalers[] =
{
{ 1, R_GPT_GTCR_TPCS_PCLKGPTNPCLKC_1 },
{ 2, R_GPT_GTCR_TPCS_PCLKGPTNPCLKC_2 },
{ 4, R_GPT_GTCR_TPCS_PCLKGPTNPCLKC_4 },
{ 8, R_GPT_GTCR_TPCS_PCLKGPTNPCLKC_8 },
{ 16, R_GPT_GTCR_TPCS_PCLKGPTNPCLKC_16 },
{ 32, R_GPT_GTCR_TPCS_PCLKGPTNPCLKC_32 },
{ 64, R_GPT_GTCR_TPCS_PCLKGPTNPCLKC_64 },
{ 256, R_GPT_GTCR_TPCS_PCLKGPTNPCLKC_256 },
{ 1024, R_GPT_GTCR_TPCS_PCLKGPTNPCLKC_1024 },
};
#define GPT_NPRESCALERS (sizeof(g_prescalers) / sizeof(g_prescalers[0]))
/* Per-channel state, only for the channels enabled in Kconfig. Channels
* 0-7 are GPT32, 8-13 are GPT16. The module-stop bit is MSTPCRE.MSTPE
* (31 - channel): GPT0-7 -> MSTPE31-24, GPT8-13 -> MSTPE23-18.
*/
#define RA_GPT_CHANNEL(n, w) \
{ \
.ops = &g_ra_gpt_ops, \
.base = R_GPT##n##_BASE, \
.mstp = (1u << (31 - (n))), \
.irq = GPT##n##_COUNTER_OVERFLOW, \
.bits = (w), \
}
#ifdef CONFIG_RA_GPT0_GPT
static struct ra_gpt_s g_gpt0 = RA_GPT_CHANNEL(0, 32);
#endif
#ifdef CONFIG_RA_GPT1_GPT
static struct ra_gpt_s g_gpt1 = RA_GPT_CHANNEL(1, 32);
#endif
#ifdef CONFIG_RA_GPT2_GPT
static struct ra_gpt_s g_gpt2 = RA_GPT_CHANNEL(2, 32);
#endif
#ifdef CONFIG_RA_GPT3_GPT
static struct ra_gpt_s g_gpt3 = RA_GPT_CHANNEL(3, 32);
#endif
#ifdef CONFIG_RA_GPT4_GPT
static struct ra_gpt_s g_gpt4 = RA_GPT_CHANNEL(4, 32);
#endif
#ifdef CONFIG_RA_GPT5_GPT
static struct ra_gpt_s g_gpt5 = RA_GPT_CHANNEL(5, 32);
#endif
#ifdef CONFIG_RA_GPT6_GPT
static struct ra_gpt_s g_gpt6 = RA_GPT_CHANNEL(6, 32);
#endif
#ifdef CONFIG_RA_GPT7_GPT
static struct ra_gpt_s g_gpt7 = RA_GPT_CHANNEL(7, 32);
#endif
#ifdef CONFIG_RA_GPT8_GPT
static struct ra_gpt_s g_gpt8 = RA_GPT_CHANNEL(8, 16);
#endif
#ifdef CONFIG_RA_GPT9_GPT
static struct ra_gpt_s g_gpt9 = RA_GPT_CHANNEL(9, 16);
#endif
#ifdef CONFIG_RA_GPT10_GPT
static struct ra_gpt_s g_gpt10 = RA_GPT_CHANNEL(10, 16);
#endif
#ifdef CONFIG_RA_GPT11_GPT
static struct ra_gpt_s g_gpt11 = RA_GPT_CHANNEL(11, 16);
#endif
#ifdef CONFIG_RA_GPT12_GPT
static struct ra_gpt_s g_gpt12 = RA_GPT_CHANNEL(12, 16);
#endif
#ifdef CONFIG_RA_GPT13_GPT
static struct ra_gpt_s g_gpt13 = RA_GPT_CHANNEL(13, 16);
#endif
/****************************************************************************
* Private Functions
****************************************************************************/
static inline uint32_t gpt_getreg(struct ra_gpt_s *priv, uint32_t offset)
{
return getreg32(priv->base + offset);
}
static inline void gpt_putreg(struct ra_gpt_s *priv, uint32_t offset,
uint32_t value)
{
putreg32(value, priv->base + offset);
}
/****************************************************************************
* Name: ra_gpt_lookup
****************************************************************************/
static struct ra_gpt_s *ra_gpt_lookup(int channel)
{
static struct ra_gpt_s * const channels[RA_GPT16_LAST + 1] =
{
#ifdef CONFIG_RA_GPT0_GPT
[0] = &g_gpt0,
#endif
#ifdef CONFIG_RA_GPT1_GPT
[1] = &g_gpt1,
#endif
#ifdef CONFIG_RA_GPT2_GPT
[2] = &g_gpt2,
#endif
#ifdef CONFIG_RA_GPT3_GPT
[3] = &g_gpt3,
#endif
#ifdef CONFIG_RA_GPT4_GPT
[4] = &g_gpt4,
#endif
#ifdef CONFIG_RA_GPT5_GPT
[5] = &g_gpt5,
#endif
#ifdef CONFIG_RA_GPT6_GPT
[6] = &g_gpt6,
#endif
#ifdef CONFIG_RA_GPT7_GPT
[7] = &g_gpt7,
#endif
#ifdef CONFIG_RA_GPT8_GPT
[8] = &g_gpt8,
#endif
#ifdef CONFIG_RA_GPT9_GPT
[9] = &g_gpt9,
#endif
#ifdef CONFIG_RA_GPT10_GPT
[10] = &g_gpt10,
#endif
#ifdef CONFIG_RA_GPT11_GPT
[11] = &g_gpt11,
#endif
#ifdef CONFIG_RA_GPT12_GPT
[12] = &g_gpt12,
#endif
#ifdef CONFIG_RA_GPT13_GPT
[13] = &g_gpt13,
#endif
};
if (channel < 0 || channel > RA_GPT16_LAST)
{
return NULL;
}
return channels[channel];
}
/****************************************************************************
* Name: ra_gpt_maxcount
*
* Description:
* Largest GTPR value: 0xffffffff for GPT32, 0xffff for GPT16.
****************************************************************************/
static inline uint32_t ra_gpt_maxcount(struct ra_gpt_s *priv)
{
return priv->bits == 32 ? 0xffffffffu : 0xffffu;
}
/****************************************************************************
* Name: ra_gpt_calc
*
* Description:
* Pick the finest PCLKD divider whose counter range holds timeout_us and
* compute GTPR. Saw-wave period is GTPR + 1 counts (manual 21.2.20).
*
****************************************************************************/
static int ra_gpt_calc(struct ra_gpt_s *priv, uint32_t timeout_us)
{
uint64_t ticks;
size_t i;
if (timeout_us == 0)
{
return -EINVAL;
}
for (i = 0; i < GPT_NPRESCALERS; i++)
{
ticks = ((uint64_t)timeout_us * GPT_CLOCK_HZ /
g_prescalers[i].divider) / 1000000ull;
if (ticks == 0)
{
ticks = 1;
}
if (ticks - 1 <= ra_gpt_maxcount(priv))
{
priv->divider = g_prescalers[i].divider;
priv->tpcs = g_prescalers[i].tpcs;
priv->period = (uint32_t)(ticks - 1);
priv->timeout_us = timeout_us;
return OK;
}
}
return -ERANGE;
}
/****************************************************************************
* Name: ra_gpt_hwstop / ra_gpt_hwstart
****************************************************************************/
static void ra_gpt_hwstop(struct ra_gpt_s *priv)
{
uint32_t regval;
regval = gpt_getreg(priv, R_GPT_GTCR_OFFSET);
gpt_putreg(priv, R_GPT_GTCR_OFFSET, regval & ~R_GPT_GTCR_CST);
/* CST is synchronised to the count clock: wait until it reads back 0
* before touching MD/TPCS/GTCNT. TODO: bound this loop.
*/
while ((gpt_getreg(priv, R_GPT_GTCR_OFFSET) & R_GPT_GTCR_CST) != 0);
}
static void ra_gpt_hwstart(struct ra_gpt_s *priv)
{
uint32_t regval;
regval = gpt_getreg(priv, R_GPT_GTCR_OFFSET);
gpt_putreg(priv, R_GPT_GTCR_OFFSET, regval | R_GPT_GTCR_CST);
}
/****************************************************************************
* Name: ra_gpt_configure
*
* Description:
* Program mode, clock, direction, period and counter (counter stopped).
* Follows Table 21.5 "periodic count operation in up-counting".
*
****************************************************************************/
static void ra_gpt_configure(struct ra_gpt_s *priv)
{
/* 1 + 3: saw-wave PWM mode (MD = 0) and prescaler */
gpt_putreg(priv, R_GPT_GTCR_OFFSET,
R_GPT_GTCR_MD_V000 | priv->tpcs);
/* 2: count direction up: force UD=1 first (UDF=1), then release UDF */
gpt_putreg(priv, R_GPT_GTUDDTYC_OFFSET,
R_GPT_GTUDDTYC_UD | R_GPT_GTUDDTYC_UDF);
gpt_putreg(priv, R_GPT_GTUDDTYC_OFFSET, R_GPT_GTUDDTYC_UD);
/* Enable GTPBR -> GTPR buffering (manual 21.2.16): a later
* same-prescaler ra_gpt_settimeout() can then reload the period
* through GTPBR alone (see there) instead of stopping the counter.
*/
gpt_putreg(priv, R_GPT_GTBER_OFFSET, R_GPT_GTBER_PR_V01);
/* 4 + 5: cycle and initial counter (GTCNT must be <= GTPR). GTPBR
* must be kept in sync with GTPR here too: with GTBER.PR enabled
* above, hardware auto-transfers whatever is in GTPBR into GTPR at
* every trough, including the very first one after this start/
* reconfigure -- an unwritten (power-on-reset garbage) GTPBR would
* silently corrupt GTPR at the end of the first cycle, well before
* any ra_gpt_settimeout() call ever touches GTPBR itself.
*/
gpt_putreg(priv, R_GPT_GTPR_OFFSET, priv->period);
gpt_putreg(priv, R_GPT_GTPBR_OFFSET, priv->period);
gpt_putreg(priv, R_GPT_GTCNT_OFFSET, 0);
/* Drop a stale overflow flag: write 0 to it, 1 to the other R/W*1 bits */
gpt_putreg(priv, R_GPT_GTST_OFFSET, GPT_GTST_W1_MASK & ~R_GPT_GTST_TCFPO);
}
/****************************************************************************
* Name: ra_gpt_interrupt
*
* Description:
* GPTn_OVF handler. Same contract as the other timer lower halves:
* the callback returns true to keep the timer running (optionally
* updating the next interval) and false to stop it.
*
****************************************************************************/
static int ra_gpt_interrupt(int irq, void *context, void *arg)
{
struct ra_gpt_s *priv = arg;
uint32_t next_us = 0;
/* Acknowledge in the ICU (IELSR.IR) and in the GPT (GTST.TCFPO) */
ra_clear_ir(irq);
gpt_putreg(priv, R_GPT_GTST_OFFSET, GPT_GTST_W1_MASK & ~R_GPT_GTST_TCFPO);
if (priv->callback != NULL)
{
if (priv->callback(&next_us, priv->arg))
{
if (next_us > 0 && next_us != priv->timeout_us)
{
uint32_t old_tpcs = priv->tpcs;
if (ra_gpt_calc(priv, next_us) == OK)
{
if (priv->tpcs == old_tpcs)
{
/* Same prescaler: reload through GTPBR instead
* of stopping the counter (see
* ra_gpt_settimeout()).
*/
gpt_putreg(priv, R_GPT_GTPBR_OFFSET, priv->period);
}
else
{
ra_gpt_hwstop(priv);
ra_gpt_configure(priv);
ra_gpt_hwstart(priv);
}
}
}
}
else
{
ra_gpt_stop((struct timer_lowerhalf_s *)priv);
}
}
return OK;
}
/****************************************************************************
* Name: ra_gpt_start / ra_gpt_stop
****************************************************************************/
static int ra_gpt_start(struct timer_lowerhalf_s *lower)
{
struct ra_gpt_s *priv = (struct ra_gpt_s *)lower;
irqstate_t flags;
if (priv->started)
{
return -EBUSY;
}
if (priv->timeout_us == 0)
{
return -EINVAL; /* settimeout() first */
}
flags = enter_critical_section();
ra_gpt_configure(priv);
up_enable_irq(priv->irq);
ra_gpt_hwstart(priv);
priv->started = true;
leave_critical_section(flags);
return OK;
}
static int ra_gpt_stop(struct timer_lowerhalf_s *lower)
{
struct ra_gpt_s *priv = (struct ra_gpt_s *)lower;
irqstate_t flags;
flags = enter_critical_section();
ra_gpt_hwstop(priv);
up_disable_irq(priv->irq);
priv->started = false;
leave_critical_section(flags);
return OK;
}
/****************************************************************************
* Name: ra_gpt_getstatus
****************************************************************************/
static int ra_gpt_getstatus(struct timer_lowerhalf_s *lower,
struct timer_status_s *status)
{
struct ra_gpt_s *priv = (struct ra_gpt_s *)lower;
uint64_t left_ticks;
irqstate_t flags;
flags = enter_critical_section();
status->flags = 0;
if (priv->started)
{
status->flags |= TCFLAGS_ACTIVE;
}
if (priv->callback != NULL)
{
status->flags |= TCFLAGS_HANDLER;
}
status->timeout = priv->timeout_us;
if (priv->started)
{
left_ticks = gpt_getreg(priv, R_GPT_GTPR_OFFSET) -
gpt_getreg(priv, R_GPT_GTCNT_OFFSET);
status->timeleft = (uint32_t)(left_ticks * priv->divider *
1000000ull / GPT_CLOCK_HZ);
}
else
{
/* The hardware is only programmed by start(): report the full
* timeout instead of the stale (reset or stopped) register values.
*/
status->timeleft = priv->timeout_us;
}
leave_critical_section(flags);
return OK;
}
/****************************************************************************
* Name: ra_gpt_settimeout
****************************************************************************/
static int ra_gpt_settimeout(struct timer_lowerhalf_s *lower,
uint32_t timeout)
{
struct ra_gpt_s *priv = (struct ra_gpt_s *)lower;
irqstate_t flags;
uint32_t old_tpcs;
int ret;
flags = enter_critical_section();
old_tpcs = priv->tpcs;
ret = ra_gpt_calc(priv, timeout);
if (ret == OK && priv->started)
{
if (priv->tpcs == old_tpcs)
{
/* Same prescaler: GTBER.PR (enabled in ra_gpt_configure())
* buffers GTPR through GTPBR, so hardware swaps it in at the
* next trough (manual 21.2.16/Table 21.5) -- the counter
* never stops and no edge is lost.
*/
gpt_putreg(priv, R_GPT_GTPBR_OFFSET, priv->period);
}
else
{
/* Prescaler changed: unlike GTPR, TPCS is not
* double-buffered, so this still needs the counter stopped
* (MD/TPCS/GTCNT may only change while it is, manual 21.10.4).
*/
ra_gpt_hwstop(priv);
ra_gpt_configure(priv);
ra_gpt_hwstart(priv);
}
}
leave_critical_section(flags);
return ret;
}
/****************************************************************************
* Name: ra_gpt_setcallback
****************************************************************************/
static void ra_gpt_setcallback(struct timer_lowerhalf_s *lower,
tccb_t callback, void *arg)
{
struct ra_gpt_s *priv = (struct ra_gpt_s *)lower;
irqstate_t flags;
flags = enter_critical_section();
priv->callback = callback;
priv->arg = arg;
leave_critical_section(flags);
}
/****************************************************************************
* Name: ra_gpt_maxtimeout
*
* Description:
* Longest timeout at the slowest divider, clamped to what a uint32_t
* microsecond count can hold.
*
****************************************************************************/
static int ra_gpt_maxtimeout(struct timer_lowerhalf_s *lower,
uint32_t *maxtimeout)
{
struct ra_gpt_s *priv = (struct ra_gpt_s *)lower;
uint64_t max_us;
max_us = ((uint64_t)ra_gpt_maxcount(priv) + 1) *
g_prescalers[GPT_NPRESCALERS - 1].divider * 1000000ull /
GPT_CLOCK_HZ;
*maxtimeout = max_us > UINT32_MAX ? UINT32_MAX : (uint32_t)max_us;
return OK;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: ra_gpt_timer_initialize
****************************************************************************/
int ra_gpt_timer_initialize(const char *devpath, int channel)
{
struct ra_gpt_s *priv = ra_gpt_lookup(channel);
int ret;
if (priv == NULL)
{
return -ENODEV; /* Channel not enabled in Kconfig */
}
if (!priv->initialized)
{
/* Release module stop (GPT is stopped after reset, manual 21.10.1)
* and dummy-read to make sure the write has landed.
*/
modifyreg32(R_MSTP_MSTPCRE, priv->mstp, 0);
getreg32(R_MSTP_MSTPCRE);
/* Registers are write-enabled after reset (GTWP.WP = 0). If a
* bootloader locked them, unlock with:
* putreg32(R_GPT_GTWP_PRKEY_V0XA5, base + R_GPT_GTWP_OFFSET);
*/
ret = irq_attach(priv->irq, ra_gpt_interrupt, priv);
if (ret < 0)
{
return ret;
}
priv->initialized = true;
}
return timer_register(devpath, (struct timer_lowerhalf_s *)priv) != NULL ?
OK : -EIO;
}
#endif /* CONFIG_RA_GPT_TIMER */

View file

@ -0,0 +1,87 @@
/****************************************************************************
* arch/arm/src/ra8m1/ra_gpt.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_RA8M1_RA_GPT_H
#define __ARCH_ARM_SRC_RA8M1_RA_GPT_H
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* GPT channels: GPT32 = channels 0-7 (32-bit), GPT16 = channels 8-13
* (16-bit).
*/
#define RA_GPT32_FIRST 0
#define RA_GPT32_LAST 7
#define RA_GPT16_FIRST 8
#define RA_GPT16_LAST 13
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
#ifndef __ASSEMBLY__
#ifdef __cplusplus
#define EXTERN extern "C"
extern "C"
{
#else
#define EXTERN extern
#endif
#ifdef CONFIG_RA_GPT_TIMER
/****************************************************************************
* Name: ra_gpt_timer_initialize
*
* Description:
* Bind a GPT channel to the upper-half timer driver and register it as
* a character device (e.g. "/dev/timer0").
*
* Input Parameters:
* devpath - The device path to register.
* channel - GPT channel number, 0-7 (GPT32) or 8-13 (GPT16). The
* channel must be enabled with CONFIG_RA_GPTn_GPT.
*
* Returned Value:
* Zero (OK) on success; a negated errno value on failure.
*
****************************************************************************/
int ra_gpt_timer_initialize(const char *devpath, int channel);
#endif /* CONFIG_RA_GPT_TIMER */
#undef EXTERN
#ifdef __cplusplus
}
#endif
#endif /* __ASSEMBLY__ */
#endif /* __ARCH_ARM_SRC_RA8M1_RA_GPT_H */

View file

@ -24,6 +24,7 @@
#include <nuttx/config.h>
#include <assert.h>
#include <stdint.h>
#include <nuttx/irq.h>
@ -33,6 +34,11 @@
#include "hardware/ra8m1_elc.h"
#include "ra_icu.h"
/* More events than IELSR slots is a configuration error */
static_assert(RA_IRQ_EVT_END <= NR_IRQS,
"Too many ICU events enabled for the IELSR slots");
/****************************************************************************
* Public Functions
****************************************************************************/
@ -86,6 +92,62 @@ void ra_attach_icu(void)
putreg32(EVENT_SCI9_TEI, R_ICU_IELSR(SCI9_TEI - RA_IRQ_FIRST));
putreg32(EVENT_SCI9_ERI, R_ICU_IELSR(SCI9_ERI - RA_IRQ_FIRST));
#endif
#ifdef CONFIG_RA_GPT0_GPT
putreg32(EVENT_GPT0_COUNTER_OVERFLOW,
R_ICU_IELSR(GPT0_COUNTER_OVERFLOW - RA_IRQ_FIRST));
#endif
#ifdef CONFIG_RA_GPT1_GPT
putreg32(EVENT_GPT1_COUNTER_OVERFLOW,
R_ICU_IELSR(GPT1_COUNTER_OVERFLOW - RA_IRQ_FIRST));
#endif
#ifdef CONFIG_RA_GPT2_GPT
putreg32(EVENT_GPT2_COUNTER_OVERFLOW,
R_ICU_IELSR(GPT2_COUNTER_OVERFLOW - RA_IRQ_FIRST));
#endif
#ifdef CONFIG_RA_GPT3_GPT
putreg32(EVENT_GPT3_COUNTER_OVERFLOW,
R_ICU_IELSR(GPT3_COUNTER_OVERFLOW - RA_IRQ_FIRST));
#endif
#ifdef CONFIG_RA_GPT4_GPT
putreg32(EVENT_GPT4_COUNTER_OVERFLOW,
R_ICU_IELSR(GPT4_COUNTER_OVERFLOW - RA_IRQ_FIRST));
#endif
#ifdef CONFIG_RA_GPT5_GPT
putreg32(EVENT_GPT5_COUNTER_OVERFLOW,
R_ICU_IELSR(GPT5_COUNTER_OVERFLOW - RA_IRQ_FIRST));
#endif
#ifdef CONFIG_RA_GPT6_GPT
putreg32(EVENT_GPT6_COUNTER_OVERFLOW,
R_ICU_IELSR(GPT6_COUNTER_OVERFLOW - RA_IRQ_FIRST));
#endif
#ifdef CONFIG_RA_GPT7_GPT
putreg32(EVENT_GPT7_COUNTER_OVERFLOW,
R_ICU_IELSR(GPT7_COUNTER_OVERFLOW - RA_IRQ_FIRST));
#endif
#ifdef CONFIG_RA_GPT8_GPT
putreg32(EVENT_GPT8_COUNTER_OVERFLOW,
R_ICU_IELSR(GPT8_COUNTER_OVERFLOW - RA_IRQ_FIRST));
#endif
#ifdef CONFIG_RA_GPT9_GPT
putreg32(EVENT_GPT9_COUNTER_OVERFLOW,
R_ICU_IELSR(GPT9_COUNTER_OVERFLOW - RA_IRQ_FIRST));
#endif
#ifdef CONFIG_RA_GPT10_GPT
putreg32(EVENT_GPT10_COUNTER_OVERFLOW,
R_ICU_IELSR(GPT10_COUNTER_OVERFLOW - RA_IRQ_FIRST));
#endif
#ifdef CONFIG_RA_GPT11_GPT
putreg32(EVENT_GPT11_COUNTER_OVERFLOW,
R_ICU_IELSR(GPT11_COUNTER_OVERFLOW - RA_IRQ_FIRST));
#endif
#ifdef CONFIG_RA_GPT12_GPT
putreg32(EVENT_GPT12_COUNTER_OVERFLOW,
R_ICU_IELSR(GPT12_COUNTER_OVERFLOW - RA_IRQ_FIRST));
#endif
#ifdef CONFIG_RA_GPT13_GPT
putreg32(EVENT_GPT13_COUNTER_OVERFLOW,
R_ICU_IELSR(GPT13_COUNTER_OVERFLOW - RA_IRQ_FIRST));
#endif
}
/****************************************************************************