1a50c0d6fSJean-Christophe DUBOIS /* 2a50c0d6fSJean-Christophe DUBOIS * IMX GPT Timer 3a50c0d6fSJean-Christophe DUBOIS * 4a50c0d6fSJean-Christophe DUBOIS * Copyright (c) 2008 OK Labs 5a50c0d6fSJean-Christophe DUBOIS * Copyright (c) 2011 NICTA Pty Ltd 6a50c0d6fSJean-Christophe DUBOIS * Originally written by Hans Jiang 7a50c0d6fSJean-Christophe DUBOIS * Updated by Peter Chubb 8*d647b26dSJean-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 15a50c0d6fSJean-Christophe DUBOIS #include "hw/arm/imx.h" 16*d647b26dSJean-Christophe Dubois #include "hw/timer/imx_gpt.h" 17*d647b26dSJean-Christophe Dubois #include "hw/misc/imx_ccm.h" 186a1751b7SAlex Bligh #include "qemu/main-loop.h" 19a50c0d6fSJean-Christophe DUBOIS 205ec694b5SJean-Christophe DUBOIS /* 215ec694b5SJean-Christophe DUBOIS * Define to 1 for debug messages 225ec694b5SJean-Christophe DUBOIS */ 235ec694b5SJean-Christophe DUBOIS #define DEBUG_TIMER 0 245ec694b5SJean-Christophe DUBOIS #if DEBUG_TIMER 255ec694b5SJean-Christophe DUBOIS 2667110c3eSJean-Christophe DUBOIS static char const *imx_gpt_reg_name(uint32_t reg) 275ec694b5SJean-Christophe DUBOIS { 285ec694b5SJean-Christophe DUBOIS switch (reg) { 295ec694b5SJean-Christophe DUBOIS case 0: 305ec694b5SJean-Christophe DUBOIS return "CR"; 315ec694b5SJean-Christophe DUBOIS case 1: 325ec694b5SJean-Christophe DUBOIS return "PR"; 335ec694b5SJean-Christophe DUBOIS case 2: 345ec694b5SJean-Christophe DUBOIS return "SR"; 355ec694b5SJean-Christophe DUBOIS case 3: 365ec694b5SJean-Christophe DUBOIS return "IR"; 375ec694b5SJean-Christophe DUBOIS case 4: 385ec694b5SJean-Christophe DUBOIS return "OCR1"; 395ec694b5SJean-Christophe DUBOIS case 5: 405ec694b5SJean-Christophe DUBOIS return "OCR2"; 415ec694b5SJean-Christophe DUBOIS case 6: 425ec694b5SJean-Christophe DUBOIS return "OCR3"; 435ec694b5SJean-Christophe DUBOIS case 7: 445ec694b5SJean-Christophe DUBOIS return "ICR1"; 455ec694b5SJean-Christophe DUBOIS case 8: 465ec694b5SJean-Christophe DUBOIS return "ICR2"; 475ec694b5SJean-Christophe DUBOIS case 9: 485ec694b5SJean-Christophe DUBOIS return "CNT"; 495ec694b5SJean-Christophe DUBOIS default: 505ec694b5SJean-Christophe DUBOIS return "[?]"; 515ec694b5SJean-Christophe DUBOIS } 525ec694b5SJean-Christophe DUBOIS } 535ec694b5SJean-Christophe DUBOIS 54a50c0d6fSJean-Christophe DUBOIS # define DPRINTF(fmt, args...) \ 555ec694b5SJean-Christophe DUBOIS do { printf("%s: " fmt , __func__, ##args); } while (0) 56a50c0d6fSJean-Christophe DUBOIS #else 57a50c0d6fSJean-Christophe DUBOIS # define DPRINTF(fmt, args...) do {} while (0) 58a50c0d6fSJean-Christophe DUBOIS #endif 59a50c0d6fSJean-Christophe DUBOIS 60a50c0d6fSJean-Christophe DUBOIS /* 61a50c0d6fSJean-Christophe DUBOIS * Define to 1 for messages about attempts to 62a50c0d6fSJean-Christophe DUBOIS * access unimplemented registers or similar. 63a50c0d6fSJean-Christophe DUBOIS */ 64a50c0d6fSJean-Christophe DUBOIS #define DEBUG_IMPLEMENTATION 1 65a50c0d6fSJean-Christophe DUBOIS #if DEBUG_IMPLEMENTATION 66a50c0d6fSJean-Christophe DUBOIS # define IPRINTF(fmt, args...) \ 675ec694b5SJean-Christophe DUBOIS do { fprintf(stderr, "%s: " fmt, __func__, ##args); } while (0) 68a50c0d6fSJean-Christophe DUBOIS #else 69a50c0d6fSJean-Christophe DUBOIS # define IPRINTF(fmt, args...) do {} while (0) 70a50c0d6fSJean-Christophe DUBOIS #endif 71a50c0d6fSJean-Christophe DUBOIS 7267110c3eSJean-Christophe DUBOIS static const VMStateDescription vmstate_imx_timer_gpt = { 736783ecf1SPeter Maydell .name = "imx.gpt", 745ec694b5SJean-Christophe DUBOIS .version_id = 3, 755ec694b5SJean-Christophe DUBOIS .minimum_version_id = 3, 76a50c0d6fSJean-Christophe DUBOIS .fields = (VMStateField[]) { 7767110c3eSJean-Christophe DUBOIS VMSTATE_UINT32(cr, IMXGPTState), 7867110c3eSJean-Christophe DUBOIS VMSTATE_UINT32(pr, IMXGPTState), 7967110c3eSJean-Christophe DUBOIS VMSTATE_UINT32(sr, IMXGPTState), 8067110c3eSJean-Christophe DUBOIS VMSTATE_UINT32(ir, IMXGPTState), 8167110c3eSJean-Christophe DUBOIS VMSTATE_UINT32(ocr1, IMXGPTState), 8267110c3eSJean-Christophe DUBOIS VMSTATE_UINT32(ocr2, IMXGPTState), 8367110c3eSJean-Christophe DUBOIS VMSTATE_UINT32(ocr3, IMXGPTState), 8467110c3eSJean-Christophe DUBOIS VMSTATE_UINT32(icr1, IMXGPTState), 8567110c3eSJean-Christophe DUBOIS VMSTATE_UINT32(icr2, IMXGPTState), 8667110c3eSJean-Christophe DUBOIS VMSTATE_UINT32(cnt, IMXGPTState), 8767110c3eSJean-Christophe DUBOIS VMSTATE_UINT32(next_timeout, IMXGPTState), 8867110c3eSJean-Christophe DUBOIS VMSTATE_UINT32(next_int, IMXGPTState), 8967110c3eSJean-Christophe DUBOIS VMSTATE_UINT32(freq, IMXGPTState), 9067110c3eSJean-Christophe DUBOIS VMSTATE_PTIMER(timer, IMXGPTState), 91a50c0d6fSJean-Christophe DUBOIS VMSTATE_END_OF_LIST() 92a50c0d6fSJean-Christophe DUBOIS } 93a50c0d6fSJean-Christophe DUBOIS }; 94a50c0d6fSJean-Christophe DUBOIS 9567110c3eSJean-Christophe DUBOIS static const IMXClk imx_gpt_clocks[] = { 96a50c0d6fSJean-Christophe DUBOIS NOCLK, /* 000 No clock source */ 97a50c0d6fSJean-Christophe DUBOIS IPG, /* 001 ipg_clk, 532MHz*/ 98a50c0d6fSJean-Christophe DUBOIS IPG, /* 010 ipg_clk_highfreq */ 99a50c0d6fSJean-Christophe DUBOIS NOCLK, /* 011 not defined */ 100a50c0d6fSJean-Christophe DUBOIS CLK_32k, /* 100 ipg_clk_32k */ 101a50c0d6fSJean-Christophe DUBOIS NOCLK, /* 101 not defined */ 102a50c0d6fSJean-Christophe DUBOIS NOCLK, /* 110 not defined */ 103a50c0d6fSJean-Christophe DUBOIS NOCLK, /* 111 not defined */ 104a50c0d6fSJean-Christophe DUBOIS }; 105a50c0d6fSJean-Christophe DUBOIS 10667110c3eSJean-Christophe DUBOIS static void imx_gpt_set_freq(IMXGPTState *s) 107a50c0d6fSJean-Christophe DUBOIS { 1085ec694b5SJean-Christophe DUBOIS uint32_t clksrc = extract32(s->cr, GPT_CR_CLKSRC_SHIFT, 3); 10967110c3eSJean-Christophe DUBOIS uint32_t freq = imx_clock_frequency(s->ccm, imx_gpt_clocks[clksrc]) 1105ec694b5SJean-Christophe DUBOIS / (1 + s->pr); 1115ec694b5SJean-Christophe DUBOIS s->freq = freq; 112a50c0d6fSJean-Christophe DUBOIS 1135ec694b5SJean-Christophe DUBOIS DPRINTF("Setting clksrc %d to frequency %d\n", clksrc, freq); 114a50c0d6fSJean-Christophe DUBOIS 115a50c0d6fSJean-Christophe DUBOIS if (freq) { 116a50c0d6fSJean-Christophe DUBOIS ptimer_set_freq(s->timer, freq); 117a50c0d6fSJean-Christophe DUBOIS } 118a50c0d6fSJean-Christophe DUBOIS } 119a50c0d6fSJean-Christophe DUBOIS 12067110c3eSJean-Christophe DUBOIS static void imx_gpt_update_int(IMXGPTState *s) 121a50c0d6fSJean-Christophe DUBOIS { 1225ec694b5SJean-Christophe DUBOIS if ((s->sr & s->ir) && (s->cr & GPT_CR_EN)) { 1235ec694b5SJean-Christophe DUBOIS qemu_irq_raise(s->irq); 1245ec694b5SJean-Christophe DUBOIS } else { 1255ec694b5SJean-Christophe DUBOIS qemu_irq_lower(s->irq); 1265ec694b5SJean-Christophe DUBOIS } 127a50c0d6fSJean-Christophe DUBOIS } 128a50c0d6fSJean-Christophe DUBOIS 12967110c3eSJean-Christophe DUBOIS static uint32_t imx_gpt_update_count(IMXGPTState *s) 130a50c0d6fSJean-Christophe DUBOIS { 1315ec694b5SJean-Christophe DUBOIS s->cnt = s->next_timeout - (uint32_t)ptimer_get_count(s->timer); 1325ec694b5SJean-Christophe DUBOIS 133a50c0d6fSJean-Christophe DUBOIS return s->cnt; 134a50c0d6fSJean-Christophe DUBOIS } 135a50c0d6fSJean-Christophe DUBOIS 13667110c3eSJean-Christophe DUBOIS static inline uint32_t imx_gpt_find_limit(uint32_t count, uint32_t reg, 1375ec694b5SJean-Christophe DUBOIS uint32_t timeout) 138a50c0d6fSJean-Christophe DUBOIS { 1395ec694b5SJean-Christophe DUBOIS if ((count < reg) && (timeout > reg)) { 1405ec694b5SJean-Christophe DUBOIS timeout = reg; 1415ec694b5SJean-Christophe DUBOIS } 142a50c0d6fSJean-Christophe DUBOIS 1435ec694b5SJean-Christophe DUBOIS return timeout; 1445ec694b5SJean-Christophe DUBOIS } 1455ec694b5SJean-Christophe DUBOIS 14667110c3eSJean-Christophe DUBOIS static void imx_gpt_compute_next_timeout(IMXGPTState *s, bool event) 1475ec694b5SJean-Christophe DUBOIS { 148203d65a4SMichael Tokarev uint32_t timeout = GPT_TIMER_MAX; 1495ec694b5SJean-Christophe DUBOIS uint32_t count = 0; 1505ec694b5SJean-Christophe DUBOIS long long limit; 1515ec694b5SJean-Christophe DUBOIS 1525ec694b5SJean-Christophe DUBOIS if (!(s->cr & GPT_CR_EN)) { 1535ec694b5SJean-Christophe DUBOIS /* if not enabled just return */ 154a50c0d6fSJean-Christophe DUBOIS return; 155a50c0d6fSJean-Christophe DUBOIS } 156a50c0d6fSJean-Christophe DUBOIS 1575ec694b5SJean-Christophe DUBOIS if (event) { 1585ec694b5SJean-Christophe DUBOIS /* This is a timer event */ 1595ec694b5SJean-Christophe DUBOIS 160203d65a4SMichael Tokarev if ((s->cr & GPT_CR_FRR) && (s->next_timeout != GPT_TIMER_MAX)) { 161a50c0d6fSJean-Christophe DUBOIS /* 1625ec694b5SJean-Christophe DUBOIS * if we are in free running mode and we have not reached 163203d65a4SMichael Tokarev * the GPT_TIMER_MAX limit, then update the count 164a50c0d6fSJean-Christophe DUBOIS */ 16567110c3eSJean-Christophe DUBOIS count = imx_gpt_update_count(s); 166a50c0d6fSJean-Christophe DUBOIS } 1675ec694b5SJean-Christophe DUBOIS } else { 1685ec694b5SJean-Christophe DUBOIS /* not a timer event, then just update the count */ 1695ec694b5SJean-Christophe DUBOIS 17067110c3eSJean-Christophe DUBOIS count = imx_gpt_update_count(s); 1715ec694b5SJean-Christophe DUBOIS } 1725ec694b5SJean-Christophe DUBOIS 1735ec694b5SJean-Christophe DUBOIS /* now, find the next timeout related to count */ 1745ec694b5SJean-Christophe DUBOIS 1755ec694b5SJean-Christophe DUBOIS if (s->ir & GPT_IR_OF1IE) { 17667110c3eSJean-Christophe DUBOIS timeout = imx_gpt_find_limit(count, s->ocr1, timeout); 1775ec694b5SJean-Christophe DUBOIS } 1785ec694b5SJean-Christophe DUBOIS if (s->ir & GPT_IR_OF2IE) { 17967110c3eSJean-Christophe DUBOIS timeout = imx_gpt_find_limit(count, s->ocr2, timeout); 1805ec694b5SJean-Christophe DUBOIS } 1815ec694b5SJean-Christophe DUBOIS if (s->ir & GPT_IR_OF3IE) { 18267110c3eSJean-Christophe DUBOIS timeout = imx_gpt_find_limit(count, s->ocr3, timeout); 1835ec694b5SJean-Christophe DUBOIS } 1845ec694b5SJean-Christophe DUBOIS 1855ec694b5SJean-Christophe DUBOIS /* find the next set of interrupts to raise for next timer event */ 1865ec694b5SJean-Christophe DUBOIS 1875ec694b5SJean-Christophe DUBOIS s->next_int = 0; 1885ec694b5SJean-Christophe DUBOIS if ((s->ir & GPT_IR_OF1IE) && (timeout == s->ocr1)) { 1895ec694b5SJean-Christophe DUBOIS s->next_int |= GPT_SR_OF1; 1905ec694b5SJean-Christophe DUBOIS } 1915ec694b5SJean-Christophe DUBOIS if ((s->ir & GPT_IR_OF2IE) && (timeout == s->ocr2)) { 1925ec694b5SJean-Christophe DUBOIS s->next_int |= GPT_SR_OF2; 1935ec694b5SJean-Christophe DUBOIS } 1945ec694b5SJean-Christophe DUBOIS if ((s->ir & GPT_IR_OF3IE) && (timeout == s->ocr3)) { 1955ec694b5SJean-Christophe DUBOIS s->next_int |= GPT_SR_OF3; 1965ec694b5SJean-Christophe DUBOIS } 197203d65a4SMichael Tokarev if ((s->ir & GPT_IR_ROVIE) && (timeout == GPT_TIMER_MAX)) { 1985ec694b5SJean-Christophe DUBOIS s->next_int |= GPT_SR_ROV; 1995ec694b5SJean-Christophe DUBOIS } 2005ec694b5SJean-Christophe DUBOIS 2015ec694b5SJean-Christophe DUBOIS /* the new range to count down from */ 20267110c3eSJean-Christophe DUBOIS limit = timeout - imx_gpt_update_count(s); 2035ec694b5SJean-Christophe DUBOIS 2045ec694b5SJean-Christophe DUBOIS if (limit < 0) { 2055ec694b5SJean-Christophe DUBOIS /* 2065ec694b5SJean-Christophe DUBOIS * if we reach here, then QEMU is running too slow and we pass the 2075ec694b5SJean-Christophe DUBOIS * timeout limit while computing it. Let's deliver the interrupt 2085ec694b5SJean-Christophe DUBOIS * and compute a new limit. 2095ec694b5SJean-Christophe DUBOIS */ 2105ec694b5SJean-Christophe DUBOIS s->sr |= s->next_int; 2115ec694b5SJean-Christophe DUBOIS 21267110c3eSJean-Christophe DUBOIS imx_gpt_compute_next_timeout(s, event); 2135ec694b5SJean-Christophe DUBOIS 21467110c3eSJean-Christophe DUBOIS imx_gpt_update_int(s); 2155ec694b5SJean-Christophe DUBOIS } else { 2165ec694b5SJean-Christophe DUBOIS /* New timeout value */ 2175ec694b5SJean-Christophe DUBOIS s->next_timeout = timeout; 2185ec694b5SJean-Christophe DUBOIS 2195ec694b5SJean-Christophe DUBOIS /* reset the limit to the computed range */ 2205ec694b5SJean-Christophe DUBOIS ptimer_set_limit(s->timer, limit, 1); 2215ec694b5SJean-Christophe DUBOIS } 222a50c0d6fSJean-Christophe DUBOIS } 223a50c0d6fSJean-Christophe DUBOIS 22467110c3eSJean-Christophe DUBOIS static uint64_t imx_gpt_read(void *opaque, hwaddr offset, unsigned size) 225a50c0d6fSJean-Christophe DUBOIS { 22667110c3eSJean-Christophe DUBOIS IMXGPTState *s = IMX_GPT(opaque); 2275ec694b5SJean-Christophe DUBOIS uint32_t reg_value = 0; 2285ec694b5SJean-Christophe DUBOIS uint32_t reg = offset >> 2; 229a50c0d6fSJean-Christophe DUBOIS 2305ec694b5SJean-Christophe DUBOIS switch (reg) { 231a50c0d6fSJean-Christophe DUBOIS case 0: /* Control Register */ 2325ec694b5SJean-Christophe DUBOIS reg_value = s->cr; 2335ec694b5SJean-Christophe DUBOIS break; 234a50c0d6fSJean-Christophe DUBOIS 235a50c0d6fSJean-Christophe DUBOIS case 1: /* prescaler */ 2365ec694b5SJean-Christophe DUBOIS reg_value = s->pr; 2375ec694b5SJean-Christophe DUBOIS break; 238a50c0d6fSJean-Christophe DUBOIS 239a50c0d6fSJean-Christophe DUBOIS case 2: /* Status Register */ 2405ec694b5SJean-Christophe DUBOIS reg_value = s->sr; 2415ec694b5SJean-Christophe DUBOIS break; 242a50c0d6fSJean-Christophe DUBOIS 243a50c0d6fSJean-Christophe DUBOIS case 3: /* Interrupt Register */ 2445ec694b5SJean-Christophe DUBOIS reg_value = s->ir; 2455ec694b5SJean-Christophe DUBOIS break; 246a50c0d6fSJean-Christophe DUBOIS 247a50c0d6fSJean-Christophe DUBOIS case 4: /* Output Compare Register 1 */ 2485ec694b5SJean-Christophe DUBOIS reg_value = s->ocr1; 2495ec694b5SJean-Christophe DUBOIS break; 250a50c0d6fSJean-Christophe DUBOIS 251a50c0d6fSJean-Christophe DUBOIS case 5: /* Output Compare Register 2 */ 2525ec694b5SJean-Christophe DUBOIS reg_value = s->ocr2; 2535ec694b5SJean-Christophe DUBOIS break; 254a50c0d6fSJean-Christophe DUBOIS 255a50c0d6fSJean-Christophe DUBOIS case 6: /* Output Compare Register 3 */ 2565ec694b5SJean-Christophe DUBOIS reg_value = s->ocr3; 2575ec694b5SJean-Christophe DUBOIS break; 258a50c0d6fSJean-Christophe DUBOIS 259a50c0d6fSJean-Christophe DUBOIS case 7: /* input Capture Register 1 */ 2605ec694b5SJean-Christophe DUBOIS qemu_log_mask(LOG_UNIMP, "icr1 feature is not implemented\n"); 2615ec694b5SJean-Christophe DUBOIS reg_value = s->icr1; 2625ec694b5SJean-Christophe DUBOIS break; 263a50c0d6fSJean-Christophe DUBOIS 264a50c0d6fSJean-Christophe DUBOIS case 8: /* input Capture Register 2 */ 2655ec694b5SJean-Christophe DUBOIS qemu_log_mask(LOG_UNIMP, "icr2 feature is not implemented\n"); 2665ec694b5SJean-Christophe DUBOIS reg_value = s->icr2; 2675ec694b5SJean-Christophe DUBOIS break; 268a50c0d6fSJean-Christophe DUBOIS 269a50c0d6fSJean-Christophe DUBOIS case 9: /* cnt */ 27067110c3eSJean-Christophe DUBOIS imx_gpt_update_count(s); 2715ec694b5SJean-Christophe DUBOIS reg_value = s->cnt; 2725ec694b5SJean-Christophe DUBOIS break; 2735ec694b5SJean-Christophe DUBOIS 2745ec694b5SJean-Christophe DUBOIS default: 2755ec694b5SJean-Christophe DUBOIS IPRINTF("Bad offset %x\n", reg); 2765ec694b5SJean-Christophe DUBOIS break; 277a50c0d6fSJean-Christophe DUBOIS } 278a50c0d6fSJean-Christophe DUBOIS 27967110c3eSJean-Christophe DUBOIS DPRINTF("(%s) = 0x%08x\n", imx_gpt_reg_name(reg), reg_value); 280a50c0d6fSJean-Christophe DUBOIS 2815ec694b5SJean-Christophe DUBOIS return reg_value; 282a50c0d6fSJean-Christophe DUBOIS } 283a50c0d6fSJean-Christophe DUBOIS 28467110c3eSJean-Christophe DUBOIS static void imx_gpt_reset(DeviceState *dev) 285a50c0d6fSJean-Christophe DUBOIS { 28667110c3eSJean-Christophe DUBOIS IMXGPTState *s = IMX_GPT(dev); 287a50c0d6fSJean-Christophe DUBOIS 2885ec694b5SJean-Christophe DUBOIS /* stop timer */ 2895ec694b5SJean-Christophe DUBOIS ptimer_stop(s->timer); 2905ec694b5SJean-Christophe DUBOIS 291a50c0d6fSJean-Christophe DUBOIS /* 292a50c0d6fSJean-Christophe DUBOIS * Soft reset doesn't touch some bits; hard reset clears them 293a50c0d6fSJean-Christophe DUBOIS */ 294a50c0d6fSJean-Christophe DUBOIS s->cr &= ~(GPT_CR_EN|GPT_CR_ENMOD|GPT_CR_STOPEN|GPT_CR_DOZEN| 295a50c0d6fSJean-Christophe DUBOIS GPT_CR_WAITEN|GPT_CR_DBGEN); 296a50c0d6fSJean-Christophe DUBOIS s->sr = 0; 297a50c0d6fSJean-Christophe DUBOIS s->pr = 0; 298a50c0d6fSJean-Christophe DUBOIS s->ir = 0; 299a50c0d6fSJean-Christophe DUBOIS s->cnt = 0; 300203d65a4SMichael Tokarev s->ocr1 = GPT_TIMER_MAX; 301203d65a4SMichael Tokarev s->ocr2 = GPT_TIMER_MAX; 302203d65a4SMichael Tokarev s->ocr3 = GPT_TIMER_MAX; 303a50c0d6fSJean-Christophe DUBOIS s->icr1 = 0; 304a50c0d6fSJean-Christophe DUBOIS s->icr2 = 0; 3055ec694b5SJean-Christophe DUBOIS 306203d65a4SMichael Tokarev s->next_timeout = GPT_TIMER_MAX; 3075ec694b5SJean-Christophe DUBOIS s->next_int = 0; 3085ec694b5SJean-Christophe DUBOIS 3095ec694b5SJean-Christophe DUBOIS /* compute new freq */ 31067110c3eSJean-Christophe DUBOIS imx_gpt_set_freq(s); 3115ec694b5SJean-Christophe DUBOIS 312203d65a4SMichael Tokarev /* reset the limit to GPT_TIMER_MAX */ 313203d65a4SMichael Tokarev ptimer_set_limit(s->timer, GPT_TIMER_MAX, 1); 3145ec694b5SJean-Christophe DUBOIS 3155ec694b5SJean-Christophe DUBOIS /* if the timer is still enabled, restart it */ 3165ec694b5SJean-Christophe DUBOIS if (s->freq && (s->cr & GPT_CR_EN)) { 3175ec694b5SJean-Christophe DUBOIS ptimer_run(s->timer, 1); 3185ec694b5SJean-Christophe DUBOIS } 319a50c0d6fSJean-Christophe DUBOIS } 320a50c0d6fSJean-Christophe DUBOIS 32167110c3eSJean-Christophe DUBOIS static void imx_gpt_write(void *opaque, hwaddr offset, uint64_t value, 32267110c3eSJean-Christophe DUBOIS unsigned size) 323a50c0d6fSJean-Christophe DUBOIS { 32467110c3eSJean-Christophe DUBOIS IMXGPTState *s = IMX_GPT(opaque); 3255ec694b5SJean-Christophe DUBOIS uint32_t oldreg; 3265ec694b5SJean-Christophe DUBOIS uint32_t reg = offset >> 2; 327a50c0d6fSJean-Christophe DUBOIS 32867110c3eSJean-Christophe DUBOIS DPRINTF("(%s, value = 0x%08x)\n", imx_gpt_reg_name(reg), 3295ec694b5SJean-Christophe DUBOIS (uint32_t)value); 330a50c0d6fSJean-Christophe DUBOIS 3315ec694b5SJean-Christophe DUBOIS switch (reg) { 3325ec694b5SJean-Christophe DUBOIS case 0: 3335ec694b5SJean-Christophe DUBOIS oldreg = s->cr; 3345ec694b5SJean-Christophe DUBOIS s->cr = value & ~0x7c14; 3355ec694b5SJean-Christophe DUBOIS if (s->cr & GPT_CR_SWR) { /* force reset */ 3365ec694b5SJean-Christophe DUBOIS /* handle the reset */ 33767110c3eSJean-Christophe DUBOIS imx_gpt_reset(DEVICE(s)); 338a50c0d6fSJean-Christophe DUBOIS } else { 3395ec694b5SJean-Christophe DUBOIS /* set our freq, as the source might have changed */ 34067110c3eSJean-Christophe DUBOIS imx_gpt_set_freq(s); 3415ec694b5SJean-Christophe DUBOIS 3425ec694b5SJean-Christophe DUBOIS if ((oldreg ^ s->cr) & GPT_CR_EN) { 3435ec694b5SJean-Christophe DUBOIS if (s->cr & GPT_CR_EN) { 3445ec694b5SJean-Christophe DUBOIS if (s->cr & GPT_CR_ENMOD) { 345203d65a4SMichael Tokarev s->next_timeout = GPT_TIMER_MAX; 346203d65a4SMichael Tokarev ptimer_set_count(s->timer, GPT_TIMER_MAX); 34767110c3eSJean-Christophe DUBOIS imx_gpt_compute_next_timeout(s, false); 3485ec694b5SJean-Christophe DUBOIS } 3495ec694b5SJean-Christophe DUBOIS ptimer_run(s->timer, 1); 3505ec694b5SJean-Christophe DUBOIS } else { 3515ec694b5SJean-Christophe DUBOIS /* stop timer */ 352a50c0d6fSJean-Christophe DUBOIS ptimer_stop(s->timer); 353a50c0d6fSJean-Christophe DUBOIS } 354a50c0d6fSJean-Christophe DUBOIS } 3555ec694b5SJean-Christophe DUBOIS } 3565ec694b5SJean-Christophe DUBOIS break; 357a50c0d6fSJean-Christophe DUBOIS 358a50c0d6fSJean-Christophe DUBOIS case 1: /* Prescaler */ 359a50c0d6fSJean-Christophe DUBOIS s->pr = value & 0xfff; 36067110c3eSJean-Christophe DUBOIS imx_gpt_set_freq(s); 3615ec694b5SJean-Christophe DUBOIS break; 362a50c0d6fSJean-Christophe DUBOIS 363a50c0d6fSJean-Christophe DUBOIS case 2: /* SR */ 3645ec694b5SJean-Christophe DUBOIS s->sr &= ~(value & 0x3f); 36567110c3eSJean-Christophe DUBOIS imx_gpt_update_int(s); 3665ec694b5SJean-Christophe DUBOIS break; 367a50c0d6fSJean-Christophe DUBOIS 368a50c0d6fSJean-Christophe DUBOIS case 3: /* IR -- interrupt register */ 369a50c0d6fSJean-Christophe DUBOIS s->ir = value & 0x3f; 37067110c3eSJean-Christophe DUBOIS imx_gpt_update_int(s); 3715ec694b5SJean-Christophe DUBOIS 37267110c3eSJean-Christophe DUBOIS imx_gpt_compute_next_timeout(s, false); 3735ec694b5SJean-Christophe DUBOIS 3745ec694b5SJean-Christophe DUBOIS break; 375a50c0d6fSJean-Christophe DUBOIS 376a50c0d6fSJean-Christophe DUBOIS case 4: /* OCR1 -- output compare register */ 3775ec694b5SJean-Christophe DUBOIS s->ocr1 = value; 3785ec694b5SJean-Christophe DUBOIS 379a50c0d6fSJean-Christophe DUBOIS /* In non-freerun mode, reset count when this register is written */ 380a50c0d6fSJean-Christophe DUBOIS if (!(s->cr & GPT_CR_FRR)) { 381203d65a4SMichael Tokarev s->next_timeout = GPT_TIMER_MAX; 382203d65a4SMichael Tokarev ptimer_set_limit(s->timer, GPT_TIMER_MAX, 1); 383a50c0d6fSJean-Christophe DUBOIS } 3845ec694b5SJean-Christophe DUBOIS 3855ec694b5SJean-Christophe DUBOIS /* compute the new timeout */ 38667110c3eSJean-Christophe DUBOIS imx_gpt_compute_next_timeout(s, false); 3875ec694b5SJean-Christophe DUBOIS 3885ec694b5SJean-Christophe DUBOIS break; 389a50c0d6fSJean-Christophe DUBOIS 390a50c0d6fSJean-Christophe DUBOIS case 5: /* OCR2 -- output compare register */ 3915ec694b5SJean-Christophe DUBOIS s->ocr2 = value; 3925ec694b5SJean-Christophe DUBOIS 3935ec694b5SJean-Christophe DUBOIS /* compute the new timeout */ 39467110c3eSJean-Christophe DUBOIS imx_gpt_compute_next_timeout(s, false); 3955ec694b5SJean-Christophe DUBOIS 3965ec694b5SJean-Christophe DUBOIS break; 3975ec694b5SJean-Christophe DUBOIS 398a50c0d6fSJean-Christophe DUBOIS case 6: /* OCR3 -- output compare register */ 3995ec694b5SJean-Christophe DUBOIS s->ocr3 = value; 4005ec694b5SJean-Christophe DUBOIS 4015ec694b5SJean-Christophe DUBOIS /* compute the new timeout */ 40267110c3eSJean-Christophe DUBOIS imx_gpt_compute_next_timeout(s, false); 4035ec694b5SJean-Christophe DUBOIS 4045ec694b5SJean-Christophe DUBOIS break; 4055ec694b5SJean-Christophe DUBOIS 406a50c0d6fSJean-Christophe DUBOIS default: 4075ec694b5SJean-Christophe DUBOIS IPRINTF("Bad offset %x\n", reg); 4085ec694b5SJean-Christophe DUBOIS break; 409a50c0d6fSJean-Christophe DUBOIS } 410a50c0d6fSJean-Christophe DUBOIS } 411a50c0d6fSJean-Christophe DUBOIS 41267110c3eSJean-Christophe DUBOIS static void imx_gpt_timeout(void *opaque) 413a50c0d6fSJean-Christophe DUBOIS { 41467110c3eSJean-Christophe DUBOIS IMXGPTState *s = IMX_GPT(opaque); 415a50c0d6fSJean-Christophe DUBOIS 4165ec694b5SJean-Christophe DUBOIS DPRINTF("\n"); 417a50c0d6fSJean-Christophe DUBOIS 4185ec694b5SJean-Christophe DUBOIS s->sr |= s->next_int; 4195ec694b5SJean-Christophe DUBOIS s->next_int = 0; 420a50c0d6fSJean-Christophe DUBOIS 42167110c3eSJean-Christophe DUBOIS imx_gpt_compute_next_timeout(s, true); 4225ec694b5SJean-Christophe DUBOIS 42367110c3eSJean-Christophe DUBOIS imx_gpt_update_int(s); 4245ec694b5SJean-Christophe DUBOIS 4255ec694b5SJean-Christophe DUBOIS if (s->freq && (s->cr & GPT_CR_EN)) { 4265ec694b5SJean-Christophe DUBOIS ptimer_run(s->timer, 1); 4275ec694b5SJean-Christophe DUBOIS } 428a50c0d6fSJean-Christophe DUBOIS } 429a50c0d6fSJean-Christophe DUBOIS 43067110c3eSJean-Christophe DUBOIS static const MemoryRegionOps imx_gpt_ops = { 43167110c3eSJean-Christophe DUBOIS .read = imx_gpt_read, 43267110c3eSJean-Christophe DUBOIS .write = imx_gpt_write, 433a50c0d6fSJean-Christophe DUBOIS .endianness = DEVICE_NATIVE_ENDIAN, 434a50c0d6fSJean-Christophe DUBOIS }; 435a50c0d6fSJean-Christophe DUBOIS 436a50c0d6fSJean-Christophe DUBOIS 43767110c3eSJean-Christophe DUBOIS static void imx_gpt_realize(DeviceState *dev, Error **errp) 438a50c0d6fSJean-Christophe DUBOIS { 43967110c3eSJean-Christophe DUBOIS IMXGPTState *s = IMX_GPT(dev); 44067110c3eSJean-Christophe DUBOIS SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 441a50c0d6fSJean-Christophe DUBOIS QEMUBH *bh; 442a50c0d6fSJean-Christophe DUBOIS 44367110c3eSJean-Christophe DUBOIS sysbus_init_irq(sbd, &s->irq); 444853dca12SPaolo Bonzini memory_region_init_io(&s->iomem, OBJECT(s), &imx_gpt_ops, s, TYPE_IMX_GPT, 445a50c0d6fSJean-Christophe DUBOIS 0x00001000); 44667110c3eSJean-Christophe DUBOIS sysbus_init_mmio(sbd, &s->iomem); 447a50c0d6fSJean-Christophe DUBOIS 44867110c3eSJean-Christophe DUBOIS bh = qemu_bh_new(imx_gpt_timeout, s); 449a50c0d6fSJean-Christophe DUBOIS s->timer = ptimer_init(bh); 450a50c0d6fSJean-Christophe DUBOIS } 451a50c0d6fSJean-Christophe DUBOIS 4525ec694b5SJean-Christophe DUBOIS void imx_timerg_create(const hwaddr addr, qemu_irq irq, DeviceState *ccm) 453a50c0d6fSJean-Christophe DUBOIS { 45467110c3eSJean-Christophe DUBOIS IMXGPTState *pp; 455a50c0d6fSJean-Christophe DUBOIS DeviceState *dev; 456a50c0d6fSJean-Christophe DUBOIS 4575ec694b5SJean-Christophe DUBOIS dev = sysbus_create_simple(TYPE_IMX_GPT, addr, irq); 45867110c3eSJean-Christophe DUBOIS pp = IMX_GPT(dev); 459a50c0d6fSJean-Christophe DUBOIS pp->ccm = ccm; 460a50c0d6fSJean-Christophe DUBOIS } 461a50c0d6fSJean-Christophe DUBOIS 46267110c3eSJean-Christophe DUBOIS static void imx_gpt_class_init(ObjectClass *klass, void *data) 463a50c0d6fSJean-Christophe DUBOIS { 464a50c0d6fSJean-Christophe DUBOIS DeviceClass *dc = DEVICE_CLASS(klass); 46567110c3eSJean-Christophe DUBOIS 46667110c3eSJean-Christophe DUBOIS dc->realize = imx_gpt_realize; 46767110c3eSJean-Christophe DUBOIS dc->reset = imx_gpt_reset; 46867110c3eSJean-Christophe DUBOIS dc->vmsd = &vmstate_imx_timer_gpt; 469a50c0d6fSJean-Christophe DUBOIS dc->desc = "i.MX general timer"; 470a50c0d6fSJean-Christophe DUBOIS } 471a50c0d6fSJean-Christophe DUBOIS 47267110c3eSJean-Christophe DUBOIS static const TypeInfo imx_gpt_info = { 4735ec694b5SJean-Christophe DUBOIS .name = TYPE_IMX_GPT, 474a50c0d6fSJean-Christophe DUBOIS .parent = TYPE_SYS_BUS_DEVICE, 47567110c3eSJean-Christophe DUBOIS .instance_size = sizeof(IMXGPTState), 47667110c3eSJean-Christophe DUBOIS .class_init = imx_gpt_class_init, 477a50c0d6fSJean-Christophe DUBOIS }; 478a50c0d6fSJean-Christophe DUBOIS 47967110c3eSJean-Christophe DUBOIS static void imx_gpt_register_types(void) 480a50c0d6fSJean-Christophe DUBOIS { 48167110c3eSJean-Christophe DUBOIS type_register_static(&imx_gpt_info); 482a50c0d6fSJean-Christophe DUBOIS } 483a50c0d6fSJean-Christophe DUBOIS 48467110c3eSJean-Christophe DUBOIS type_init(imx_gpt_register_types) 485