1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20#include "qemu/osdep.h"
21#include "qemu/timer.h"
22#include "hw/arm/omap.h"
23struct omap_synctimer_s {
24 MemoryRegion iomem;
25 uint32_t val;
26 uint16_t readh;
27};
28
29
30static uint32_t omap_synctimer_read(struct omap_synctimer_s *s) {
31 return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 0x8000,
32 NANOSECONDS_PER_SECOND);
33}
34
35void omap_synctimer_reset(struct omap_synctimer_s *s)
36{
37 s->val = omap_synctimer_read(s);
38}
39
40static uint32_t omap_synctimer_readw(void *opaque, hwaddr addr)
41{
42 struct omap_synctimer_s *s = (struct omap_synctimer_s *) opaque;
43
44 switch (addr) {
45 case 0x00:
46 return 0x21;
47
48 case 0x10:
49 return omap_synctimer_read(s) - s->val;
50 }
51
52 OMAP_BAD_REG(addr);
53 return 0;
54}
55
56static uint32_t omap_synctimer_readh(void *opaque, hwaddr addr)
57{
58 struct omap_synctimer_s *s = (struct omap_synctimer_s *) opaque;
59 uint32_t ret;
60
61 if (addr & 2)
62 return s->readh;
63 else {
64 ret = omap_synctimer_readw(opaque, addr);
65 s->readh = ret >> 16;
66 return ret & 0xffff;
67 }
68}
69
70static uint64_t omap_synctimer_readfn(void *opaque, hwaddr addr,
71 unsigned size)
72{
73 switch (size) {
74 case 1:
75 return omap_badwidth_read32(opaque, addr);
76 case 2:
77 return omap_synctimer_readh(opaque, addr);
78 case 4:
79 return omap_synctimer_readw(opaque, addr);
80 default:
81 g_assert_not_reached();
82 }
83}
84
85static void omap_synctimer_writefn(void *opaque, hwaddr addr,
86 uint64_t value, unsigned size)
87{
88 OMAP_BAD_REG(addr);
89}
90
91static const MemoryRegionOps omap_synctimer_ops = {
92 .read = omap_synctimer_readfn,
93 .write = omap_synctimer_writefn,
94 .valid.min_access_size = 1,
95 .valid.max_access_size = 4,
96 .endianness = DEVICE_NATIVE_ENDIAN,
97};
98
99struct omap_synctimer_s *omap_synctimer_init(struct omap_target_agent_s *ta,
100 struct omap_mpu_state_s *mpu, omap_clk fclk, omap_clk iclk)
101{
102 struct omap_synctimer_s *s = g_malloc0(sizeof(*s));
103
104 omap_synctimer_reset(s);
105 memory_region_init_io(&s->iomem, NULL, &omap_synctimer_ops, s, "omap.synctimer",
106 omap_l4_region_size(ta, 0));
107 omap_l4_attach(ta, 0, &s->iomem);
108
109 return s;
110}
111