1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27#include "qemu/osdep.h"
28#include "trace.h"
29#include "hw/irq.h"
30#include "hw/timer/sifive_pwm.h"
31#include "hw/qdev-properties.h"
32#include "hw/registerfields.h"
33#include "migration/vmstate.h"
34#include "qemu/log.h"
35#include "qemu/module.h"
36
37#define HAS_PWM_EN_BITS(cfg) ((cfg & R_CONFIG_ENONESHOT_MASK) || \
38 (cfg & R_CONFIG_ENALWAYS_MASK))
39
40#define PWMCMP_MASK 0xFFFF
41#define PWMCOUNT_MASK 0x7FFFFFFF
42
43REG32(CONFIG, 0x00)
44 FIELD(CONFIG, SCALE, 0, 4)
45 FIELD(CONFIG, STICKY, 8, 1)
46 FIELD(CONFIG, ZEROCMP, 9, 1)
47 FIELD(CONFIG, DEGLITCH, 10, 1)
48 FIELD(CONFIG, ENALWAYS, 12, 1)
49 FIELD(CONFIG, ENONESHOT, 13, 1)
50 FIELD(CONFIG, CMP0CENTER, 16, 1)
51 FIELD(CONFIG, CMP1CENTER, 17, 1)
52 FIELD(CONFIG, CMP2CENTER, 18, 1)
53 FIELD(CONFIG, CMP3CENTER, 19, 1)
54 FIELD(CONFIG, CMP0GANG, 24, 1)
55 FIELD(CONFIG, CMP1GANG, 25, 1)
56 FIELD(CONFIG, CMP2GANG, 26, 1)
57 FIELD(CONFIG, CMP3GANG, 27, 1)
58 FIELD(CONFIG, CMP0IP, 28, 1)
59 FIELD(CONFIG, CMP1IP, 29, 1)
60 FIELD(CONFIG, CMP2IP, 30, 1)
61 FIELD(CONFIG, CMP3IP, 31, 1)
62REG32(COUNT, 0x08)
63REG32(PWMS, 0x10)
64REG32(PWMCMP0, 0x20)
65REG32(PWMCMP1, 0x24)
66REG32(PWMCMP2, 0x28)
67REG32(PWMCMP3, 0x2C)
68
69static inline uint64_t sifive_pwm_ns_to_ticks(SiFivePwmState *s,
70 uint64_t time)
71{
72 return muldiv64(time, s->freq_hz, NANOSECONDS_PER_SECOND);
73}
74
75static inline uint64_t sifive_pwm_ticks_to_ns(SiFivePwmState *s,
76 uint64_t ticks)
77{
78 return muldiv64(ticks, NANOSECONDS_PER_SECOND, s->freq_hz);
79}
80
81static inline uint64_t sifive_pwm_compute_scale(SiFivePwmState *s)
82{
83 return s->pwmcfg & R_CONFIG_SCALE_MASK;
84}
85
86static void sifive_pwm_set_alarms(SiFivePwmState *s)
87{
88 uint64_t now_ns = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
89
90 if (HAS_PWM_EN_BITS(s->pwmcfg)) {
91
92
93
94
95 uint64_t pwmcount = (sifive_pwm_ns_to_ticks(s, now_ns) -
96 s->tick_offset) & PWMCOUNT_MASK;
97 uint64_t scale = sifive_pwm_compute_scale(s);
98
99 uint64_t pwms = (pwmcount & (PWMCMP_MASK << scale)) >> scale;
100
101 for (int i = 0; i < SIFIVE_PWM_CHANS; i++) {
102 uint64_t pwmcmp = s->pwmcmp[i] & PWMCMP_MASK;
103 uint64_t pwmcmp_ticks = pwmcmp << scale;
104
105
106
107
108
109 if (pwmcmp > pwms) {
110 uint64_t offset = pwmcmp_ticks - pwmcount + 1;
111 uint64_t when_to_fire = now_ns +
112 sifive_pwm_ticks_to_ns(s, offset);
113
114 trace_sifive_pwm_set_alarm(when_to_fire, now_ns);
115 timer_mod(&s->timer[i], when_to_fire);
116 } else {
117
118 trace_sifive_pwm_set_alarm(now_ns + 1, now_ns);
119 timer_mod(&s->timer[i], now_ns + 1);
120 }
121
122 }
123 } else {
124
125
126
127
128 uint64_t pwmcount = (s->tick_offset) & PWMCOUNT_MASK;
129 uint64_t scale = sifive_pwm_compute_scale(s);
130 uint64_t pwms = (pwmcount & (PWMCMP_MASK << scale)) >> scale;
131
132 for (int i = 0; i < SIFIVE_PWM_CHANS; i++) {
133 uint64_t pwmcmp = s->pwmcmp[i] & PWMCMP_MASK;
134
135 if (pwms >= pwmcmp) {
136 trace_sifive_pwm_set_alarm(now_ns + 1, now_ns);
137 timer_mod(&s->timer[i], now_ns + 1);
138 } else {
139
140 trace_sifive_pwm_set_alarm(0xFFFFFFFFFFFFFF, now_ns);
141 timer_mod(&s->timer[i], 0xFFFFFFFFFFFFFF);
142 }
143 }
144 }
145}
146
147static void sifive_pwm_interrupt(SiFivePwmState *s, int num)
148{
149 uint64_t now = sifive_pwm_ns_to_ticks(s,
150 qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
151 bool was_incrementing = HAS_PWM_EN_BITS(s->pwmcfg);
152
153 trace_sifive_pwm_interrupt(num);
154
155 s->pwmcfg |= R_CONFIG_CMP0IP_MASK << num;
156 qemu_irq_raise(s->irqs[num]);
157
158
159
160
161
162 if ((s->pwmcfg & R_CONFIG_ZEROCMP_MASK) && (num == 0)) {
163
164 s->pwmcfg &= ~R_CONFIG_ENONESHOT_MASK;
165
166 if (was_incrementing) {
167
168 s->tick_offset = now;
169 } else {
170
171 s->tick_offset = 0;
172 }
173 }
174
175
176
177
178
179 if (was_incrementing &&
180 ((now & PWMCOUNT_MASK) < (s->tick_offset & PWMCOUNT_MASK))) {
181 s->pwmcfg &= ~R_CONFIG_ENONESHOT_MASK;
182 }
183
184
185 sifive_pwm_set_alarms(s);
186
187
188 if (was_incrementing && !HAS_PWM_EN_BITS(s->pwmcfg)) {
189 s->tick_offset = (now - s->tick_offset) & PWMCOUNT_MASK;
190 }
191}
192
193static void sifive_pwm_interrupt_0(void *opaque)
194{
195 SiFivePwmState *s = opaque;
196
197 sifive_pwm_interrupt(s, 0);
198}
199
200static void sifive_pwm_interrupt_1(void *opaque)
201{
202 SiFivePwmState *s = opaque;
203
204 sifive_pwm_interrupt(s, 1);
205}
206
207static void sifive_pwm_interrupt_2(void *opaque)
208{
209 SiFivePwmState *s = opaque;
210
211 sifive_pwm_interrupt(s, 2);
212}
213
214static void sifive_pwm_interrupt_3(void *opaque)
215{
216 SiFivePwmState *s = opaque;
217
218 sifive_pwm_interrupt(s, 3);
219}
220
221static uint64_t sifive_pwm_read(void *opaque, hwaddr addr,
222 unsigned int size)
223{
224 SiFivePwmState *s = opaque;
225 uint64_t cur_time, scale;
226 uint64_t now = sifive_pwm_ns_to_ticks(s,
227 qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
228
229 trace_sifive_pwm_read(addr);
230
231 switch (addr) {
232 case A_CONFIG:
233 return s->pwmcfg;
234 case A_COUNT:
235 cur_time = s->tick_offset;
236
237 if (HAS_PWM_EN_BITS(s->pwmcfg)) {
238 cur_time = now - cur_time;
239 }
240
241
242
243
244
245 return cur_time & PWMCOUNT_MASK;
246 case A_PWMS:
247 cur_time = s->tick_offset;
248 scale = sifive_pwm_compute_scale(s);
249
250 if (HAS_PWM_EN_BITS(s->pwmcfg)) {
251 cur_time = now - cur_time;
252 }
253
254 return ((cur_time & PWMCOUNT_MASK) >> scale) & PWMCMP_MASK;
255 case A_PWMCMP0:
256 return s->pwmcmp[0] & PWMCMP_MASK;
257 case A_PWMCMP1:
258 return s->pwmcmp[1] & PWMCMP_MASK;
259 case A_PWMCMP2:
260 return s->pwmcmp[2] & PWMCMP_MASK;
261 case A_PWMCMP3:
262 return s->pwmcmp[3] & PWMCMP_MASK;
263 default:
264 qemu_log_mask(LOG_GUEST_ERROR,
265 "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr);
266 return 0;
267 }
268
269 return 0;
270}
271
272static void sifive_pwm_write(void *opaque, hwaddr addr,
273 uint64_t val64, unsigned int size)
274{
275 SiFivePwmState *s = opaque;
276 uint32_t value = val64;
277 uint64_t new_offset, scale;
278 uint64_t now = sifive_pwm_ns_to_ticks(s,
279 qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
280
281 trace_sifive_pwm_write(value, addr);
282
283 switch (addr) {
284 case A_CONFIG:
285 if (value & (R_CONFIG_CMP0CENTER_MASK | R_CONFIG_CMP1CENTER_MASK |
286 R_CONFIG_CMP2CENTER_MASK | R_CONFIG_CMP3CENTER_MASK)) {
287 qemu_log_mask(LOG_UNIMP, "%s: CMPxCENTER is not supported\n",
288 __func__);
289 }
290
291 if (value & (R_CONFIG_CMP0GANG_MASK | R_CONFIG_CMP1GANG_MASK |
292 R_CONFIG_CMP2GANG_MASK | R_CONFIG_CMP3GANG_MASK)) {
293 qemu_log_mask(LOG_UNIMP, "%s: CMPxGANG is not supported\n",
294 __func__);
295 }
296
297 if (value & (R_CONFIG_CMP0IP_MASK | R_CONFIG_CMP1IP_MASK |
298 R_CONFIG_CMP2IP_MASK | R_CONFIG_CMP3IP_MASK)) {
299 qemu_log_mask(LOG_UNIMP, "%s: CMPxIP is not supported\n",
300 __func__);
301 }
302
303 if (!(value & R_CONFIG_CMP0IP_MASK)) {
304 qemu_irq_lower(s->irqs[0]);
305 }
306
307 if (!(value & R_CONFIG_CMP1IP_MASK)) {
308 qemu_irq_lower(s->irqs[1]);
309 }
310
311 if (!(value & R_CONFIG_CMP2IP_MASK)) {
312 qemu_irq_lower(s->irqs[2]);
313 }
314
315 if (!(value & R_CONFIG_CMP3IP_MASK)) {
316 qemu_irq_lower(s->irqs[3]);
317 }
318
319
320
321
322
323
324
325
326 if ((!HAS_PWM_EN_BITS(s->pwmcfg) && HAS_PWM_EN_BITS(value)) ||
327 (HAS_PWM_EN_BITS(s->pwmcfg) && !HAS_PWM_EN_BITS(value))) {
328 s->tick_offset = (now - s->tick_offset) & PWMCOUNT_MASK;
329 }
330
331 s->pwmcfg = value;
332 break;
333 case A_COUNT:
334
335 new_offset = value;
336
337 if (HAS_PWM_EN_BITS(s->pwmcfg)) {
338 new_offset = now - new_offset;
339 }
340
341 s->tick_offset = new_offset;
342 break;
343 case A_PWMS:
344 scale = sifive_pwm_compute_scale(s);
345 new_offset = (((value & PWMCMP_MASK) << scale) & PWMCOUNT_MASK);
346
347 if (HAS_PWM_EN_BITS(s->pwmcfg)) {
348 new_offset = now - new_offset;
349 }
350
351 s->tick_offset = new_offset;
352 break;
353 case A_PWMCMP0:
354 s->pwmcmp[0] = value & PWMCMP_MASK;
355 break;
356 case A_PWMCMP1:
357 s->pwmcmp[1] = value & PWMCMP_MASK;
358 break;
359 case A_PWMCMP2:
360 s->pwmcmp[2] = value & PWMCMP_MASK;
361 break;
362 case A_PWMCMP3:
363 s->pwmcmp[3] = value & PWMCMP_MASK;
364 break;
365 default:
366 qemu_log_mask(LOG_GUEST_ERROR,
367 "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr);
368 }
369
370
371 sifive_pwm_set_alarms(s);
372}
373
374static void sifive_pwm_reset(DeviceState *dev)
375{
376 SiFivePwmState *s = SIFIVE_PWM(dev);
377 uint64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
378
379 s->pwmcfg = 0x00000000;
380 s->pwmcmp[0] = 0x00000000;
381 s->pwmcmp[1] = 0x00000000;
382 s->pwmcmp[2] = 0x00000000;
383 s->pwmcmp[3] = 0x00000000;
384
385 s->tick_offset = sifive_pwm_ns_to_ticks(s, now);
386}
387
388static const MemoryRegionOps sifive_pwm_ops = {
389 .read = sifive_pwm_read,
390 .write = sifive_pwm_write,
391 .endianness = DEVICE_NATIVE_ENDIAN,
392};
393
394static const VMStateDescription vmstate_sifive_pwm = {
395 .name = TYPE_SIFIVE_PWM,
396 .version_id = 1,
397 .minimum_version_id = 1,
398 .fields = (VMStateField[]) {
399 VMSTATE_TIMER_ARRAY(timer, SiFivePwmState, 4),
400 VMSTATE_UINT64(tick_offset, SiFivePwmState),
401 VMSTATE_UINT32(pwmcfg, SiFivePwmState),
402 VMSTATE_UINT32_ARRAY(pwmcmp, SiFivePwmState, 4),
403 VMSTATE_END_OF_LIST()
404 }
405};
406
407static Property sifive_pwm_properties[] = {
408
409 DEFINE_PROP_UINT64("clock-frequency", struct SiFivePwmState,
410 freq_hz, 500000000ULL),
411 DEFINE_PROP_END_OF_LIST(),
412};
413
414static void sifive_pwm_init(Object *obj)
415{
416 SiFivePwmState *s = SIFIVE_PWM(obj);
417 int i;
418
419 for (i = 0; i < SIFIVE_PWM_IRQS; i++) {
420 sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irqs[i]);
421 }
422
423 memory_region_init_io(&s->mmio, obj, &sifive_pwm_ops, s,
424 TYPE_SIFIVE_PWM, 0x100);
425 sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
426}
427
428static void sifive_pwm_realize(DeviceState *dev, Error **errp)
429{
430 SiFivePwmState *s = SIFIVE_PWM(dev);
431
432 timer_init_ns(&s->timer[0], QEMU_CLOCK_VIRTUAL,
433 sifive_pwm_interrupt_0, s);
434
435 timer_init_ns(&s->timer[1], QEMU_CLOCK_VIRTUAL,
436 sifive_pwm_interrupt_1, s);
437
438 timer_init_ns(&s->timer[2], QEMU_CLOCK_VIRTUAL,
439 sifive_pwm_interrupt_2, s);
440
441 timer_init_ns(&s->timer[3], QEMU_CLOCK_VIRTUAL,
442 sifive_pwm_interrupt_3, s);
443}
444
445static void sifive_pwm_class_init(ObjectClass *klass, void *data)
446{
447 DeviceClass *dc = DEVICE_CLASS(klass);
448
449 dc->reset = sifive_pwm_reset;
450 device_class_set_props(dc, sifive_pwm_properties);
451 dc->vmsd = &vmstate_sifive_pwm;
452 dc->realize = sifive_pwm_realize;
453}
454
455static const TypeInfo sifive_pwm_info = {
456 .name = TYPE_SIFIVE_PWM,
457 .parent = TYPE_SYS_BUS_DEVICE,
458 .instance_size = sizeof(SiFivePwmState),
459 .instance_init = sifive_pwm_init,
460 .class_init = sifive_pwm_class_init,
461};
462
463static void sifive_pwm_register_types(void)
464{
465 type_register_static(&sifive_pwm_info);
466}
467
468type_init(sifive_pwm_register_types)
469