root / hw / timer / omap_synctimer.c @ 3bd88451
History | View | Annotate | Download (2.8 kB)
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 "hw/hw.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 */
|
30 |
static uint32_t omap_synctimer_read(struct omap_synctimer_s *s) { |
31 |
return muldiv64(qemu_get_clock_ns(vm_clock), 0x8000, get_ticks_per_sec()); |
32 |
} |
33 |
|
34 |
void omap_synctimer_reset(struct omap_synctimer_s *s) |
35 |
{ |
36 |
s->val = omap_synctimer_read(s); |
37 |
} |
38 |
|
39 |
static uint32_t omap_synctimer_readw(void *opaque, hwaddr addr) |
40 |
{ |
41 |
struct omap_synctimer_s *s = (struct omap_synctimer_s *) opaque; |
42 |
|
43 |
switch (addr) {
|
44 |
case 0x00: /* 32KSYNCNT_REV */ |
45 |
return 0x21; |
46 |
|
47 |
case 0x10: /* CR */ |
48 |
return omap_synctimer_read(s) - s->val;
|
49 |
} |
50 |
|
51 |
OMAP_BAD_REG(addr); |
52 |
return 0; |
53 |
} |
54 |
|
55 |
static uint32_t omap_synctimer_readh(void *opaque, hwaddr addr) |
56 |
{ |
57 |
struct omap_synctimer_s *s = (struct omap_synctimer_s *) opaque; |
58 |
uint32_t ret; |
59 |
|
60 |
if (addr & 2) |
61 |
return s->readh;
|
62 |
else {
|
63 |
ret = omap_synctimer_readw(opaque, addr); |
64 |
s->readh = ret >> 16;
|
65 |
return ret & 0xffff; |
66 |
} |
67 |
} |
68 |
|
69 |
static void omap_synctimer_write(void *opaque, hwaddr addr, |
70 |
uint32_t value) |
71 |
{ |
72 |
OMAP_BAD_REG(addr); |
73 |
} |
74 |
|
75 |
static const MemoryRegionOps omap_synctimer_ops = { |
76 |
.old_mmio = { |
77 |
.read = { |
78 |
omap_badwidth_read32, |
79 |
omap_synctimer_readh, |
80 |
omap_synctimer_readw, |
81 |
}, |
82 |
.write = { |
83 |
omap_badwidth_write32, |
84 |
omap_synctimer_write, |
85 |
omap_synctimer_write, |
86 |
}, |
87 |
}, |
88 |
.endianness = DEVICE_NATIVE_ENDIAN, |
89 |
}; |
90 |
|
91 |
struct omap_synctimer_s *omap_synctimer_init(struct omap_target_agent_s *ta, |
92 |
struct omap_mpu_state_s *mpu, omap_clk fclk, omap_clk iclk)
|
93 |
{ |
94 |
struct omap_synctimer_s *s = g_malloc0(sizeof(*s)); |
95 |
|
96 |
omap_synctimer_reset(s); |
97 |
memory_region_init_io(&s->iomem, &omap_synctimer_ops, s, "omap.synctimer",
|
98 |
omap_l4_region_size(ta, 0));
|
99 |
omap_l4_attach(ta, 0, &s->iomem);
|
100 |
|
101 |
return s;
|
102 |
} |