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 8d647b26dSJean-Christophe Dubois * Updated by Jean-Christophe Dubois <jcd@tribudubois.net> 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 15d647b26dSJean-Christophe Dubois #include "hw/timer/imx_gpt.h" 16d647b26dSJean-Christophe Dubois #include "hw/misc/imx_ccm.h" 176a1751b7SAlex Bligh #include "qemu/main-loop.h" 18a50c0d6fSJean-Christophe DUBOIS 1905453526SJean-Christophe Dubois #ifndef DEBUG_IMX_GPT 2005453526SJean-Christophe Dubois #define DEBUG_IMX_GPT 0 2105453526SJean-Christophe Dubois #endif 2205453526SJean-Christophe Dubois 2305453526SJean-Christophe Dubois #define DPRINTF(fmt, args...) \ 2405453526SJean-Christophe Dubois do { \ 2505453526SJean-Christophe Dubois if (DEBUG_IMX_GPT) { \ 2605453526SJean-Christophe Dubois fprintf(stderr, "[%s]%s: " fmt , TYPE_IMX_GPT, \ 2705453526SJean-Christophe Dubois __func__, ##args); \ 2805453526SJean-Christophe Dubois } \ 2905453526SJean-Christophe Dubois } while (0) 305ec694b5SJean-Christophe DUBOIS 3167110c3eSJean-Christophe DUBOIS static char const *imx_gpt_reg_name(uint32_t reg) 325ec694b5SJean-Christophe DUBOIS { 335ec694b5SJean-Christophe DUBOIS switch (reg) { 345ec694b5SJean-Christophe DUBOIS case 0: 355ec694b5SJean-Christophe DUBOIS return "CR"; 365ec694b5SJean-Christophe DUBOIS case 1: 375ec694b5SJean-Christophe DUBOIS return "PR"; 385ec694b5SJean-Christophe DUBOIS case 2: 395ec694b5SJean-Christophe DUBOIS return "SR"; 405ec694b5SJean-Christophe DUBOIS case 3: 415ec694b5SJean-Christophe DUBOIS return "IR"; 425ec694b5SJean-Christophe DUBOIS case 4: 435ec694b5SJean-Christophe DUBOIS return "OCR1"; 445ec694b5SJean-Christophe DUBOIS case 5: 455ec694b5SJean-Christophe DUBOIS return "OCR2"; 465ec694b5SJean-Christophe DUBOIS case 6: 475ec694b5SJean-Christophe DUBOIS return "OCR3"; 485ec694b5SJean-Christophe DUBOIS case 7: 495ec694b5SJean-Christophe DUBOIS return "ICR1"; 505ec694b5SJean-Christophe DUBOIS case 8: 515ec694b5SJean-Christophe DUBOIS return "ICR2"; 525ec694b5SJean-Christophe DUBOIS case 9: 535ec694b5SJean-Christophe DUBOIS return "CNT"; 545ec694b5SJean-Christophe DUBOIS default: 555ec694b5SJean-Christophe DUBOIS return "[?]"; 565ec694b5SJean-Christophe DUBOIS } 575ec694b5SJean-Christophe DUBOIS } 585ec694b5SJean-Christophe DUBOIS 5967110c3eSJean-Christophe DUBOIS static const VMStateDescription vmstate_imx_timer_gpt = { 6068b85290SJean-Christophe Dubois .name = TYPE_IMX_GPT, 615ec694b5SJean-Christophe DUBOIS .version_id = 3, 625ec694b5SJean-Christophe DUBOIS .minimum_version_id = 3, 63a50c0d6fSJean-Christophe DUBOIS .fields = (VMStateField[]) { 6467110c3eSJean-Christophe DUBOIS VMSTATE_UINT32(cr, IMXGPTState), 6567110c3eSJean-Christophe DUBOIS VMSTATE_UINT32(pr, IMXGPTState), 6667110c3eSJean-Christophe DUBOIS VMSTATE_UINT32(sr, IMXGPTState), 6767110c3eSJean-Christophe DUBOIS VMSTATE_UINT32(ir, IMXGPTState), 6867110c3eSJean-Christophe DUBOIS VMSTATE_UINT32(ocr1, IMXGPTState), 6967110c3eSJean-Christophe DUBOIS VMSTATE_UINT32(ocr2, IMXGPTState), 7067110c3eSJean-Christophe DUBOIS VMSTATE_UINT32(ocr3, IMXGPTState), 7167110c3eSJean-Christophe DUBOIS VMSTATE_UINT32(icr1, IMXGPTState), 7267110c3eSJean-Christophe DUBOIS VMSTATE_UINT32(icr2, IMXGPTState), 7367110c3eSJean-Christophe DUBOIS VMSTATE_UINT32(cnt, IMXGPTState), 7467110c3eSJean-Christophe DUBOIS VMSTATE_UINT32(next_timeout, IMXGPTState), 7567110c3eSJean-Christophe DUBOIS VMSTATE_UINT32(next_int, IMXGPTState), 7667110c3eSJean-Christophe DUBOIS VMSTATE_UINT32(freq, IMXGPTState), 7767110c3eSJean-Christophe DUBOIS VMSTATE_PTIMER(timer, IMXGPTState), 78a50c0d6fSJean-Christophe DUBOIS VMSTATE_END_OF_LIST() 79a50c0d6fSJean-Christophe DUBOIS } 80a50c0d6fSJean-Christophe DUBOIS }; 81a50c0d6fSJean-Christophe DUBOIS 8267110c3eSJean-Christophe DUBOIS static const IMXClk imx_gpt_clocks[] = { 83a50c0d6fSJean-Christophe DUBOIS NOCLK, /* 000 No clock source */ 84*aaa9ec3bSJean-Christophe Dubois CLK_IPG, /* 001 ipg_clk, 532MHz*/ 85*aaa9ec3bSJean-Christophe Dubois CLK_IPG, /* 010 ipg_clk_highfreq */ 86a50c0d6fSJean-Christophe DUBOIS NOCLK, /* 011 not defined */ 87a50c0d6fSJean-Christophe DUBOIS CLK_32k, /* 100 ipg_clk_32k */ 88a50c0d6fSJean-Christophe DUBOIS NOCLK, /* 101 not defined */ 89a50c0d6fSJean-Christophe DUBOIS NOCLK, /* 110 not defined */ 90a50c0d6fSJean-Christophe DUBOIS NOCLK, /* 111 not defined */ 91a50c0d6fSJean-Christophe DUBOIS }; 92a50c0d6fSJean-Christophe DUBOIS 9367110c3eSJean-Christophe DUBOIS static void imx_gpt_set_freq(IMXGPTState *s) 94a50c0d6fSJean-Christophe DUBOIS { 955ec694b5SJean-Christophe DUBOIS uint32_t clksrc = extract32(s->cr, GPT_CR_CLKSRC_SHIFT, 3); 96a50c0d6fSJean-Christophe DUBOIS 97*aaa9ec3bSJean-Christophe Dubois s->freq = imx_ccm_get_clock_frequency(s->ccm, 98*aaa9ec3bSJean-Christophe Dubois imx_gpt_clocks[clksrc]) / (1 + s->pr); 99a50c0d6fSJean-Christophe DUBOIS 100*aaa9ec3bSJean-Christophe Dubois DPRINTF("Setting clksrc %d to frequency %d\n", clksrc, s->freq); 101*aaa9ec3bSJean-Christophe Dubois 102*aaa9ec3bSJean-Christophe Dubois if (s->freq) { 103*aaa9ec3bSJean-Christophe Dubois ptimer_set_freq(s->timer, s->freq); 104a50c0d6fSJean-Christophe DUBOIS } 105a50c0d6fSJean-Christophe DUBOIS } 106a50c0d6fSJean-Christophe DUBOIS 10767110c3eSJean-Christophe DUBOIS static void imx_gpt_update_int(IMXGPTState *s) 108a50c0d6fSJean-Christophe DUBOIS { 1095ec694b5SJean-Christophe DUBOIS if ((s->sr & s->ir) && (s->cr & GPT_CR_EN)) { 1105ec694b5SJean-Christophe DUBOIS qemu_irq_raise(s->irq); 1115ec694b5SJean-Christophe DUBOIS } else { 1125ec694b5SJean-Christophe DUBOIS qemu_irq_lower(s->irq); 1135ec694b5SJean-Christophe DUBOIS } 114a50c0d6fSJean-Christophe DUBOIS } 115a50c0d6fSJean-Christophe DUBOIS 11667110c3eSJean-Christophe DUBOIS static uint32_t imx_gpt_update_count(IMXGPTState *s) 117a50c0d6fSJean-Christophe DUBOIS { 1185ec694b5SJean-Christophe DUBOIS s->cnt = s->next_timeout - (uint32_t)ptimer_get_count(s->timer); 1195ec694b5SJean-Christophe DUBOIS 120a50c0d6fSJean-Christophe DUBOIS return s->cnt; 121a50c0d6fSJean-Christophe DUBOIS } 122a50c0d6fSJean-Christophe DUBOIS 12367110c3eSJean-Christophe DUBOIS static inline uint32_t imx_gpt_find_limit(uint32_t count, uint32_t reg, 1245ec694b5SJean-Christophe DUBOIS uint32_t timeout) 125a50c0d6fSJean-Christophe DUBOIS { 1265ec694b5SJean-Christophe DUBOIS if ((count < reg) && (timeout > reg)) { 1275ec694b5SJean-Christophe DUBOIS timeout = reg; 1285ec694b5SJean-Christophe DUBOIS } 129a50c0d6fSJean-Christophe DUBOIS 1305ec694b5SJean-Christophe DUBOIS return timeout; 1315ec694b5SJean-Christophe DUBOIS } 1325ec694b5SJean-Christophe DUBOIS 13367110c3eSJean-Christophe DUBOIS static void imx_gpt_compute_next_timeout(IMXGPTState *s, bool event) 1345ec694b5SJean-Christophe DUBOIS { 135203d65a4SMichael Tokarev uint32_t timeout = GPT_TIMER_MAX; 1365ec694b5SJean-Christophe DUBOIS uint32_t count = 0; 1375ec694b5SJean-Christophe DUBOIS long long limit; 1385ec694b5SJean-Christophe DUBOIS 1395ec694b5SJean-Christophe DUBOIS if (!(s->cr & GPT_CR_EN)) { 1405ec694b5SJean-Christophe DUBOIS /* if not enabled just return */ 141a50c0d6fSJean-Christophe DUBOIS return; 142a50c0d6fSJean-Christophe DUBOIS } 143a50c0d6fSJean-Christophe DUBOIS 1445ec694b5SJean-Christophe DUBOIS if (event) { 1455ec694b5SJean-Christophe DUBOIS /* This is a timer event */ 1465ec694b5SJean-Christophe DUBOIS 147203d65a4SMichael Tokarev if ((s->cr & GPT_CR_FRR) && (s->next_timeout != GPT_TIMER_MAX)) { 148a50c0d6fSJean-Christophe DUBOIS /* 1495ec694b5SJean-Christophe DUBOIS * if we are in free running mode and we have not reached 150203d65a4SMichael Tokarev * the GPT_TIMER_MAX limit, then update the count 151a50c0d6fSJean-Christophe DUBOIS */ 15267110c3eSJean-Christophe DUBOIS count = imx_gpt_update_count(s); 153a50c0d6fSJean-Christophe DUBOIS } 1545ec694b5SJean-Christophe DUBOIS } else { 1555ec694b5SJean-Christophe DUBOIS /* not a timer event, then just update the count */ 1565ec694b5SJean-Christophe DUBOIS 15767110c3eSJean-Christophe DUBOIS count = imx_gpt_update_count(s); 1585ec694b5SJean-Christophe DUBOIS } 1595ec694b5SJean-Christophe DUBOIS 1605ec694b5SJean-Christophe DUBOIS /* now, find the next timeout related to count */ 1615ec694b5SJean-Christophe DUBOIS 1625ec694b5SJean-Christophe DUBOIS if (s->ir & GPT_IR_OF1IE) { 16367110c3eSJean-Christophe DUBOIS timeout = imx_gpt_find_limit(count, s->ocr1, timeout); 1645ec694b5SJean-Christophe DUBOIS } 1655ec694b5SJean-Christophe DUBOIS if (s->ir & GPT_IR_OF2IE) { 16667110c3eSJean-Christophe DUBOIS timeout = imx_gpt_find_limit(count, s->ocr2, timeout); 1675ec694b5SJean-Christophe DUBOIS } 1685ec694b5SJean-Christophe DUBOIS if (s->ir & GPT_IR_OF3IE) { 16967110c3eSJean-Christophe DUBOIS timeout = imx_gpt_find_limit(count, s->ocr3, timeout); 1705ec694b5SJean-Christophe DUBOIS } 1715ec694b5SJean-Christophe DUBOIS 1725ec694b5SJean-Christophe DUBOIS /* find the next set of interrupts to raise for next timer event */ 1735ec694b5SJean-Christophe DUBOIS 1745ec694b5SJean-Christophe DUBOIS s->next_int = 0; 1755ec694b5SJean-Christophe DUBOIS if ((s->ir & GPT_IR_OF1IE) && (timeout == s->ocr1)) { 1765ec694b5SJean-Christophe DUBOIS s->next_int |= GPT_SR_OF1; 1775ec694b5SJean-Christophe DUBOIS } 1785ec694b5SJean-Christophe DUBOIS if ((s->ir & GPT_IR_OF2IE) && (timeout == s->ocr2)) { 1795ec694b5SJean-Christophe DUBOIS s->next_int |= GPT_SR_OF2; 1805ec694b5SJean-Christophe DUBOIS } 1815ec694b5SJean-Christophe DUBOIS if ((s->ir & GPT_IR_OF3IE) && (timeout == s->ocr3)) { 1825ec694b5SJean-Christophe DUBOIS s->next_int |= GPT_SR_OF3; 1835ec694b5SJean-Christophe DUBOIS } 184203d65a4SMichael Tokarev if ((s->ir & GPT_IR_ROVIE) && (timeout == GPT_TIMER_MAX)) { 1855ec694b5SJean-Christophe DUBOIS s->next_int |= GPT_SR_ROV; 1865ec694b5SJean-Christophe DUBOIS } 1875ec694b5SJean-Christophe DUBOIS 1885ec694b5SJean-Christophe DUBOIS /* the new range to count down from */ 18967110c3eSJean-Christophe DUBOIS limit = timeout - imx_gpt_update_count(s); 1905ec694b5SJean-Christophe DUBOIS 1915ec694b5SJean-Christophe DUBOIS if (limit < 0) { 1925ec694b5SJean-Christophe DUBOIS /* 1935ec694b5SJean-Christophe DUBOIS * if we reach here, then QEMU is running too slow and we pass the 1945ec694b5SJean-Christophe DUBOIS * timeout limit while computing it. Let's deliver the interrupt 1955ec694b5SJean-Christophe DUBOIS * and compute a new limit. 1965ec694b5SJean-Christophe DUBOIS */ 1975ec694b5SJean-Christophe DUBOIS s->sr |= s->next_int; 1985ec694b5SJean-Christophe DUBOIS 19967110c3eSJean-Christophe DUBOIS imx_gpt_compute_next_timeout(s, event); 2005ec694b5SJean-Christophe DUBOIS 20167110c3eSJean-Christophe DUBOIS imx_gpt_update_int(s); 2025ec694b5SJean-Christophe DUBOIS } else { 2035ec694b5SJean-Christophe DUBOIS /* New timeout value */ 2045ec694b5SJean-Christophe DUBOIS s->next_timeout = timeout; 2055ec694b5SJean-Christophe DUBOIS 2065ec694b5SJean-Christophe DUBOIS /* reset the limit to the computed range */ 2075ec694b5SJean-Christophe DUBOIS ptimer_set_limit(s->timer, limit, 1); 2085ec694b5SJean-Christophe DUBOIS } 209a50c0d6fSJean-Christophe DUBOIS } 210a50c0d6fSJean-Christophe DUBOIS 21167110c3eSJean-Christophe DUBOIS static uint64_t imx_gpt_read(void *opaque, hwaddr offset, unsigned size) 212a50c0d6fSJean-Christophe DUBOIS { 21367110c3eSJean-Christophe DUBOIS IMXGPTState *s = IMX_GPT(opaque); 2145ec694b5SJean-Christophe DUBOIS uint32_t reg_value = 0; 215a50c0d6fSJean-Christophe DUBOIS 21605453526SJean-Christophe Dubois switch (offset >> 2) { 217a50c0d6fSJean-Christophe DUBOIS case 0: /* Control Register */ 2185ec694b5SJean-Christophe DUBOIS reg_value = s->cr; 2195ec694b5SJean-Christophe DUBOIS break; 220a50c0d6fSJean-Christophe DUBOIS 221a50c0d6fSJean-Christophe DUBOIS case 1: /* prescaler */ 2225ec694b5SJean-Christophe DUBOIS reg_value = s->pr; 2235ec694b5SJean-Christophe DUBOIS break; 224a50c0d6fSJean-Christophe DUBOIS 225a50c0d6fSJean-Christophe DUBOIS case 2: /* Status Register */ 2265ec694b5SJean-Christophe DUBOIS reg_value = s->sr; 2275ec694b5SJean-Christophe DUBOIS break; 228a50c0d6fSJean-Christophe DUBOIS 229a50c0d6fSJean-Christophe DUBOIS case 3: /* Interrupt Register */ 2305ec694b5SJean-Christophe DUBOIS reg_value = s->ir; 2315ec694b5SJean-Christophe DUBOIS break; 232a50c0d6fSJean-Christophe DUBOIS 233a50c0d6fSJean-Christophe DUBOIS case 4: /* Output Compare Register 1 */ 2345ec694b5SJean-Christophe DUBOIS reg_value = s->ocr1; 2355ec694b5SJean-Christophe DUBOIS break; 236a50c0d6fSJean-Christophe DUBOIS 237a50c0d6fSJean-Christophe DUBOIS case 5: /* Output Compare Register 2 */ 2385ec694b5SJean-Christophe DUBOIS reg_value = s->ocr2; 2395ec694b5SJean-Christophe DUBOIS break; 240a50c0d6fSJean-Christophe DUBOIS 241a50c0d6fSJean-Christophe DUBOIS case 6: /* Output Compare Register 3 */ 2425ec694b5SJean-Christophe DUBOIS reg_value = s->ocr3; 2435ec694b5SJean-Christophe DUBOIS break; 244a50c0d6fSJean-Christophe DUBOIS 245a50c0d6fSJean-Christophe DUBOIS case 7: /* input Capture Register 1 */ 24605453526SJean-Christophe Dubois qemu_log_mask(LOG_UNIMP, "[%s]%s: icr1 feature is not implemented\n", 24705453526SJean-Christophe Dubois TYPE_IMX_GPT, __func__); 2485ec694b5SJean-Christophe DUBOIS reg_value = s->icr1; 2495ec694b5SJean-Christophe DUBOIS break; 250a50c0d6fSJean-Christophe DUBOIS 251a50c0d6fSJean-Christophe DUBOIS case 8: /* input Capture Register 2 */ 25205453526SJean-Christophe Dubois qemu_log_mask(LOG_UNIMP, "[%s]%s: icr2 feature is not implemented\n", 25305453526SJean-Christophe Dubois TYPE_IMX_GPT, __func__); 2545ec694b5SJean-Christophe DUBOIS reg_value = s->icr2; 2555ec694b5SJean-Christophe DUBOIS break; 256a50c0d6fSJean-Christophe DUBOIS 257a50c0d6fSJean-Christophe DUBOIS case 9: /* cnt */ 25867110c3eSJean-Christophe DUBOIS imx_gpt_update_count(s); 2595ec694b5SJean-Christophe DUBOIS reg_value = s->cnt; 2605ec694b5SJean-Christophe DUBOIS break; 2615ec694b5SJean-Christophe DUBOIS 2625ec694b5SJean-Christophe DUBOIS default: 26305453526SJean-Christophe Dubois qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%" 26405453526SJean-Christophe Dubois HWADDR_PRIx "\n", TYPE_IMX_GPT, __func__, offset); 2655ec694b5SJean-Christophe DUBOIS break; 266a50c0d6fSJean-Christophe DUBOIS } 267a50c0d6fSJean-Christophe DUBOIS 26805453526SJean-Christophe Dubois DPRINTF("(%s) = 0x%08x\n", imx_gpt_reg_name(offset >> 2), reg_value); 269a50c0d6fSJean-Christophe DUBOIS 2705ec694b5SJean-Christophe DUBOIS return reg_value; 271a50c0d6fSJean-Christophe DUBOIS } 272a50c0d6fSJean-Christophe DUBOIS 27367110c3eSJean-Christophe DUBOIS static void imx_gpt_reset(DeviceState *dev) 274a50c0d6fSJean-Christophe DUBOIS { 27567110c3eSJean-Christophe DUBOIS IMXGPTState *s = IMX_GPT(dev); 276a50c0d6fSJean-Christophe DUBOIS 2775ec694b5SJean-Christophe DUBOIS /* stop timer */ 2785ec694b5SJean-Christophe DUBOIS ptimer_stop(s->timer); 2795ec694b5SJean-Christophe DUBOIS 280a50c0d6fSJean-Christophe DUBOIS /* 281a50c0d6fSJean-Christophe DUBOIS * Soft reset doesn't touch some bits; hard reset clears them 282a50c0d6fSJean-Christophe DUBOIS */ 283a50c0d6fSJean-Christophe DUBOIS s->cr &= ~(GPT_CR_EN|GPT_CR_ENMOD|GPT_CR_STOPEN|GPT_CR_DOZEN| 284a50c0d6fSJean-Christophe DUBOIS GPT_CR_WAITEN|GPT_CR_DBGEN); 285a50c0d6fSJean-Christophe DUBOIS s->sr = 0; 286a50c0d6fSJean-Christophe DUBOIS s->pr = 0; 287a50c0d6fSJean-Christophe DUBOIS s->ir = 0; 288a50c0d6fSJean-Christophe DUBOIS s->cnt = 0; 289203d65a4SMichael Tokarev s->ocr1 = GPT_TIMER_MAX; 290203d65a4SMichael Tokarev s->ocr2 = GPT_TIMER_MAX; 291203d65a4SMichael Tokarev s->ocr3 = GPT_TIMER_MAX; 292a50c0d6fSJean-Christophe DUBOIS s->icr1 = 0; 293a50c0d6fSJean-Christophe DUBOIS s->icr2 = 0; 2945ec694b5SJean-Christophe DUBOIS 295203d65a4SMichael Tokarev s->next_timeout = GPT_TIMER_MAX; 2965ec694b5SJean-Christophe DUBOIS s->next_int = 0; 2975ec694b5SJean-Christophe DUBOIS 2985ec694b5SJean-Christophe DUBOIS /* compute new freq */ 29967110c3eSJean-Christophe DUBOIS imx_gpt_set_freq(s); 3005ec694b5SJean-Christophe DUBOIS 301203d65a4SMichael Tokarev /* reset the limit to GPT_TIMER_MAX */ 302203d65a4SMichael Tokarev ptimer_set_limit(s->timer, GPT_TIMER_MAX, 1); 3035ec694b5SJean-Christophe DUBOIS 3045ec694b5SJean-Christophe DUBOIS /* if the timer is still enabled, restart it */ 3055ec694b5SJean-Christophe DUBOIS if (s->freq && (s->cr & GPT_CR_EN)) { 3065ec694b5SJean-Christophe DUBOIS ptimer_run(s->timer, 1); 3075ec694b5SJean-Christophe DUBOIS } 308a50c0d6fSJean-Christophe DUBOIS } 309a50c0d6fSJean-Christophe DUBOIS 31067110c3eSJean-Christophe DUBOIS static void imx_gpt_write(void *opaque, hwaddr offset, uint64_t value, 31167110c3eSJean-Christophe DUBOIS unsigned size) 312a50c0d6fSJean-Christophe DUBOIS { 31367110c3eSJean-Christophe DUBOIS IMXGPTState *s = IMX_GPT(opaque); 3145ec694b5SJean-Christophe DUBOIS uint32_t oldreg; 315a50c0d6fSJean-Christophe DUBOIS 31605453526SJean-Christophe Dubois DPRINTF("(%s, value = 0x%08x)\n", imx_gpt_reg_name(offset >> 2), 3175ec694b5SJean-Christophe DUBOIS (uint32_t)value); 318a50c0d6fSJean-Christophe DUBOIS 31905453526SJean-Christophe Dubois switch (offset >> 2) { 3205ec694b5SJean-Christophe DUBOIS case 0: 3215ec694b5SJean-Christophe DUBOIS oldreg = s->cr; 3225ec694b5SJean-Christophe DUBOIS s->cr = value & ~0x7c14; 3235ec694b5SJean-Christophe DUBOIS if (s->cr & GPT_CR_SWR) { /* force reset */ 3245ec694b5SJean-Christophe DUBOIS /* handle the reset */ 32567110c3eSJean-Christophe DUBOIS imx_gpt_reset(DEVICE(s)); 326a50c0d6fSJean-Christophe DUBOIS } else { 3275ec694b5SJean-Christophe DUBOIS /* set our freq, as the source might have changed */ 32867110c3eSJean-Christophe DUBOIS imx_gpt_set_freq(s); 3295ec694b5SJean-Christophe DUBOIS 3305ec694b5SJean-Christophe DUBOIS if ((oldreg ^ s->cr) & GPT_CR_EN) { 3315ec694b5SJean-Christophe DUBOIS if (s->cr & GPT_CR_EN) { 3325ec694b5SJean-Christophe DUBOIS if (s->cr & GPT_CR_ENMOD) { 333203d65a4SMichael Tokarev s->next_timeout = GPT_TIMER_MAX; 334203d65a4SMichael Tokarev ptimer_set_count(s->timer, GPT_TIMER_MAX); 33567110c3eSJean-Christophe DUBOIS imx_gpt_compute_next_timeout(s, false); 3365ec694b5SJean-Christophe DUBOIS } 3375ec694b5SJean-Christophe DUBOIS ptimer_run(s->timer, 1); 3385ec694b5SJean-Christophe DUBOIS } else { 3395ec694b5SJean-Christophe DUBOIS /* stop timer */ 340a50c0d6fSJean-Christophe DUBOIS ptimer_stop(s->timer); 341a50c0d6fSJean-Christophe DUBOIS } 342a50c0d6fSJean-Christophe DUBOIS } 3435ec694b5SJean-Christophe DUBOIS } 3445ec694b5SJean-Christophe DUBOIS break; 345a50c0d6fSJean-Christophe DUBOIS 346a50c0d6fSJean-Christophe DUBOIS case 1: /* Prescaler */ 347a50c0d6fSJean-Christophe DUBOIS s->pr = value & 0xfff; 34867110c3eSJean-Christophe DUBOIS imx_gpt_set_freq(s); 3495ec694b5SJean-Christophe DUBOIS break; 350a50c0d6fSJean-Christophe DUBOIS 351a50c0d6fSJean-Christophe DUBOIS case 2: /* SR */ 3525ec694b5SJean-Christophe DUBOIS s->sr &= ~(value & 0x3f); 35367110c3eSJean-Christophe DUBOIS imx_gpt_update_int(s); 3545ec694b5SJean-Christophe DUBOIS break; 355a50c0d6fSJean-Christophe DUBOIS 356a50c0d6fSJean-Christophe DUBOIS case 3: /* IR -- interrupt register */ 357a50c0d6fSJean-Christophe DUBOIS s->ir = value & 0x3f; 35867110c3eSJean-Christophe DUBOIS imx_gpt_update_int(s); 3595ec694b5SJean-Christophe DUBOIS 36067110c3eSJean-Christophe DUBOIS imx_gpt_compute_next_timeout(s, false); 3615ec694b5SJean-Christophe DUBOIS 3625ec694b5SJean-Christophe DUBOIS break; 363a50c0d6fSJean-Christophe DUBOIS 364a50c0d6fSJean-Christophe DUBOIS case 4: /* OCR1 -- output compare register */ 3655ec694b5SJean-Christophe DUBOIS s->ocr1 = value; 3665ec694b5SJean-Christophe DUBOIS 367a50c0d6fSJean-Christophe DUBOIS /* In non-freerun mode, reset count when this register is written */ 368a50c0d6fSJean-Christophe DUBOIS if (!(s->cr & GPT_CR_FRR)) { 369203d65a4SMichael Tokarev s->next_timeout = GPT_TIMER_MAX; 370203d65a4SMichael Tokarev ptimer_set_limit(s->timer, GPT_TIMER_MAX, 1); 371a50c0d6fSJean-Christophe DUBOIS } 3725ec694b5SJean-Christophe DUBOIS 3735ec694b5SJean-Christophe DUBOIS /* compute the new timeout */ 37467110c3eSJean-Christophe DUBOIS imx_gpt_compute_next_timeout(s, false); 3755ec694b5SJean-Christophe DUBOIS 3765ec694b5SJean-Christophe DUBOIS break; 377a50c0d6fSJean-Christophe DUBOIS 378a50c0d6fSJean-Christophe DUBOIS case 5: /* OCR2 -- output compare register */ 3795ec694b5SJean-Christophe DUBOIS s->ocr2 = value; 3805ec694b5SJean-Christophe DUBOIS 3815ec694b5SJean-Christophe DUBOIS /* compute the new timeout */ 38267110c3eSJean-Christophe DUBOIS imx_gpt_compute_next_timeout(s, false); 3835ec694b5SJean-Christophe DUBOIS 3845ec694b5SJean-Christophe DUBOIS break; 3855ec694b5SJean-Christophe DUBOIS 386a50c0d6fSJean-Christophe DUBOIS case 6: /* OCR3 -- output compare register */ 3875ec694b5SJean-Christophe DUBOIS s->ocr3 = value; 3885ec694b5SJean-Christophe DUBOIS 3895ec694b5SJean-Christophe DUBOIS /* compute the new timeout */ 39067110c3eSJean-Christophe DUBOIS imx_gpt_compute_next_timeout(s, false); 3915ec694b5SJean-Christophe DUBOIS 3925ec694b5SJean-Christophe DUBOIS break; 3935ec694b5SJean-Christophe DUBOIS 394a50c0d6fSJean-Christophe DUBOIS default: 39505453526SJean-Christophe Dubois qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%" 39605453526SJean-Christophe Dubois HWADDR_PRIx "\n", TYPE_IMX_GPT, __func__, offset); 3975ec694b5SJean-Christophe DUBOIS break; 398a50c0d6fSJean-Christophe DUBOIS } 399a50c0d6fSJean-Christophe DUBOIS } 400a50c0d6fSJean-Christophe DUBOIS 40167110c3eSJean-Christophe DUBOIS static void imx_gpt_timeout(void *opaque) 402a50c0d6fSJean-Christophe DUBOIS { 40367110c3eSJean-Christophe DUBOIS IMXGPTState *s = IMX_GPT(opaque); 404a50c0d6fSJean-Christophe DUBOIS 4055ec694b5SJean-Christophe DUBOIS DPRINTF("\n"); 406a50c0d6fSJean-Christophe DUBOIS 4075ec694b5SJean-Christophe DUBOIS s->sr |= s->next_int; 4085ec694b5SJean-Christophe DUBOIS s->next_int = 0; 409a50c0d6fSJean-Christophe DUBOIS 41067110c3eSJean-Christophe DUBOIS imx_gpt_compute_next_timeout(s, true); 4115ec694b5SJean-Christophe DUBOIS 41267110c3eSJean-Christophe DUBOIS imx_gpt_update_int(s); 4135ec694b5SJean-Christophe DUBOIS 4145ec694b5SJean-Christophe DUBOIS if (s->freq && (s->cr & GPT_CR_EN)) { 4155ec694b5SJean-Christophe DUBOIS ptimer_run(s->timer, 1); 4165ec694b5SJean-Christophe DUBOIS } 417a50c0d6fSJean-Christophe DUBOIS } 418a50c0d6fSJean-Christophe DUBOIS 41967110c3eSJean-Christophe DUBOIS static const MemoryRegionOps imx_gpt_ops = { 42067110c3eSJean-Christophe DUBOIS .read = imx_gpt_read, 42167110c3eSJean-Christophe DUBOIS .write = imx_gpt_write, 422a50c0d6fSJean-Christophe DUBOIS .endianness = DEVICE_NATIVE_ENDIAN, 423a50c0d6fSJean-Christophe DUBOIS }; 424a50c0d6fSJean-Christophe DUBOIS 425a50c0d6fSJean-Christophe DUBOIS 42667110c3eSJean-Christophe DUBOIS static void imx_gpt_realize(DeviceState *dev, Error **errp) 427a50c0d6fSJean-Christophe DUBOIS { 42867110c3eSJean-Christophe DUBOIS IMXGPTState *s = IMX_GPT(dev); 42967110c3eSJean-Christophe DUBOIS SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 430a50c0d6fSJean-Christophe DUBOIS QEMUBH *bh; 431a50c0d6fSJean-Christophe DUBOIS 43267110c3eSJean-Christophe DUBOIS sysbus_init_irq(sbd, &s->irq); 433853dca12SPaolo Bonzini memory_region_init_io(&s->iomem, OBJECT(s), &imx_gpt_ops, s, TYPE_IMX_GPT, 434a50c0d6fSJean-Christophe DUBOIS 0x00001000); 43567110c3eSJean-Christophe DUBOIS sysbus_init_mmio(sbd, &s->iomem); 436a50c0d6fSJean-Christophe DUBOIS 43767110c3eSJean-Christophe DUBOIS bh = qemu_bh_new(imx_gpt_timeout, s); 438a50c0d6fSJean-Christophe DUBOIS s->timer = ptimer_init(bh); 439a50c0d6fSJean-Christophe DUBOIS } 440a50c0d6fSJean-Christophe DUBOIS 44167110c3eSJean-Christophe DUBOIS static void imx_gpt_class_init(ObjectClass *klass, void *data) 442a50c0d6fSJean-Christophe DUBOIS { 443a50c0d6fSJean-Christophe DUBOIS DeviceClass *dc = DEVICE_CLASS(klass); 44467110c3eSJean-Christophe DUBOIS 44567110c3eSJean-Christophe DUBOIS dc->realize = imx_gpt_realize; 44667110c3eSJean-Christophe DUBOIS dc->reset = imx_gpt_reset; 44767110c3eSJean-Christophe DUBOIS dc->vmsd = &vmstate_imx_timer_gpt; 448a50c0d6fSJean-Christophe DUBOIS dc->desc = "i.MX general timer"; 449a50c0d6fSJean-Christophe DUBOIS } 450a50c0d6fSJean-Christophe DUBOIS 45167110c3eSJean-Christophe DUBOIS static const TypeInfo imx_gpt_info = { 4525ec694b5SJean-Christophe DUBOIS .name = TYPE_IMX_GPT, 453a50c0d6fSJean-Christophe DUBOIS .parent = TYPE_SYS_BUS_DEVICE, 45467110c3eSJean-Christophe DUBOIS .instance_size = sizeof(IMXGPTState), 45567110c3eSJean-Christophe DUBOIS .class_init = imx_gpt_class_init, 456a50c0d6fSJean-Christophe DUBOIS }; 457a50c0d6fSJean-Christophe DUBOIS 45867110c3eSJean-Christophe DUBOIS static void imx_gpt_register_types(void) 459a50c0d6fSJean-Christophe DUBOIS { 46067110c3eSJean-Christophe DUBOIS type_register_static(&imx_gpt_info); 461a50c0d6fSJean-Christophe DUBOIS } 462a50c0d6fSJean-Christophe DUBOIS 46367110c3eSJean-Christophe DUBOIS type_init(imx_gpt_register_types) 464