1 /*
2 * TI OMAP2 32kHz sync timer emulation.
3 *
4 * Copyright (C) 2007-2008 Nokia Corporation
5 * Written by Andrzej Zaborowski <andrew@openedhand.com>
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2 or
10 * (at your option) any later version of the License.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, see <http://www.gnu.org/licenses/>.
19 */
20 #include "qemu/osdep.h"
21 #include "qemu/timer.h"
22 #include "hw/arm/omap.h"
23 struct omap_synctimer_s {
24 MemoryRegion iomem;
25 uint32_t val;
26 uint16_t readh;
27 };
28
29 /* 32-kHz Sync Timer of the OMAP2 */
omap_synctimer_read(struct omap_synctimer_s * s)30 static 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
omap_synctimer_reset(struct omap_synctimer_s * s)35 void omap_synctimer_reset(struct omap_synctimer_s *s)
36 {
37 s->val = omap_synctimer_read(s);
38 }
39
omap_synctimer_readw(void * opaque,hwaddr addr)40 static uint32_t omap_synctimer_readw(void *opaque, hwaddr addr)
41 {
42 struct omap_synctimer_s *s = opaque;
43
44 switch (addr) {
45 case 0x00: /* 32KSYNCNT_REV */
46 return 0x21;
47
48 case 0x10: /* CR */
49 return omap_synctimer_read(s) - s->val;
50 }
51
52 OMAP_BAD_REG(addr);
53 return 0;
54 }
55
omap_synctimer_readh(void * opaque,hwaddr addr)56 static uint32_t omap_synctimer_readh(void *opaque, hwaddr addr)
57 {
58 struct omap_synctimer_s *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
omap_synctimer_readfn(void * opaque,hwaddr addr,unsigned size)70 static 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
omap_synctimer_writefn(void * opaque,hwaddr addr,uint64_t value,unsigned size)85 static void omap_synctimer_writefn(void *opaque, hwaddr addr,
86 uint64_t value, unsigned size)
87 {
88 OMAP_BAD_REG(addr);
89 }
90
91 static 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
omap_synctimer_init(struct omap_target_agent_s * ta,struct omap_mpu_state_s * mpu,omap_clk fclk,omap_clk iclk)99 struct 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