* [Qemu-devel] [PATCH] integrator/cp: add support for REFCNT register @ 2013-11-05 11:41 Jan Petrouš 2013-11-05 13:54 ` Peter Maydell 0 siblings, 1 reply; 7+ messages in thread From: Jan Petrouš @ 2013-11-05 11:41 UTC (permalink / raw) To: qemu-devel [-- Attachment #1.1: Type: text/plain, Size: 1111 bytes --] Linux kernel from version 3.4 requires CM_REFCNT register for sched timer for Integrator/CP board (integrator_defconfig). See http://infocenter.arm.com/help/topic/com.arm.doc.dui0138e/ch04s06s11.html Signed-off-by: Jan Petrous <jan.petrous@tieto.com> --- hw/arm/integratorcp.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/hw/arm/integratorcp.c b/hw/arm/integratorcp.c index c44b2a4..f419764 100644 --- a/hw/arm/integratorcp.c +++ b/hw/arm/integratorcp.c @@ -83,8 +83,11 @@ static uint64_t integratorcm_read(void *opaque, hwaddr offset, case 9: /* CM_INIT */ return s->cm_init; case 10: /* CM_REFCT */ - /* ??? High frequency timer. */ - hw_error("integratorcm_read: CM_REFCT"); + /* This register, CM_REFCNT, provides a 32-bit count value. + * The count increments at the fixed reference clock frequency of 24MHz + * and can be used as a real-time counter. + */ + return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 24, 1000); case 12: /* CM_FLAGS */ return s->cm_flags; case 14: /* CM_NVFLAGS */ -- 1.7.11.3 [-- Attachment #1.2: Type: text/html, Size: 1775 bytes --] [-- Attachment #2: 0001-integrator-cp-add-support-for-REFCNT-register.patch --] [-- Type: text/x-patch, Size: 1327 bytes --] From a4f7f6220df71a7c7540a6722cc5f96c7d061e28 Mon Sep 17 00:00:00 2001 From: Jan Petrous <jan.petrous@tieto.com> Date: Tue, 5 Nov 2013 12:13:57 +0100 Subject: [PATCH] integrator/cp: add support for REFCNT register Linux kernel from version 3.4 requires CM_REFCNT register for sched timer for Integrator/CP board (integrator_defconfig). See http://infocenter.arm.com/help/topic/com.arm.doc.dui0138e/ch04s06s11.html Signed-off-by: Jan Petrous <jan.petrous@tieto.com> --- hw/arm/integratorcp.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/hw/arm/integratorcp.c b/hw/arm/integratorcp.c index c44b2a4..f419764 100644 --- a/hw/arm/integratorcp.c +++ b/hw/arm/integratorcp.c @@ -83,8 +83,11 @@ static uint64_t integratorcm_read(void *opaque, hwaddr offset, case 9: /* CM_INIT */ return s->cm_init; case 10: /* CM_REFCT */ - /* ??? High frequency timer. */ - hw_error("integratorcm_read: CM_REFCT"); + /* This register, CM_REFCNT, provides a 32-bit count value. + * The count increments at the fixed reference clock frequency of 24MHz + * and can be used as a real-time counter. + */ + return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 24, 1000); case 12: /* CM_FLAGS */ return s->cm_flags; case 14: /* CM_NVFLAGS */ -- 1.7.11.3 ^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [Qemu-devel] [PATCH] integrator/cp: add support for REFCNT register 2013-11-05 11:41 [Qemu-devel] [PATCH] integrator/cp: add support for REFCNT register Jan Petrouš @ 2013-11-05 13:54 ` Peter Maydell 2013-11-05 14:44 ` Jan Petrouš 0 siblings, 1 reply; 7+ messages in thread From: Peter Maydell @ 2013-11-05 13:54 UTC (permalink / raw) To: Jan Petrouš; +Cc: QEMU Developers On 5 November 2013 11:41, Jan Petrouš <jan.petrous@tieto.com> wrote: > Linux kernel from version 3.4 requires CM_REFCNT register for sched timer > for Integrator/CP board (integrator_defconfig). > > See > http://infocenter.arm.com/help/topic/com.arm.doc.dui0138e/ch04s06s11.html > > Signed-off-by: Jan Petrous <jan.petrous@tieto.com> Hi; thanks for this patch. (I have to wonder why on earth people are still messing with kernel functionality for such an ancient devboard :-)). > diff --git a/hw/arm/integratorcp.c b/hw/arm/integratorcp.c > index c44b2a4..f419764 100644 > --- a/hw/arm/integratorcp.c > +++ b/hw/arm/integratorcp.c > @@ -83,8 +83,11 @@ static uint64_t integratorcm_read(void *opaque, hwaddr > offset, > case 9: /* CM_INIT */ > return s->cm_init; > case 10: /* CM_REFCT */ could you fix this comment to add the 'N' to CM_REFCNT while you're changing this bit of code, please? > - /* ??? High frequency timer. */ > - hw_error("integratorcm_read: CM_REFCT"); > + /* This register, CM_REFCNT, provides a 32-bit count value. > + * The count increments at the fixed reference clock frequency of 24MHz > + * and can be used as a real-time counter. > + */ The indent here doesn't look right, I think you have hardcoded tabs here rather than spaces. If you run your patch through scripts/checkpatch.pl it should catch this sort of mistake. > + return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 24, 1000); > case 12: /* CM_FLAGS */ > return s->cm_flags; > case 14: /* CM_NVFLAGS */ The spec says that this register resets to zero, so I think it would be good to implement that: put a uint32_t cm_refcnt_offset in the IntegratorCMState struct, initialize it with the initial value of muldiv64(etc) in integratorcm_init(), and then in integratorcm_read() return (uint32_t)muldiv64(etc) - cm_refcnt_offset for the register read. (We don't actually implement a proper reset function in this device at the moment, but putting in the offset field gives us a marker for doing it right if/when we add a reset function later on.) thanks -- PMM ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [Qemu-devel] [PATCH] integrator/cp: add support for REFCNT register 2013-11-05 13:54 ` Peter Maydell @ 2013-11-05 14:44 ` Jan Petrouš 2013-11-05 14:56 ` Peter Maydell 0 siblings, 1 reply; 7+ messages in thread From: Jan Petrouš @ 2013-11-05 14:44 UTC (permalink / raw) To: Peter Maydell; +Cc: QEMU Developers [-- Attachment #1.1: Type: text/plain, Size: 4876 bytes --] Hi Peter. On 5 November 2013 14:54, Peter Maydell <peter.maydell@linaro.org> wrote: > > On 5 November 2013 11:41, Jan Petrouš <jan.petrous@tieto.com> wrote: > > Linux kernel from version 3.4 requires CM_REFCNT register for sched timer > > for Integrator/CP board (integrator_defconfig). > > > > See > > http://infocenter.arm.com/help/topic/com.arm.doc.dui0138e/ch04s06s11.html > > > > Signed-off-by: Jan Petrous <jan.petrous@tieto.com> > > Hi; thanks for this patch. (I have to wonder why on earth > people are still messing with kernel functionality for such > an ancient devboard :-)). > Hehe, duno, but when I started learning QEMU the Integrator devboard looked for me the nice start-up point = very simple to understand and only very basic, but still core, device list. And when I moved from precompiled kernels (downloaded from internet) to my own ones I found the issue with default kernel configuration. And because it can help to not fool somebody later I decided to release patch :) > > > diff --git a/hw/arm/integratorcp.c b/hw/arm/integratorcp.c > > index c44b2a4..f419764 100644 > > --- a/hw/arm/integratorcp.c > > +++ b/hw/arm/integratorcp.c > > @@ -83,8 +83,11 @@ static uint64_t integratorcm_read(void *opaque, hwaddr > > offset, > > case 9: /* CM_INIT */ > > return s->cm_init; > > case 10: /* CM_REFCT */ > > could you fix this comment to add the 'N' to CM_REFCNT while > you're changing this bit of code, please? Done. > > > > - /* ??? High frequency timer. */ > > - hw_error("integratorcm_read: CM_REFCT"); > > + /* This register, CM_REFCNT, provides a 32-bit count value. > > + * The count increments at the fixed reference clock frequency of 24MHz > > + * and can be used as a real-time counter. > > + */ > > The indent here doesn't look right, I think you have > hardcoded tabs here rather than spaces. If you run your > patch through scripts/checkpatch.pl it should catch this > sort of mistake. > Yes, you are right. My fault. Fixed now. > > > + return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 24, 1000); > > case 12: /* CM_FLAGS */ > > return s->cm_flags; > > case 14: /* CM_NVFLAGS */ > > The spec says that this register resets to zero, so I think > it would be good to implement that: put a uint32_t cm_refcnt_offset > in the IntegratorCMState struct, initialize it with the initial > value of muldiv64(etc) in integratorcm_init(), and then in > integratorcm_read() return (uint32_t)muldiv64(etc) - cm_refcnt_offset > for the register read. > Added too. > > (We don't actually implement a proper reset function in this device > at the moment, but putting in the offset field gives us a marker > for doing it right if/when we add a reset function later on.) > > thanks > -- PMM Here is my next version: Linux kernel from version 3.4 requires CM_REFCNT register for sched timer for Integrator/CP board (integrator_defconfig). See http://infocenter.arm.com/help/topic/com.arm.doc.dui0138e/ch04s06s11.html Signed-off-by: Jan Petrous <jan.petrous@tieto.com> --- hw/arm/integratorcp.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/hw/arm/integratorcp.c b/hw/arm/integratorcp.c index c44b2a4..a759689 100644 --- a/hw/arm/integratorcp.c +++ b/hw/arm/integratorcp.c @@ -36,6 +36,7 @@ typedef struct IntegratorCMState { uint32_t cm_init; uint32_t cm_flags; uint32_t cm_nvflags; + uint32_t cm_refcnt_offset; uint32_t int_level; uint32_t irq_enabled; uint32_t fiq_enabled; @@ -82,9 +83,13 @@ static uint64_t integratorcm_read(void *opaque, hwaddr offset, return s->cm_sdram; case 9: /* CM_INIT */ return s->cm_init; - case 10: /* CM_REFCT */ - /* ??? High frequency timer. */ - hw_error("integratorcm_read: CM_REFCT"); + case 10: /* CM_REFCNT */ + /* This register, CM_REFCNT, provides a 32-bit count value. + * The count increments at the fixed reference clock frequency of 24MHz + * and can be used as a real-time counter. + */ + return (uint32_t)muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 24, + 1000) - s->cm_refcnt_offset; case 12: /* CM_FLAGS */ return s->cm_flags; case 14: /* CM_NVFLAGS */ @@ -257,6 +262,8 @@ static int integratorcm_init(SysBusDevice *dev) } memcpy(integrator_spd + 73, "QEMU-MEMORY", 11); s->cm_init = 0x00000112; + s->cm_refcnt_offset = muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 24, + 1000); memory_region_init_ram(&s->flash, OBJECT(s), "integrator.flash", 0x100000); vmstate_register_ram_global(&s->flash); -- 1.7.11.3 [-- Attachment #1.2: Type: text/html, Size: 6560 bytes --] [-- Attachment #2: 0001-integrator-cp-add-support-for-REFCNT-register.patch --] [-- Type: text/x-patch, Size: 2132 bytes --] From ff26b99b586f5633fc7b876f75e5a5271e141563 Mon Sep 17 00:00:00 2001 From: Jan Petrous <jan.petrous@tieto.com> Date: Tue, 5 Nov 2013 12:13:57 +0100 Subject: [PATCH] integrator/cp: add support for REFCNT register Linux kernel from version 3.4 requires CM_REFCNT register for sched timer for Integrator/CP board (integrator_defconfig). See http://infocenter.arm.com/help/topic/com.arm.doc.dui0138e/ch04s06s11.html Signed-off-by: Jan Petrous <jan.petrous@tieto.com> --- hw/arm/integratorcp.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/hw/arm/integratorcp.c b/hw/arm/integratorcp.c index c44b2a4..a759689 100644 --- a/hw/arm/integratorcp.c +++ b/hw/arm/integratorcp.c @@ -36,6 +36,7 @@ typedef struct IntegratorCMState { uint32_t cm_init; uint32_t cm_flags; uint32_t cm_nvflags; + uint32_t cm_refcnt_offset; uint32_t int_level; uint32_t irq_enabled; uint32_t fiq_enabled; @@ -82,9 +83,13 @@ static uint64_t integratorcm_read(void *opaque, hwaddr offset, return s->cm_sdram; case 9: /* CM_INIT */ return s->cm_init; - case 10: /* CM_REFCT */ - /* ??? High frequency timer. */ - hw_error("integratorcm_read: CM_REFCT"); + case 10: /* CM_REFCNT */ + /* This register, CM_REFCNT, provides a 32-bit count value. + * The count increments at the fixed reference clock frequency of 24MHz + * and can be used as a real-time counter. + */ + return (uint32_t)muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 24, + 1000) - s->cm_refcnt_offset; case 12: /* CM_FLAGS */ return s->cm_flags; case 14: /* CM_NVFLAGS */ @@ -257,6 +262,8 @@ static int integratorcm_init(SysBusDevice *dev) } memcpy(integrator_spd + 73, "QEMU-MEMORY", 11); s->cm_init = 0x00000112; + s->cm_refcnt_offset = muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 24, + 1000); memory_region_init_ram(&s->flash, OBJECT(s), "integrator.flash", 0x100000); vmstate_register_ram_global(&s->flash); -- 1.7.11.3 ^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [Qemu-devel] [PATCH] integrator/cp: add support for REFCNT register 2013-11-05 14:44 ` Jan Petrouš @ 2013-11-05 14:56 ` Peter Maydell 2013-11-05 16:18 ` [Qemu-devel] [PATCH] integrator/cp: add support for REFCNTregisterr Alex Bennée 0 siblings, 1 reply; 7+ messages in thread From: Peter Maydell @ 2013-11-05 14:56 UTC (permalink / raw) To: Jan Petrouš; +Cc: QEMU Developers On 5 November 2013 14:44, Jan Petrouš <jan.petrous@tieto.com> wrote: > Hehe, duno, but when I started learning QEMU the Integrator devboard > looked for me the nice start-up point = very simple to understand > and only very basic, but still core, device list. QEMU's integrator model is really very minimally maintained. A lot of its code is still using out of date ways of doing things and hasn't been updated in years; my only test case for it is an ancient 2.6.17 kernel. vexpress is rather more maintained and I do at least occasionally test with new kernels. > And when I moved > from precompiled kernels (downloaded from internet) to my own > ones I found the issue with default kernel configuration. And because > it can help to not fool somebody later I decided to release patch :) I'm entirely happy to accept and review integrator patches though. > Here is my next version: > > Linux kernel from version 3.4 requires CM_REFCNT register for sched timer > for Integrator/CP board (integrator_defconfig). > > See > http://infocenter.arm.com/help/topic/com.arm.doc.dui0138e/ch04s06s11.html > > Signed-off-by: Jan Petrous <jan.petrous@tieto.com> Thanks. This version Reviewed-by: Peter Maydell <peter.maydell@linaro.org> and I've applied it to my target-arm tree. May get into 1.7 but possibly not til 1.8. PS: doesn't matter for this one but for future patches, version-2 patches are better sent as separate top level emails with a "[PATCH v2]" subject line tag; peoples' patch workflow generally assumes that. -- PMM ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [Qemu-devel] [PATCH] integrator/cp: add support for REFCNTregisterr 2013-11-05 14:56 ` Peter Maydell @ 2013-11-05 16:18 ` Alex Bennée 2013-11-05 16:19 ` Peter Maydell 0 siblings, 1 reply; 7+ messages in thread From: Alex Bennée @ 2013-11-05 16:18 UTC (permalink / raw) To: Peter Maydell; +Cc: QEMU Developers, Jan Petrouš peter.maydell@linaro.org writes: > On 5 November 2013 14:44, Jan Petrouš <jan.petrous@tieto.com> wrote: >> Hehe, duno, but when I started learning QEMU the Integrator devboard >> looked for me the nice start-up point = very simple to understand >> and only very basic, but still core, device list. > > QEMU's integrator model is really very minimally maintained. > A lot of its code is still using out of date ways of doing > things and hasn't been updated in years; my only test case > for it is an ancient 2.6.17 kernel. vexpress is rather > more maintained and I do at least occasionally test with > new kernels. <snip> I suspect it would be worth updating the QEMU wiki pages and building a simple vexpress image (or showing simple steps for the Linaro vexpress builds). I suspect Jan's choice was also influenced as mine by the fact it's the test ARM image mentioned on the wiki page. Of course the first time I ran it I found it had regressed also ;-) -- Alex Bennée ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [Qemu-devel] [PATCH] integrator/cp: add support for REFCNTregisterr 2013-11-05 16:18 ` [Qemu-devel] [PATCH] integrator/cp: add support for REFCNTregisterr Alex Bennée @ 2013-11-05 16:19 ` Peter Maydell 2013-11-06 12:13 ` Jan Petrouš 0 siblings, 1 reply; 7+ messages in thread From: Peter Maydell @ 2013-11-05 16:19 UTC (permalink / raw) To: Alex Bennée; +Cc: QEMU Developers, Jan Petrouš On 5 November 2013 16:18, Alex Bennée <alex.bennee@linaro.org> wrote: > I suspect it would be worth updating the QEMU wiki pages and building a > simple vexpress image (or showing simple steps for the Linaro vexpress > builds). It's painful because of GPL issues if you just provide the binary... -- PMM ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [Qemu-devel] [PATCH] integrator/cp: add support for REFCNTregisterr 2013-11-05 16:19 ` Peter Maydell @ 2013-11-06 12:13 ` Jan Petrouš 0 siblings, 0 replies; 7+ messages in thread From: Jan Petrouš @ 2013-11-06 12:13 UTC (permalink / raw) To: Peter Maydell; +Cc: Alex Bennée, QEMU Developers [-- Attachment #1.1: Type: text/plain, Size: 853 bytes --] BTW, I just cooked very simple support for PL030 RTC chip, but I guess there is zero interest on it as it seems that PL030 is somehow simplified predecessor of well-known PL031, which in turn, is used on all devboards but Integrator. So, I'm sending it here only for reference. I need to note that I have no access to any PL030 documentation, so it was reverse work of corresponding rtc-pl030.c driver from Linux kernel 3.12 The only reason for having PL030 here is that Linux kernel's integrator_defconfig enables only PL030, so without current code, the kernel console says something like that: "drivers/rtc/hctosys.c: unable to open rtc device (rtc0)" Adding PL030 support to QEMU makes kernel start happy: rtc-pl030 mb:15: rtc core: registered pl030 as rtc0 rtc-pl030 mb:15: setting system clock to 2013-11-06 11:55:09 UTC (1383738909) BR. /Jan [-- Attachment #1.2: Type: text/html, Size: 1127 bytes --] [-- Attachment #2: 0001-arm-add-pl030-rtc-support.patch --] [-- Type: text/x-patch, Size: 9055 bytes --] From cd7c6f0130392c0c81064867e346b8a4b218e2cd Mon Sep 17 00:00:00 2001 From: Jan Petrous <jan.petrous@tieto.com> Date: Wed, 6 Nov 2013 12:38:58 +0100 Subject: [PATCH] arm: add pl030 rtc support Devboard Integrator/CP features RTC PL030. To get supported default kernel config for Integrator (integrator_defconfig) the PL030 RTC IP is added. Signed-off-by: Jan Petrous <jan.petrous@tieto.com> --- default-configs/arm-softmmu.mak | 1 + hw/arm/integratorcp.c | 2 +- hw/timer/Makefile.objs | 1 + hw/timer/pl030.c | 245 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 248 insertions(+), 1 deletion(-) create mode 100644 hw/timer/pl030.c diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak index 7e69137..87b9852 100644 --- a/default-configs/arm-softmmu.mak +++ b/default-configs/arm-softmmu.mak @@ -43,6 +43,7 @@ CONFIG_ARM_TIMER=y CONFIG_ARM_MPTIMER=y CONFIG_PL011=y CONFIG_PL022=y +CONFIG_PL030=y CONFIG_PL031=y CONFIG_PL041=y CONFIG_PL050=y diff --git a/hw/arm/integratorcp.c b/hw/arm/integratorcp.c index a759689..0f703b2 100644 --- a/hw/arm/integratorcp.c +++ b/hw/arm/integratorcp.c @@ -510,7 +510,7 @@ static void integratorcp_init(QEMUMachineInitArgs *args) sysbus_create_simple(TYPE_INTEGRATOR_PIC, 0xca000000, pic[26]); sysbus_create_varargs("integrator_pit", 0x13000000, pic[5], pic[6], pic[7], NULL); - sysbus_create_simple("pl031", 0x15000000, pic[8]); + sysbus_create_simple("pl030", 0x15000000, pic[8]); sysbus_create_simple("pl011", 0x16000000, pic[1]); sysbus_create_simple("pl011", 0x17000000, pic[2]); icp_control_init(0xcb000000); diff --git a/hw/timer/Makefile.objs b/hw/timer/Makefile.objs index eca5905..f4b4ea1 100644 --- a/hw/timer/Makefile.objs +++ b/hw/timer/Makefile.objs @@ -5,6 +5,7 @@ common-obj-$(CONFIG_DS1338) += ds1338.o common-obj-$(CONFIG_HPET) += hpet.o common-obj-$(CONFIG_I8254) += i8254_common.o i8254.o common-obj-$(CONFIG_M48T59) += m48t59.o +common-obj-$(CONFIG_PL030) += pl030.o common-obj-$(CONFIG_PL031) += pl031.o common-obj-$(CONFIG_PUV3) += puv3_ost.o common-obj-$(CONFIG_TWL92230) += twl92230.o diff --git a/hw/timer/pl030.c b/hw/timer/pl030.c new file mode 100644 index 0000000..cee7a74 --- /dev/null +++ b/hw/timer/pl030.c @@ -0,0 +1,245 @@ +/* + * ARM AMBA PrimeCell PL030 RTC + * + * Tightly based on pl031.c QEMU sources (c) 2007 CodeSourcery + * Copyright (c) 2013 Tieto Corp., Jan Petrous + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Contributions after 2012-01-13 are licensed under the terms of the + * GNU GPL, version 2 or (at your option) any later version. + */ + +#include "hw/sysbus.h" +#include "qemu/timer.h" +#include "sysemu/sysemu.h" + +//#define DEBUG_PL030 + +#ifdef DEBUG_PL030 +#define DPRINTF(fmt, ...) \ +do { printf("pl030: " fmt , ## __VA_ARGS__); } while (0) +#else +#define DPRINTF(fmt, ...) do {} while (0) +#endif + +#define RTC_DR 0x00 /* Data read register */ +#define RTC_MR 0x04 /* Match register */ +#define RTC_STAT 0x08 /* Masked interrupt status register */ +#define RTC_LR 0x0c /* Data load register */ +#define RTC_CR 0x10 /* Control register */ + +#define TYPE_PL030 "pl030" +#define PL030(obj) OBJECT_CHECK(PL030State, (obj), TYPE_PL030) + +typedef struct PL030State { + SysBusDevice parent_obj; + + MemoryRegion iomem; + QEMUTimer *timer; + qemu_irq irq; + + /* Needed to preserve the tick_count across migration, even if the + * absolute value of the rtc_clock is different on the source and + * destination. + */ + uint32_t tick_offset_vmstate; + uint32_t tick_offset; + + uint32_t mr; + uint32_t lr; + uint32_t cr; + uint32_t stat; +} PL030State; + +static const unsigned char pl030_id[] = { + 0x30, 0x10, 0x04, 0x00, /* Device ID */ + 0x0d, 0xf0, 0x05, 0xb1 /* Cell ID */ +}; + +static void pl030_update(PL030State *s) +{ + qemu_set_irq(s->irq, s->stat); +} + +static void pl030_interrupt(void *opaque) +{ + PL030State *s = (PL030State *)opaque; + + s->stat = 1; + DPRINTF("Alarm raised\n"); + pl030_update(s); +} + +static uint32_t pl030_get_count(PL030State *s) +{ + int64_t now = qemu_clock_get_ns(rtc_clock); + return s->tick_offset + now / get_ticks_per_sec(); +} + +static void pl030_set_alarm(PL030State *s) +{ + uint32_t ticks; + + /* The timer wraps around. This subtraction also wraps in the same way, + and gives correct results when alarm < now_ticks. */ + ticks = s->mr - pl030_get_count(s); + DPRINTF("Alarm set in %ud ticks\n", ticks); + if (ticks == 0) { + timer_del(s->timer); + pl030_interrupt(s); + } else { + int64_t now = qemu_clock_get_ns(rtc_clock); + timer_mod(s->timer, now + (int64_t)ticks * get_ticks_per_sec()); + } +} + +static uint64_t pl030_read(void *opaque, hwaddr offset, + unsigned size) +{ + PL030State *s = (PL030State *)opaque; + + if (offset >= 0xfe0 && offset < 0x1000) + return pl030_id[(offset - 0xfe0) >> 2]; + + switch (offset) { + case RTC_DR: + return pl030_get_count(s); + case RTC_MR: + return s->mr; + case RTC_STAT: + return s->stat; + case RTC_LR: + return s->lr; + case RTC_CR: + /* RTC is permanently enabled. */ + return 1; + default: + qemu_log_mask(LOG_GUEST_ERROR, + "pl030_read: Bad offset 0x%x\n", (int)offset); + break; + } + + return 0; +} + +static void pl030_write(void *opaque, hwaddr offset, + uint64_t value, unsigned size) +{ + PL030State *s = (PL030State *)opaque; + + + switch (offset) { + case RTC_LR: + s->tick_offset += value - pl030_get_count(s); + pl030_set_alarm(s); + break; + case RTC_MR: + s->mr = value; + pl030_set_alarm(s); + break; + case RTC_CR: + /* Written value is ignored. */ + break; + + case RTC_DR: + case RTC_STAT: + qemu_log_mask(LOG_GUEST_ERROR, + "pl030: write to read-only register at offset 0x%x\n", + (int)offset); + break; + + default: + qemu_log_mask(LOG_GUEST_ERROR, + "pl030_write: Bad offset 0x%x\n", (int)offset); + break; + } +} + +static const MemoryRegionOps pl030_ops = { + .read = pl030_read, + .write = pl030_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static int pl030_init(SysBusDevice *dev) +{ + PL030State *s = PL030(dev); + struct tm tm; + + memory_region_init_io(&s->iomem, OBJECT(s), &pl030_ops, s, "pl030", 0x1000); + sysbus_init_mmio(dev, &s->iomem); + + sysbus_init_irq(dev, &s->irq); + qemu_get_timedate(&tm, 0); + s->tick_offset = mktimegm(&tm) - + qemu_clock_get_ns(rtc_clock) / get_ticks_per_sec(); + + s->timer = timer_new_ns(rtc_clock, pl030_interrupt, s); + return 0; +} + +static void pl030_pre_save(void *opaque) +{ + PL030State *s = opaque; + + /* tick_offset is base_time - rtc_clock base time. + * Instead we want to store the base time relative to the QEMU_CLOCK_VIRTUAL + * for backwards-compatibility. */ + int64_t delta = qemu_clock_get_ns(rtc_clock) - + qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + s->tick_offset_vmstate = s->tick_offset + delta / get_ticks_per_sec(); +} + +static int pl030_post_load(void *opaque, int version_id) +{ + PL030State *s = opaque; + + int64_t delta = qemu_clock_get_ns(rtc_clock) - + qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + s->tick_offset = s->tick_offset_vmstate - delta / get_ticks_per_sec(); + pl030_set_alarm(s); + return 0; +} + +static const VMStateDescription vmstate_pl030 = { + .name = "pl030", + .version_id = 1, + .minimum_version_id = 1, + .pre_save = pl030_pre_save, + .post_load = pl030_post_load, + .fields = (VMStateField[]) { + VMSTATE_UINT32(tick_offset_vmstate, PL030State), + VMSTATE_UINT32(mr, PL030State), + VMSTATE_UINT32(lr, PL030State), + VMSTATE_UINT32(cr, PL030State), + VMSTATE_UINT32(stat, PL030State), + VMSTATE_END_OF_LIST() + } +}; + +static void pl030_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = pl030_init; + dc->no_user = 1; + dc->vmsd = &vmstate_pl030; +} + +static const TypeInfo pl030_info = { + .name = TYPE_PL030, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(PL030State), + .class_init = pl030_class_init, +}; + +static void pl030_register_types(void) +{ + type_register_static(&pl030_info); +} + +type_init(pl030_register_types) -- 1.7.11.3 ^ permalink raw reply related [flat|nested] 7+ messages in thread
end of thread, other threads:[~2013-11-06 12:13 UTC | newest] Thread overview: 7+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2013-11-05 11:41 [Qemu-devel] [PATCH] integrator/cp: add support for REFCNT register Jan Petrouš 2013-11-05 13:54 ` Peter Maydell 2013-11-05 14:44 ` Jan Petrouš 2013-11-05 14:56 ` Peter Maydell 2013-11-05 16:18 ` [Qemu-devel] [PATCH] integrator/cp: add support for REFCNTregisterr Alex Bennée 2013-11-05 16:19 ` Peter Maydell 2013-11-06 12:13 ` Jan Petrouš
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.