1*a50c0d6fSJean-Christophe DUBOIS /* 2*a50c0d6fSJean-Christophe DUBOIS * IMX GPT Timer 3*a50c0d6fSJean-Christophe DUBOIS * 4*a50c0d6fSJean-Christophe DUBOIS * Copyright (c) 2008 OK Labs 5*a50c0d6fSJean-Christophe DUBOIS * Copyright (c) 2011 NICTA Pty Ltd 6*a50c0d6fSJean-Christophe DUBOIS * Originally written by Hans Jiang 7*a50c0d6fSJean-Christophe DUBOIS * Updated by Peter Chubb 8*a50c0d6fSJean-Christophe DUBOIS * 9*a50c0d6fSJean-Christophe DUBOIS * This code is licensed under GPL version 2 or later. See 10*a50c0d6fSJean-Christophe DUBOIS * the COPYING file in the top-level directory. 11*a50c0d6fSJean-Christophe DUBOIS * 12*a50c0d6fSJean-Christophe DUBOIS */ 13*a50c0d6fSJean-Christophe DUBOIS 14*a50c0d6fSJean-Christophe DUBOIS #include "hw/hw.h" 15*a50c0d6fSJean-Christophe DUBOIS #include "qemu/bitops.h" 16*a50c0d6fSJean-Christophe DUBOIS #include "qemu/timer.h" 17*a50c0d6fSJean-Christophe DUBOIS #include "hw/ptimer.h" 18*a50c0d6fSJean-Christophe DUBOIS #include "hw/sysbus.h" 19*a50c0d6fSJean-Christophe DUBOIS #include "hw/arm/imx.h" 20*a50c0d6fSJean-Christophe DUBOIS 21*a50c0d6fSJean-Christophe DUBOIS //#define DEBUG_TIMER 1 22*a50c0d6fSJean-Christophe DUBOIS #ifdef DEBUG_TIMER 23*a50c0d6fSJean-Christophe DUBOIS # define DPRINTF(fmt, args...) \ 24*a50c0d6fSJean-Christophe DUBOIS do { printf("imx_timer: " fmt , ##args); } while (0) 25*a50c0d6fSJean-Christophe DUBOIS #else 26*a50c0d6fSJean-Christophe DUBOIS # define DPRINTF(fmt, args...) do {} while (0) 27*a50c0d6fSJean-Christophe DUBOIS #endif 28*a50c0d6fSJean-Christophe DUBOIS 29*a50c0d6fSJean-Christophe DUBOIS /* 30*a50c0d6fSJean-Christophe DUBOIS * Define to 1 for messages about attempts to 31*a50c0d6fSJean-Christophe DUBOIS * access unimplemented registers or similar. 32*a50c0d6fSJean-Christophe DUBOIS */ 33*a50c0d6fSJean-Christophe DUBOIS #define DEBUG_IMPLEMENTATION 1 34*a50c0d6fSJean-Christophe DUBOIS #if DEBUG_IMPLEMENTATION 35*a50c0d6fSJean-Christophe DUBOIS # define IPRINTF(fmt, args...) \ 36*a50c0d6fSJean-Christophe DUBOIS do { fprintf(stderr, "imx_timer: " fmt, ##args); } while (0) 37*a50c0d6fSJean-Christophe DUBOIS #else 38*a50c0d6fSJean-Christophe DUBOIS # define IPRINTF(fmt, args...) do {} while (0) 39*a50c0d6fSJean-Christophe DUBOIS #endif 40*a50c0d6fSJean-Christophe DUBOIS 41*a50c0d6fSJean-Christophe DUBOIS /* 42*a50c0d6fSJean-Christophe DUBOIS * GPT : General purpose timer 43*a50c0d6fSJean-Christophe DUBOIS * 44*a50c0d6fSJean-Christophe DUBOIS * This timer counts up continuously while it is enabled, resetting itself 45*a50c0d6fSJean-Christophe DUBOIS * to 0 when it reaches TIMER_MAX (in freerun mode) or when it 46*a50c0d6fSJean-Christophe DUBOIS * reaches the value of ocr1 (in periodic mode). WE simulate this using a 47*a50c0d6fSJean-Christophe DUBOIS * QEMU ptimer counting down from ocr1 and reloading from ocr1 in 48*a50c0d6fSJean-Christophe DUBOIS * periodic mode, or counting from ocr1 to zero, then TIMER_MAX - ocr1. 49*a50c0d6fSJean-Christophe DUBOIS * waiting_rov is set when counting from TIMER_MAX. 50*a50c0d6fSJean-Christophe DUBOIS * 51*a50c0d6fSJean-Christophe DUBOIS * In the real hardware, there are three comparison registers that can 52*a50c0d6fSJean-Christophe DUBOIS * trigger interrupts, and compare channel 1 can be used to 53*a50c0d6fSJean-Christophe DUBOIS * force-reset the timer. However, this is a `bare-bones' 54*a50c0d6fSJean-Christophe DUBOIS * implementation: only what Linux 3.x uses has been implemented 55*a50c0d6fSJean-Christophe DUBOIS * (free-running timer from 0 to OCR1 or TIMER_MAX) . 56*a50c0d6fSJean-Christophe DUBOIS */ 57*a50c0d6fSJean-Christophe DUBOIS 58*a50c0d6fSJean-Christophe DUBOIS #define TIMER_MAX 0XFFFFFFFFUL 59*a50c0d6fSJean-Christophe DUBOIS 60*a50c0d6fSJean-Christophe DUBOIS /* Control register. Not all of these bits have any effect (yet) */ 61*a50c0d6fSJean-Christophe DUBOIS #define GPT_CR_EN (1 << 0) /* GPT Enable */ 62*a50c0d6fSJean-Christophe DUBOIS #define GPT_CR_ENMOD (1 << 1) /* GPT Enable Mode */ 63*a50c0d6fSJean-Christophe DUBOIS #define GPT_CR_DBGEN (1 << 2) /* GPT Debug mode enable */ 64*a50c0d6fSJean-Christophe DUBOIS #define GPT_CR_WAITEN (1 << 3) /* GPT Wait Mode Enable */ 65*a50c0d6fSJean-Christophe DUBOIS #define GPT_CR_DOZEN (1 << 4) /* GPT Doze mode enable */ 66*a50c0d6fSJean-Christophe DUBOIS #define GPT_CR_STOPEN (1 << 5) /* GPT Stop Mode Enable */ 67*a50c0d6fSJean-Christophe DUBOIS #define GPT_CR_CLKSRC_SHIFT (6) 68*a50c0d6fSJean-Christophe DUBOIS #define GPT_CR_CLKSRC_MASK (0x7) 69*a50c0d6fSJean-Christophe DUBOIS 70*a50c0d6fSJean-Christophe DUBOIS #define GPT_CR_FRR (1 << 9) /* Freerun or Restart */ 71*a50c0d6fSJean-Christophe DUBOIS #define GPT_CR_SWR (1 << 15) /* Software Reset */ 72*a50c0d6fSJean-Christophe DUBOIS #define GPT_CR_IM1 (3 << 16) /* Input capture channel 1 mode (2 bits) */ 73*a50c0d6fSJean-Christophe DUBOIS #define GPT_CR_IM2 (3 << 18) /* Input capture channel 2 mode (2 bits) */ 74*a50c0d6fSJean-Christophe DUBOIS #define GPT_CR_OM1 (7 << 20) /* Output Compare Channel 1 Mode (3 bits) */ 75*a50c0d6fSJean-Christophe DUBOIS #define GPT_CR_OM2 (7 << 23) /* Output Compare Channel 2 Mode (3 bits) */ 76*a50c0d6fSJean-Christophe DUBOIS #define GPT_CR_OM3 (7 << 26) /* Output Compare Channel 3 Mode (3 bits) */ 77*a50c0d6fSJean-Christophe DUBOIS #define GPT_CR_FO1 (1 << 29) /* Force Output Compare Channel 1 */ 78*a50c0d6fSJean-Christophe DUBOIS #define GPT_CR_FO2 (1 << 30) /* Force Output Compare Channel 2 */ 79*a50c0d6fSJean-Christophe DUBOIS #define GPT_CR_FO3 (1 << 31) /* Force Output Compare Channel 3 */ 80*a50c0d6fSJean-Christophe DUBOIS 81*a50c0d6fSJean-Christophe DUBOIS #define GPT_SR_OF1 (1 << 0) 82*a50c0d6fSJean-Christophe DUBOIS #define GPT_SR_ROV (1 << 5) 83*a50c0d6fSJean-Christophe DUBOIS 84*a50c0d6fSJean-Christophe DUBOIS #define GPT_IR_OF1IE (1 << 0) 85*a50c0d6fSJean-Christophe DUBOIS #define GPT_IR_ROVIE (1 << 5) 86*a50c0d6fSJean-Christophe DUBOIS 87*a50c0d6fSJean-Christophe DUBOIS typedef struct { 88*a50c0d6fSJean-Christophe DUBOIS SysBusDevice busdev; 89*a50c0d6fSJean-Christophe DUBOIS ptimer_state *timer; 90*a50c0d6fSJean-Christophe DUBOIS MemoryRegion iomem; 91*a50c0d6fSJean-Christophe DUBOIS DeviceState *ccm; 92*a50c0d6fSJean-Christophe DUBOIS 93*a50c0d6fSJean-Christophe DUBOIS uint32_t cr; 94*a50c0d6fSJean-Christophe DUBOIS uint32_t pr; 95*a50c0d6fSJean-Christophe DUBOIS uint32_t sr; 96*a50c0d6fSJean-Christophe DUBOIS uint32_t ir; 97*a50c0d6fSJean-Christophe DUBOIS uint32_t ocr1; 98*a50c0d6fSJean-Christophe DUBOIS uint32_t ocr2; 99*a50c0d6fSJean-Christophe DUBOIS uint32_t ocr3; 100*a50c0d6fSJean-Christophe DUBOIS uint32_t icr1; 101*a50c0d6fSJean-Christophe DUBOIS uint32_t icr2; 102*a50c0d6fSJean-Christophe DUBOIS uint32_t cnt; 103*a50c0d6fSJean-Christophe DUBOIS 104*a50c0d6fSJean-Christophe DUBOIS uint32_t waiting_rov; 105*a50c0d6fSJean-Christophe DUBOIS qemu_irq irq; 106*a50c0d6fSJean-Christophe DUBOIS } IMXTimerGState; 107*a50c0d6fSJean-Christophe DUBOIS 108*a50c0d6fSJean-Christophe DUBOIS static const VMStateDescription vmstate_imx_timerg = { 109*a50c0d6fSJean-Christophe DUBOIS .name = "imx-timerg", 110*a50c0d6fSJean-Christophe DUBOIS .version_id = 2, 111*a50c0d6fSJean-Christophe DUBOIS .minimum_version_id = 2, 112*a50c0d6fSJean-Christophe DUBOIS .minimum_version_id_old = 2, 113*a50c0d6fSJean-Christophe DUBOIS .fields = (VMStateField[]) { 114*a50c0d6fSJean-Christophe DUBOIS VMSTATE_UINT32(cr, IMXTimerGState), 115*a50c0d6fSJean-Christophe DUBOIS VMSTATE_UINT32(pr, IMXTimerGState), 116*a50c0d6fSJean-Christophe DUBOIS VMSTATE_UINT32(sr, IMXTimerGState), 117*a50c0d6fSJean-Christophe DUBOIS VMSTATE_UINT32(ir, IMXTimerGState), 118*a50c0d6fSJean-Christophe DUBOIS VMSTATE_UINT32(ocr1, IMXTimerGState), 119*a50c0d6fSJean-Christophe DUBOIS VMSTATE_UINT32(ocr2, IMXTimerGState), 120*a50c0d6fSJean-Christophe DUBOIS VMSTATE_UINT32(ocr3, IMXTimerGState), 121*a50c0d6fSJean-Christophe DUBOIS VMSTATE_UINT32(icr1, IMXTimerGState), 122*a50c0d6fSJean-Christophe DUBOIS VMSTATE_UINT32(icr2, IMXTimerGState), 123*a50c0d6fSJean-Christophe DUBOIS VMSTATE_UINT32(cnt, IMXTimerGState), 124*a50c0d6fSJean-Christophe DUBOIS VMSTATE_UINT32(waiting_rov, IMXTimerGState), 125*a50c0d6fSJean-Christophe DUBOIS VMSTATE_PTIMER(timer, IMXTimerGState), 126*a50c0d6fSJean-Christophe DUBOIS VMSTATE_END_OF_LIST() 127*a50c0d6fSJean-Christophe DUBOIS } 128*a50c0d6fSJean-Christophe DUBOIS }; 129*a50c0d6fSJean-Christophe DUBOIS 130*a50c0d6fSJean-Christophe DUBOIS static const IMXClk imx_timerg_clocks[] = { 131*a50c0d6fSJean-Christophe DUBOIS NOCLK, /* 000 No clock source */ 132*a50c0d6fSJean-Christophe DUBOIS IPG, /* 001 ipg_clk, 532MHz*/ 133*a50c0d6fSJean-Christophe DUBOIS IPG, /* 010 ipg_clk_highfreq */ 134*a50c0d6fSJean-Christophe DUBOIS NOCLK, /* 011 not defined */ 135*a50c0d6fSJean-Christophe DUBOIS CLK_32k, /* 100 ipg_clk_32k */ 136*a50c0d6fSJean-Christophe DUBOIS NOCLK, /* 101 not defined */ 137*a50c0d6fSJean-Christophe DUBOIS NOCLK, /* 110 not defined */ 138*a50c0d6fSJean-Christophe DUBOIS NOCLK, /* 111 not defined */ 139*a50c0d6fSJean-Christophe DUBOIS }; 140*a50c0d6fSJean-Christophe DUBOIS 141*a50c0d6fSJean-Christophe DUBOIS 142*a50c0d6fSJean-Christophe DUBOIS static void imx_timerg_set_freq(IMXTimerGState *s) 143*a50c0d6fSJean-Christophe DUBOIS { 144*a50c0d6fSJean-Christophe DUBOIS int clksrc; 145*a50c0d6fSJean-Christophe DUBOIS uint32_t freq; 146*a50c0d6fSJean-Christophe DUBOIS 147*a50c0d6fSJean-Christophe DUBOIS clksrc = (s->cr >> GPT_CR_CLKSRC_SHIFT) & GPT_CR_CLKSRC_MASK; 148*a50c0d6fSJean-Christophe DUBOIS freq = imx_clock_frequency(s->ccm, imx_timerg_clocks[clksrc]) / (1 + s->pr); 149*a50c0d6fSJean-Christophe DUBOIS 150*a50c0d6fSJean-Christophe DUBOIS DPRINTF("Setting gtimer clksrc %d to frequency %d\n", clksrc, freq); 151*a50c0d6fSJean-Christophe DUBOIS 152*a50c0d6fSJean-Christophe DUBOIS if (freq) { 153*a50c0d6fSJean-Christophe DUBOIS ptimer_set_freq(s->timer, freq); 154*a50c0d6fSJean-Christophe DUBOIS } 155*a50c0d6fSJean-Christophe DUBOIS } 156*a50c0d6fSJean-Christophe DUBOIS 157*a50c0d6fSJean-Christophe DUBOIS static void imx_timerg_update(IMXTimerGState *s) 158*a50c0d6fSJean-Christophe DUBOIS { 159*a50c0d6fSJean-Christophe DUBOIS uint32_t flags = s->sr & s->ir & (GPT_SR_OF1 | GPT_SR_ROV); 160*a50c0d6fSJean-Christophe DUBOIS 161*a50c0d6fSJean-Christophe DUBOIS DPRINTF("g-timer SR: %s %s IR=%s %s, %s\n", 162*a50c0d6fSJean-Christophe DUBOIS s->sr & GPT_SR_OF1 ? "OF1" : "", 163*a50c0d6fSJean-Christophe DUBOIS s->sr & GPT_SR_ROV ? "ROV" : "", 164*a50c0d6fSJean-Christophe DUBOIS s->ir & GPT_SR_OF1 ? "OF1" : "", 165*a50c0d6fSJean-Christophe DUBOIS s->ir & GPT_SR_ROV ? "ROV" : "", 166*a50c0d6fSJean-Christophe DUBOIS s->cr & GPT_CR_EN ? "CR_EN" : "Not Enabled"); 167*a50c0d6fSJean-Christophe DUBOIS 168*a50c0d6fSJean-Christophe DUBOIS qemu_set_irq(s->irq, (s->cr & GPT_CR_EN) && flags); 169*a50c0d6fSJean-Christophe DUBOIS } 170*a50c0d6fSJean-Christophe DUBOIS 171*a50c0d6fSJean-Christophe DUBOIS static uint32_t imx_timerg_update_counts(IMXTimerGState *s) 172*a50c0d6fSJean-Christophe DUBOIS { 173*a50c0d6fSJean-Christophe DUBOIS uint64_t target = s->waiting_rov ? TIMER_MAX : s->ocr1; 174*a50c0d6fSJean-Christophe DUBOIS uint64_t cnt = ptimer_get_count(s->timer); 175*a50c0d6fSJean-Christophe DUBOIS s->cnt = target - cnt; 176*a50c0d6fSJean-Christophe DUBOIS return s->cnt; 177*a50c0d6fSJean-Christophe DUBOIS } 178*a50c0d6fSJean-Christophe DUBOIS 179*a50c0d6fSJean-Christophe DUBOIS static void imx_timerg_reload(IMXTimerGState *s, uint32_t timeout) 180*a50c0d6fSJean-Christophe DUBOIS { 181*a50c0d6fSJean-Christophe DUBOIS uint64_t diff_cnt; 182*a50c0d6fSJean-Christophe DUBOIS 183*a50c0d6fSJean-Christophe DUBOIS if (!(s->cr & GPT_CR_FRR)) { 184*a50c0d6fSJean-Christophe DUBOIS IPRINTF("IMX_timerg_reload --- called in reset-mode\n"); 185*a50c0d6fSJean-Christophe DUBOIS return; 186*a50c0d6fSJean-Christophe DUBOIS } 187*a50c0d6fSJean-Christophe DUBOIS 188*a50c0d6fSJean-Christophe DUBOIS /* 189*a50c0d6fSJean-Christophe DUBOIS * For small timeouts, qemu sometimes runs too slow. 190*a50c0d6fSJean-Christophe DUBOIS * Better deliver a late interrupt than none. 191*a50c0d6fSJean-Christophe DUBOIS * 192*a50c0d6fSJean-Christophe DUBOIS * In Reset mode (FRR bit clear) 193*a50c0d6fSJean-Christophe DUBOIS * the ptimer reloads itself from OCR1; 194*a50c0d6fSJean-Christophe DUBOIS * in free-running mode we need to fake 195*a50c0d6fSJean-Christophe DUBOIS * running from 0 to ocr1 to TIMER_MAX 196*a50c0d6fSJean-Christophe DUBOIS */ 197*a50c0d6fSJean-Christophe DUBOIS if (timeout > s->cnt) { 198*a50c0d6fSJean-Christophe DUBOIS diff_cnt = timeout - s->cnt; 199*a50c0d6fSJean-Christophe DUBOIS } else { 200*a50c0d6fSJean-Christophe DUBOIS diff_cnt = 0; 201*a50c0d6fSJean-Christophe DUBOIS } 202*a50c0d6fSJean-Christophe DUBOIS ptimer_set_count(s->timer, diff_cnt); 203*a50c0d6fSJean-Christophe DUBOIS } 204*a50c0d6fSJean-Christophe DUBOIS 205*a50c0d6fSJean-Christophe DUBOIS static uint64_t imx_timerg_read(void *opaque, hwaddr offset, 206*a50c0d6fSJean-Christophe DUBOIS unsigned size) 207*a50c0d6fSJean-Christophe DUBOIS { 208*a50c0d6fSJean-Christophe DUBOIS IMXTimerGState *s = (IMXTimerGState *)opaque; 209*a50c0d6fSJean-Christophe DUBOIS 210*a50c0d6fSJean-Christophe DUBOIS DPRINTF("g-read(offset=%x)", (unsigned int)(offset >> 2)); 211*a50c0d6fSJean-Christophe DUBOIS switch (offset >> 2) { 212*a50c0d6fSJean-Christophe DUBOIS case 0: /* Control Register */ 213*a50c0d6fSJean-Christophe DUBOIS DPRINTF(" cr = %x\n", s->cr); 214*a50c0d6fSJean-Christophe DUBOIS return s->cr; 215*a50c0d6fSJean-Christophe DUBOIS 216*a50c0d6fSJean-Christophe DUBOIS case 1: /* prescaler */ 217*a50c0d6fSJean-Christophe DUBOIS DPRINTF(" pr = %x\n", s->pr); 218*a50c0d6fSJean-Christophe DUBOIS return s->pr; 219*a50c0d6fSJean-Christophe DUBOIS 220*a50c0d6fSJean-Christophe DUBOIS case 2: /* Status Register */ 221*a50c0d6fSJean-Christophe DUBOIS DPRINTF(" sr = %x\n", s->sr); 222*a50c0d6fSJean-Christophe DUBOIS return s->sr; 223*a50c0d6fSJean-Christophe DUBOIS 224*a50c0d6fSJean-Christophe DUBOIS case 3: /* Interrupt Register */ 225*a50c0d6fSJean-Christophe DUBOIS DPRINTF(" ir = %x\n", s->ir); 226*a50c0d6fSJean-Christophe DUBOIS return s->ir; 227*a50c0d6fSJean-Christophe DUBOIS 228*a50c0d6fSJean-Christophe DUBOIS case 4: /* Output Compare Register 1 */ 229*a50c0d6fSJean-Christophe DUBOIS DPRINTF(" ocr1 = %x\n", s->ocr1); 230*a50c0d6fSJean-Christophe DUBOIS return s->ocr1; 231*a50c0d6fSJean-Christophe DUBOIS 232*a50c0d6fSJean-Christophe DUBOIS case 5: /* Output Compare Register 2 */ 233*a50c0d6fSJean-Christophe DUBOIS DPRINTF(" ocr2 = %x\n", s->ocr2); 234*a50c0d6fSJean-Christophe DUBOIS return s->ocr2; 235*a50c0d6fSJean-Christophe DUBOIS 236*a50c0d6fSJean-Christophe DUBOIS case 6: /* Output Compare Register 3 */ 237*a50c0d6fSJean-Christophe DUBOIS DPRINTF(" ocr3 = %x\n", s->ocr3); 238*a50c0d6fSJean-Christophe DUBOIS return s->ocr3; 239*a50c0d6fSJean-Christophe DUBOIS 240*a50c0d6fSJean-Christophe DUBOIS case 7: /* input Capture Register 1 */ 241*a50c0d6fSJean-Christophe DUBOIS DPRINTF(" icr1 = %x\n", s->icr1); 242*a50c0d6fSJean-Christophe DUBOIS return s->icr1; 243*a50c0d6fSJean-Christophe DUBOIS 244*a50c0d6fSJean-Christophe DUBOIS case 8: /* input Capture Register 2 */ 245*a50c0d6fSJean-Christophe DUBOIS DPRINTF(" icr2 = %x\n", s->icr2); 246*a50c0d6fSJean-Christophe DUBOIS return s->icr2; 247*a50c0d6fSJean-Christophe DUBOIS 248*a50c0d6fSJean-Christophe DUBOIS case 9: /* cnt */ 249*a50c0d6fSJean-Christophe DUBOIS imx_timerg_update_counts(s); 250*a50c0d6fSJean-Christophe DUBOIS DPRINTF(" cnt = %x\n", s->cnt); 251*a50c0d6fSJean-Christophe DUBOIS return s->cnt; 252*a50c0d6fSJean-Christophe DUBOIS } 253*a50c0d6fSJean-Christophe DUBOIS 254*a50c0d6fSJean-Christophe DUBOIS IPRINTF("imx_timerg_read: Bad offset %x\n", 255*a50c0d6fSJean-Christophe DUBOIS (int)offset >> 2); 256*a50c0d6fSJean-Christophe DUBOIS 257*a50c0d6fSJean-Christophe DUBOIS return 0; 258*a50c0d6fSJean-Christophe DUBOIS } 259*a50c0d6fSJean-Christophe DUBOIS 260*a50c0d6fSJean-Christophe DUBOIS static void imx_timerg_reset(DeviceState *dev) 261*a50c0d6fSJean-Christophe DUBOIS { 262*a50c0d6fSJean-Christophe DUBOIS IMXTimerGState *s = container_of(dev, IMXTimerGState, busdev.qdev); 263*a50c0d6fSJean-Christophe DUBOIS 264*a50c0d6fSJean-Christophe DUBOIS /* 265*a50c0d6fSJean-Christophe DUBOIS * Soft reset doesn't touch some bits; hard reset clears them 266*a50c0d6fSJean-Christophe DUBOIS */ 267*a50c0d6fSJean-Christophe DUBOIS s->cr &= ~(GPT_CR_EN|GPT_CR_ENMOD|GPT_CR_STOPEN|GPT_CR_DOZEN| 268*a50c0d6fSJean-Christophe DUBOIS GPT_CR_WAITEN|GPT_CR_DBGEN); 269*a50c0d6fSJean-Christophe DUBOIS s->sr = 0; 270*a50c0d6fSJean-Christophe DUBOIS s->pr = 0; 271*a50c0d6fSJean-Christophe DUBOIS s->ir = 0; 272*a50c0d6fSJean-Christophe DUBOIS s->cnt = 0; 273*a50c0d6fSJean-Christophe DUBOIS s->ocr1 = TIMER_MAX; 274*a50c0d6fSJean-Christophe DUBOIS s->ocr2 = TIMER_MAX; 275*a50c0d6fSJean-Christophe DUBOIS s->ocr3 = TIMER_MAX; 276*a50c0d6fSJean-Christophe DUBOIS s->icr1 = 0; 277*a50c0d6fSJean-Christophe DUBOIS s->icr2 = 0; 278*a50c0d6fSJean-Christophe DUBOIS ptimer_stop(s->timer); 279*a50c0d6fSJean-Christophe DUBOIS ptimer_set_limit(s->timer, TIMER_MAX, 1); 280*a50c0d6fSJean-Christophe DUBOIS ptimer_set_count(s->timer, TIMER_MAX); 281*a50c0d6fSJean-Christophe DUBOIS imx_timerg_set_freq(s); 282*a50c0d6fSJean-Christophe DUBOIS } 283*a50c0d6fSJean-Christophe DUBOIS 284*a50c0d6fSJean-Christophe DUBOIS static void imx_timerg_write(void *opaque, hwaddr offset, 285*a50c0d6fSJean-Christophe DUBOIS uint64_t value, unsigned size) 286*a50c0d6fSJean-Christophe DUBOIS { 287*a50c0d6fSJean-Christophe DUBOIS IMXTimerGState *s = (IMXTimerGState *)opaque; 288*a50c0d6fSJean-Christophe DUBOIS DPRINTF("g-write(offset=%x, value = 0x%x)\n", (unsigned int)offset >> 2, 289*a50c0d6fSJean-Christophe DUBOIS (unsigned int)value); 290*a50c0d6fSJean-Christophe DUBOIS 291*a50c0d6fSJean-Christophe DUBOIS switch (offset >> 2) { 292*a50c0d6fSJean-Christophe DUBOIS case 0: { 293*a50c0d6fSJean-Christophe DUBOIS uint32_t oldcr = s->cr; 294*a50c0d6fSJean-Christophe DUBOIS /* CR */ 295*a50c0d6fSJean-Christophe DUBOIS if (value & GPT_CR_SWR) { /* force reset */ 296*a50c0d6fSJean-Christophe DUBOIS value &= ~GPT_CR_SWR; 297*a50c0d6fSJean-Christophe DUBOIS imx_timerg_reset(&s->busdev.qdev); 298*a50c0d6fSJean-Christophe DUBOIS imx_timerg_update(s); 299*a50c0d6fSJean-Christophe DUBOIS } 300*a50c0d6fSJean-Christophe DUBOIS 301*a50c0d6fSJean-Christophe DUBOIS s->cr = value & ~0x7c00; 302*a50c0d6fSJean-Christophe DUBOIS imx_timerg_set_freq(s); 303*a50c0d6fSJean-Christophe DUBOIS if ((oldcr ^ value) & GPT_CR_EN) { 304*a50c0d6fSJean-Christophe DUBOIS if (value & GPT_CR_EN) { 305*a50c0d6fSJean-Christophe DUBOIS if (value & GPT_CR_ENMOD) { 306*a50c0d6fSJean-Christophe DUBOIS ptimer_set_count(s->timer, s->ocr1); 307*a50c0d6fSJean-Christophe DUBOIS s->cnt = 0; 308*a50c0d6fSJean-Christophe DUBOIS } 309*a50c0d6fSJean-Christophe DUBOIS ptimer_run(s->timer, 310*a50c0d6fSJean-Christophe DUBOIS (value & GPT_CR_FRR) && (s->ocr1 != TIMER_MAX)); 311*a50c0d6fSJean-Christophe DUBOIS } else { 312*a50c0d6fSJean-Christophe DUBOIS ptimer_stop(s->timer); 313*a50c0d6fSJean-Christophe DUBOIS }; 314*a50c0d6fSJean-Christophe DUBOIS } 315*a50c0d6fSJean-Christophe DUBOIS return; 316*a50c0d6fSJean-Christophe DUBOIS } 317*a50c0d6fSJean-Christophe DUBOIS 318*a50c0d6fSJean-Christophe DUBOIS case 1: /* Prescaler */ 319*a50c0d6fSJean-Christophe DUBOIS s->pr = value & 0xfff; 320*a50c0d6fSJean-Christophe DUBOIS imx_timerg_set_freq(s); 321*a50c0d6fSJean-Christophe DUBOIS return; 322*a50c0d6fSJean-Christophe DUBOIS 323*a50c0d6fSJean-Christophe DUBOIS case 2: /* SR */ 324*a50c0d6fSJean-Christophe DUBOIS /* 325*a50c0d6fSJean-Christophe DUBOIS * No point in implementing the status register bits to do with 326*a50c0d6fSJean-Christophe DUBOIS * external interrupt sources. 327*a50c0d6fSJean-Christophe DUBOIS */ 328*a50c0d6fSJean-Christophe DUBOIS value &= GPT_SR_OF1 | GPT_SR_ROV; 329*a50c0d6fSJean-Christophe DUBOIS s->sr &= ~value; 330*a50c0d6fSJean-Christophe DUBOIS imx_timerg_update(s); 331*a50c0d6fSJean-Christophe DUBOIS return; 332*a50c0d6fSJean-Christophe DUBOIS 333*a50c0d6fSJean-Christophe DUBOIS case 3: /* IR -- interrupt register */ 334*a50c0d6fSJean-Christophe DUBOIS s->ir = value & 0x3f; 335*a50c0d6fSJean-Christophe DUBOIS imx_timerg_update(s); 336*a50c0d6fSJean-Christophe DUBOIS return; 337*a50c0d6fSJean-Christophe DUBOIS 338*a50c0d6fSJean-Christophe DUBOIS case 4: /* OCR1 -- output compare register */ 339*a50c0d6fSJean-Christophe DUBOIS /* In non-freerun mode, reset count when this register is written */ 340*a50c0d6fSJean-Christophe DUBOIS if (!(s->cr & GPT_CR_FRR)) { 341*a50c0d6fSJean-Christophe DUBOIS s->waiting_rov = 0; 342*a50c0d6fSJean-Christophe DUBOIS ptimer_set_limit(s->timer, value, 1); 343*a50c0d6fSJean-Christophe DUBOIS } else { 344*a50c0d6fSJean-Christophe DUBOIS imx_timerg_update_counts(s); 345*a50c0d6fSJean-Christophe DUBOIS if (value > s->cnt) { 346*a50c0d6fSJean-Christophe DUBOIS s->waiting_rov = 0; 347*a50c0d6fSJean-Christophe DUBOIS imx_timerg_reload(s, value); 348*a50c0d6fSJean-Christophe DUBOIS } else { 349*a50c0d6fSJean-Christophe DUBOIS s->waiting_rov = 1; 350*a50c0d6fSJean-Christophe DUBOIS imx_timerg_reload(s, TIMER_MAX - s->cnt); 351*a50c0d6fSJean-Christophe DUBOIS } 352*a50c0d6fSJean-Christophe DUBOIS } 353*a50c0d6fSJean-Christophe DUBOIS s->ocr1 = value; 354*a50c0d6fSJean-Christophe DUBOIS return; 355*a50c0d6fSJean-Christophe DUBOIS 356*a50c0d6fSJean-Christophe DUBOIS case 5: /* OCR2 -- output compare register */ 357*a50c0d6fSJean-Christophe DUBOIS case 6: /* OCR3 -- output compare register */ 358*a50c0d6fSJean-Christophe DUBOIS default: 359*a50c0d6fSJean-Christophe DUBOIS IPRINTF("imx_timerg_write: Bad offset %x\n", 360*a50c0d6fSJean-Christophe DUBOIS (int)offset >> 2); 361*a50c0d6fSJean-Christophe DUBOIS } 362*a50c0d6fSJean-Christophe DUBOIS } 363*a50c0d6fSJean-Christophe DUBOIS 364*a50c0d6fSJean-Christophe DUBOIS static void imx_timerg_timeout(void *opaque) 365*a50c0d6fSJean-Christophe DUBOIS { 366*a50c0d6fSJean-Christophe DUBOIS IMXTimerGState *s = (IMXTimerGState *)opaque; 367*a50c0d6fSJean-Christophe DUBOIS 368*a50c0d6fSJean-Christophe DUBOIS DPRINTF("imx_timerg_timeout, waiting rov=%d\n", s->waiting_rov); 369*a50c0d6fSJean-Christophe DUBOIS if (s->cr & GPT_CR_FRR) { 370*a50c0d6fSJean-Christophe DUBOIS /* 371*a50c0d6fSJean-Christophe DUBOIS * Free running timer from 0 -> TIMERMAX 372*a50c0d6fSJean-Christophe DUBOIS * Generates interrupt at TIMER_MAX and at cnt==ocr1 373*a50c0d6fSJean-Christophe DUBOIS * If ocr1 == TIMER_MAX, then no need to reload timer. 374*a50c0d6fSJean-Christophe DUBOIS */ 375*a50c0d6fSJean-Christophe DUBOIS if (s->ocr1 == TIMER_MAX) { 376*a50c0d6fSJean-Christophe DUBOIS DPRINTF("s->ocr1 == TIMER_MAX, FRR\n"); 377*a50c0d6fSJean-Christophe DUBOIS s->sr |= GPT_SR_OF1 | GPT_SR_ROV; 378*a50c0d6fSJean-Christophe DUBOIS imx_timerg_update(s); 379*a50c0d6fSJean-Christophe DUBOIS return; 380*a50c0d6fSJean-Christophe DUBOIS } 381*a50c0d6fSJean-Christophe DUBOIS 382*a50c0d6fSJean-Christophe DUBOIS if (s->waiting_rov) { 383*a50c0d6fSJean-Christophe DUBOIS /* 384*a50c0d6fSJean-Christophe DUBOIS * We were waiting for cnt==TIMER_MAX 385*a50c0d6fSJean-Christophe DUBOIS */ 386*a50c0d6fSJean-Christophe DUBOIS s->sr |= GPT_SR_ROV; 387*a50c0d6fSJean-Christophe DUBOIS s->waiting_rov = 0; 388*a50c0d6fSJean-Christophe DUBOIS s->cnt = 0; 389*a50c0d6fSJean-Christophe DUBOIS imx_timerg_reload(s, s->ocr1); 390*a50c0d6fSJean-Christophe DUBOIS } else { 391*a50c0d6fSJean-Christophe DUBOIS /* Must have got a cnt==ocr1 timeout. */ 392*a50c0d6fSJean-Christophe DUBOIS s->sr |= GPT_SR_OF1; 393*a50c0d6fSJean-Christophe DUBOIS s->cnt = s->ocr1; 394*a50c0d6fSJean-Christophe DUBOIS s->waiting_rov = 1; 395*a50c0d6fSJean-Christophe DUBOIS imx_timerg_reload(s, TIMER_MAX); 396*a50c0d6fSJean-Christophe DUBOIS } 397*a50c0d6fSJean-Christophe DUBOIS imx_timerg_update(s); 398*a50c0d6fSJean-Christophe DUBOIS return; 399*a50c0d6fSJean-Christophe DUBOIS } 400*a50c0d6fSJean-Christophe DUBOIS 401*a50c0d6fSJean-Christophe DUBOIS s->sr |= GPT_SR_OF1; 402*a50c0d6fSJean-Christophe DUBOIS imx_timerg_update(s); 403*a50c0d6fSJean-Christophe DUBOIS } 404*a50c0d6fSJean-Christophe DUBOIS 405*a50c0d6fSJean-Christophe DUBOIS static const MemoryRegionOps imx_timerg_ops = { 406*a50c0d6fSJean-Christophe DUBOIS .read = imx_timerg_read, 407*a50c0d6fSJean-Christophe DUBOIS .write = imx_timerg_write, 408*a50c0d6fSJean-Christophe DUBOIS .endianness = DEVICE_NATIVE_ENDIAN, 409*a50c0d6fSJean-Christophe DUBOIS }; 410*a50c0d6fSJean-Christophe DUBOIS 411*a50c0d6fSJean-Christophe DUBOIS 412*a50c0d6fSJean-Christophe DUBOIS static int imx_timerg_init(SysBusDevice *dev) 413*a50c0d6fSJean-Christophe DUBOIS { 414*a50c0d6fSJean-Christophe DUBOIS IMXTimerGState *s = FROM_SYSBUS(IMXTimerGState, dev); 415*a50c0d6fSJean-Christophe DUBOIS QEMUBH *bh; 416*a50c0d6fSJean-Christophe DUBOIS 417*a50c0d6fSJean-Christophe DUBOIS sysbus_init_irq(dev, &s->irq); 418*a50c0d6fSJean-Christophe DUBOIS memory_region_init_io(&s->iomem, &imx_timerg_ops, 419*a50c0d6fSJean-Christophe DUBOIS s, "imxg-timer", 420*a50c0d6fSJean-Christophe DUBOIS 0x00001000); 421*a50c0d6fSJean-Christophe DUBOIS sysbus_init_mmio(dev, &s->iomem); 422*a50c0d6fSJean-Christophe DUBOIS 423*a50c0d6fSJean-Christophe DUBOIS bh = qemu_bh_new(imx_timerg_timeout, s); 424*a50c0d6fSJean-Christophe DUBOIS s->timer = ptimer_init(bh); 425*a50c0d6fSJean-Christophe DUBOIS 426*a50c0d6fSJean-Christophe DUBOIS /* Hard reset resets extra bits in CR */ 427*a50c0d6fSJean-Christophe DUBOIS s->cr = 0; 428*a50c0d6fSJean-Christophe DUBOIS return 0; 429*a50c0d6fSJean-Christophe DUBOIS } 430*a50c0d6fSJean-Christophe DUBOIS 431*a50c0d6fSJean-Christophe DUBOIS void imx_timerg_create(const hwaddr addr, 432*a50c0d6fSJean-Christophe DUBOIS qemu_irq irq, 433*a50c0d6fSJean-Christophe DUBOIS DeviceState *ccm) 434*a50c0d6fSJean-Christophe DUBOIS { 435*a50c0d6fSJean-Christophe DUBOIS IMXTimerGState *pp; 436*a50c0d6fSJean-Christophe DUBOIS DeviceState *dev; 437*a50c0d6fSJean-Christophe DUBOIS 438*a50c0d6fSJean-Christophe DUBOIS dev = sysbus_create_simple("imx_timerg", addr, irq); 439*a50c0d6fSJean-Christophe DUBOIS pp = container_of(dev, IMXTimerGState, busdev.qdev); 440*a50c0d6fSJean-Christophe DUBOIS pp->ccm = ccm; 441*a50c0d6fSJean-Christophe DUBOIS } 442*a50c0d6fSJean-Christophe DUBOIS 443*a50c0d6fSJean-Christophe DUBOIS static void imx_timerg_class_init(ObjectClass *klass, void *data) 444*a50c0d6fSJean-Christophe DUBOIS { 445*a50c0d6fSJean-Christophe DUBOIS DeviceClass *dc = DEVICE_CLASS(klass); 446*a50c0d6fSJean-Christophe DUBOIS SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); 447*a50c0d6fSJean-Christophe DUBOIS k->init = imx_timerg_init; 448*a50c0d6fSJean-Christophe DUBOIS dc->vmsd = &vmstate_imx_timerg; 449*a50c0d6fSJean-Christophe DUBOIS dc->reset = imx_timerg_reset; 450*a50c0d6fSJean-Christophe DUBOIS dc->desc = "i.MX general timer"; 451*a50c0d6fSJean-Christophe DUBOIS } 452*a50c0d6fSJean-Christophe DUBOIS 453*a50c0d6fSJean-Christophe DUBOIS static const TypeInfo imx_timerg_info = { 454*a50c0d6fSJean-Christophe DUBOIS .name = "imx_timerg", 455*a50c0d6fSJean-Christophe DUBOIS .parent = TYPE_SYS_BUS_DEVICE, 456*a50c0d6fSJean-Christophe DUBOIS .instance_size = sizeof(IMXTimerGState), 457*a50c0d6fSJean-Christophe DUBOIS .class_init = imx_timerg_class_init, 458*a50c0d6fSJean-Christophe DUBOIS }; 459*a50c0d6fSJean-Christophe DUBOIS 460*a50c0d6fSJean-Christophe DUBOIS static void imx_timer_register_types(void) 461*a50c0d6fSJean-Christophe DUBOIS { 462*a50c0d6fSJean-Christophe DUBOIS type_register_static(&imx_timerg_info); 463*a50c0d6fSJean-Christophe DUBOIS } 464*a50c0d6fSJean-Christophe DUBOIS 465*a50c0d6fSJean-Christophe DUBOIS type_init(imx_timer_register_types) 466