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