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