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