1 /* Copyright (C) 2023 BeagleBoard.org Foundation
2  * Copyright (C) 2023 S Prashanth
3  * Copyright (c) 2024 Texas Instruments Incorporated
4  *	Andrew Davis <afd@ti.com>
5  *
6  * SPDX-License-Identifier: Apache-2.0
7  */
8 
9 #include <zephyr/device.h>
10 #include <zephyr/drivers/timer/system_timer.h>
11 #include <zephyr/irq.h>
12 #include <zephyr/sys_clock.h>
13 #include <zephyr/kernel.h>
14 #include <zephyr/spinlock.h>
15 
16 #include "ti_dmtimer.h"
17 
18 #define DT_DRV_COMPAT ti_am654_timer
19 
20 #define TIMER_IRQ_NUM   DT_INST_IRQN(0)
21 #define TIMER_IRQ_PRIO  DT_INST_IRQ(0, priority)
22 #define TIMER_IRQ_FLAGS DT_INST_IRQ(0, flags)
23 
24 #if defined(CONFIG_TEST)
25 const int32_t z_sys_timer_irq_for_test = TIMER_IRQ_NUM;
26 #endif
27 
28 #define CYC_PER_TICK ((uint32_t)(sys_clock_hw_cycles_per_sec() / CONFIG_SYS_CLOCK_TICKS_PER_SEC))
29 
30 #define MAX_TICKS ((k_ticks_t)(UINT32_MAX / CYC_PER_TICK) - 1)
31 
32 #define DEV_CFG(_dev)  ((const struct ti_dm_timer_config *)(_dev)->config)
33 #define DEV_DATA(_dev) ((struct ti_dm_timer_data *)(_dev)->data)
34 
35 struct ti_dm_timer_config {
36 	DEVICE_MMIO_NAMED_ROM(reg_base);
37 };
38 
39 struct ti_dm_timer_data {
40 	DEVICE_MMIO_NAMED_RAM(reg_base);
41 	struct k_spinlock lock;
42 	uint32_t last_cycle;
43 };
44 
45 static const struct device *systick_timer_dev;
46 
47 #define TI_DM_TIMER_MASK(reg)  TI_DM_TIMER_##reg##_MASK
48 #define TI_DM_TIMER_SHIFT(reg) TI_DM_TIMER_##reg##_SHIFT
49 
50 #define TI_DM_TIMER_READ(dev, reg) sys_read32(DEVICE_MMIO_GET(dev) + TI_DM_TIMER_##reg)
51 #define TI_DM_TIMER_WRITE(dev, data, reg, bits)                                                    \
52 	ti_dm_timer_write_masks(data, DEVICE_MMIO_GET(dev) + TI_DM_TIMER_##reg,                    \
53 				TI_DM_TIMER_MASK(reg##_##bits), TI_DM_TIMER_SHIFT(reg##_##bits))
54 
ti_dm_timer_write_masks(uint32_t data,uint32_t reg,uint32_t mask,uint32_t shift)55 static void ti_dm_timer_write_masks(uint32_t data, uint32_t reg, uint32_t mask, uint32_t shift)
56 {
57 	uint32_t reg_val;
58 
59 	reg_val = sys_read32(reg);
60 	reg_val = (reg_val & ~(mask)) | (data << shift);
61 	sys_write32(reg_val, reg);
62 }
63 
ti_dmtimer_isr(void * param)64 static void ti_dmtimer_isr(void *param)
65 {
66 	ARG_UNUSED(param);
67 
68 	struct ti_dm_timer_data *data = systick_timer_dev->data;
69 
70 	/* If no pending event */
71 	if (!TI_DM_TIMER_READ(systick_timer_dev, IRQSTATUS)) {
72 		return;
73 	}
74 
75 	k_spinlock_key_t key = k_spin_lock(&data->lock);
76 
77 	uint32_t curr_cycle = TI_DM_TIMER_READ(systick_timer_dev, TCRR);
78 	uint32_t delta_cycles = curr_cycle - data->last_cycle;
79 	uint32_t delta_ticks = delta_cycles / CYC_PER_TICK;
80 
81 	data->last_cycle = curr_cycle;
82 
83 	/* ACK match interrupt */
84 	TI_DM_TIMER_WRITE(systick_timer_dev, 1, IRQSTATUS, MAT_IT_FLAG);
85 
86 	if (!IS_ENABLED(CONFIG_TICKLESS_KERNEL)) {
87 		/* Setup next match time */
88 		uint64_t next_cycle = curr_cycle + CYC_PER_TICK;
89 
90 		TI_DM_TIMER_WRITE(systick_timer_dev, next_cycle, TMAR, COMPARE_VALUE);
91 	}
92 
93 	k_spin_unlock(&data->lock, key);
94 
95 	sys_clock_announce(delta_ticks);
96 }
97 
sys_clock_set_timeout(int32_t ticks,bool idle)98 void sys_clock_set_timeout(int32_t ticks, bool idle)
99 {
100 	ARG_UNUSED(idle);
101 
102 	struct ti_dm_timer_data *data = systick_timer_dev->data;
103 
104 	if (!IS_ENABLED(CONFIG_TICKLESS_KERNEL)) {
105 		/* Not supported on tickful kernels */
106 		return;
107 	}
108 
109 	ticks = (ticks == K_TICKS_FOREVER) ? MAX_TICKS : ticks;
110 	ticks = CLAMP(ticks, 1, (int32_t)MAX_TICKS);
111 
112 	k_spinlock_key_t key = k_spin_lock(&data->lock);
113 
114 	/* Setup next match time */
115 	uint32_t curr_cycle = TI_DM_TIMER_READ(systick_timer_dev, TCRR);
116 	uint32_t next_cycle = curr_cycle + (ticks * CYC_PER_TICK);
117 
118 	TI_DM_TIMER_WRITE(systick_timer_dev, next_cycle, TMAR, COMPARE_VALUE);
119 
120 	k_spin_unlock(&data->lock, key);
121 }
122 
sys_clock_cycle_get_32(void)123 uint32_t sys_clock_cycle_get_32(void)
124 {
125 	struct ti_dm_timer_data *data = systick_timer_dev->data;
126 
127 	k_spinlock_key_t key = k_spin_lock(&data->lock);
128 
129 	uint32_t curr_cycle = TI_DM_TIMER_READ(systick_timer_dev, TCRR);
130 
131 	k_spin_unlock(&data->lock, key);
132 
133 	return curr_cycle;
134 }
135 
sys_clock_elapsed(void)136 unsigned int sys_clock_elapsed(void)
137 {
138 	struct ti_dm_timer_data *data = systick_timer_dev->data;
139 
140 	if (!IS_ENABLED(CONFIG_TICKLESS_KERNEL)) {
141 		/* Always return 0 for tickful kernel system */
142 		return 0;
143 	}
144 
145 	k_spinlock_key_t key = k_spin_lock(&data->lock);
146 
147 	uint32_t curr_cycle = TI_DM_TIMER_READ(systick_timer_dev, TCRR);
148 	uint32_t delta_cycles = curr_cycle - data->last_cycle;
149 	uint32_t delta_ticks = delta_cycles / CYC_PER_TICK;
150 
151 	k_spin_unlock(&data->lock, key);
152 
153 	return delta_ticks;
154 }
155 
sys_clock_driver_init(void)156 static int sys_clock_driver_init(void)
157 {
158 	struct ti_dm_timer_data *data;
159 
160 	systick_timer_dev = DEVICE_DT_GET(DT_DRV_INST(0));
161 
162 	data = systick_timer_dev->data;
163 
164 	data->last_cycle = 0;
165 
166 	DEVICE_MMIO_NAMED_MAP(systick_timer_dev, reg_base, K_MEM_CACHE_NONE);
167 
168 	IRQ_CONNECT(TIMER_IRQ_NUM, TIMER_IRQ_PRIO, ti_dmtimer_isr, NULL, TIMER_IRQ_FLAGS);
169 
170 	/* Disable prescalar */
171 	TI_DM_TIMER_WRITE(systick_timer_dev, 0, TCLR, PRE);
172 
173 	/* Select autoreload mode */
174 	TI_DM_TIMER_WRITE(systick_timer_dev, 1, TCLR, AR);
175 
176 	/* Enable match interrupt */
177 	TI_DM_TIMER_WRITE(systick_timer_dev, 1, IRQENABLE_SET, MAT_EN_FLAG);
178 
179 	/* Load timer counter value */
180 	TI_DM_TIMER_WRITE(systick_timer_dev, 0, TCRR, TIMER_COUNTER);
181 
182 	/* Load timer load value */
183 	TI_DM_TIMER_WRITE(systick_timer_dev, 0, TLDR, LOAD_VALUE);
184 
185 	/* Load timer compare value */
186 	TI_DM_TIMER_WRITE(systick_timer_dev, CYC_PER_TICK, TMAR, COMPARE_VALUE);
187 
188 	/* Enable compare mode */
189 	TI_DM_TIMER_WRITE(systick_timer_dev, 1, TCLR, CE);
190 
191 	/* Start the timer */
192 	TI_DM_TIMER_WRITE(systick_timer_dev, 1, TCLR, ST);
193 
194 	irq_enable(TIMER_IRQ_NUM);
195 
196 	return 0;
197 }
198 
199 #define TI_DM_TIMER(n)                                                                             \
200 	static struct ti_dm_timer_data ti_dm_timer_data_##n;                                       \
201 	static const struct ti_dm_timer_config ti_dm_timer_config_##n = {                          \
202 		DEVICE_MMIO_NAMED_ROM_INIT(reg_base, DT_DRV_INST(n)),                              \
203 	};                                                                                         \
204 	DEVICE_DT_INST_DEFINE(n, NULL, NULL, &ti_dm_timer_data_##n, &ti_dm_timer_config_##n,       \
205 			      PRE_KERNEL_2, CONFIG_SYSTEM_CLOCK_INIT_PRIORITY, NULL);
206 
207 DT_INST_FOREACH_STATUS_OKAY(TI_DM_TIMER);
208 
209 SYS_INIT(sys_clock_driver_init, PRE_KERNEL_2, CONFIG_SYSTEM_CLOCK_INIT_PRIORITY);
210