xref: /qemu/hw/timer/grlib_gptimer.c (revision e3d08143)
1 /*
2  * QEMU GRLIB GPTimer Emulator
3  *
4  * SPDX-License-Identifier: MIT
5  *
6  * Copyright (c) 2010-2024 AdaCore
7  *
8  * Permission is hereby granted, free of charge, to any person obtaining a copy
9  * of this software and associated documentation files (the "Software"), to deal
10  * in the Software without restriction, including without limitation the rights
11  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12  * copies of the Software, and to permit persons to whom the Software is
13  * furnished to do so, subject to the following conditions:
14  *
15  * The above copyright notice and this permission notice shall be included in
16  * all copies or substantial portions of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24  * THE SOFTWARE.
25  */
26 
27 #include "qemu/osdep.h"
28 #include "hw/timer/grlib_gptimer.h"
29 #include "hw/sysbus.h"
30 #include "qemu/timer.h"
31 #include "hw/irq.h"
32 #include "hw/ptimer.h"
33 #include "hw/qdev-properties.h"
34 #include "qemu/module.h"
35 
36 #include "trace.h"
37 #include "qom/object.h"
38 
39 #define UNIT_REG_SIZE    16     /* Size of memory mapped regs for the unit */
40 #define GPTIMER_REG_SIZE 16     /* Size of memory mapped regs for a GPTimer */
41 
42 #define GPTIMER_MAX_TIMERS 8
43 
44 /* GPTimer Config register fields */
45 #define GPTIMER_ENABLE      (1 << 0)
46 #define GPTIMER_RESTART     (1 << 1)
47 #define GPTIMER_LOAD        (1 << 2)
48 #define GPTIMER_INT_ENABLE  (1 << 3)
49 #define GPTIMER_INT_PENDING (1 << 4)
50 #define GPTIMER_CHAIN       (1 << 5) /* Not supported */
51 #define GPTIMER_DEBUG_HALT  (1 << 6) /* Not supported */
52 
53 /* Memory mapped register offsets */
54 #define SCALER_OFFSET         0x00
55 #define SCALER_RELOAD_OFFSET  0x04
56 #define CONFIG_OFFSET         0x08
57 #define COUNTER_OFFSET        0x00
58 #define COUNTER_RELOAD_OFFSET 0x04
59 #define TIMER_BASE            0x10
60 
61 OBJECT_DECLARE_SIMPLE_TYPE(GPTimerUnit, GRLIB_GPTIMER)
62 
63 typedef struct GPTimer     GPTimer;
64 
65 struct GPTimer {
66     struct ptimer_state *ptimer;
67 
68     qemu_irq     irq;
69     int          id;
70     GPTimerUnit *unit;
71 
72     /* registers */
73     uint32_t counter;
74     uint32_t reload;
75     uint32_t config;
76 };
77 
78 struct GPTimerUnit {
79     SysBusDevice  parent_obj;
80 
81     MemoryRegion iomem;
82 
83     uint32_t nr_timers;         /* Number of timers available */
84     uint32_t freq_hz;           /* System frequency */
85     uint32_t irq_line;          /* Base irq line */
86 
87     GPTimer *timers;
88 
89     /* registers */
90     uint32_t scaler;
91     uint32_t reload;
92     uint32_t config;
93 };
94 
grlib_gptimer_tx_begin(GPTimer * timer)95 static void grlib_gptimer_tx_begin(GPTimer *timer)
96 {
97     ptimer_transaction_begin(timer->ptimer);
98 }
99 
grlib_gptimer_tx_commit(GPTimer * timer)100 static void grlib_gptimer_tx_commit(GPTimer *timer)
101 {
102     ptimer_transaction_commit(timer->ptimer);
103 }
104 
105 /* Must be called within grlib_gptimer_tx_begin/commit block */
grlib_gptimer_enable(GPTimer * timer)106 static void grlib_gptimer_enable(GPTimer *timer)
107 {
108     assert(timer != NULL);
109 
110 
111     ptimer_stop(timer->ptimer);
112 
113     if (!(timer->config & GPTIMER_ENABLE)) {
114         /* Timer disabled */
115         trace_grlib_gptimer_disabled(timer->id, timer->config);
116         return;
117     }
118 
119     /* ptimer is triggered when the counter reach 0 but GPTimer is triggered at
120        underflow. Set count + 1 to simulate the GPTimer behavior. */
121 
122     trace_grlib_gptimer_enable(timer->id, timer->counter);
123 
124     ptimer_set_count(timer->ptimer, (uint64_t)timer->counter + 1);
125     ptimer_run(timer->ptimer, 1);
126 }
127 
128 /* Must be called within grlib_gptimer_tx_begin/commit block */
grlib_gptimer_restart(GPTimer * timer)129 static void grlib_gptimer_restart(GPTimer *timer)
130 {
131     assert(timer != NULL);
132 
133     trace_grlib_gptimer_restart(timer->id, timer->reload);
134 
135     timer->counter = timer->reload;
136     grlib_gptimer_enable(timer);
137 }
138 
grlib_gptimer_set_scaler(GPTimerUnit * unit,uint32_t scaler)139 static void grlib_gptimer_set_scaler(GPTimerUnit *unit, uint32_t scaler)
140 {
141     int i = 0;
142     uint32_t value = 0;
143 
144     assert(unit != NULL);
145 
146     if (scaler > 0) {
147         value = unit->freq_hz / (scaler + 1);
148     } else {
149         value = unit->freq_hz;
150     }
151 
152     trace_grlib_gptimer_set_scaler(scaler, value);
153 
154     for (i = 0; i < unit->nr_timers; i++) {
155         ptimer_transaction_begin(unit->timers[i].ptimer);
156         ptimer_set_freq(unit->timers[i].ptimer, value);
157         ptimer_transaction_commit(unit->timers[i].ptimer);
158     }
159 }
160 
grlib_gptimer_hit(void * opaque)161 static void grlib_gptimer_hit(void *opaque)
162 {
163     GPTimer *timer = opaque;
164     assert(timer != NULL);
165 
166     trace_grlib_gptimer_hit(timer->id);
167 
168     /* Timer expired */
169 
170     if (timer->config & GPTIMER_INT_ENABLE) {
171         /* Set the pending bit (only unset by write in the config register) */
172         timer->config |= GPTIMER_INT_PENDING;
173         qemu_irq_pulse(timer->irq);
174     }
175 
176     if (timer->config & GPTIMER_RESTART) {
177         grlib_gptimer_restart(timer);
178     }
179 }
180 
grlib_gptimer_read(void * opaque,hwaddr addr,unsigned size)181 static uint64_t grlib_gptimer_read(void *opaque, hwaddr addr,
182                                    unsigned size)
183 {
184     GPTimerUnit        *unit  = opaque;
185     hwaddr  timer_addr;
186     int                 id;
187     uint32_t            value = 0;
188 
189     addr &= 0xff;
190 
191     /* Unit registers */
192     switch (addr) {
193     case SCALER_OFFSET:
194         trace_grlib_gptimer_readl(-1, addr, unit->scaler);
195         return unit->scaler;
196 
197     case SCALER_RELOAD_OFFSET:
198         trace_grlib_gptimer_readl(-1, addr, unit->reload);
199         return unit->reload;
200 
201     case CONFIG_OFFSET:
202         trace_grlib_gptimer_readl(-1, addr, unit->config);
203         return unit->config;
204 
205     default:
206         break;
207     }
208 
209     timer_addr = (addr % TIMER_BASE);
210     id         = (addr - TIMER_BASE) / TIMER_BASE;
211 
212     if (id >= 0 && id < unit->nr_timers) {
213 
214         /* GPTimer registers */
215         switch (timer_addr) {
216         case COUNTER_OFFSET:
217             value = ptimer_get_count(unit->timers[id].ptimer);
218             trace_grlib_gptimer_readl(id, addr, value);
219             return value;
220 
221         case COUNTER_RELOAD_OFFSET:
222             value = unit->timers[id].reload;
223             trace_grlib_gptimer_readl(id, addr, value);
224             return value;
225 
226         case CONFIG_OFFSET:
227             trace_grlib_gptimer_readl(id, addr, unit->timers[id].config);
228             return unit->timers[id].config;
229 
230         default:
231             break;
232         }
233 
234     }
235 
236     trace_grlib_gptimer_readl(-1, addr, 0);
237     return 0;
238 }
239 
grlib_gptimer_write(void * opaque,hwaddr addr,uint64_t value,unsigned size)240 static void grlib_gptimer_write(void *opaque, hwaddr addr,
241                                 uint64_t value, unsigned size)
242 {
243     GPTimerUnit        *unit = opaque;
244     hwaddr  timer_addr;
245     int                 id;
246 
247     addr &= 0xff;
248 
249     /* Unit registers */
250     switch (addr) {
251     case SCALER_OFFSET:
252         value &= 0xFFFF; /* clean up the value */
253         unit->scaler = value;
254         trace_grlib_gptimer_writel(-1, addr, unit->scaler);
255         return;
256 
257     case SCALER_RELOAD_OFFSET:
258         value &= 0xFFFF; /* clean up the value */
259         unit->reload = value;
260         trace_grlib_gptimer_writel(-1, addr, unit->reload);
261         grlib_gptimer_set_scaler(unit, value);
262         return;
263 
264     case CONFIG_OFFSET:
265         /* Read Only (disable timer freeze not supported) */
266         trace_grlib_gptimer_writel(-1, addr, 0);
267         return;
268 
269     default:
270         break;
271     }
272 
273     timer_addr = (addr % TIMER_BASE);
274     id         = (addr - TIMER_BASE) / TIMER_BASE;
275 
276     if (id >= 0 && id < unit->nr_timers) {
277 
278         /* GPTimer registers */
279         switch (timer_addr) {
280         case COUNTER_OFFSET:
281             trace_grlib_gptimer_writel(id, addr, value);
282             grlib_gptimer_tx_begin(&unit->timers[id]);
283             unit->timers[id].counter = value;
284             grlib_gptimer_enable(&unit->timers[id]);
285             grlib_gptimer_tx_commit(&unit->timers[id]);
286             return;
287 
288         case COUNTER_RELOAD_OFFSET:
289             trace_grlib_gptimer_writel(id, addr, value);
290             unit->timers[id].reload = value;
291             return;
292 
293         case CONFIG_OFFSET:
294             trace_grlib_gptimer_writel(id, addr, value);
295 
296             if (value & GPTIMER_INT_PENDING) {
297                 /* clear pending bit */
298                 value &= ~GPTIMER_INT_PENDING;
299             } else {
300                 /* keep pending bit */
301                 value |= unit->timers[id].config & GPTIMER_INT_PENDING;
302             }
303 
304             unit->timers[id].config = value;
305 
306             /* gptimer_restart calls gptimer_enable, so if "enable" and "load"
307                bits are present, we just have to call restart. */
308 
309             grlib_gptimer_tx_begin(&unit->timers[id]);
310             if (value & GPTIMER_LOAD) {
311                 grlib_gptimer_restart(&unit->timers[id]);
312             } else if (value & GPTIMER_ENABLE) {
313                 grlib_gptimer_enable(&unit->timers[id]);
314             }
315 
316             /* These fields must always be read as 0 */
317             value &= ~(GPTIMER_LOAD & GPTIMER_DEBUG_HALT);
318 
319             unit->timers[id].config = value;
320             grlib_gptimer_tx_commit(&unit->timers[id]);
321             return;
322 
323         default:
324             break;
325         }
326 
327     }
328 
329     trace_grlib_gptimer_writel(-1, addr, value);
330 }
331 
332 static const MemoryRegionOps grlib_gptimer_ops = {
333     .read = grlib_gptimer_read,
334     .write = grlib_gptimer_write,
335     .endianness = DEVICE_NATIVE_ENDIAN,
336     .valid = {
337         .min_access_size = 4,
338         .max_access_size = 4,
339     },
340 };
341 
grlib_gptimer_reset(DeviceState * d)342 static void grlib_gptimer_reset(DeviceState *d)
343 {
344     GPTimerUnit *unit = GRLIB_GPTIMER(d);
345     int          i    = 0;
346 
347     assert(unit != NULL);
348 
349     unit->scaler = 0;
350     unit->reload = 0;
351 
352     unit->config  = unit->nr_timers;
353     unit->config |= unit->irq_line << 3;
354     unit->config |= 1 << 8;     /* separate interrupt */
355     unit->config |= 1 << 9;     /* Disable timer freeze */
356 
357 
358     for (i = 0; i < unit->nr_timers; i++) {
359         GPTimer *timer = &unit->timers[i];
360 
361         timer->counter = 0;
362         timer->reload = 0;
363         timer->config = 0;
364         ptimer_transaction_begin(timer->ptimer);
365         ptimer_stop(timer->ptimer);
366         ptimer_set_count(timer->ptimer, 0);
367         ptimer_set_freq(timer->ptimer, unit->freq_hz);
368         ptimer_transaction_commit(timer->ptimer);
369     }
370 }
371 
grlib_gptimer_realize(DeviceState * dev,Error ** errp)372 static void grlib_gptimer_realize(DeviceState *dev, Error **errp)
373 {
374     GPTimerUnit  *unit = GRLIB_GPTIMER(dev);
375     unsigned int  i;
376     SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
377 
378     assert(unit->nr_timers > 0);
379     assert(unit->nr_timers <= GPTIMER_MAX_TIMERS);
380 
381     unit->timers = g_malloc0(sizeof unit->timers[0] * unit->nr_timers);
382 
383     for (i = 0; i < unit->nr_timers; i++) {
384         GPTimer *timer = &unit->timers[i];
385 
386         timer->unit   = unit;
387         timer->ptimer = ptimer_init(grlib_gptimer_hit, timer,
388                                     PTIMER_POLICY_LEGACY);
389         timer->id     = i;
390 
391         /* One IRQ line for each timer */
392         sysbus_init_irq(sbd, &timer->irq);
393 
394         ptimer_transaction_begin(timer->ptimer);
395         ptimer_set_freq(timer->ptimer, unit->freq_hz);
396         ptimer_transaction_commit(timer->ptimer);
397     }
398 
399     memory_region_init_io(&unit->iomem, OBJECT(unit), &grlib_gptimer_ops,
400                           unit, "gptimer",
401                           UNIT_REG_SIZE + GPTIMER_REG_SIZE * unit->nr_timers);
402 
403     sysbus_init_mmio(sbd, &unit->iomem);
404 }
405 
406 static Property grlib_gptimer_properties[] = {
407     DEFINE_PROP_UINT32("frequency", GPTimerUnit, freq_hz,   40000000),
408     DEFINE_PROP_UINT32("irq-line",  GPTimerUnit, irq_line,  8),
409     DEFINE_PROP_UINT32("nr-timers", GPTimerUnit, nr_timers, 2),
410     DEFINE_PROP_END_OF_LIST(),
411 };
412 
grlib_gptimer_class_init(ObjectClass * klass,void * data)413 static void grlib_gptimer_class_init(ObjectClass *klass, void *data)
414 {
415     DeviceClass *dc = DEVICE_CLASS(klass);
416 
417     dc->realize = grlib_gptimer_realize;
418     device_class_set_legacy_reset(dc, grlib_gptimer_reset);
419     device_class_set_props(dc, grlib_gptimer_properties);
420 }
421 
422 static const TypeInfo grlib_gptimer_info = {
423     .name          = TYPE_GRLIB_GPTIMER,
424     .parent        = TYPE_SYS_BUS_DEVICE,
425     .instance_size = sizeof(GPTimerUnit),
426     .class_init    = grlib_gptimer_class_init,
427 };
428 
grlib_gptimer_register_types(void)429 static void grlib_gptimer_register_types(void)
430 {
431     type_register_static(&grlib_gptimer_info);
432 }
433 
434 type_init(grlib_gptimer_register_types)
435