1 /*
2  * Copyright (c) 2020 Stephanos Ioannidis <root@stephanos.io>
3  * Copyright (c) 2018 Xilinx, Inc.
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 #define DT_DRV_COMPAT xlnx_ttcps
9 
10 #include <soc.h>
11 #include <drivers/timer/system_timer.h>
12 #include "xlnx_psttc_timer_priv.h"
13 
14 #define TIMER_INDEX		CONFIG_XLNX_PSTTC_TIMER_INDEX
15 
16 #define TIMER_IRQ		DT_INST_IRQN(0)
17 #define TIMER_BASE_ADDR		DT_INST_REG_ADDR(0)
18 #define TIMER_CLOCK_FREQUECY	DT_INST_PROP(0, clock_frequency)
19 
20 #define TICKS_PER_SEC		CONFIG_SYS_CLOCK_TICKS_PER_SEC
21 #define CYCLES_PER_SEC		TIMER_CLOCK_FREQUECY
22 #define CYCLES_PER_TICK		(CYCLES_PER_SEC / TICKS_PER_SEC)
23 
24 /*
25  * CYCLES_NEXT_MIN must be large enough to ensure that the timer does not miss
26  * interrupts.  This value was conservatively set using the trial and error
27  * method, and there is room for improvement.
28  */
29 #define CYCLES_NEXT_MIN		(10000)
30 #define CYCLES_NEXT_MAX		(XTTC_MAX_INTERVAL_COUNT)
31 
32 BUILD_ASSERT(TIMER_CLOCK_FREQUECY ==
33 			CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC,
34 	     "Configured system timer frequency does not match the TTC "
35 	     "clock frequency in the device tree");
36 
37 BUILD_ASSERT(CYCLES_PER_SEC >= TICKS_PER_SEC,
38 	     "Timer clock frequency must be greater than the system tick "
39 	     "frequency");
40 
41 BUILD_ASSERT((CYCLES_PER_SEC % TICKS_PER_SEC) == 0,
42 	     "Timer clock frequency is not divisible by the system tick "
43 	     "frequency");
44 
45 #ifdef CONFIG_TICKLESS_KERNEL
46 static uint32_t last_cycles;
47 #endif
48 
read_count(void)49 static uint32_t read_count(void)
50 {
51 	/* Read current counter value */
52 	return sys_read32(TIMER_BASE_ADDR + XTTCPS_COUNT_VALUE_OFFSET);
53 }
54 
update_match(uint32_t cycles,uint32_t match)55 static void update_match(uint32_t cycles, uint32_t match)
56 {
57 	uint32_t delta = match - cycles;
58 
59 	/* Ensure that the match value meets the minimum timing requirements */
60 	if (delta < CYCLES_NEXT_MIN) {
61 		match += CYCLES_NEXT_MIN - delta;
62 	}
63 
64 	/* Write counter match value for interrupt generation */
65 	sys_write32(match, TIMER_BASE_ADDR + XTTCPS_MATCH_0_OFFSET);
66 }
67 
ttc_isr(const void * arg)68 static void ttc_isr(const void *arg)
69 {
70 	uint32_t cycles;
71 	uint32_t ticks;
72 
73 	ARG_UNUSED(arg);
74 
75 	/* Acknowledge interrupt */
76 	sys_read32(TIMER_BASE_ADDR + XTTCPS_ISR_OFFSET);
77 
78 	/* Read counter value */
79 	cycles = read_count();
80 
81 #ifdef CONFIG_TICKLESS_KERNEL
82 	/* Calculate the number of ticks since last announcement  */
83 	ticks = (cycles - last_cycles) / CYCLES_PER_TICK;
84 
85 	/* Update last cycles count */
86 	last_cycles = cycles;
87 #else
88 	/* Update counter match value for the next interrupt */
89 	update_match(cycles, cycles + CYCLES_PER_TICK);
90 
91 	/* Advance tick count by 1 */
92 	ticks = 1;
93 #endif
94 
95 	/* Announce to the kernel*/
96 	sys_clock_announce(ticks);
97 }
98 
sys_clock_driver_init(const struct device * dev)99 int sys_clock_driver_init(const struct device *dev)
100 {
101 	uint32_t reg_val;
102 	ARG_UNUSED(dev);
103 
104 	/* Stop timer */
105 	sys_write32(XTTCPS_CNT_CNTRL_DIS_MASK,
106 		    TIMER_BASE_ADDR + XTTCPS_CNT_CNTRL_OFFSET);
107 
108 #ifdef CONFIG_TICKLESS_KERNEL
109 	/* Initialise internal states */
110 	last_cycles = 0;
111 #endif
112 
113 	/* Initialise timer registers */
114 	sys_write32(XTTCPS_CNT_CNTRL_RESET_VALUE,
115 		    TIMER_BASE_ADDR + XTTCPS_CNT_CNTRL_OFFSET);
116 	sys_write32(0, TIMER_BASE_ADDR + XTTCPS_CLK_CNTRL_OFFSET);
117 	sys_write32(0, TIMER_BASE_ADDR + XTTCPS_INTERVAL_VAL_OFFSET);
118 	sys_write32(0, TIMER_BASE_ADDR + XTTCPS_MATCH_0_OFFSET);
119 	sys_write32(0, TIMER_BASE_ADDR + XTTCPS_MATCH_1_OFFSET);
120 	sys_write32(0, TIMER_BASE_ADDR + XTTCPS_MATCH_2_OFFSET);
121 	sys_write32(0, TIMER_BASE_ADDR + XTTCPS_IER_OFFSET);
122 	sys_write32(XTTCPS_IXR_ALL_MASK, TIMER_BASE_ADDR + XTTCPS_ISR_OFFSET);
123 
124 	/* Reset counter value */
125 	reg_val = sys_read32(TIMER_BASE_ADDR + XTTCPS_CNT_CNTRL_OFFSET);
126 	reg_val |= XTTCPS_CNT_CNTRL_RST_MASK;
127 	sys_write32(reg_val, TIMER_BASE_ADDR + XTTCPS_CNT_CNTRL_OFFSET);
128 
129 	/* Set match mode */
130 	reg_val = sys_read32(TIMER_BASE_ADDR + XTTCPS_CNT_CNTRL_OFFSET);
131 	reg_val |= XTTCPS_CNT_CNTRL_MATCH_MASK;
132 	sys_write32(reg_val, TIMER_BASE_ADDR + XTTCPS_CNT_CNTRL_OFFSET);
133 
134 	/* Set initial timeout */
135 	reg_val = IS_ENABLED(CONFIG_TICKLESS_KERNEL) ?
136 			CYCLES_NEXT_MAX : CYCLES_PER_TICK;
137 	sys_write32(reg_val, TIMER_BASE_ADDR + XTTCPS_MATCH_0_OFFSET);
138 
139 	/* Connect timer interrupt */
140 	IRQ_CONNECT(TIMER_IRQ, 0, ttc_isr, 0, 0);
141 	irq_enable(TIMER_IRQ);
142 
143 	/* Enable timer interrupt */
144 	reg_val = sys_read32(TIMER_BASE_ADDR + XTTCPS_IER_OFFSET);
145 	reg_val |= XTTCPS_IXR_MATCH_0_MASK;
146 	sys_write32(reg_val, TIMER_BASE_ADDR + XTTCPS_IER_OFFSET);
147 
148 	/* Start timer */
149 	reg_val = sys_read32(TIMER_BASE_ADDR + XTTCPS_CNT_CNTRL_OFFSET);
150 	reg_val &= (~XTTCPS_CNT_CNTRL_DIS_MASK);
151 	sys_write32(reg_val, TIMER_BASE_ADDR + XTTCPS_CNT_CNTRL_OFFSET);
152 
153 	return 0;
154 }
155 
sys_clock_set_timeout(int32_t ticks,bool idle)156 void sys_clock_set_timeout(int32_t ticks, bool idle)
157 {
158 #ifdef CONFIG_TICKLESS_KERNEL
159 	uint32_t cycles;
160 	uint32_t next_cycles;
161 
162 	/* Read counter value */
163 	cycles = read_count();
164 
165 	/* Calculate timeout counter value */
166 	if (ticks == K_TICKS_FOREVER) {
167 		next_cycles = cycles + CYCLES_NEXT_MAX;
168 	} else {
169 		next_cycles = cycles + ((uint32_t)ticks * CYCLES_PER_TICK);
170 	}
171 
172 	/* Set match value for the next interrupt */
173 	update_match(cycles, next_cycles);
174 #endif
175 }
176 
sys_clock_elapsed(void)177 uint32_t sys_clock_elapsed(void)
178 {
179 #ifdef CONFIG_TICKLESS_KERNEL
180 	uint32_t cycles;
181 
182 	/* Read counter value */
183 	cycles = read_count();
184 
185 	/* Return the number of ticks since last announcement */
186 	return (cycles - last_cycles) / CYCLES_PER_TICK;
187 #else
188 	/* Always return 0 for tickful operation */
189 	return 0;
190 #endif
191 }
192 
sys_clock_cycle_get_32(void)193 uint32_t sys_clock_cycle_get_32(void)
194 {
195 	/* Return the current counter value */
196 	return read_count();
197 }
198