|
| 1 | +/* |
| 2 | + * Copyright (c) 2018 Xilinx, Inc. |
| 3 | + * SPDX-License-Identifier: Apache-2.0 |
| 4 | + */ |
| 5 | + |
| 6 | +#include <drivers/timer/system_timer.h> |
| 7 | +#include <sys_clock.h> |
| 8 | +#include "irq.h" |
| 9 | +#include "legacy_api.h" |
| 10 | + |
| 11 | +#define TIMER_FREQ CONFIG_SYS_CLOCK_TICKS_PER_SEC |
| 12 | + |
| 13 | +#if (CONFIG_XLNX_PSTTC_TIMER_INDEX == 0) |
| 14 | +#define TIMER_INPUT_CLKHZ DT_INST_0_CDNS_TTC_CLOCK_FREQUENCY |
| 15 | +#define TIMER_IRQ DT_INST_0_CDNS_TTC_IRQ_0 |
| 16 | +#define TIMER_BASEADDR DT_INST_0_CDNS_TTC_BASE_ADDRESS |
| 17 | +#else |
| 18 | +#error ("No timer is specified") |
| 19 | +#endif |
| 20 | + |
| 21 | +#define XTTCPS_CLK_CNTRL_OFFSET 0x00000000U /**< Clock Control Register */ |
| 22 | +#define XTTCPS_CNT_CNTRL_OFFSET 0x0000000CU /**< Counter Control Register*/ |
| 23 | +#define XTTCPS_COUNT_VALUE_OFFSET 0x00000018U /**< Current Counter Value */ |
| 24 | +#define XTTCPS_INTERVAL_VAL_OFFSET 0x00000024U /**< Interval Count Value */ |
| 25 | +#define XTTCPS_MATCH_0_OFFSET 0x00000030U /**< Match 1 value */ |
| 26 | +#define XTTCPS_MATCH_1_OFFSET 0x0000003CU /**< Match 2 value */ |
| 27 | +#define XTTCPS_MATCH_2_OFFSET 0x00000048U /**< Match 3 value */ |
| 28 | +#define XTTCPS_ISR_OFFSET 0x00000054U /**< Interrupt Status Register */ |
| 29 | +#define XTTCPS_IER_OFFSET 0x00000060U /**< Interrupt Enable Register */ |
| 30 | + |
| 31 | +/* Clock Control Register definitions */ |
| 32 | +#define XTTCPS_CLK_CNTRL_PS_EN_MASK 0x00000001U /**< Prescale enable */ |
| 33 | +#define XTTCPS_CLK_CNTRL_PS_VAL_MASK 0x0000001EU /**< Prescale value */ |
| 34 | +#define XTTCPS_CLK_CNTRL_PS_VAL_SHIFT 1U /**< Prescale shift */ |
| 35 | +#define XTTCPS_CLK_CNTRL_PS_DISABLE 16U /**< Prescale disable */ |
| 36 | +#define XTTCPS_CLK_CNTRL_SRC_MASK 0x00000020U /**< Clock source */ |
| 37 | +#define XTTCPS_CLK_CNTRL_EXT_EDGE_MASK 0x00000040U /**< External Clock edge */ |
| 38 | + |
| 39 | +/* Counter Control Register definitions */ |
| 40 | +#define XTTCPS_CNT_CNTRL_DIS_MASK 0x00000001U /**< Disable the counter */ |
| 41 | +#define XTTCPS_CNT_CNTRL_INT_MASK 0x00000002U /**< Interval mode */ |
| 42 | +#define XTTCPS_CNT_CNTRL_DECR_MASK 0x00000004U /**< Decrement mode */ |
| 43 | +#define XTTCPS_CNT_CNTRL_MATCH_MASK 0x00000008U /**< Match mode */ |
| 44 | +#define XTTCPS_CNT_CNTRL_RST_MASK 0x00000010U /**< Reset counter */ |
| 45 | +#define XTTCPS_CNT_CNTRL_EN_WAVE_MASK 0x00000020U /**< Enable waveform */ |
| 46 | +#define XTTCPS_CNT_CNTRL_POL_WAVE_MASK 0x00000040U /**< Waveform polarity */ |
| 47 | +#define XTTCPS_CNT_CNTRL_RESET_VALUE 0x00000021U /**< Reset value */ |
| 48 | + |
| 49 | +/* Interrupt register masks */ |
| 50 | +#define XTTCPS_IXR_INTERVAL_MASK 0x00000001U /**< Interval Interrupt */ |
| 51 | +#define XTTCPS_IXR_MATCH_0_MASK 0x00000002U /**< Match 1 Interrupt */ |
| 52 | +#define XTTCPS_IXR_MATCH_1_MASK 0x00000004U /**< Match 2 Interrupt */ |
| 53 | +#define XTTCPS_IXR_MATCH_2_MASK 0x00000008U /**< Match 3 Interrupt */ |
| 54 | +#define XTTCPS_IXR_CNT_OVR_MASK 0x00000010U /**< Counter Overflow */ |
| 55 | +#define XTTCPS_IXR_ALL_MASK 0x0000001FU /**< All valid Interrupts */ |
| 56 | + |
| 57 | +#define XTTC_MAX_INTERVAL_COUNT 0xFFFFFFFFU /**< Maximum value of interval counter */ |
| 58 | + |
| 59 | +static u32_t accumulated_cycles; |
| 60 | +static s32_t _sys_idle_elapsed_ticks = 1; |
| 61 | + |
| 62 | +static int xttc_calculate_interval(u32_t *interval, u8_t *prescaler) |
| 63 | +{ |
| 64 | + u32_t tmpinterval = 0; |
| 65 | + u8_t tmpprescaler = 0; |
| 66 | + unsigned int tmpval; |
| 67 | + |
| 68 | + tmpval = (u32_t)(TIMER_INPUT_CLKHZ / TIMER_FREQ); |
| 69 | + |
| 70 | + if (tmpval < (u32_t)65536U) { |
| 71 | + /* no prescaler is required */ |
| 72 | + tmpinterval = tmpval; |
| 73 | + tmpprescaler = 0; |
| 74 | + } else { |
| 75 | + for (tmpprescaler = 1U; tmpprescaler < 16; tmpprescaler++) { |
| 76 | + tmpval = (u32_t)(TIMER_INPUT_CLKHZ / |
| 77 | + (TIMER_FREQ * (1U << tmpprescaler))); |
| 78 | + if (tmpval < (u32_t)65536U) { |
| 79 | + tmpinterval = tmpval; |
| 80 | + break; |
| 81 | + } |
| 82 | + } |
| 83 | + } |
| 84 | + |
| 85 | + if (tmpinterval != 0) { |
| 86 | + *interval = tmpinterval; |
| 87 | + *prescaler = tmpprescaler; |
| 88 | + return 0; |
| 89 | + } |
| 90 | + |
| 91 | + /* TBD: Is there a way to adjust the sys clock parameters such as |
| 92 | + * ticks per sec if it failed to configure the timer as specified |
| 93 | + */ |
| 94 | + return -EINVAL; |
| 95 | +} |
| 96 | + |
| 97 | +/** |
| 98 | + * @brief System timer tick handler |
| 99 | + * |
| 100 | + * This routine handles the system clock tick interrupt. A TICK_EVENT event |
| 101 | + * is pushed onto the kernel stack. |
| 102 | + * |
| 103 | + * The symbol for this routine is either _timer_int_handler. |
| 104 | + * |
| 105 | + * @return N/A |
| 106 | + */ |
| 107 | +void _timer_int_handler(void *unused) |
| 108 | +{ |
| 109 | + ARG_UNUSED(unused); |
| 110 | + |
| 111 | + u32_t regval; |
| 112 | + |
| 113 | + regval = sys_read32(TIMER_BASEADDR + XTTCPS_ISR_OFFSET); |
| 114 | + accumulated_cycles += sys_clock_hw_cycles_per_tick(); |
| 115 | + z_clock_announce(_sys_idle_elapsed_ticks); |
| 116 | +} |
| 117 | + |
| 118 | +/** |
| 119 | + * @brief Initialize and enable the system clock |
| 120 | + * |
| 121 | + * This routine is used to program the systick to deliver interrupts at the |
| 122 | + * rate specified via the 'sys_clock_us_per_tick' global variable. |
| 123 | + * |
| 124 | + * @return 0 |
| 125 | + */ |
| 126 | +int z_clock_driver_init(struct device *device) |
| 127 | +{ |
| 128 | + int ret; |
| 129 | + u32_t interval; |
| 130 | + u8_t prescaler; |
| 131 | + u32_t regval; |
| 132 | + |
| 133 | + /* Stop timer */ |
| 134 | + sys_write32(XTTCPS_CNT_CNTRL_DIS_MASK, |
| 135 | + TIMER_BASEADDR + XTTCPS_CNT_CNTRL_OFFSET); |
| 136 | + |
| 137 | + /* Calculate prescaler */ |
| 138 | + ret = xttc_calculate_interval(&interval, &prescaler); |
| 139 | + if (ret < 0) { |
| 140 | + printk("Failed to calculate prescaler.\n"); |
| 141 | + return ret; |
| 142 | + } |
| 143 | + |
| 144 | + /* Reset registers */ |
| 145 | + sys_write32(XTTCPS_CNT_CNTRL_RESET_VALUE, |
| 146 | + TIMER_BASEADDR + XTTCPS_CNT_CNTRL_OFFSET); |
| 147 | + sys_write32(0, TIMER_BASEADDR + XTTCPS_CLK_CNTRL_OFFSET); |
| 148 | + sys_write32(0, TIMER_BASEADDR + XTTCPS_INTERVAL_VAL_OFFSET); |
| 149 | + sys_write32(0, TIMER_BASEADDR + XTTCPS_MATCH_0_OFFSET); |
| 150 | + sys_write32(0, TIMER_BASEADDR + XTTCPS_MATCH_1_OFFSET); |
| 151 | + sys_write32(0, TIMER_BASEADDR + XTTCPS_MATCH_2_OFFSET); |
| 152 | + sys_write32(0, TIMER_BASEADDR + XTTCPS_IER_OFFSET); |
| 153 | + sys_write32(XTTCPS_IXR_ALL_MASK, TIMER_BASEADDR + XTTCPS_ISR_OFFSET); |
| 154 | + /* Reset counter value */ |
| 155 | + regval = sys_read32(TIMER_BASEADDR + XTTCPS_CNT_CNTRL_OFFSET); |
| 156 | + regval |= XTTCPS_CNT_CNTRL_RST_MASK; |
| 157 | + sys_write32(regval, TIMER_BASEADDR + XTTCPS_CNT_CNTRL_OFFSET); |
| 158 | + |
| 159 | + /* Set options */ |
| 160 | + regval = sys_read32(TIMER_BASEADDR + XTTCPS_CNT_CNTRL_OFFSET); |
| 161 | + regval |= XTTCPS_CNT_CNTRL_INT_MASK; |
| 162 | + sys_write32(regval, TIMER_BASEADDR + XTTCPS_CNT_CNTRL_OFFSET); |
| 163 | + |
| 164 | + /* Set interval and prescaller */ |
| 165 | + sys_write32(interval, TIMER_BASEADDR + XTTCPS_INTERVAL_VAL_OFFSET); |
| 166 | + regval = (u32_t)((prescaler & 0xFU) << 1); |
| 167 | + sys_write32(regval, TIMER_BASEADDR + XTTCPS_CLK_CNTRL_OFFSET); |
| 168 | + |
| 169 | + /* Enable timer interrupt */ |
| 170 | + IRQ_CONNECT(TIMER_IRQ, 0, _timer_int_handler, 0, 0); |
| 171 | + irq_enable(TIMER_IRQ); |
| 172 | + regval = sys_read32(TIMER_BASEADDR + XTTCPS_IER_OFFSET); |
| 173 | + regval |= XTTCPS_IXR_INTERVAL_MASK; |
| 174 | + sys_write32(regval, TIMER_BASEADDR + XTTCPS_IER_OFFSET); |
| 175 | + |
| 176 | + /* Start timer */ |
| 177 | + regval = sys_read32(TIMER_BASEADDR + XTTCPS_CNT_CNTRL_OFFSET); |
| 178 | + regval &= (~XTTCPS_CNT_CNTRL_DIS_MASK); |
| 179 | + sys_write32(regval, TIMER_BASEADDR + XTTCPS_CNT_CNTRL_OFFSET); |
| 180 | + |
| 181 | + return 0; |
| 182 | +} |
| 183 | + |
| 184 | + |
| 185 | +/** |
| 186 | + * @brief Read the platform's timer hardware |
| 187 | + * |
| 188 | + * This routine returns the current time in terms of timer hardware clock |
| 189 | + * cycles. |
| 190 | + * |
| 191 | + * @return up counter of elapsed clock cycles |
| 192 | + */ |
| 193 | +u32_t z_timer_cycle_get_32(void) |
| 194 | +{ |
| 195 | + return accumulated_cycles; |
| 196 | +} |
0 commit comments