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_ */