target-arm queue:
* i.MX code cleanup/refactorings * i.MX UART fix to work with uninitialized chardev * minor GIC code refactorings * implement the ARM Secure physical timer * implement the ARM Hypervisor timer -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABCAAGBQJVzHQ4AAoJEDwlJe0UNgzefeAQAJoUuhCUnssxy8eVXZ81ijpF MxBm7jy/l64iCWXmVb85j2xAWNbcStE775BOlJNWYdFTeXJRKBNnFxAgQP75XLbs r1pszGqjQDz15Raa9yCq3mcZ/W1ww/ZqbKMq4OxIfBaSvsPAIN73sJaYnE9J08RX oAMZ7Ji76mNU4fp6D9c/aMzhODcKlCkjhWfr3d9WKQNcxBTlNWhaeZEDKHCChnKw CyRekUn8hMgdtVHpUG8hO7Q8/l8BgB9dhY8twS5rurVt1Pm7PSS+t2OmUFkR3E9Y hwHeJANV2kWxBi5iL20YSDQCtxETpcvfo1ASUWfKU39yYYHk/zFIAskMuZ5T9iah +I1dLt3gP+Md6D4S5vMPr6s8s5iInc3qHYs7hMMWsxbubZ9+poflyNRdhh7sJIJ+ 75GmLIePxRCIukzEDbIp51y4kmBNi376oR/3HHOs4rp9Nvt0PQOsSj+Prk5vmWq+ klZ7hdE5cDZhvTHhmkGstswT9+XtXZsef7kFRhgf83LnSIim2iZmH23jpKTi7x5i 6hluA/JLoS/OSLuXFdmo84GbSoh962dIk73UT7jhef+9D8306v/VC2nv0oXR/iNm sxNIN7MqMilWeMVfB5TELhqoBuSr10tfUgWaQMvRHaF6KrzkJtNZBcZxb302g6n0 5RIKpvNw2lK2jtmziCca =geLz -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20150813' into staging target-arm queue: * i.MX code cleanup/refactorings * i.MX UART fix to work with uninitialized chardev * minor GIC code refactorings * implement the ARM Secure physical timer * implement the ARM Hypervisor timer # gpg: Signature made Thu 13 Aug 2015 11:40:56 BST using RSA key ID 14360CDE # gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" * remotes/pmaydell/tags/pull-target-arm-20150813: (27 commits) i.MX: Fix UART driver to work with unitialized "chardev" device hw/cpu/a15mpcore: Wire up hyp and secure physical timer interrupts hw/arm/virt: Wire up secure timer interrupt target-arm: Add AArch32 banked register access to secure physical timer target-arm: Add the AArch64 view of the Secure physical timer target-arm: Add debug check for mismatched cpreg resets Introduce gic_class_name() instead of repeating condition hw/arm/gic: Kill code duplication Merge memory_region_init_reservation() into memory_region_init_io() i.MX: Fix Coding style for GPT emulator i.MX: Split GPT emulator in a header file and a source file i.MX: Fix Coding style for EPIT emulator i.MX: Split EPIT emulator in a header file and a source file i.MX: Fix Coding style for CCM emulator i.MX: Split CCM emulator in a header file and a source file i.MX: Fix Coding style for AVIC emulator. i.MX: Split AVIC emulator in a header file and a source file i.MX:Fix Coding style for UART emulator. i.MX: Move serial initialization to init/realize of DeviceClass. i.MX: Split UART emulator in a header file and a source file ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
425591e3ef
@ -22,6 +22,7 @@
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "hw/boards.h"
|
||||
#include "hw/char/serial.h"
|
||||
#include "hw/intc/imx_avic.h"
|
||||
#include "hw/arm/imx.h"
|
||||
|
||||
/* Memory map for Kzm Emulation Baseboard:
|
||||
@ -106,7 +107,7 @@ static void kzm_init(MachineState *machine)
|
||||
memory_region_init_ram(sram, NULL, "kzm.sram", 0x4000, &error_abort);
|
||||
memory_region_add_subregion(address_space_mem, 0x1FFFC000, sram);
|
||||
|
||||
dev = sysbus_create_varargs("imx_avic", 0x68000000,
|
||||
dev = sysbus_create_varargs(TYPE_IMX_AVIC, 0x68000000,
|
||||
qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ),
|
||||
qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_FIQ),
|
||||
NULL);
|
||||
@ -114,7 +115,7 @@ static void kzm_init(MachineState *machine)
|
||||
imx_serial_create(0, 0x43f90000, qdev_get_gpio_in(dev, 45));
|
||||
imx_serial_create(1, 0x43f94000, qdev_get_gpio_in(dev, 32));
|
||||
|
||||
ccm = sysbus_create_simple("imx_ccm", 0x53f80000, NULL);
|
||||
ccm = sysbus_create_simple(TYPE_IMX_CCM, 0x53f80000, NULL);
|
||||
|
||||
imx_timerp_create(0x53f94000, qdev_get_gpio_in(dev, 28), ccm);
|
||||
imx_timerp_create(0x53f98000, qdev_get_gpio_in(dev, 27), ccm);
|
||||
|
@ -48,6 +48,8 @@
|
||||
#include "hw/arm/sysbus-fdt.h"
|
||||
#include "hw/platform-bus.h"
|
||||
#include "hw/arm/fdt.h"
|
||||
#include "hw/intc/arm_gic_common.h"
|
||||
#include "kvm_arm.h"
|
||||
|
||||
/* Number of external interrupt lines to configure the GIC with */
|
||||
#define NUM_IRQS 256
|
||||
@ -365,12 +367,10 @@ static void create_gic(VirtBoardInfo *vbi, qemu_irq *pic)
|
||||
/* We create a standalone GIC v2 */
|
||||
DeviceState *gicdev;
|
||||
SysBusDevice *gicbusdev;
|
||||
const char *gictype = "arm_gic";
|
||||
const char *gictype;
|
||||
int i;
|
||||
|
||||
if (kvm_irqchip_in_kernel()) {
|
||||
gictype = "kvm-arm-gic";
|
||||
}
|
||||
gictype = gic_class_name();
|
||||
|
||||
gicdev = qdev_create(NULL, gictype);
|
||||
qdev_prop_set_uint32(gicdev, "revision", 2);
|
||||
@ -390,15 +390,23 @@ static void create_gic(VirtBoardInfo *vbi, qemu_irq *pic)
|
||||
*/
|
||||
for (i = 0; i < smp_cpus; i++) {
|
||||
DeviceState *cpudev = DEVICE(qemu_get_cpu(i));
|
||||
int ppibase = NUM_IRQS + i * 32;
|
||||
/* physical timer; we wire it up to the non-secure timer's ID,
|
||||
* since a real A15 always has TrustZone but QEMU doesn't.
|
||||
int ppibase = NUM_IRQS + i * GIC_INTERNAL + GIC_NR_SGIS;
|
||||
int irq;
|
||||
/* Mapping from the output timer irq lines from the CPU to the
|
||||
* GIC PPI inputs we use for the virt board.
|
||||
*/
|
||||
qdev_connect_gpio_out(cpudev, 0,
|
||||
qdev_get_gpio_in(gicdev, ppibase + 30));
|
||||
/* virtual timer */
|
||||
qdev_connect_gpio_out(cpudev, 1,
|
||||
qdev_get_gpio_in(gicdev, ppibase + 27));
|
||||
const int timer_irq[] = {
|
||||
[GTIMER_PHYS] = ARCH_TIMER_NS_EL1_IRQ,
|
||||
[GTIMER_VIRT] = ARCH_TIMER_VIRT_IRQ,
|
||||
[GTIMER_HYP] = ARCH_TIMER_NS_EL2_IRQ,
|
||||
[GTIMER_SEC] = ARCH_TIMER_S_EL1_IRQ,
|
||||
};
|
||||
|
||||
for (irq = 0; irq < ARRAY_SIZE(timer_irq); irq++) {
|
||||
qdev_connect_gpio_out(cpudev, irq,
|
||||
qdev_get_gpio_in(gicdev,
|
||||
ppibase + timer_irq[irq]));
|
||||
}
|
||||
|
||||
sysbus_connect_irq(gicbusdev, i, qdev_get_gpio_in(cpudev, ARM_CPU_IRQ));
|
||||
sysbus_connect_irq(gicbusdev, i + smp_cpus,
|
||||
|
@ -4,6 +4,7 @@
|
||||
* Copyright (c) 2008 OKL
|
||||
* Originally Written by Hans Jiang
|
||||
* Copyright (c) 2011 NICTA Pty Ltd.
|
||||
* Updated by Jean-Christophe Dubois <jcd@tribudubois.net>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
@ -17,8 +18,7 @@
|
||||
* is a real serial device.
|
||||
*/
|
||||
|
||||
#include "hw/hw.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/char/imx_serial.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "sysemu/char.h"
|
||||
#include "hw/arm/imx.h"
|
||||
@ -26,7 +26,7 @@
|
||||
//#define DEBUG_SERIAL 1
|
||||
#ifdef DEBUG_SERIAL
|
||||
#define DPRINTF(fmt, args...) \
|
||||
do { printf("imx_serial: " fmt , ##args); } while (0)
|
||||
do { printf("%s: " fmt , TYPE_IMX_SERIAL, ##args); } while (0)
|
||||
#else
|
||||
#define DPRINTF(fmt, args...) do {} while (0)
|
||||
#endif
|
||||
@ -38,42 +38,13 @@ do { printf("imx_serial: " fmt , ##args); } while (0)
|
||||
//#define DEBUG_IMPLEMENTATION 1
|
||||
#ifdef DEBUG_IMPLEMENTATION
|
||||
# define IPRINTF(fmt, args...) \
|
||||
do { fprintf(stderr, "imx_serial: " fmt, ##args); } while (0)
|
||||
do { fprintf(stderr, "%s: " fmt, TYPE_IMX_SERIAL, ##args); } while (0)
|
||||
#else
|
||||
# define IPRINTF(fmt, args...) do {} while (0)
|
||||
#endif
|
||||
|
||||
#define TYPE_IMX_SERIAL "imx-serial"
|
||||
#define IMX_SERIAL(obj) OBJECT_CHECK(IMXSerialState, (obj), TYPE_IMX_SERIAL)
|
||||
|
||||
typedef struct IMXSerialState {
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
MemoryRegion iomem;
|
||||
int32_t readbuff;
|
||||
|
||||
uint32_t usr1;
|
||||
uint32_t usr2;
|
||||
uint32_t ucr1;
|
||||
uint32_t ucr2;
|
||||
uint32_t uts1;
|
||||
|
||||
/*
|
||||
* The registers below are implemented just so that the
|
||||
* guest OS sees what it has written
|
||||
*/
|
||||
uint32_t onems;
|
||||
uint32_t ufcr;
|
||||
uint32_t ubmr;
|
||||
uint32_t ubrc;
|
||||
uint32_t ucr3;
|
||||
|
||||
qemu_irq irq;
|
||||
CharDriverState *chr;
|
||||
} IMXSerialState;
|
||||
|
||||
static const VMStateDescription vmstate_imx_serial = {
|
||||
.name = "imx-serial",
|
||||
.name = TYPE_IMX_SERIAL,
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
@ -91,55 +62,6 @@ static const VMStateDescription vmstate_imx_serial = {
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
#define URXD_CHARRDY (1<<15) /* character read is valid */
|
||||
#define URXD_ERR (1<<14) /* Character has error */
|
||||
#define URXD_BRK (1<<11) /* Break received */
|
||||
|
||||
#define USR1_PARTYER (1<<15) /* Parity Error */
|
||||
#define USR1_RTSS (1<<14) /* RTS pin status */
|
||||
#define USR1_TRDY (1<<13) /* Tx ready */
|
||||
#define USR1_RTSD (1<<12) /* RTS delta: pin changed state */
|
||||
#define USR1_ESCF (1<<11) /* Escape sequence interrupt */
|
||||
#define USR1_FRAMERR (1<<10) /* Framing error */
|
||||
#define USR1_RRDY (1<<9) /* receiver ready */
|
||||
#define USR1_AGTIM (1<<8) /* Aging timer interrupt */
|
||||
#define USR1_DTRD (1<<7) /* DTR changed */
|
||||
#define USR1_RXDS (1<<6) /* Receiver is idle */
|
||||
#define USR1_AIRINT (1<<5) /* Aysnch IR interrupt */
|
||||
#define USR1_AWAKE (1<<4) /* Falling edge detected on RXd pin */
|
||||
|
||||
#define USR2_ADET (1<<15) /* Autobaud complete */
|
||||
#define USR2_TXFE (1<<14) /* Transmit FIFO empty */
|
||||
#define USR2_DTRF (1<<13) /* DTR/DSR transition */
|
||||
#define USR2_IDLE (1<<12) /* UART has been idle for too long */
|
||||
#define USR2_ACST (1<<11) /* Autobaud counter stopped */
|
||||
#define USR2_RIDELT (1<<10) /* Ring Indicator delta */
|
||||
#define USR2_RIIN (1<<9) /* Ring Indicator Input */
|
||||
#define USR2_IRINT (1<<8) /* Serial Infrared Interrupt */
|
||||
#define USR2_WAKE (1<<7) /* Start bit detected */
|
||||
#define USR2_DCDDELT (1<<6) /* Data Carrier Detect delta */
|
||||
#define USR2_DCDIN (1<<5) /* Data Carrier Detect Input */
|
||||
#define USR2_RTSF (1<<4) /* RTS transition */
|
||||
#define USR2_TXDC (1<<3) /* Transmission complete */
|
||||
#define USR2_BRCD (1<<2) /* Break condition detected */
|
||||
#define USR2_ORE (1<<1) /* Overrun error */
|
||||
#define USR2_RDR (1<<0) /* Receive data ready */
|
||||
|
||||
#define UCR1_TRDYEN (1<<13) /* Tx Ready Interrupt Enable */
|
||||
#define UCR1_RRDYEN (1<<9) /* Rx Ready Interrupt Enable */
|
||||
#define UCR1_TXMPTYEN (1<<6) /* Tx Empty Interrupt Enable */
|
||||
#define UCR1_UARTEN (1<<0) /* UART Enable */
|
||||
|
||||
#define UCR2_TXEN (1<<2) /* Transmitter enable */
|
||||
#define UCR2_RXEN (1<<1) /* Receiver enable */
|
||||
#define UCR2_SRST (1<<0) /* Reset complete */
|
||||
|
||||
#define UTS1_TXEMPTY (1<<6)
|
||||
#define UTS1_RXEMPTY (1<<5)
|
||||
#define UTS1_TXFULL (1<<4)
|
||||
#define UTS1_RXFULL (1<<3)
|
||||
|
||||
static void imx_update(IMXSerialState *s)
|
||||
{
|
||||
uint32_t flags;
|
||||
@ -203,7 +125,9 @@ static uint64_t imx_serial_read(void *opaque, hwaddr offset,
|
||||
s->usr2 &= ~USR2_RDR;
|
||||
s->uts1 |= UTS1_RXEMPTY;
|
||||
imx_update(s);
|
||||
qemu_chr_accept_input(s->chr);
|
||||
if (s->chr) {
|
||||
qemu_chr_accept_input(s->chr);
|
||||
}
|
||||
}
|
||||
return c;
|
||||
|
||||
@ -242,13 +166,13 @@ static uint64_t imx_serial_read(void *opaque, hwaddr offset,
|
||||
return 0x0; /* TODO */
|
||||
|
||||
default:
|
||||
IPRINTF("imx_serial_read: bad offset: 0x%x\n", (int)offset);
|
||||
IPRINTF("%s: bad offset: 0x%x\n", __func__, (int)offset);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void imx_serial_write(void *opaque, hwaddr offset,
|
||||
uint64_t value, unsigned size)
|
||||
uint64_t value, unsigned size)
|
||||
{
|
||||
IMXSerialState *s = (IMXSerialState *)opaque;
|
||||
unsigned char ch;
|
||||
@ -290,7 +214,9 @@ static void imx_serial_write(void *opaque, hwaddr offset,
|
||||
}
|
||||
if (value & UCR2_RXEN) {
|
||||
if (!(s->ucr2 & UCR2_RXEN)) {
|
||||
qemu_chr_accept_input(s->chr);
|
||||
if (s->chr) {
|
||||
qemu_chr_accept_input(s->chr);
|
||||
}
|
||||
}
|
||||
}
|
||||
s->ucr2 = value & 0xffff;
|
||||
@ -298,25 +224,25 @@ static void imx_serial_write(void *opaque, hwaddr offset,
|
||||
|
||||
case 0x25: /* USR1 */
|
||||
value &= USR1_AWAKE | USR1_AIRINT | USR1_DTRD | USR1_AGTIM |
|
||||
USR1_FRAMERR | USR1_ESCF | USR1_RTSD | USR1_PARTYER;
|
||||
USR1_FRAMERR | USR1_ESCF | USR1_RTSD | USR1_PARTYER;
|
||||
s->usr1 &= ~value;
|
||||
break;
|
||||
|
||||
case 0x26: /* USR2 */
|
||||
/*
|
||||
* Writing 1 to some bits clears them; all other
|
||||
* values are ignored
|
||||
*/
|
||||
/*
|
||||
* Writing 1 to some bits clears them; all other
|
||||
* values are ignored
|
||||
*/
|
||||
value &= USR2_ADET | USR2_DTRF | USR2_IDLE | USR2_ACST |
|
||||
USR2_RIDELT | USR2_IRINT | USR2_WAKE |
|
||||
USR2_DCDDELT | USR2_RTSF | USR2_BRCD | USR2_ORE;
|
||||
USR2_RIDELT | USR2_IRINT | USR2_WAKE |
|
||||
USR2_DCDDELT | USR2_RTSF | USR2_BRCD | USR2_ORE;
|
||||
s->usr2 &= ~value;
|
||||
break;
|
||||
|
||||
/*
|
||||
* Linux expects to see what it writes to these registers
|
||||
* We don't currently alter the baud rate
|
||||
*/
|
||||
/*
|
||||
* Linux expects to see what it writes to these registers
|
||||
* We don't currently alter the baud rate
|
||||
*/
|
||||
case 0x29: /* UBIR */
|
||||
s->ubrc = value & 0xffff;
|
||||
break;
|
||||
@ -344,7 +270,7 @@ static void imx_serial_write(void *opaque, hwaddr offset,
|
||||
break;
|
||||
|
||||
default:
|
||||
IPRINTF("imx_serial_write: Bad offset 0x%x\n", (int)offset);
|
||||
IPRINTF("%s: Bad offset 0x%x\n", __func__, (int)offset);
|
||||
}
|
||||
}
|
||||
|
||||
@ -384,16 +310,10 @@ static const struct MemoryRegionOps imx_serial_ops = {
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
static int imx_serial_init(SysBusDevice *dev)
|
||||
static void imx_serial_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
IMXSerialState *s = IMX_SERIAL(dev);
|
||||
|
||||
|
||||
memory_region_init_io(&s->iomem, OBJECT(s), &imx_serial_ops, s,
|
||||
"imx-serial", 0x1000);
|
||||
sysbus_init_mmio(dev, &s->iomem);
|
||||
sysbus_init_irq(dev, &s->irq);
|
||||
|
||||
if (s->chr) {
|
||||
qemu_chr_add_handlers(s->chr, imx_can_receive, imx_receive,
|
||||
imx_event, s);
|
||||
@ -401,8 +321,17 @@ static int imx_serial_init(SysBusDevice *dev)
|
||||
DPRINTF("No char dev for uart at 0x%lx\n",
|
||||
(unsigned long)s->iomem.ram_addr);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
static void imx_serial_init(Object *obj)
|
||||
{
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
||||
IMXSerialState *s = IMX_SERIAL(obj);
|
||||
|
||||
memory_region_init_io(&s->iomem, obj, &imx_serial_ops, s,
|
||||
TYPE_IMX_SERIAL, 0x1000);
|
||||
sysbus_init_mmio(sbd, &s->iomem);
|
||||
sysbus_init_irq(sbd, &s->irq);
|
||||
}
|
||||
|
||||
void imx_serial_create(int uart, const hwaddr addr, qemu_irq irq)
|
||||
@ -439,7 +368,7 @@ void imx_serial_create(int uart, const hwaddr addr, qemu_irq irq)
|
||||
}
|
||||
|
||||
|
||||
static Property imx32_serial_properties[] = {
|
||||
static Property imx_serial_properties[] = {
|
||||
DEFINE_PROP_CHR("chardev", IMXSerialState, chr),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
@ -447,21 +376,21 @@ static Property imx32_serial_properties[] = {
|
||||
static void imx_serial_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
|
||||
|
||||
k->init = imx_serial_init;
|
||||
dc->realize = imx_serial_realize;
|
||||
dc->vmsd = &vmstate_imx_serial;
|
||||
dc->reset = imx_serial_reset_at_boot;
|
||||
set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
|
||||
dc->desc = "i.MX series UART";
|
||||
dc->props = imx32_serial_properties;
|
||||
dc->props = imx_serial_properties;
|
||||
}
|
||||
|
||||
static const TypeInfo imx_serial_info = {
|
||||
.name = TYPE_IMX_SERIAL,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(IMXSerialState),
|
||||
.class_init = imx_serial_class_init,
|
||||
.name = TYPE_IMX_SERIAL,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(IMXSerialState),
|
||||
.instance_init = imx_serial_init,
|
||||
.class_init = imx_serial_class_init,
|
||||
};
|
||||
|
||||
static void imx_serial_register_types(void)
|
||||
|
@ -20,6 +20,7 @@
|
||||
|
||||
#include "hw/cpu/a15mpcore.h"
|
||||
#include "sysemu/kvm.h"
|
||||
#include "kvm_arm.h"
|
||||
|
||||
static void a15mp_priv_set_irq(void *opaque, int irq, int level)
|
||||
{
|
||||
@ -33,16 +34,11 @@ static void a15mp_priv_initfn(Object *obj)
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
||||
A15MPPrivState *s = A15MPCORE_PRIV(obj);
|
||||
DeviceState *gicdev;
|
||||
const char *gictype = "arm_gic";
|
||||
|
||||
if (kvm_irqchip_in_kernel()) {
|
||||
gictype = "kvm-arm-gic";
|
||||
}
|
||||
|
||||
memory_region_init(&s->container, obj, "a15mp-priv-container", 0x8000);
|
||||
sysbus_init_mmio(sbd, &s->container);
|
||||
|
||||
object_initialize(&s->gic, sizeof(s->gic), gictype);
|
||||
object_initialize(&s->gic, sizeof(s->gic), gic_class_name());
|
||||
gicdev = DEVICE(&s->gic);
|
||||
qdev_set_parent_bus(gicdev, sysbus_get_default());
|
||||
qdev_prop_set_uint32(gicdev, "revision", 2);
|
||||
@ -79,14 +75,21 @@ static void a15mp_priv_realize(DeviceState *dev, Error **errp)
|
||||
for (i = 0; i < s->num_cpu; i++) {
|
||||
DeviceState *cpudev = DEVICE(qemu_get_cpu(i));
|
||||
int ppibase = s->num_irq - 32 + i * 32;
|
||||
/* physical timer; we wire it up to the non-secure timer's ID,
|
||||
* since a real A15 always has TrustZone but QEMU doesn't.
|
||||
int irq;
|
||||
/* Mapping from the output timer irq lines from the CPU to the
|
||||
* GIC PPI inputs used on the A15:
|
||||
*/
|
||||
qdev_connect_gpio_out(cpudev, 0,
|
||||
qdev_get_gpio_in(gicdev, ppibase + 30));
|
||||
/* virtual timer */
|
||||
qdev_connect_gpio_out(cpudev, 1,
|
||||
qdev_get_gpio_in(gicdev, ppibase + 27));
|
||||
const int timer_irq[] = {
|
||||
[GTIMER_PHYS] = 30,
|
||||
[GTIMER_VIRT] = 27,
|
||||
[GTIMER_HYP] = 26,
|
||||
[GTIMER_SEC] = 29,
|
||||
};
|
||||
for (irq = 0; irq < ARRAY_SIZE(timer_irq); irq++) {
|
||||
qdev_connect_gpio_out(cpudev, irq,
|
||||
qdev_get_gpio_in(gicdev,
|
||||
ppibase + timer_irq[irq]));
|
||||
}
|
||||
}
|
||||
|
||||
/* Memory map (addresses are offsets from PERIPHBASE):
|
||||
|
@ -922,12 +922,6 @@ static MemTxResult gic_dist_write(void *opaque, hwaddr offset, uint64_t data,
|
||||
}
|
||||
}
|
||||
|
||||
static const MemoryRegionOps gic_dist_ops = {
|
||||
.read_with_attrs = gic_dist_read,
|
||||
.write_with_attrs = gic_dist_write,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
static MemTxResult gic_cpu_read(GICState *s, int cpu, int offset,
|
||||
uint64_t *data, MemTxAttrs attrs)
|
||||
{
|
||||
@ -1056,10 +1050,17 @@ static MemTxResult gic_do_cpu_write(void *opaque, hwaddr addr,
|
||||
return gic_cpu_write(s, id, addr, value, attrs);
|
||||
}
|
||||
|
||||
static const MemoryRegionOps gic_thiscpu_ops = {
|
||||
.read_with_attrs = gic_thiscpu_read,
|
||||
.write_with_attrs = gic_thiscpu_write,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
static const MemoryRegionOps gic_ops[2] = {
|
||||
{
|
||||
.read_with_attrs = gic_dist_read,
|
||||
.write_with_attrs = gic_dist_write,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
},
|
||||
{
|
||||
.read_with_attrs = gic_thiscpu_read,
|
||||
.write_with_attrs = gic_thiscpu_write,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
}
|
||||
};
|
||||
|
||||
static const MemoryRegionOps gic_cpu_ops = {
|
||||
@ -1068,31 +1069,10 @@ static const MemoryRegionOps gic_cpu_ops = {
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
/* This function is used by nvic model */
|
||||
void gic_init_irqs_and_distributor(GICState *s)
|
||||
{
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(s);
|
||||
int i;
|
||||
|
||||
i = s->num_irq - GIC_INTERNAL;
|
||||
/* For the GIC, also expose incoming GPIO lines for PPIs for each CPU.
|
||||
* GPIO array layout is thus:
|
||||
* [0..N-1] SPIs
|
||||
* [N..N+31] PPIs for CPU 0
|
||||
* [N+32..N+63] PPIs for CPU 1
|
||||
* ...
|
||||
*/
|
||||
if (s->revision != REV_NVIC) {
|
||||
i += (GIC_INTERNAL * s->num_cpu);
|
||||
}
|
||||
qdev_init_gpio_in(DEVICE(s), gic_set_irq, i);
|
||||
for (i = 0; i < NUM_CPU(s); i++) {
|
||||
sysbus_init_irq(sbd, &s->parent_irq[i]);
|
||||
}
|
||||
for (i = 0; i < NUM_CPU(s); i++) {
|
||||
sysbus_init_irq(sbd, &s->parent_fiq[i]);
|
||||
}
|
||||
memory_region_init_io(&s->iomem, OBJECT(s), &gic_dist_ops, s,
|
||||
"gic_dist", 0x1000);
|
||||
gic_init_irqs_and_mmio(s, gic_set_irq, gic_ops);
|
||||
}
|
||||
|
||||
static void arm_gic_realize(DeviceState *dev, Error **errp)
|
||||
@ -1110,28 +1090,22 @@ static void arm_gic_realize(DeviceState *dev, Error **errp)
|
||||
return;
|
||||
}
|
||||
|
||||
gic_init_irqs_and_distributor(s);
|
||||
/* This creates distributor and main CPU interface (s->cpuiomem[0]) */
|
||||
gic_init_irqs_and_mmio(s, gic_set_irq, gic_ops);
|
||||
|
||||
/* Memory regions for the CPU interfaces (NVIC doesn't have these):
|
||||
* a region for "CPU interface for this core", then a region for
|
||||
* "CPU interface for core 0", "for core 1", ...
|
||||
/* Extra core-specific regions for the CPU interfaces. This is
|
||||
* necessary for "franken-GIC" implementations, for example on
|
||||
* Exynos 4.
|
||||
* NB that the memory region size of 0x100 applies for the 11MPCore
|
||||
* and also cores following the GIC v1 spec (ie A9).
|
||||
* GIC v2 defines a larger memory region (0x1000) so this will need
|
||||
* to be extended when we implement A15.
|
||||
*/
|
||||
memory_region_init_io(&s->cpuiomem[0], OBJECT(s), &gic_thiscpu_ops, s,
|
||||
"gic_cpu", 0x100);
|
||||
for (i = 0; i < NUM_CPU(s); i++) {
|
||||
s->backref[i] = s;
|
||||
memory_region_init_io(&s->cpuiomem[i+1], OBJECT(s), &gic_cpu_ops,
|
||||
&s->backref[i], "gic_cpu", 0x100);
|
||||
}
|
||||
/* Distributor */
|
||||
sysbus_init_mmio(sbd, &s->iomem);
|
||||
/* cpu interfaces (one for "current cpu" plus one per cpu) */
|
||||
for (i = 0; i <= NUM_CPU(s); i++) {
|
||||
sysbus_init_mmio(sbd, &s->cpuiomem[i]);
|
||||
sysbus_init_mmio(sbd, &s->cpuiomem[i+1]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -84,6 +84,47 @@ static const VMStateDescription vmstate_gic = {
|
||||
}
|
||||
};
|
||||
|
||||
void gic_init_irqs_and_mmio(GICState *s, qemu_irq_handler handler,
|
||||
const MemoryRegionOps *ops)
|
||||
{
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(s);
|
||||
int i = s->num_irq - GIC_INTERNAL;
|
||||
|
||||
/* For the GIC, also expose incoming GPIO lines for PPIs for each CPU.
|
||||
* GPIO array layout is thus:
|
||||
* [0..N-1] SPIs
|
||||
* [N..N+31] PPIs for CPU 0
|
||||
* [N+32..N+63] PPIs for CPU 1
|
||||
* ...
|
||||
*/
|
||||
if (s->revision != REV_NVIC) {
|
||||
i += (GIC_INTERNAL * s->num_cpu);
|
||||
}
|
||||
qdev_init_gpio_in(DEVICE(s), handler, i);
|
||||
|
||||
for (i = 0; i < s->num_cpu; i++) {
|
||||
sysbus_init_irq(sbd, &s->parent_irq[i]);
|
||||
}
|
||||
for (i = 0; i < s->num_cpu; i++) {
|
||||
sysbus_init_irq(sbd, &s->parent_fiq[i]);
|
||||
}
|
||||
|
||||
/* Distributor */
|
||||
memory_region_init_io(&s->iomem, OBJECT(s), ops, s, "gic_dist", 0x1000);
|
||||
sysbus_init_mmio(sbd, &s->iomem);
|
||||
|
||||
if (s->revision != REV_NVIC) {
|
||||
/* This is the main CPU interface "for this core". It is always
|
||||
* present because it is required by both software emulation and KVM.
|
||||
* NVIC is not handled here because its CPU interface is different,
|
||||
* neither it can use KVM.
|
||||
*/
|
||||
memory_region_init_io(&s->cpuiomem[0], OBJECT(s), ops ? &ops[1] : NULL,
|
||||
s, "gic_cpu", s->revision == 2 ? 0x1000 : 0x100);
|
||||
sysbus_init_mmio(sbd, &s->cpuiomem[0]);
|
||||
}
|
||||
}
|
||||
|
||||
static void arm_gic_common_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
GICState *s = ARM_GIC_COMMON(dev);
|
||||
|
@ -543,7 +543,6 @@ static void kvm_arm_gic_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
int i;
|
||||
GICState *s = KVM_ARM_GIC(dev);
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
|
||||
KVMARMGICClass *kgc = KVM_ARM_GIC_GET_CLASS(s);
|
||||
Error *local_err = NULL;
|
||||
int ret;
|
||||
@ -560,32 +559,13 @@ static void kvm_arm_gic_realize(DeviceState *dev, Error **errp)
|
||||
return;
|
||||
}
|
||||
|
||||
i = s->num_irq - GIC_INTERNAL;
|
||||
/* For the GIC, also expose incoming GPIO lines for PPIs for each CPU.
|
||||
* GPIO array layout is thus:
|
||||
* [0..N-1] SPIs
|
||||
* [N..N+31] PPIs for CPU 0
|
||||
* [N+32..N+63] PPIs for CPU 1
|
||||
* ...
|
||||
*/
|
||||
i += (GIC_INTERNAL * s->num_cpu);
|
||||
qdev_init_gpio_in(dev, kvm_arm_gic_set_irq, i);
|
||||
gic_init_irqs_and_mmio(s, kvm_arm_gic_set_irq, NULL);
|
||||
|
||||
for (i = 0; i < s->num_irq - GIC_INTERNAL; i++) {
|
||||
qemu_irq irq = qdev_get_gpio_in(dev, i);
|
||||
kvm_irqchip_set_qemuirq_gsi(kvm_state, irq, i);
|
||||
}
|
||||
|
||||
/* We never use our outbound IRQ/FIQ lines but provide them so that
|
||||
* we maintain the same interface as the non-KVM GIC.
|
||||
*/
|
||||
for (i = 0; i < s->num_cpu; i++) {
|
||||
sysbus_init_irq(sbd, &s->parent_irq[i]);
|
||||
}
|
||||
for (i = 0; i < s->num_cpu; i++) {
|
||||
sysbus_init_irq(sbd, &s->parent_fiq[i]);
|
||||
}
|
||||
|
||||
/* Try to create the device via the device control API */
|
||||
s->dev_fd = -1;
|
||||
ret = kvm_create_device(kvm_state, KVM_DEV_TYPE_ARM_VGIC_V2, false);
|
||||
@ -609,9 +589,6 @@ static void kvm_arm_gic_realize(DeviceState *dev, Error **errp)
|
||||
}
|
||||
|
||||
/* Distributor */
|
||||
memory_region_init_reservation(&s->iomem, OBJECT(s),
|
||||
"kvm-gic_dist", 0x1000);
|
||||
sysbus_init_mmio(sbd, &s->iomem);
|
||||
kvm_arm_register_device(&s->iomem,
|
||||
(KVM_ARM_DEVICE_VGIC_V2 << KVM_ARM_DEVICE_ID_SHIFT)
|
||||
| KVM_VGIC_V2_ADDR_TYPE_DIST,
|
||||
@ -622,9 +599,6 @@ static void kvm_arm_gic_realize(DeviceState *dev, Error **errp)
|
||||
* provide the "interface for core #N" memory regions, because
|
||||
* cores with a VGIC don't have those.
|
||||
*/
|
||||
memory_region_init_reservation(&s->cpuiomem[0], OBJECT(s),
|
||||
"kvm-gic_cpu", 0x1000);
|
||||
sysbus_init_mmio(sbd, &s->cpuiomem[0]);
|
||||
kvm_arm_register_device(&s->cpuiomem[0],
|
||||
(KVM_ARM_DEVICE_VGIC_V2 << KVM_ARM_DEVICE_ID_SHIFT)
|
||||
| KVM_VGIC_V2_ADDR_TYPE_CPU,
|
||||
|
@ -7,6 +7,7 @@
|
||||
* Copyright (c) 2008 OKL
|
||||
* Copyright (c) 2011 NICTA Pty Ltd
|
||||
* Originally written by Hans Jiang
|
||||
* Updated by Jean-Christophe Dubois <jcd@tribudubois.net>
|
||||
*
|
||||
* This code is licensed under the GPL version 2 or later. See
|
||||
* the COPYING file in the top-level directory.
|
||||
@ -14,16 +15,14 @@
|
||||
* TODO: implement vectors.
|
||||
*/
|
||||
|
||||
#include "hw/hw.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "qemu/host-utils.h"
|
||||
#include "hw/intc/imx_avic.h"
|
||||
|
||||
#define DEBUG_INT 1
|
||||
#undef DEBUG_INT /* comment out for debugging */
|
||||
|
||||
#ifdef DEBUG_INT
|
||||
#define DPRINTF(fmt, args...) \
|
||||
do { printf("imx_avic: " fmt , ##args); } while (0)
|
||||
do { printf("%s: " fmt , TYPE_IMX_AVIC, ##args); } while (0)
|
||||
#else
|
||||
#define DPRINTF(fmt, args...) do {} while (0)
|
||||
#endif
|
||||
@ -35,46 +34,13 @@ do { printf("imx_avic: " fmt , ##args); } while (0)
|
||||
#define DEBUG_IMPLEMENTATION 1
|
||||
#if DEBUG_IMPLEMENTATION
|
||||
# define IPRINTF(fmt, args...) \
|
||||
do { fprintf(stderr, "imx_avic: " fmt, ##args); } while (0)
|
||||
do { fprintf(stderr, "%s: " fmt, TYPE_IMX_AVIC, ##args); } while (0)
|
||||
#else
|
||||
# define IPRINTF(fmt, args...) do {} while (0)
|
||||
#endif
|
||||
|
||||
#define IMX_AVIC_NUM_IRQS 64
|
||||
|
||||
/* Interrupt Control Bits */
|
||||
#define ABFLAG (1<<25)
|
||||
#define ABFEN (1<<24)
|
||||
#define NIDIS (1<<22) /* Normal Interrupt disable */
|
||||
#define FIDIS (1<<21) /* Fast interrupt disable */
|
||||
#define NIAD (1<<20) /* Normal Interrupt Arbiter Rise ARM level */
|
||||
#define FIAD (1<<19) /* Fast Interrupt Arbiter Rise ARM level */
|
||||
#define NM (1<<18) /* Normal interrupt mode */
|
||||
|
||||
|
||||
#define PRIO_PER_WORD (sizeof(uint32_t) * 8 / 4)
|
||||
#define PRIO_WORDS (IMX_AVIC_NUM_IRQS/PRIO_PER_WORD)
|
||||
|
||||
#define TYPE_IMX_AVIC "imx_avic"
|
||||
#define IMX_AVIC(obj) \
|
||||
OBJECT_CHECK(IMXAVICState, (obj), TYPE_IMX_AVIC)
|
||||
|
||||
typedef struct IMXAVICState {
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
MemoryRegion iomem;
|
||||
uint64_t pending;
|
||||
uint64_t enabled;
|
||||
uint64_t is_fiq;
|
||||
uint32_t intcntl;
|
||||
uint32_t intmask;
|
||||
qemu_irq irq;
|
||||
qemu_irq fiq;
|
||||
uint32_t prio[PRIO_WORDS]; /* Priorities are 4-bits each */
|
||||
} IMXAVICState;
|
||||
|
||||
static const VMStateDescription vmstate_imx_avic = {
|
||||
.name = "imx-avic",
|
||||
.name = TYPE_IMX_AVIC,
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
@ -88,8 +54,6 @@ static const VMStateDescription vmstate_imx_avic = {
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
|
||||
static inline int imx_avic_prio(IMXAVICState *s, int irq)
|
||||
{
|
||||
uint32_t word = irq / PRIO_PER_WORD;
|
||||
@ -249,7 +213,7 @@ static uint64_t imx_avic_read(void *opaque,
|
||||
return 0x4;
|
||||
|
||||
default:
|
||||
IPRINTF("imx_avic_read: Bad offset 0x%x\n", (int)offset);
|
||||
IPRINTF("%s: Bad offset 0x%x\n", __func__, (int)offset);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@ -261,12 +225,12 @@ static void imx_avic_write(void *opaque, hwaddr offset,
|
||||
|
||||
/* Vector Registers not yet supported */
|
||||
if (offset >= 0x100 && offset <= 0x2fc) {
|
||||
IPRINTF("imx_avic_write to vector register %d ignored\n",
|
||||
IPRINTF("%s to vector register %d ignored\n", __func__,
|
||||
(unsigned int)((offset - 0x100) >> 2));
|
||||
return;
|
||||
}
|
||||
|
||||
DPRINTF("imx_avic_write(0x%x) = %x\n",
|
||||
DPRINTF("%s(0x%x) = %x\n", __func__,
|
||||
(unsigned int)offset>>2, (unsigned int)val);
|
||||
switch (offset >> 2) {
|
||||
case 0: /* Interrupt Control Register, INTCNTL */
|
||||
@ -341,7 +305,7 @@ static void imx_avic_write(void *opaque, hwaddr offset,
|
||||
return;
|
||||
|
||||
default:
|
||||
IPRINTF("imx_avic_write: Bad offset %x\n", (int)offset);
|
||||
IPRINTF("%s: Bad offset %x\n", __func__, (int)offset);
|
||||
}
|
||||
imx_avic_update(s);
|
||||
}
|
||||
@ -370,7 +334,7 @@ static int imx_avic_init(SysBusDevice *sbd)
|
||||
IMXAVICState *s = IMX_AVIC(dev);
|
||||
|
||||
memory_region_init_io(&s->iomem, OBJECT(s), &imx_avic_ops, s,
|
||||
"imx_avic", 0x1000);
|
||||
TYPE_IMX_AVIC, 0x1000);
|
||||
sysbus_init_mmio(sbd, &s->iomem);
|
||||
|
||||
qdev_init_gpio_in(dev, imx_avic_set_irq, IMX_AVIC_NUM_IRQS);
|
||||
|
@ -2,6 +2,7 @@
|
||||
* IMX31 Clock Control Module
|
||||
*
|
||||
* Copyright (C) 2012 NICTA
|
||||
* Updated by Jean-Christophe Dubois <jcd@tribudubois.net>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
@ -10,51 +11,23 @@
|
||||
* the CCM.
|
||||
*/
|
||||
|
||||
#include "hw/hw.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "hw/arm/imx.h"
|
||||
#include "hw/misc/imx_ccm.h"
|
||||
|
||||
#define CKIH_FREQ 26000000 /* 26MHz crystal input */
|
||||
#define CKIL_FREQ 32768 /* nominal 32khz clock */
|
||||
|
||||
|
||||
//#define DEBUG_CCM 1
|
||||
#ifdef DEBUG_CCM
|
||||
#define DPRINTF(fmt, args...) \
|
||||
do { printf("imx_ccm: " fmt , ##args); } while (0)
|
||||
do { printf("%s: " fmt , TYPE_IMX_CCM, ##args); } while (0)
|
||||
#else
|
||||
#define DPRINTF(fmt, args...) do {} while (0)
|
||||
#endif
|
||||
|
||||
static int imx_ccm_post_load(void *opaque, int version_id);
|
||||
|
||||
#define TYPE_IMX_CCM "imx_ccm"
|
||||
#define IMX_CCM(obj) OBJECT_CHECK(IMXCCMState, (obj), TYPE_IMX_CCM)
|
||||
|
||||
typedef struct IMXCCMState {
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
MemoryRegion iomem;
|
||||
|
||||
uint32_t ccmr;
|
||||
uint32_t pdr0;
|
||||
uint32_t pdr1;
|
||||
uint32_t mpctl;
|
||||
uint32_t spctl;
|
||||
uint32_t cgr[3];
|
||||
uint32_t pmcr0;
|
||||
uint32_t pmcr1;
|
||||
|
||||
/* Frequencies precalculated on register changes */
|
||||
uint32_t pll_refclk_freq;
|
||||
uint32_t mcu_clk_freq;
|
||||
uint32_t hsp_clk_freq;
|
||||
uint32_t ipg_clk_freq;
|
||||
} IMXCCMState;
|
||||
|
||||
static const VMStateDescription vmstate_imx_ccm = {
|
||||
.name = "imx-ccm",
|
||||
.name = TYPE_IMX_CCM,
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
@ -72,44 +45,6 @@ static const VMStateDescription vmstate_imx_ccm = {
|
||||
.post_load = imx_ccm_post_load,
|
||||
};
|
||||
|
||||
/* CCMR */
|
||||
#define CCMR_FPME (1<<0)
|
||||
#define CCMR_MPE (1<<3)
|
||||
#define CCMR_MDS (1<<7)
|
||||
#define CCMR_FPMF (1<<26)
|
||||
#define CCMR_PRCS (3<<1)
|
||||
|
||||
/* PDR0 */
|
||||
#define PDR0_MCU_PODF_SHIFT (0)
|
||||
#define PDR0_MCU_PODF_MASK (0x7)
|
||||
#define PDR0_MAX_PODF_SHIFT (3)
|
||||
#define PDR0_MAX_PODF_MASK (0x7)
|
||||
#define PDR0_IPG_PODF_SHIFT (6)
|
||||
#define PDR0_IPG_PODF_MASK (0x3)
|
||||
#define PDR0_NFC_PODF_SHIFT (8)
|
||||
#define PDR0_NFC_PODF_MASK (0x7)
|
||||
#define PDR0_HSP_PODF_SHIFT (11)
|
||||
#define PDR0_HSP_PODF_MASK (0x7)
|
||||
#define PDR0_PER_PODF_SHIFT (16)
|
||||
#define PDR0_PER_PODF_MASK (0x1f)
|
||||
#define PDR0_CSI_PODF_SHIFT (23)
|
||||
#define PDR0_CSI_PODF_MASK (0x1ff)
|
||||
|
||||
#define EXTRACT(value, name) (((value) >> PDR0_##name##_PODF_SHIFT) \
|
||||
& PDR0_##name##_PODF_MASK)
|
||||
#define INSERT(value, name) (((value) & PDR0_##name##_PODF_MASK) << \
|
||||
PDR0_##name##_PODF_SHIFT)
|
||||
/* PLL control registers */
|
||||
#define PD(v) (((v) >> 26) & 0xf)
|
||||
#define MFD(v) (((v) >> 16) & 0x3ff)
|
||||
#define MFI(v) (((v) >> 10) & 0xf);
|
||||
#define MFN(v) ((v) & 0x3ff)
|
||||
|
||||
#define PLL_PD(x) (((x) & 0xf) << 26)
|
||||
#define PLL_MFD(x) (((x) & 0x3ff) << 16)
|
||||
#define PLL_MFI(x) (((x) & 0xf) << 10)
|
||||
#define PLL_MFN(x) (((x) & 0x3ff) << 0)
|
||||
|
||||
uint32_t imx_clock_frequency(DeviceState *dev, IMXClk clock)
|
||||
{
|
||||
IMXCCMState *s = IMX_CCM(dev);
|
||||
@ -174,7 +109,7 @@ static void update_clocks(IMXCCMState *s)
|
||||
s->hsp_clk_freq = s->mcu_clk_freq / (1 + EXTRACT(s->pdr0, HSP));
|
||||
s->ipg_clk_freq = s->hsp_clk_freq / (1 + EXTRACT(s->pdr0, IPG));
|
||||
|
||||
DPRINTF("Clocks: mcu %uMHz, HSP %uMHz, IPG %uHz\n",
|
||||
DPRINTF("%s: mcu %uMHz, HSP %uMHz, IPG %uHz\n", __func__,
|
||||
s->mcu_clk_freq / 1000000,
|
||||
s->hsp_clk_freq / 1000000,
|
||||
s->ipg_clk_freq);
|
||||
@ -200,7 +135,7 @@ static uint64_t imx_ccm_read(void *opaque, hwaddr offset,
|
||||
{
|
||||
IMXCCMState *s = (IMXCCMState *)opaque;
|
||||
|
||||
DPRINTF("read(offset=%x)", offset >> 2);
|
||||
DPRINTF("%s(offset=%x)", __func__, offset >> 2);
|
||||
switch (offset >> 2) {
|
||||
case 0: /* CCMR */
|
||||
DPRINTF(" ccmr = 0x%x\n", s->ccmr);
|
||||
@ -241,7 +176,7 @@ static void imx_ccm_write(void *opaque, hwaddr offset,
|
||||
{
|
||||
IMXCCMState *s = (IMXCCMState *)opaque;
|
||||
|
||||
DPRINTF("write(offset=%x, value = %x)\n",
|
||||
DPRINTF("%s(offset=%x, value = %x)\n", __func__,
|
||||
offset >> 2, (unsigned int)value);
|
||||
switch (offset >> 2) {
|
||||
case 0:
|
||||
@ -286,7 +221,7 @@ static int imx_ccm_init(SysBusDevice *dev)
|
||||
IMXCCMState *s = IMX_CCM(dev);
|
||||
|
||||
memory_region_init_io(&s->iomem, OBJECT(dev), &imx_ccm_ops, s,
|
||||
"imx_ccm", 0x1000);
|
||||
TYPE_IMX_CCM, 0x1000);
|
||||
sysbus_init_mmio(dev, &s->iomem);
|
||||
|
||||
return 0;
|
||||
|
@ -5,23 +5,18 @@
|
||||
* 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 "hw/timer/imx_epit.h"
|
||||
#include "hw/misc/imx_ccm.h"
|
||||
#include "qemu/main-loop.h"
|
||||
|
||||
#define TYPE_IMX_EPIT "imx.epit"
|
||||
|
||||
#define DEBUG_TIMER 0
|
||||
#if DEBUG_TIMER
|
||||
|
||||
@ -61,30 +56,6 @@ static char const *imx_epit_reg_name(uint32_t reg)
|
||||
# define IPRINTF(fmt, args...) do {} while (0)
|
||||
#endif
|
||||
|
||||
#define IMX_EPIT(obj) \
|
||||
OBJECT_CHECK(IMXEPITState, (obj), TYPE_IMX_EPIT)
|
||||
|
||||
/*
|
||||
* EPIT: Enhanced periodic interrupt timer
|
||||
*/
|
||||
|
||||
#define CR_EN (1 << 0)
|
||||
#define CR_ENMOD (1 << 1)
|
||||
#define CR_OCIEN (1 << 2)
|
||||
#define CR_RLD (1 << 3)
|
||||
#define CR_PRESCALE_SHIFT (4)
|
||||
#define CR_PRESCALE_MASK (0xfff)
|
||||
#define CR_SWR (1 << 16)
|
||||
#define CR_IOVW (1 << 17)
|
||||
#define CR_DBGEN (1 << 18)
|
||||
#define CR_WAITEN (1 << 19)
|
||||
#define CR_DOZEN (1 << 20)
|
||||
#define CR_STOPEN (1 << 21)
|
||||
#define CR_CLKSRC_SHIFT (24)
|
||||
#define CR_CLKSRC_MASK (0x3 << CR_CLKSRC_SHIFT)
|
||||
|
||||
#define EPIT_TIMER_MAX 0XFFFFFFFFUL
|
||||
|
||||
/*
|
||||
* Exact clock frequencies vary from board to board.
|
||||
* These are typical.
|
||||
@ -96,23 +67,6 @@ static const IMXClk imx_epit_clocks[] = {
|
||||
CLK_32k, /* 11 ipg_clk_32k -- ~32kHz */
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
SysBusDevice busdev;
|
||||
ptimer_state *timer_reload;
|
||||
ptimer_state *timer_cmp;
|
||||
MemoryRegion iomem;
|
||||
DeviceState *ccm;
|
||||
|
||||
uint32_t cr;
|
||||
uint32_t sr;
|
||||
uint32_t lr;
|
||||
uint32_t cmp;
|
||||
uint32_t cnt;
|
||||
|
||||
uint32_t freq;
|
||||
qemu_irq irq;
|
||||
} IMXEPITState;
|
||||
|
||||
/*
|
||||
* Update interrupt status
|
||||
*/
|
||||
@ -174,9 +128,9 @@ static void imx_epit_reset(DeviceState *dev)
|
||||
|
||||
static uint32_t imx_epit_update_count(IMXEPITState *s)
|
||||
{
|
||||
s->cnt = ptimer_get_count(s->timer_reload);
|
||||
s->cnt = ptimer_get_count(s->timer_reload);
|
||||
|
||||
return s->cnt;
|
||||
return s->cnt;
|
||||
}
|
||||
|
||||
static uint64_t imx_epit_read(void *opaque, hwaddr offset, unsigned size)
|
||||
@ -344,13 +298,13 @@ void imx_timerp_create(const hwaddr addr, qemu_irq irq, DeviceState *ccm)
|
||||
}
|
||||
|
||||
static const MemoryRegionOps imx_epit_ops = {
|
||||
.read = imx_epit_read,
|
||||
.write = imx_epit_write,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
.read = imx_epit_read,
|
||||
.write = imx_epit_write,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
static const VMStateDescription vmstate_imx_timer_epit = {
|
||||
.name = "imx.epit",
|
||||
.name = TYPE_IMX_EPIT,
|
||||
.version_id = 2,
|
||||
.minimum_version_id = 2,
|
||||
.fields = (VMStateField[]) {
|
||||
|
@ -5,23 +5,18 @@
|
||||
* 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 "hw/timer/imx_gpt.h"
|
||||
#include "hw/misc/imx_ccm.h"
|
||||
#include "qemu/main-loop.h"
|
||||
|
||||
#define TYPE_IMX_GPT "imx.gpt"
|
||||
|
||||
/*
|
||||
* Define to 1 for debug messages
|
||||
*/
|
||||
@ -74,76 +69,8 @@ static char const *imx_gpt_reg_name(uint32_t reg)
|
||||
# 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[]) {
|
||||
@ -180,7 +107,7 @@ 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);
|
||||
/ (1 + s->pr);
|
||||
s->freq = freq;
|
||||
|
||||
DPRINTF("Setting clksrc %d to frequency %d\n", clksrc, freq);
|
||||
@ -207,7 +134,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;
|
||||
|
@ -437,6 +437,9 @@ void memory_region_init_alias(MemoryRegion *mr,
|
||||
* memory_region_init_rom_device: Initialize a ROM memory region. Writes are
|
||||
* handled via callbacks.
|
||||
*
|
||||
* If NULL callbacks pointer is given, then I/O space is not supposed to be
|
||||
* handled by QEMU itself. Any access via the memory API will cause an abort().
|
||||
*
|
||||
* @mr: the #MemoryRegion to be initialized.
|
||||
* @owner: the object that tracks the region's reference count
|
||||
* @ops: callbacks for write access handling.
|
||||
@ -459,16 +462,21 @@ void memory_region_init_rom_device(MemoryRegion *mr,
|
||||
* A reservation region primariy serves debugging purposes. It claims I/O
|
||||
* space that is not supposed to be handled by QEMU itself. Any access via
|
||||
* the memory API will cause an abort().
|
||||
* This function is deprecated. Use memory_region_init_io() with NULL
|
||||
* callbacks instead.
|
||||
*
|
||||
* @mr: the #MemoryRegion to be initialized
|
||||
* @owner: the object that tracks the region's reference count
|
||||
* @name: used for debugging; not visible to the user or ABI
|
||||
* @size: size of the region.
|
||||
*/
|
||||
void memory_region_init_reservation(MemoryRegion *mr,
|
||||
struct Object *owner,
|
||||
static inline void memory_region_init_reservation(MemoryRegion *mr,
|
||||
Object *owner,
|
||||
const char *name,
|
||||
uint64_t size);
|
||||
uint64_t size)
|
||||
{
|
||||
memory_region_init_io(mr, owner, NULL, mr, name, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* memory_region_init_iommu: Initialize a memory region that translates
|
||||
|
@ -11,18 +11,10 @@
|
||||
#ifndef IMX_H
|
||||
#define IMX_H
|
||||
|
||||
#include "hw/misc/imx_ccm.h"
|
||||
|
||||
void imx_serial_create(int uart, const hwaddr addr, qemu_irq irq);
|
||||
|
||||
typedef enum {
|
||||
NOCLK,
|
||||
MCU,
|
||||
HSP,
|
||||
IPG,
|
||||
CLK_32k
|
||||
} IMXClk;
|
||||
|
||||
uint32_t imx_clock_frequency(DeviceState *s, IMXClk clock);
|
||||
|
||||
void imx_timerp_create(const hwaddr addr,
|
||||
qemu_irq irq,
|
||||
DeviceState *ccm);
|
||||
|
102
include/hw/char/imx_serial.h
Normal file
102
include/hw/char/imx_serial.h
Normal file
@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Device model for i.MX UART
|
||||
*
|
||||
* Copyright (c) 2008 OKL
|
||||
* Originally Written by Hans Jiang
|
||||
* Copyright (c) 2011 NICTA Pty Ltd.
|
||||
* Updated by Jean-Christophe Dubois <jcd@tribudubois.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef IMX_SERIAL_H
|
||||
#define IMX_SERIAL_H
|
||||
|
||||
#include "hw/sysbus.h"
|
||||
|
||||
#define TYPE_IMX_SERIAL "imx.serial"
|
||||
#define IMX_SERIAL(obj) OBJECT_CHECK(IMXSerialState, (obj), TYPE_IMX_SERIAL)
|
||||
|
||||
#define URXD_CHARRDY (1<<15) /* character read is valid */
|
||||
#define URXD_ERR (1<<14) /* Character has error */
|
||||
#define URXD_BRK (1<<11) /* Break received */
|
||||
|
||||
#define USR1_PARTYER (1<<15) /* Parity Error */
|
||||
#define USR1_RTSS (1<<14) /* RTS pin status */
|
||||
#define USR1_TRDY (1<<13) /* Tx ready */
|
||||
#define USR1_RTSD (1<<12) /* RTS delta: pin changed state */
|
||||
#define USR1_ESCF (1<<11) /* Escape sequence interrupt */
|
||||
#define USR1_FRAMERR (1<<10) /* Framing error */
|
||||
#define USR1_RRDY (1<<9) /* receiver ready */
|
||||
#define USR1_AGTIM (1<<8) /* Aging timer interrupt */
|
||||
#define USR1_DTRD (1<<7) /* DTR changed */
|
||||
#define USR1_RXDS (1<<6) /* Receiver is idle */
|
||||
#define USR1_AIRINT (1<<5) /* Aysnch IR interrupt */
|
||||
#define USR1_AWAKE (1<<4) /* Falling edge detected on RXd pin */
|
||||
|
||||
#define USR2_ADET (1<<15) /* Autobaud complete */
|
||||
#define USR2_TXFE (1<<14) /* Transmit FIFO empty */
|
||||
#define USR2_DTRF (1<<13) /* DTR/DSR transition */
|
||||
#define USR2_IDLE (1<<12) /* UART has been idle for too long */
|
||||
#define USR2_ACST (1<<11) /* Autobaud counter stopped */
|
||||
#define USR2_RIDELT (1<<10) /* Ring Indicator delta */
|
||||
#define USR2_RIIN (1<<9) /* Ring Indicator Input */
|
||||
#define USR2_IRINT (1<<8) /* Serial Infrared Interrupt */
|
||||
#define USR2_WAKE (1<<7) /* Start bit detected */
|
||||
#define USR2_DCDDELT (1<<6) /* Data Carrier Detect delta */
|
||||
#define USR2_DCDIN (1<<5) /* Data Carrier Detect Input */
|
||||
#define USR2_RTSF (1<<4) /* RTS transition */
|
||||
#define USR2_TXDC (1<<3) /* Transmission complete */
|
||||
#define USR2_BRCD (1<<2) /* Break condition detected */
|
||||
#define USR2_ORE (1<<1) /* Overrun error */
|
||||
#define USR2_RDR (1<<0) /* Receive data ready */
|
||||
|
||||
#define UCR1_TRDYEN (1<<13) /* Tx Ready Interrupt Enable */
|
||||
#define UCR1_RRDYEN (1<<9) /* Rx Ready Interrupt Enable */
|
||||
#define UCR1_TXMPTYEN (1<<6) /* Tx Empty Interrupt Enable */
|
||||
#define UCR1_UARTEN (1<<0) /* UART Enable */
|
||||
|
||||
#define UCR2_TXEN (1<<2) /* Transmitter enable */
|
||||
#define UCR2_RXEN (1<<1) /* Receiver enable */
|
||||
#define UCR2_SRST (1<<0) /* Reset complete */
|
||||
|
||||
#define UTS1_TXEMPTY (1<<6)
|
||||
#define UTS1_RXEMPTY (1<<5)
|
||||
#define UTS1_TXFULL (1<<4)
|
||||
#define UTS1_RXFULL (1<<3)
|
||||
|
||||
typedef struct IMXSerialState {
|
||||
/*< private >*/
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
/*< public >*/
|
||||
MemoryRegion iomem;
|
||||
int32_t readbuff;
|
||||
|
||||
uint32_t usr1;
|
||||
uint32_t usr2;
|
||||
uint32_t ucr1;
|
||||
uint32_t ucr2;
|
||||
uint32_t uts1;
|
||||
|
||||
/*
|
||||
* The registers below are implemented just so that the
|
||||
* guest OS sees what it has written
|
||||
*/
|
||||
uint32_t onems;
|
||||
uint32_t ufcr;
|
||||
uint32_t ubmr;
|
||||
uint32_t ubrc;
|
||||
uint32_t ucr3;
|
||||
|
||||
qemu_irq irq;
|
||||
CharDriverState *chr;
|
||||
} IMXSerialState;
|
||||
|
||||
#endif
|
@ -138,4 +138,7 @@ typedef struct ARMGICCommonClass {
|
||||
void (*post_load)(GICState *s);
|
||||
} ARMGICCommonClass;
|
||||
|
||||
void gic_init_irqs_and_mmio(GICState *s, qemu_irq_handler handler,
|
||||
const MemoryRegionOps *ops);
|
||||
|
||||
#endif
|
||||
|
55
include/hw/intc/imx_avic.h
Normal file
55
include/hw/intc/imx_avic.h
Normal file
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* i.MX31 Vectored Interrupt Controller
|
||||
*
|
||||
* Note this is NOT the PL192 provided by ARM, but
|
||||
* a custom implementation by Freescale.
|
||||
*
|
||||
* Copyright (c) 2008 OKL
|
||||
* Copyright (c) 2011 NICTA Pty Ltd
|
||||
* Originally written by Hans Jiang
|
||||
* Updated by Jean-Christophe Dubois <jcd@tribudubois.net>
|
||||
*
|
||||
* This code is licensed under the GPL version 2 or later. See
|
||||
* the COPYING file in the top-level directory.
|
||||
*
|
||||
* TODO: implement vectors.
|
||||
*/
|
||||
#ifndef IMX_AVIC_H
|
||||
#define IMX_AVIC_H
|
||||
|
||||
#include "hw/sysbus.h"
|
||||
|
||||
#define TYPE_IMX_AVIC "imx.avic"
|
||||
#define IMX_AVIC(obj) OBJECT_CHECK(IMXAVICState, (obj), TYPE_IMX_AVIC)
|
||||
|
||||
#define IMX_AVIC_NUM_IRQS 64
|
||||
|
||||
/* Interrupt Control Bits */
|
||||
#define ABFLAG (1<<25)
|
||||
#define ABFEN (1<<24)
|
||||
#define NIDIS (1<<22) /* Normal Interrupt disable */
|
||||
#define FIDIS (1<<21) /* Fast interrupt disable */
|
||||
#define NIAD (1<<20) /* Normal Interrupt Arbiter Rise ARM level */
|
||||
#define FIAD (1<<19) /* Fast Interrupt Arbiter Rise ARM level */
|
||||
#define NM (1<<18) /* Normal interrupt mode */
|
||||
|
||||
#define PRIO_PER_WORD (sizeof(uint32_t) * 8 / 4)
|
||||
#define PRIO_WORDS (IMX_AVIC_NUM_IRQS/PRIO_PER_WORD)
|
||||
|
||||
typedef struct IMXAVICState{
|
||||
/*< private >*/
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
/*< public >*/
|
||||
MemoryRegion iomem;
|
||||
uint64_t pending;
|
||||
uint64_t enabled;
|
||||
uint64_t is_fiq;
|
||||
uint32_t intcntl;
|
||||
uint32_t intmask;
|
||||
qemu_irq irq;
|
||||
qemu_irq fiq;
|
||||
uint32_t prio[PRIO_WORDS]; /* Priorities are 4-bits each */
|
||||
} IMXAVICState;
|
||||
|
||||
#endif /* IMX_AVIC_H */
|
91
include/hw/misc/imx_ccm.h
Normal file
91
include/hw/misc/imx_ccm.h
Normal file
@ -0,0 +1,91 @@
|
||||
/*
|
||||
* IMX31 Clock Control Module
|
||||
*
|
||||
* Copyright (C) 2012 NICTA
|
||||
* Updated by Jean-Christophe Dubois <jcd@tribudubois.net>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#ifndef IMX_CCM_H
|
||||
#define IMX_CCM_H
|
||||
|
||||
#include "hw/sysbus.h"
|
||||
|
||||
/* CCMR */
|
||||
#define CCMR_FPME (1<<0)
|
||||
#define CCMR_MPE (1<<3)
|
||||
#define CCMR_MDS (1<<7)
|
||||
#define CCMR_FPMF (1<<26)
|
||||
#define CCMR_PRCS (3<<1)
|
||||
|
||||
/* PDR0 */
|
||||
#define PDR0_MCU_PODF_SHIFT (0)
|
||||
#define PDR0_MCU_PODF_MASK (0x7)
|
||||
#define PDR0_MAX_PODF_SHIFT (3)
|
||||
#define PDR0_MAX_PODF_MASK (0x7)
|
||||
#define PDR0_IPG_PODF_SHIFT (6)
|
||||
#define PDR0_IPG_PODF_MASK (0x3)
|
||||
#define PDR0_NFC_PODF_SHIFT (8)
|
||||
#define PDR0_NFC_PODF_MASK (0x7)
|
||||
#define PDR0_HSP_PODF_SHIFT (11)
|
||||
#define PDR0_HSP_PODF_MASK (0x7)
|
||||
#define PDR0_PER_PODF_SHIFT (16)
|
||||
#define PDR0_PER_PODF_MASK (0x1f)
|
||||
#define PDR0_CSI_PODF_SHIFT (23)
|
||||
#define PDR0_CSI_PODF_MASK (0x1ff)
|
||||
|
||||
#define EXTRACT(value, name) (((value) >> PDR0_##name##_PODF_SHIFT) \
|
||||
& PDR0_##name##_PODF_MASK)
|
||||
#define INSERT(value, name) (((value) & PDR0_##name##_PODF_MASK) << \
|
||||
PDR0_##name##_PODF_SHIFT)
|
||||
|
||||
/* PLL control registers */
|
||||
#define PD(v) (((v) >> 26) & 0xf)
|
||||
#define MFD(v) (((v) >> 16) & 0x3ff)
|
||||
#define MFI(v) (((v) >> 10) & 0xf);
|
||||
#define MFN(v) ((v) & 0x3ff)
|
||||
|
||||
#define PLL_PD(x) (((x) & 0xf) << 26)
|
||||
#define PLL_MFD(x) (((x) & 0x3ff) << 16)
|
||||
#define PLL_MFI(x) (((x) & 0xf) << 10)
|
||||
#define PLL_MFN(x) (((x) & 0x3ff) << 0)
|
||||
|
||||
#define TYPE_IMX_CCM "imx.ccm"
|
||||
#define IMX_CCM(obj) OBJECT_CHECK(IMXCCMState, (obj), TYPE_IMX_CCM)
|
||||
|
||||
typedef struct IMXCCMState {
|
||||
/* <private> */
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
/* <public> */
|
||||
MemoryRegion iomem;
|
||||
|
||||
uint32_t ccmr;
|
||||
uint32_t pdr0;
|
||||
uint32_t pdr1;
|
||||
uint32_t mpctl;
|
||||
uint32_t spctl;
|
||||
uint32_t cgr[3];
|
||||
uint32_t pmcr0;
|
||||
uint32_t pmcr1;
|
||||
|
||||
/* Frequencies precalculated on register changes */
|
||||
uint32_t pll_refclk_freq;
|
||||
uint32_t mcu_clk_freq;
|
||||
uint32_t hsp_clk_freq;
|
||||
uint32_t ipg_clk_freq;
|
||||
} IMXCCMState;
|
||||
|
||||
typedef enum {
|
||||
NOCLK,
|
||||
MCU,
|
||||
HSP,
|
||||
IPG,
|
||||
CLK_32k
|
||||
} IMXClk;
|
||||
|
||||
uint32_t imx_clock_frequency(DeviceState *s, IMXClk clock);
|
||||
|
||||
#endif /* IMX_CCM_H */
|
79
include/hw/timer/imx_epit.h
Normal file
79
include/hw/timer/imx_epit.h
Normal file
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* i.MX EPIT Timer
|
||||
*
|
||||
* Copyright (c) 2008 OK Labs
|
||||
* Copyright (c) 2011 NICTA Pty Ltd
|
||||
* Originally written by Hans Jiang
|
||||
* Updated by Peter Chubb
|
||||
* Updated by Jean-Christophe Dubois <jcd@tribudubois.net>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef IMX_EPIT_H
|
||||
#define IMX_EPIT_H
|
||||
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/ptimer.h"
|
||||
|
||||
/*
|
||||
* EPIT: Enhanced periodic interrupt timer
|
||||
*/
|
||||
|
||||
#define CR_EN (1 << 0)
|
||||
#define CR_ENMOD (1 << 1)
|
||||
#define CR_OCIEN (1 << 2)
|
||||
#define CR_RLD (1 << 3)
|
||||
#define CR_PRESCALE_SHIFT (4)
|
||||
#define CR_PRESCALE_MASK (0xfff)
|
||||
#define CR_SWR (1 << 16)
|
||||
#define CR_IOVW (1 << 17)
|
||||
#define CR_DBGEN (1 << 18)
|
||||
#define CR_WAITEN (1 << 19)
|
||||
#define CR_DOZEN (1 << 20)
|
||||
#define CR_STOPEN (1 << 21)
|
||||
#define CR_CLKSRC_SHIFT (24)
|
||||
#define CR_CLKSRC_MASK (0x3 << CR_CLKSRC_SHIFT)
|
||||
|
||||
#define EPIT_TIMER_MAX 0XFFFFFFFFUL
|
||||
|
||||
#define TYPE_IMX_EPIT "imx.epit"
|
||||
#define IMX_EPIT(obj) OBJECT_CHECK(IMXEPITState, (obj), TYPE_IMX_EPIT)
|
||||
|
||||
typedef struct IMXEPITState{
|
||||
/*< private >*/
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
/*< public >*/
|
||||
ptimer_state *timer_reload;
|
||||
ptimer_state *timer_cmp;
|
||||
MemoryRegion iomem;
|
||||
DeviceState *ccm;
|
||||
|
||||
uint32_t cr;
|
||||
uint32_t sr;
|
||||
uint32_t lr;
|
||||
uint32_t cmp;
|
||||
uint32_t cnt;
|
||||
|
||||
uint32_t freq;
|
||||
qemu_irq irq;
|
||||
} IMXEPITState;
|
||||
|
||||
#endif /* IMX_EPIT_H */
|
107
include/hw/timer/imx_gpt.h
Normal file
107
include/hw/timer/imx_gpt.h
Normal file
@ -0,0 +1,107 @@
|
||||
/*
|
||||
* i.MX GPT Timer
|
||||
*
|
||||
* Copyright (c) 2008 OK Labs
|
||||
* Copyright (c) 2011 NICTA Pty Ltd
|
||||
* Originally written by Hans Jiang
|
||||
* Updated by Peter Chubb
|
||||
* Updated by Jean-Christophe Dubois <jcd@tribudubois.net>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef IMX_GPT_H
|
||||
#define IMX_GPT_H
|
||||
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/ptimer.h"
|
||||
|
||||
/*
|
||||
* 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)
|
||||
|
||||
#define TYPE_IMX_GPT "imx.gpt"
|
||||
#define IMX_GPT(obj) OBJECT_CHECK(IMXGPTState, (obj), TYPE_IMX_GPT)
|
||||
|
||||
typedef struct IMXGPTState{
|
||||
/*< private >*/
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
/*< public >*/
|
||||
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;
|
||||
|
||||
#endif /* IMX_GPT_H */
|
10
memory.c
10
memory.c
@ -1182,7 +1182,7 @@ void memory_region_init_io(MemoryRegion *mr,
|
||||
uint64_t size)
|
||||
{
|
||||
memory_region_init(mr, owner, name, size);
|
||||
mr->ops = ops;
|
||||
mr->ops = ops ? ops : &unassigned_mem_ops;
|
||||
mr->opaque = opaque;
|
||||
mr->terminates = true;
|
||||
}
|
||||
@ -1300,14 +1300,6 @@ void memory_region_init_iommu(MemoryRegion *mr,
|
||||
notifier_list_init(&mr->iommu_notify);
|
||||
}
|
||||
|
||||
void memory_region_init_reservation(MemoryRegion *mr,
|
||||
Object *owner,
|
||||
const char *name,
|
||||
uint64_t size)
|
||||
{
|
||||
memory_region_init_io(mr, owner, &unassigned_mem_ops, mr, name, size);
|
||||
}
|
||||
|
||||
static void memory_region_finalize(Object *obj)
|
||||
{
|
||||
MemoryRegion *mr = MEMORY_REGION(obj);
|
||||
|
@ -224,6 +224,8 @@ int arm_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
|
||||
/* Callback functions for the generic timer's timers. */
|
||||
void arm_gt_ptimer_cb(void *opaque);
|
||||
void arm_gt_vtimer_cb(void *opaque);
|
||||
void arm_gt_htimer_cb(void *opaque);
|
||||
void arm_gt_stimer_cb(void *opaque);
|
||||
|
||||
#ifdef TARGET_AARCH64
|
||||
int aarch64_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
|
||||
|
@ -79,6 +79,27 @@ static void cp_reg_reset(gpointer key, gpointer value, gpointer opaque)
|
||||
}
|
||||
}
|
||||
|
||||
static void cp_reg_check_reset(gpointer key, gpointer value, gpointer opaque)
|
||||
{
|
||||
/* Purely an assertion check: we've already done reset once,
|
||||
* so now check that running the reset for the cpreg doesn't
|
||||
* change its value. This traps bugs where two different cpregs
|
||||
* both try to reset the same state field but to different values.
|
||||
*/
|
||||
ARMCPRegInfo *ri = value;
|
||||
ARMCPU *cpu = opaque;
|
||||
uint64_t oldvalue, newvalue;
|
||||
|
||||
if (ri->type & (ARM_CP_SPECIAL | ARM_CP_ALIAS | ARM_CP_NO_RAW)) {
|
||||
return;
|
||||
}
|
||||
|
||||
oldvalue = read_raw_cp_reg(&cpu->env, ri);
|
||||
cp_reg_reset(key, value, opaque);
|
||||
newvalue = read_raw_cp_reg(&cpu->env, ri);
|
||||
assert(oldvalue == newvalue);
|
||||
}
|
||||
|
||||
/* CPUClass::reset() */
|
||||
static void arm_cpu_reset(CPUState *s)
|
||||
{
|
||||
@ -90,6 +111,8 @@ static void arm_cpu_reset(CPUState *s)
|
||||
|
||||
memset(env, 0, offsetof(CPUARMState, features));
|
||||
g_hash_table_foreach(cpu->cp_regs, cp_reg_reset, cpu);
|
||||
g_hash_table_foreach(cpu->cp_regs, cp_reg_check_reset, cpu);
|
||||
|
||||
env->vfp.xregs[ARM_VFP_FPSID] = cpu->reset_fpsid;
|
||||
env->vfp.xregs[ARM_VFP_MVFR0] = cpu->mvfr0;
|
||||
env->vfp.xregs[ARM_VFP_MVFR1] = cpu->mvfr1;
|
||||
@ -453,6 +476,10 @@ static void arm_cpu_initfn(Object *obj)
|
||||
arm_gt_ptimer_cb, cpu);
|
||||
cpu->gt_timer[GTIMER_VIRT] = timer_new(QEMU_CLOCK_VIRTUAL, GTIMER_SCALE,
|
||||
arm_gt_vtimer_cb, cpu);
|
||||
cpu->gt_timer[GTIMER_HYP] = timer_new(QEMU_CLOCK_VIRTUAL, GTIMER_SCALE,
|
||||
arm_gt_htimer_cb, cpu);
|
||||
cpu->gt_timer[GTIMER_SEC] = timer_new(QEMU_CLOCK_VIRTUAL, GTIMER_SCALE,
|
||||
arm_gt_stimer_cb, cpu);
|
||||
qdev_init_gpio_out(DEVICE(cpu), cpu->gt_timer_outputs,
|
||||
ARRAY_SIZE(cpu->gt_timer_outputs));
|
||||
#endif
|
||||
|
@ -113,7 +113,9 @@ typedef struct ARMGenericTimer {
|
||||
|
||||
#define GTIMER_PHYS 0
|
||||
#define GTIMER_VIRT 1
|
||||
#define NUM_GTIMERS 2
|
||||
#define GTIMER_HYP 2
|
||||
#define GTIMER_SEC 3
|
||||
#define NUM_GTIMERS 4
|
||||
|
||||
typedef struct {
|
||||
uint64_t raw_tcr;
|
||||
@ -358,6 +360,8 @@ typedef struct CPUARMState {
|
||||
};
|
||||
uint64_t c14_cntfrq; /* Counter Frequency register */
|
||||
uint64_t c14_cntkctl; /* Timer Control register */
|
||||
uint32_t cnthctl_el2; /* Counter/Timer Hyp Control register */
|
||||
uint64_t cntvoff_el2; /* Counter Virtual Offset register */
|
||||
ARMGenericTimer c14_timer[NUM_GTIMERS];
|
||||
uint32_t c15_cpar; /* XScale Coprocessor Access Register */
|
||||
uint32_t c15_ticonfig; /* TI925T configuration byte. */
|
||||
@ -1445,6 +1449,9 @@ static inline bool cp_access_ok(int current_el,
|
||||
return (ri->access >> ((current_el * 2) + isread)) & 1;
|
||||
}
|
||||
|
||||
/* Raw read of a coprocessor register (as needed for migration, etc) */
|
||||
uint64_t read_raw_cp_reg(CPUARMState *env, const ARMCPRegInfo *ri);
|
||||
|
||||
/**
|
||||
* write_list_to_cpustate
|
||||
* @cpu: ARMCPU
|
||||
|
@ -144,7 +144,7 @@ static void *raw_ptr(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||
return (char *)env + ri->fieldoffset;
|
||||
}
|
||||
|
||||
static uint64_t read_raw_cp_reg(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||
uint64_t read_raw_cp_reg(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||
{
|
||||
/* Raw read of a coprocessor register (as needed for migration, etc). */
|
||||
if (ri->type & ARM_CP_CONST) {
|
||||
@ -1154,23 +1154,41 @@ static CPAccessResult gt_cntfrq_access(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||
|
||||
static CPAccessResult gt_counter_access(CPUARMState *env, int timeridx)
|
||||
{
|
||||
unsigned int cur_el = arm_current_el(env);
|
||||
bool secure = arm_is_secure(env);
|
||||
|
||||
/* CNT[PV]CT: not visible from PL0 if ELO[PV]CTEN is zero */
|
||||
if (arm_current_el(env) == 0 &&
|
||||
if (cur_el == 0 &&
|
||||
!extract32(env->cp15.c14_cntkctl, timeridx, 1)) {
|
||||
return CP_ACCESS_TRAP;
|
||||
}
|
||||
|
||||
if (arm_feature(env, ARM_FEATURE_EL2) &&
|
||||
timeridx == GTIMER_PHYS && !secure && cur_el < 2 &&
|
||||
!extract32(env->cp15.cnthctl_el2, 0, 1)) {
|
||||
return CP_ACCESS_TRAP_EL2;
|
||||
}
|
||||
return CP_ACCESS_OK;
|
||||
}
|
||||
|
||||
static CPAccessResult gt_timer_access(CPUARMState *env, int timeridx)
|
||||
{
|
||||
unsigned int cur_el = arm_current_el(env);
|
||||
bool secure = arm_is_secure(env);
|
||||
|
||||
/* CNT[PV]_CVAL, CNT[PV]_CTL, CNT[PV]_TVAL: not visible from PL0 if
|
||||
* EL0[PV]TEN is zero.
|
||||
*/
|
||||
if (arm_current_el(env) == 0 &&
|
||||
if (cur_el == 0 &&
|
||||
!extract32(env->cp15.c14_cntkctl, 9 - timeridx, 1)) {
|
||||
return CP_ACCESS_TRAP;
|
||||
}
|
||||
|
||||
if (arm_feature(env, ARM_FEATURE_EL2) &&
|
||||
timeridx == GTIMER_PHYS && !secure && cur_el < 2 &&
|
||||
!extract32(env->cp15.cnthctl_el2, 1, 1)) {
|
||||
return CP_ACCESS_TRAP_EL2;
|
||||
}
|
||||
return CP_ACCESS_OK;
|
||||
}
|
||||
|
||||
@ -1196,6 +1214,32 @@ static CPAccessResult gt_vtimer_access(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||
return gt_timer_access(env, GTIMER_VIRT);
|
||||
}
|
||||
|
||||
static CPAccessResult gt_stimer_access(CPUARMState *env,
|
||||
const ARMCPRegInfo *ri)
|
||||
{
|
||||
/* The AArch64 register view of the secure physical timer is
|
||||
* always accessible from EL3, and configurably accessible from
|
||||
* Secure EL1.
|
||||
*/
|
||||
switch (arm_current_el(env)) {
|
||||
case 1:
|
||||
if (!arm_is_secure(env)) {
|
||||
return CP_ACCESS_TRAP;
|
||||
}
|
||||
if (!(env->cp15.scr_el3 & SCR_ST)) {
|
||||
return CP_ACCESS_TRAP_EL3;
|
||||
}
|
||||
return CP_ACCESS_OK;
|
||||
case 0:
|
||||
case 2:
|
||||
return CP_ACCESS_TRAP;
|
||||
case 3:
|
||||
return CP_ACCESS_OK;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t gt_get_countervalue(CPUARMState *env)
|
||||
{
|
||||
return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / GTIMER_SCALE;
|
||||
@ -1209,9 +1253,11 @@ static void gt_recalc_timer(ARMCPU *cpu, int timeridx)
|
||||
/* Timer enabled: calculate and set current ISTATUS, irq, and
|
||||
* reset timer to when ISTATUS next has to change
|
||||
*/
|
||||
uint64_t offset = timeridx == GTIMER_VIRT ?
|
||||
cpu->env.cp15.cntvoff_el2 : 0;
|
||||
uint64_t count = gt_get_countervalue(&cpu->env);
|
||||
/* Note that this must be unsigned 64 bit arithmetic: */
|
||||
int istatus = count >= gt->cval;
|
||||
int istatus = count - offset >= gt->cval;
|
||||
uint64_t nexttick;
|
||||
|
||||
gt->ctl = deposit32(gt->ctl, 2, 1, istatus);
|
||||
@ -1222,7 +1268,7 @@ static void gt_recalc_timer(ARMCPU *cpu, int timeridx)
|
||||
nexttick = UINT64_MAX;
|
||||
} else {
|
||||
/* Next transition is when we hit cval */
|
||||
nexttick = gt->cval;
|
||||
nexttick = gt->cval + offset;
|
||||
}
|
||||
/* Note that the desired next expiry time might be beyond the
|
||||
* signed-64-bit range of a QEMUTimer -- in this case we just
|
||||
@ -1241,10 +1287,10 @@ static void gt_recalc_timer(ARMCPU *cpu, int timeridx)
|
||||
}
|
||||
}
|
||||
|
||||
static void gt_cnt_reset(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||
static void gt_timer_reset(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
int timeridx)
|
||||
{
|
||||
ARMCPU *cpu = arm_env_get_cpu(env);
|
||||
int timeridx = ri->opc1 & 1;
|
||||
|
||||
timer_del(cpu->gt_timer[timeridx]);
|
||||
}
|
||||
@ -1254,38 +1300,44 @@ static uint64_t gt_cnt_read(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||
return gt_get_countervalue(env);
|
||||
}
|
||||
|
||||
static uint64_t gt_virt_cnt_read(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||
{
|
||||
return gt_get_countervalue(env) - env->cp15.cntvoff_el2;
|
||||
}
|
||||
|
||||
static void gt_cval_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
int timeridx,
|
||||
uint64_t value)
|
||||
{
|
||||
int timeridx = ri->opc1 & 1;
|
||||
|
||||
env->cp15.c14_timer[timeridx].cval = value;
|
||||
gt_recalc_timer(arm_env_get_cpu(env), timeridx);
|
||||
}
|
||||
|
||||
static uint64_t gt_tval_read(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||
static uint64_t gt_tval_read(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
int timeridx)
|
||||
{
|
||||
int timeridx = ri->crm & 1;
|
||||
uint64_t offset = timeridx == GTIMER_VIRT ? env->cp15.cntvoff_el2 : 0;
|
||||
|
||||
return (uint32_t)(env->cp15.c14_timer[timeridx].cval -
|
||||
gt_get_countervalue(env));
|
||||
(gt_get_countervalue(env) - offset));
|
||||
}
|
||||
|
||||
static void gt_tval_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
int timeridx,
|
||||
uint64_t value)
|
||||
{
|
||||
int timeridx = ri->crm & 1;
|
||||
uint64_t offset = timeridx == GTIMER_VIRT ? env->cp15.cntvoff_el2 : 0;
|
||||
|
||||
env->cp15.c14_timer[timeridx].cval = gt_get_countervalue(env) +
|
||||
env->cp15.c14_timer[timeridx].cval = gt_get_countervalue(env) - offset +
|
||||
sextract64(value, 0, 32);
|
||||
gt_recalc_timer(arm_env_get_cpu(env), timeridx);
|
||||
}
|
||||
|
||||
static void gt_ctl_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
int timeridx,
|
||||
uint64_t value)
|
||||
{
|
||||
ARMCPU *cpu = arm_env_get_cpu(env);
|
||||
int timeridx = ri->crm & 1;
|
||||
uint32_t oldval = env->cp15.c14_timer[timeridx].ctl;
|
||||
|
||||
env->cp15.c14_timer[timeridx].ctl = deposit64(oldval, 0, 2, value);
|
||||
@ -1301,6 +1353,127 @@ static void gt_ctl_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
}
|
||||
}
|
||||
|
||||
static void gt_phys_timer_reset(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||
{
|
||||
gt_timer_reset(env, ri, GTIMER_PHYS);
|
||||
}
|
||||
|
||||
static void gt_phys_cval_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
uint64_t value)
|
||||
{
|
||||
gt_cval_write(env, ri, GTIMER_PHYS, value);
|
||||
}
|
||||
|
||||
static uint64_t gt_phys_tval_read(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||
{
|
||||
return gt_tval_read(env, ri, GTIMER_PHYS);
|
||||
}
|
||||
|
||||
static void gt_phys_tval_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
uint64_t value)
|
||||
{
|
||||
gt_tval_write(env, ri, GTIMER_PHYS, value);
|
||||
}
|
||||
|
||||
static void gt_phys_ctl_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
uint64_t value)
|
||||
{
|
||||
gt_ctl_write(env, ri, GTIMER_PHYS, value);
|
||||
}
|
||||
|
||||
static void gt_virt_timer_reset(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||
{
|
||||
gt_timer_reset(env, ri, GTIMER_VIRT);
|
||||
}
|
||||
|
||||
static void gt_virt_cval_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
uint64_t value)
|
||||
{
|
||||
gt_cval_write(env, ri, GTIMER_VIRT, value);
|
||||
}
|
||||
|
||||
static uint64_t gt_virt_tval_read(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||
{
|
||||
return gt_tval_read(env, ri, GTIMER_VIRT);
|
||||
}
|
||||
|
||||
static void gt_virt_tval_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
uint64_t value)
|
||||
{
|
||||
gt_tval_write(env, ri, GTIMER_VIRT, value);
|
||||
}
|
||||
|
||||
static void gt_virt_ctl_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
uint64_t value)
|
||||
{
|
||||
gt_ctl_write(env, ri, GTIMER_VIRT, value);
|
||||
}
|
||||
|
||||
static void gt_cntvoff_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
uint64_t value)
|
||||
{
|
||||
ARMCPU *cpu = arm_env_get_cpu(env);
|
||||
|
||||
raw_write(env, ri, value);
|
||||
gt_recalc_timer(cpu, GTIMER_VIRT);
|
||||
}
|
||||
|
||||
static void gt_hyp_timer_reset(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||
{
|
||||
gt_timer_reset(env, ri, GTIMER_HYP);
|
||||
}
|
||||
|
||||
static void gt_hyp_cval_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
uint64_t value)
|
||||
{
|
||||
gt_cval_write(env, ri, GTIMER_HYP, value);
|
||||
}
|
||||
|
||||
static uint64_t gt_hyp_tval_read(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||
{
|
||||
return gt_tval_read(env, ri, GTIMER_HYP);
|
||||
}
|
||||
|
||||
static void gt_hyp_tval_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
uint64_t value)
|
||||
{
|
||||
gt_tval_write(env, ri, GTIMER_HYP, value);
|
||||
}
|
||||
|
||||
static void gt_hyp_ctl_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
uint64_t value)
|
||||
{
|
||||
gt_ctl_write(env, ri, GTIMER_HYP, value);
|
||||
}
|
||||
|
||||
static void gt_sec_timer_reset(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||
{
|
||||
gt_timer_reset(env, ri, GTIMER_SEC);
|
||||
}
|
||||
|
||||
static void gt_sec_cval_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
uint64_t value)
|
||||
{
|
||||
gt_cval_write(env, ri, GTIMER_SEC, value);
|
||||
}
|
||||
|
||||
static uint64_t gt_sec_tval_read(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||
{
|
||||
return gt_tval_read(env, ri, GTIMER_SEC);
|
||||
}
|
||||
|
||||
static void gt_sec_tval_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
uint64_t value)
|
||||
{
|
||||
gt_tval_write(env, ri, GTIMER_SEC, value);
|
||||
}
|
||||
|
||||
static void gt_sec_ctl_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
uint64_t value)
|
||||
{
|
||||
gt_ctl_write(env, ri, GTIMER_SEC, value);
|
||||
}
|
||||
|
||||
void arm_gt_ptimer_cb(void *opaque)
|
||||
{
|
||||
ARMCPU *cpu = opaque;
|
||||
@ -1315,6 +1488,20 @@ void arm_gt_vtimer_cb(void *opaque)
|
||||
gt_recalc_timer(cpu, GTIMER_VIRT);
|
||||
}
|
||||
|
||||
void arm_gt_htimer_cb(void *opaque)
|
||||
{
|
||||
ARMCPU *cpu = opaque;
|
||||
|
||||
gt_recalc_timer(cpu, GTIMER_HYP);
|
||||
}
|
||||
|
||||
void arm_gt_stimer_cb(void *opaque)
|
||||
{
|
||||
ARMCPU *cpu = opaque;
|
||||
|
||||
gt_recalc_timer(cpu, GTIMER_SEC);
|
||||
}
|
||||
|
||||
static const ARMCPRegInfo generic_timer_cp_reginfo[] = {
|
||||
/* Note that CNTFRQ is purely reads-as-written for the benefit
|
||||
* of software; writing it doesn't actually change the timer frequency.
|
||||
@ -1340,11 +1527,21 @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = {
|
||||
},
|
||||
/* per-timer control */
|
||||
{ .name = "CNTP_CTL", .cp = 15, .crn = 14, .crm = 2, .opc1 = 0, .opc2 = 1,
|
||||
.secure = ARM_CP_SECSTATE_NS,
|
||||
.type = ARM_CP_IO | ARM_CP_ALIAS, .access = PL1_RW | PL0_R,
|
||||
.accessfn = gt_ptimer_access,
|
||||
.fieldoffset = offsetoflow32(CPUARMState,
|
||||
cp15.c14_timer[GTIMER_PHYS].ctl),
|
||||
.writefn = gt_ctl_write, .raw_writefn = raw_write,
|
||||
.writefn = gt_phys_ctl_write, .raw_writefn = raw_write,
|
||||
},
|
||||
{ .name = "CNTP_CTL(S)",
|
||||
.cp = 15, .crn = 14, .crm = 2, .opc1 = 0, .opc2 = 1,
|
||||
.secure = ARM_CP_SECSTATE_S,
|
||||
.type = ARM_CP_IO | ARM_CP_ALIAS, .access = PL1_RW | PL0_R,
|
||||
.accessfn = gt_ptimer_access,
|
||||
.fieldoffset = offsetoflow32(CPUARMState,
|
||||
cp15.c14_timer[GTIMER_SEC].ctl),
|
||||
.writefn = gt_sec_ctl_write, .raw_writefn = raw_write,
|
||||
},
|
||||
{ .name = "CNTP_CTL_EL0", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 3, .opc1 = 3, .crn = 14, .crm = 2, .opc2 = 1,
|
||||
@ -1352,14 +1549,14 @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = {
|
||||
.accessfn = gt_ptimer_access,
|
||||
.fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_PHYS].ctl),
|
||||
.resetvalue = 0,
|
||||
.writefn = gt_ctl_write, .raw_writefn = raw_write,
|
||||
.writefn = gt_phys_ctl_write, .raw_writefn = raw_write,
|
||||
},
|
||||
{ .name = "CNTV_CTL", .cp = 15, .crn = 14, .crm = 3, .opc1 = 0, .opc2 = 1,
|
||||
.type = ARM_CP_IO | ARM_CP_ALIAS, .access = PL1_RW | PL0_R,
|
||||
.accessfn = gt_vtimer_access,
|
||||
.fieldoffset = offsetoflow32(CPUARMState,
|
||||
cp15.c14_timer[GTIMER_VIRT].ctl),
|
||||
.writefn = gt_ctl_write, .raw_writefn = raw_write,
|
||||
.writefn = gt_virt_ctl_write, .raw_writefn = raw_write,
|
||||
},
|
||||
{ .name = "CNTV_CTL_EL0", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 3, .opc1 = 3, .crn = 14, .crm = 3, .opc2 = 1,
|
||||
@ -1367,30 +1564,38 @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = {
|
||||
.accessfn = gt_vtimer_access,
|
||||
.fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_VIRT].ctl),
|
||||
.resetvalue = 0,
|
||||
.writefn = gt_ctl_write, .raw_writefn = raw_write,
|
||||
.writefn = gt_virt_ctl_write, .raw_writefn = raw_write,
|
||||
},
|
||||
/* TimerValue views: a 32 bit downcounting view of the underlying state */
|
||||
{ .name = "CNTP_TVAL", .cp = 15, .crn = 14, .crm = 2, .opc1 = 0, .opc2 = 0,
|
||||
.secure = ARM_CP_SECSTATE_NS,
|
||||
.type = ARM_CP_NO_RAW | ARM_CP_IO, .access = PL1_RW | PL0_R,
|
||||
.accessfn = gt_ptimer_access,
|
||||
.readfn = gt_tval_read, .writefn = gt_tval_write,
|
||||
.readfn = gt_phys_tval_read, .writefn = gt_phys_tval_write,
|
||||
},
|
||||
{ .name = "CNTP_TVAL(S)",
|
||||
.cp = 15, .crn = 14, .crm = 2, .opc1 = 0, .opc2 = 0,
|
||||
.secure = ARM_CP_SECSTATE_S,
|
||||
.type = ARM_CP_NO_RAW | ARM_CP_IO, .access = PL1_RW | PL0_R,
|
||||
.accessfn = gt_ptimer_access,
|
||||
.readfn = gt_sec_tval_read, .writefn = gt_sec_tval_write,
|
||||
},
|
||||
{ .name = "CNTP_TVAL_EL0", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 3, .opc1 = 3, .crn = 14, .crm = 2, .opc2 = 0,
|
||||
.type = ARM_CP_NO_RAW | ARM_CP_IO, .access = PL1_RW | PL0_R,
|
||||
.accessfn = gt_ptimer_access,
|
||||
.readfn = gt_tval_read, .writefn = gt_tval_write,
|
||||
.accessfn = gt_ptimer_access, .resetfn = gt_phys_timer_reset,
|
||||
.readfn = gt_phys_tval_read, .writefn = gt_phys_tval_write,
|
||||
},
|
||||
{ .name = "CNTV_TVAL", .cp = 15, .crn = 14, .crm = 3, .opc1 = 0, .opc2 = 0,
|
||||
.type = ARM_CP_NO_RAW | ARM_CP_IO, .access = PL1_RW | PL0_R,
|
||||
.accessfn = gt_vtimer_access,
|
||||
.readfn = gt_tval_read, .writefn = gt_tval_write,
|
||||
.readfn = gt_virt_tval_read, .writefn = gt_virt_tval_write,
|
||||
},
|
||||
{ .name = "CNTV_TVAL_EL0", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 3, .opc1 = 3, .crn = 14, .crm = 3, .opc2 = 0,
|
||||
.type = ARM_CP_NO_RAW | ARM_CP_IO, .access = PL1_RW | PL0_R,
|
||||
.accessfn = gt_vtimer_access,
|
||||
.readfn = gt_tval_read, .writefn = gt_tval_write,
|
||||
.accessfn = gt_vtimer_access, .resetfn = gt_virt_timer_reset,
|
||||
.readfn = gt_virt_tval_read, .writefn = gt_virt_tval_write,
|
||||
},
|
||||
/* The counter itself */
|
||||
{ .name = "CNTPCT", .cp = 15, .crm = 14, .opc1 = 0,
|
||||
@ -1401,27 +1606,34 @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = {
|
||||
{ .name = "CNTPCT_EL0", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 3, .opc1 = 3, .crn = 14, .crm = 0, .opc2 = 1,
|
||||
.access = PL0_R, .type = ARM_CP_NO_RAW | ARM_CP_IO,
|
||||
.accessfn = gt_pct_access,
|
||||
.readfn = gt_cnt_read, .resetfn = gt_cnt_reset,
|
||||
.accessfn = gt_pct_access, .readfn = gt_cnt_read,
|
||||
},
|
||||
{ .name = "CNTVCT", .cp = 15, .crm = 14, .opc1 = 1,
|
||||
.access = PL0_R, .type = ARM_CP_64BIT | ARM_CP_NO_RAW | ARM_CP_IO,
|
||||
.accessfn = gt_vct_access,
|
||||
.readfn = gt_cnt_read, .resetfn = arm_cp_reset_ignore,
|
||||
.readfn = gt_virt_cnt_read, .resetfn = arm_cp_reset_ignore,
|
||||
},
|
||||
{ .name = "CNTVCT_EL0", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 3, .opc1 = 3, .crn = 14, .crm = 0, .opc2 = 2,
|
||||
.access = PL0_R, .type = ARM_CP_NO_RAW | ARM_CP_IO,
|
||||
.accessfn = gt_vct_access,
|
||||
.readfn = gt_cnt_read, .resetfn = gt_cnt_reset,
|
||||
.accessfn = gt_vct_access, .readfn = gt_virt_cnt_read,
|
||||
},
|
||||
/* Comparison value, indicating when the timer goes off */
|
||||
{ .name = "CNTP_CVAL", .cp = 15, .crm = 14, .opc1 = 2,
|
||||
.secure = ARM_CP_SECSTATE_NS,
|
||||
.access = PL1_RW | PL0_R,
|
||||
.type = ARM_CP_64BIT | ARM_CP_IO | ARM_CP_ALIAS,
|
||||
.fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_PHYS].cval),
|
||||
.accessfn = gt_ptimer_access,
|
||||
.writefn = gt_cval_write, .raw_writefn = raw_write,
|
||||
.writefn = gt_phys_cval_write, .raw_writefn = raw_write,
|
||||
},
|
||||
{ .name = "CNTP_CVAL(S)", .cp = 15, .crm = 14, .opc1 = 2,
|
||||
.secure = ARM_CP_SECSTATE_S,
|
||||
.access = PL1_RW | PL0_R,
|
||||
.type = ARM_CP_64BIT | ARM_CP_IO | ARM_CP_ALIAS,
|
||||
.fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_SEC].cval),
|
||||
.accessfn = gt_ptimer_access,
|
||||
.writefn = gt_sec_cval_write, .raw_writefn = raw_write,
|
||||
},
|
||||
{ .name = "CNTP_CVAL_EL0", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 3, .opc1 = 3, .crn = 14, .crm = 2, .opc2 = 2,
|
||||
@ -1429,14 +1641,14 @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = {
|
||||
.type = ARM_CP_IO,
|
||||
.fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_PHYS].cval),
|
||||
.resetvalue = 0, .accessfn = gt_ptimer_access,
|
||||
.writefn = gt_cval_write, .raw_writefn = raw_write,
|
||||
.writefn = gt_phys_cval_write, .raw_writefn = raw_write,
|
||||
},
|
||||
{ .name = "CNTV_CVAL", .cp = 15, .crm = 14, .opc1 = 3,
|
||||
.access = PL1_RW | PL0_R,
|
||||
.type = ARM_CP_64BIT | ARM_CP_IO | ARM_CP_ALIAS,
|
||||
.fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_VIRT].cval),
|
||||
.accessfn = gt_vtimer_access,
|
||||
.writefn = gt_cval_write, .raw_writefn = raw_write,
|
||||
.writefn = gt_virt_cval_write, .raw_writefn = raw_write,
|
||||
},
|
||||
{ .name = "CNTV_CVAL_EL0", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 3, .opc1 = 3, .crn = 14, .crm = 3, .opc2 = 2,
|
||||
@ -1444,7 +1656,33 @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = {
|
||||
.type = ARM_CP_IO,
|
||||
.fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_VIRT].cval),
|
||||
.resetvalue = 0, .accessfn = gt_vtimer_access,
|
||||
.writefn = gt_cval_write, .raw_writefn = raw_write,
|
||||
.writefn = gt_virt_cval_write, .raw_writefn = raw_write,
|
||||
},
|
||||
/* Secure timer -- this is actually restricted to only EL3
|
||||
* and configurably Secure-EL1 via the accessfn.
|
||||
*/
|
||||
{ .name = "CNTPS_TVAL_EL1", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 3, .opc1 = 7, .crn = 14, .crm = 2, .opc2 = 0,
|
||||
.type = ARM_CP_NO_RAW | ARM_CP_IO, .access = PL1_RW,
|
||||
.accessfn = gt_stimer_access,
|
||||
.readfn = gt_sec_tval_read,
|
||||
.writefn = gt_sec_tval_write,
|
||||
.resetfn = gt_sec_timer_reset,
|
||||
},
|
||||
{ .name = "CNTPS_CTL_EL1", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 3, .opc1 = 7, .crn = 14, .crm = 2, .opc2 = 1,
|
||||
.type = ARM_CP_IO, .access = PL1_RW,
|
||||
.accessfn = gt_stimer_access,
|
||||
.fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_SEC].ctl),
|
||||
.resetvalue = 0,
|
||||
.writefn = gt_sec_ctl_write, .raw_writefn = raw_write,
|
||||
},
|
||||
{ .name = "CNTPS_CVAL_EL1", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 3, .opc1 = 7, .crn = 14, .crm = 2, .opc2 = 2,
|
||||
.type = ARM_CP_IO, .access = PL1_RW,
|
||||
.accessfn = gt_stimer_access,
|
||||
.fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_SEC].cval),
|
||||
.writefn = gt_sec_cval_write, .raw_writefn = raw_write,
|
||||
},
|
||||
REGINFO_SENTINEL
|
||||
};
|
||||
@ -2613,6 +2851,27 @@ static const ARMCPRegInfo el3_no_el2_cp_reginfo[] = {
|
||||
{ .name = "HTTBR", .cp = 15, .opc1 = 4, .crm = 2,
|
||||
.access = PL2_RW, .type = ARM_CP_64BIT | ARM_CP_CONST,
|
||||
.resetvalue = 0 },
|
||||
{ .name = "CNTHCTL_EL2", .state = ARM_CP_STATE_BOTH,
|
||||
.opc0 = 3, .opc1 = 4, .crn = 14, .crm = 1, .opc2 = 0,
|
||||
.access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
|
||||
{ .name = "CNTVOFF_EL2", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 3, .opc1 = 4, .crn = 14, .crm = 0, .opc2 = 3,
|
||||
.access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
|
||||
{ .name = "CNTVOFF", .cp = 15, .opc1 = 4, .crm = 14,
|
||||
.access = PL2_RW, .type = ARM_CP_64BIT | ARM_CP_CONST,
|
||||
.resetvalue = 0 },
|
||||
{ .name = "CNTHP_CVAL_EL2", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 3, .opc1 = 4, .crn = 14, .crm = 2, .opc2 = 2,
|
||||
.access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
|
||||
{ .name = "CNTHP_CVAL", .cp = 15, .opc1 = 6, .crm = 14,
|
||||
.access = PL2_RW, .type = ARM_CP_64BIT | ARM_CP_CONST,
|
||||
.resetvalue = 0 },
|
||||
{ .name = "CNTHP_TVAL_EL2", .state = ARM_CP_STATE_BOTH,
|
||||
.opc0 = 3, .opc1 = 4, .crn = 14, .crm = 2, .opc2 = 0,
|
||||
.access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
|
||||
{ .name = "CNTHP_CTL_EL2", .state = ARM_CP_STATE_BOTH,
|
||||
.opc0 = 3, .opc1 = 4, .crn = 14, .crm = 2, .opc2 = 1,
|
||||
.access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
|
||||
REGINFO_SENTINEL
|
||||
};
|
||||
|
||||
@ -2724,6 +2983,46 @@ static const ARMCPRegInfo el2_cp_reginfo[] = {
|
||||
.opc0 = 1, .opc1 = 4, .crn = 8, .crm = 3, .opc2 = 1,
|
||||
.type = ARM_CP_NO_RAW, .access = PL2_W,
|
||||
.writefn = tlbi_aa64_vaa_write },
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
{ .name = "CNTHCTL_EL2", .state = ARM_CP_STATE_BOTH,
|
||||
.opc0 = 3, .opc1 = 4, .crn = 14, .crm = 1, .opc2 = 0,
|
||||
/* ARMv7 requires bit 0 and 1 to reset to 1. ARMv8 defines the
|
||||
* reset values as IMPDEF. We choose to reset to 3 to comply with
|
||||
* both ARMv7 and ARMv8.
|
||||
*/
|
||||
.access = PL2_RW, .resetvalue = 3,
|
||||
.fieldoffset = offsetof(CPUARMState, cp15.cnthctl_el2) },
|
||||
{ .name = "CNTVOFF_EL2", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 3, .opc1 = 4, .crn = 14, .crm = 0, .opc2 = 3,
|
||||
.access = PL2_RW, .type = ARM_CP_IO, .resetvalue = 0,
|
||||
.writefn = gt_cntvoff_write,
|
||||
.fieldoffset = offsetof(CPUARMState, cp15.cntvoff_el2) },
|
||||
{ .name = "CNTVOFF", .cp = 15, .opc1 = 4, .crm = 14,
|
||||
.access = PL2_RW, .type = ARM_CP_64BIT | ARM_CP_ALIAS | ARM_CP_IO,
|
||||
.writefn = gt_cntvoff_write,
|
||||
.fieldoffset = offsetof(CPUARMState, cp15.cntvoff_el2) },
|
||||
{ .name = "CNTHP_CVAL_EL2", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 3, .opc1 = 4, .crn = 14, .crm = 2, .opc2 = 2,
|
||||
.fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_HYP].cval),
|
||||
.type = ARM_CP_IO, .access = PL2_RW,
|
||||
.writefn = gt_hyp_cval_write, .raw_writefn = raw_write },
|
||||
{ .name = "CNTHP_CVAL", .cp = 15, .opc1 = 6, .crm = 14,
|
||||
.fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_HYP].cval),
|
||||
.access = PL2_RW, .type = ARM_CP_64BIT | ARM_CP_IO,
|
||||
.writefn = gt_hyp_cval_write, .raw_writefn = raw_write },
|
||||
{ .name = "CNTHP_TVAL_EL2", .state = ARM_CP_STATE_BOTH,
|
||||
.opc0 = 3, .opc1 = 4, .crn = 14, .crm = 2, .opc2 = 0,
|
||||
.type = ARM_CP_IO, .access = PL2_RW,
|
||||
.resetfn = gt_hyp_timer_reset,
|
||||
.readfn = gt_hyp_tval_read, .writefn = gt_hyp_tval_write },
|
||||
{ .name = "CNTHP_CTL_EL2", .state = ARM_CP_STATE_BOTH,
|
||||
.type = ARM_CP_IO,
|
||||
.opc0 = 3, .opc1 = 4, .crn = 14, .crm = 2, .opc2 = 1,
|
||||
.access = PL2_RW,
|
||||
.fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_HYP].ctl),
|
||||
.resetvalue = 0,
|
||||
.writefn = gt_hyp_ctl_write, .raw_writefn = raw_write },
|
||||
#endif
|
||||
REGINFO_SENTINEL
|
||||
};
|
||||
|
||||
|
@ -191,4 +191,9 @@ int kvm_arm_sync_mpstate_to_qemu(ARMCPU *cpu);
|
||||
|
||||
#endif
|
||||
|
||||
static inline const char *gic_class_name(void)
|
||||
{
|
||||
return kvm_irqchip_in_kernel() ? "kvm-arm-gic" : "arm_gic";
|
||||
}
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user