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 158ef94f0bSPeter Maydell #include "qemu/osdep.h" 16d647b26dSJean-Christophe Dubois #include "hw/timer/imx_gpt.h" 176a1751b7SAlex Bligh #include "qemu/main-loop.h" 1803dd024fSPaolo Bonzini #include "qemu/log.h" 19a50c0d6fSJean-Christophe DUBOIS 2005453526SJean-Christophe Dubois #ifndef DEBUG_IMX_GPT 2105453526SJean-Christophe Dubois #define DEBUG_IMX_GPT 0 2205453526SJean-Christophe Dubois #endif 2305453526SJean-Christophe Dubois 2405453526SJean-Christophe Dubois #define DPRINTF(fmt, args...) \ 2505453526SJean-Christophe Dubois do { \ 2605453526SJean-Christophe Dubois if (DEBUG_IMX_GPT) { \ 2705453526SJean-Christophe Dubois fprintf(stderr, "[%s]%s: " fmt , TYPE_IMX_GPT, \ 2805453526SJean-Christophe Dubois __func__, ##args); \ 2905453526SJean-Christophe Dubois } \ 3005453526SJean-Christophe Dubois } while (0) 315ec694b5SJean-Christophe DUBOIS 3267110c3eSJean-Christophe DUBOIS static char const *imx_gpt_reg_name(uint32_t reg) 335ec694b5SJean-Christophe DUBOIS { 345ec694b5SJean-Christophe DUBOIS switch (reg) { 355ec694b5SJean-Christophe DUBOIS case 0: 365ec694b5SJean-Christophe DUBOIS return "CR"; 375ec694b5SJean-Christophe DUBOIS case 1: 385ec694b5SJean-Christophe DUBOIS return "PR"; 395ec694b5SJean-Christophe DUBOIS case 2: 405ec694b5SJean-Christophe DUBOIS return "SR"; 415ec694b5SJean-Christophe DUBOIS case 3: 425ec694b5SJean-Christophe DUBOIS return "IR"; 435ec694b5SJean-Christophe DUBOIS case 4: 445ec694b5SJean-Christophe DUBOIS return "OCR1"; 455ec694b5SJean-Christophe DUBOIS case 5: 465ec694b5SJean-Christophe DUBOIS return "OCR2"; 475ec694b5SJean-Christophe DUBOIS case 6: 485ec694b5SJean-Christophe DUBOIS return "OCR3"; 495ec694b5SJean-Christophe DUBOIS case 7: 505ec694b5SJean-Christophe DUBOIS return "ICR1"; 515ec694b5SJean-Christophe DUBOIS case 8: 525ec694b5SJean-Christophe DUBOIS return "ICR2"; 535ec694b5SJean-Christophe DUBOIS case 9: 545ec694b5SJean-Christophe DUBOIS return "CNT"; 555ec694b5SJean-Christophe DUBOIS default: 565ec694b5SJean-Christophe DUBOIS return "[?]"; 575ec694b5SJean-Christophe DUBOIS } 585ec694b5SJean-Christophe DUBOIS } 595ec694b5SJean-Christophe DUBOIS 6067110c3eSJean-Christophe DUBOIS static const VMStateDescription vmstate_imx_timer_gpt = { 6168b85290SJean-Christophe Dubois .name = TYPE_IMX_GPT, 625ec694b5SJean-Christophe DUBOIS .version_id = 3, 635ec694b5SJean-Christophe DUBOIS .minimum_version_id = 3, 64a50c0d6fSJean-Christophe DUBOIS .fields = (VMStateField[]) { 6567110c3eSJean-Christophe DUBOIS VMSTATE_UINT32(cr, IMXGPTState), 6667110c3eSJean-Christophe DUBOIS VMSTATE_UINT32(pr, IMXGPTState), 6767110c3eSJean-Christophe DUBOIS VMSTATE_UINT32(sr, IMXGPTState), 6867110c3eSJean-Christophe DUBOIS VMSTATE_UINT32(ir, IMXGPTState), 6967110c3eSJean-Christophe DUBOIS VMSTATE_UINT32(ocr1, IMXGPTState), 7067110c3eSJean-Christophe DUBOIS VMSTATE_UINT32(ocr2, IMXGPTState), 7167110c3eSJean-Christophe DUBOIS VMSTATE_UINT32(ocr3, IMXGPTState), 7267110c3eSJean-Christophe DUBOIS VMSTATE_UINT32(icr1, IMXGPTState), 7367110c3eSJean-Christophe DUBOIS VMSTATE_UINT32(icr2, IMXGPTState), 7467110c3eSJean-Christophe DUBOIS VMSTATE_UINT32(cnt, IMXGPTState), 7567110c3eSJean-Christophe DUBOIS VMSTATE_UINT32(next_timeout, IMXGPTState), 7667110c3eSJean-Christophe DUBOIS VMSTATE_UINT32(next_int, IMXGPTState), 7767110c3eSJean-Christophe DUBOIS VMSTATE_UINT32(freq, IMXGPTState), 7867110c3eSJean-Christophe DUBOIS VMSTATE_PTIMER(timer, IMXGPTState), 79a50c0d6fSJean-Christophe DUBOIS VMSTATE_END_OF_LIST() 80a50c0d6fSJean-Christophe DUBOIS } 81a50c0d6fSJean-Christophe DUBOIS }; 82a50c0d6fSJean-Christophe DUBOIS 8366542f63SJean-Christophe Dubois static const IMXClk imx25_gpt_clocks[] = { 8466542f63SJean-Christophe Dubois CLK_NONE, /* 000 No clock source */ 8566542f63SJean-Christophe Dubois CLK_IPG, /* 001 ipg_clk, 532MHz*/ 8666542f63SJean-Christophe Dubois CLK_IPG_HIGH, /* 010 ipg_clk_highfreq */ 8766542f63SJean-Christophe Dubois CLK_NONE, /* 011 not defined */ 8866542f63SJean-Christophe Dubois CLK_32k, /* 100 ipg_clk_32k */ 8966542f63SJean-Christophe Dubois CLK_32k, /* 101 ipg_clk_32k */ 9066542f63SJean-Christophe Dubois CLK_32k, /* 110 ipg_clk_32k */ 9166542f63SJean-Christophe Dubois CLK_32k, /* 111 ipg_clk_32k */ 9266542f63SJean-Christophe Dubois }; 9366542f63SJean-Christophe Dubois 9466542f63SJean-Christophe Dubois static const IMXClk imx31_gpt_clocks[] = { 95c91a5883SJean-Christophe Dubois CLK_NONE, /* 000 No clock source */ 96aaa9ec3bSJean-Christophe Dubois CLK_IPG, /* 001 ipg_clk, 532MHz*/ 97d552f675SJean-Christophe Dubois CLK_IPG_HIGH, /* 010 ipg_clk_highfreq */ 98c91a5883SJean-Christophe Dubois CLK_NONE, /* 011 not defined */ 99a50c0d6fSJean-Christophe DUBOIS CLK_32k, /* 100 ipg_clk_32k */ 100c91a5883SJean-Christophe Dubois CLK_NONE, /* 101 not defined */ 101c91a5883SJean-Christophe Dubois CLK_NONE, /* 110 not defined */ 102c91a5883SJean-Christophe Dubois CLK_NONE, /* 111 not defined */ 103a50c0d6fSJean-Christophe DUBOIS }; 104a50c0d6fSJean-Christophe DUBOIS 10566542f63SJean-Christophe Dubois static const IMXClk imx6_gpt_clocks[] = { 10666542f63SJean-Christophe Dubois CLK_NONE, /* 000 No clock source */ 10766542f63SJean-Christophe Dubois CLK_IPG, /* 001 ipg_clk, 532MHz*/ 10866542f63SJean-Christophe Dubois CLK_IPG_HIGH, /* 010 ipg_clk_highfreq */ 10966542f63SJean-Christophe Dubois CLK_EXT, /* 011 External clock */ 11066542f63SJean-Christophe Dubois CLK_32k, /* 100 ipg_clk_32k */ 11166542f63SJean-Christophe Dubois CLK_HIGH_DIV, /* 101 reference clock / 8 */ 11266542f63SJean-Christophe Dubois CLK_NONE, /* 110 not defined */ 11366542f63SJean-Christophe Dubois CLK_HIGH, /* 111 reference clock */ 11466542f63SJean-Christophe Dubois }; 11566542f63SJean-Christophe Dubois 11667110c3eSJean-Christophe DUBOIS static void imx_gpt_set_freq(IMXGPTState *s) 117a50c0d6fSJean-Christophe DUBOIS { 1185ec694b5SJean-Christophe DUBOIS uint32_t clksrc = extract32(s->cr, GPT_CR_CLKSRC_SHIFT, 3); 119a50c0d6fSJean-Christophe DUBOIS 120aaa9ec3bSJean-Christophe Dubois s->freq = imx_ccm_get_clock_frequency(s->ccm, 12166542f63SJean-Christophe Dubois s->clocks[clksrc]) / (1 + s->pr); 122a50c0d6fSJean-Christophe DUBOIS 123aaa9ec3bSJean-Christophe Dubois DPRINTF("Setting clksrc %d to frequency %d\n", clksrc, s->freq); 124aaa9ec3bSJean-Christophe Dubois 125aaa9ec3bSJean-Christophe Dubois if (s->freq) { 126aaa9ec3bSJean-Christophe Dubois ptimer_set_freq(s->timer, s->freq); 127a50c0d6fSJean-Christophe DUBOIS } 128a50c0d6fSJean-Christophe DUBOIS } 129a50c0d6fSJean-Christophe DUBOIS 13067110c3eSJean-Christophe DUBOIS static void imx_gpt_update_int(IMXGPTState *s) 131a50c0d6fSJean-Christophe DUBOIS { 1325ec694b5SJean-Christophe DUBOIS if ((s->sr & s->ir) && (s->cr & GPT_CR_EN)) { 1335ec694b5SJean-Christophe DUBOIS qemu_irq_raise(s->irq); 1345ec694b5SJean-Christophe DUBOIS } else { 1355ec694b5SJean-Christophe DUBOIS qemu_irq_lower(s->irq); 1365ec694b5SJean-Christophe DUBOIS } 137a50c0d6fSJean-Christophe DUBOIS } 138a50c0d6fSJean-Christophe DUBOIS 13967110c3eSJean-Christophe DUBOIS static uint32_t imx_gpt_update_count(IMXGPTState *s) 140a50c0d6fSJean-Christophe DUBOIS { 1415ec694b5SJean-Christophe DUBOIS s->cnt = s->next_timeout - (uint32_t)ptimer_get_count(s->timer); 1425ec694b5SJean-Christophe DUBOIS 143a50c0d6fSJean-Christophe DUBOIS return s->cnt; 144a50c0d6fSJean-Christophe DUBOIS } 145a50c0d6fSJean-Christophe DUBOIS 14667110c3eSJean-Christophe DUBOIS static inline uint32_t imx_gpt_find_limit(uint32_t count, uint32_t reg, 1475ec694b5SJean-Christophe DUBOIS uint32_t timeout) 148a50c0d6fSJean-Christophe DUBOIS { 1495ec694b5SJean-Christophe DUBOIS if ((count < reg) && (timeout > reg)) { 1505ec694b5SJean-Christophe DUBOIS timeout = reg; 1515ec694b5SJean-Christophe DUBOIS } 152a50c0d6fSJean-Christophe DUBOIS 1535ec694b5SJean-Christophe DUBOIS return timeout; 1545ec694b5SJean-Christophe DUBOIS } 1555ec694b5SJean-Christophe DUBOIS 15667110c3eSJean-Christophe DUBOIS static void imx_gpt_compute_next_timeout(IMXGPTState *s, bool event) 1575ec694b5SJean-Christophe DUBOIS { 158203d65a4SMichael Tokarev uint32_t timeout = GPT_TIMER_MAX; 1594833e15fSJean-Christophe Dubois uint32_t count; 1605ec694b5SJean-Christophe DUBOIS long long limit; 1615ec694b5SJean-Christophe DUBOIS 1625ec694b5SJean-Christophe DUBOIS if (!(s->cr & GPT_CR_EN)) { 1635ec694b5SJean-Christophe DUBOIS /* if not enabled just return */ 164a50c0d6fSJean-Christophe DUBOIS return; 165a50c0d6fSJean-Christophe DUBOIS } 166a50c0d6fSJean-Christophe DUBOIS 1674833e15fSJean-Christophe Dubois /* update the count */ 1684833e15fSJean-Christophe Dubois count = imx_gpt_update_count(s); 1694833e15fSJean-Christophe Dubois 1705ec694b5SJean-Christophe DUBOIS if (event) { 171a50c0d6fSJean-Christophe DUBOIS /* 1724833e15fSJean-Christophe Dubois * This is an event (the ptimer reached 0 and stopped), and the 1734833e15fSJean-Christophe Dubois * timer counter is now equal to s->next_timeout. 174a50c0d6fSJean-Christophe DUBOIS */ 1754833e15fSJean-Christophe Dubois if (!(s->cr & GPT_CR_FRR) && (count == s->ocr1)) { 1764833e15fSJean-Christophe Dubois /* We are in restart mode and we crossed the compare channel 1 1774833e15fSJean-Christophe Dubois * value. We need to reset the counter to 0. 1784833e15fSJean-Christophe Dubois */ 1794833e15fSJean-Christophe Dubois count = s->cnt = s->next_timeout = 0; 1804833e15fSJean-Christophe Dubois } else if (count == GPT_TIMER_MAX) { 1814833e15fSJean-Christophe Dubois /* We reached GPT_TIMER_MAX so we need to rollover */ 1824833e15fSJean-Christophe Dubois count = s->cnt = s->next_timeout = 0; 183a50c0d6fSJean-Christophe DUBOIS } 1845ec694b5SJean-Christophe DUBOIS } 1855ec694b5SJean-Christophe DUBOIS 1865ec694b5SJean-Christophe DUBOIS /* now, find the next timeout related to count */ 1875ec694b5SJean-Christophe DUBOIS 1885ec694b5SJean-Christophe DUBOIS if (s->ir & GPT_IR_OF1IE) { 18967110c3eSJean-Christophe DUBOIS timeout = imx_gpt_find_limit(count, s->ocr1, timeout); 1905ec694b5SJean-Christophe DUBOIS } 1915ec694b5SJean-Christophe DUBOIS if (s->ir & GPT_IR_OF2IE) { 19267110c3eSJean-Christophe DUBOIS timeout = imx_gpt_find_limit(count, s->ocr2, timeout); 1935ec694b5SJean-Christophe DUBOIS } 1945ec694b5SJean-Christophe DUBOIS if (s->ir & GPT_IR_OF3IE) { 19567110c3eSJean-Christophe DUBOIS timeout = imx_gpt_find_limit(count, s->ocr3, timeout); 1965ec694b5SJean-Christophe DUBOIS } 1975ec694b5SJean-Christophe DUBOIS 1985ec694b5SJean-Christophe DUBOIS /* find the next set of interrupts to raise for next timer event */ 1995ec694b5SJean-Christophe DUBOIS 2005ec694b5SJean-Christophe DUBOIS s->next_int = 0; 2015ec694b5SJean-Christophe DUBOIS if ((s->ir & GPT_IR_OF1IE) && (timeout == s->ocr1)) { 2025ec694b5SJean-Christophe DUBOIS s->next_int |= GPT_SR_OF1; 2035ec694b5SJean-Christophe DUBOIS } 2045ec694b5SJean-Christophe DUBOIS if ((s->ir & GPT_IR_OF2IE) && (timeout == s->ocr2)) { 2055ec694b5SJean-Christophe DUBOIS s->next_int |= GPT_SR_OF2; 2065ec694b5SJean-Christophe DUBOIS } 2075ec694b5SJean-Christophe DUBOIS if ((s->ir & GPT_IR_OF3IE) && (timeout == s->ocr3)) { 2085ec694b5SJean-Christophe DUBOIS s->next_int |= GPT_SR_OF3; 2095ec694b5SJean-Christophe DUBOIS } 210203d65a4SMichael Tokarev if ((s->ir & GPT_IR_ROVIE) && (timeout == GPT_TIMER_MAX)) { 2115ec694b5SJean-Christophe DUBOIS s->next_int |= GPT_SR_ROV; 2125ec694b5SJean-Christophe DUBOIS } 2135ec694b5SJean-Christophe DUBOIS 2145ec694b5SJean-Christophe DUBOIS /* the new range to count down from */ 21567110c3eSJean-Christophe DUBOIS limit = timeout - imx_gpt_update_count(s); 2165ec694b5SJean-Christophe DUBOIS 2175ec694b5SJean-Christophe DUBOIS if (limit < 0) { 2185ec694b5SJean-Christophe DUBOIS /* 2195ec694b5SJean-Christophe DUBOIS * if we reach here, then QEMU is running too slow and we pass the 2205ec694b5SJean-Christophe DUBOIS * timeout limit while computing it. Let's deliver the interrupt 2215ec694b5SJean-Christophe DUBOIS * and compute a new limit. 2225ec694b5SJean-Christophe DUBOIS */ 2235ec694b5SJean-Christophe DUBOIS s->sr |= s->next_int; 2245ec694b5SJean-Christophe DUBOIS 22567110c3eSJean-Christophe DUBOIS imx_gpt_compute_next_timeout(s, event); 2265ec694b5SJean-Christophe DUBOIS 22767110c3eSJean-Christophe DUBOIS imx_gpt_update_int(s); 2285ec694b5SJean-Christophe DUBOIS } else { 2295ec694b5SJean-Christophe DUBOIS /* New timeout value */ 2305ec694b5SJean-Christophe DUBOIS s->next_timeout = timeout; 2315ec694b5SJean-Christophe DUBOIS 2325ec694b5SJean-Christophe DUBOIS /* reset the limit to the computed range */ 2335ec694b5SJean-Christophe DUBOIS ptimer_set_limit(s->timer, limit, 1); 2345ec694b5SJean-Christophe DUBOIS } 235a50c0d6fSJean-Christophe DUBOIS } 236a50c0d6fSJean-Christophe DUBOIS 23767110c3eSJean-Christophe DUBOIS static uint64_t imx_gpt_read(void *opaque, hwaddr offset, unsigned size) 238a50c0d6fSJean-Christophe DUBOIS { 23967110c3eSJean-Christophe DUBOIS IMXGPTState *s = IMX_GPT(opaque); 2405ec694b5SJean-Christophe DUBOIS uint32_t reg_value = 0; 241a50c0d6fSJean-Christophe DUBOIS 24205453526SJean-Christophe Dubois switch (offset >> 2) { 243a50c0d6fSJean-Christophe DUBOIS case 0: /* Control Register */ 2445ec694b5SJean-Christophe DUBOIS reg_value = s->cr; 2455ec694b5SJean-Christophe DUBOIS break; 246a50c0d6fSJean-Christophe DUBOIS 247a50c0d6fSJean-Christophe DUBOIS case 1: /* prescaler */ 2485ec694b5SJean-Christophe DUBOIS reg_value = s->pr; 2495ec694b5SJean-Christophe DUBOIS break; 250a50c0d6fSJean-Christophe DUBOIS 251a50c0d6fSJean-Christophe DUBOIS case 2: /* Status Register */ 2525ec694b5SJean-Christophe DUBOIS reg_value = s->sr; 2535ec694b5SJean-Christophe DUBOIS break; 254a50c0d6fSJean-Christophe DUBOIS 255a50c0d6fSJean-Christophe DUBOIS case 3: /* Interrupt Register */ 2565ec694b5SJean-Christophe DUBOIS reg_value = s->ir; 2575ec694b5SJean-Christophe DUBOIS break; 258a50c0d6fSJean-Christophe DUBOIS 259a50c0d6fSJean-Christophe DUBOIS case 4: /* Output Compare Register 1 */ 2605ec694b5SJean-Christophe DUBOIS reg_value = s->ocr1; 2615ec694b5SJean-Christophe DUBOIS break; 262a50c0d6fSJean-Christophe DUBOIS 263a50c0d6fSJean-Christophe DUBOIS case 5: /* Output Compare Register 2 */ 2645ec694b5SJean-Christophe DUBOIS reg_value = s->ocr2; 2655ec694b5SJean-Christophe DUBOIS break; 266a50c0d6fSJean-Christophe DUBOIS 267a50c0d6fSJean-Christophe DUBOIS case 6: /* Output Compare Register 3 */ 2685ec694b5SJean-Christophe DUBOIS reg_value = s->ocr3; 2695ec694b5SJean-Christophe DUBOIS break; 270a50c0d6fSJean-Christophe DUBOIS 271a50c0d6fSJean-Christophe DUBOIS case 7: /* input Capture Register 1 */ 27205453526SJean-Christophe Dubois qemu_log_mask(LOG_UNIMP, "[%s]%s: icr1 feature is not implemented\n", 27305453526SJean-Christophe Dubois TYPE_IMX_GPT, __func__); 2745ec694b5SJean-Christophe DUBOIS reg_value = s->icr1; 2755ec694b5SJean-Christophe DUBOIS break; 276a50c0d6fSJean-Christophe DUBOIS 277a50c0d6fSJean-Christophe DUBOIS case 8: /* input Capture Register 2 */ 27805453526SJean-Christophe Dubois qemu_log_mask(LOG_UNIMP, "[%s]%s: icr2 feature is not implemented\n", 27905453526SJean-Christophe Dubois TYPE_IMX_GPT, __func__); 2805ec694b5SJean-Christophe DUBOIS reg_value = s->icr2; 2815ec694b5SJean-Christophe DUBOIS break; 282a50c0d6fSJean-Christophe DUBOIS 283a50c0d6fSJean-Christophe DUBOIS case 9: /* cnt */ 28467110c3eSJean-Christophe DUBOIS imx_gpt_update_count(s); 2855ec694b5SJean-Christophe DUBOIS reg_value = s->cnt; 2865ec694b5SJean-Christophe DUBOIS break; 2875ec694b5SJean-Christophe DUBOIS 2885ec694b5SJean-Christophe DUBOIS default: 28905453526SJean-Christophe Dubois qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%" 29005453526SJean-Christophe Dubois HWADDR_PRIx "\n", TYPE_IMX_GPT, __func__, offset); 2915ec694b5SJean-Christophe DUBOIS break; 292a50c0d6fSJean-Christophe DUBOIS } 293a50c0d6fSJean-Christophe DUBOIS 29405453526SJean-Christophe Dubois DPRINTF("(%s) = 0x%08x\n", imx_gpt_reg_name(offset >> 2), reg_value); 295a50c0d6fSJean-Christophe DUBOIS 2965ec694b5SJean-Christophe DUBOIS return reg_value; 297a50c0d6fSJean-Christophe DUBOIS } 298a50c0d6fSJean-Christophe DUBOIS 29967110c3eSJean-Christophe DUBOIS static void imx_gpt_reset(DeviceState *dev) 300a50c0d6fSJean-Christophe DUBOIS { 30167110c3eSJean-Christophe DUBOIS IMXGPTState *s = IMX_GPT(dev); 302a50c0d6fSJean-Christophe DUBOIS 3035ec694b5SJean-Christophe DUBOIS /* stop timer */ 3045ec694b5SJean-Christophe DUBOIS ptimer_stop(s->timer); 3055ec694b5SJean-Christophe DUBOIS 306a50c0d6fSJean-Christophe DUBOIS /* 307a50c0d6fSJean-Christophe DUBOIS * Soft reset doesn't touch some bits; hard reset clears them 308a50c0d6fSJean-Christophe DUBOIS */ 309a50c0d6fSJean-Christophe DUBOIS s->cr &= ~(GPT_CR_EN|GPT_CR_ENMOD|GPT_CR_STOPEN|GPT_CR_DOZEN| 310a50c0d6fSJean-Christophe DUBOIS GPT_CR_WAITEN|GPT_CR_DBGEN); 311a50c0d6fSJean-Christophe DUBOIS s->sr = 0; 312a50c0d6fSJean-Christophe DUBOIS s->pr = 0; 313a50c0d6fSJean-Christophe DUBOIS s->ir = 0; 314a50c0d6fSJean-Christophe DUBOIS s->cnt = 0; 315203d65a4SMichael Tokarev s->ocr1 = GPT_TIMER_MAX; 316203d65a4SMichael Tokarev s->ocr2 = GPT_TIMER_MAX; 317203d65a4SMichael Tokarev s->ocr3 = GPT_TIMER_MAX; 318a50c0d6fSJean-Christophe DUBOIS s->icr1 = 0; 319a50c0d6fSJean-Christophe DUBOIS s->icr2 = 0; 3205ec694b5SJean-Christophe DUBOIS 321203d65a4SMichael Tokarev s->next_timeout = GPT_TIMER_MAX; 3225ec694b5SJean-Christophe DUBOIS s->next_int = 0; 3235ec694b5SJean-Christophe DUBOIS 3245ec694b5SJean-Christophe DUBOIS /* compute new freq */ 32567110c3eSJean-Christophe DUBOIS imx_gpt_set_freq(s); 3265ec694b5SJean-Christophe DUBOIS 327203d65a4SMichael Tokarev /* reset the limit to GPT_TIMER_MAX */ 328203d65a4SMichael Tokarev ptimer_set_limit(s->timer, GPT_TIMER_MAX, 1); 3295ec694b5SJean-Christophe DUBOIS 3305ec694b5SJean-Christophe DUBOIS /* if the timer is still enabled, restart it */ 3315ec694b5SJean-Christophe DUBOIS if (s->freq && (s->cr & GPT_CR_EN)) { 3325ec694b5SJean-Christophe DUBOIS ptimer_run(s->timer, 1); 3335ec694b5SJean-Christophe DUBOIS } 334a50c0d6fSJean-Christophe DUBOIS } 335a50c0d6fSJean-Christophe DUBOIS 33667110c3eSJean-Christophe DUBOIS static void imx_gpt_write(void *opaque, hwaddr offset, uint64_t value, 33767110c3eSJean-Christophe DUBOIS unsigned size) 338a50c0d6fSJean-Christophe DUBOIS { 33967110c3eSJean-Christophe DUBOIS IMXGPTState *s = IMX_GPT(opaque); 3405ec694b5SJean-Christophe DUBOIS uint32_t oldreg; 341a50c0d6fSJean-Christophe DUBOIS 34205453526SJean-Christophe Dubois DPRINTF("(%s, value = 0x%08x)\n", imx_gpt_reg_name(offset >> 2), 3435ec694b5SJean-Christophe DUBOIS (uint32_t)value); 344a50c0d6fSJean-Christophe DUBOIS 34505453526SJean-Christophe Dubois switch (offset >> 2) { 3465ec694b5SJean-Christophe DUBOIS case 0: 3475ec694b5SJean-Christophe DUBOIS oldreg = s->cr; 3485ec694b5SJean-Christophe DUBOIS s->cr = value & ~0x7c14; 3495ec694b5SJean-Christophe DUBOIS if (s->cr & GPT_CR_SWR) { /* force reset */ 3505ec694b5SJean-Christophe DUBOIS /* handle the reset */ 35167110c3eSJean-Christophe DUBOIS imx_gpt_reset(DEVICE(s)); 352a50c0d6fSJean-Christophe DUBOIS } else { 3535ec694b5SJean-Christophe DUBOIS /* set our freq, as the source might have changed */ 35467110c3eSJean-Christophe DUBOIS imx_gpt_set_freq(s); 3555ec694b5SJean-Christophe DUBOIS 3565ec694b5SJean-Christophe DUBOIS if ((oldreg ^ s->cr) & GPT_CR_EN) { 3575ec694b5SJean-Christophe DUBOIS if (s->cr & GPT_CR_EN) { 3585ec694b5SJean-Christophe DUBOIS if (s->cr & GPT_CR_ENMOD) { 359203d65a4SMichael Tokarev s->next_timeout = GPT_TIMER_MAX; 360203d65a4SMichael Tokarev ptimer_set_count(s->timer, GPT_TIMER_MAX); 36167110c3eSJean-Christophe DUBOIS imx_gpt_compute_next_timeout(s, false); 3625ec694b5SJean-Christophe DUBOIS } 3635ec694b5SJean-Christophe DUBOIS ptimer_run(s->timer, 1); 3645ec694b5SJean-Christophe DUBOIS } else { 3655ec694b5SJean-Christophe DUBOIS /* stop timer */ 366a50c0d6fSJean-Christophe DUBOIS ptimer_stop(s->timer); 367a50c0d6fSJean-Christophe DUBOIS } 368a50c0d6fSJean-Christophe DUBOIS } 3695ec694b5SJean-Christophe DUBOIS } 3705ec694b5SJean-Christophe DUBOIS break; 371a50c0d6fSJean-Christophe DUBOIS 372a50c0d6fSJean-Christophe DUBOIS case 1: /* Prescaler */ 373a50c0d6fSJean-Christophe DUBOIS s->pr = value & 0xfff; 37467110c3eSJean-Christophe DUBOIS imx_gpt_set_freq(s); 3755ec694b5SJean-Christophe DUBOIS break; 376a50c0d6fSJean-Christophe DUBOIS 377a50c0d6fSJean-Christophe DUBOIS case 2: /* SR */ 3785ec694b5SJean-Christophe DUBOIS s->sr &= ~(value & 0x3f); 37967110c3eSJean-Christophe DUBOIS imx_gpt_update_int(s); 3805ec694b5SJean-Christophe DUBOIS break; 381a50c0d6fSJean-Christophe DUBOIS 382a50c0d6fSJean-Christophe DUBOIS case 3: /* IR -- interrupt register */ 383a50c0d6fSJean-Christophe DUBOIS s->ir = value & 0x3f; 38467110c3eSJean-Christophe DUBOIS imx_gpt_update_int(s); 3855ec694b5SJean-Christophe DUBOIS 38667110c3eSJean-Christophe DUBOIS imx_gpt_compute_next_timeout(s, false); 3875ec694b5SJean-Christophe DUBOIS 3885ec694b5SJean-Christophe DUBOIS break; 389a50c0d6fSJean-Christophe DUBOIS 390a50c0d6fSJean-Christophe DUBOIS case 4: /* OCR1 -- output compare register */ 3915ec694b5SJean-Christophe DUBOIS s->ocr1 = value; 3925ec694b5SJean-Christophe DUBOIS 393a50c0d6fSJean-Christophe DUBOIS /* In non-freerun mode, reset count when this register is written */ 394a50c0d6fSJean-Christophe DUBOIS if (!(s->cr & GPT_CR_FRR)) { 395203d65a4SMichael Tokarev s->next_timeout = GPT_TIMER_MAX; 396203d65a4SMichael Tokarev ptimer_set_limit(s->timer, GPT_TIMER_MAX, 1); 397a50c0d6fSJean-Christophe DUBOIS } 3985ec694b5SJean-Christophe DUBOIS 3995ec694b5SJean-Christophe DUBOIS /* compute the new timeout */ 40067110c3eSJean-Christophe DUBOIS imx_gpt_compute_next_timeout(s, false); 4015ec694b5SJean-Christophe DUBOIS 4025ec694b5SJean-Christophe DUBOIS break; 403a50c0d6fSJean-Christophe DUBOIS 404a50c0d6fSJean-Christophe DUBOIS case 5: /* OCR2 -- output compare register */ 4055ec694b5SJean-Christophe DUBOIS s->ocr2 = value; 4065ec694b5SJean-Christophe DUBOIS 4075ec694b5SJean-Christophe DUBOIS /* compute the new timeout */ 40867110c3eSJean-Christophe DUBOIS imx_gpt_compute_next_timeout(s, false); 4095ec694b5SJean-Christophe DUBOIS 4105ec694b5SJean-Christophe DUBOIS break; 4115ec694b5SJean-Christophe DUBOIS 412a50c0d6fSJean-Christophe DUBOIS case 6: /* OCR3 -- output compare register */ 4135ec694b5SJean-Christophe DUBOIS s->ocr3 = value; 4145ec694b5SJean-Christophe DUBOIS 4155ec694b5SJean-Christophe DUBOIS /* compute the new timeout */ 41667110c3eSJean-Christophe DUBOIS imx_gpt_compute_next_timeout(s, false); 4175ec694b5SJean-Christophe DUBOIS 4185ec694b5SJean-Christophe DUBOIS break; 4195ec694b5SJean-Christophe DUBOIS 420a50c0d6fSJean-Christophe DUBOIS default: 42105453526SJean-Christophe Dubois qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%" 42205453526SJean-Christophe Dubois HWADDR_PRIx "\n", TYPE_IMX_GPT, __func__, offset); 4235ec694b5SJean-Christophe DUBOIS break; 424a50c0d6fSJean-Christophe DUBOIS } 425a50c0d6fSJean-Christophe DUBOIS } 426a50c0d6fSJean-Christophe DUBOIS 42767110c3eSJean-Christophe DUBOIS static void imx_gpt_timeout(void *opaque) 428a50c0d6fSJean-Christophe DUBOIS { 42967110c3eSJean-Christophe DUBOIS IMXGPTState *s = IMX_GPT(opaque); 430a50c0d6fSJean-Christophe DUBOIS 4315ec694b5SJean-Christophe DUBOIS DPRINTF("\n"); 432a50c0d6fSJean-Christophe DUBOIS 4335ec694b5SJean-Christophe DUBOIS s->sr |= s->next_int; 4345ec694b5SJean-Christophe DUBOIS s->next_int = 0; 435a50c0d6fSJean-Christophe DUBOIS 43667110c3eSJean-Christophe DUBOIS imx_gpt_compute_next_timeout(s, true); 4375ec694b5SJean-Christophe DUBOIS 43867110c3eSJean-Christophe DUBOIS imx_gpt_update_int(s); 4395ec694b5SJean-Christophe DUBOIS 4405ec694b5SJean-Christophe DUBOIS if (s->freq && (s->cr & GPT_CR_EN)) { 4415ec694b5SJean-Christophe DUBOIS ptimer_run(s->timer, 1); 4425ec694b5SJean-Christophe DUBOIS } 443a50c0d6fSJean-Christophe DUBOIS } 444a50c0d6fSJean-Christophe DUBOIS 44567110c3eSJean-Christophe DUBOIS static const MemoryRegionOps imx_gpt_ops = { 44667110c3eSJean-Christophe DUBOIS .read = imx_gpt_read, 44767110c3eSJean-Christophe DUBOIS .write = imx_gpt_write, 448a50c0d6fSJean-Christophe DUBOIS .endianness = DEVICE_NATIVE_ENDIAN, 449a50c0d6fSJean-Christophe DUBOIS }; 450a50c0d6fSJean-Christophe DUBOIS 451a50c0d6fSJean-Christophe DUBOIS 45267110c3eSJean-Christophe DUBOIS static void imx_gpt_realize(DeviceState *dev, Error **errp) 453a50c0d6fSJean-Christophe DUBOIS { 45467110c3eSJean-Christophe DUBOIS IMXGPTState *s = IMX_GPT(dev); 45567110c3eSJean-Christophe DUBOIS SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 456a50c0d6fSJean-Christophe DUBOIS QEMUBH *bh; 457a50c0d6fSJean-Christophe DUBOIS 45867110c3eSJean-Christophe DUBOIS sysbus_init_irq(sbd, &s->irq); 459853dca12SPaolo Bonzini memory_region_init_io(&s->iomem, OBJECT(s), &imx_gpt_ops, s, TYPE_IMX_GPT, 460a50c0d6fSJean-Christophe DUBOIS 0x00001000); 46167110c3eSJean-Christophe DUBOIS sysbus_init_mmio(sbd, &s->iomem); 462a50c0d6fSJean-Christophe DUBOIS 46367110c3eSJean-Christophe DUBOIS bh = qemu_bh_new(imx_gpt_timeout, s); 464*e7ea81c3SDmitry Osipenko s->timer = ptimer_init(bh, PTIMER_POLICY_DEFAULT); 465a50c0d6fSJean-Christophe DUBOIS } 466a50c0d6fSJean-Christophe DUBOIS 46767110c3eSJean-Christophe DUBOIS static void imx_gpt_class_init(ObjectClass *klass, void *data) 468a50c0d6fSJean-Christophe DUBOIS { 469a50c0d6fSJean-Christophe DUBOIS DeviceClass *dc = DEVICE_CLASS(klass); 47067110c3eSJean-Christophe DUBOIS 47167110c3eSJean-Christophe DUBOIS dc->realize = imx_gpt_realize; 47267110c3eSJean-Christophe DUBOIS dc->reset = imx_gpt_reset; 47367110c3eSJean-Christophe DUBOIS dc->vmsd = &vmstate_imx_timer_gpt; 474a50c0d6fSJean-Christophe DUBOIS dc->desc = "i.MX general timer"; 475a50c0d6fSJean-Christophe DUBOIS } 476a50c0d6fSJean-Christophe DUBOIS 47766542f63SJean-Christophe Dubois static void imx25_gpt_init(Object *obj) 47866542f63SJean-Christophe Dubois { 47966542f63SJean-Christophe Dubois IMXGPTState *s = IMX_GPT(obj); 48066542f63SJean-Christophe Dubois 48166542f63SJean-Christophe Dubois s->clocks = imx25_gpt_clocks; 48266542f63SJean-Christophe Dubois } 48366542f63SJean-Christophe Dubois 48466542f63SJean-Christophe Dubois static void imx31_gpt_init(Object *obj) 48566542f63SJean-Christophe Dubois { 48666542f63SJean-Christophe Dubois IMXGPTState *s = IMX_GPT(obj); 48766542f63SJean-Christophe Dubois 48866542f63SJean-Christophe Dubois s->clocks = imx31_gpt_clocks; 48966542f63SJean-Christophe Dubois } 49066542f63SJean-Christophe Dubois 49166542f63SJean-Christophe Dubois static void imx6_gpt_init(Object *obj) 49266542f63SJean-Christophe Dubois { 49366542f63SJean-Christophe Dubois IMXGPTState *s = IMX_GPT(obj); 49466542f63SJean-Christophe Dubois 49566542f63SJean-Christophe Dubois s->clocks = imx6_gpt_clocks; 49666542f63SJean-Christophe Dubois } 49766542f63SJean-Christophe Dubois 49866542f63SJean-Christophe Dubois static const TypeInfo imx25_gpt_info = { 49966542f63SJean-Christophe Dubois .name = TYPE_IMX25_GPT, 500a50c0d6fSJean-Christophe DUBOIS .parent = TYPE_SYS_BUS_DEVICE, 50167110c3eSJean-Christophe DUBOIS .instance_size = sizeof(IMXGPTState), 50266542f63SJean-Christophe Dubois .instance_init = imx25_gpt_init, 50367110c3eSJean-Christophe DUBOIS .class_init = imx_gpt_class_init, 504a50c0d6fSJean-Christophe DUBOIS }; 505a50c0d6fSJean-Christophe DUBOIS 50666542f63SJean-Christophe Dubois static const TypeInfo imx31_gpt_info = { 50766542f63SJean-Christophe Dubois .name = TYPE_IMX31_GPT, 50866542f63SJean-Christophe Dubois .parent = TYPE_IMX25_GPT, 50966542f63SJean-Christophe Dubois .instance_init = imx31_gpt_init, 51066542f63SJean-Christophe Dubois }; 51166542f63SJean-Christophe Dubois 51266542f63SJean-Christophe Dubois static const TypeInfo imx6_gpt_info = { 51366542f63SJean-Christophe Dubois .name = TYPE_IMX6_GPT, 51466542f63SJean-Christophe Dubois .parent = TYPE_IMX25_GPT, 51566542f63SJean-Christophe Dubois .instance_init = imx6_gpt_init, 51666542f63SJean-Christophe Dubois }; 51766542f63SJean-Christophe Dubois 51867110c3eSJean-Christophe DUBOIS static void imx_gpt_register_types(void) 519a50c0d6fSJean-Christophe DUBOIS { 52066542f63SJean-Christophe Dubois type_register_static(&imx25_gpt_info); 52166542f63SJean-Christophe Dubois type_register_static(&imx31_gpt_info); 52266542f63SJean-Christophe Dubois type_register_static(&imx6_gpt_info); 523a50c0d6fSJean-Christophe DUBOIS } 524a50c0d6fSJean-Christophe DUBOIS 52567110c3eSJean-Christophe DUBOIS type_init(imx_gpt_register_types) 526