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 85ec694b5SJean-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 225ec694b5SJean-Christophe DUBOIS #define TYPE_IMX_GPT "imx.gpt" 235ec694b5SJean-Christophe DUBOIS 245ec694b5SJean-Christophe DUBOIS /* 255ec694b5SJean-Christophe DUBOIS * Define to 1 for debug messages 265ec694b5SJean-Christophe DUBOIS */ 275ec694b5SJean-Christophe DUBOIS #define DEBUG_TIMER 0 285ec694b5SJean-Christophe DUBOIS #if DEBUG_TIMER 295ec694b5SJean-Christophe DUBOIS 30*67110c3eSJean-Christophe DUBOIS static char const *imx_gpt_reg_name(uint32_t reg) 315ec694b5SJean-Christophe DUBOIS { 325ec694b5SJean-Christophe DUBOIS switch (reg) { 335ec694b5SJean-Christophe DUBOIS case 0: 345ec694b5SJean-Christophe DUBOIS return "CR"; 355ec694b5SJean-Christophe DUBOIS case 1: 365ec694b5SJean-Christophe DUBOIS return "PR"; 375ec694b5SJean-Christophe DUBOIS case 2: 385ec694b5SJean-Christophe DUBOIS return "SR"; 395ec694b5SJean-Christophe DUBOIS case 3: 405ec694b5SJean-Christophe DUBOIS return "IR"; 415ec694b5SJean-Christophe DUBOIS case 4: 425ec694b5SJean-Christophe DUBOIS return "OCR1"; 435ec694b5SJean-Christophe DUBOIS case 5: 445ec694b5SJean-Christophe DUBOIS return "OCR2"; 455ec694b5SJean-Christophe DUBOIS case 6: 465ec694b5SJean-Christophe DUBOIS return "OCR3"; 475ec694b5SJean-Christophe DUBOIS case 7: 485ec694b5SJean-Christophe DUBOIS return "ICR1"; 495ec694b5SJean-Christophe DUBOIS case 8: 505ec694b5SJean-Christophe DUBOIS return "ICR2"; 515ec694b5SJean-Christophe DUBOIS case 9: 525ec694b5SJean-Christophe DUBOIS return "CNT"; 535ec694b5SJean-Christophe DUBOIS default: 545ec694b5SJean-Christophe DUBOIS return "[?]"; 555ec694b5SJean-Christophe DUBOIS } 565ec694b5SJean-Christophe DUBOIS } 575ec694b5SJean-Christophe DUBOIS 58a50c0d6fSJean-Christophe DUBOIS # define DPRINTF(fmt, args...) \ 595ec694b5SJean-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...) \ 715ec694b5SJean-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 76*67110c3eSJean-Christophe DUBOIS #define IMX_GPT(obj) \ 77*67110c3eSJean-Christophe DUBOIS OBJECT_CHECK(IMXGPTState, (obj), TYPE_IMX_GPT) 78a50c0d6fSJean-Christophe DUBOIS /* 79a50c0d6fSJean-Christophe DUBOIS * GPT : General purpose timer 80a50c0d6fSJean-Christophe DUBOIS * 81a50c0d6fSJean-Christophe DUBOIS * This timer counts up continuously while it is enabled, resetting itself 82a50c0d6fSJean-Christophe DUBOIS * to 0 when it reaches TIMER_MAX (in freerun mode) or when it 835ec694b5SJean-Christophe DUBOIS * reaches the value of one of the ocrX (in periodic mode). 84a50c0d6fSJean-Christophe DUBOIS */ 85a50c0d6fSJean-Christophe DUBOIS 86a50c0d6fSJean-Christophe DUBOIS #define TIMER_MAX 0XFFFFFFFFUL 87a50c0d6fSJean-Christophe DUBOIS 88a50c0d6fSJean-Christophe DUBOIS /* Control register. Not all of these bits have any effect (yet) */ 89a50c0d6fSJean-Christophe DUBOIS #define GPT_CR_EN (1 << 0) /* GPT Enable */ 90a50c0d6fSJean-Christophe DUBOIS #define GPT_CR_ENMOD (1 << 1) /* GPT Enable Mode */ 91a50c0d6fSJean-Christophe DUBOIS #define GPT_CR_DBGEN (1 << 2) /* GPT Debug mode enable */ 92a50c0d6fSJean-Christophe DUBOIS #define GPT_CR_WAITEN (1 << 3) /* GPT Wait Mode Enable */ 93a50c0d6fSJean-Christophe DUBOIS #define GPT_CR_DOZEN (1 << 4) /* GPT Doze mode enable */ 94a50c0d6fSJean-Christophe DUBOIS #define GPT_CR_STOPEN (1 << 5) /* GPT Stop Mode Enable */ 95a50c0d6fSJean-Christophe DUBOIS #define GPT_CR_CLKSRC_SHIFT (6) 96a50c0d6fSJean-Christophe DUBOIS #define GPT_CR_CLKSRC_MASK (0x7) 97a50c0d6fSJean-Christophe DUBOIS 98a50c0d6fSJean-Christophe DUBOIS #define GPT_CR_FRR (1 << 9) /* Freerun or Restart */ 99a50c0d6fSJean-Christophe DUBOIS #define GPT_CR_SWR (1 << 15) /* Software Reset */ 100a50c0d6fSJean-Christophe DUBOIS #define GPT_CR_IM1 (3 << 16) /* Input capture channel 1 mode (2 bits) */ 101a50c0d6fSJean-Christophe DUBOIS #define GPT_CR_IM2 (3 << 18) /* Input capture channel 2 mode (2 bits) */ 102a50c0d6fSJean-Christophe DUBOIS #define GPT_CR_OM1 (7 << 20) /* Output Compare Channel 1 Mode (3 bits) */ 103a50c0d6fSJean-Christophe DUBOIS #define GPT_CR_OM2 (7 << 23) /* Output Compare Channel 2 Mode (3 bits) */ 104a50c0d6fSJean-Christophe DUBOIS #define GPT_CR_OM3 (7 << 26) /* Output Compare Channel 3 Mode (3 bits) */ 105a50c0d6fSJean-Christophe DUBOIS #define GPT_CR_FO1 (1 << 29) /* Force Output Compare Channel 1 */ 106a50c0d6fSJean-Christophe DUBOIS #define GPT_CR_FO2 (1 << 30) /* Force Output Compare Channel 2 */ 107a50c0d6fSJean-Christophe DUBOIS #define GPT_CR_FO3 (1 << 31) /* Force Output Compare Channel 3 */ 108a50c0d6fSJean-Christophe DUBOIS 109a50c0d6fSJean-Christophe DUBOIS #define GPT_SR_OF1 (1 << 0) 1105ec694b5SJean-Christophe DUBOIS #define GPT_SR_OF2 (1 << 1) 1115ec694b5SJean-Christophe DUBOIS #define GPT_SR_OF3 (1 << 2) 112a50c0d6fSJean-Christophe DUBOIS #define GPT_SR_ROV (1 << 5) 113a50c0d6fSJean-Christophe DUBOIS 114a50c0d6fSJean-Christophe DUBOIS #define GPT_IR_OF1IE (1 << 0) 1155ec694b5SJean-Christophe DUBOIS #define GPT_IR_OF2IE (1 << 1) 1165ec694b5SJean-Christophe DUBOIS #define GPT_IR_OF3IE (1 << 2) 117a50c0d6fSJean-Christophe DUBOIS #define GPT_IR_ROVIE (1 << 5) 118a50c0d6fSJean-Christophe DUBOIS 119a50c0d6fSJean-Christophe DUBOIS typedef struct { 120a50c0d6fSJean-Christophe DUBOIS SysBusDevice busdev; 121a50c0d6fSJean-Christophe DUBOIS ptimer_state *timer; 122a50c0d6fSJean-Christophe DUBOIS MemoryRegion iomem; 123a50c0d6fSJean-Christophe DUBOIS DeviceState *ccm; 124a50c0d6fSJean-Christophe DUBOIS 125a50c0d6fSJean-Christophe DUBOIS uint32_t cr; 126a50c0d6fSJean-Christophe DUBOIS uint32_t pr; 127a50c0d6fSJean-Christophe DUBOIS uint32_t sr; 128a50c0d6fSJean-Christophe DUBOIS uint32_t ir; 129a50c0d6fSJean-Christophe DUBOIS uint32_t ocr1; 130a50c0d6fSJean-Christophe DUBOIS uint32_t ocr2; 131a50c0d6fSJean-Christophe DUBOIS uint32_t ocr3; 132a50c0d6fSJean-Christophe DUBOIS uint32_t icr1; 133a50c0d6fSJean-Christophe DUBOIS uint32_t icr2; 134a50c0d6fSJean-Christophe DUBOIS uint32_t cnt; 135a50c0d6fSJean-Christophe DUBOIS 1365ec694b5SJean-Christophe DUBOIS uint32_t next_timeout; 1375ec694b5SJean-Christophe DUBOIS uint32_t next_int; 1385ec694b5SJean-Christophe DUBOIS 1395ec694b5SJean-Christophe DUBOIS uint32_t freq; 1405ec694b5SJean-Christophe DUBOIS 141a50c0d6fSJean-Christophe DUBOIS qemu_irq irq; 142*67110c3eSJean-Christophe DUBOIS } IMXGPTState; 143a50c0d6fSJean-Christophe DUBOIS 144*67110c3eSJean-Christophe DUBOIS static const VMStateDescription vmstate_imx_timer_gpt = { 1455ec694b5SJean-Christophe DUBOIS .name = TYPE_IMX_GPT, 1465ec694b5SJean-Christophe DUBOIS .version_id = 3, 1475ec694b5SJean-Christophe DUBOIS .minimum_version_id = 3, 1485ec694b5SJean-Christophe DUBOIS .minimum_version_id_old = 3, 149a50c0d6fSJean-Christophe DUBOIS .fields = (VMStateField[]) { 150*67110c3eSJean-Christophe DUBOIS VMSTATE_UINT32(cr, IMXGPTState), 151*67110c3eSJean-Christophe DUBOIS VMSTATE_UINT32(pr, IMXGPTState), 152*67110c3eSJean-Christophe DUBOIS VMSTATE_UINT32(sr, IMXGPTState), 153*67110c3eSJean-Christophe DUBOIS VMSTATE_UINT32(ir, IMXGPTState), 154*67110c3eSJean-Christophe DUBOIS VMSTATE_UINT32(ocr1, IMXGPTState), 155*67110c3eSJean-Christophe DUBOIS VMSTATE_UINT32(ocr2, IMXGPTState), 156*67110c3eSJean-Christophe DUBOIS VMSTATE_UINT32(ocr3, IMXGPTState), 157*67110c3eSJean-Christophe DUBOIS VMSTATE_UINT32(icr1, IMXGPTState), 158*67110c3eSJean-Christophe DUBOIS VMSTATE_UINT32(icr2, IMXGPTState), 159*67110c3eSJean-Christophe DUBOIS VMSTATE_UINT32(cnt, IMXGPTState), 160*67110c3eSJean-Christophe DUBOIS VMSTATE_UINT32(next_timeout, IMXGPTState), 161*67110c3eSJean-Christophe DUBOIS VMSTATE_UINT32(next_int, IMXGPTState), 162*67110c3eSJean-Christophe DUBOIS VMSTATE_UINT32(freq, IMXGPTState), 163*67110c3eSJean-Christophe DUBOIS VMSTATE_PTIMER(timer, IMXGPTState), 164a50c0d6fSJean-Christophe DUBOIS VMSTATE_END_OF_LIST() 165a50c0d6fSJean-Christophe DUBOIS } 166a50c0d6fSJean-Christophe DUBOIS }; 167a50c0d6fSJean-Christophe DUBOIS 168*67110c3eSJean-Christophe DUBOIS static const IMXClk imx_gpt_clocks[] = { 169a50c0d6fSJean-Christophe DUBOIS NOCLK, /* 000 No clock source */ 170a50c0d6fSJean-Christophe DUBOIS IPG, /* 001 ipg_clk, 532MHz*/ 171a50c0d6fSJean-Christophe DUBOIS IPG, /* 010 ipg_clk_highfreq */ 172a50c0d6fSJean-Christophe DUBOIS NOCLK, /* 011 not defined */ 173a50c0d6fSJean-Christophe DUBOIS CLK_32k, /* 100 ipg_clk_32k */ 174a50c0d6fSJean-Christophe DUBOIS NOCLK, /* 101 not defined */ 175a50c0d6fSJean-Christophe DUBOIS NOCLK, /* 110 not defined */ 176a50c0d6fSJean-Christophe DUBOIS NOCLK, /* 111 not defined */ 177a50c0d6fSJean-Christophe DUBOIS }; 178a50c0d6fSJean-Christophe DUBOIS 179*67110c3eSJean-Christophe DUBOIS static void imx_gpt_set_freq(IMXGPTState *s) 180a50c0d6fSJean-Christophe DUBOIS { 1815ec694b5SJean-Christophe DUBOIS uint32_t clksrc = extract32(s->cr, GPT_CR_CLKSRC_SHIFT, 3); 182*67110c3eSJean-Christophe DUBOIS uint32_t freq = imx_clock_frequency(s->ccm, imx_gpt_clocks[clksrc]) 1835ec694b5SJean-Christophe DUBOIS / (1 + s->pr); 1845ec694b5SJean-Christophe DUBOIS s->freq = freq; 185a50c0d6fSJean-Christophe DUBOIS 1865ec694b5SJean-Christophe DUBOIS DPRINTF("Setting clksrc %d to frequency %d\n", clksrc, freq); 187a50c0d6fSJean-Christophe DUBOIS 188a50c0d6fSJean-Christophe DUBOIS if (freq) { 189a50c0d6fSJean-Christophe DUBOIS ptimer_set_freq(s->timer, freq); 190a50c0d6fSJean-Christophe DUBOIS } 191a50c0d6fSJean-Christophe DUBOIS } 192a50c0d6fSJean-Christophe DUBOIS 193*67110c3eSJean-Christophe DUBOIS static void imx_gpt_update_int(IMXGPTState *s) 194a50c0d6fSJean-Christophe DUBOIS { 1955ec694b5SJean-Christophe DUBOIS if ((s->sr & s->ir) && (s->cr & GPT_CR_EN)) { 1965ec694b5SJean-Christophe DUBOIS qemu_irq_raise(s->irq); 1975ec694b5SJean-Christophe DUBOIS } else { 1985ec694b5SJean-Christophe DUBOIS qemu_irq_lower(s->irq); 1995ec694b5SJean-Christophe DUBOIS } 200a50c0d6fSJean-Christophe DUBOIS } 201a50c0d6fSJean-Christophe DUBOIS 202*67110c3eSJean-Christophe DUBOIS static uint32_t imx_gpt_update_count(IMXGPTState *s) 203a50c0d6fSJean-Christophe DUBOIS { 2045ec694b5SJean-Christophe DUBOIS s->cnt = s->next_timeout - (uint32_t)ptimer_get_count(s->timer); 2055ec694b5SJean-Christophe DUBOIS 206a50c0d6fSJean-Christophe DUBOIS return s->cnt; 207a50c0d6fSJean-Christophe DUBOIS } 208a50c0d6fSJean-Christophe DUBOIS 209*67110c3eSJean-Christophe DUBOIS static inline uint32_t imx_gpt_find_limit(uint32_t count, uint32_t reg, 2105ec694b5SJean-Christophe DUBOIS uint32_t timeout) 211a50c0d6fSJean-Christophe DUBOIS { 2125ec694b5SJean-Christophe DUBOIS if ((count < reg) && (timeout > reg)) { 2135ec694b5SJean-Christophe DUBOIS timeout = reg; 2145ec694b5SJean-Christophe DUBOIS } 215a50c0d6fSJean-Christophe DUBOIS 2165ec694b5SJean-Christophe DUBOIS return timeout; 2175ec694b5SJean-Christophe DUBOIS } 2185ec694b5SJean-Christophe DUBOIS 219*67110c3eSJean-Christophe DUBOIS static void imx_gpt_compute_next_timeout(IMXGPTState *s, bool event) 2205ec694b5SJean-Christophe DUBOIS { 2215ec694b5SJean-Christophe DUBOIS uint32_t timeout = TIMER_MAX; 2225ec694b5SJean-Christophe DUBOIS uint32_t count = 0; 2235ec694b5SJean-Christophe DUBOIS long long limit; 2245ec694b5SJean-Christophe DUBOIS 2255ec694b5SJean-Christophe DUBOIS if (!(s->cr & GPT_CR_EN)) { 2265ec694b5SJean-Christophe DUBOIS /* if not enabled just return */ 227a50c0d6fSJean-Christophe DUBOIS return; 228a50c0d6fSJean-Christophe DUBOIS } 229a50c0d6fSJean-Christophe DUBOIS 2305ec694b5SJean-Christophe DUBOIS if (event) { 2315ec694b5SJean-Christophe DUBOIS /* This is a timer event */ 2325ec694b5SJean-Christophe DUBOIS 2335ec694b5SJean-Christophe DUBOIS if ((s->cr & GPT_CR_FRR) && (s->next_timeout != TIMER_MAX)) { 234a50c0d6fSJean-Christophe DUBOIS /* 2355ec694b5SJean-Christophe DUBOIS * if we are in free running mode and we have not reached 2365ec694b5SJean-Christophe DUBOIS * the TIMER_MAX limit, then update the count 237a50c0d6fSJean-Christophe DUBOIS */ 238*67110c3eSJean-Christophe DUBOIS count = imx_gpt_update_count(s); 239a50c0d6fSJean-Christophe DUBOIS } 2405ec694b5SJean-Christophe DUBOIS } else { 2415ec694b5SJean-Christophe DUBOIS /* not a timer event, then just update the count */ 2425ec694b5SJean-Christophe DUBOIS 243*67110c3eSJean-Christophe DUBOIS count = imx_gpt_update_count(s); 2445ec694b5SJean-Christophe DUBOIS } 2455ec694b5SJean-Christophe DUBOIS 2465ec694b5SJean-Christophe DUBOIS /* now, find the next timeout related to count */ 2475ec694b5SJean-Christophe DUBOIS 2485ec694b5SJean-Christophe DUBOIS if (s->ir & GPT_IR_OF1IE) { 249*67110c3eSJean-Christophe DUBOIS timeout = imx_gpt_find_limit(count, s->ocr1, timeout); 2505ec694b5SJean-Christophe DUBOIS } 2515ec694b5SJean-Christophe DUBOIS if (s->ir & GPT_IR_OF2IE) { 252*67110c3eSJean-Christophe DUBOIS timeout = imx_gpt_find_limit(count, s->ocr2, timeout); 2535ec694b5SJean-Christophe DUBOIS } 2545ec694b5SJean-Christophe DUBOIS if (s->ir & GPT_IR_OF3IE) { 255*67110c3eSJean-Christophe DUBOIS timeout = imx_gpt_find_limit(count, s->ocr3, timeout); 2565ec694b5SJean-Christophe DUBOIS } 2575ec694b5SJean-Christophe DUBOIS 2585ec694b5SJean-Christophe DUBOIS /* find the next set of interrupts to raise for next timer event */ 2595ec694b5SJean-Christophe DUBOIS 2605ec694b5SJean-Christophe DUBOIS s->next_int = 0; 2615ec694b5SJean-Christophe DUBOIS if ((s->ir & GPT_IR_OF1IE) && (timeout == s->ocr1)) { 2625ec694b5SJean-Christophe DUBOIS s->next_int |= GPT_SR_OF1; 2635ec694b5SJean-Christophe DUBOIS } 2645ec694b5SJean-Christophe DUBOIS if ((s->ir & GPT_IR_OF2IE) && (timeout == s->ocr2)) { 2655ec694b5SJean-Christophe DUBOIS s->next_int |= GPT_SR_OF2; 2665ec694b5SJean-Christophe DUBOIS } 2675ec694b5SJean-Christophe DUBOIS if ((s->ir & GPT_IR_OF3IE) && (timeout == s->ocr3)) { 2685ec694b5SJean-Christophe DUBOIS s->next_int |= GPT_SR_OF3; 2695ec694b5SJean-Christophe DUBOIS } 2705ec694b5SJean-Christophe DUBOIS if ((s->ir & GPT_IR_ROVIE) && (timeout == TIMER_MAX)) { 2715ec694b5SJean-Christophe DUBOIS s->next_int |= GPT_SR_ROV; 2725ec694b5SJean-Christophe DUBOIS } 2735ec694b5SJean-Christophe DUBOIS 2745ec694b5SJean-Christophe DUBOIS /* the new range to count down from */ 275*67110c3eSJean-Christophe DUBOIS limit = timeout - imx_gpt_update_count(s); 2765ec694b5SJean-Christophe DUBOIS 2775ec694b5SJean-Christophe DUBOIS if (limit < 0) { 2785ec694b5SJean-Christophe DUBOIS /* 2795ec694b5SJean-Christophe DUBOIS * if we reach here, then QEMU is running too slow and we pass the 2805ec694b5SJean-Christophe DUBOIS * timeout limit while computing it. Let's deliver the interrupt 2815ec694b5SJean-Christophe DUBOIS * and compute a new limit. 2825ec694b5SJean-Christophe DUBOIS */ 2835ec694b5SJean-Christophe DUBOIS s->sr |= s->next_int; 2845ec694b5SJean-Christophe DUBOIS 285*67110c3eSJean-Christophe DUBOIS imx_gpt_compute_next_timeout(s, event); 2865ec694b5SJean-Christophe DUBOIS 287*67110c3eSJean-Christophe DUBOIS imx_gpt_update_int(s); 2885ec694b5SJean-Christophe DUBOIS } else { 2895ec694b5SJean-Christophe DUBOIS /* New timeout value */ 2905ec694b5SJean-Christophe DUBOIS s->next_timeout = timeout; 2915ec694b5SJean-Christophe DUBOIS 2925ec694b5SJean-Christophe DUBOIS /* reset the limit to the computed range */ 2935ec694b5SJean-Christophe DUBOIS ptimer_set_limit(s->timer, limit, 1); 2945ec694b5SJean-Christophe DUBOIS } 295a50c0d6fSJean-Christophe DUBOIS } 296a50c0d6fSJean-Christophe DUBOIS 297*67110c3eSJean-Christophe DUBOIS static uint64_t imx_gpt_read(void *opaque, hwaddr offset, unsigned size) 298a50c0d6fSJean-Christophe DUBOIS { 299*67110c3eSJean-Christophe DUBOIS IMXGPTState *s = IMX_GPT(opaque); 3005ec694b5SJean-Christophe DUBOIS uint32_t reg_value = 0; 3015ec694b5SJean-Christophe DUBOIS uint32_t reg = offset >> 2; 302a50c0d6fSJean-Christophe DUBOIS 3035ec694b5SJean-Christophe DUBOIS switch (reg) { 304a50c0d6fSJean-Christophe DUBOIS case 0: /* Control Register */ 3055ec694b5SJean-Christophe DUBOIS reg_value = s->cr; 3065ec694b5SJean-Christophe DUBOIS break; 307a50c0d6fSJean-Christophe DUBOIS 308a50c0d6fSJean-Christophe DUBOIS case 1: /* prescaler */ 3095ec694b5SJean-Christophe DUBOIS reg_value = s->pr; 3105ec694b5SJean-Christophe DUBOIS break; 311a50c0d6fSJean-Christophe DUBOIS 312a50c0d6fSJean-Christophe DUBOIS case 2: /* Status Register */ 3135ec694b5SJean-Christophe DUBOIS reg_value = s->sr; 3145ec694b5SJean-Christophe DUBOIS break; 315a50c0d6fSJean-Christophe DUBOIS 316a50c0d6fSJean-Christophe DUBOIS case 3: /* Interrupt Register */ 3175ec694b5SJean-Christophe DUBOIS reg_value = s->ir; 3185ec694b5SJean-Christophe DUBOIS break; 319a50c0d6fSJean-Christophe DUBOIS 320a50c0d6fSJean-Christophe DUBOIS case 4: /* Output Compare Register 1 */ 3215ec694b5SJean-Christophe DUBOIS reg_value = s->ocr1; 3225ec694b5SJean-Christophe DUBOIS break; 323a50c0d6fSJean-Christophe DUBOIS 324a50c0d6fSJean-Christophe DUBOIS case 5: /* Output Compare Register 2 */ 3255ec694b5SJean-Christophe DUBOIS reg_value = s->ocr2; 3265ec694b5SJean-Christophe DUBOIS break; 327a50c0d6fSJean-Christophe DUBOIS 328a50c0d6fSJean-Christophe DUBOIS case 6: /* Output Compare Register 3 */ 3295ec694b5SJean-Christophe DUBOIS reg_value = s->ocr3; 3305ec694b5SJean-Christophe DUBOIS break; 331a50c0d6fSJean-Christophe DUBOIS 332a50c0d6fSJean-Christophe DUBOIS case 7: /* input Capture Register 1 */ 3335ec694b5SJean-Christophe DUBOIS qemu_log_mask(LOG_UNIMP, "icr1 feature is not implemented\n"); 3345ec694b5SJean-Christophe DUBOIS reg_value = s->icr1; 3355ec694b5SJean-Christophe DUBOIS break; 336a50c0d6fSJean-Christophe DUBOIS 337a50c0d6fSJean-Christophe DUBOIS case 8: /* input Capture Register 2 */ 3385ec694b5SJean-Christophe DUBOIS qemu_log_mask(LOG_UNIMP, "icr2 feature is not implemented\n"); 3395ec694b5SJean-Christophe DUBOIS reg_value = s->icr2; 3405ec694b5SJean-Christophe DUBOIS break; 341a50c0d6fSJean-Christophe DUBOIS 342a50c0d6fSJean-Christophe DUBOIS case 9: /* cnt */ 343*67110c3eSJean-Christophe DUBOIS imx_gpt_update_count(s); 3445ec694b5SJean-Christophe DUBOIS reg_value = s->cnt; 3455ec694b5SJean-Christophe DUBOIS break; 3465ec694b5SJean-Christophe DUBOIS 3475ec694b5SJean-Christophe DUBOIS default: 3485ec694b5SJean-Christophe DUBOIS IPRINTF("Bad offset %x\n", reg); 3495ec694b5SJean-Christophe DUBOIS break; 350a50c0d6fSJean-Christophe DUBOIS } 351a50c0d6fSJean-Christophe DUBOIS 352*67110c3eSJean-Christophe DUBOIS DPRINTF("(%s) = 0x%08x\n", imx_gpt_reg_name(reg), reg_value); 353a50c0d6fSJean-Christophe DUBOIS 3545ec694b5SJean-Christophe DUBOIS return reg_value; 355a50c0d6fSJean-Christophe DUBOIS } 356a50c0d6fSJean-Christophe DUBOIS 357*67110c3eSJean-Christophe DUBOIS static void imx_gpt_reset(DeviceState *dev) 358a50c0d6fSJean-Christophe DUBOIS { 359*67110c3eSJean-Christophe DUBOIS IMXGPTState *s = IMX_GPT(dev); 360a50c0d6fSJean-Christophe DUBOIS 3615ec694b5SJean-Christophe DUBOIS /* stop timer */ 3625ec694b5SJean-Christophe DUBOIS ptimer_stop(s->timer); 3635ec694b5SJean-Christophe DUBOIS 364a50c0d6fSJean-Christophe DUBOIS /* 365a50c0d6fSJean-Christophe DUBOIS * Soft reset doesn't touch some bits; hard reset clears them 366a50c0d6fSJean-Christophe DUBOIS */ 367a50c0d6fSJean-Christophe DUBOIS s->cr &= ~(GPT_CR_EN|GPT_CR_ENMOD|GPT_CR_STOPEN|GPT_CR_DOZEN| 368a50c0d6fSJean-Christophe DUBOIS GPT_CR_WAITEN|GPT_CR_DBGEN); 369a50c0d6fSJean-Christophe DUBOIS s->sr = 0; 370a50c0d6fSJean-Christophe DUBOIS s->pr = 0; 371a50c0d6fSJean-Christophe DUBOIS s->ir = 0; 372a50c0d6fSJean-Christophe DUBOIS s->cnt = 0; 373a50c0d6fSJean-Christophe DUBOIS s->ocr1 = TIMER_MAX; 374a50c0d6fSJean-Christophe DUBOIS s->ocr2 = TIMER_MAX; 375a50c0d6fSJean-Christophe DUBOIS s->ocr3 = TIMER_MAX; 376a50c0d6fSJean-Christophe DUBOIS s->icr1 = 0; 377a50c0d6fSJean-Christophe DUBOIS s->icr2 = 0; 3785ec694b5SJean-Christophe DUBOIS 3795ec694b5SJean-Christophe DUBOIS s->next_timeout = TIMER_MAX; 3805ec694b5SJean-Christophe DUBOIS s->next_int = 0; 3815ec694b5SJean-Christophe DUBOIS 3825ec694b5SJean-Christophe DUBOIS /* compute new freq */ 383*67110c3eSJean-Christophe DUBOIS imx_gpt_set_freq(s); 3845ec694b5SJean-Christophe DUBOIS 3855ec694b5SJean-Christophe DUBOIS /* reset the limit to TIMER_MAX */ 3865ec694b5SJean-Christophe DUBOIS ptimer_set_limit(s->timer, TIMER_MAX, 1); 3875ec694b5SJean-Christophe DUBOIS 3885ec694b5SJean-Christophe DUBOIS /* if the timer is still enabled, restart it */ 3895ec694b5SJean-Christophe DUBOIS if (s->freq && (s->cr & GPT_CR_EN)) { 3905ec694b5SJean-Christophe DUBOIS ptimer_run(s->timer, 1); 3915ec694b5SJean-Christophe DUBOIS } 392a50c0d6fSJean-Christophe DUBOIS } 393a50c0d6fSJean-Christophe DUBOIS 394*67110c3eSJean-Christophe DUBOIS static void imx_gpt_write(void *opaque, hwaddr offset, uint64_t value, 395*67110c3eSJean-Christophe DUBOIS unsigned size) 396a50c0d6fSJean-Christophe DUBOIS { 397*67110c3eSJean-Christophe DUBOIS IMXGPTState *s = IMX_GPT(opaque); 3985ec694b5SJean-Christophe DUBOIS uint32_t oldreg; 3995ec694b5SJean-Christophe DUBOIS uint32_t reg = offset >> 2; 400a50c0d6fSJean-Christophe DUBOIS 401*67110c3eSJean-Christophe DUBOIS DPRINTF("(%s, value = 0x%08x)\n", imx_gpt_reg_name(reg), 4025ec694b5SJean-Christophe DUBOIS (uint32_t)value); 403a50c0d6fSJean-Christophe DUBOIS 4045ec694b5SJean-Christophe DUBOIS switch (reg) { 4055ec694b5SJean-Christophe DUBOIS case 0: 4065ec694b5SJean-Christophe DUBOIS oldreg = s->cr; 4075ec694b5SJean-Christophe DUBOIS s->cr = value & ~0x7c14; 4085ec694b5SJean-Christophe DUBOIS if (s->cr & GPT_CR_SWR) { /* force reset */ 4095ec694b5SJean-Christophe DUBOIS /* handle the reset */ 410*67110c3eSJean-Christophe DUBOIS imx_gpt_reset(DEVICE(s)); 411a50c0d6fSJean-Christophe DUBOIS } else { 4125ec694b5SJean-Christophe DUBOIS /* set our freq, as the source might have changed */ 413*67110c3eSJean-Christophe DUBOIS imx_gpt_set_freq(s); 4145ec694b5SJean-Christophe DUBOIS 4155ec694b5SJean-Christophe DUBOIS if ((oldreg ^ s->cr) & GPT_CR_EN) { 4165ec694b5SJean-Christophe DUBOIS if (s->cr & GPT_CR_EN) { 4175ec694b5SJean-Christophe DUBOIS if (s->cr & GPT_CR_ENMOD) { 4185ec694b5SJean-Christophe DUBOIS s->next_timeout = TIMER_MAX; 4195ec694b5SJean-Christophe DUBOIS ptimer_set_count(s->timer, TIMER_MAX); 420*67110c3eSJean-Christophe DUBOIS imx_gpt_compute_next_timeout(s, false); 4215ec694b5SJean-Christophe DUBOIS } 4225ec694b5SJean-Christophe DUBOIS ptimer_run(s->timer, 1); 4235ec694b5SJean-Christophe DUBOIS } else { 4245ec694b5SJean-Christophe DUBOIS /* stop timer */ 425a50c0d6fSJean-Christophe DUBOIS ptimer_stop(s->timer); 426a50c0d6fSJean-Christophe DUBOIS } 427a50c0d6fSJean-Christophe DUBOIS } 4285ec694b5SJean-Christophe DUBOIS } 4295ec694b5SJean-Christophe DUBOIS break; 430a50c0d6fSJean-Christophe DUBOIS 431a50c0d6fSJean-Christophe DUBOIS case 1: /* Prescaler */ 432a50c0d6fSJean-Christophe DUBOIS s->pr = value & 0xfff; 433*67110c3eSJean-Christophe DUBOIS imx_gpt_set_freq(s); 4345ec694b5SJean-Christophe DUBOIS break; 435a50c0d6fSJean-Christophe DUBOIS 436a50c0d6fSJean-Christophe DUBOIS case 2: /* SR */ 4375ec694b5SJean-Christophe DUBOIS s->sr &= ~(value & 0x3f); 438*67110c3eSJean-Christophe DUBOIS imx_gpt_update_int(s); 4395ec694b5SJean-Christophe DUBOIS break; 440a50c0d6fSJean-Christophe DUBOIS 441a50c0d6fSJean-Christophe DUBOIS case 3: /* IR -- interrupt register */ 442a50c0d6fSJean-Christophe DUBOIS s->ir = value & 0x3f; 443*67110c3eSJean-Christophe DUBOIS imx_gpt_update_int(s); 4445ec694b5SJean-Christophe DUBOIS 445*67110c3eSJean-Christophe DUBOIS imx_gpt_compute_next_timeout(s, false); 4465ec694b5SJean-Christophe DUBOIS 4475ec694b5SJean-Christophe DUBOIS break; 448a50c0d6fSJean-Christophe DUBOIS 449a50c0d6fSJean-Christophe DUBOIS case 4: /* OCR1 -- output compare register */ 4505ec694b5SJean-Christophe DUBOIS s->ocr1 = value; 4515ec694b5SJean-Christophe DUBOIS 452a50c0d6fSJean-Christophe DUBOIS /* In non-freerun mode, reset count when this register is written */ 453a50c0d6fSJean-Christophe DUBOIS if (!(s->cr & GPT_CR_FRR)) { 4545ec694b5SJean-Christophe DUBOIS s->next_timeout = TIMER_MAX; 4555ec694b5SJean-Christophe DUBOIS ptimer_set_limit(s->timer, TIMER_MAX, 1); 456a50c0d6fSJean-Christophe DUBOIS } 4575ec694b5SJean-Christophe DUBOIS 4585ec694b5SJean-Christophe DUBOIS /* compute the new timeout */ 459*67110c3eSJean-Christophe DUBOIS imx_gpt_compute_next_timeout(s, false); 4605ec694b5SJean-Christophe DUBOIS 4615ec694b5SJean-Christophe DUBOIS break; 462a50c0d6fSJean-Christophe DUBOIS 463a50c0d6fSJean-Christophe DUBOIS case 5: /* OCR2 -- output compare register */ 4645ec694b5SJean-Christophe DUBOIS s->ocr2 = value; 4655ec694b5SJean-Christophe DUBOIS 4665ec694b5SJean-Christophe DUBOIS /* compute the new timeout */ 467*67110c3eSJean-Christophe DUBOIS imx_gpt_compute_next_timeout(s, false); 4685ec694b5SJean-Christophe DUBOIS 4695ec694b5SJean-Christophe DUBOIS break; 4705ec694b5SJean-Christophe DUBOIS 471a50c0d6fSJean-Christophe DUBOIS case 6: /* OCR3 -- output compare register */ 4725ec694b5SJean-Christophe DUBOIS s->ocr3 = value; 4735ec694b5SJean-Christophe DUBOIS 4745ec694b5SJean-Christophe DUBOIS /* compute the new timeout */ 475*67110c3eSJean-Christophe DUBOIS imx_gpt_compute_next_timeout(s, false); 4765ec694b5SJean-Christophe DUBOIS 4775ec694b5SJean-Christophe DUBOIS break; 4785ec694b5SJean-Christophe DUBOIS 479a50c0d6fSJean-Christophe DUBOIS default: 4805ec694b5SJean-Christophe DUBOIS IPRINTF("Bad offset %x\n", reg); 4815ec694b5SJean-Christophe DUBOIS break; 482a50c0d6fSJean-Christophe DUBOIS } 483a50c0d6fSJean-Christophe DUBOIS } 484a50c0d6fSJean-Christophe DUBOIS 485*67110c3eSJean-Christophe DUBOIS static void imx_gpt_timeout(void *opaque) 486a50c0d6fSJean-Christophe DUBOIS { 487*67110c3eSJean-Christophe DUBOIS IMXGPTState *s = IMX_GPT(opaque); 488a50c0d6fSJean-Christophe DUBOIS 4895ec694b5SJean-Christophe DUBOIS DPRINTF("\n"); 490a50c0d6fSJean-Christophe DUBOIS 4915ec694b5SJean-Christophe DUBOIS s->sr |= s->next_int; 4925ec694b5SJean-Christophe DUBOIS s->next_int = 0; 493a50c0d6fSJean-Christophe DUBOIS 494*67110c3eSJean-Christophe DUBOIS imx_gpt_compute_next_timeout(s, true); 4955ec694b5SJean-Christophe DUBOIS 496*67110c3eSJean-Christophe DUBOIS imx_gpt_update_int(s); 4975ec694b5SJean-Christophe DUBOIS 4985ec694b5SJean-Christophe DUBOIS if (s->freq && (s->cr & GPT_CR_EN)) { 4995ec694b5SJean-Christophe DUBOIS ptimer_run(s->timer, 1); 5005ec694b5SJean-Christophe DUBOIS } 501a50c0d6fSJean-Christophe DUBOIS } 502a50c0d6fSJean-Christophe DUBOIS 503*67110c3eSJean-Christophe DUBOIS static const MemoryRegionOps imx_gpt_ops = { 504*67110c3eSJean-Christophe DUBOIS .read = imx_gpt_read, 505*67110c3eSJean-Christophe DUBOIS .write = imx_gpt_write, 506a50c0d6fSJean-Christophe DUBOIS .endianness = DEVICE_NATIVE_ENDIAN, 507a50c0d6fSJean-Christophe DUBOIS }; 508a50c0d6fSJean-Christophe DUBOIS 509a50c0d6fSJean-Christophe DUBOIS 510*67110c3eSJean-Christophe DUBOIS static void imx_gpt_realize(DeviceState *dev, Error **errp) 511a50c0d6fSJean-Christophe DUBOIS { 512*67110c3eSJean-Christophe DUBOIS IMXGPTState *s = IMX_GPT(dev); 513*67110c3eSJean-Christophe DUBOIS SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 514a50c0d6fSJean-Christophe DUBOIS QEMUBH *bh; 515a50c0d6fSJean-Christophe DUBOIS 516*67110c3eSJean-Christophe DUBOIS sysbus_init_irq(sbd, &s->irq); 517*67110c3eSJean-Christophe DUBOIS memory_region_init_io(&s->iomem, &imx_gpt_ops, s, TYPE_IMX_GPT, 518a50c0d6fSJean-Christophe DUBOIS 0x00001000); 519*67110c3eSJean-Christophe DUBOIS sysbus_init_mmio(sbd, &s->iomem); 520a50c0d6fSJean-Christophe DUBOIS 521*67110c3eSJean-Christophe DUBOIS bh = qemu_bh_new(imx_gpt_timeout, s); 522a50c0d6fSJean-Christophe DUBOIS s->timer = ptimer_init(bh); 523a50c0d6fSJean-Christophe DUBOIS } 524a50c0d6fSJean-Christophe DUBOIS 5255ec694b5SJean-Christophe DUBOIS void imx_timerg_create(const hwaddr addr, qemu_irq irq, DeviceState *ccm) 526a50c0d6fSJean-Christophe DUBOIS { 527*67110c3eSJean-Christophe DUBOIS IMXGPTState *pp; 528a50c0d6fSJean-Christophe DUBOIS DeviceState *dev; 529a50c0d6fSJean-Christophe DUBOIS 5305ec694b5SJean-Christophe DUBOIS dev = sysbus_create_simple(TYPE_IMX_GPT, addr, irq); 531*67110c3eSJean-Christophe DUBOIS pp = IMX_GPT(dev); 532a50c0d6fSJean-Christophe DUBOIS pp->ccm = ccm; 533a50c0d6fSJean-Christophe DUBOIS } 534a50c0d6fSJean-Christophe DUBOIS 535*67110c3eSJean-Christophe DUBOIS static void imx_gpt_class_init(ObjectClass *klass, void *data) 536a50c0d6fSJean-Christophe DUBOIS { 537a50c0d6fSJean-Christophe DUBOIS DeviceClass *dc = DEVICE_CLASS(klass); 538*67110c3eSJean-Christophe DUBOIS 539*67110c3eSJean-Christophe DUBOIS dc->realize = imx_gpt_realize; 540*67110c3eSJean-Christophe DUBOIS dc->reset = imx_gpt_reset; 541*67110c3eSJean-Christophe DUBOIS dc->vmsd = &vmstate_imx_timer_gpt; 542a50c0d6fSJean-Christophe DUBOIS dc->desc = "i.MX general timer"; 543a50c0d6fSJean-Christophe DUBOIS } 544a50c0d6fSJean-Christophe DUBOIS 545*67110c3eSJean-Christophe DUBOIS static const TypeInfo imx_gpt_info = { 5465ec694b5SJean-Christophe DUBOIS .name = TYPE_IMX_GPT, 547a50c0d6fSJean-Christophe DUBOIS .parent = TYPE_SYS_BUS_DEVICE, 548*67110c3eSJean-Christophe DUBOIS .instance_size = sizeof(IMXGPTState), 549*67110c3eSJean-Christophe DUBOIS .class_init = imx_gpt_class_init, 550a50c0d6fSJean-Christophe DUBOIS }; 551a50c0d6fSJean-Christophe DUBOIS 552*67110c3eSJean-Christophe DUBOIS static void imx_gpt_register_types(void) 553a50c0d6fSJean-Christophe DUBOIS { 554*67110c3eSJean-Christophe DUBOIS type_register_static(&imx_gpt_info); 555a50c0d6fSJean-Christophe DUBOIS } 556a50c0d6fSJean-Christophe DUBOIS 557*67110c3eSJean-Christophe DUBOIS type_init(imx_gpt_register_types) 558