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" 1664552b6bSMarkus Armbruster #include "hw/irq.h" 17d647b26dSJean-Christophe Dubois #include "hw/timer/imx_gpt.h" 18d6454270SMarkus Armbruster #include "migration/vmstate.h" 190b8fa32fSMarkus Armbruster #include "qemu/module.h" 2003dd024fSPaolo Bonzini #include "qemu/log.h" 21afd431e4SBernhard Beschow #include "trace.h" 22a50c0d6fSJean-Christophe DUBOIS 23d675765aSPeter Maydell static const char *imx_gpt_reg_name(uint32_t reg) 245ec694b5SJean-Christophe DUBOIS { 255ec694b5SJean-Christophe DUBOIS switch (reg) { 265ec694b5SJean-Christophe DUBOIS case 0: 275ec694b5SJean-Christophe DUBOIS return "CR"; 285ec694b5SJean-Christophe DUBOIS case 1: 295ec694b5SJean-Christophe DUBOIS return "PR"; 305ec694b5SJean-Christophe DUBOIS case 2: 315ec694b5SJean-Christophe DUBOIS return "SR"; 325ec694b5SJean-Christophe DUBOIS case 3: 335ec694b5SJean-Christophe DUBOIS return "IR"; 345ec694b5SJean-Christophe DUBOIS case 4: 355ec694b5SJean-Christophe DUBOIS return "OCR1"; 365ec694b5SJean-Christophe DUBOIS case 5: 375ec694b5SJean-Christophe DUBOIS return "OCR2"; 385ec694b5SJean-Christophe DUBOIS case 6: 395ec694b5SJean-Christophe DUBOIS return "OCR3"; 405ec694b5SJean-Christophe DUBOIS case 7: 415ec694b5SJean-Christophe DUBOIS return "ICR1"; 425ec694b5SJean-Christophe DUBOIS case 8: 435ec694b5SJean-Christophe DUBOIS return "ICR2"; 445ec694b5SJean-Christophe DUBOIS case 9: 455ec694b5SJean-Christophe DUBOIS return "CNT"; 465ec694b5SJean-Christophe DUBOIS default: 475ec694b5SJean-Christophe DUBOIS return "[?]"; 485ec694b5SJean-Christophe DUBOIS } 495ec694b5SJean-Christophe DUBOIS } 505ec694b5SJean-Christophe DUBOIS 5167110c3eSJean-Christophe DUBOIS static const VMStateDescription vmstate_imx_timer_gpt = { 5268b85290SJean-Christophe Dubois .name = TYPE_IMX_GPT, 535ec694b5SJean-Christophe DUBOIS .version_id = 3, 545ec694b5SJean-Christophe DUBOIS .minimum_version_id = 3, 55ba324b3fSRichard Henderson .fields = (const VMStateField[]) { 5667110c3eSJean-Christophe DUBOIS VMSTATE_UINT32(cr, IMXGPTState), 5767110c3eSJean-Christophe DUBOIS VMSTATE_UINT32(pr, IMXGPTState), 5867110c3eSJean-Christophe DUBOIS VMSTATE_UINT32(sr, IMXGPTState), 5967110c3eSJean-Christophe DUBOIS VMSTATE_UINT32(ir, IMXGPTState), 6067110c3eSJean-Christophe DUBOIS VMSTATE_UINT32(ocr1, IMXGPTState), 6167110c3eSJean-Christophe DUBOIS VMSTATE_UINT32(ocr2, IMXGPTState), 6267110c3eSJean-Christophe DUBOIS VMSTATE_UINT32(ocr3, IMXGPTState), 6367110c3eSJean-Christophe DUBOIS VMSTATE_UINT32(icr1, IMXGPTState), 6467110c3eSJean-Christophe DUBOIS VMSTATE_UINT32(icr2, IMXGPTState), 6567110c3eSJean-Christophe DUBOIS VMSTATE_UINT32(cnt, IMXGPTState), 6667110c3eSJean-Christophe DUBOIS VMSTATE_UINT32(next_timeout, IMXGPTState), 6767110c3eSJean-Christophe DUBOIS VMSTATE_UINT32(next_int, IMXGPTState), 6867110c3eSJean-Christophe DUBOIS VMSTATE_UINT32(freq, IMXGPTState), 6967110c3eSJean-Christophe DUBOIS VMSTATE_PTIMER(timer, IMXGPTState), 70a50c0d6fSJean-Christophe DUBOIS VMSTATE_END_OF_LIST() 71a50c0d6fSJean-Christophe DUBOIS } 72a50c0d6fSJean-Christophe DUBOIS }; 73a50c0d6fSJean-Christophe DUBOIS 7466542f63SJean-Christophe Dubois static const IMXClk imx25_gpt_clocks[] = { 7566542f63SJean-Christophe Dubois CLK_NONE, /* 000 No clock source */ 7666542f63SJean-Christophe Dubois CLK_IPG, /* 001 ipg_clk, 532MHz*/ 7766542f63SJean-Christophe Dubois CLK_IPG_HIGH, /* 010 ipg_clk_highfreq */ 7866542f63SJean-Christophe Dubois CLK_NONE, /* 011 not defined */ 7966542f63SJean-Christophe Dubois CLK_32k, /* 100 ipg_clk_32k */ 8066542f63SJean-Christophe Dubois CLK_32k, /* 101 ipg_clk_32k */ 8166542f63SJean-Christophe Dubois CLK_32k, /* 110 ipg_clk_32k */ 8266542f63SJean-Christophe Dubois CLK_32k, /* 111 ipg_clk_32k */ 8366542f63SJean-Christophe Dubois }; 8466542f63SJean-Christophe Dubois 8566542f63SJean-Christophe Dubois static const IMXClk imx31_gpt_clocks[] = { 86c91a5883SJean-Christophe Dubois CLK_NONE, /* 000 No clock source */ 87aaa9ec3bSJean-Christophe Dubois CLK_IPG, /* 001 ipg_clk, 532MHz*/ 88d552f675SJean-Christophe Dubois CLK_IPG_HIGH, /* 010 ipg_clk_highfreq */ 89c91a5883SJean-Christophe Dubois CLK_NONE, /* 011 not defined */ 90a50c0d6fSJean-Christophe DUBOIS CLK_32k, /* 100 ipg_clk_32k */ 91c91a5883SJean-Christophe Dubois CLK_NONE, /* 101 not defined */ 92c91a5883SJean-Christophe Dubois CLK_NONE, /* 110 not defined */ 93c91a5883SJean-Christophe Dubois CLK_NONE, /* 111 not defined */ 94a50c0d6fSJean-Christophe DUBOIS }; 95a50c0d6fSJean-Christophe DUBOIS 9666542f63SJean-Christophe Dubois static const IMXClk imx6_gpt_clocks[] = { 9766542f63SJean-Christophe Dubois CLK_NONE, /* 000 No clock source */ 9866542f63SJean-Christophe Dubois CLK_IPG, /* 001 ipg_clk, 532MHz*/ 9966542f63SJean-Christophe Dubois CLK_IPG_HIGH, /* 010 ipg_clk_highfreq */ 10066542f63SJean-Christophe Dubois CLK_EXT, /* 011 External clock */ 10166542f63SJean-Christophe Dubois CLK_32k, /* 100 ipg_clk_32k */ 10266542f63SJean-Christophe Dubois CLK_HIGH_DIV, /* 101 reference clock / 8 */ 10366542f63SJean-Christophe Dubois CLK_NONE, /* 110 not defined */ 10466542f63SJean-Christophe Dubois CLK_HIGH, /* 111 reference clock */ 10566542f63SJean-Christophe Dubois }; 10666542f63SJean-Christophe Dubois 107a1e03956SJean-Christophe Dubois static const IMXClk imx6ul_gpt_clocks[] = { 108a1e03956SJean-Christophe Dubois CLK_NONE, /* 000 No clock source */ 109a1e03956SJean-Christophe Dubois CLK_IPG, /* 001 ipg_clk, 532MHz*/ 110a1e03956SJean-Christophe Dubois CLK_IPG_HIGH, /* 010 ipg_clk_highfreq */ 111a1e03956SJean-Christophe Dubois CLK_EXT, /* 011 External clock */ 112a1e03956SJean-Christophe Dubois CLK_32k, /* 100 ipg_clk_32k */ 113a1e03956SJean-Christophe Dubois CLK_NONE, /* 101 not defined */ 114a1e03956SJean-Christophe Dubois CLK_NONE, /* 110 not defined */ 115a1e03956SJean-Christophe Dubois CLK_NONE, /* 111 not defined */ 116a1e03956SJean-Christophe Dubois }; 117a1e03956SJean-Christophe Dubois 118a62bf59fSAndrey Smirnov static const IMXClk imx7_gpt_clocks[] = { 119a62bf59fSAndrey Smirnov CLK_NONE, /* 000 No clock source */ 120a62bf59fSAndrey Smirnov CLK_IPG, /* 001 ipg_clk, 532MHz*/ 121a62bf59fSAndrey Smirnov CLK_IPG_HIGH, /* 010 ipg_clk_highfreq */ 122a62bf59fSAndrey Smirnov CLK_EXT, /* 011 External clock */ 123a62bf59fSAndrey Smirnov CLK_32k, /* 100 ipg_clk_32k */ 124a62bf59fSAndrey Smirnov CLK_HIGH, /* 101 reference clock */ 125a62bf59fSAndrey Smirnov CLK_NONE, /* 110 not defined */ 126a62bf59fSAndrey Smirnov CLK_NONE, /* 111 not defined */ 127a62bf59fSAndrey Smirnov }; 128a62bf59fSAndrey Smirnov 129*f8b26121SBernhard Beschow static const IMXClk imx8mp_gpt_clocks[] = { 130*f8b26121SBernhard Beschow CLK_NONE, /* 000 No clock source */ 131*f8b26121SBernhard Beschow CLK_IPG, /* 001 ipg_clk, 532MHz */ 132*f8b26121SBernhard Beschow CLK_IPG_HIGH, /* 010 ipg_clk_highfreq */ 133*f8b26121SBernhard Beschow CLK_EXT, /* 011 External clock */ 134*f8b26121SBernhard Beschow CLK_32k, /* 100 ipg_clk_32k */ 135*f8b26121SBernhard Beschow CLK_HIGH, /* 101 ipg_clk_16M */ 136*f8b26121SBernhard Beschow CLK_NONE, /* 110 not defined */ 137*f8b26121SBernhard Beschow CLK_NONE, /* 111 not defined */ 138*f8b26121SBernhard Beschow }; 139*f8b26121SBernhard Beschow 1401b914994SPeter Maydell /* Must be called from within ptimer_transaction_begin/commit block */ 14167110c3eSJean-Christophe DUBOIS static void imx_gpt_set_freq(IMXGPTState *s) 142a50c0d6fSJean-Christophe DUBOIS { 1435ec694b5SJean-Christophe DUBOIS uint32_t clksrc = extract32(s->cr, GPT_CR_CLKSRC_SHIFT, 3); 144a50c0d6fSJean-Christophe DUBOIS 145aaa9ec3bSJean-Christophe Dubois s->freq = imx_ccm_get_clock_frequency(s->ccm, 14666542f63SJean-Christophe Dubois s->clocks[clksrc]) / (1 + s->pr); 147a50c0d6fSJean-Christophe DUBOIS 148afd431e4SBernhard Beschow trace_imx_gpt_set_freq(clksrc, s->freq); 149aaa9ec3bSJean-Christophe Dubois 150aaa9ec3bSJean-Christophe Dubois if (s->freq) { 151aaa9ec3bSJean-Christophe Dubois ptimer_set_freq(s->timer, s->freq); 152a50c0d6fSJean-Christophe DUBOIS } 153a50c0d6fSJean-Christophe DUBOIS } 154a50c0d6fSJean-Christophe DUBOIS 15567110c3eSJean-Christophe DUBOIS static void imx_gpt_update_int(IMXGPTState *s) 156a50c0d6fSJean-Christophe DUBOIS { 1575ec694b5SJean-Christophe DUBOIS if ((s->sr & s->ir) && (s->cr & GPT_CR_EN)) { 1585ec694b5SJean-Christophe DUBOIS qemu_irq_raise(s->irq); 1595ec694b5SJean-Christophe DUBOIS } else { 1605ec694b5SJean-Christophe DUBOIS qemu_irq_lower(s->irq); 1615ec694b5SJean-Christophe DUBOIS } 162a50c0d6fSJean-Christophe DUBOIS } 163a50c0d6fSJean-Christophe DUBOIS 16467110c3eSJean-Christophe DUBOIS static uint32_t imx_gpt_update_count(IMXGPTState *s) 165a50c0d6fSJean-Christophe DUBOIS { 1665ec694b5SJean-Christophe DUBOIS s->cnt = s->next_timeout - (uint32_t)ptimer_get_count(s->timer); 1675ec694b5SJean-Christophe DUBOIS 168a50c0d6fSJean-Christophe DUBOIS return s->cnt; 169a50c0d6fSJean-Christophe DUBOIS } 170a50c0d6fSJean-Christophe DUBOIS 17167110c3eSJean-Christophe DUBOIS static inline uint32_t imx_gpt_find_limit(uint32_t count, uint32_t reg, 1725ec694b5SJean-Christophe DUBOIS uint32_t timeout) 173a50c0d6fSJean-Christophe DUBOIS { 1745ec694b5SJean-Christophe DUBOIS if ((count < reg) && (timeout > reg)) { 1755ec694b5SJean-Christophe DUBOIS timeout = reg; 1765ec694b5SJean-Christophe DUBOIS } 177a50c0d6fSJean-Christophe DUBOIS 1785ec694b5SJean-Christophe DUBOIS return timeout; 1795ec694b5SJean-Christophe DUBOIS } 1805ec694b5SJean-Christophe DUBOIS 1811b914994SPeter Maydell /* Must be called from within ptimer_transaction_begin/commit block */ 18267110c3eSJean-Christophe DUBOIS static void imx_gpt_compute_next_timeout(IMXGPTState *s, bool event) 1835ec694b5SJean-Christophe DUBOIS { 184203d65a4SMichael Tokarev uint32_t timeout = GPT_TIMER_MAX; 1854833e15fSJean-Christophe Dubois uint32_t count; 1865ec694b5SJean-Christophe DUBOIS long long limit; 1875ec694b5SJean-Christophe DUBOIS 1885ec694b5SJean-Christophe DUBOIS if (!(s->cr & GPT_CR_EN)) { 1895ec694b5SJean-Christophe DUBOIS /* if not enabled just return */ 190a50c0d6fSJean-Christophe DUBOIS return; 191a50c0d6fSJean-Christophe DUBOIS } 192a50c0d6fSJean-Christophe DUBOIS 1934833e15fSJean-Christophe Dubois /* update the count */ 1944833e15fSJean-Christophe Dubois count = imx_gpt_update_count(s); 1954833e15fSJean-Christophe Dubois 1965ec694b5SJean-Christophe DUBOIS if (event) { 197a50c0d6fSJean-Christophe DUBOIS /* 1984833e15fSJean-Christophe Dubois * This is an event (the ptimer reached 0 and stopped), and the 1994833e15fSJean-Christophe Dubois * timer counter is now equal to s->next_timeout. 200a50c0d6fSJean-Christophe DUBOIS */ 2014833e15fSJean-Christophe Dubois if (!(s->cr & GPT_CR_FRR) && (count == s->ocr1)) { 2024833e15fSJean-Christophe Dubois /* We are in restart mode and we crossed the compare channel 1 2034833e15fSJean-Christophe Dubois * value. We need to reset the counter to 0. 2044833e15fSJean-Christophe Dubois */ 2054833e15fSJean-Christophe Dubois count = s->cnt = s->next_timeout = 0; 2064833e15fSJean-Christophe Dubois } else if (count == GPT_TIMER_MAX) { 2074833e15fSJean-Christophe Dubois /* We reached GPT_TIMER_MAX so we need to rollover */ 2084833e15fSJean-Christophe Dubois count = s->cnt = s->next_timeout = 0; 209a50c0d6fSJean-Christophe DUBOIS } 2105ec694b5SJean-Christophe DUBOIS } 2115ec694b5SJean-Christophe DUBOIS 2125ec694b5SJean-Christophe DUBOIS /* now, find the next timeout related to count */ 2135ec694b5SJean-Christophe DUBOIS 2145ec694b5SJean-Christophe DUBOIS if (s->ir & GPT_IR_OF1IE) { 21567110c3eSJean-Christophe DUBOIS timeout = imx_gpt_find_limit(count, s->ocr1, timeout); 2165ec694b5SJean-Christophe DUBOIS } 2175ec694b5SJean-Christophe DUBOIS if (s->ir & GPT_IR_OF2IE) { 21867110c3eSJean-Christophe DUBOIS timeout = imx_gpt_find_limit(count, s->ocr2, timeout); 2195ec694b5SJean-Christophe DUBOIS } 2205ec694b5SJean-Christophe DUBOIS if (s->ir & GPT_IR_OF3IE) { 22167110c3eSJean-Christophe DUBOIS timeout = imx_gpt_find_limit(count, s->ocr3, timeout); 2225ec694b5SJean-Christophe DUBOIS } 2235ec694b5SJean-Christophe DUBOIS 2245ec694b5SJean-Christophe DUBOIS /* find the next set of interrupts to raise for next timer event */ 2255ec694b5SJean-Christophe DUBOIS 2265ec694b5SJean-Christophe DUBOIS s->next_int = 0; 2275ec694b5SJean-Christophe DUBOIS if ((s->ir & GPT_IR_OF1IE) && (timeout == s->ocr1)) { 2285ec694b5SJean-Christophe DUBOIS s->next_int |= GPT_SR_OF1; 2295ec694b5SJean-Christophe DUBOIS } 2305ec694b5SJean-Christophe DUBOIS if ((s->ir & GPT_IR_OF2IE) && (timeout == s->ocr2)) { 2315ec694b5SJean-Christophe DUBOIS s->next_int |= GPT_SR_OF2; 2325ec694b5SJean-Christophe DUBOIS } 2335ec694b5SJean-Christophe DUBOIS if ((s->ir & GPT_IR_OF3IE) && (timeout == s->ocr3)) { 2345ec694b5SJean-Christophe DUBOIS s->next_int |= GPT_SR_OF3; 2355ec694b5SJean-Christophe DUBOIS } 236203d65a4SMichael Tokarev if ((s->ir & GPT_IR_ROVIE) && (timeout == GPT_TIMER_MAX)) { 2375ec694b5SJean-Christophe DUBOIS s->next_int |= GPT_SR_ROV; 2385ec694b5SJean-Christophe DUBOIS } 2395ec694b5SJean-Christophe DUBOIS 2405ec694b5SJean-Christophe DUBOIS /* the new range to count down from */ 24167110c3eSJean-Christophe DUBOIS limit = timeout - imx_gpt_update_count(s); 2425ec694b5SJean-Christophe DUBOIS 2435ec694b5SJean-Christophe DUBOIS if (limit < 0) { 2445ec694b5SJean-Christophe DUBOIS /* 2455ec694b5SJean-Christophe DUBOIS * if we reach here, then QEMU is running too slow and we pass the 2465ec694b5SJean-Christophe DUBOIS * timeout limit while computing it. Let's deliver the interrupt 2475ec694b5SJean-Christophe DUBOIS * and compute a new limit. 2485ec694b5SJean-Christophe DUBOIS */ 2495ec694b5SJean-Christophe DUBOIS s->sr |= s->next_int; 2505ec694b5SJean-Christophe DUBOIS 25167110c3eSJean-Christophe DUBOIS imx_gpt_compute_next_timeout(s, event); 2525ec694b5SJean-Christophe DUBOIS 25367110c3eSJean-Christophe DUBOIS imx_gpt_update_int(s); 2545ec694b5SJean-Christophe DUBOIS } else { 2555ec694b5SJean-Christophe DUBOIS /* New timeout value */ 2565ec694b5SJean-Christophe DUBOIS s->next_timeout = timeout; 2575ec694b5SJean-Christophe DUBOIS 2585ec694b5SJean-Christophe DUBOIS /* reset the limit to the computed range */ 2595ec694b5SJean-Christophe DUBOIS ptimer_set_limit(s->timer, limit, 1); 2605ec694b5SJean-Christophe DUBOIS } 261a50c0d6fSJean-Christophe DUBOIS } 262a50c0d6fSJean-Christophe DUBOIS 26367110c3eSJean-Christophe DUBOIS static uint64_t imx_gpt_read(void *opaque, hwaddr offset, unsigned size) 264a50c0d6fSJean-Christophe DUBOIS { 26567110c3eSJean-Christophe DUBOIS IMXGPTState *s = IMX_GPT(opaque); 2665ec694b5SJean-Christophe DUBOIS uint32_t reg_value = 0; 267a50c0d6fSJean-Christophe DUBOIS 26805453526SJean-Christophe Dubois switch (offset >> 2) { 269a50c0d6fSJean-Christophe DUBOIS case 0: /* Control Register */ 2705ec694b5SJean-Christophe DUBOIS reg_value = s->cr; 2715ec694b5SJean-Christophe DUBOIS break; 272a50c0d6fSJean-Christophe DUBOIS 273a50c0d6fSJean-Christophe DUBOIS case 1: /* prescaler */ 2745ec694b5SJean-Christophe DUBOIS reg_value = s->pr; 2755ec694b5SJean-Christophe DUBOIS break; 276a50c0d6fSJean-Christophe DUBOIS 277a50c0d6fSJean-Christophe DUBOIS case 2: /* Status Register */ 2785ec694b5SJean-Christophe DUBOIS reg_value = s->sr; 2795ec694b5SJean-Christophe DUBOIS break; 280a50c0d6fSJean-Christophe DUBOIS 281a50c0d6fSJean-Christophe DUBOIS case 3: /* Interrupt Register */ 2825ec694b5SJean-Christophe DUBOIS reg_value = s->ir; 2835ec694b5SJean-Christophe DUBOIS break; 284a50c0d6fSJean-Christophe DUBOIS 285a50c0d6fSJean-Christophe DUBOIS case 4: /* Output Compare Register 1 */ 2865ec694b5SJean-Christophe DUBOIS reg_value = s->ocr1; 2875ec694b5SJean-Christophe DUBOIS break; 288a50c0d6fSJean-Christophe DUBOIS 289a50c0d6fSJean-Christophe DUBOIS case 5: /* Output Compare Register 2 */ 2905ec694b5SJean-Christophe DUBOIS reg_value = s->ocr2; 2915ec694b5SJean-Christophe DUBOIS break; 292a50c0d6fSJean-Christophe DUBOIS 293a50c0d6fSJean-Christophe DUBOIS case 6: /* Output Compare Register 3 */ 2945ec694b5SJean-Christophe DUBOIS reg_value = s->ocr3; 2955ec694b5SJean-Christophe DUBOIS break; 296a50c0d6fSJean-Christophe DUBOIS 297a50c0d6fSJean-Christophe DUBOIS case 7: /* input Capture Register 1 */ 29805453526SJean-Christophe Dubois qemu_log_mask(LOG_UNIMP, "[%s]%s: icr1 feature is not implemented\n", 29905453526SJean-Christophe Dubois TYPE_IMX_GPT, __func__); 3005ec694b5SJean-Christophe DUBOIS reg_value = s->icr1; 3015ec694b5SJean-Christophe DUBOIS break; 302a50c0d6fSJean-Christophe DUBOIS 303a50c0d6fSJean-Christophe DUBOIS case 8: /* input Capture Register 2 */ 30405453526SJean-Christophe Dubois qemu_log_mask(LOG_UNIMP, "[%s]%s: icr2 feature is not implemented\n", 30505453526SJean-Christophe Dubois TYPE_IMX_GPT, __func__); 3065ec694b5SJean-Christophe DUBOIS reg_value = s->icr2; 3075ec694b5SJean-Christophe DUBOIS break; 308a50c0d6fSJean-Christophe DUBOIS 309a50c0d6fSJean-Christophe DUBOIS case 9: /* cnt */ 31067110c3eSJean-Christophe DUBOIS imx_gpt_update_count(s); 3115ec694b5SJean-Christophe DUBOIS reg_value = s->cnt; 3125ec694b5SJean-Christophe DUBOIS break; 3135ec694b5SJean-Christophe DUBOIS 3145ec694b5SJean-Christophe DUBOIS default: 31505453526SJean-Christophe Dubois qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%" 31605453526SJean-Christophe Dubois HWADDR_PRIx "\n", TYPE_IMX_GPT, __func__, offset); 3175ec694b5SJean-Christophe DUBOIS break; 318a50c0d6fSJean-Christophe DUBOIS } 319a50c0d6fSJean-Christophe DUBOIS 320afd431e4SBernhard Beschow trace_imx_gpt_read(imx_gpt_reg_name(offset >> 2), reg_value); 321a50c0d6fSJean-Christophe DUBOIS 3225ec694b5SJean-Christophe DUBOIS return reg_value; 323a50c0d6fSJean-Christophe DUBOIS } 324a50c0d6fSJean-Christophe DUBOIS 325a50c0d6fSJean-Christophe DUBOIS 326c98c9ebaSKurban Mallachiev static void imx_gpt_reset_common(IMXGPTState *s, bool is_soft_reset) 327c98c9ebaSKurban Mallachiev { 3281b914994SPeter Maydell ptimer_transaction_begin(s->timer); 3295ec694b5SJean-Christophe DUBOIS /* stop timer */ 3305ec694b5SJean-Christophe DUBOIS ptimer_stop(s->timer); 3315ec694b5SJean-Christophe DUBOIS 332c98c9ebaSKurban Mallachiev /* Soft reset and hard reset differ only in their handling of the CR 333c98c9ebaSKurban Mallachiev * register -- soft reset preserves the values of some bits there. 334a50c0d6fSJean-Christophe DUBOIS */ 335c98c9ebaSKurban Mallachiev if (is_soft_reset) { 336c98c9ebaSKurban Mallachiev /* Clear all CR bits except those that are preserved by soft reset. */ 337c98c9ebaSKurban Mallachiev s->cr &= GPT_CR_EN | GPT_CR_ENMOD | GPT_CR_STOPEN | GPT_CR_DOZEN | 338c98c9ebaSKurban Mallachiev GPT_CR_WAITEN | GPT_CR_DBGEN | 339c98c9ebaSKurban Mallachiev (GPT_CR_CLKSRC_MASK << GPT_CR_CLKSRC_SHIFT); 340c98c9ebaSKurban Mallachiev } else { 341c98c9ebaSKurban Mallachiev s->cr = 0; 342c98c9ebaSKurban Mallachiev } 343a50c0d6fSJean-Christophe DUBOIS s->sr = 0; 344a50c0d6fSJean-Christophe DUBOIS s->pr = 0; 345a50c0d6fSJean-Christophe DUBOIS s->ir = 0; 346a50c0d6fSJean-Christophe DUBOIS s->cnt = 0; 347203d65a4SMichael Tokarev s->ocr1 = GPT_TIMER_MAX; 348203d65a4SMichael Tokarev s->ocr2 = GPT_TIMER_MAX; 349203d65a4SMichael Tokarev s->ocr3 = GPT_TIMER_MAX; 350a50c0d6fSJean-Christophe DUBOIS s->icr1 = 0; 351a50c0d6fSJean-Christophe DUBOIS s->icr2 = 0; 3525ec694b5SJean-Christophe DUBOIS 353203d65a4SMichael Tokarev s->next_timeout = GPT_TIMER_MAX; 3545ec694b5SJean-Christophe DUBOIS s->next_int = 0; 3555ec694b5SJean-Christophe DUBOIS 3565ec694b5SJean-Christophe DUBOIS /* compute new freq */ 35767110c3eSJean-Christophe DUBOIS imx_gpt_set_freq(s); 3585ec694b5SJean-Christophe DUBOIS 359203d65a4SMichael Tokarev /* reset the limit to GPT_TIMER_MAX */ 360203d65a4SMichael Tokarev ptimer_set_limit(s->timer, GPT_TIMER_MAX, 1); 3615ec694b5SJean-Christophe DUBOIS 3625ec694b5SJean-Christophe DUBOIS /* if the timer is still enabled, restart it */ 3635ec694b5SJean-Christophe DUBOIS if (s->freq && (s->cr & GPT_CR_EN)) { 3645ec694b5SJean-Christophe DUBOIS ptimer_run(s->timer, 1); 3655ec694b5SJean-Christophe DUBOIS } 3661b914994SPeter Maydell ptimer_transaction_commit(s->timer); 367a50c0d6fSJean-Christophe DUBOIS } 368a50c0d6fSJean-Christophe DUBOIS 369c98c9ebaSKurban Mallachiev static void imx_gpt_soft_reset(DeviceState *dev) 370c98c9ebaSKurban Mallachiev { 371c98c9ebaSKurban Mallachiev IMXGPTState *s = IMX_GPT(dev); 372c98c9ebaSKurban Mallachiev imx_gpt_reset_common(s, true); 373c98c9ebaSKurban Mallachiev } 374c98c9ebaSKurban Mallachiev 375c98c9ebaSKurban Mallachiev static void imx_gpt_reset(DeviceState *dev) 376c98c9ebaSKurban Mallachiev { 377c98c9ebaSKurban Mallachiev IMXGPTState *s = IMX_GPT(dev); 378c98c9ebaSKurban Mallachiev imx_gpt_reset_common(s, false); 379c98c9ebaSKurban Mallachiev } 380c98c9ebaSKurban Mallachiev 38167110c3eSJean-Christophe DUBOIS static void imx_gpt_write(void *opaque, hwaddr offset, uint64_t value, 38267110c3eSJean-Christophe DUBOIS unsigned size) 383a50c0d6fSJean-Christophe DUBOIS { 38467110c3eSJean-Christophe DUBOIS IMXGPTState *s = IMX_GPT(opaque); 3855ec694b5SJean-Christophe DUBOIS uint32_t oldreg; 386a50c0d6fSJean-Christophe DUBOIS 387afd431e4SBernhard Beschow trace_imx_gpt_write(imx_gpt_reg_name(offset >> 2), (uint32_t)value); 388a50c0d6fSJean-Christophe DUBOIS 38905453526SJean-Christophe Dubois switch (offset >> 2) { 3905ec694b5SJean-Christophe DUBOIS case 0: 3915ec694b5SJean-Christophe DUBOIS oldreg = s->cr; 3925ec694b5SJean-Christophe DUBOIS s->cr = value & ~0x7c14; 3935ec694b5SJean-Christophe DUBOIS if (s->cr & GPT_CR_SWR) { /* force reset */ 3945ec694b5SJean-Christophe DUBOIS /* handle the reset */ 395c98c9ebaSKurban Mallachiev imx_gpt_soft_reset(DEVICE(s)); 396a50c0d6fSJean-Christophe DUBOIS } else { 3975ec694b5SJean-Christophe DUBOIS /* set our freq, as the source might have changed */ 3981b914994SPeter Maydell ptimer_transaction_begin(s->timer); 39967110c3eSJean-Christophe DUBOIS imx_gpt_set_freq(s); 4005ec694b5SJean-Christophe DUBOIS 4015ec694b5SJean-Christophe DUBOIS if ((oldreg ^ s->cr) & GPT_CR_EN) { 4025ec694b5SJean-Christophe DUBOIS if (s->cr & GPT_CR_EN) { 4035ec694b5SJean-Christophe DUBOIS if (s->cr & GPT_CR_ENMOD) { 404203d65a4SMichael Tokarev s->next_timeout = GPT_TIMER_MAX; 405203d65a4SMichael Tokarev ptimer_set_count(s->timer, GPT_TIMER_MAX); 40667110c3eSJean-Christophe DUBOIS imx_gpt_compute_next_timeout(s, false); 4075ec694b5SJean-Christophe DUBOIS } 4085ec694b5SJean-Christophe DUBOIS ptimer_run(s->timer, 1); 4095ec694b5SJean-Christophe DUBOIS } else { 4105ec694b5SJean-Christophe DUBOIS /* stop timer */ 411a50c0d6fSJean-Christophe DUBOIS ptimer_stop(s->timer); 412a50c0d6fSJean-Christophe DUBOIS } 413a50c0d6fSJean-Christophe DUBOIS } 4141b914994SPeter Maydell ptimer_transaction_commit(s->timer); 4155ec694b5SJean-Christophe DUBOIS } 4165ec694b5SJean-Christophe DUBOIS break; 417a50c0d6fSJean-Christophe DUBOIS 418a50c0d6fSJean-Christophe DUBOIS case 1: /* Prescaler */ 419a50c0d6fSJean-Christophe DUBOIS s->pr = value & 0xfff; 4201b914994SPeter Maydell ptimer_transaction_begin(s->timer); 42167110c3eSJean-Christophe DUBOIS imx_gpt_set_freq(s); 4221b914994SPeter Maydell ptimer_transaction_commit(s->timer); 4235ec694b5SJean-Christophe DUBOIS break; 424a50c0d6fSJean-Christophe DUBOIS 425a50c0d6fSJean-Christophe DUBOIS case 2: /* SR */ 4265ec694b5SJean-Christophe DUBOIS s->sr &= ~(value & 0x3f); 42767110c3eSJean-Christophe DUBOIS imx_gpt_update_int(s); 4285ec694b5SJean-Christophe DUBOIS break; 429a50c0d6fSJean-Christophe DUBOIS 430a50c0d6fSJean-Christophe DUBOIS case 3: /* IR -- interrupt register */ 431a50c0d6fSJean-Christophe DUBOIS s->ir = value & 0x3f; 43267110c3eSJean-Christophe DUBOIS imx_gpt_update_int(s); 4335ec694b5SJean-Christophe DUBOIS 4341b914994SPeter Maydell ptimer_transaction_begin(s->timer); 43567110c3eSJean-Christophe DUBOIS imx_gpt_compute_next_timeout(s, false); 4361b914994SPeter Maydell ptimer_transaction_commit(s->timer); 4375ec694b5SJean-Christophe DUBOIS 4385ec694b5SJean-Christophe DUBOIS break; 439a50c0d6fSJean-Christophe DUBOIS 440a50c0d6fSJean-Christophe DUBOIS case 4: /* OCR1 -- output compare register */ 4415ec694b5SJean-Christophe DUBOIS s->ocr1 = value; 4425ec694b5SJean-Christophe DUBOIS 4431b914994SPeter Maydell ptimer_transaction_begin(s->timer); 444a50c0d6fSJean-Christophe DUBOIS /* In non-freerun mode, reset count when this register is written */ 445a50c0d6fSJean-Christophe DUBOIS if (!(s->cr & GPT_CR_FRR)) { 446203d65a4SMichael Tokarev s->next_timeout = GPT_TIMER_MAX; 447203d65a4SMichael Tokarev ptimer_set_limit(s->timer, GPT_TIMER_MAX, 1); 448a50c0d6fSJean-Christophe DUBOIS } 4495ec694b5SJean-Christophe DUBOIS 4505ec694b5SJean-Christophe DUBOIS /* compute the new timeout */ 45167110c3eSJean-Christophe DUBOIS imx_gpt_compute_next_timeout(s, false); 4521b914994SPeter Maydell ptimer_transaction_commit(s->timer); 4535ec694b5SJean-Christophe DUBOIS 4545ec694b5SJean-Christophe DUBOIS break; 455a50c0d6fSJean-Christophe DUBOIS 456a50c0d6fSJean-Christophe DUBOIS case 5: /* OCR2 -- output compare register */ 4575ec694b5SJean-Christophe DUBOIS s->ocr2 = value; 4585ec694b5SJean-Christophe DUBOIS 4595ec694b5SJean-Christophe DUBOIS /* compute the new timeout */ 4601b914994SPeter Maydell ptimer_transaction_begin(s->timer); 46167110c3eSJean-Christophe DUBOIS imx_gpt_compute_next_timeout(s, false); 4621b914994SPeter Maydell ptimer_transaction_commit(s->timer); 4635ec694b5SJean-Christophe DUBOIS 4645ec694b5SJean-Christophe DUBOIS break; 4655ec694b5SJean-Christophe DUBOIS 466a50c0d6fSJean-Christophe DUBOIS case 6: /* OCR3 -- output compare register */ 4675ec694b5SJean-Christophe DUBOIS s->ocr3 = value; 4685ec694b5SJean-Christophe DUBOIS 4695ec694b5SJean-Christophe DUBOIS /* compute the new timeout */ 4701b914994SPeter Maydell ptimer_transaction_begin(s->timer); 47167110c3eSJean-Christophe DUBOIS imx_gpt_compute_next_timeout(s, false); 4721b914994SPeter Maydell ptimer_transaction_commit(s->timer); 4735ec694b5SJean-Christophe DUBOIS 4745ec694b5SJean-Christophe DUBOIS break; 4755ec694b5SJean-Christophe DUBOIS 476a50c0d6fSJean-Christophe DUBOIS default: 47705453526SJean-Christophe Dubois qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%" 47805453526SJean-Christophe Dubois HWADDR_PRIx "\n", TYPE_IMX_GPT, __func__, offset); 4795ec694b5SJean-Christophe DUBOIS break; 480a50c0d6fSJean-Christophe DUBOIS } 481a50c0d6fSJean-Christophe DUBOIS } 482a50c0d6fSJean-Christophe DUBOIS 48367110c3eSJean-Christophe DUBOIS static void imx_gpt_timeout(void *opaque) 484a50c0d6fSJean-Christophe DUBOIS { 48567110c3eSJean-Christophe DUBOIS IMXGPTState *s = IMX_GPT(opaque); 486a50c0d6fSJean-Christophe DUBOIS 487afd431e4SBernhard Beschow trace_imx_gpt_timeout(); 488a50c0d6fSJean-Christophe DUBOIS 4895ec694b5SJean-Christophe DUBOIS s->sr |= s->next_int; 4905ec694b5SJean-Christophe DUBOIS s->next_int = 0; 491a50c0d6fSJean-Christophe DUBOIS 49267110c3eSJean-Christophe DUBOIS imx_gpt_compute_next_timeout(s, true); 4935ec694b5SJean-Christophe DUBOIS 49467110c3eSJean-Christophe DUBOIS imx_gpt_update_int(s); 4955ec694b5SJean-Christophe DUBOIS 4965ec694b5SJean-Christophe DUBOIS if (s->freq && (s->cr & GPT_CR_EN)) { 4975ec694b5SJean-Christophe DUBOIS ptimer_run(s->timer, 1); 4985ec694b5SJean-Christophe DUBOIS } 499a50c0d6fSJean-Christophe DUBOIS } 500a50c0d6fSJean-Christophe DUBOIS 50167110c3eSJean-Christophe DUBOIS static const MemoryRegionOps imx_gpt_ops = { 50267110c3eSJean-Christophe DUBOIS .read = imx_gpt_read, 50367110c3eSJean-Christophe DUBOIS .write = imx_gpt_write, 504a50c0d6fSJean-Christophe DUBOIS .endianness = DEVICE_NATIVE_ENDIAN, 505a50c0d6fSJean-Christophe DUBOIS }; 506a50c0d6fSJean-Christophe DUBOIS 507a50c0d6fSJean-Christophe DUBOIS 50867110c3eSJean-Christophe DUBOIS static void imx_gpt_realize(DeviceState *dev, Error **errp) 509a50c0d6fSJean-Christophe DUBOIS { 51067110c3eSJean-Christophe DUBOIS IMXGPTState *s = IMX_GPT(dev); 51167110c3eSJean-Christophe DUBOIS SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 512a50c0d6fSJean-Christophe DUBOIS 51367110c3eSJean-Christophe DUBOIS sysbus_init_irq(sbd, &s->irq); 514853dca12SPaolo Bonzini memory_region_init_io(&s->iomem, OBJECT(s), &imx_gpt_ops, s, TYPE_IMX_GPT, 515a50c0d6fSJean-Christophe DUBOIS 0x00001000); 51667110c3eSJean-Christophe DUBOIS sysbus_init_mmio(sbd, &s->iomem); 517a50c0d6fSJean-Christophe DUBOIS 5189598c1bbSPeter Maydell s->timer = ptimer_init(imx_gpt_timeout, s, PTIMER_POLICY_LEGACY); 519a50c0d6fSJean-Christophe DUBOIS } 520a50c0d6fSJean-Christophe DUBOIS 52167110c3eSJean-Christophe DUBOIS static void imx_gpt_class_init(ObjectClass *klass, void *data) 522a50c0d6fSJean-Christophe DUBOIS { 523a50c0d6fSJean-Christophe DUBOIS DeviceClass *dc = DEVICE_CLASS(klass); 52467110c3eSJean-Christophe DUBOIS 52567110c3eSJean-Christophe DUBOIS dc->realize = imx_gpt_realize; 526e3d08143SPeter Maydell device_class_set_legacy_reset(dc, imx_gpt_reset); 52767110c3eSJean-Christophe DUBOIS dc->vmsd = &vmstate_imx_timer_gpt; 528a50c0d6fSJean-Christophe DUBOIS dc->desc = "i.MX general timer"; 529a50c0d6fSJean-Christophe DUBOIS } 530a50c0d6fSJean-Christophe DUBOIS 53166542f63SJean-Christophe Dubois static void imx25_gpt_init(Object *obj) 53266542f63SJean-Christophe Dubois { 53366542f63SJean-Christophe Dubois IMXGPTState *s = IMX_GPT(obj); 53466542f63SJean-Christophe Dubois 53566542f63SJean-Christophe Dubois s->clocks = imx25_gpt_clocks; 53666542f63SJean-Christophe Dubois } 53766542f63SJean-Christophe Dubois 53866542f63SJean-Christophe Dubois static void imx31_gpt_init(Object *obj) 53966542f63SJean-Christophe Dubois { 54066542f63SJean-Christophe Dubois IMXGPTState *s = IMX_GPT(obj); 54166542f63SJean-Christophe Dubois 54266542f63SJean-Christophe Dubois s->clocks = imx31_gpt_clocks; 54366542f63SJean-Christophe Dubois } 54466542f63SJean-Christophe Dubois 54566542f63SJean-Christophe Dubois static void imx6_gpt_init(Object *obj) 54666542f63SJean-Christophe Dubois { 54766542f63SJean-Christophe Dubois IMXGPTState *s = IMX_GPT(obj); 54866542f63SJean-Christophe Dubois 54966542f63SJean-Christophe Dubois s->clocks = imx6_gpt_clocks; 55066542f63SJean-Christophe Dubois } 55166542f63SJean-Christophe Dubois 552a1e03956SJean-Christophe Dubois static void imx6ul_gpt_init(Object *obj) 553a1e03956SJean-Christophe Dubois { 554a1e03956SJean-Christophe Dubois IMXGPTState *s = IMX_GPT(obj); 555a1e03956SJean-Christophe Dubois 556a1e03956SJean-Christophe Dubois s->clocks = imx6ul_gpt_clocks; 557a1e03956SJean-Christophe Dubois } 558a1e03956SJean-Christophe Dubois 559a62bf59fSAndrey Smirnov static void imx7_gpt_init(Object *obj) 560a62bf59fSAndrey Smirnov { 561a62bf59fSAndrey Smirnov IMXGPTState *s = IMX_GPT(obj); 562a62bf59fSAndrey Smirnov 563a62bf59fSAndrey Smirnov s->clocks = imx7_gpt_clocks; 564a62bf59fSAndrey Smirnov } 565a62bf59fSAndrey Smirnov 566*f8b26121SBernhard Beschow static void imx8mp_gpt_init(Object *obj) 567*f8b26121SBernhard Beschow { 568*f8b26121SBernhard Beschow IMXGPTState *s = IMX_GPT(obj); 569*f8b26121SBernhard Beschow 570*f8b26121SBernhard Beschow s->clocks = imx8mp_gpt_clocks; 571*f8b26121SBernhard Beschow } 572*f8b26121SBernhard Beschow 57366542f63SJean-Christophe Dubois static const TypeInfo imx25_gpt_info = { 57466542f63SJean-Christophe Dubois .name = TYPE_IMX25_GPT, 575a50c0d6fSJean-Christophe DUBOIS .parent = TYPE_SYS_BUS_DEVICE, 57667110c3eSJean-Christophe DUBOIS .instance_size = sizeof(IMXGPTState), 57766542f63SJean-Christophe Dubois .instance_init = imx25_gpt_init, 57867110c3eSJean-Christophe DUBOIS .class_init = imx_gpt_class_init, 579a50c0d6fSJean-Christophe DUBOIS }; 580a50c0d6fSJean-Christophe DUBOIS 58166542f63SJean-Christophe Dubois static const TypeInfo imx31_gpt_info = { 58266542f63SJean-Christophe Dubois .name = TYPE_IMX31_GPT, 58366542f63SJean-Christophe Dubois .parent = TYPE_IMX25_GPT, 58466542f63SJean-Christophe Dubois .instance_init = imx31_gpt_init, 58566542f63SJean-Christophe Dubois }; 58666542f63SJean-Christophe Dubois 58766542f63SJean-Christophe Dubois static const TypeInfo imx6_gpt_info = { 58866542f63SJean-Christophe Dubois .name = TYPE_IMX6_GPT, 58966542f63SJean-Christophe Dubois .parent = TYPE_IMX25_GPT, 59066542f63SJean-Christophe Dubois .instance_init = imx6_gpt_init, 59166542f63SJean-Christophe Dubois }; 59266542f63SJean-Christophe Dubois 593a1e03956SJean-Christophe Dubois static const TypeInfo imx6ul_gpt_info = { 594a1e03956SJean-Christophe Dubois .name = TYPE_IMX6UL_GPT, 595a1e03956SJean-Christophe Dubois .parent = TYPE_IMX25_GPT, 596a1e03956SJean-Christophe Dubois .instance_init = imx6ul_gpt_init, 597a1e03956SJean-Christophe Dubois }; 598a1e03956SJean-Christophe Dubois 599a62bf59fSAndrey Smirnov static const TypeInfo imx7_gpt_info = { 600a62bf59fSAndrey Smirnov .name = TYPE_IMX7_GPT, 601a62bf59fSAndrey Smirnov .parent = TYPE_IMX25_GPT, 602a62bf59fSAndrey Smirnov .instance_init = imx7_gpt_init, 603a62bf59fSAndrey Smirnov }; 604a62bf59fSAndrey Smirnov 605*f8b26121SBernhard Beschow static const TypeInfo imx8mp_gpt_info = { 606*f8b26121SBernhard Beschow .name = TYPE_IMX8MP_GPT, 607*f8b26121SBernhard Beschow .parent = TYPE_IMX25_GPT, 608*f8b26121SBernhard Beschow .instance_init = imx8mp_gpt_init, 609*f8b26121SBernhard Beschow }; 610*f8b26121SBernhard Beschow 61167110c3eSJean-Christophe DUBOIS static void imx_gpt_register_types(void) 612a50c0d6fSJean-Christophe DUBOIS { 61366542f63SJean-Christophe Dubois type_register_static(&imx25_gpt_info); 61466542f63SJean-Christophe Dubois type_register_static(&imx31_gpt_info); 61566542f63SJean-Christophe Dubois type_register_static(&imx6_gpt_info); 616a1e03956SJean-Christophe Dubois type_register_static(&imx6ul_gpt_info); 617a62bf59fSAndrey Smirnov type_register_static(&imx7_gpt_info); 618*f8b26121SBernhard Beschow type_register_static(&imx8mp_gpt_info); 619a50c0d6fSJean-Christophe DUBOIS } 620a50c0d6fSJean-Christophe DUBOIS 62167110c3eSJean-Christophe DUBOIS type_init(imx_gpt_register_types) 622