diff options
Diffstat (limited to 'qemu/hw/timer/imx_gpt.c')
-rw-r--r-- | qemu/hw/timer/imx_gpt.c | 204 |
1 files changed, 57 insertions, 147 deletions
diff --git a/qemu/hw/timer/imx_gpt.c b/qemu/hw/timer/imx_gpt.c index 3b3101084..ab2e213a1 100644 --- a/qemu/hw/timer/imx_gpt.c +++ b/qemu/hw/timer/imx_gpt.c @@ -5,28 +5,29 @@ * Copyright (c) 2011 NICTA Pty Ltd * Originally written by Hans Jiang * Updated by Peter Chubb - * Updated by Jean-Christophe Dubois + * Updated by Jean-Christophe Dubois <jcd@tribudubois.net> * * This code is licensed under GPL version 2 or later. See * the COPYING file in the top-level directory. * */ -#include "hw/hw.h" -#include "qemu/bitops.h" -#include "qemu/timer.h" -#include "hw/ptimer.h" -#include "hw/sysbus.h" -#include "hw/arm/imx.h" +#include "qemu/osdep.h" +#include "hw/timer/imx_gpt.h" +#include "hw/misc/imx_ccm.h" #include "qemu/main-loop.h" -#define TYPE_IMX_GPT "imx.gpt" +#ifndef DEBUG_IMX_GPT +#define DEBUG_IMX_GPT 0 +#endif -/* - * Define to 1 for debug messages - */ -#define DEBUG_TIMER 0 -#if DEBUG_TIMER +#define DPRINTF(fmt, args...) \ + do { \ + if (DEBUG_IMX_GPT) { \ + fprintf(stderr, "[%s]%s: " fmt , TYPE_IMX_GPT, \ + __func__, ##args); \ + } \ + } while (0) static char const *imx_gpt_reg_name(uint32_t reg) { @@ -56,94 +57,8 @@ static char const *imx_gpt_reg_name(uint32_t reg) } } -# define DPRINTF(fmt, args...) \ - do { printf("%s: " fmt , __func__, ##args); } while (0) -#else -# define DPRINTF(fmt, args...) do {} while (0) -#endif - -/* - * Define to 1 for messages about attempts to - * access unimplemented registers or similar. - */ -#define DEBUG_IMPLEMENTATION 1 -#if DEBUG_IMPLEMENTATION -# define IPRINTF(fmt, args...) \ - do { fprintf(stderr, "%s: " fmt, __func__, ##args); } while (0) -#else -# define IPRINTF(fmt, args...) do {} while (0) -#endif - -#define IMX_GPT(obj) \ - OBJECT_CHECK(IMXGPTState, (obj), TYPE_IMX_GPT) -/* - * GPT : General purpose timer - * - * This timer counts up continuously while it is enabled, resetting itself - * to 0 when it reaches GPT_TIMER_MAX (in freerun mode) or when it - * reaches the value of one of the ocrX (in periodic mode). - */ - -#define GPT_TIMER_MAX 0XFFFFFFFFUL - -/* Control register. Not all of these bits have any effect (yet) */ -#define GPT_CR_EN (1 << 0) /* GPT Enable */ -#define GPT_CR_ENMOD (1 << 1) /* GPT Enable Mode */ -#define GPT_CR_DBGEN (1 << 2) /* GPT Debug mode enable */ -#define GPT_CR_WAITEN (1 << 3) /* GPT Wait Mode Enable */ -#define GPT_CR_DOZEN (1 << 4) /* GPT Doze mode enable */ -#define GPT_CR_STOPEN (1 << 5) /* GPT Stop Mode Enable */ -#define GPT_CR_CLKSRC_SHIFT (6) -#define GPT_CR_CLKSRC_MASK (0x7) - -#define GPT_CR_FRR (1 << 9) /* Freerun or Restart */ -#define GPT_CR_SWR (1 << 15) /* Software Reset */ -#define GPT_CR_IM1 (3 << 16) /* Input capture channel 1 mode (2 bits) */ -#define GPT_CR_IM2 (3 << 18) /* Input capture channel 2 mode (2 bits) */ -#define GPT_CR_OM1 (7 << 20) /* Output Compare Channel 1 Mode (3 bits) */ -#define GPT_CR_OM2 (7 << 23) /* Output Compare Channel 2 Mode (3 bits) */ -#define GPT_CR_OM3 (7 << 26) /* Output Compare Channel 3 Mode (3 bits) */ -#define GPT_CR_FO1 (1 << 29) /* Force Output Compare Channel 1 */ -#define GPT_CR_FO2 (1 << 30) /* Force Output Compare Channel 2 */ -#define GPT_CR_FO3 (1 << 31) /* Force Output Compare Channel 3 */ - -#define GPT_SR_OF1 (1 << 0) -#define GPT_SR_OF2 (1 << 1) -#define GPT_SR_OF3 (1 << 2) -#define GPT_SR_ROV (1 << 5) - -#define GPT_IR_OF1IE (1 << 0) -#define GPT_IR_OF2IE (1 << 1) -#define GPT_IR_OF3IE (1 << 2) -#define GPT_IR_ROVIE (1 << 5) - -typedef struct { - SysBusDevice busdev; - ptimer_state *timer; - MemoryRegion iomem; - DeviceState *ccm; - - uint32_t cr; - uint32_t pr; - uint32_t sr; - uint32_t ir; - uint32_t ocr1; - uint32_t ocr2; - uint32_t ocr3; - uint32_t icr1; - uint32_t icr2; - uint32_t cnt; - - uint32_t next_timeout; - uint32_t next_int; - - uint32_t freq; - - qemu_irq irq; -} IMXGPTState; - static const VMStateDescription vmstate_imx_timer_gpt = { - .name = "imx.gpt", + .name = TYPE_IMX_GPT, .version_id = 3, .minimum_version_id = 3, .fields = (VMStateField[]) { @@ -166,27 +81,27 @@ static const VMStateDescription vmstate_imx_timer_gpt = { }; static const IMXClk imx_gpt_clocks[] = { - NOCLK, /* 000 No clock source */ - IPG, /* 001 ipg_clk, 532MHz*/ - IPG, /* 010 ipg_clk_highfreq */ - NOCLK, /* 011 not defined */ - CLK_32k, /* 100 ipg_clk_32k */ - NOCLK, /* 101 not defined */ - NOCLK, /* 110 not defined */ - NOCLK, /* 111 not defined */ + CLK_NONE, /* 000 No clock source */ + CLK_IPG, /* 001 ipg_clk, 532MHz*/ + CLK_IPG_HIGH, /* 010 ipg_clk_highfreq */ + CLK_NONE, /* 011 not defined */ + CLK_32k, /* 100 ipg_clk_32k */ + CLK_NONE, /* 101 not defined */ + CLK_NONE, /* 110 not defined */ + CLK_NONE, /* 111 not defined */ }; static void imx_gpt_set_freq(IMXGPTState *s) { uint32_t clksrc = extract32(s->cr, GPT_CR_CLKSRC_SHIFT, 3); - uint32_t freq = imx_clock_frequency(s->ccm, imx_gpt_clocks[clksrc]) - / (1 + s->pr); - s->freq = freq; - DPRINTF("Setting clksrc %d to frequency %d\n", clksrc, freq); + s->freq = imx_ccm_get_clock_frequency(s->ccm, + imx_gpt_clocks[clksrc]) / (1 + s->pr); + + DPRINTF("Setting clksrc %d to frequency %d\n", clksrc, s->freq); - if (freq) { - ptimer_set_freq(s->timer, freq); + if (s->freq) { + ptimer_set_freq(s->timer, s->freq); } } @@ -207,7 +122,7 @@ static uint32_t imx_gpt_update_count(IMXGPTState *s) } static inline uint32_t imx_gpt_find_limit(uint32_t count, uint32_t reg, - uint32_t timeout) + uint32_t timeout) { if ((count < reg) && (timeout > reg)) { timeout = reg; @@ -219,7 +134,7 @@ static inline uint32_t imx_gpt_find_limit(uint32_t count, uint32_t reg, static void imx_gpt_compute_next_timeout(IMXGPTState *s, bool event) { uint32_t timeout = GPT_TIMER_MAX; - uint32_t count = 0; + uint32_t count; long long limit; if (!(s->cr & GPT_CR_EN)) { @@ -227,20 +142,23 @@ static void imx_gpt_compute_next_timeout(IMXGPTState *s, bool event) return; } - if (event) { - /* This is a timer event */ + /* update the count */ + count = imx_gpt_update_count(s); - if ((s->cr & GPT_CR_FRR) && (s->next_timeout != GPT_TIMER_MAX)) { - /* - * if we are in free running mode and we have not reached - * the GPT_TIMER_MAX limit, then update the count + if (event) { + /* + * This is an event (the ptimer reached 0 and stopped), and the + * timer counter is now equal to s->next_timeout. + */ + if (!(s->cr & GPT_CR_FRR) && (count == s->ocr1)) { + /* We are in restart mode and we crossed the compare channel 1 + * value. We need to reset the counter to 0. */ - count = imx_gpt_update_count(s); + count = s->cnt = s->next_timeout = 0; + } else if (count == GPT_TIMER_MAX) { + /* We reached GPT_TIMER_MAX so we need to rollover */ + count = s->cnt = s->next_timeout = 0; } - } else { - /* not a timer event, then just update the count */ - - count = imx_gpt_update_count(s); } /* now, find the next timeout related to count */ @@ -298,9 +216,8 @@ static uint64_t imx_gpt_read(void *opaque, hwaddr offset, unsigned size) { IMXGPTState *s = IMX_GPT(opaque); uint32_t reg_value = 0; - uint32_t reg = offset >> 2; - switch (reg) { + switch (offset >> 2) { case 0: /* Control Register */ reg_value = s->cr; break; @@ -330,12 +247,14 @@ static uint64_t imx_gpt_read(void *opaque, hwaddr offset, unsigned size) break; case 7: /* input Capture Register 1 */ - qemu_log_mask(LOG_UNIMP, "icr1 feature is not implemented\n"); + qemu_log_mask(LOG_UNIMP, "[%s]%s: icr1 feature is not implemented\n", + TYPE_IMX_GPT, __func__); reg_value = s->icr1; break; case 8: /* input Capture Register 2 */ - qemu_log_mask(LOG_UNIMP, "icr2 feature is not implemented\n"); + qemu_log_mask(LOG_UNIMP, "[%s]%s: icr2 feature is not implemented\n", + TYPE_IMX_GPT, __func__); reg_value = s->icr2; break; @@ -345,11 +264,12 @@ static uint64_t imx_gpt_read(void *opaque, hwaddr offset, unsigned size) break; default: - IPRINTF("Bad offset %x\n", reg); + qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%" + HWADDR_PRIx "\n", TYPE_IMX_GPT, __func__, offset); break; } - DPRINTF("(%s) = 0x%08x\n", imx_gpt_reg_name(reg), reg_value); + DPRINTF("(%s) = 0x%08x\n", imx_gpt_reg_name(offset >> 2), reg_value); return reg_value; } @@ -396,12 +316,11 @@ static void imx_gpt_write(void *opaque, hwaddr offset, uint64_t value, { IMXGPTState *s = IMX_GPT(opaque); uint32_t oldreg; - uint32_t reg = offset >> 2; - DPRINTF("(%s, value = 0x%08x)\n", imx_gpt_reg_name(reg), + DPRINTF("(%s, value = 0x%08x)\n", imx_gpt_reg_name(offset >> 2), (uint32_t)value); - switch (reg) { + switch (offset >> 2) { case 0: oldreg = s->cr; s->cr = value & ~0x7c14; @@ -477,7 +396,8 @@ static void imx_gpt_write(void *opaque, hwaddr offset, uint64_t value, break; default: - IPRINTF("Bad offset %x\n", reg); + qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%" + HWADDR_PRIx "\n", TYPE_IMX_GPT, __func__, offset); break; } } @@ -522,16 +442,6 @@ static void imx_gpt_realize(DeviceState *dev, Error **errp) s->timer = ptimer_init(bh); } -void imx_timerg_create(const hwaddr addr, qemu_irq irq, DeviceState *ccm) -{ - IMXGPTState *pp; - DeviceState *dev; - - dev = sysbus_create_simple(TYPE_IMX_GPT, addr, irq); - pp = IMX_GPT(dev); - pp->ccm = ccm; -} - static void imx_gpt_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); |