diff mbox

[PULL,2/8] i.MX: Implement a more complete version of the GPT timer.

Message ID 1372184516-32397-3-git-send-email-peter.maydell@linaro.org
State New
Headers show

Commit Message

Peter Maydell June 25, 2013, 6:21 p.m. UTC
From: Jean-Christophe DUBOIS <jcd@tribudubois.net>

* implement compare 1 2 and 3 registers
* simplify Debug printf

Signed-off-by: Jean-Christophe DUBOIS <jcd@tribudubois.net>
Message-id: 1369898943-1993-2-git-send-email-jcd@tribudubois.net
Reviewed-by: Peter Chubb <peter.chubb@nicta.com.au>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/timer/imx_gpt.c |  443 +++++++++++++++++++++++++++++++---------------------
 1 file changed, 269 insertions(+), 174 deletions(-)

Comments

Paolo Bonzini June 25, 2013, 6:42 p.m. UTC | #1
Il 25/06/2013 20:21, Peter Maydell ha scritto:
> @@ -416,7 +513,7 @@ static int imx_timerg_init(SysBusDevice *dev)
>  
>      sysbus_init_irq(dev, &s->irq);
>      memory_region_init_io(&s->iomem, &imx_timerg_ops,
> -                          s, "imxg-timer",
> +                          s, TYPE_IMX_GPT,
>                            0x00001000);
>      sysbus_init_mmio(dev, &s->iomem);
>  

There was some agreement that this is not a good change.

Paolo
Peter Maydell June 25, 2013, 8:53 p.m. UTC | #2
On 25 June 2013 19:42, Paolo Bonzini <pbonzini@redhat.com> wrote:
> Il 25/06/2013 20:21, Peter Maydell ha scritto:
>> @@ -416,7 +513,7 @@ static int imx_timerg_init(SysBusDevice *dev)
>>
>>      sysbus_init_irq(dev, &s->irq);
>>      memory_region_init_io(&s->iomem, &imx_timerg_ops,
>> -                          s, "imxg-timer",
>> +                          s, TYPE_IMX_GPT,
>>                            0x00001000);
>>      sysbus_init_mmio(dev, &s->iomem);
>>
>
> There was some agreement that this is not a good change.

I agree (and more so regarding the use of the macro in the
vmstate name), but nobody actually posted any comment to
that effect against any of the versions of this patch that
got sent out for review...

thanks
-- PMM
Paolo Bonzini June 26, 2013, 6:56 a.m. UTC | #3
Il 25/06/2013 22:53, Peter Maydell ha scritto:
> On 25 June 2013 19:42, Paolo Bonzini <pbonzini@redhat.com> wrote:
>> Il 25/06/2013 20:21, Peter Maydell ha scritto:
>>> @@ -416,7 +513,7 @@ static int imx_timerg_init(SysBusDevice *dev)
>>>
>>>      sysbus_init_irq(dev, &s->irq);
>>>      memory_region_init_io(&s->iomem, &imx_timerg_ops,
>>> -                          s, "imxg-timer",
>>> +                          s, TYPE_IMX_GPT,
>>>                            0x00001000);
>>>      sysbus_init_mmio(dev, &s->iomem);
>>>
>>
>> There was some agreement that this is not a good change.
> 
> I agree (and more so regarding the use of the macro in the
> vmstate name), but nobody actually posted any comment to
> that effect against any of the versions of this patch that
> got sent out for review...

Yeah, the timing was bad... Can you post a revert, though?

Paolo
Jean-Christophe Dubois June 26, 2013, 7:08 a.m. UTC | #4
For my own education, could you elaborate on the reason this is not a good change? 

Thanks. 

JC 

----- Mail original -----

> Il 25/06/2013 22:53, Peter Maydell ha scritto:
> > On 25 June 2013 19:42, Paolo Bonzini <pbonzini@redhat.com> wrote:
> >> Il 25/06/2013 20:21, Peter Maydell ha scritto:
> >>> @@ -416,7 +513,7 @@ static int imx_timerg_init(SysBusDevice *dev)
> >>>
> >>> sysbus_init_irq(dev, &s->irq);
> >>> memory_region_init_io(&s->iomem, &imx_timerg_ops,
> >>> - s, "imxg-timer",
> >>> + s, TYPE_IMX_GPT,
> >>> 0x00001000);
> >>> sysbus_init_mmio(dev, &s->iomem);
> >>>
> >>
> >> There was some agreement that this is not a good change.
> >
> > I agree (and more so regarding the use of the macro in the
> > vmstate name), but nobody actually posted any comment to
> > that effect against any of the versions of this patch that
> > got sent out for review...

> Yeah, the timing was bad... Can you post a revert, though?

> Paolo
Paolo Bonzini June 26, 2013, 7:11 a.m. UTC | #5
Il 26/06/2013 09:08, jcd@tribudubois.net ha scritto:
> For my own education, could you elaborate on the reason this is not a
> good change?

Quoting from http://article.gmane.org/gmane.comp.emulators.qemu/218078:

> The MemoryRegion name is free text that can be changed as desired and
> doesn't need to match the type name.
> 
> The TYPE_* constant serves to keep consistency between usages of the
> string literal but does not prohibit changing its value.
> 
> The VMStateDescription should thus not use the TYPE_* constant because
> it must not ever change for live migration. Renaming a type is a valid
> thing to do if there is no command line compatibility to keep (think
> board-level "xlnx.foo" -> "xlnx,foo").

Paolo
Jean-Christophe Dubois June 26, 2013, 7:17 a.m. UTC | #6
Thanks for the info. 

Is this consolidated into some "developper documentation" somewhere (a wiki, ...)? 

JC 

----- Mail original -----

> Il 26/06/2013 09:08, jcd@tribudubois.net ha scritto:
> > For my own education, could you elaborate on the reason this is not a
> > good change?

> Quoting from http://article.gmane.org/gmane.comp.emulators.qemu/218078:

> > The MemoryRegion name is free text that can be changed as desired and
> > doesn't need to match the type name.
> >
> > The TYPE_* constant serves to keep consistency between usages of the
> > string literal but does not prohibit changing its value.
> >
> > The VMStateDescription should thus not use the TYPE_* constant because
> > it must not ever change for live migration. Renaming a type is a valid
> > thing to do if there is no command line compatibility to keep (think
> > board-level "xlnx.foo" -> "xlnx,foo").

> Paolo
Peter Crosthwaite June 26, 2013, 7:21 a.m. UTC | #7
Hi

On Wed, Jun 26, 2013 at 4:56 PM, Paolo Bonzini <pbonzini@redhat.com> wrote:
> Il 25/06/2013 22:53, Peter Maydell ha scritto:
>> On 25 June 2013 19:42, Paolo Bonzini <pbonzini@redhat.com> wrote:
>>> Il 25/06/2013 20:21, Peter Maydell ha scritto:
>>>> @@ -416,7 +513,7 @@ static int imx_timerg_init(SysBusDevice *dev)
>>>>
>>>>      sysbus_init_irq(dev, &s->irq);
>>>>      memory_region_init_io(&s->iomem, &imx_timerg_ops,
>>>> -                          s, "imxg-timer",
>>>> +                          s, TYPE_IMX_GPT,
>>>>                            0x00001000);
>>>>      sysbus_init_mmio(dev, &s->iomem);
>>>>
>>>
>>> There was some agreement that this is not a good change.
>>
>> I agree (and more so regarding the use of the macro in the
>> vmstate name), but nobody actually posted any comment to
>> that effect against any of the versions of this patch that
>> got sent out for review...
>
> Yeah, the timing was bad... Can you post a revert, though?
>

The original string being replaced was a poor choice as well. IIUC the
consensus was string field of the memory regions is supposed to
indicate the purpose of the memory region for the device. Good
examples would be "Control regs" or "MMIO". Naming the memory region
after the device type is a redundancy as that info will come via
memory region owners.

So rather than revert could you just choose something more descriptive?

Regards,
Peter

> Paolo
>
Jean-Christophe Dubois June 26, 2013, 6:58 p.m. UTC | #8
On 06/26/2013 09:21 AM, Peter Crosthwaite wrote:
> Hi
>
> On Wed, Jun 26, 2013 at 4:56 PM, Paolo Bonzini <pbonzini@redhat.com> wrote:
>> Il 25/06/2013 22:53, Peter Maydell ha scritto:
>>> On 25 June 2013 19:42, Paolo Bonzini <pbonzini@redhat.com> wrote:
>>>> Il 25/06/2013 20:21, Peter Maydell ha scritto:
>>>>> @@ -416,7 +513,7 @@ static int imx_timerg_init(SysBusDevice *dev)
>>>>>
>>>>>       sysbus_init_irq(dev, &s->irq);
>>>>>       memory_region_init_io(&s->iomem, &imx_timerg_ops,
>>>>> -                          s, "imxg-timer",
>>>>> +                          s, TYPE_IMX_GPT,
>>>>>                             0x00001000);
>>>>>       sysbus_init_mmio(dev, &s->iomem);
>>>>>
>>>> There was some agreement that this is not a good change.
>>> I agree (and more so regarding the use of the macro in the
>>> vmstate name), but nobody actually posted any comment to
>>> that effect against any of the versions of this patch that
>>> got sent out for review...
>> Yeah, the timing was bad... Can you post a revert, though?
>>
> The original string being replaced was a poor choice as well. IIUC the
> consensus was string field of the memory regions is supposed to
> indicate the purpose of the memory region for the device. Good
> examples would be "Control regs" or "MMIO". Naming the memory region
> after the device type is a redundancy as that info will come via
> memory region owners.
>
> So rather than revert could you just choose something more descriptive?
Peter (Maydell),

How do you want to work this out?

Do you revert it and we start over?

Or should I provide a patch on top of the actual file to change the 
"wrong name"?

Please advise.

JC

>
> Regards,
> Peter
>
>> Paolo
>>
>
Jean-Christophe Dubois June 26, 2013, 9:13 p.m. UTC | #9
On 06/26/2013 08:58 PM, Jean-Christophe DUBOIS wrote:
> On 06/26/2013 09:21 AM, Peter Crosthwaite wrote:
>> Hi
>>
>> On Wed, Jun 26, 2013 at 4:56 PM, Paolo Bonzini <pbonzini@redhat.com> 
>> wrote:
>>> Il 25/06/2013 22:53, Peter Maydell ha scritto:
>>>> On 25 June 2013 19:42, Paolo Bonzini <pbonzini@redhat.com> wrote:
>>>>> Il 25/06/2013 20:21, Peter Maydell ha scritto:
>>>>>> @@ -416,7 +513,7 @@ static int imx_timerg_init(SysBusDevice *dev)
>>>>>>
>>>>>>       sysbus_init_irq(dev, &s->irq);
>>>>>>       memory_region_init_io(&s->iomem, &imx_timerg_ops,
>>>>>> -                          s, "imxg-timer",
>>>>>> +                          s, TYPE_IMX_GPT,
>>>>>>                             0x00001000);
>>>>>>       sysbus_init_mmio(dev, &s->iomem);
>>>>>>
>>>>> There was some agreement that this is not a good change.
>>>> I agree (and more so regarding the use of the macro in the
>>>> vmstate name), but nobody actually posted any comment to
>>>> that effect against any of the versions of this patch that
>>>> got sent out for review...
>>> Yeah, the timing was bad... Can you post a revert, though?
>>>
>> The original string being replaced was a poor choice as well. IIUC the
>> consensus was string field of the memory regions is supposed to
>> indicate the purpose of the memory region for the device. Good
>> examples would be "Control regs" or "MMIO". Naming the memory region
>> after the device type is a redundancy as that info will come via
>> memory region owners.
>>
>> So rather than revert could you just choose something more descriptive?
> Peter (Maydell),
>
> How do you want to work this out?
>
> Do you revert it and we start over?
>
> Or should I provide a patch on top of the actual file to change the 
> "wrong name"?
>
> Please advise.

I browsed through the various timer implementations in the hw/timer 
directory and I was not able to spot one that would follow the 
convention you indicated.

Could you point me to a "good citizen" example?

JC

>
> JC
>
>>
>> Regards,
>> Peter
>>
>>> Paolo
>>>
>>
>
>
>
Paolo Bonzini June 26, 2013, 9:18 p.m. UTC | #10
Il 26/06/2013 23:13, Jean-Christophe DUBOIS ha scritto:
> On 06/26/2013 08:58 PM, Jean-Christophe DUBOIS wrote:
>> On 06/26/2013 09:21 AM, Peter Crosthwaite wrote:
>>> Hi
>>>
>>> On Wed, Jun 26, 2013 at 4:56 PM, Paolo Bonzini <pbonzini@redhat.com>
>>> wrote:
>>>> Il 25/06/2013 22:53, Peter Maydell ha scritto:
>>>>> On 25 June 2013 19:42, Paolo Bonzini <pbonzini@redhat.com> wrote:
>>>>>> Il 25/06/2013 20:21, Peter Maydell ha scritto:
>>>>>>> @@ -416,7 +513,7 @@ static int imx_timerg_init(SysBusDevice *dev)
>>>>>>>
>>>>>>>       sysbus_init_irq(dev, &s->irq);
>>>>>>>       memory_region_init_io(&s->iomem, &imx_timerg_ops,
>>>>>>> -                          s, "imxg-timer",
>>>>>>> +                          s, TYPE_IMX_GPT,
>>>>>>>                             0x00001000);
>>>>>>>       sysbus_init_mmio(dev, &s->iomem);
>>>>>>>
>>>>>> There was some agreement that this is not a good change.
>>>>> I agree (and more so regarding the use of the macro in the
>>>>> vmstate name), but nobody actually posted any comment to
>>>>> that effect against any of the versions of this patch that
>>>>> got sent out for review...
>>>> Yeah, the timing was bad... Can you post a revert, though?
>>>>
>>> The original string being replaced was a poor choice as well. IIUC the
>>> consensus was string field of the memory regions is supposed to
>>> indicate the purpose of the memory region for the device. Good
>>> examples would be "Control regs" or "MMIO". Naming the memory region
>>> after the device type is a redundancy as that info will come via
>>> memory region owners.
>>>
>>> So rather than revert could you just choose something more descriptive?
>> Peter (Maydell),
>>
>> How do you want to work this out?
>>
>> Do you revert it and we start over?
>>
>> Or should I provide a patch on top of the actual file to change the
>> "wrong name"?
>>
>> Please advise.
> 
> I browsed through the various timer implementations in the hw/timer
> directory and I was not able to spot one that would follow the
> convention you indicated.
> 
> Could you point me to a "good citizen" example?

Here is one example (hw/pci-host/piix.c):

    memory_region_init_io(&s->conf_mem, &pci_host_conf_le_ops, s,
                          "pci-conf-idx", 4);
    sysbus_add_io(dev, 0xcf8, &s->conf_mem);
    sysbus_init_ioports(&s->busdev, 0xcf8, 4);

    memory_region_init_io(&s->data_mem, &pci_host_data_le_ops, s,
                          "pci-conf-data", 4);
    sysbus_add_io(dev, 0xcfc, &s->data_mem);
    sysbus_init_ioports(&s->busdev, 0xcfc, 4);

Just reverting the changes to memory regions and vmstate names is enough
for now.

Paolo
Jean-Christophe Dubois June 26, 2013, 9:57 p.m. UTC | #11
On 06/26/2013 11:18 PM, Paolo Bonzini wrote:
> Il 26/06/2013 23:13, Jean-Christophe DUBOIS ha scritto:
>> On 06/26/2013 08:58 PM, Jean-Christophe DUBOIS wrote:
>>> On 06/26/2013 09:21 AM, Peter Crosthwaite wrote:
>>>> Hi
>>>>
>>>> On Wed, Jun 26, 2013 at 4:56 PM, Paolo Bonzini <pbonzini@redhat.com>
>>>> wrote:
>>>>> Il 25/06/2013 22:53, Peter Maydell ha scritto:
>>>>>> On 25 June 2013 19:42, Paolo Bonzini <pbonzini@redhat.com> wrote:
>>>>>>> Il 25/06/2013 20:21, Peter Maydell ha scritto:
>>>>>>>> @@ -416,7 +513,7 @@ static int imx_timerg_init(SysBusDevice *dev)
>>>>>>>>
>>>>>>>>        sysbus_init_irq(dev, &s->irq);
>>>>>>>>        memory_region_init_io(&s->iomem, &imx_timerg_ops,
>>>>>>>> -                          s, "imxg-timer",
>>>>>>>> +                          s, TYPE_IMX_GPT,
>>>>>>>>                              0x00001000);
>>>>>>>>        sysbus_init_mmio(dev, &s->iomem);
>>>>>>>>
>>>>>>> There was some agreement that this is not a good change.
>>>>>> I agree (and more so regarding the use of the macro in the
>>>>>> vmstate name), but nobody actually posted any comment to
>>>>>> that effect against any of the versions of this patch that
>>>>>> got sent out for review...
>>>>> Yeah, the timing was bad... Can you post a revert, though?
>>>>>
>>>> The original string being replaced was a poor choice as well. IIUC the
>>>> consensus was string field of the memory regions is supposed to
>>>> indicate the purpose of the memory region for the device. Good
>>>> examples would be "Control regs" or "MMIO". Naming the memory region
>>>> after the device type is a redundancy as that info will come via
>>>> memory region owners.
>>>>
>>>> So rather than revert could you just choose something more descriptive?
>>> Peter (Maydell),
>>>
>>> How do you want to work this out?
>>>
>>> Do you revert it and we start over?
>>>
>>> Or should I provide a patch on top of the actual file to change the
>>> "wrong name"?
>>>
>>> Please advise.
>> I browsed through the various timer implementations in the hw/timer
>> directory and I was not able to spot one that would follow the
>> convention you indicated.
>>
>> Could you point me to a "good citizen" example?
> Here is one example (hw/pci-host/piix.c):
>
>      memory_region_init_io(&s->conf_mem, &pci_host_conf_le_ops, s,
>                            "pci-conf-idx", 4);
>      sysbus_add_io(dev, 0xcf8, &s->conf_mem);
>      sysbus_init_ioports(&s->busdev, 0xcf8, 4);
>
>      memory_region_init_io(&s->data_mem, &pci_host_data_le_ops, s,
>                            "pci-conf-data", 4);
>      sysbus_add_io(dev, 0xcfc, &s->data_mem);
>      sysbus_init_ioports(&s->busdev, 0xcfc, 4);
>
> Just reverting the changes to memory regions and vmstate names is enough
> for now.

I tried to change the memory region name for the timer registers to 
something not prepended wit the device name (I choose "regs") and here 
is the result in the qemu console (I changes both EPIT and GPT timers). 
We went from:

    (qemu) info mtree
    memory
    0000000000000000-7ffffffffffffffe (prio 0, RW): system
       000000001fffc000-000000001fffffff (prio 0, RW): kzm.sram
       0000000043f90000-0000000043f90fff (prio 0, RW): imx-serial
       0000000043f94000-0000000043f94fff (prio 0, RW): imx-serial
       0000000053f80000-0000000053f80fff (prio 0, RW): imx_ccm
       0000000053f90000-0000000053f90fff (prio 0, RW): imx.gpt
       0000000053f94000-0000000053f94fff (prio 0, RW): imx.epit
       0000000053f98000-0000000053f98fff (prio 0, RW): imx.epit
       0000000068000000-0000000068000fff (prio 0, RW): imx_avic
       0000000080000000-0000000083ffffff (prio 0, RW): kzm.ram
       0000000088000000-000000008bffffff (prio 0, RW): alias ram.alias
    @kzm.ram 0000000000000000-0000000003ffffff
       00000000b6000000-00000000b60000ff (prio 0, RW): lan9118-mmio
    I/O
    0000000000000000-000000000000ffff (prio 0, RW): io
    aliases
    kzm.ram
    0000000080000000-0000000083ffffff (prio 0, RW): kzm.ram
    (qemu)

to:

    (qemu) info mtree
    memory
    0000000000000000-7ffffffffffffffe (prio 0, RW): system
       000000001fffc000-000000001fffffff (prio 0, RW): kzm.sram
       0000000043f90000-0000000043f90fff (prio 0, RW): imx-serial
       0000000043f94000-0000000043f94fff (prio 0, RW): imx-serial
       0000000053f80000-0000000053f80fff (prio 0, RW): imx_ccm
       0000000053f90000-0000000053f90fff (prio 0, RW): regs
       0000000053f94000-0000000053f94fff (prio 0, RW): regs
       0000000053f98000-0000000053f98fff (prio 0, RW): regs
       0000000068000000-0000000068000fff (prio 0, RW): imx_avic
       0000000080000000-0000000083ffffff (prio 0, RW): kzm.ram
       0000000088000000-000000008bffffff (prio 0, RW): alias ram.alias
    @kzm.ram 0000000000000000-0000000003ffffff
       00000000b6000000-00000000b60000ff (prio 0, RW): lan9118-mmio
    I/O
    0000000000000000-000000000000ffff (prio 0, RW): io
    aliases
    kzm.ram
    0000000080000000-0000000083ffffff (prio 0, RW): kzm.ram
    (qemu)


Names don't feel really useful in the second case as they are 
indistinguishable. Is the consensus around "generic" names (like MMIO or 
"Ctrl regs") without adding reference to the device a good one for all 
platforms?

JC


>
> Paolo
>
>
Peter Maydell June 26, 2013, 10:15 p.m. UTC | #12
On 26 June 2013 22:57, Jean-Christophe DUBOIS <jcd@tribudubois.net> wrote:
> Names don't feel really useful in the second case as they are
> indistinguishable. Is the consensus around "generic" names (like MMIO or
> "Ctrl regs") without adding reference to the device a good one for all
> platforms?

Just leave the memory region and vmstate names as they
were before your patches.

(Personally I think it's entirely fine to include the device
name in the memory region name. These strings are for debugging,
so if I print region->name in my debugger it's much more helpful
if it says "imx-serial" than if it just says "regs".)

-- PMM
Andreas Färber June 26, 2013, 10:17 p.m. UTC | #13
Am 26.06.2013 23:57, schrieb Jean-Christophe DUBOIS:
> On 06/26/2013 11:18 PM, Paolo Bonzini wrote:
>> Il 26/06/2013 23:13, Jean-Christophe DUBOIS ha scritto:
>>> On 06/26/2013 08:58 PM, Jean-Christophe DUBOIS wrote:
>>>> On 06/26/2013 09:21 AM, Peter Crosthwaite wrote:
>>>>> Hi
>>>>>
>>>>> On Wed, Jun 26, 2013 at 4:56 PM, Paolo Bonzini <pbonzini@redhat.com>
>>>>> wrote:
>>>>>> Il 25/06/2013 22:53, Peter Maydell ha scritto:
>>>>>>> On 25 June 2013 19:42, Paolo Bonzini <pbonzini@redhat.com> wrote:
>>>>>>>> Il 25/06/2013 20:21, Peter Maydell ha scritto:
>>>>>>>>> @@ -416,7 +513,7 @@ static int imx_timerg_init(SysBusDevice *dev)
>>>>>>>>>
>>>>>>>>>       sysbus_init_irq(dev, &s->irq);
>>>>>>>>>       memory_region_init_io(&s->iomem, &imx_timerg_ops,
>>>>>>>>> -                          s, "imxg-timer",
>>>>>>>>> +                          s, TYPE_IMX_GPT,
>>>>>>>>>                             0x00001000);
>>>>>>>>>       sysbus_init_mmio(dev, &s->iomem);
>>>>>>>>>
>>>>>>>> There was some agreement that this is not a good change.
>>>>>>> I agree (and more so regarding the use of the macro in the
>>>>>>> vmstate name), but nobody actually posted any comment to
>>>>>>> that effect against any of the versions of this patch that
>>>>>>> got sent out for review...
>>>>>> Yeah, the timing was bad... Can you post a revert, though?
>>>>>>
>>>>> The original string being replaced was a poor choice as well. IIUC the
>>>>> consensus was string field of the memory regions is supposed to
>>>>> indicate the purpose of the memory region for the device. Good
>>>>> examples would be "Control regs" or "MMIO". Naming the memory region
>>>>> after the device type is a redundancy as that info will come via
>>>>> memory region owners.
>>>>>
>>>>> So rather than revert could you just choose something more descriptive?
>>>> Peter (Maydell),
>>>>
>>>> How do you want to work this out?
>>>>
>>>> Do you revert it and we start over?
>>>>
>>>> Or should I provide a patch on top of the actual file to change the
>>>> "wrong name"?
>>>>
>>>> Please advise.
>>> I browsed through the various timer implementations in the hw/timer
>>> directory and I was not able to spot one that would follow the
>>> convention you indicated.
>>>
>>> Could you point me to a "good citizen" example?
>> Here is one example (hw/pci-host/piix.c):
>>
>>     memory_region_init_io(&s->conf_mem, &pci_host_conf_le_ops, s,
>>                           "pci-conf-idx", 4);
>>     sysbus_add_io(dev, 0xcf8, &s->conf_mem);
>>     sysbus_init_ioports(&s->busdev, 0xcf8, 4);
>>
>>     memory_region_init_io(&s->data_mem, &pci_host_data_le_ops, s,
>>                           "pci-conf-data", 4);
>>     sysbus_add_io(dev, 0xcfc, &s->data_mem);
>>     sysbus_init_ioports(&s->busdev, 0xcfc, 4);
>>
>> Just reverting the changes to memory regions and vmstate names is enough
>> for now.
> 
> I tried to change the memory region name for the timer registers to
> something not prepended wit the device name (I choose "regs") and here
> is the result in the qemu console (I changes both EPIT and GPT timers).
> We went from:
> 
>     (qemu) info mtree
>     memory
>     0000000000000000-7ffffffffffffffe (prio 0, RW): system
>       000000001fffc000-000000001fffffff (prio 0, RW): kzm.sram
>       0000000043f90000-0000000043f90fff (prio 0, RW): imx-serial
>       0000000043f94000-0000000043f94fff (prio 0, RW): imx-serial
>       0000000053f80000-0000000053f80fff (prio 0, RW): imx_ccm
>       0000000053f90000-0000000053f90fff (prio 0, RW): imx.gpt
>       0000000053f94000-0000000053f94fff (prio 0, RW): imx.epit
>       0000000053f98000-0000000053f98fff (prio 0, RW): imx.epit
>       0000000068000000-0000000068000fff (prio 0, RW): imx_avic
>       0000000080000000-0000000083ffffff (prio 0, RW): kzm.ram
>       0000000088000000-000000008bffffff (prio 0, RW): alias ram.alias
>     @kzm.ram 0000000000000000-0000000003ffffff
>       00000000b6000000-00000000b60000ff (prio 0, RW): lan9118-mmio
>     I/O
>     0000000000000000-000000000000ffff (prio 0, RW): io
>     aliases
>     kzm.ram
>     0000000080000000-0000000083ffffff (prio 0, RW): kzm.ram
>     (qemu)
> 
> to:
> 
>     (qemu) info mtree
>     memory
>     0000000000000000-7ffffffffffffffe (prio 0, RW): system
>       000000001fffc000-000000001fffffff (prio 0, RW): kzm.sram
>       0000000043f90000-0000000043f90fff (prio 0, RW): imx-serial
>       0000000043f94000-0000000043f94fff (prio 0, RW): imx-serial
>       0000000053f80000-0000000053f80fff (prio 0, RW): imx_ccm
>       0000000053f90000-0000000053f90fff (prio 0, RW): regs
>       0000000053f94000-0000000053f94fff (prio 0, RW): regs
>       0000000053f98000-0000000053f98fff (prio 0, RW): regs
>       0000000068000000-0000000068000fff (prio 0, RW): imx_avic
>       0000000080000000-0000000083ffffff (prio 0, RW): kzm.ram
>       0000000088000000-000000008bffffff (prio 0, RW): alias ram.alias
>     @kzm.ram 0000000000000000-0000000003ffffff
>       00000000b6000000-00000000b60000ff (prio 0, RW): lan9118-mmio
>     I/O
>     0000000000000000-000000000000ffff (prio 0, RW): io
>     aliases
>     kzm.ram
>     0000000080000000-0000000083ffffff (prio 0, RW): kzm.ram
>     (qemu)
> 
> 
> Names don't feel really useful in the second case as they are
> indistinguishable. Is the consensus around "generic" names (like MMIO or
> "Ctrl regs") without adding reference to the device a good one for all
> platforms?

Paolo's series adds the MemoryRegion owner but hasn't been merged yet.
Just revert the names so that Paolo's series applies cleanly. Any name
changes can then still be done as follow-ups.

Andreas
Jean-Christophe Dubois June 26, 2013, 10:32 p.m. UTC | #14
On 06/27/2013 12:15 AM, Peter Maydell wrote:
> On 26 June 2013 22:57, Jean-Christophe DUBOIS <jcd@tribudubois.net> wrote:
>> Names don't feel really useful in the second case as they are
>> indistinguishable. Is the consensus around "generic" names (like MMIO or
>> "Ctrl regs") without adding reference to the device a good one for all
>> platforms?
> Just leave the memory region and vmstate names as they
> were before your patches.

OK, I will.

Now, please notice that the EPIT timer has been changed recently (on 
main line) with the exact same code model as the one proposed in this 
patch. So it is not on par either with any consensus that might have 
been made on VMState or memory region naming.

JC

>
> (Personally I think it's entirely fine to include the device
> name in the memory region name. These strings are for debugging,
> so if I print region->name in my debugger it's much more helpful
> if it says "imx-serial" than if it just says "regs".)
>
> -- PMM
>
Peter Maydell June 27, 2013, 10:46 a.m. UTC | #15
On 26 June 2013 23:32, Jean-Christophe DUBOIS <jcd@tribudubois.net> wrote:
> On 06/27/2013 12:15 AM, Peter Maydell wrote:
>> Just leave the memory region and vmstate names as they
>> were before your patches.

> OK, I will.
>
> Now, please notice that the EPIT timer has been changed recently (on main
> line) with the exact same code model as the one proposed in this patch. So
> it is not on par either with any consensus that might have been made on
> VMState or memory region naming.

Since Anthony's now applied this pullreq, I'll just send
out a fresh patch which corrects these (and also which
fixes some other devices which were also using type name
macros in vmstate).

thanks
-- PMM
diff mbox

Patch

diff --git a/hw/timer/imx_gpt.c b/hw/timer/imx_gpt.c
index d8c4f0b..ecf6e53 100644
--- a/hw/timer/imx_gpt.c
+++ b/hw/timer/imx_gpt.c
@@ -5,6 +5,7 @@ 
  * Copyright (c) 2011 NICTA Pty Ltd
  * Originally written by Hans Jiang
  * Updated by Peter Chubb
+ * Updated by Jean-Christophe Dubois
  *
  * This code is licensed under GPL version 2 or later.  See
  * the COPYING file in the top-level directory.
@@ -18,10 +19,44 @@ 
 #include "hw/sysbus.h"
 #include "hw/arm/imx.h"
 
-//#define DEBUG_TIMER 1
-#ifdef DEBUG_TIMER
+#define TYPE_IMX_GPT "imx.gpt"
+
+/*
+ * Define to 1 for debug messages
+ */
+#define DEBUG_TIMER 0
+#if DEBUG_TIMER
+
+static char const *imx_timerg_reg_name(uint32_t reg)
+{
+    switch (reg) {
+    case 0:
+        return "CR";
+    case 1:
+        return "PR";
+    case 2:
+        return "SR";
+    case 3:
+        return "IR";
+    case 4:
+        return "OCR1";
+    case 5:
+        return "OCR2";
+    case 6:
+        return "OCR3";
+    case 7:
+        return "ICR1";
+    case 8:
+        return "ICR2";
+    case 9:
+        return "CNT";
+    default:
+        return "[?]";
+    }
+}
+
 #  define DPRINTF(fmt, args...) \
-      do { printf("imx_timer: " fmt , ##args); } while (0)
+          do { printf("%s: " fmt , __func__, ##args); } while (0)
 #else
 #  define DPRINTF(fmt, args...) do {} while (0)
 #endif
@@ -33,7 +68,7 @@ 
 #define DEBUG_IMPLEMENTATION 1
 #if DEBUG_IMPLEMENTATION
 #  define IPRINTF(fmt, args...)                                         \
-    do  { fprintf(stderr, "imx_timer: " fmt, ##args); } while (0)
+          do { fprintf(stderr, "%s: " fmt, __func__, ##args); } while (0)
 #else
 #  define IPRINTF(fmt, args...) do {} while (0)
 #endif
@@ -43,16 +78,7 @@ 
  *
  * This timer counts up continuously while it is enabled, resetting itself
  * to 0 when it reaches TIMER_MAX (in freerun mode) or when it
- * reaches the value of ocr1 (in periodic mode).  WE simulate this using a
- * QEMU ptimer counting down from ocr1 and reloading from ocr1 in
- * periodic mode, or counting from ocr1 to zero, then TIMER_MAX - ocr1.
- * waiting_rov is set when counting from TIMER_MAX.
- *
- * In the real hardware, there are three comparison registers that can
- * trigger interrupts, and compare channel 1 can be used to
- * force-reset the timer. However, this is a `bare-bones'
- * implementation: only what Linux 3.x uses has been implemented
- * (free-running timer from 0 to OCR1 or TIMER_MAX) .
+ * reaches the value of one of the ocrX (in periodic mode).
  */
 
 #define TIMER_MAX  0XFFFFFFFFUL
@@ -79,9 +105,13 @@ 
 #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 {
@@ -101,15 +131,19 @@  typedef struct {
     uint32_t icr2;
     uint32_t cnt;
 
-    uint32_t waiting_rov;
+    uint32_t next_timeout;
+    uint32_t next_int;
+
+    uint32_t freq;
+
     qemu_irq irq;
 } IMXTimerGState;
 
 static const VMStateDescription vmstate_imx_timerg = {
-    .name = "imx-timerg",
-    .version_id = 2,
-    .minimum_version_id = 2,
-    .minimum_version_id_old = 2,
+    .name = TYPE_IMX_GPT,
+    .version_id = 3,
+    .minimum_version_id = 3,
+    .minimum_version_id_old = 3,
     .fields      = (VMStateField[]) {
         VMSTATE_UINT32(cr, IMXTimerGState),
         VMSTATE_UINT32(pr, IMXTimerGState),
@@ -121,7 +155,9 @@  static const VMStateDescription vmstate_imx_timerg = {
         VMSTATE_UINT32(icr1, IMXTimerGState),
         VMSTATE_UINT32(icr2, IMXTimerGState),
         VMSTATE_UINT32(cnt, IMXTimerGState),
-        VMSTATE_UINT32(waiting_rov, IMXTimerGState),
+        VMSTATE_UINT32(next_timeout, IMXTimerGState),
+        VMSTATE_UINT32(next_int, IMXTimerGState),
+        VMSTATE_UINT32(freq, IMXTimerGState),
         VMSTATE_PTIMER(timer, IMXTimerGState),
         VMSTATE_END_OF_LIST()
     }
@@ -138,16 +174,14 @@  static const IMXClk imx_timerg_clocks[] = {
     NOCLK,    /* 111 not defined */
 };
 
-
 static void imx_timerg_set_freq(IMXTimerGState *s)
 {
-    int clksrc;
-    uint32_t freq;
-
-    clksrc = (s->cr >> GPT_CR_CLKSRC_SHIFT) & GPT_CR_CLKSRC_MASK;
-    freq = imx_clock_frequency(s->ccm, imx_timerg_clocks[clksrc]) / (1 + s->pr);
+    uint32_t clksrc = extract32(s->cr, GPT_CR_CLKSRC_SHIFT, 3);
+    uint32_t freq = imx_clock_frequency(s->ccm, imx_timerg_clocks[clksrc])
+                                                / (1 + s->pr);
+    s->freq = freq;
 
-    DPRINTF("Setting gtimer clksrc %d to frequency %d\n", clksrc, freq);
+    DPRINTF("Setting clksrc %d to frequency %d\n", clksrc, freq);
 
     if (freq) {
         ptimer_set_freq(s->timer, freq);
@@ -156,111 +190,176 @@  static void imx_timerg_set_freq(IMXTimerGState *s)
 
 static void imx_timerg_update(IMXTimerGState *s)
 {
-    uint32_t flags = s->sr & s->ir & (GPT_SR_OF1 | GPT_SR_ROV);
-
-    DPRINTF("g-timer SR: %s %s IR=%s %s, %s\n",
-            s->sr & GPT_SR_OF1 ? "OF1" : "",
-            s->sr & GPT_SR_ROV ? "ROV" : "",
-            s->ir & GPT_SR_OF1 ? "OF1" : "",
-            s->ir & GPT_SR_ROV ? "ROV" : "",
-            s->cr & GPT_CR_EN ? "CR_EN" : "Not Enabled");
-
-    qemu_set_irq(s->irq, (s->cr & GPT_CR_EN) && flags);
+    if ((s->sr & s->ir) && (s->cr & GPT_CR_EN)) {
+        qemu_irq_raise(s->irq);
+    } else {
+        qemu_irq_lower(s->irq);
+    }
 }
 
 static uint32_t imx_timerg_update_counts(IMXTimerGState *s)
 {
-    uint64_t target = s->waiting_rov ? TIMER_MAX : s->ocr1;
-    uint64_t cnt = ptimer_get_count(s->timer);
-    s->cnt = target - cnt;
+    s->cnt = s->next_timeout - (uint32_t)ptimer_get_count(s->timer);
+
     return s->cnt;
 }
 
-static void imx_timerg_reload(IMXTimerGState *s, uint32_t timeout)
+static inline uint32_t imx_timerg_find_limit(uint32_t count, uint32_t reg,
+                                             uint32_t timeout)
 {
-    uint64_t diff_cnt;
+    if ((count < reg) && (timeout > reg)) {
+        timeout = reg;
+    }
+
+    return timeout;
+}
 
-    if (!(s->cr & GPT_CR_FRR)) {
-        IPRINTF("IMX_timerg_reload --- called in reset-mode\n");
+static void imx_timerg_compute_next_timeout(IMXTimerGState *s, bool event)
+{
+    uint32_t timeout = TIMER_MAX;
+    uint32_t count = 0;
+    long long limit;
+
+    if (!(s->cr & GPT_CR_EN)) {
+        /* if not enabled just return */
         return;
     }
 
-    /*
-     * For small timeouts, qemu sometimes runs too slow.
-     * Better deliver a late interrupt than none.
-     *
-     * In Reset mode (FRR bit clear)
-     * the ptimer reloads itself from OCR1;
-     * in free-running mode we need to fake
-     * running from 0 to ocr1 to TIMER_MAX
-     */
-    if (timeout > s->cnt) {
-        diff_cnt = timeout - s->cnt;
+    if (event) {
+        /* This is a timer event  */
+
+        if ((s->cr & GPT_CR_FRR)  && (s->next_timeout != TIMER_MAX)) {
+            /*
+             * if we are in free running mode and we have not reached
+             * the TIMER_MAX limit, then update the count
+             */
+            count = imx_timerg_update_counts(s);
+        }
     } else {
-        diff_cnt = 0;
+        /* not a timer event, then just update the count */
+
+        count = imx_timerg_update_counts(s);
+    }
+
+    /* now, find the next timeout related to count */
+
+    if (s->ir & GPT_IR_OF1IE) {
+        timeout = imx_timerg_find_limit(count, s->ocr1, timeout);
+    }
+    if (s->ir & GPT_IR_OF2IE) {
+        timeout = imx_timerg_find_limit(count, s->ocr2, timeout);
+    }
+    if (s->ir & GPT_IR_OF3IE) {
+        timeout = imx_timerg_find_limit(count, s->ocr3, timeout);
+    }
+
+    /* find the next set of interrupts to raise for next timer event */
+
+    s->next_int = 0;
+    if ((s->ir & GPT_IR_OF1IE) && (timeout == s->ocr1)) {
+        s->next_int |= GPT_SR_OF1;
+    }
+    if ((s->ir & GPT_IR_OF2IE) && (timeout == s->ocr2)) {
+        s->next_int |= GPT_SR_OF2;
+    }
+    if ((s->ir & GPT_IR_OF3IE) && (timeout == s->ocr3)) {
+        s->next_int |= GPT_SR_OF3;
+    }
+    if ((s->ir & GPT_IR_ROVIE) && (timeout == TIMER_MAX)) {
+        s->next_int |= GPT_SR_ROV;
+    }
+
+    /* the new range to count down from */
+    limit = timeout - imx_timerg_update_counts(s);
+
+    if (limit < 0) {
+        /*
+         * if we reach here, then QEMU is running too slow and we pass the
+         * timeout limit while computing it. Let's deliver the interrupt
+         * and compute a new limit.
+         */
+        s->sr |= s->next_int;
+
+        imx_timerg_compute_next_timeout(s, event);
+
+        imx_timerg_update(s);
+    } else {
+        /* New timeout value */
+        s->next_timeout = timeout;
+
+        /* reset the limit to the computed range */
+        ptimer_set_limit(s->timer, limit, 1);
     }
-    ptimer_set_count(s->timer, diff_cnt);
 }
 
 static uint64_t imx_timerg_read(void *opaque, hwaddr offset,
                                 unsigned size)
 {
     IMXTimerGState *s = (IMXTimerGState *)opaque;
+    uint32_t reg_value = 0;
+    uint32_t reg = offset >> 2;
 
-    DPRINTF("g-read(offset=%x)", (unsigned int)(offset >> 2));
-    switch (offset >> 2) {
+    switch (reg) {
     case 0: /* Control Register */
-        DPRINTF(" cr = %x\n", s->cr);
-        return s->cr;
+        reg_value = s->cr;
+        break;
 
     case 1: /* prescaler */
-        DPRINTF(" pr = %x\n", s->pr);
-        return s->pr;
+        reg_value = s->pr;
+        break;
 
     case 2: /* Status Register */
-        DPRINTF(" sr = %x\n", s->sr);
-        return s->sr;
+        reg_value = s->sr;
+        break;
 
     case 3: /* Interrupt Register */
-        DPRINTF(" ir = %x\n", s->ir);
-        return s->ir;
+        reg_value = s->ir;
+        break;
 
     case 4: /* Output Compare Register 1 */
-        DPRINTF(" ocr1 = %x\n", s->ocr1);
-        return s->ocr1;
+        reg_value = s->ocr1;
+        break;
 
     case 5: /* Output Compare Register 2 */
-        DPRINTF(" ocr2 = %x\n", s->ocr2);
-        return s->ocr2;
+        reg_value = s->ocr2;
+        break;
 
     case 6: /* Output Compare Register 3 */
-        DPRINTF(" ocr3 = %x\n", s->ocr3);
-        return s->ocr3;
+        reg_value = s->ocr3;
+        break;
 
     case 7: /* input Capture Register 1 */
-        DPRINTF(" icr1 = %x\n", s->icr1);
-        return s->icr1;
+        qemu_log_mask(LOG_UNIMP, "icr1 feature is not implemented\n");
+        reg_value = s->icr1;
+        break;
 
     case 8: /* input Capture Register 2 */
-        DPRINTF(" icr2 = %x\n", s->icr2);
-        return s->icr2;
+        qemu_log_mask(LOG_UNIMP, "icr2 feature is not implemented\n");
+        reg_value = s->icr2;
+        break;
 
     case 9: /* cnt */
         imx_timerg_update_counts(s);
-        DPRINTF(" cnt = %x\n", s->cnt);
-        return s->cnt;
+        reg_value = s->cnt;
+        break;
+
+    default:
+        IPRINTF("Bad offset %x\n", reg);
+        break;
     }
 
-    IPRINTF("imx_timerg_read: Bad offset %x\n",
-            (int)offset >> 2);
+    DPRINTF("(%s) = 0x%08x\n", imx_timerg_reg_name(reg), reg_value);
 
-    return 0;
+    return reg_value;
 }
 
 static void imx_timerg_reset(DeviceState *dev)
 {
     IMXTimerGState *s = container_of(dev, IMXTimerGState, busdev.qdev);
 
+    /* stop timer */
+    ptimer_stop(s->timer);
+
     /*
      * Soft reset doesn't touch some bits; hard reset clears them
      */
@@ -275,89 +374,110 @@  static void imx_timerg_reset(DeviceState *dev)
     s->ocr3 = TIMER_MAX;
     s->icr1 = 0;
     s->icr2 = 0;
-    ptimer_stop(s->timer);
-    ptimer_set_limit(s->timer, TIMER_MAX, 1);
-    ptimer_set_count(s->timer, TIMER_MAX);
+
+    s->next_timeout = TIMER_MAX;
+    s->next_int = 0;
+
+    /* compute new freq */
     imx_timerg_set_freq(s);
+
+    /* reset the limit to TIMER_MAX */
+    ptimer_set_limit(s->timer, TIMER_MAX, 1);
+
+    /* if the timer is still enabled, restart it */
+    if (s->freq && (s->cr & GPT_CR_EN)) {
+        ptimer_run(s->timer, 1);
+    }
 }
 
 static void imx_timerg_write(void *opaque, hwaddr offset,
                              uint64_t value, unsigned size)
 {
     IMXTimerGState *s = (IMXTimerGState *)opaque;
-    DPRINTF("g-write(offset=%x, value = 0x%x)\n", (unsigned int)offset >> 2,
-            (unsigned int)value);
-
-    switch (offset >> 2) {
-    case 0: {
-        uint32_t oldcr = s->cr;
-        /* CR */
-        if (value & GPT_CR_SWR) { /* force reset */
-            value &= ~GPT_CR_SWR;
-            imx_timerg_reset(&s->busdev.qdev);
-            imx_timerg_update(s);
-        }
-
-        s->cr = value & ~0x7c00;
-        imx_timerg_set_freq(s);
-        if ((oldcr ^ value) & GPT_CR_EN) {
-            if (value & GPT_CR_EN) {
-                if (value & GPT_CR_ENMOD) {
-                    ptimer_set_count(s->timer, s->ocr1);
-                    s->cnt = 0;
+    uint32_t oldreg;
+    uint32_t reg = offset >> 2;
+
+    DPRINTF("(%s, value = 0x%08x)\n", imx_timerg_reg_name(reg),
+            (uint32_t)value);
+
+    switch (reg) {
+    case 0:
+        oldreg = s->cr;
+        s->cr = value & ~0x7c14;
+        if (s->cr & GPT_CR_SWR) { /* force reset */
+            /* handle the reset */
+            imx_timerg_reset(DEVICE(s));
+        } else {
+            /* set our freq, as the source might have changed */
+            imx_timerg_set_freq(s);
+
+            if ((oldreg ^ s->cr) & GPT_CR_EN) {
+                if (s->cr & GPT_CR_EN) {
+                    if (s->cr & GPT_CR_ENMOD) {
+                        s->next_timeout = TIMER_MAX;
+                        ptimer_set_count(s->timer, TIMER_MAX);
+                        imx_timerg_compute_next_timeout(s, false);
+                    }
+                    ptimer_run(s->timer, 1);
+                } else {
+                    /* stop timer */
+                    ptimer_stop(s->timer);
                 }
-                ptimer_run(s->timer,
-                           (value & GPT_CR_FRR) && (s->ocr1 != TIMER_MAX));
-            } else {
-                ptimer_stop(s->timer);
-            };
+            }
         }
-        return;
-    }
+        break;
 
     case 1: /* Prescaler */
         s->pr = value & 0xfff;
         imx_timerg_set_freq(s);
-        return;
+        break;
 
     case 2: /* SR */
-        /*
-         * No point in implementing the status register bits to do with
-         * external interrupt sources.
-         */
-        value &= GPT_SR_OF1 | GPT_SR_ROV;
-        s->sr &= ~value;
+        s->sr &= ~(value & 0x3f);
         imx_timerg_update(s);
-        return;
+        break;
 
     case 3: /* IR -- interrupt register */
         s->ir = value & 0x3f;
         imx_timerg_update(s);
-        return;
+
+        imx_timerg_compute_next_timeout(s, false);
+
+        break;
 
     case 4: /* OCR1 -- output compare register */
+        s->ocr1 = value;
+
         /* In non-freerun mode, reset count when this register is written */
         if (!(s->cr & GPT_CR_FRR)) {
-            s->waiting_rov = 0;
-            ptimer_set_limit(s->timer, value, 1);
-        } else {
-            imx_timerg_update_counts(s);
-            if (value > s->cnt) {
-                s->waiting_rov = 0;
-                imx_timerg_reload(s, value);
-            } else {
-                s->waiting_rov = 1;
-                imx_timerg_reload(s, TIMER_MAX - s->cnt);
-            }
+            s->next_timeout = TIMER_MAX;
+            ptimer_set_limit(s->timer, TIMER_MAX, 1);
         }
-        s->ocr1 = value;
-        return;
+
+        /* compute the new timeout */
+        imx_timerg_compute_next_timeout(s, false);
+
+        break;
 
     case 5: /* OCR2 -- output compare register */
+        s->ocr2 = value;
+
+        /* compute the new timeout */
+        imx_timerg_compute_next_timeout(s, false);
+
+        break;
+
     case 6: /* OCR3 -- output compare register */
+        s->ocr3 = value;
+
+        /* compute the new timeout */
+        imx_timerg_compute_next_timeout(s, false);
+
+        break;
+
     default:
-        IPRINTF("imx_timerg_write: Bad offset %x\n",
-                (int)offset >> 2);
+        IPRINTF("Bad offset %x\n", reg);
+        break;
     }
 }
 
@@ -365,41 +485,18 @@  static void imx_timerg_timeout(void *opaque)
 {
     IMXTimerGState *s = (IMXTimerGState *)opaque;
 
-    DPRINTF("imx_timerg_timeout, waiting rov=%d\n", s->waiting_rov);
-    if (s->cr & GPT_CR_FRR) {
-        /*
-         * Free running timer from 0 -> TIMERMAX
-         * Generates interrupt at TIMER_MAX and at cnt==ocr1
-         * If ocr1 == TIMER_MAX, then no need to reload timer.
-         */
-        if (s->ocr1 == TIMER_MAX) {
-            DPRINTF("s->ocr1 == TIMER_MAX, FRR\n");
-            s->sr |= GPT_SR_OF1 | GPT_SR_ROV;
-            imx_timerg_update(s);
-            return;
-        }
+    DPRINTF("\n");
 
-        if (s->waiting_rov) {
-            /*
-             * We were waiting for cnt==TIMER_MAX
-             */
-            s->sr |= GPT_SR_ROV;
-            s->waiting_rov = 0;
-            s->cnt = 0;
-            imx_timerg_reload(s, s->ocr1);
-        } else {
-            /* Must have got a cnt==ocr1 timeout. */
-            s->sr |= GPT_SR_OF1;
-            s->cnt = s->ocr1;
-            s->waiting_rov = 1;
-            imx_timerg_reload(s, TIMER_MAX);
-        }
-        imx_timerg_update(s);
-        return;
-    }
+    s->sr |= s->next_int;
+    s->next_int = 0;
+
+    imx_timerg_compute_next_timeout(s, true);
 
-    s->sr |= GPT_SR_OF1;
     imx_timerg_update(s);
+
+    if (s->freq && (s->cr & GPT_CR_EN)) {
+        ptimer_run(s->timer, 1);
+    }
 }
 
 static const MemoryRegionOps imx_timerg_ops = {
@@ -416,7 +513,7 @@  static int imx_timerg_init(SysBusDevice *dev)
 
     sysbus_init_irq(dev, &s->irq);
     memory_region_init_io(&s->iomem, &imx_timerg_ops,
-                          s, "imxg-timer",
+                          s, TYPE_IMX_GPT,
                           0x00001000);
     sysbus_init_mmio(dev, &s->iomem);
 
@@ -428,14 +525,12 @@  static int imx_timerg_init(SysBusDevice *dev)
     return 0;
 }
 
-void imx_timerg_create(const hwaddr addr,
-                              qemu_irq irq,
-                              DeviceState *ccm)
+void imx_timerg_create(const hwaddr addr, qemu_irq irq, DeviceState *ccm)
 {
     IMXTimerGState *pp;
     DeviceState *dev;
 
-    dev = sysbus_create_simple("imx_timerg", addr, irq);
+    dev = sysbus_create_simple(TYPE_IMX_GPT, addr, irq);
     pp = container_of(dev, IMXTimerGState, busdev.qdev);
     pp->ccm = ccm;
 }
@@ -451,7 +546,7 @@  static void imx_timerg_class_init(ObjectClass *klass, void *data)
 }
 
 static const TypeInfo imx_timerg_info = {
-    .name = "imx_timerg",
+    .name = TYPE_IMX_GPT,
     .parent = TYPE_SYS_BUS_DEVICE,
     .instance_size = sizeof(IMXTimerGState),
     .class_init = imx_timerg_class_init,