Line data Source code
1 0 : /*
2 : * Copyright (c) 2021 IoT.bzh
3 : *
4 : * SPDX-License-Identifier: Apache-2.0
5 : */
6 :
7 : #ifndef ZEPHYR_INCLUDE_ARCH_ARM_CORTEX_A_R_TIMER_H_
8 : #define ZEPHYR_INCLUDE_ARCH_ARM_CORTEX_A_R_TIMER_H_
9 :
10 : #ifdef CONFIG_ARM_ARCH_TIMER
11 :
12 : #ifndef _ASMLANGUAGE
13 :
14 : #include <zephyr/drivers/timer/arm_arch_timer.h>
15 : #include <zephyr/sys/device_mmio.h>
16 : #include <zephyr/types.h>
17 :
18 : #ifdef __cplusplus
19 : extern "C" {
20 : #endif
21 :
22 : #define ARM_ARCH_TIMER_BASE DT_REG_ADDR_BY_IDX(ARM_TIMER_NODE, 0)
23 : #define ARM_ARCH_TIMER_IRQ ARM_TIMER_VIRTUAL_IRQ
24 : #define ARM_ARCH_TIMER_PRIO ARM_TIMER_VIRTUAL_PRIO
25 : #define ARM_ARCH_TIMER_FLAGS ARM_TIMER_VIRTUAL_FLAGS
26 :
27 : #define TIMER_CNT_LOWER 0x00
28 : #define TIMER_CNT_UPPER 0x04
29 : #define TIMER_CTRL 0x08
30 : #define TIMER_ISR 0x0c
31 : #define TIMER_CMP_LOWER 0x10
32 : #define TIMER_CMP_UPPER 0x14
33 :
34 : #define TIMER_IRQ_ENABLE BIT(2)
35 : #define TIMER_COMP_ENABLE BIT(1)
36 : #define TIMER_ENABLE BIT(0)
37 :
38 : #define TIMER_ISR_EVENT_FLAG BIT(0)
39 :
40 : DEVICE_MMIO_TOPLEVEL_STATIC(timer_regs, ARM_TIMER_NODE);
41 :
42 : #define TIMER_REG_GET(offs) (DEVICE_MMIO_TOPLEVEL_GET(timer_regs) + offs)
43 :
44 : static ALWAYS_INLINE void arm_arch_timer_init(void)
45 : {
46 : DEVICE_MMIO_TOPLEVEL_MAP(timer_regs, K_MEM_CACHE_NONE);
47 : }
48 :
49 : static ALWAYS_INLINE void arm_arch_timer_set_compare(uint64_t val)
50 : {
51 : uint32_t lower = (uint32_t)val;
52 : uint32_t upper = (uint32_t)(val >> 32);
53 : uint32_t ctrl;
54 :
55 : /* Disable IRQ and comparator */
56 : ctrl = sys_read32(TIMER_REG_GET(TIMER_CTRL));
57 : ctrl &= ~(TIMER_COMP_ENABLE | TIMER_IRQ_ENABLE);
58 : sys_write32(ctrl, TIMER_REG_GET(TIMER_CTRL));
59 :
60 : sys_write32(lower, TIMER_REG_GET(TIMER_CMP_LOWER));
61 : sys_write32(upper, TIMER_REG_GET(TIMER_CMP_UPPER));
62 :
63 : /* enable comparator back, let set_irq_mask enabling the IRQ again */
64 : ctrl |= TIMER_COMP_ENABLE;
65 : sys_write32(ctrl, TIMER_REG_GET(TIMER_CTRL));
66 : }
67 :
68 : #if defined(CONFIG_ARM_ARCH_TIMER_ERRATUM_740657)
69 :
70 : /*
71 : * R/W access to the event flag register is required for the timer errata
72 : * 740657 workaround -> comp. ISR implementation in arm_arch_timer.c.
73 : * This functionality is not present in the aarch64 implementation of the
74 : * ARM global timer access functions.
75 : *
76 : * comp. ARM Cortex-A9 processors Software Developers Errata Notice,
77 : * ARM document ID032315.
78 : */
79 :
80 : static ALWAYS_INLINE uint8_t arm_arch_timer_get_int_status(void)
81 : {
82 : return (uint8_t)(sys_read32(TIMER_REG_GET(TIMER_ISR)) & TIMER_ISR_EVENT_FLAG);
83 : }
84 :
85 : static ALWAYS_INLINE void arm_arch_timer_clear_int_status(void)
86 : {
87 : sys_write32(TIMER_ISR_EVENT_FLAG, TIMER_REG_GET(TIMER_ISR));
88 : }
89 :
90 : #endif /* CONFIG_ARM_ARCH_TIMER_ERRATUM_740657 */
91 :
92 : static ALWAYS_INLINE void arm_arch_timer_enable(bool enable)
93 : {
94 : uint32_t ctrl;
95 :
96 : ctrl = sys_read32(TIMER_REG_GET(TIMER_CTRL));
97 : if (enable) {
98 : ctrl |= TIMER_ENABLE;
99 : } else {
100 : ctrl &= ~TIMER_ENABLE;
101 : }
102 :
103 : sys_write32(ctrl, TIMER_REG_GET(TIMER_CTRL));
104 : }
105 :
106 : static ALWAYS_INLINE void arm_arch_timer_set_irq_mask(bool mask)
107 : {
108 : uint32_t ctrl;
109 :
110 : ctrl = sys_read32(TIMER_REG_GET(TIMER_CTRL));
111 : if (mask) {
112 : ctrl &= ~TIMER_IRQ_ENABLE;
113 : } else {
114 : ctrl |= TIMER_IRQ_ENABLE;
115 : sys_write32(1, TIMER_REG_GET(TIMER_ISR));
116 : }
117 : sys_write32(ctrl, TIMER_REG_GET(TIMER_CTRL));
118 : }
119 :
120 : static ALWAYS_INLINE uint64_t arm_arch_timer_count(void)
121 : {
122 : uint32_t lower;
123 : uint32_t upper, upper_saved;
124 :
125 : /* To get the value from the Global Timer Counter register proceed
126 : * as follows:
127 : * 1. Read the upper 32-bit timer counter register.
128 : * 2. Read the lower 32-bit timer counter register.
129 : * 3. Read the upper 32-bit timer counter register again. If the value
130 : * is different to the 32-bit upper value read previously,
131 : * go back to step 2.
132 : * Otherwise the 64-bit timer counter value is correct.
133 : */
134 : upper = sys_read32(TIMER_REG_GET(TIMER_CNT_UPPER));
135 : do {
136 : upper_saved = upper;
137 : lower = sys_read32(TIMER_REG_GET(TIMER_CNT_LOWER));
138 : upper = sys_read32(TIMER_REG_GET(TIMER_CNT_UPPER));
139 : } while (upper != upper_saved);
140 :
141 : return ((uint64_t)upper) << 32 | lower;
142 : }
143 :
144 : #ifdef __cplusplus
145 : }
146 : #endif
147 :
148 : #endif /* _ASMLANGUAGE */
149 :
150 : #endif /* CONFIG_ARM_ARCH_TIMER */
151 :
152 : #endif /* ZEPHYR_INCLUDE_ARCH_ARM_CORTEX_A_R_TIMER_H_ */
|