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 } 103