cpu/a9mpcore: Add Global Timer

Add the global timer to A9 MPCore.

Signed-off-by: François LEGAL <devel@thom.fr.eu.org>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Message-id: ff92f35f438ac671b57d99d823723dd3e62d2c49.1385969450.git.peter.crosthwaite@xilinx.com
[PC Changes:
 * new commit message
 * split off original version as a separate patch
 * Rebased against new mpcore implementation (with struct embedding)
]
Signed-off-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
master
François LEGAL 2013-12-01 23:37:11 -08:00 committed by Peter Maydell
parent c21c3b53e1
commit 57e72f2a19
2 changed files with 23 additions and 5 deletions

View File

@ -30,6 +30,9 @@ static void a9mp_priv_initfn(Object *obj)
object_initialize(&s->gic, sizeof(s->gic), TYPE_ARM_GIC);
qdev_set_parent_bus(DEVICE(&s->gic), sysbus_get_default());
object_initialize(&s->gtimer, sizeof(s->gtimer), TYPE_A9_GTIMER);
qdev_set_parent_bus(DEVICE(&s->gtimer), sysbus_get_default());
object_initialize(&s->mptimer, sizeof(s->mptimer), TYPE_ARM_MPTIMER);
qdev_set_parent_bus(DEVICE(&s->mptimer), sysbus_get_default());
@ -41,8 +44,9 @@ static void a9mp_priv_realize(DeviceState *dev, Error **errp)
{
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
A9MPPrivState *s = A9MPCORE_PRIV(dev);
DeviceState *scudev, *gicdev, *mptimerdev, *wdtdev;
SysBusDevice *scubusdev, *gicbusdev, *mptimerbusdev, *wdtbusdev;
DeviceState *scudev, *gicdev, *gtimerdev, *mptimerdev, *wdtdev;
SysBusDevice *scubusdev, *gicbusdev, *gtimerbusdev, *mptimerbusdev,
*wdtbusdev;
Error *err = NULL;
int i;
@ -71,6 +75,15 @@ static void a9mp_priv_realize(DeviceState *dev, Error **errp)
/* Pass through inbound GPIO lines to the GIC */
qdev_init_gpio_in(dev, a9mp_priv_set_irq, s->num_irq - 32);
gtimerdev = DEVICE(&s->gtimer);
qdev_prop_set_uint32(gtimerdev, "num-cpu", s->num_cpu);
object_property_set_bool(OBJECT(&s->gtimer), true, "realized", &err);
if (err != NULL) {
error_propagate(errp, err);
return;
}
gtimerbusdev = SYS_BUS_DEVICE(&s->gtimer);
mptimerdev = DEVICE(&s->mptimer);
qdev_prop_set_uint32(mptimerdev, "num-cpu", s->num_cpu);
object_property_set_bool(OBJECT(&s->mptimer), true, "realized", &err);
@ -97,14 +110,14 @@ static void a9mp_priv_realize(DeviceState *dev, Error **errp)
* 0x0600-0x06ff -- private timers and watchdogs
* 0x0700-0x0fff -- nothing
* 0x1000-0x1fff -- GIC Distributor
*
* We should implement the global timer but don't currently do so.
*/
memory_region_add_subregion(&s->container, 0,
sysbus_mmio_get_region(scubusdev, 0));
/* GIC CPU interface */
memory_region_add_subregion(&s->container, 0x100,
sysbus_mmio_get_region(gicbusdev, 1));
memory_region_add_subregion(&s->container, 0x200,
sysbus_mmio_get_region(gtimerbusdev, 0));
/* Note that the A9 exposes only the "timer/watchdog for this core"
* memory region, not the "timer/watchdog for core X" ones 11MPcore has.
*/
@ -116,10 +129,13 @@ static void a9mp_priv_realize(DeviceState *dev, Error **errp)
sysbus_mmio_get_region(gicbusdev, 0));
/* Wire up the interrupt from each watchdog and timer.
* For each core the timer is PPI 29 and the watchdog PPI 30.
* For each core the global timer is PPI 27, the private
* timer is PPI 29 and the watchdog PPI 30.
*/
for (i = 0; i < s->num_cpu; i++) {
int ppibase = (s->num_irq - 32) + i * 32;
sysbus_connect_irq(gtimerbusdev, i,
qdev_get_gpio_in(gicdev, ppibase + 27));
sysbus_connect_irq(mptimerbusdev, i,
qdev_get_gpio_in(gicdev, ppibase + 29));
sysbus_connect_irq(wdtbusdev, i,

View File

@ -14,6 +14,7 @@
#include "hw/intc/arm_gic.h"
#include "hw/misc/a9scu.h"
#include "hw/timer/arm_mptimer.h"
#include "hw/timer/a9gtimer.h"
#define TYPE_A9MPCORE_PRIV "a9mpcore_priv"
#define A9MPCORE_PRIV(obj) \
@ -30,6 +31,7 @@ typedef struct A9MPPrivState {
A9SCUState scu;
GICState gic;
A9GTimerState gtimer;
ARMMPTimerState mptimer;
ARMMPTimerState wdt;
} A9MPPrivState;