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 */ 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 35 void omap_synctimer_reset(struct omap_synctimer_s *s) 36 { 37 s->val = omap_synctimer_read(s); 38 } 39 40 static 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: /* 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 56 static 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 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 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 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