1a50c0d6fSJean-Christophe DUBOIS /* 2a50c0d6fSJean-Christophe DUBOIS * IMX GPT Timer 3a50c0d6fSJean-Christophe DUBOIS * 4a50c0d6fSJean-Christophe DUBOIS * Copyright (c) 2008 OK Labs 5a50c0d6fSJean-Christophe DUBOIS * Copyright (c) 2011 NICTA Pty Ltd 6a50c0d6fSJean-Christophe DUBOIS * Originally written by Hans Jiang 7a50c0d6fSJean-Christophe DUBOIS * Updated by Peter Chubb 8*5ec694b5SJean-Christophe DUBOIS * Updated by Jean-Christophe Dubois 9a50c0d6fSJean-Christophe DUBOIS * 10a50c0d6fSJean-Christophe DUBOIS * This code is licensed under GPL version 2 or later. See 11a50c0d6fSJean-Christophe DUBOIS * the COPYING file in the top-level directory. 12a50c0d6fSJean-Christophe DUBOIS * 13a50c0d6fSJean-Christophe DUBOIS */ 14a50c0d6fSJean-Christophe DUBOIS 15a50c0d6fSJean-Christophe DUBOIS #include "hw/hw.h" 16a50c0d6fSJean-Christophe DUBOIS #include "qemu/bitops.h" 17a50c0d6fSJean-Christophe DUBOIS #include "qemu/timer.h" 18a50c0d6fSJean-Christophe DUBOIS #include "hw/ptimer.h" 19a50c0d6fSJean-Christophe DUBOIS #include "hw/sysbus.h" 20a50c0d6fSJean-Christophe DUBOIS #include "hw/arm/imx.h" 21a50c0d6fSJean-Christophe DUBOIS 22*5ec694b5SJean-Christophe DUBOIS #define TYPE_IMX_GPT "imx.gpt" 23*5ec694b5SJean-Christophe DUBOIS 24*5ec694b5SJean-Christophe DUBOIS /* 25*5ec694b5SJean-Christophe DUBOIS * Define to 1 for debug messages 26*5ec694b5SJean-Christophe DUBOIS */ 27*5ec694b5SJean-Christophe DUBOIS #define DEBUG_TIMER 0 28*5ec694b5SJean-Christophe DUBOIS #if DEBUG_TIMER 29*5ec694b5SJean-Christophe DUBOIS 30*5ec694b5SJean-Christophe DUBOIS static char const *imx_timerg_reg_name(uint32_t reg) 31*5ec694b5SJean-Christophe DUBOIS { 32*5ec694b5SJean-Christophe DUBOIS switch (reg) { 33*5ec694b5SJean-Christophe DUBOIS case 0: 34*5ec694b5SJean-Christophe DUBOIS return "CR"; 35*5ec694b5SJean-Christophe DUBOIS case 1: 36*5ec694b5SJean-Christophe DUBOIS return "PR"; 37*5ec694b5SJean-Christophe DUBOIS case 2: 38*5ec694b5SJean-Christophe DUBOIS return "SR"; 39*5ec694b5SJean-Christophe DUBOIS case 3: 40*5ec694b5SJean-Christophe DUBOIS return "IR"; 41*5ec694b5SJean-Christophe DUBOIS case 4: 42*5ec694b5SJean-Christophe DUBOIS return "OCR1"; 43*5ec694b5SJean-Christophe DUBOIS case 5: 44*5ec694b5SJean-Christophe DUBOIS return "OCR2"; 45*5ec694b5SJean-Christophe DUBOIS case 6: 46*5ec694b5SJean-Christophe DUBOIS return "OCR3"; 47*5ec694b5SJean-Christophe DUBOIS case 7: 48*5ec694b5SJean-Christophe DUBOIS return "ICR1"; 49*5ec694b5SJean-Christophe DUBOIS case 8: 50*5ec694b5SJean-Christophe DUBOIS return "ICR2"; 51*5ec694b5SJean-Christophe DUBOIS case 9: 52*5ec694b5SJean-Christophe DUBOIS return "CNT"; 53*5ec694b5SJean-Christophe DUBOIS default: 54*5ec694b5SJean-Christophe DUBOIS return "[?]"; 55*5ec694b5SJean-Christophe DUBOIS } 56*5ec694b5SJean-Christophe DUBOIS } 57*5ec694b5SJean-Christophe DUBOIS 58a50c0d6fSJean-Christophe DUBOIS # define DPRINTF(fmt, args...) \ 59*5ec694b5SJean-Christophe DUBOIS do { printf("%s: " fmt , __func__, ##args); } while (0) 60a50c0d6fSJean-Christophe DUBOIS #else 61a50c0d6fSJean-Christophe DUBOIS # define DPRINTF(fmt, args...) do {} while (0) 62a50c0d6fSJean-Christophe DUBOIS #endif 63a50c0d6fSJean-Christophe DUBOIS 64a50c0d6fSJean-Christophe DUBOIS /* 65a50c0d6fSJean-Christophe DUBOIS * Define to 1 for messages about attempts to 66a50c0d6fSJean-Christophe DUBOIS * access unimplemented registers or similar. 67a50c0d6fSJean-Christophe DUBOIS */ 68a50c0d6fSJean-Christophe DUBOIS #define DEBUG_IMPLEMENTATION 1 69a50c0d6fSJean-Christophe DUBOIS #if DEBUG_IMPLEMENTATION 70a50c0d6fSJean-Christophe DUBOIS # define IPRINTF(fmt, args...) \ 71*5ec694b5SJean-Christophe DUBOIS do { fprintf(stderr, "%s: " fmt, __func__, ##args); } while (0) 72a50c0d6fSJean-Christophe DUBOIS #else 73a50c0d6fSJean-Christophe DUBOIS # define IPRINTF(fmt, args...) do {} while (0) 74a50c0d6fSJean-Christophe DUBOIS #endif 75a50c0d6fSJean-Christophe DUBOIS 76a50c0d6fSJean-Christophe DUBOIS /* 77a50c0d6fSJean-Christophe DUBOIS * GPT : General purpose timer 78a50c0d6fSJean-Christophe DUBOIS * 79a50c0d6fSJean-Christophe DUBOIS * This timer counts up continuously while it is enabled, resetting itself 80a50c0d6fSJean-Christophe DUBOIS * to 0 when it reaches TIMER_MAX (in freerun mode) or when it 81*5ec694b5SJean-Christophe DUBOIS * reaches the value of one of the ocrX (in periodic mode). 82a50c0d6fSJean-Christophe DUBOIS */ 83a50c0d6fSJean-Christophe DUBOIS 84a50c0d6fSJean-Christophe DUBOIS #define TIMER_MAX 0XFFFFFFFFUL 85a50c0d6fSJean-Christophe DUBOIS 86a50c0d6fSJean-Christophe DUBOIS /* Control register. Not all of these bits have any effect (yet) */ 87a50c0d6fSJean-Christophe DUBOIS #define GPT_CR_EN (1 << 0) /* GPT Enable */ 88a50c0d6fSJean-Christophe DUBOIS #define GPT_CR_ENMOD (1 << 1) /* GPT Enable Mode */ 89a50c0d6fSJean-Christophe DUBOIS #define GPT_CR_DBGEN (1 << 2) /* GPT Debug mode enable */ 90a50c0d6fSJean-Christophe DUBOIS #define GPT_CR_WAITEN (1 << 3) /* GPT Wait Mode Enable */ 91a50c0d6fSJean-Christophe DUBOIS #define GPT_CR_DOZEN (1 << 4) /* GPT Doze mode enable */ 92a50c0d6fSJean-Christophe DUBOIS #define GPT_CR_STOPEN (1 << 5) /* GPT Stop Mode Enable */ 93a50c0d6fSJean-Christophe DUBOIS #define GPT_CR_CLKSRC_SHIFT (6) 94a50c0d6fSJean-Christophe DUBOIS #define GPT_CR_CLKSRC_MASK (0x7) 95a50c0d6fSJean-Christophe DUBOIS 96a50c0d6fSJean-Christophe DUBOIS #define GPT_CR_FRR (1 << 9) /* Freerun or Restart */ 97a50c0d6fSJean-Christophe DUBOIS #define GPT_CR_SWR (1 << 15) /* Software Reset */ 98a50c0d6fSJean-Christophe DUBOIS #define GPT_CR_IM1 (3 << 16) /* Input capture channel 1 mode (2 bits) */ 99a50c0d6fSJean-Christophe DUBOIS #define GPT_CR_IM2 (3 << 18) /* Input capture channel 2 mode (2 bits) */ 100a50c0d6fSJean-Christophe DUBOIS #define GPT_CR_OM1 (7 << 20) /* Output Compare Channel 1 Mode (3 bits) */ 101a50c0d6fSJean-Christophe DUBOIS #define GPT_CR_OM2 (7 << 23) /* Output Compare Channel 2 Mode (3 bits) */ 102a50c0d6fSJean-Christophe DUBOIS #define GPT_CR_OM3 (7 << 26) /* Output Compare Channel 3 Mode (3 bits) */ 103a50c0d6fSJean-Christophe DUBOIS #define GPT_CR_FO1 (1 << 29) /* Force Output Compare Channel 1 */ 104a50c0d6fSJean-Christophe DUBOIS #define GPT_CR_FO2 (1 << 30) /* Force Output Compare Channel 2 */ 105a50c0d6fSJean-Christophe DUBOIS #define GPT_CR_FO3 (1 << 31) /* Force Output Compare Channel 3 */ 106a50c0d6fSJean-Christophe DUBOIS 107a50c0d6fSJean-Christophe DUBOIS #define GPT_SR_OF1 (1 << 0) 108*5ec694b5SJean-Christophe DUBOIS #define GPT_SR_OF2 (1 << 1) 109*5ec694b5SJean-Christophe DUBOIS #define GPT_SR_OF3 (1 << 2) 110a50c0d6fSJean-Christophe DUBOIS #define GPT_SR_ROV (1 << 5) 111a50c0d6fSJean-Christophe DUBOIS 112a50c0d6fSJean-Christophe DUBOIS #define GPT_IR_OF1IE (1 << 0) 113*5ec694b5SJean-Christophe DUBOIS #define GPT_IR_OF2IE (1 << 1) 114*5ec694b5SJean-Christophe DUBOIS #define GPT_IR_OF3IE (1 << 2) 115a50c0d6fSJean-Christophe DUBOIS #define GPT_IR_ROVIE (1 << 5) 116a50c0d6fSJean-Christophe DUBOIS 117a50c0d6fSJean-Christophe DUBOIS typedef struct { 118a50c0d6fSJean-Christophe DUBOIS SysBusDevice busdev; 119a50c0d6fSJean-Christophe DUBOIS ptimer_state *timer; 120a50c0d6fSJean-Christophe DUBOIS MemoryRegion iomem; 121a50c0d6fSJean-Christophe DUBOIS DeviceState *ccm; 122a50c0d6fSJean-Christophe DUBOIS 123a50c0d6fSJean-Christophe DUBOIS uint32_t cr; 124a50c0d6fSJean-Christophe DUBOIS uint32_t pr; 125a50c0d6fSJean-Christophe DUBOIS uint32_t sr; 126a50c0d6fSJean-Christophe DUBOIS uint32_t ir; 127a50c0d6fSJean-Christophe DUBOIS uint32_t ocr1; 128a50c0d6fSJean-Christophe DUBOIS uint32_t ocr2; 129a50c0d6fSJean-Christophe DUBOIS uint32_t ocr3; 130a50c0d6fSJean-Christophe DUBOIS uint32_t icr1; 131a50c0d6fSJean-Christophe DUBOIS uint32_t icr2; 132a50c0d6fSJean-Christophe DUBOIS uint32_t cnt; 133a50c0d6fSJean-Christophe DUBOIS 134*5ec694b5SJean-Christophe DUBOIS uint32_t next_timeout; 135*5ec694b5SJean-Christophe DUBOIS uint32_t next_int; 136*5ec694b5SJean-Christophe DUBOIS 137*5ec694b5SJean-Christophe DUBOIS uint32_t freq; 138*5ec694b5SJean-Christophe DUBOIS 139a50c0d6fSJean-Christophe DUBOIS qemu_irq irq; 140a50c0d6fSJean-Christophe DUBOIS } IMXTimerGState; 141a50c0d6fSJean-Christophe DUBOIS 142a50c0d6fSJean-Christophe DUBOIS static const VMStateDescription vmstate_imx_timerg = { 143*5ec694b5SJean-Christophe DUBOIS .name = TYPE_IMX_GPT, 144*5ec694b5SJean-Christophe DUBOIS .version_id = 3, 145*5ec694b5SJean-Christophe DUBOIS .minimum_version_id = 3, 146*5ec694b5SJean-Christophe DUBOIS .minimum_version_id_old = 3, 147a50c0d6fSJean-Christophe DUBOIS .fields = (VMStateField[]) { 148a50c0d6fSJean-Christophe DUBOIS VMSTATE_UINT32(cr, IMXTimerGState), 149a50c0d6fSJean-Christophe DUBOIS VMSTATE_UINT32(pr, IMXTimerGState), 150a50c0d6fSJean-Christophe DUBOIS VMSTATE_UINT32(sr, IMXTimerGState), 151a50c0d6fSJean-Christophe DUBOIS VMSTATE_UINT32(ir, IMXTimerGState), 152a50c0d6fSJean-Christophe DUBOIS VMSTATE_UINT32(ocr1, IMXTimerGState), 153a50c0d6fSJean-Christophe DUBOIS VMSTATE_UINT32(ocr2, IMXTimerGState), 154a50c0d6fSJean-Christophe DUBOIS VMSTATE_UINT32(ocr3, IMXTimerGState), 155a50c0d6fSJean-Christophe DUBOIS VMSTATE_UINT32(icr1, IMXTimerGState), 156a50c0d6fSJean-Christophe DUBOIS VMSTATE_UINT32(icr2, IMXTimerGState), 157a50c0d6fSJean-Christophe DUBOIS VMSTATE_UINT32(cnt, IMXTimerGState), 158*5ec694b5SJean-Christophe DUBOIS VMSTATE_UINT32(next_timeout, IMXTimerGState), 159*5ec694b5SJean-Christophe DUBOIS VMSTATE_UINT32(next_int, IMXTimerGState), 160*5ec694b5SJean-Christophe DUBOIS VMSTATE_UINT32(freq, IMXTimerGState), 161a50c0d6fSJean-Christophe DUBOIS VMSTATE_PTIMER(timer, IMXTimerGState), 162a50c0d6fSJean-Christophe DUBOIS VMSTATE_END_OF_LIST() 163a50c0d6fSJean-Christophe DUBOIS } 164a50c0d6fSJean-Christophe DUBOIS }; 165a50c0d6fSJean-Christophe DUBOIS 166a50c0d6fSJean-Christophe DUBOIS static const IMXClk imx_timerg_clocks[] = { 167a50c0d6fSJean-Christophe DUBOIS NOCLK, /* 000 No clock source */ 168a50c0d6fSJean-Christophe DUBOIS IPG, /* 001 ipg_clk, 532MHz*/ 169a50c0d6fSJean-Christophe DUBOIS IPG, /* 010 ipg_clk_highfreq */ 170a50c0d6fSJean-Christophe DUBOIS NOCLK, /* 011 not defined */ 171a50c0d6fSJean-Christophe DUBOIS CLK_32k, /* 100 ipg_clk_32k */ 172a50c0d6fSJean-Christophe DUBOIS NOCLK, /* 101 not defined */ 173a50c0d6fSJean-Christophe DUBOIS NOCLK, /* 110 not defined */ 174a50c0d6fSJean-Christophe DUBOIS NOCLK, /* 111 not defined */ 175a50c0d6fSJean-Christophe DUBOIS }; 176a50c0d6fSJean-Christophe DUBOIS 177a50c0d6fSJean-Christophe DUBOIS static void imx_timerg_set_freq(IMXTimerGState *s) 178a50c0d6fSJean-Christophe DUBOIS { 179*5ec694b5SJean-Christophe DUBOIS uint32_t clksrc = extract32(s->cr, GPT_CR_CLKSRC_SHIFT, 3); 180*5ec694b5SJean-Christophe DUBOIS uint32_t freq = imx_clock_frequency(s->ccm, imx_timerg_clocks[clksrc]) 181*5ec694b5SJean-Christophe DUBOIS / (1 + s->pr); 182*5ec694b5SJean-Christophe DUBOIS s->freq = freq; 183a50c0d6fSJean-Christophe DUBOIS 184*5ec694b5SJean-Christophe DUBOIS DPRINTF("Setting clksrc %d to frequency %d\n", clksrc, freq); 185a50c0d6fSJean-Christophe DUBOIS 186a50c0d6fSJean-Christophe DUBOIS if (freq) { 187a50c0d6fSJean-Christophe DUBOIS ptimer_set_freq(s->timer, freq); 188a50c0d6fSJean-Christophe DUBOIS } 189a50c0d6fSJean-Christophe DUBOIS } 190a50c0d6fSJean-Christophe DUBOIS 191a50c0d6fSJean-Christophe DUBOIS static void imx_timerg_update(IMXTimerGState *s) 192a50c0d6fSJean-Christophe DUBOIS { 193*5ec694b5SJean-Christophe DUBOIS if ((s->sr & s->ir) && (s->cr & GPT_CR_EN)) { 194*5ec694b5SJean-Christophe DUBOIS qemu_irq_raise(s->irq); 195*5ec694b5SJean-Christophe DUBOIS } else { 196*5ec694b5SJean-Christophe DUBOIS qemu_irq_lower(s->irq); 197*5ec694b5SJean-Christophe DUBOIS } 198a50c0d6fSJean-Christophe DUBOIS } 199a50c0d6fSJean-Christophe DUBOIS 200a50c0d6fSJean-Christophe DUBOIS static uint32_t imx_timerg_update_counts(IMXTimerGState *s) 201a50c0d6fSJean-Christophe DUBOIS { 202*5ec694b5SJean-Christophe DUBOIS s->cnt = s->next_timeout - (uint32_t)ptimer_get_count(s->timer); 203*5ec694b5SJean-Christophe DUBOIS 204a50c0d6fSJean-Christophe DUBOIS return s->cnt; 205a50c0d6fSJean-Christophe DUBOIS } 206a50c0d6fSJean-Christophe DUBOIS 207*5ec694b5SJean-Christophe DUBOIS static inline uint32_t imx_timerg_find_limit(uint32_t count, uint32_t reg, 208*5ec694b5SJean-Christophe DUBOIS uint32_t timeout) 209a50c0d6fSJean-Christophe DUBOIS { 210*5ec694b5SJean-Christophe DUBOIS if ((count < reg) && (timeout > reg)) { 211*5ec694b5SJean-Christophe DUBOIS timeout = reg; 212*5ec694b5SJean-Christophe DUBOIS } 213a50c0d6fSJean-Christophe DUBOIS 214*5ec694b5SJean-Christophe DUBOIS return timeout; 215*5ec694b5SJean-Christophe DUBOIS } 216*5ec694b5SJean-Christophe DUBOIS 217*5ec694b5SJean-Christophe DUBOIS static void imx_timerg_compute_next_timeout(IMXTimerGState *s, bool event) 218*5ec694b5SJean-Christophe DUBOIS { 219*5ec694b5SJean-Christophe DUBOIS uint32_t timeout = TIMER_MAX; 220*5ec694b5SJean-Christophe DUBOIS uint32_t count = 0; 221*5ec694b5SJean-Christophe DUBOIS long long limit; 222*5ec694b5SJean-Christophe DUBOIS 223*5ec694b5SJean-Christophe DUBOIS if (!(s->cr & GPT_CR_EN)) { 224*5ec694b5SJean-Christophe DUBOIS /* if not enabled just return */ 225a50c0d6fSJean-Christophe DUBOIS return; 226a50c0d6fSJean-Christophe DUBOIS } 227a50c0d6fSJean-Christophe DUBOIS 228*5ec694b5SJean-Christophe DUBOIS if (event) { 229*5ec694b5SJean-Christophe DUBOIS /* This is a timer event */ 230*5ec694b5SJean-Christophe DUBOIS 231*5ec694b5SJean-Christophe DUBOIS if ((s->cr & GPT_CR_FRR) && (s->next_timeout != TIMER_MAX)) { 232a50c0d6fSJean-Christophe DUBOIS /* 233*5ec694b5SJean-Christophe DUBOIS * if we are in free running mode and we have not reached 234*5ec694b5SJean-Christophe DUBOIS * the TIMER_MAX limit, then update the count 235a50c0d6fSJean-Christophe DUBOIS */ 236*5ec694b5SJean-Christophe DUBOIS count = imx_timerg_update_counts(s); 237a50c0d6fSJean-Christophe DUBOIS } 238*5ec694b5SJean-Christophe DUBOIS } else { 239*5ec694b5SJean-Christophe DUBOIS /* not a timer event, then just update the count */ 240*5ec694b5SJean-Christophe DUBOIS 241*5ec694b5SJean-Christophe DUBOIS count = imx_timerg_update_counts(s); 242*5ec694b5SJean-Christophe DUBOIS } 243*5ec694b5SJean-Christophe DUBOIS 244*5ec694b5SJean-Christophe DUBOIS /* now, find the next timeout related to count */ 245*5ec694b5SJean-Christophe DUBOIS 246*5ec694b5SJean-Christophe DUBOIS if (s->ir & GPT_IR_OF1IE) { 247*5ec694b5SJean-Christophe DUBOIS timeout = imx_timerg_find_limit(count, s->ocr1, timeout); 248*5ec694b5SJean-Christophe DUBOIS } 249*5ec694b5SJean-Christophe DUBOIS if (s->ir & GPT_IR_OF2IE) { 250*5ec694b5SJean-Christophe DUBOIS timeout = imx_timerg_find_limit(count, s->ocr2, timeout); 251*5ec694b5SJean-Christophe DUBOIS } 252*5ec694b5SJean-Christophe DUBOIS if (s->ir & GPT_IR_OF3IE) { 253*5ec694b5SJean-Christophe DUBOIS timeout = imx_timerg_find_limit(count, s->ocr3, timeout); 254*5ec694b5SJean-Christophe DUBOIS } 255*5ec694b5SJean-Christophe DUBOIS 256*5ec694b5SJean-Christophe DUBOIS /* find the next set of interrupts to raise for next timer event */ 257*5ec694b5SJean-Christophe DUBOIS 258*5ec694b5SJean-Christophe DUBOIS s->next_int = 0; 259*5ec694b5SJean-Christophe DUBOIS if ((s->ir & GPT_IR_OF1IE) && (timeout == s->ocr1)) { 260*5ec694b5SJean-Christophe DUBOIS s->next_int |= GPT_SR_OF1; 261*5ec694b5SJean-Christophe DUBOIS } 262*5ec694b5SJean-Christophe DUBOIS if ((s->ir & GPT_IR_OF2IE) && (timeout == s->ocr2)) { 263*5ec694b5SJean-Christophe DUBOIS s->next_int |= GPT_SR_OF2; 264*5ec694b5SJean-Christophe DUBOIS } 265*5ec694b5SJean-Christophe DUBOIS if ((s->ir & GPT_IR_OF3IE) && (timeout == s->ocr3)) { 266*5ec694b5SJean-Christophe DUBOIS s->next_int |= GPT_SR_OF3; 267*5ec694b5SJean-Christophe DUBOIS } 268*5ec694b5SJean-Christophe DUBOIS if ((s->ir & GPT_IR_ROVIE) && (timeout == TIMER_MAX)) { 269*5ec694b5SJean-Christophe DUBOIS s->next_int |= GPT_SR_ROV; 270*5ec694b5SJean-Christophe DUBOIS } 271*5ec694b5SJean-Christophe DUBOIS 272*5ec694b5SJean-Christophe DUBOIS /* the new range to count down from */ 273*5ec694b5SJean-Christophe DUBOIS limit = timeout - imx_timerg_update_counts(s); 274*5ec694b5SJean-Christophe DUBOIS 275*5ec694b5SJean-Christophe DUBOIS if (limit < 0) { 276*5ec694b5SJean-Christophe DUBOIS /* 277*5ec694b5SJean-Christophe DUBOIS * if we reach here, then QEMU is running too slow and we pass the 278*5ec694b5SJean-Christophe DUBOIS * timeout limit while computing it. Let's deliver the interrupt 279*5ec694b5SJean-Christophe DUBOIS * and compute a new limit. 280*5ec694b5SJean-Christophe DUBOIS */ 281*5ec694b5SJean-Christophe DUBOIS s->sr |= s->next_int; 282*5ec694b5SJean-Christophe DUBOIS 283*5ec694b5SJean-Christophe DUBOIS imx_timerg_compute_next_timeout(s, event); 284*5ec694b5SJean-Christophe DUBOIS 285*5ec694b5SJean-Christophe DUBOIS imx_timerg_update(s); 286*5ec694b5SJean-Christophe DUBOIS } else { 287*5ec694b5SJean-Christophe DUBOIS /* New timeout value */ 288*5ec694b5SJean-Christophe DUBOIS s->next_timeout = timeout; 289*5ec694b5SJean-Christophe DUBOIS 290*5ec694b5SJean-Christophe DUBOIS /* reset the limit to the computed range */ 291*5ec694b5SJean-Christophe DUBOIS ptimer_set_limit(s->timer, limit, 1); 292*5ec694b5SJean-Christophe DUBOIS } 293a50c0d6fSJean-Christophe DUBOIS } 294a50c0d6fSJean-Christophe DUBOIS 295a50c0d6fSJean-Christophe DUBOIS static uint64_t imx_timerg_read(void *opaque, hwaddr offset, 296a50c0d6fSJean-Christophe DUBOIS unsigned size) 297a50c0d6fSJean-Christophe DUBOIS { 298a50c0d6fSJean-Christophe DUBOIS IMXTimerGState *s = (IMXTimerGState *)opaque; 299*5ec694b5SJean-Christophe DUBOIS uint32_t reg_value = 0; 300*5ec694b5SJean-Christophe DUBOIS uint32_t reg = offset >> 2; 301a50c0d6fSJean-Christophe DUBOIS 302*5ec694b5SJean-Christophe DUBOIS switch (reg) { 303a50c0d6fSJean-Christophe DUBOIS case 0: /* Control Register */ 304*5ec694b5SJean-Christophe DUBOIS reg_value = s->cr; 305*5ec694b5SJean-Christophe DUBOIS break; 306a50c0d6fSJean-Christophe DUBOIS 307a50c0d6fSJean-Christophe DUBOIS case 1: /* prescaler */ 308*5ec694b5SJean-Christophe DUBOIS reg_value = s->pr; 309*5ec694b5SJean-Christophe DUBOIS break; 310a50c0d6fSJean-Christophe DUBOIS 311a50c0d6fSJean-Christophe DUBOIS case 2: /* Status Register */ 312*5ec694b5SJean-Christophe DUBOIS reg_value = s->sr; 313*5ec694b5SJean-Christophe DUBOIS break; 314a50c0d6fSJean-Christophe DUBOIS 315a50c0d6fSJean-Christophe DUBOIS case 3: /* Interrupt Register */ 316*5ec694b5SJean-Christophe DUBOIS reg_value = s->ir; 317*5ec694b5SJean-Christophe DUBOIS break; 318a50c0d6fSJean-Christophe DUBOIS 319a50c0d6fSJean-Christophe DUBOIS case 4: /* Output Compare Register 1 */ 320*5ec694b5SJean-Christophe DUBOIS reg_value = s->ocr1; 321*5ec694b5SJean-Christophe DUBOIS break; 322a50c0d6fSJean-Christophe DUBOIS 323a50c0d6fSJean-Christophe DUBOIS case 5: /* Output Compare Register 2 */ 324*5ec694b5SJean-Christophe DUBOIS reg_value = s->ocr2; 325*5ec694b5SJean-Christophe DUBOIS break; 326a50c0d6fSJean-Christophe DUBOIS 327a50c0d6fSJean-Christophe DUBOIS case 6: /* Output Compare Register 3 */ 328*5ec694b5SJean-Christophe DUBOIS reg_value = s->ocr3; 329*5ec694b5SJean-Christophe DUBOIS break; 330a50c0d6fSJean-Christophe DUBOIS 331a50c0d6fSJean-Christophe DUBOIS case 7: /* input Capture Register 1 */ 332*5ec694b5SJean-Christophe DUBOIS qemu_log_mask(LOG_UNIMP, "icr1 feature is not implemented\n"); 333*5ec694b5SJean-Christophe DUBOIS reg_value = s->icr1; 334*5ec694b5SJean-Christophe DUBOIS break; 335a50c0d6fSJean-Christophe DUBOIS 336a50c0d6fSJean-Christophe DUBOIS case 8: /* input Capture Register 2 */ 337*5ec694b5SJean-Christophe DUBOIS qemu_log_mask(LOG_UNIMP, "icr2 feature is not implemented\n"); 338*5ec694b5SJean-Christophe DUBOIS reg_value = s->icr2; 339*5ec694b5SJean-Christophe DUBOIS break; 340a50c0d6fSJean-Christophe DUBOIS 341a50c0d6fSJean-Christophe DUBOIS case 9: /* cnt */ 342a50c0d6fSJean-Christophe DUBOIS imx_timerg_update_counts(s); 343*5ec694b5SJean-Christophe DUBOIS reg_value = s->cnt; 344*5ec694b5SJean-Christophe DUBOIS break; 345*5ec694b5SJean-Christophe DUBOIS 346*5ec694b5SJean-Christophe DUBOIS default: 347*5ec694b5SJean-Christophe DUBOIS IPRINTF("Bad offset %x\n", reg); 348*5ec694b5SJean-Christophe DUBOIS break; 349a50c0d6fSJean-Christophe DUBOIS } 350a50c0d6fSJean-Christophe DUBOIS 351*5ec694b5SJean-Christophe DUBOIS DPRINTF("(%s) = 0x%08x\n", imx_timerg_reg_name(reg), reg_value); 352a50c0d6fSJean-Christophe DUBOIS 353*5ec694b5SJean-Christophe DUBOIS return reg_value; 354a50c0d6fSJean-Christophe DUBOIS } 355a50c0d6fSJean-Christophe DUBOIS 356a50c0d6fSJean-Christophe DUBOIS static void imx_timerg_reset(DeviceState *dev) 357a50c0d6fSJean-Christophe DUBOIS { 358a50c0d6fSJean-Christophe DUBOIS IMXTimerGState *s = container_of(dev, IMXTimerGState, busdev.qdev); 359a50c0d6fSJean-Christophe DUBOIS 360*5ec694b5SJean-Christophe DUBOIS /* stop timer */ 361*5ec694b5SJean-Christophe DUBOIS ptimer_stop(s->timer); 362*5ec694b5SJean-Christophe DUBOIS 363a50c0d6fSJean-Christophe DUBOIS /* 364a50c0d6fSJean-Christophe DUBOIS * Soft reset doesn't touch some bits; hard reset clears them 365a50c0d6fSJean-Christophe DUBOIS */ 366a50c0d6fSJean-Christophe DUBOIS s->cr &= ~(GPT_CR_EN|GPT_CR_ENMOD|GPT_CR_STOPEN|GPT_CR_DOZEN| 367a50c0d6fSJean-Christophe DUBOIS GPT_CR_WAITEN|GPT_CR_DBGEN); 368a50c0d6fSJean-Christophe DUBOIS s->sr = 0; 369a50c0d6fSJean-Christophe DUBOIS s->pr = 0; 370a50c0d6fSJean-Christophe DUBOIS s->ir = 0; 371a50c0d6fSJean-Christophe DUBOIS s->cnt = 0; 372a50c0d6fSJean-Christophe DUBOIS s->ocr1 = TIMER_MAX; 373a50c0d6fSJean-Christophe DUBOIS s->ocr2 = TIMER_MAX; 374a50c0d6fSJean-Christophe DUBOIS s->ocr3 = TIMER_MAX; 375a50c0d6fSJean-Christophe DUBOIS s->icr1 = 0; 376a50c0d6fSJean-Christophe DUBOIS s->icr2 = 0; 377*5ec694b5SJean-Christophe DUBOIS 378*5ec694b5SJean-Christophe DUBOIS s->next_timeout = TIMER_MAX; 379*5ec694b5SJean-Christophe DUBOIS s->next_int = 0; 380*5ec694b5SJean-Christophe DUBOIS 381*5ec694b5SJean-Christophe DUBOIS /* compute new freq */ 382a50c0d6fSJean-Christophe DUBOIS imx_timerg_set_freq(s); 383*5ec694b5SJean-Christophe DUBOIS 384*5ec694b5SJean-Christophe DUBOIS /* reset the limit to TIMER_MAX */ 385*5ec694b5SJean-Christophe DUBOIS ptimer_set_limit(s->timer, TIMER_MAX, 1); 386*5ec694b5SJean-Christophe DUBOIS 387*5ec694b5SJean-Christophe DUBOIS /* if the timer is still enabled, restart it */ 388*5ec694b5SJean-Christophe DUBOIS if (s->freq && (s->cr & GPT_CR_EN)) { 389*5ec694b5SJean-Christophe DUBOIS ptimer_run(s->timer, 1); 390*5ec694b5SJean-Christophe DUBOIS } 391a50c0d6fSJean-Christophe DUBOIS } 392a50c0d6fSJean-Christophe DUBOIS 393a50c0d6fSJean-Christophe DUBOIS static void imx_timerg_write(void *opaque, hwaddr offset, 394a50c0d6fSJean-Christophe DUBOIS uint64_t value, unsigned size) 395a50c0d6fSJean-Christophe DUBOIS { 396a50c0d6fSJean-Christophe DUBOIS IMXTimerGState *s = (IMXTimerGState *)opaque; 397*5ec694b5SJean-Christophe DUBOIS uint32_t oldreg; 398*5ec694b5SJean-Christophe DUBOIS uint32_t reg = offset >> 2; 399a50c0d6fSJean-Christophe DUBOIS 400*5ec694b5SJean-Christophe DUBOIS DPRINTF("(%s, value = 0x%08x)\n", imx_timerg_reg_name(reg), 401*5ec694b5SJean-Christophe DUBOIS (uint32_t)value); 402a50c0d6fSJean-Christophe DUBOIS 403*5ec694b5SJean-Christophe DUBOIS switch (reg) { 404*5ec694b5SJean-Christophe DUBOIS case 0: 405*5ec694b5SJean-Christophe DUBOIS oldreg = s->cr; 406*5ec694b5SJean-Christophe DUBOIS s->cr = value & ~0x7c14; 407*5ec694b5SJean-Christophe DUBOIS if (s->cr & GPT_CR_SWR) { /* force reset */ 408*5ec694b5SJean-Christophe DUBOIS /* handle the reset */ 409*5ec694b5SJean-Christophe DUBOIS imx_timerg_reset(DEVICE(s)); 410a50c0d6fSJean-Christophe DUBOIS } else { 411*5ec694b5SJean-Christophe DUBOIS /* set our freq, as the source might have changed */ 412*5ec694b5SJean-Christophe DUBOIS imx_timerg_set_freq(s); 413*5ec694b5SJean-Christophe DUBOIS 414*5ec694b5SJean-Christophe DUBOIS if ((oldreg ^ s->cr) & GPT_CR_EN) { 415*5ec694b5SJean-Christophe DUBOIS if (s->cr & GPT_CR_EN) { 416*5ec694b5SJean-Christophe DUBOIS if (s->cr & GPT_CR_ENMOD) { 417*5ec694b5SJean-Christophe DUBOIS s->next_timeout = TIMER_MAX; 418*5ec694b5SJean-Christophe DUBOIS ptimer_set_count(s->timer, TIMER_MAX); 419*5ec694b5SJean-Christophe DUBOIS imx_timerg_compute_next_timeout(s, false); 420*5ec694b5SJean-Christophe DUBOIS } 421*5ec694b5SJean-Christophe DUBOIS ptimer_run(s->timer, 1); 422*5ec694b5SJean-Christophe DUBOIS } else { 423*5ec694b5SJean-Christophe DUBOIS /* stop timer */ 424a50c0d6fSJean-Christophe DUBOIS ptimer_stop(s->timer); 425a50c0d6fSJean-Christophe DUBOIS } 426a50c0d6fSJean-Christophe DUBOIS } 427*5ec694b5SJean-Christophe DUBOIS } 428*5ec694b5SJean-Christophe DUBOIS break; 429a50c0d6fSJean-Christophe DUBOIS 430a50c0d6fSJean-Christophe DUBOIS case 1: /* Prescaler */ 431a50c0d6fSJean-Christophe DUBOIS s->pr = value & 0xfff; 432a50c0d6fSJean-Christophe DUBOIS imx_timerg_set_freq(s); 433*5ec694b5SJean-Christophe DUBOIS break; 434a50c0d6fSJean-Christophe DUBOIS 435a50c0d6fSJean-Christophe DUBOIS case 2: /* SR */ 436*5ec694b5SJean-Christophe DUBOIS s->sr &= ~(value & 0x3f); 437a50c0d6fSJean-Christophe DUBOIS imx_timerg_update(s); 438*5ec694b5SJean-Christophe DUBOIS break; 439a50c0d6fSJean-Christophe DUBOIS 440a50c0d6fSJean-Christophe DUBOIS case 3: /* IR -- interrupt register */ 441a50c0d6fSJean-Christophe DUBOIS s->ir = value & 0x3f; 442a50c0d6fSJean-Christophe DUBOIS imx_timerg_update(s); 443*5ec694b5SJean-Christophe DUBOIS 444*5ec694b5SJean-Christophe DUBOIS imx_timerg_compute_next_timeout(s, false); 445*5ec694b5SJean-Christophe DUBOIS 446*5ec694b5SJean-Christophe DUBOIS break; 447a50c0d6fSJean-Christophe DUBOIS 448a50c0d6fSJean-Christophe DUBOIS case 4: /* OCR1 -- output compare register */ 449*5ec694b5SJean-Christophe DUBOIS s->ocr1 = value; 450*5ec694b5SJean-Christophe DUBOIS 451a50c0d6fSJean-Christophe DUBOIS /* In non-freerun mode, reset count when this register is written */ 452a50c0d6fSJean-Christophe DUBOIS if (!(s->cr & GPT_CR_FRR)) { 453*5ec694b5SJean-Christophe DUBOIS s->next_timeout = TIMER_MAX; 454*5ec694b5SJean-Christophe DUBOIS ptimer_set_limit(s->timer, TIMER_MAX, 1); 455a50c0d6fSJean-Christophe DUBOIS } 456*5ec694b5SJean-Christophe DUBOIS 457*5ec694b5SJean-Christophe DUBOIS /* compute the new timeout */ 458*5ec694b5SJean-Christophe DUBOIS imx_timerg_compute_next_timeout(s, false); 459*5ec694b5SJean-Christophe DUBOIS 460*5ec694b5SJean-Christophe DUBOIS break; 461a50c0d6fSJean-Christophe DUBOIS 462a50c0d6fSJean-Christophe DUBOIS case 5: /* OCR2 -- output compare register */ 463*5ec694b5SJean-Christophe DUBOIS s->ocr2 = value; 464*5ec694b5SJean-Christophe DUBOIS 465*5ec694b5SJean-Christophe DUBOIS /* compute the new timeout */ 466*5ec694b5SJean-Christophe DUBOIS imx_timerg_compute_next_timeout(s, false); 467*5ec694b5SJean-Christophe DUBOIS 468*5ec694b5SJean-Christophe DUBOIS break; 469*5ec694b5SJean-Christophe DUBOIS 470a50c0d6fSJean-Christophe DUBOIS case 6: /* OCR3 -- output compare register */ 471*5ec694b5SJean-Christophe DUBOIS s->ocr3 = value; 472*5ec694b5SJean-Christophe DUBOIS 473*5ec694b5SJean-Christophe DUBOIS /* compute the new timeout */ 474*5ec694b5SJean-Christophe DUBOIS imx_timerg_compute_next_timeout(s, false); 475*5ec694b5SJean-Christophe DUBOIS 476*5ec694b5SJean-Christophe DUBOIS break; 477*5ec694b5SJean-Christophe DUBOIS 478a50c0d6fSJean-Christophe DUBOIS default: 479*5ec694b5SJean-Christophe DUBOIS IPRINTF("Bad offset %x\n", reg); 480*5ec694b5SJean-Christophe DUBOIS break; 481a50c0d6fSJean-Christophe DUBOIS } 482a50c0d6fSJean-Christophe DUBOIS } 483a50c0d6fSJean-Christophe DUBOIS 484a50c0d6fSJean-Christophe DUBOIS static void imx_timerg_timeout(void *opaque) 485a50c0d6fSJean-Christophe DUBOIS { 486a50c0d6fSJean-Christophe DUBOIS IMXTimerGState *s = (IMXTimerGState *)opaque; 487a50c0d6fSJean-Christophe DUBOIS 488*5ec694b5SJean-Christophe DUBOIS DPRINTF("\n"); 489a50c0d6fSJean-Christophe DUBOIS 490*5ec694b5SJean-Christophe DUBOIS s->sr |= s->next_int; 491*5ec694b5SJean-Christophe DUBOIS s->next_int = 0; 492a50c0d6fSJean-Christophe DUBOIS 493*5ec694b5SJean-Christophe DUBOIS imx_timerg_compute_next_timeout(s, true); 494*5ec694b5SJean-Christophe DUBOIS 495a50c0d6fSJean-Christophe DUBOIS imx_timerg_update(s); 496*5ec694b5SJean-Christophe DUBOIS 497*5ec694b5SJean-Christophe DUBOIS if (s->freq && (s->cr & GPT_CR_EN)) { 498*5ec694b5SJean-Christophe DUBOIS ptimer_run(s->timer, 1); 499*5ec694b5SJean-Christophe DUBOIS } 500a50c0d6fSJean-Christophe DUBOIS } 501a50c0d6fSJean-Christophe DUBOIS 502a50c0d6fSJean-Christophe DUBOIS static const MemoryRegionOps imx_timerg_ops = { 503a50c0d6fSJean-Christophe DUBOIS .read = imx_timerg_read, 504a50c0d6fSJean-Christophe DUBOIS .write = imx_timerg_write, 505a50c0d6fSJean-Christophe DUBOIS .endianness = DEVICE_NATIVE_ENDIAN, 506a50c0d6fSJean-Christophe DUBOIS }; 507a50c0d6fSJean-Christophe DUBOIS 508a50c0d6fSJean-Christophe DUBOIS 509a50c0d6fSJean-Christophe DUBOIS static int imx_timerg_init(SysBusDevice *dev) 510a50c0d6fSJean-Christophe DUBOIS { 511a50c0d6fSJean-Christophe DUBOIS IMXTimerGState *s = FROM_SYSBUS(IMXTimerGState, dev); 512a50c0d6fSJean-Christophe DUBOIS QEMUBH *bh; 513a50c0d6fSJean-Christophe DUBOIS 514a50c0d6fSJean-Christophe DUBOIS sysbus_init_irq(dev, &s->irq); 515a50c0d6fSJean-Christophe DUBOIS memory_region_init_io(&s->iomem, &imx_timerg_ops, 516*5ec694b5SJean-Christophe DUBOIS s, TYPE_IMX_GPT, 517a50c0d6fSJean-Christophe DUBOIS 0x00001000); 518a50c0d6fSJean-Christophe DUBOIS sysbus_init_mmio(dev, &s->iomem); 519a50c0d6fSJean-Christophe DUBOIS 520a50c0d6fSJean-Christophe DUBOIS bh = qemu_bh_new(imx_timerg_timeout, s); 521a50c0d6fSJean-Christophe DUBOIS s->timer = ptimer_init(bh); 522a50c0d6fSJean-Christophe DUBOIS 523a50c0d6fSJean-Christophe DUBOIS /* Hard reset resets extra bits in CR */ 524a50c0d6fSJean-Christophe DUBOIS s->cr = 0; 525a50c0d6fSJean-Christophe DUBOIS return 0; 526a50c0d6fSJean-Christophe DUBOIS } 527a50c0d6fSJean-Christophe DUBOIS 528*5ec694b5SJean-Christophe DUBOIS void imx_timerg_create(const hwaddr addr, qemu_irq irq, DeviceState *ccm) 529a50c0d6fSJean-Christophe DUBOIS { 530a50c0d6fSJean-Christophe DUBOIS IMXTimerGState *pp; 531a50c0d6fSJean-Christophe DUBOIS DeviceState *dev; 532a50c0d6fSJean-Christophe DUBOIS 533*5ec694b5SJean-Christophe DUBOIS dev = sysbus_create_simple(TYPE_IMX_GPT, addr, irq); 534a50c0d6fSJean-Christophe DUBOIS pp = container_of(dev, IMXTimerGState, busdev.qdev); 535a50c0d6fSJean-Christophe DUBOIS pp->ccm = ccm; 536a50c0d6fSJean-Christophe DUBOIS } 537a50c0d6fSJean-Christophe DUBOIS 538a50c0d6fSJean-Christophe DUBOIS static void imx_timerg_class_init(ObjectClass *klass, void *data) 539a50c0d6fSJean-Christophe DUBOIS { 540a50c0d6fSJean-Christophe DUBOIS DeviceClass *dc = DEVICE_CLASS(klass); 541a50c0d6fSJean-Christophe DUBOIS SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); 542a50c0d6fSJean-Christophe DUBOIS k->init = imx_timerg_init; 543a50c0d6fSJean-Christophe DUBOIS dc->vmsd = &vmstate_imx_timerg; 544a50c0d6fSJean-Christophe DUBOIS dc->reset = imx_timerg_reset; 545a50c0d6fSJean-Christophe DUBOIS dc->desc = "i.MX general timer"; 546a50c0d6fSJean-Christophe DUBOIS } 547a50c0d6fSJean-Christophe DUBOIS 548a50c0d6fSJean-Christophe DUBOIS static const TypeInfo imx_timerg_info = { 549*5ec694b5SJean-Christophe DUBOIS .name = TYPE_IMX_GPT, 550a50c0d6fSJean-Christophe DUBOIS .parent = TYPE_SYS_BUS_DEVICE, 551a50c0d6fSJean-Christophe DUBOIS .instance_size = sizeof(IMXTimerGState), 552a50c0d6fSJean-Christophe DUBOIS .class_init = imx_timerg_class_init, 553a50c0d6fSJean-Christophe DUBOIS }; 554a50c0d6fSJean-Christophe DUBOIS 555a50c0d6fSJean-Christophe DUBOIS static void imx_timer_register_types(void) 556a50c0d6fSJean-Christophe DUBOIS { 557a50c0d6fSJean-Christophe DUBOIS type_register_static(&imx_timerg_info); 558a50c0d6fSJean-Christophe DUBOIS } 559a50c0d6fSJean-Christophe DUBOIS 560a50c0d6fSJean-Christophe DUBOIS type_init(imx_timer_register_types) 561