1*3bd88451SPaolo Bonzini /* 2*3bd88451SPaolo Bonzini * TI OMAP2 general purpose timers emulation. 3*3bd88451SPaolo Bonzini * 4*3bd88451SPaolo Bonzini * Copyright (C) 2007-2008 Nokia Corporation 5*3bd88451SPaolo Bonzini * Written by Andrzej Zaborowski <andrew@openedhand.com> 6*3bd88451SPaolo Bonzini * 7*3bd88451SPaolo Bonzini * This program is free software; you can redistribute it and/or 8*3bd88451SPaolo Bonzini * modify it under the terms of the GNU General Public License as 9*3bd88451SPaolo Bonzini * published by the Free Software Foundation; either version 2 or 10*3bd88451SPaolo Bonzini * (at your option) any later version of the License. 11*3bd88451SPaolo Bonzini * 12*3bd88451SPaolo Bonzini * This program is distributed in the hope that it will be useful, 13*3bd88451SPaolo Bonzini * but WITHOUT ANY WARRANTY; without even the implied warranty of 14*3bd88451SPaolo Bonzini * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15*3bd88451SPaolo Bonzini * GNU General Public License for more details. 16*3bd88451SPaolo Bonzini * 17*3bd88451SPaolo Bonzini * You should have received a copy of the GNU General Public License along 18*3bd88451SPaolo Bonzini * with this program; if not, see <http://www.gnu.org/licenses/>. 19*3bd88451SPaolo Bonzini */ 20*3bd88451SPaolo Bonzini #include "hw/hw.h" 21*3bd88451SPaolo Bonzini #include "qemu/timer.h" 22*3bd88451SPaolo Bonzini #include "hw/arm/omap.h" 23*3bd88451SPaolo Bonzini 24*3bd88451SPaolo Bonzini /* GP timers */ 25*3bd88451SPaolo Bonzini struct omap_gp_timer_s { 26*3bd88451SPaolo Bonzini MemoryRegion iomem; 27*3bd88451SPaolo Bonzini qemu_irq irq; 28*3bd88451SPaolo Bonzini qemu_irq wkup; 29*3bd88451SPaolo Bonzini qemu_irq in; 30*3bd88451SPaolo Bonzini qemu_irq out; 31*3bd88451SPaolo Bonzini omap_clk clk; 32*3bd88451SPaolo Bonzini QEMUTimer *timer; 33*3bd88451SPaolo Bonzini QEMUTimer *match; 34*3bd88451SPaolo Bonzini struct omap_target_agent_s *ta; 35*3bd88451SPaolo Bonzini 36*3bd88451SPaolo Bonzini int in_val; 37*3bd88451SPaolo Bonzini int out_val; 38*3bd88451SPaolo Bonzini int64_t time; 39*3bd88451SPaolo Bonzini int64_t rate; 40*3bd88451SPaolo Bonzini int64_t ticks_per_sec; 41*3bd88451SPaolo Bonzini 42*3bd88451SPaolo Bonzini int16_t config; 43*3bd88451SPaolo Bonzini int status; 44*3bd88451SPaolo Bonzini int it_ena; 45*3bd88451SPaolo Bonzini int wu_ena; 46*3bd88451SPaolo Bonzini int enable; 47*3bd88451SPaolo Bonzini int inout; 48*3bd88451SPaolo Bonzini int capt2; 49*3bd88451SPaolo Bonzini int pt; 50*3bd88451SPaolo Bonzini enum { 51*3bd88451SPaolo Bonzini gpt_trigger_none, gpt_trigger_overflow, gpt_trigger_both 52*3bd88451SPaolo Bonzini } trigger; 53*3bd88451SPaolo Bonzini enum { 54*3bd88451SPaolo Bonzini gpt_capture_none, gpt_capture_rising, 55*3bd88451SPaolo Bonzini gpt_capture_falling, gpt_capture_both 56*3bd88451SPaolo Bonzini } capture; 57*3bd88451SPaolo Bonzini int scpwm; 58*3bd88451SPaolo Bonzini int ce; 59*3bd88451SPaolo Bonzini int pre; 60*3bd88451SPaolo Bonzini int ptv; 61*3bd88451SPaolo Bonzini int ar; 62*3bd88451SPaolo Bonzini int st; 63*3bd88451SPaolo Bonzini int posted; 64*3bd88451SPaolo Bonzini uint32_t val; 65*3bd88451SPaolo Bonzini uint32_t load_val; 66*3bd88451SPaolo Bonzini uint32_t capture_val[2]; 67*3bd88451SPaolo Bonzini uint32_t match_val; 68*3bd88451SPaolo Bonzini int capt_num; 69*3bd88451SPaolo Bonzini 70*3bd88451SPaolo Bonzini uint16_t writeh; /* LSB */ 71*3bd88451SPaolo Bonzini uint16_t readh; /* MSB */ 72*3bd88451SPaolo Bonzini }; 73*3bd88451SPaolo Bonzini 74*3bd88451SPaolo Bonzini #define GPT_TCAR_IT (1 << 2) 75*3bd88451SPaolo Bonzini #define GPT_OVF_IT (1 << 1) 76*3bd88451SPaolo Bonzini #define GPT_MAT_IT (1 << 0) 77*3bd88451SPaolo Bonzini 78*3bd88451SPaolo Bonzini static inline void omap_gp_timer_intr(struct omap_gp_timer_s *timer, int it) 79*3bd88451SPaolo Bonzini { 80*3bd88451SPaolo Bonzini if (timer->it_ena & it) { 81*3bd88451SPaolo Bonzini if (!timer->status) 82*3bd88451SPaolo Bonzini qemu_irq_raise(timer->irq); 83*3bd88451SPaolo Bonzini 84*3bd88451SPaolo Bonzini timer->status |= it; 85*3bd88451SPaolo Bonzini /* Or are the status bits set even when masked? 86*3bd88451SPaolo Bonzini * i.e. is masking applied before or after the status register? */ 87*3bd88451SPaolo Bonzini } 88*3bd88451SPaolo Bonzini 89*3bd88451SPaolo Bonzini if (timer->wu_ena & it) 90*3bd88451SPaolo Bonzini qemu_irq_pulse(timer->wkup); 91*3bd88451SPaolo Bonzini } 92*3bd88451SPaolo Bonzini 93*3bd88451SPaolo Bonzini static inline void omap_gp_timer_out(struct omap_gp_timer_s *timer, int level) 94*3bd88451SPaolo Bonzini { 95*3bd88451SPaolo Bonzini if (!timer->inout && timer->out_val != level) { 96*3bd88451SPaolo Bonzini timer->out_val = level; 97*3bd88451SPaolo Bonzini qemu_set_irq(timer->out, level); 98*3bd88451SPaolo Bonzini } 99*3bd88451SPaolo Bonzini } 100*3bd88451SPaolo Bonzini 101*3bd88451SPaolo Bonzini static inline uint32_t omap_gp_timer_read(struct omap_gp_timer_s *timer) 102*3bd88451SPaolo Bonzini { 103*3bd88451SPaolo Bonzini uint64_t distance; 104*3bd88451SPaolo Bonzini 105*3bd88451SPaolo Bonzini if (timer->st && timer->rate) { 106*3bd88451SPaolo Bonzini distance = qemu_get_clock_ns(vm_clock) - timer->time; 107*3bd88451SPaolo Bonzini distance = muldiv64(distance, timer->rate, timer->ticks_per_sec); 108*3bd88451SPaolo Bonzini 109*3bd88451SPaolo Bonzini if (distance >= 0xffffffff - timer->val) 110*3bd88451SPaolo Bonzini return 0xffffffff; 111*3bd88451SPaolo Bonzini else 112*3bd88451SPaolo Bonzini return timer->val + distance; 113*3bd88451SPaolo Bonzini } else 114*3bd88451SPaolo Bonzini return timer->val; 115*3bd88451SPaolo Bonzini } 116*3bd88451SPaolo Bonzini 117*3bd88451SPaolo Bonzini static inline void omap_gp_timer_sync(struct omap_gp_timer_s *timer) 118*3bd88451SPaolo Bonzini { 119*3bd88451SPaolo Bonzini if (timer->st) { 120*3bd88451SPaolo Bonzini timer->val = omap_gp_timer_read(timer); 121*3bd88451SPaolo Bonzini timer->time = qemu_get_clock_ns(vm_clock); 122*3bd88451SPaolo Bonzini } 123*3bd88451SPaolo Bonzini } 124*3bd88451SPaolo Bonzini 125*3bd88451SPaolo Bonzini static inline void omap_gp_timer_update(struct omap_gp_timer_s *timer) 126*3bd88451SPaolo Bonzini { 127*3bd88451SPaolo Bonzini int64_t expires, matches; 128*3bd88451SPaolo Bonzini 129*3bd88451SPaolo Bonzini if (timer->st && timer->rate) { 130*3bd88451SPaolo Bonzini expires = muldiv64(0x100000000ll - timer->val, 131*3bd88451SPaolo Bonzini timer->ticks_per_sec, timer->rate); 132*3bd88451SPaolo Bonzini qemu_mod_timer(timer->timer, timer->time + expires); 133*3bd88451SPaolo Bonzini 134*3bd88451SPaolo Bonzini if (timer->ce && timer->match_val >= timer->val) { 135*3bd88451SPaolo Bonzini matches = muldiv64(timer->match_val - timer->val, 136*3bd88451SPaolo Bonzini timer->ticks_per_sec, timer->rate); 137*3bd88451SPaolo Bonzini qemu_mod_timer(timer->match, timer->time + matches); 138*3bd88451SPaolo Bonzini } else 139*3bd88451SPaolo Bonzini qemu_del_timer(timer->match); 140*3bd88451SPaolo Bonzini } else { 141*3bd88451SPaolo Bonzini qemu_del_timer(timer->timer); 142*3bd88451SPaolo Bonzini qemu_del_timer(timer->match); 143*3bd88451SPaolo Bonzini omap_gp_timer_out(timer, timer->scpwm); 144*3bd88451SPaolo Bonzini } 145*3bd88451SPaolo Bonzini } 146*3bd88451SPaolo Bonzini 147*3bd88451SPaolo Bonzini static inline void omap_gp_timer_trigger(struct omap_gp_timer_s *timer) 148*3bd88451SPaolo Bonzini { 149*3bd88451SPaolo Bonzini if (timer->pt) 150*3bd88451SPaolo Bonzini /* TODO in overflow-and-match mode if the first event to 151*3bd88451SPaolo Bonzini * occur is the match, don't toggle. */ 152*3bd88451SPaolo Bonzini omap_gp_timer_out(timer, !timer->out_val); 153*3bd88451SPaolo Bonzini else 154*3bd88451SPaolo Bonzini /* TODO inverted pulse on timer->out_val == 1? */ 155*3bd88451SPaolo Bonzini qemu_irq_pulse(timer->out); 156*3bd88451SPaolo Bonzini } 157*3bd88451SPaolo Bonzini 158*3bd88451SPaolo Bonzini static void omap_gp_timer_tick(void *opaque) 159*3bd88451SPaolo Bonzini { 160*3bd88451SPaolo Bonzini struct omap_gp_timer_s *timer = (struct omap_gp_timer_s *) opaque; 161*3bd88451SPaolo Bonzini 162*3bd88451SPaolo Bonzini if (!timer->ar) { 163*3bd88451SPaolo Bonzini timer->st = 0; 164*3bd88451SPaolo Bonzini timer->val = 0; 165*3bd88451SPaolo Bonzini } else { 166*3bd88451SPaolo Bonzini timer->val = timer->load_val; 167*3bd88451SPaolo Bonzini timer->time = qemu_get_clock_ns(vm_clock); 168*3bd88451SPaolo Bonzini } 169*3bd88451SPaolo Bonzini 170*3bd88451SPaolo Bonzini if (timer->trigger == gpt_trigger_overflow || 171*3bd88451SPaolo Bonzini timer->trigger == gpt_trigger_both) 172*3bd88451SPaolo Bonzini omap_gp_timer_trigger(timer); 173*3bd88451SPaolo Bonzini 174*3bd88451SPaolo Bonzini omap_gp_timer_intr(timer, GPT_OVF_IT); 175*3bd88451SPaolo Bonzini omap_gp_timer_update(timer); 176*3bd88451SPaolo Bonzini } 177*3bd88451SPaolo Bonzini 178*3bd88451SPaolo Bonzini static void omap_gp_timer_match(void *opaque) 179*3bd88451SPaolo Bonzini { 180*3bd88451SPaolo Bonzini struct omap_gp_timer_s *timer = (struct omap_gp_timer_s *) opaque; 181*3bd88451SPaolo Bonzini 182*3bd88451SPaolo Bonzini if (timer->trigger == gpt_trigger_both) 183*3bd88451SPaolo Bonzini omap_gp_timer_trigger(timer); 184*3bd88451SPaolo Bonzini 185*3bd88451SPaolo Bonzini omap_gp_timer_intr(timer, GPT_MAT_IT); 186*3bd88451SPaolo Bonzini } 187*3bd88451SPaolo Bonzini 188*3bd88451SPaolo Bonzini static void omap_gp_timer_input(void *opaque, int line, int on) 189*3bd88451SPaolo Bonzini { 190*3bd88451SPaolo Bonzini struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque; 191*3bd88451SPaolo Bonzini int trigger; 192*3bd88451SPaolo Bonzini 193*3bd88451SPaolo Bonzini switch (s->capture) { 194*3bd88451SPaolo Bonzini default: 195*3bd88451SPaolo Bonzini case gpt_capture_none: 196*3bd88451SPaolo Bonzini trigger = 0; 197*3bd88451SPaolo Bonzini break; 198*3bd88451SPaolo Bonzini case gpt_capture_rising: 199*3bd88451SPaolo Bonzini trigger = !s->in_val && on; 200*3bd88451SPaolo Bonzini break; 201*3bd88451SPaolo Bonzini case gpt_capture_falling: 202*3bd88451SPaolo Bonzini trigger = s->in_val && !on; 203*3bd88451SPaolo Bonzini break; 204*3bd88451SPaolo Bonzini case gpt_capture_both: 205*3bd88451SPaolo Bonzini trigger = (s->in_val == !on); 206*3bd88451SPaolo Bonzini break; 207*3bd88451SPaolo Bonzini } 208*3bd88451SPaolo Bonzini s->in_val = on; 209*3bd88451SPaolo Bonzini 210*3bd88451SPaolo Bonzini if (s->inout && trigger && s->capt_num < 2) { 211*3bd88451SPaolo Bonzini s->capture_val[s->capt_num] = omap_gp_timer_read(s); 212*3bd88451SPaolo Bonzini 213*3bd88451SPaolo Bonzini if (s->capt2 == s->capt_num ++) 214*3bd88451SPaolo Bonzini omap_gp_timer_intr(s, GPT_TCAR_IT); 215*3bd88451SPaolo Bonzini } 216*3bd88451SPaolo Bonzini } 217*3bd88451SPaolo Bonzini 218*3bd88451SPaolo Bonzini static void omap_gp_timer_clk_update(void *opaque, int line, int on) 219*3bd88451SPaolo Bonzini { 220*3bd88451SPaolo Bonzini struct omap_gp_timer_s *timer = (struct omap_gp_timer_s *) opaque; 221*3bd88451SPaolo Bonzini 222*3bd88451SPaolo Bonzini omap_gp_timer_sync(timer); 223*3bd88451SPaolo Bonzini timer->rate = on ? omap_clk_getrate(timer->clk) : 0; 224*3bd88451SPaolo Bonzini omap_gp_timer_update(timer); 225*3bd88451SPaolo Bonzini } 226*3bd88451SPaolo Bonzini 227*3bd88451SPaolo Bonzini static void omap_gp_timer_clk_setup(struct omap_gp_timer_s *timer) 228*3bd88451SPaolo Bonzini { 229*3bd88451SPaolo Bonzini omap_clk_adduser(timer->clk, 230*3bd88451SPaolo Bonzini qemu_allocate_irqs(omap_gp_timer_clk_update, timer, 1)[0]); 231*3bd88451SPaolo Bonzini timer->rate = omap_clk_getrate(timer->clk); 232*3bd88451SPaolo Bonzini } 233*3bd88451SPaolo Bonzini 234*3bd88451SPaolo Bonzini void omap_gp_timer_reset(struct omap_gp_timer_s *s) 235*3bd88451SPaolo Bonzini { 236*3bd88451SPaolo Bonzini s->config = 0x000; 237*3bd88451SPaolo Bonzini s->status = 0; 238*3bd88451SPaolo Bonzini s->it_ena = 0; 239*3bd88451SPaolo Bonzini s->wu_ena = 0; 240*3bd88451SPaolo Bonzini s->inout = 0; 241*3bd88451SPaolo Bonzini s->capt2 = 0; 242*3bd88451SPaolo Bonzini s->capt_num = 0; 243*3bd88451SPaolo Bonzini s->pt = 0; 244*3bd88451SPaolo Bonzini s->trigger = gpt_trigger_none; 245*3bd88451SPaolo Bonzini s->capture = gpt_capture_none; 246*3bd88451SPaolo Bonzini s->scpwm = 0; 247*3bd88451SPaolo Bonzini s->ce = 0; 248*3bd88451SPaolo Bonzini s->pre = 0; 249*3bd88451SPaolo Bonzini s->ptv = 0; 250*3bd88451SPaolo Bonzini s->ar = 0; 251*3bd88451SPaolo Bonzini s->st = 0; 252*3bd88451SPaolo Bonzini s->posted = 1; 253*3bd88451SPaolo Bonzini s->val = 0x00000000; 254*3bd88451SPaolo Bonzini s->load_val = 0x00000000; 255*3bd88451SPaolo Bonzini s->capture_val[0] = 0x00000000; 256*3bd88451SPaolo Bonzini s->capture_val[1] = 0x00000000; 257*3bd88451SPaolo Bonzini s->match_val = 0x00000000; 258*3bd88451SPaolo Bonzini omap_gp_timer_update(s); 259*3bd88451SPaolo Bonzini } 260*3bd88451SPaolo Bonzini 261*3bd88451SPaolo Bonzini static uint32_t omap_gp_timer_readw(void *opaque, hwaddr addr) 262*3bd88451SPaolo Bonzini { 263*3bd88451SPaolo Bonzini struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque; 264*3bd88451SPaolo Bonzini 265*3bd88451SPaolo Bonzini switch (addr) { 266*3bd88451SPaolo Bonzini case 0x00: /* TIDR */ 267*3bd88451SPaolo Bonzini return 0x21; 268*3bd88451SPaolo Bonzini 269*3bd88451SPaolo Bonzini case 0x10: /* TIOCP_CFG */ 270*3bd88451SPaolo Bonzini return s->config; 271*3bd88451SPaolo Bonzini 272*3bd88451SPaolo Bonzini case 0x14: /* TISTAT */ 273*3bd88451SPaolo Bonzini /* ??? When's this bit reset? */ 274*3bd88451SPaolo Bonzini return 1; /* RESETDONE */ 275*3bd88451SPaolo Bonzini 276*3bd88451SPaolo Bonzini case 0x18: /* TISR */ 277*3bd88451SPaolo Bonzini return s->status; 278*3bd88451SPaolo Bonzini 279*3bd88451SPaolo Bonzini case 0x1c: /* TIER */ 280*3bd88451SPaolo Bonzini return s->it_ena; 281*3bd88451SPaolo Bonzini 282*3bd88451SPaolo Bonzini case 0x20: /* TWER */ 283*3bd88451SPaolo Bonzini return s->wu_ena; 284*3bd88451SPaolo Bonzini 285*3bd88451SPaolo Bonzini case 0x24: /* TCLR */ 286*3bd88451SPaolo Bonzini return (s->inout << 14) | 287*3bd88451SPaolo Bonzini (s->capt2 << 13) | 288*3bd88451SPaolo Bonzini (s->pt << 12) | 289*3bd88451SPaolo Bonzini (s->trigger << 10) | 290*3bd88451SPaolo Bonzini (s->capture << 8) | 291*3bd88451SPaolo Bonzini (s->scpwm << 7) | 292*3bd88451SPaolo Bonzini (s->ce << 6) | 293*3bd88451SPaolo Bonzini (s->pre << 5) | 294*3bd88451SPaolo Bonzini (s->ptv << 2) | 295*3bd88451SPaolo Bonzini (s->ar << 1) | 296*3bd88451SPaolo Bonzini (s->st << 0); 297*3bd88451SPaolo Bonzini 298*3bd88451SPaolo Bonzini case 0x28: /* TCRR */ 299*3bd88451SPaolo Bonzini return omap_gp_timer_read(s); 300*3bd88451SPaolo Bonzini 301*3bd88451SPaolo Bonzini case 0x2c: /* TLDR */ 302*3bd88451SPaolo Bonzini return s->load_val; 303*3bd88451SPaolo Bonzini 304*3bd88451SPaolo Bonzini case 0x30: /* TTGR */ 305*3bd88451SPaolo Bonzini return 0xffffffff; 306*3bd88451SPaolo Bonzini 307*3bd88451SPaolo Bonzini case 0x34: /* TWPS */ 308*3bd88451SPaolo Bonzini return 0x00000000; /* No posted writes pending. */ 309*3bd88451SPaolo Bonzini 310*3bd88451SPaolo Bonzini case 0x38: /* TMAR */ 311*3bd88451SPaolo Bonzini return s->match_val; 312*3bd88451SPaolo Bonzini 313*3bd88451SPaolo Bonzini case 0x3c: /* TCAR1 */ 314*3bd88451SPaolo Bonzini return s->capture_val[0]; 315*3bd88451SPaolo Bonzini 316*3bd88451SPaolo Bonzini case 0x40: /* TSICR */ 317*3bd88451SPaolo Bonzini return s->posted << 2; 318*3bd88451SPaolo Bonzini 319*3bd88451SPaolo Bonzini case 0x44: /* TCAR2 */ 320*3bd88451SPaolo Bonzini return s->capture_val[1]; 321*3bd88451SPaolo Bonzini } 322*3bd88451SPaolo Bonzini 323*3bd88451SPaolo Bonzini OMAP_BAD_REG(addr); 324*3bd88451SPaolo Bonzini return 0; 325*3bd88451SPaolo Bonzini } 326*3bd88451SPaolo Bonzini 327*3bd88451SPaolo Bonzini static uint32_t omap_gp_timer_readh(void *opaque, hwaddr addr) 328*3bd88451SPaolo Bonzini { 329*3bd88451SPaolo Bonzini struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque; 330*3bd88451SPaolo Bonzini uint32_t ret; 331*3bd88451SPaolo Bonzini 332*3bd88451SPaolo Bonzini if (addr & 2) 333*3bd88451SPaolo Bonzini return s->readh; 334*3bd88451SPaolo Bonzini else { 335*3bd88451SPaolo Bonzini ret = omap_gp_timer_readw(opaque, addr); 336*3bd88451SPaolo Bonzini s->readh = ret >> 16; 337*3bd88451SPaolo Bonzini return ret & 0xffff; 338*3bd88451SPaolo Bonzini } 339*3bd88451SPaolo Bonzini } 340*3bd88451SPaolo Bonzini 341*3bd88451SPaolo Bonzini static void omap_gp_timer_write(void *opaque, hwaddr addr, 342*3bd88451SPaolo Bonzini uint32_t value) 343*3bd88451SPaolo Bonzini { 344*3bd88451SPaolo Bonzini struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque; 345*3bd88451SPaolo Bonzini 346*3bd88451SPaolo Bonzini switch (addr) { 347*3bd88451SPaolo Bonzini case 0x00: /* TIDR */ 348*3bd88451SPaolo Bonzini case 0x14: /* TISTAT */ 349*3bd88451SPaolo Bonzini case 0x34: /* TWPS */ 350*3bd88451SPaolo Bonzini case 0x3c: /* TCAR1 */ 351*3bd88451SPaolo Bonzini case 0x44: /* TCAR2 */ 352*3bd88451SPaolo Bonzini OMAP_RO_REG(addr); 353*3bd88451SPaolo Bonzini break; 354*3bd88451SPaolo Bonzini 355*3bd88451SPaolo Bonzini case 0x10: /* TIOCP_CFG */ 356*3bd88451SPaolo Bonzini s->config = value & 0x33d; 357*3bd88451SPaolo Bonzini if (((value >> 3) & 3) == 3) /* IDLEMODE */ 358*3bd88451SPaolo Bonzini fprintf(stderr, "%s: illegal IDLEMODE value in TIOCP_CFG\n", 359*3bd88451SPaolo Bonzini __FUNCTION__); 360*3bd88451SPaolo Bonzini if (value & 2) /* SOFTRESET */ 361*3bd88451SPaolo Bonzini omap_gp_timer_reset(s); 362*3bd88451SPaolo Bonzini break; 363*3bd88451SPaolo Bonzini 364*3bd88451SPaolo Bonzini case 0x18: /* TISR */ 365*3bd88451SPaolo Bonzini if (value & GPT_TCAR_IT) 366*3bd88451SPaolo Bonzini s->capt_num = 0; 367*3bd88451SPaolo Bonzini if (s->status && !(s->status &= ~value)) 368*3bd88451SPaolo Bonzini qemu_irq_lower(s->irq); 369*3bd88451SPaolo Bonzini break; 370*3bd88451SPaolo Bonzini 371*3bd88451SPaolo Bonzini case 0x1c: /* TIER */ 372*3bd88451SPaolo Bonzini s->it_ena = value & 7; 373*3bd88451SPaolo Bonzini break; 374*3bd88451SPaolo Bonzini 375*3bd88451SPaolo Bonzini case 0x20: /* TWER */ 376*3bd88451SPaolo Bonzini s->wu_ena = value & 7; 377*3bd88451SPaolo Bonzini break; 378*3bd88451SPaolo Bonzini 379*3bd88451SPaolo Bonzini case 0x24: /* TCLR */ 380*3bd88451SPaolo Bonzini omap_gp_timer_sync(s); 381*3bd88451SPaolo Bonzini s->inout = (value >> 14) & 1; 382*3bd88451SPaolo Bonzini s->capt2 = (value >> 13) & 1; 383*3bd88451SPaolo Bonzini s->pt = (value >> 12) & 1; 384*3bd88451SPaolo Bonzini s->trigger = (value >> 10) & 3; 385*3bd88451SPaolo Bonzini if (s->capture == gpt_capture_none && 386*3bd88451SPaolo Bonzini ((value >> 8) & 3) != gpt_capture_none) 387*3bd88451SPaolo Bonzini s->capt_num = 0; 388*3bd88451SPaolo Bonzini s->capture = (value >> 8) & 3; 389*3bd88451SPaolo Bonzini s->scpwm = (value >> 7) & 1; 390*3bd88451SPaolo Bonzini s->ce = (value >> 6) & 1; 391*3bd88451SPaolo Bonzini s->pre = (value >> 5) & 1; 392*3bd88451SPaolo Bonzini s->ptv = (value >> 2) & 7; 393*3bd88451SPaolo Bonzini s->ar = (value >> 1) & 1; 394*3bd88451SPaolo Bonzini s->st = (value >> 0) & 1; 395*3bd88451SPaolo Bonzini if (s->inout && s->trigger != gpt_trigger_none) 396*3bd88451SPaolo Bonzini fprintf(stderr, "%s: GP timer pin must be an output " 397*3bd88451SPaolo Bonzini "for this trigger mode\n", __FUNCTION__); 398*3bd88451SPaolo Bonzini if (!s->inout && s->capture != gpt_capture_none) 399*3bd88451SPaolo Bonzini fprintf(stderr, "%s: GP timer pin must be an input " 400*3bd88451SPaolo Bonzini "for this capture mode\n", __FUNCTION__); 401*3bd88451SPaolo Bonzini if (s->trigger == gpt_trigger_none) 402*3bd88451SPaolo Bonzini omap_gp_timer_out(s, s->scpwm); 403*3bd88451SPaolo Bonzini /* TODO: make sure this doesn't overflow 32-bits */ 404*3bd88451SPaolo Bonzini s->ticks_per_sec = get_ticks_per_sec() << (s->pre ? s->ptv + 1 : 0); 405*3bd88451SPaolo Bonzini omap_gp_timer_update(s); 406*3bd88451SPaolo Bonzini break; 407*3bd88451SPaolo Bonzini 408*3bd88451SPaolo Bonzini case 0x28: /* TCRR */ 409*3bd88451SPaolo Bonzini s->time = qemu_get_clock_ns(vm_clock); 410*3bd88451SPaolo Bonzini s->val = value; 411*3bd88451SPaolo Bonzini omap_gp_timer_update(s); 412*3bd88451SPaolo Bonzini break; 413*3bd88451SPaolo Bonzini 414*3bd88451SPaolo Bonzini case 0x2c: /* TLDR */ 415*3bd88451SPaolo Bonzini s->load_val = value; 416*3bd88451SPaolo Bonzini break; 417*3bd88451SPaolo Bonzini 418*3bd88451SPaolo Bonzini case 0x30: /* TTGR */ 419*3bd88451SPaolo Bonzini s->time = qemu_get_clock_ns(vm_clock); 420*3bd88451SPaolo Bonzini s->val = s->load_val; 421*3bd88451SPaolo Bonzini omap_gp_timer_update(s); 422*3bd88451SPaolo Bonzini break; 423*3bd88451SPaolo Bonzini 424*3bd88451SPaolo Bonzini case 0x38: /* TMAR */ 425*3bd88451SPaolo Bonzini omap_gp_timer_sync(s); 426*3bd88451SPaolo Bonzini s->match_val = value; 427*3bd88451SPaolo Bonzini omap_gp_timer_update(s); 428*3bd88451SPaolo Bonzini break; 429*3bd88451SPaolo Bonzini 430*3bd88451SPaolo Bonzini case 0x40: /* TSICR */ 431*3bd88451SPaolo Bonzini s->posted = (value >> 2) & 1; 432*3bd88451SPaolo Bonzini if (value & 2) /* How much exactly are we supposed to reset? */ 433*3bd88451SPaolo Bonzini omap_gp_timer_reset(s); 434*3bd88451SPaolo Bonzini break; 435*3bd88451SPaolo Bonzini 436*3bd88451SPaolo Bonzini default: 437*3bd88451SPaolo Bonzini OMAP_BAD_REG(addr); 438*3bd88451SPaolo Bonzini } 439*3bd88451SPaolo Bonzini } 440*3bd88451SPaolo Bonzini 441*3bd88451SPaolo Bonzini static void omap_gp_timer_writeh(void *opaque, hwaddr addr, 442*3bd88451SPaolo Bonzini uint32_t value) 443*3bd88451SPaolo Bonzini { 444*3bd88451SPaolo Bonzini struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque; 445*3bd88451SPaolo Bonzini 446*3bd88451SPaolo Bonzini if (addr & 2) 447*3bd88451SPaolo Bonzini return omap_gp_timer_write(opaque, addr, (value << 16) | s->writeh); 448*3bd88451SPaolo Bonzini else 449*3bd88451SPaolo Bonzini s->writeh = (uint16_t) value; 450*3bd88451SPaolo Bonzini } 451*3bd88451SPaolo Bonzini 452*3bd88451SPaolo Bonzini static const MemoryRegionOps omap_gp_timer_ops = { 453*3bd88451SPaolo Bonzini .old_mmio = { 454*3bd88451SPaolo Bonzini .read = { 455*3bd88451SPaolo Bonzini omap_badwidth_read32, 456*3bd88451SPaolo Bonzini omap_gp_timer_readh, 457*3bd88451SPaolo Bonzini omap_gp_timer_readw, 458*3bd88451SPaolo Bonzini }, 459*3bd88451SPaolo Bonzini .write = { 460*3bd88451SPaolo Bonzini omap_badwidth_write32, 461*3bd88451SPaolo Bonzini omap_gp_timer_writeh, 462*3bd88451SPaolo Bonzini omap_gp_timer_write, 463*3bd88451SPaolo Bonzini }, 464*3bd88451SPaolo Bonzini }, 465*3bd88451SPaolo Bonzini .endianness = DEVICE_NATIVE_ENDIAN, 466*3bd88451SPaolo Bonzini }; 467*3bd88451SPaolo Bonzini 468*3bd88451SPaolo Bonzini struct omap_gp_timer_s *omap_gp_timer_init(struct omap_target_agent_s *ta, 469*3bd88451SPaolo Bonzini qemu_irq irq, omap_clk fclk, omap_clk iclk) 470*3bd88451SPaolo Bonzini { 471*3bd88451SPaolo Bonzini struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) 472*3bd88451SPaolo Bonzini g_malloc0(sizeof(struct omap_gp_timer_s)); 473*3bd88451SPaolo Bonzini 474*3bd88451SPaolo Bonzini s->ta = ta; 475*3bd88451SPaolo Bonzini s->irq = irq; 476*3bd88451SPaolo Bonzini s->clk = fclk; 477*3bd88451SPaolo Bonzini s->timer = qemu_new_timer_ns(vm_clock, omap_gp_timer_tick, s); 478*3bd88451SPaolo Bonzini s->match = qemu_new_timer_ns(vm_clock, omap_gp_timer_match, s); 479*3bd88451SPaolo Bonzini s->in = qemu_allocate_irqs(omap_gp_timer_input, s, 1)[0]; 480*3bd88451SPaolo Bonzini omap_gp_timer_reset(s); 481*3bd88451SPaolo Bonzini omap_gp_timer_clk_setup(s); 482*3bd88451SPaolo Bonzini 483*3bd88451SPaolo Bonzini memory_region_init_io(&s->iomem, &omap_gp_timer_ops, s, "omap.gptimer", 484*3bd88451SPaolo Bonzini omap_l4_region_size(ta, 0)); 485*3bd88451SPaolo Bonzini omap_l4_attach(ta, 0, &s->iomem); 486*3bd88451SPaolo Bonzini 487*3bd88451SPaolo Bonzini return s; 488*3bd88451SPaolo Bonzini } 489