target-arm queue:
* tests/acceptance: Add a test for the canon-a1100 machine * docs/system: Document some of the Arm development boards * linux-user: make BKPT insn cause SIGTRAP, not be a syscall * target/arm: Remove unused GEN_NEON_INTEGER_OP macro * fsl-imx25, fsl-imx31, fsl-imx6, fsl-imx6ul, fsl-imx7: implement watchdog * hw/arm: Use qemu_log_mask() instead of hw_error() in various places * ARM: PL061: Introduce N_GPIOS * target/arm: Improve clear_vec_high() usage * target/arm: Allow user-mode code to write CPSR.E via MSR * linux-user/arm: Reset CPSR_E when entering a signal handler * linux-user/arm/signal.c: Drop TARGET_CONFIG_CPU_32 -----BEGIN PGP SIGNATURE----- iQJNBAABCAA3FiEE4aXFk81BneKOgxXPPCUl7RQ2DN4FAl7G7SwZHHBldGVyLm1h eWRlbGxAbGluYXJvLm9yZwAKCRA8JSXtFDYM3qlND/0bnTGXns6FdYfWahEchgzJ 2C3LbE7ELund+vmn8BQX+TNsxC3sypbNa0HTx5uiAaRt3ohD6f/lYmvKjGkLJJ0l g/6KQNXz2Tru5uB3wXWJuSQhX5qEei4EAHoHLo5lseslQq8pF8xpZvkj7P6TYJGp ReEd48OPQJwrs6nlHahQkLX1TveDGNI/GTvUxVG6wTXZnYP6+/LK71yCZDplaKFb j2vD7Q9kgFBHmjRiBMvYRhxQXRMnRe+5Y4khDSyiQdZId+2zD0PkxoL6qujSU0Ty /P6vWzqdn66n3nD86PzthuWT2294xdsKGx6+otxIsJevMlZxZ7jNP/z7eJEIEvMI Pqd28iStpdheiU2siM0NwunRWyr+c/zX6J1KYGBFrVFb869eePaDmIrn0AGKOh9S IEO4n7t+M+IkYbc5RfdU2UhE2ubijLDrWnm/mZ7cCd7jT3SwPitVLqtcQWYFI0fL GUEJlRstsuSXTWI4g5Cwpuv6U90sc/sIERAVW5qP45FoSnhRaK3+ySzmlTTqZ+jq k8xywFjAijITplrvsbIsN0Y074PHFiOuk6e+FXaCyBOc9TA9sZKQUNk/XLuYzhYr 86jSELIt+YHrpHwxkplrvO+3MvqV95+6AU77cuNAC9O2E5HgE4SPE4RnfRTG8ULj FtzVM8JOjCLKha+oAD9ucA== =bh3x -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20200521-1' into staging target-arm queue: * tests/acceptance: Add a test for the canon-a1100 machine * docs/system: Document some of the Arm development boards * linux-user: make BKPT insn cause SIGTRAP, not be a syscall * target/arm: Remove unused GEN_NEON_INTEGER_OP macro * fsl-imx25, fsl-imx31, fsl-imx6, fsl-imx6ul, fsl-imx7: implement watchdog * hw/arm: Use qemu_log_mask() instead of hw_error() in various places * ARM: PL061: Introduce N_GPIOS * target/arm: Improve clear_vec_high() usage * target/arm: Allow user-mode code to write CPSR.E via MSR * linux-user/arm: Reset CPSR_E when entering a signal handler * linux-user/arm/signal.c: Drop TARGET_CONFIG_CPU_32 # gpg: Signature made Thu 21 May 2020 22:05:48 BST # gpg: using RSA key E1A5C593CD419DE28E8315CF3C2525ED14360CDE # gpg: issuer "peter.maydell@linaro.org" # gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" [ultimate] # gpg: aka "Peter Maydell <pmaydell@gmail.com>" [ultimate] # gpg: aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>" [ultimate] # Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83 15CF 3C25 25ED 1436 0CDE * remotes/pmaydell/tags/pull-target-arm-20200521-1: (29 commits) linux-user/arm/signal.c: Drop TARGET_CONFIG_CPU_32 linux-user/arm: Reset CPSR_E when entering a signal handler target/arm: Allow user-mode code to write CPSR.E via MSR target/arm: Use clear_vec_high more effectively target/arm: Use tcg_gen_gvec_mov for clear_vec_high ARM: PL061: Introduce N_GPIOS hw/timer/exynos4210_mct: Replace hw_error() by qemu_log_mask() hw/char/xilinx_uartlite: Replace hw_error() by qemu_log_mask() hw/arm/pxa2xx: Replace hw_error() by qemu_log_mask() hw/arm/integratorcp: Replace hw_error() by qemu_log_mask() hw/arm/fsl-imx7: Connect watchdog interrupts hw/arm/fsl-imx7: Instantiate various unimplemented devices hw/arm/fsl-imx6ul: Connect watchdog interrupts hw/arm/fsl-imx6: Connect watchdog interrupts hw/arm/fsl-imx31: Wire up watchdog hw/arm/fsl-imx25: Wire up watchdog hw/watchdog: Implement full i.MX watchdog support hw: Move i.MX watchdog driver to hw/watchdog target/arm: Remove unused GEN_NEON_INTEGER_OP macro linux-user/arm: Fix identification of syscall numbers ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
d19f1ab0de
@ -608,6 +608,7 @@ S: Odd Fixes
|
||||
F: include/hw/arm/digic.h
|
||||
F: hw/*/digic*
|
||||
F: include/hw/*/digic*
|
||||
F: tests/acceptance/machine_arm_canona1100.py
|
||||
|
||||
Goldfish RTC
|
||||
M: Anup Patel <anup.patel@wdc.com>
|
||||
@ -632,8 +633,10 @@ S: Odd Fixes
|
||||
F: hw/arm/fsl-imx25.c
|
||||
F: hw/arm/imx25_pdk.c
|
||||
F: hw/misc/imx25_ccm.c
|
||||
F: hw/watchdog/wdt_imx2.c
|
||||
F: include/hw/arm/fsl-imx25.h
|
||||
F: include/hw/misc/imx25_ccm.h
|
||||
F: include/hw/watchdog/wdt_imx2.h
|
||||
|
||||
i.MX31 (kzm)
|
||||
M: Peter Chubb <peter.chubb@nicta.com.au>
|
||||
@ -700,12 +703,14 @@ F: hw/misc/armsse-cpuid.c
|
||||
F: include/hw/misc/armsse-cpuid.h
|
||||
F: hw/misc/armsse-mhu.c
|
||||
F: include/hw/misc/armsse-mhu.h
|
||||
F: docs/system/arm/mps2.rst
|
||||
|
||||
Musca
|
||||
M: Peter Maydell <peter.maydell@linaro.org>
|
||||
L: qemu-arm@nongnu.org
|
||||
S: Maintained
|
||||
F: hw/arm/musca.c
|
||||
F: docs/system/arm/musca.rst
|
||||
|
||||
Musicpal
|
||||
M: Jan Kiszka <jan.kiszka@web.de>
|
||||
@ -827,6 +832,7 @@ M: Peter Maydell <peter.maydell@linaro.org>
|
||||
L: qemu-arm@nongnu.org
|
||||
S: Maintained
|
||||
F: hw/arm/vexpress.c
|
||||
F: docs/system/arm/vexpress.rst
|
||||
|
||||
Versatile PB
|
||||
M: Peter Maydell <peter.maydell@linaro.org>
|
||||
|
@ -1,5 +1,5 @@
|
||||
Integrator/CP (``integratorcp``)
|
||||
================================
|
||||
Arm Integrator/CP (``integratorcp``)
|
||||
====================================
|
||||
|
||||
The Arm Integrator/CP board is emulated with the following devices:
|
||||
|
||||
|
29
docs/system/arm/mps2.rst
Normal file
29
docs/system/arm/mps2.rst
Normal file
@ -0,0 +1,29 @@
|
||||
Arm MPS2 boards (``mps2-an385``, ``mps2-an505``, ``mps2-an511``, ``mps2-an521``)
|
||||
================================================================================
|
||||
|
||||
These board models all use Arm M-profile CPUs.
|
||||
|
||||
The Arm MPS2 and MPS2+ dev boards are FPGA based (the 2+ has a bigger
|
||||
FPGA but is otherwise the same as the 2). Since the CPU itself
|
||||
and most of the devices are in the FPGA, the details of the board
|
||||
as seen by the guest depend significantly on the FPGA image.
|
||||
|
||||
QEMU models the following FPGA images:
|
||||
|
||||
``mps2-an385``
|
||||
Cortex-M3 as documented in ARM Application Note AN385
|
||||
``mps2-an511``
|
||||
Cortex-M3 'DesignStart' as documented in AN511
|
||||
``mps2-an505``
|
||||
Cortex-M33 as documented in ARM Application Note AN505
|
||||
``mps2-an521``
|
||||
Dual Cortex-M33 as documented in Application Note AN521
|
||||
|
||||
Differences between QEMU and real hardware:
|
||||
|
||||
- AN385 remapping of low 16K of memory to either ZBT SSRAM1 or to
|
||||
block RAM is unimplemented (QEMU always maps this to ZBT SSRAM1, as
|
||||
if zbt_boot_ctrl is always zero)
|
||||
- QEMU provides a LAN9118 ethernet rather than LAN9220; the only guest
|
||||
visible difference is that the LAN9118 doesn't support checksum
|
||||
offloading
|
31
docs/system/arm/musca.rst
Normal file
31
docs/system/arm/musca.rst
Normal file
@ -0,0 +1,31 @@
|
||||
Arm Musca boards (``musca-a``, ``musca-b1``)
|
||||
============================================
|
||||
|
||||
The Arm Musca development boards are a reference implementation
|
||||
of a system using the SSE-200 Subsystem for Embedded. They are
|
||||
dual Cortex-M33 systems.
|
||||
|
||||
QEMU provides models of the A and B1 variants of this board.
|
||||
|
||||
Unimplemented devices:
|
||||
|
||||
- SPI
|
||||
- |I2C|
|
||||
- |I2S|
|
||||
- PWM
|
||||
- QSPI
|
||||
- Timer
|
||||
- SCC
|
||||
- GPIO
|
||||
- eFlash
|
||||
- MHU
|
||||
- PVT
|
||||
- SDIO
|
||||
- CryptoCell
|
||||
|
||||
Note that (like the real hardware) the Musca-A machine is
|
||||
asymmetric: CPU 0 does not have the FPU or DSP extensions,
|
||||
but CPU 1 does. Also like the real hardware, the memory maps
|
||||
for the A and B1 variants differ significantly, so guest
|
||||
software must be built for the right variant.
|
||||
|
60
docs/system/arm/vexpress.rst
Normal file
60
docs/system/arm/vexpress.rst
Normal file
@ -0,0 +1,60 @@
|
||||
Arm Versatile Express boards (``vexpress-a9``, ``vexpress-a15``)
|
||||
================================================================
|
||||
|
||||
QEMU models two variants of the Arm Versatile Express development
|
||||
board family:
|
||||
|
||||
- ``vexpress-a9`` models the combination of the Versatile Express
|
||||
motherboard and the CoreTile Express A9x4 daughterboard
|
||||
- ``vexpress-a15`` models the combination of the Versatile Express
|
||||
motherboard and the CoreTile Express A15x2 daughterboard
|
||||
|
||||
Note that as this hardware does not have PCI, IDE or SCSI,
|
||||
the only available storage option is emulated SD card.
|
||||
|
||||
Implemented devices:
|
||||
|
||||
- PL041 audio
|
||||
- PL181 SD controller
|
||||
- PL050 keyboard and mouse
|
||||
- PL011 UARTs
|
||||
- SP804 timers
|
||||
- I2C controller
|
||||
- PL031 RTC
|
||||
- PL111 LCD display controller
|
||||
- Flash memory
|
||||
- LAN9118 ethernet
|
||||
|
||||
Unimplemented devices:
|
||||
|
||||
- SP810 system control block
|
||||
- PCI-express
|
||||
- USB controller (Philips ISP1761)
|
||||
- Local DAP ROM
|
||||
- CoreSight interfaces
|
||||
- PL301 AXI interconnect
|
||||
- SCC
|
||||
- System counter
|
||||
- HDLCD controller (``vexpress-a15``)
|
||||
- SP805 watchdog
|
||||
- PL341 dynamic memory controller
|
||||
- DMA330 DMA controller
|
||||
- PL354 static memory controller
|
||||
- BP147 TrustZone Protection Controller
|
||||
- TrustZone Address Space Controller
|
||||
|
||||
Other differences between the hardware and the QEMU model:
|
||||
|
||||
- QEMU will default to creating one CPU unless you pass a different
|
||||
``-smp`` argument
|
||||
- QEMU allows the amount of RAM provided to be specified with the
|
||||
``-m`` argument
|
||||
- QEMU defaults to providing a CPU which does not provide either
|
||||
TrustZone or the Virtualization Extensions: if you want these you
|
||||
must enable them with ``-machine secure=on`` and ``-machine
|
||||
virtualization=on``
|
||||
- QEMU provides 4 virtio-mmio virtio transports; these start at
|
||||
address ``0x10013000`` for ``vexpress-a9`` and at ``0x1c130000`` for
|
||||
``vexpress-a15``, and have IRQs from 40 upwards. If a dtb is
|
||||
provided on the command line then QEMU will edit it to include
|
||||
suitable entries describing these transports for the guest.
|
@ -67,19 +67,27 @@ Unfortunately many of the Arm boards QEMU supports are currently
|
||||
undocumented; you can get a complete list by running
|
||||
``qemu-system-aarch64 --machine help``.
|
||||
|
||||
..
|
||||
This table of contents should be kept sorted alphabetically
|
||||
by the title text of each file, which isn't the same ordering
|
||||
as an alphabetical sort by filename.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
arm/integratorcp
|
||||
arm/versatile
|
||||
arm/mps2
|
||||
arm/musca
|
||||
arm/realview
|
||||
arm/xscale
|
||||
arm/palm
|
||||
arm/nseries
|
||||
arm/stellaris
|
||||
arm/versatile
|
||||
arm/vexpress
|
||||
arm/musicpal
|
||||
arm/sx1
|
||||
arm/nseries
|
||||
arm/orangepi
|
||||
arm/palm
|
||||
arm/xscale
|
||||
arm/sx1
|
||||
arm/stellaris
|
||||
|
||||
Arm CPU features
|
||||
================
|
||||
|
@ -359,6 +359,7 @@ config FSL_IMX25
|
||||
select IMX
|
||||
select IMX_FEC
|
||||
select IMX_I2C
|
||||
select WDT_IMX2
|
||||
select DS1338
|
||||
|
||||
config FSL_IMX31
|
||||
@ -366,6 +367,7 @@ config FSL_IMX31
|
||||
select SERIAL
|
||||
select IMX
|
||||
select IMX_I2C
|
||||
select WDT_IMX2
|
||||
select LAN9118
|
||||
|
||||
config FSL_IMX6
|
||||
@ -375,6 +377,7 @@ config FSL_IMX6
|
||||
select IMX_FEC
|
||||
select IMX_I2C
|
||||
select IMX_USBPHY
|
||||
select WDT_IMX2
|
||||
select SDHCI
|
||||
|
||||
config ASPEED_SOC
|
||||
@ -412,6 +415,7 @@ config FSL_IMX7
|
||||
select IMX
|
||||
select IMX_FEC
|
||||
select IMX_I2C
|
||||
select WDT_IMX2
|
||||
select PCI_EXPRESS_DESIGNWARE
|
||||
select SDHCI
|
||||
select UNIMP
|
||||
@ -425,6 +429,7 @@ config FSL_IMX6UL
|
||||
select IMX
|
||||
select IMX_FEC
|
||||
select IMX_I2C
|
||||
select WDT_IMX2
|
||||
select SDHCI
|
||||
select UNIMP
|
||||
|
||||
|
@ -87,6 +87,7 @@ static void fsl_imx25_init(Object *obj)
|
||||
TYPE_CHIPIDEA);
|
||||
}
|
||||
|
||||
sysbus_init_child_obj(obj, "wdt", &s->wdt, sizeof(s->wdt), TYPE_IMX2_WDT);
|
||||
}
|
||||
|
||||
static void fsl_imx25_realize(DeviceState *dev, Error **errp)
|
||||
@ -302,6 +303,15 @@ static void fsl_imx25_realize(DeviceState *dev, Error **errp)
|
||||
usb_table[i].irq));
|
||||
}
|
||||
|
||||
/* Watchdog */
|
||||
object_property_set_bool(OBJECT(&s->wdt), true, "pretimeout-support",
|
||||
&error_abort);
|
||||
object_property_set_bool(OBJECT(&s->wdt), true, "realized", &error_abort);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->wdt), 0, FSL_IMX25_WDT_ADDR);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(&s->wdt), 0,
|
||||
qdev_get_gpio_in(DEVICE(&s->avic),
|
||||
FSL_IMX25_WDT_IRQ));
|
||||
|
||||
/* initialize 2 x 16 KB ROM */
|
||||
memory_region_init_rom(&s->rom[0], OBJECT(dev), "imx25.rom0",
|
||||
FSL_IMX25_ROM0_SIZE, &err);
|
||||
|
@ -63,6 +63,8 @@ static void fsl_imx31_init(Object *obj)
|
||||
sysbus_init_child_obj(obj, "gpio[*]", &s->gpio[i], sizeof(s->gpio[i]),
|
||||
TYPE_IMX_GPIO);
|
||||
}
|
||||
|
||||
sysbus_init_child_obj(obj, "wdt", &s->wdt, sizeof(s->wdt), TYPE_IMX2_WDT);
|
||||
}
|
||||
|
||||
static void fsl_imx31_realize(DeviceState *dev, Error **errp)
|
||||
@ -205,6 +207,10 @@ static void fsl_imx31_realize(DeviceState *dev, Error **errp)
|
||||
gpio_table[i].irq));
|
||||
}
|
||||
|
||||
/* Watchdog */
|
||||
object_property_set_bool(OBJECT(&s->wdt), true, "realized", &error_abort);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->wdt), 0, FSL_IMX31_WDT_ADDR);
|
||||
|
||||
/* On a real system, the first 16k is a `secure boot rom' */
|
||||
memory_region_init_rom(&s->secure_rom, OBJECT(dev), "imx31.secure_rom",
|
||||
FSL_IMX31_SECURE_ROM_SIZE, &err);
|
||||
|
@ -433,11 +433,20 @@ static void fsl_imx6_realize(DeviceState *dev, Error **errp)
|
||||
FSL_IMX6_WDOG1_ADDR,
|
||||
FSL_IMX6_WDOG2_ADDR,
|
||||
};
|
||||
static const int FSL_IMX6_WDOGn_IRQ[FSL_IMX6_NUM_WDTS] = {
|
||||
FSL_IMX6_WDOG1_IRQ,
|
||||
FSL_IMX6_WDOG2_IRQ,
|
||||
};
|
||||
|
||||
object_property_set_bool(OBJECT(&s->wdt[i]), true, "pretimeout-support",
|
||||
&error_abort);
|
||||
object_property_set_bool(OBJECT(&s->wdt[i]), true, "realized",
|
||||
&error_abort);
|
||||
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->wdt[i]), 0, FSL_IMX6_WDOGn_ADDR[i]);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(&s->wdt[i]), 0,
|
||||
qdev_get_gpio_in(DEVICE(&s->a9mpcore),
|
||||
FSL_IMX6_WDOGn_IRQ[i]));
|
||||
}
|
||||
|
||||
/* ROM memory */
|
||||
|
@ -531,12 +531,22 @@ static void fsl_imx6ul_realize(DeviceState *dev, Error **errp)
|
||||
FSL_IMX6UL_WDOG2_ADDR,
|
||||
FSL_IMX6UL_WDOG3_ADDR,
|
||||
};
|
||||
static const int FSL_IMX6UL_WDOGn_IRQ[FSL_IMX6UL_NUM_WDTS] = {
|
||||
FSL_IMX6UL_WDOG1_IRQ,
|
||||
FSL_IMX6UL_WDOG2_IRQ,
|
||||
FSL_IMX6UL_WDOG3_IRQ,
|
||||
};
|
||||
|
||||
object_property_set_bool(OBJECT(&s->wdt[i]), true, "pretimeout-support",
|
||||
&error_abort);
|
||||
object_property_set_bool(OBJECT(&s->wdt[i]), true, "realized",
|
||||
&error_abort);
|
||||
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->wdt[i]), 0,
|
||||
FSL_IMX6UL_WDOGn_ADDR[i]);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(&s->wdt[i]), 0,
|
||||
qdev_get_gpio_in(DEVICE(&s->a7mpcore),
|
||||
FSL_IMX6UL_WDOGn_IRQ[i]));
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -447,11 +447,22 @@ static void fsl_imx7_realize(DeviceState *dev, Error **errp)
|
||||
FSL_IMX7_WDOG3_ADDR,
|
||||
FSL_IMX7_WDOG4_ADDR,
|
||||
};
|
||||
static const int FSL_IMX7_WDOGn_IRQ[FSL_IMX7_NUM_WDTS] = {
|
||||
FSL_IMX7_WDOG1_IRQ,
|
||||
FSL_IMX7_WDOG2_IRQ,
|
||||
FSL_IMX7_WDOG3_IRQ,
|
||||
FSL_IMX7_WDOG4_IRQ,
|
||||
};
|
||||
|
||||
object_property_set_bool(OBJECT(&s->wdt[i]), true, "pretimeout-support",
|
||||
&error_abort);
|
||||
object_property_set_bool(OBJECT(&s->wdt[i]), true, "realized",
|
||||
&error_abort);
|
||||
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->wdt[i]), 0, FSL_IMX7_WDOGn_ADDR[i]);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(&s->wdt[i]), 0,
|
||||
qdev_get_gpio_in(DEVICE(&s->a7mpcore),
|
||||
FSL_IMX7_WDOGn_IRQ[i]));
|
||||
}
|
||||
|
||||
/*
|
||||
@ -459,6 +470,30 @@ static void fsl_imx7_realize(DeviceState *dev, Error **errp)
|
||||
*/
|
||||
create_unimplemented_device("sdma", FSL_IMX7_SDMA_ADDR, FSL_IMX7_SDMA_SIZE);
|
||||
|
||||
/*
|
||||
* CAAM
|
||||
*/
|
||||
create_unimplemented_device("caam", FSL_IMX7_CAAM_ADDR, FSL_IMX7_CAAM_SIZE);
|
||||
|
||||
/*
|
||||
* PWM
|
||||
*/
|
||||
create_unimplemented_device("pwm1", FSL_IMX7_PWM1_ADDR, FSL_IMX7_PWMn_SIZE);
|
||||
create_unimplemented_device("pwm2", FSL_IMX7_PWM2_ADDR, FSL_IMX7_PWMn_SIZE);
|
||||
create_unimplemented_device("pwm3", FSL_IMX7_PWM3_ADDR, FSL_IMX7_PWMn_SIZE);
|
||||
create_unimplemented_device("pwm4", FSL_IMX7_PWM4_ADDR, FSL_IMX7_PWMn_SIZE);
|
||||
|
||||
/*
|
||||
* CAN
|
||||
*/
|
||||
create_unimplemented_device("can1", FSL_IMX7_CAN1_ADDR, FSL_IMX7_CANn_SIZE);
|
||||
create_unimplemented_device("can2", FSL_IMX7_CAN2_ADDR, FSL_IMX7_CANn_SIZE);
|
||||
|
||||
/*
|
||||
* OCOTP
|
||||
*/
|
||||
create_unimplemented_device("ocotp", FSL_IMX7_OCOTP_ADDR,
|
||||
FSL_IMX7_OCOTP_SIZE);
|
||||
|
||||
object_property_set_bool(OBJECT(&s->gpr), true, "realized",
|
||||
&error_abort);
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "exec/address-spaces.h"
|
||||
#include "sysemu/runstate.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "qemu/log.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "hw/char/pl011.h"
|
||||
#include "hw/hw.h"
|
||||
@ -144,8 +145,9 @@ static uint64_t integratorcm_read(void *opaque, hwaddr offset,
|
||||
/* ??? Voltage control unimplemented. */
|
||||
return 0;
|
||||
default:
|
||||
hw_error("integratorcm_read: Unimplemented offset 0x%x\n",
|
||||
(int)offset);
|
||||
qemu_log_mask(LOG_UNIMP,
|
||||
"%s: Unimplemented offset 0x%" HWADDR_PRIX "\n",
|
||||
__func__, offset);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@ -252,8 +254,9 @@ static void integratorcm_write(void *opaque, hwaddr offset,
|
||||
/* ??? Voltage control unimplemented. */
|
||||
break;
|
||||
default:
|
||||
hw_error("integratorcm_write: Unimplemented offset 0x%x\n",
|
||||
(int)offset);
|
||||
qemu_log_mask(LOG_UNIMP,
|
||||
"%s: Unimplemented offset 0x%" HWADDR_PRIX "\n",
|
||||
__func__, offset);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -394,7 +397,8 @@ static uint64_t icp_pic_read(void *opaque, hwaddr offset,
|
||||
case 5: /* INT_SOFTCLR */
|
||||
case 11: /* FRQ_ENABLECLR */
|
||||
default:
|
||||
printf ("icp_pic_read: Bad register offset 0x%x\n", (int)offset);
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIX "\n",
|
||||
__func__, offset);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@ -430,7 +434,8 @@ static void icp_pic_write(void *opaque, hwaddr offset,
|
||||
case 8: /* FRQ_STATUS */
|
||||
case 9: /* FRQ_RAWSTAT */
|
||||
default:
|
||||
printf ("icp_pic_write: Bad register offset 0x%x\n", (int)offset);
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIX "\n",
|
||||
__func__, offset);
|
||||
return;
|
||||
}
|
||||
icp_pic_update(s);
|
||||
@ -504,7 +509,8 @@ static uint64_t icp_control_read(void *opaque, hwaddr offset,
|
||||
case 3: /* CP_DECODE */
|
||||
return 0x11;
|
||||
default:
|
||||
hw_error("icp_control_read: Bad offset %x\n", (int)offset);
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIX "\n",
|
||||
__func__, offset);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@ -524,7 +530,8 @@ static void icp_control_write(void *opaque, hwaddr offset,
|
||||
/* Nothing interesting implemented yet. */
|
||||
break;
|
||||
default:
|
||||
hw_error("icp_control_write: Bad offset %x\n", (int)offset);
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIX "\n",
|
||||
__func__, offset);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9,7 +9,6 @@
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "cpu.h"
|
||||
#include "hw/hw.h"
|
||||
#include "hw/irq.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "hw/sysbus.h"
|
||||
@ -199,7 +198,8 @@ static uint64_t pxa2xx_gpio_read(void *opaque, hwaddr offset,
|
||||
return s->status[bank];
|
||||
|
||||
default:
|
||||
hw_error("%s: Bad offset " REG_FMT "\n", __func__, offset);
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIX "\n",
|
||||
__func__, offset);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -252,7 +252,8 @@ static void pxa2xx_gpio_write(void *opaque, hwaddr offset,
|
||||
break;
|
||||
|
||||
default:
|
||||
hw_error("%s: Bad offset " REG_FMT "\n", __func__, offset);
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIX "\n",
|
||||
__func__, offset);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -23,7 +23,7 @@
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/hw.h"
|
||||
#include "qemu/log.h"
|
||||
#include "hw/irq.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "hw/sysbus.h"
|
||||
@ -135,7 +135,8 @@ uart_write(void *opaque, hwaddr addr,
|
||||
switch (addr)
|
||||
{
|
||||
case R_STATUS:
|
||||
hw_error("write to UART STATUS?\n");
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: write to UART STATUS\n",
|
||||
__func__);
|
||||
break;
|
||||
|
||||
case R_CTRL:
|
||||
|
@ -11,7 +11,7 @@
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/hw.h"
|
||||
#include "qemu/log.h"
|
||||
#include "hw/irq.h"
|
||||
#include "migration/vmstate.h"
|
||||
#include "ui/console.h"
|
||||
@ -407,7 +407,8 @@ static uint64_t pxa2xx_lcdc_read(void *opaque, hwaddr offset,
|
||||
|
||||
default:
|
||||
fail:
|
||||
hw_error("%s: Bad offset " REG_FMT "\n", __func__, offset);
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIX "\n",
|
||||
__func__, offset);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -562,7 +563,8 @@ static void pxa2xx_lcdc_write(void *opaque, hwaddr offset,
|
||||
|
||||
default:
|
||||
fail:
|
||||
hw_error("%s: Bad offset " REG_FMT "\n", __func__, offset);
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIX "\n",
|
||||
__func__, offset);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9,6 +9,7 @@
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/log.h"
|
||||
#include "hw/hw.h"
|
||||
#include "hw/irq.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
@ -268,7 +269,8 @@ static uint64_t pxa2xx_dma_read(void *opaque, hwaddr offset,
|
||||
unsigned int channel;
|
||||
|
||||
if (size != 4) {
|
||||
hw_error("%s: Bad access width\n", __func__);
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad access width %u\n",
|
||||
__func__, size);
|
||||
return 5;
|
||||
}
|
||||
|
||||
@ -315,8 +317,8 @@ static uint64_t pxa2xx_dma_read(void *opaque, hwaddr offset,
|
||||
return s->chan[channel].cmd;
|
||||
}
|
||||
}
|
||||
|
||||
hw_error("%s: Bad offset 0x" TARGET_FMT_plx "\n", __func__, offset);
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIX "\n",
|
||||
__func__, offset);
|
||||
return 7;
|
||||
}
|
||||
|
||||
@ -327,7 +329,8 @@ static void pxa2xx_dma_write(void *opaque, hwaddr offset,
|
||||
unsigned int channel;
|
||||
|
||||
if (size != 4) {
|
||||
hw_error("%s: Bad access width\n", __func__);
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad access width %u\n",
|
||||
__func__, size);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -420,7 +423,8 @@ static void pxa2xx_dma_write(void *opaque, hwaddr offset,
|
||||
break;
|
||||
}
|
||||
fail:
|
||||
hw_error("%s: Bad offset " TARGET_FMT_plx "\n", __func__, offset);
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIX "\n",
|
||||
__func__, offset);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -36,6 +36,8 @@ static const uint8_t pl061_id_luminary[12] =
|
||||
#define TYPE_PL061 "pl061"
|
||||
#define PL061(obj) OBJECT_CHECK(PL061State, (obj), TYPE_PL061)
|
||||
|
||||
#define N_GPIOS 8
|
||||
|
||||
typedef struct PL061State {
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
@ -62,7 +64,7 @@ typedef struct PL061State {
|
||||
uint32_t cr;
|
||||
uint32_t amsel;
|
||||
qemu_irq irq;
|
||||
qemu_irq out[8];
|
||||
qemu_irq out[N_GPIOS];
|
||||
const unsigned char *id;
|
||||
uint32_t rsvd_start; /* reserved area: [rsvd_start, 0xfcc] */
|
||||
} PL061State;
|
||||
@ -112,7 +114,7 @@ static void pl061_update(PL061State *s)
|
||||
changed = s->old_out_data ^ out;
|
||||
if (changed) {
|
||||
s->old_out_data = out;
|
||||
for (i = 0; i < 8; i++) {
|
||||
for (i = 0; i < N_GPIOS; i++) {
|
||||
mask = 1 << i;
|
||||
if (changed & mask) {
|
||||
DPRINTF("Set output %d = %d\n", i, (out & mask) != 0);
|
||||
@ -125,7 +127,7 @@ static void pl061_update(PL061State *s)
|
||||
changed = (s->old_in_data ^ s->data) & ~s->dir;
|
||||
if (changed) {
|
||||
s->old_in_data = s->data;
|
||||
for (i = 0; i < 8; i++) {
|
||||
for (i = 0; i < N_GPIOS; i++) {
|
||||
mask = 1 << i;
|
||||
if (changed & mask) {
|
||||
DPRINTF("Changed input %d = %d\n", i, (s->data & mask) != 0);
|
||||
@ -364,8 +366,8 @@ static void pl061_init(Object *obj)
|
||||
memory_region_init_io(&s->iomem, obj, &pl061_ops, s, "pl061", 0x1000);
|
||||
sysbus_init_mmio(sbd, &s->iomem);
|
||||
sysbus_init_irq(sbd, &s->irq);
|
||||
qdev_init_gpio_in(dev, pl061_set_irq, 8);
|
||||
qdev_init_gpio_out(dev, s->out, 8);
|
||||
qdev_init_gpio_in(dev, pl061_set_irq, N_GPIOS);
|
||||
qdev_init_gpio_out(dev, s->out, N_GPIOS);
|
||||
}
|
||||
|
||||
static void pl061_class_init(ObjectClass *klass, void *data)
|
||||
|
@ -44,7 +44,6 @@ common-obj-$(CONFIG_IMX) += imx6_ccm.o
|
||||
common-obj-$(CONFIG_IMX) += imx6ul_ccm.o
|
||||
obj-$(CONFIG_IMX) += imx6_src.o
|
||||
common-obj-$(CONFIG_IMX) += imx7_ccm.o
|
||||
common-obj-$(CONFIG_IMX) += imx2_wdt.o
|
||||
common-obj-$(CONFIG_IMX) += imx7_snvs.o
|
||||
common-obj-$(CONFIG_IMX) += imx7_gpr.o
|
||||
common-obj-$(CONFIG_IMX) += imx_rngc.o
|
||||
|
@ -1,90 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Impinj, Inc.
|
||||
*
|
||||
* i.MX2 Watchdog IP block
|
||||
*
|
||||
* Author: Andrey Smirnov <andrew.smirnov@gmail.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/bitops.h"
|
||||
#include "qemu/module.h"
|
||||
#include "sysemu/watchdog.h"
|
||||
|
||||
#include "hw/misc/imx2_wdt.h"
|
||||
|
||||
#define IMX2_WDT_WCR_WDA BIT(5) /* -> External Reset WDOG_B */
|
||||
#define IMX2_WDT_WCR_SRS BIT(4) /* -> Software Reset Signal */
|
||||
|
||||
static uint64_t imx2_wdt_read(void *opaque, hwaddr addr,
|
||||
unsigned int size)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void imx2_wdt_write(void *opaque, hwaddr addr,
|
||||
uint64_t value, unsigned int size)
|
||||
{
|
||||
if (addr == IMX2_WDT_WCR &&
|
||||
(~value & (IMX2_WDT_WCR_WDA | IMX2_WDT_WCR_SRS))) {
|
||||
watchdog_perform_action();
|
||||
}
|
||||
}
|
||||
|
||||
static const MemoryRegionOps imx2_wdt_ops = {
|
||||
.read = imx2_wdt_read,
|
||||
.write = imx2_wdt_write,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
.impl = {
|
||||
/*
|
||||
* Our device would not work correctly if the guest was doing
|
||||
* unaligned access. This might not be a limitation on the
|
||||
* real device but in practice there is no reason for a guest
|
||||
* to access this device unaligned.
|
||||
*/
|
||||
.min_access_size = 4,
|
||||
.max_access_size = 4,
|
||||
.unaligned = false,
|
||||
},
|
||||
};
|
||||
|
||||
static void imx2_wdt_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
IMX2WdtState *s = IMX2_WDT(dev);
|
||||
|
||||
memory_region_init_io(&s->mmio, OBJECT(dev),
|
||||
&imx2_wdt_ops, s,
|
||||
TYPE_IMX2_WDT".mmio",
|
||||
IMX2_WDT_REG_NUM * sizeof(uint16_t));
|
||||
sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio);
|
||||
}
|
||||
|
||||
static void imx2_wdt_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->realize = imx2_wdt_realize;
|
||||
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
|
||||
}
|
||||
|
||||
static const TypeInfo imx2_wdt_info = {
|
||||
.name = TYPE_IMX2_WDT,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(IMX2WdtState),
|
||||
.class_init = imx2_wdt_class_init,
|
||||
};
|
||||
|
||||
static WatchdogTimerModel model = {
|
||||
.wdt_name = "imx2-watchdog",
|
||||
.wdt_description = "i.MX2 Watchdog",
|
||||
};
|
||||
|
||||
static void imx2_wdt_register_type(void)
|
||||
{
|
||||
watchdog_add_model(&model);
|
||||
type_register_static(&imx2_wdt_info);
|
||||
}
|
||||
type_init(imx2_wdt_register_type)
|
@ -54,7 +54,6 @@
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/log.h"
|
||||
#include "hw/hw.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "migration/vmstate.h"
|
||||
#include "qemu/timer.h"
|
||||
@ -62,7 +61,6 @@
|
||||
#include "hw/ptimer.h"
|
||||
|
||||
#include "hw/arm/exynos4210.h"
|
||||
#include "hw/hw.h"
|
||||
#include "hw/irq.h"
|
||||
|
||||
//#define DEBUG_MCT
|
||||
@ -1062,7 +1060,7 @@ static uint64_t exynos4210_mct_read(void *opaque, hwaddr offset,
|
||||
int index;
|
||||
int shift;
|
||||
uint64_t count;
|
||||
uint32_t value;
|
||||
uint32_t value = 0;
|
||||
int lt_i;
|
||||
|
||||
switch (offset) {
|
||||
@ -1158,8 +1156,8 @@ static uint64_t exynos4210_mct_read(void *opaque, hwaddr offset,
|
||||
break;
|
||||
|
||||
default:
|
||||
hw_error("exynos4210.mct: bad read offset "
|
||||
TARGET_FMT_plx "\n", offset);
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIX "\n",
|
||||
__func__, offset);
|
||||
break;
|
||||
}
|
||||
return value;
|
||||
@ -1484,8 +1482,8 @@ static void exynos4210_mct_write(void *opaque, hwaddr offset,
|
||||
break;
|
||||
|
||||
default:
|
||||
hw_error("exynos4210.mct: bad write offset "
|
||||
TARGET_FMT_plx "\n", offset);
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIX "\n",
|
||||
__func__, offset);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -14,3 +14,6 @@ config WDT_IB700
|
||||
|
||||
config WDT_DIAG288
|
||||
bool
|
||||
|
||||
config WDT_IMX2
|
||||
bool
|
||||
|
@ -4,3 +4,4 @@ common-obj-$(CONFIG_WDT_IB6300ESB) += wdt_i6300esb.o
|
||||
common-obj-$(CONFIG_WDT_IB700) += wdt_ib700.o
|
||||
common-obj-$(CONFIG_WDT_DIAG288) += wdt_diag288.o
|
||||
common-obj-$(CONFIG_ASPEED_SOC) += wdt_aspeed.o
|
||||
common-obj-$(CONFIG_WDT_IMX2) += wdt_imx2.o
|
||||
|
304
hw/watchdog/wdt_imx2.c
Normal file
304
hw/watchdog/wdt_imx2.c
Normal file
@ -0,0 +1,304 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Impinj, Inc.
|
||||
*
|
||||
* i.MX2 Watchdog IP block
|
||||
*
|
||||
* Author: Andrey Smirnov <andrew.smirnov@gmail.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/bitops.h"
|
||||
#include "qemu/module.h"
|
||||
#include "sysemu/watchdog.h"
|
||||
#include "migration/vmstate.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
|
||||
#include "hw/watchdog/wdt_imx2.h"
|
||||
|
||||
static void imx2_wdt_interrupt(void *opaque)
|
||||
{
|
||||
IMX2WdtState *s = IMX2_WDT(opaque);
|
||||
|
||||
s->wicr |= IMX2_WDT_WICR_WTIS;
|
||||
qemu_set_irq(s->irq, 1);
|
||||
}
|
||||
|
||||
static void imx2_wdt_expired(void *opaque)
|
||||
{
|
||||
IMX2WdtState *s = IMX2_WDT(opaque);
|
||||
|
||||
s->wrsr = IMX2_WDT_WRSR_TOUT;
|
||||
|
||||
/* Perform watchdog action if watchdog is enabled */
|
||||
if (s->wcr & IMX2_WDT_WCR_WDE) {
|
||||
s->wrsr = IMX2_WDT_WRSR_TOUT;
|
||||
watchdog_perform_action();
|
||||
}
|
||||
}
|
||||
|
||||
static void imx2_wdt_reset(DeviceState *dev)
|
||||
{
|
||||
IMX2WdtState *s = IMX2_WDT(dev);
|
||||
|
||||
ptimer_transaction_begin(s->timer);
|
||||
ptimer_stop(s->timer);
|
||||
ptimer_transaction_commit(s->timer);
|
||||
|
||||
if (s->pretimeout_support) {
|
||||
ptimer_transaction_begin(s->itimer);
|
||||
ptimer_stop(s->itimer);
|
||||
ptimer_transaction_commit(s->itimer);
|
||||
}
|
||||
|
||||
s->wicr_locked = false;
|
||||
s->wcr_locked = false;
|
||||
s->wcr_wde_locked = false;
|
||||
|
||||
s->wcr = IMX2_WDT_WCR_WDA | IMX2_WDT_WCR_SRS;
|
||||
s->wsr = 0;
|
||||
s->wrsr &= ~(IMX2_WDT_WRSR_TOUT | IMX2_WDT_WRSR_SFTW);
|
||||
s->wicr = IMX2_WDT_WICR_WICT_DEF;
|
||||
s->wmcr = IMX2_WDT_WMCR_PDE;
|
||||
}
|
||||
|
||||
static uint64_t imx2_wdt_read(void *opaque, hwaddr addr, unsigned int size)
|
||||
{
|
||||
IMX2WdtState *s = IMX2_WDT(opaque);
|
||||
|
||||
switch (addr) {
|
||||
case IMX2_WDT_WCR:
|
||||
return s->wcr;
|
||||
case IMX2_WDT_WSR:
|
||||
return s->wsr;
|
||||
case IMX2_WDT_WRSR:
|
||||
return s->wrsr;
|
||||
case IMX2_WDT_WICR:
|
||||
return s->wicr;
|
||||
case IMX2_WDT_WMCR:
|
||||
return s->wmcr;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void imx_wdt2_update_itimer(IMX2WdtState *s, bool start)
|
||||
{
|
||||
bool running = (s->wcr & IMX2_WDT_WCR_WDE) && (s->wcr & IMX2_WDT_WCR_WT);
|
||||
bool enabled = s->wicr & IMX2_WDT_WICR_WIE;
|
||||
|
||||
ptimer_transaction_begin(s->itimer);
|
||||
if (start || !enabled) {
|
||||
ptimer_stop(s->itimer);
|
||||
}
|
||||
if (running && enabled) {
|
||||
int count = ptimer_get_count(s->timer);
|
||||
int pretimeout = s->wicr & IMX2_WDT_WICR_WICT;
|
||||
|
||||
/*
|
||||
* Only (re-)start pretimeout timer if its counter value is larger
|
||||
* than 0. Otherwise it will fire right away and we'll get an
|
||||
* interrupt loop.
|
||||
*/
|
||||
if (count > pretimeout) {
|
||||
ptimer_set_count(s->itimer, count - pretimeout);
|
||||
if (start) {
|
||||
ptimer_run(s->itimer, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
ptimer_transaction_commit(s->itimer);
|
||||
}
|
||||
|
||||
static void imx_wdt2_update_timer(IMX2WdtState *s, bool start)
|
||||
{
|
||||
ptimer_transaction_begin(s->timer);
|
||||
if (start) {
|
||||
ptimer_stop(s->timer);
|
||||
}
|
||||
if ((s->wcr & IMX2_WDT_WCR_WDE) && (s->wcr & IMX2_WDT_WCR_WT)) {
|
||||
int count = (s->wcr & IMX2_WDT_WCR_WT) >> 8;
|
||||
|
||||
/* A value of 0 reflects one period (0.5s). */
|
||||
ptimer_set_count(s->timer, count + 1);
|
||||
if (start) {
|
||||
ptimer_run(s->timer, 1);
|
||||
}
|
||||
}
|
||||
ptimer_transaction_commit(s->timer);
|
||||
if (s->pretimeout_support) {
|
||||
imx_wdt2_update_itimer(s, start);
|
||||
}
|
||||
}
|
||||
|
||||
static void imx2_wdt_write(void *opaque, hwaddr addr,
|
||||
uint64_t value, unsigned int size)
|
||||
{
|
||||
IMX2WdtState *s = IMX2_WDT(opaque);
|
||||
|
||||
switch (addr) {
|
||||
case IMX2_WDT_WCR:
|
||||
if (s->wcr_locked) {
|
||||
value &= ~IMX2_WDT_WCR_LOCK_MASK;
|
||||
value |= (s->wicr & IMX2_WDT_WCR_LOCK_MASK);
|
||||
}
|
||||
s->wcr_locked = true;
|
||||
if (s->wcr_wde_locked) {
|
||||
value &= ~IMX2_WDT_WCR_WDE;
|
||||
value |= (s->wicr & ~IMX2_WDT_WCR_WDE);
|
||||
} else if (value & IMX2_WDT_WCR_WDE) {
|
||||
s->wcr_wde_locked = true;
|
||||
}
|
||||
if (s->wcr_wdt_locked) {
|
||||
value &= ~IMX2_WDT_WCR_WDT;
|
||||
value |= (s->wicr & ~IMX2_WDT_WCR_WDT);
|
||||
} else if (value & IMX2_WDT_WCR_WDT) {
|
||||
s->wcr_wdt_locked = true;
|
||||
}
|
||||
|
||||
s->wcr = value;
|
||||
if (!(value & IMX2_WDT_WCR_SRS)) {
|
||||
s->wrsr = IMX2_WDT_WRSR_SFTW;
|
||||
}
|
||||
if (!(value & (IMX2_WDT_WCR_WDA | IMX2_WDT_WCR_SRS)) ||
|
||||
(!(value & IMX2_WDT_WCR_WT) && (value & IMX2_WDT_WCR_WDE))) {
|
||||
watchdog_perform_action();
|
||||
}
|
||||
s->wcr |= IMX2_WDT_WCR_SRS;
|
||||
imx_wdt2_update_timer(s, true);
|
||||
break;
|
||||
case IMX2_WDT_WSR:
|
||||
if (s->wsr == IMX2_WDT_SEQ1 && value == IMX2_WDT_SEQ2) {
|
||||
imx_wdt2_update_timer(s, false);
|
||||
}
|
||||
s->wsr = value;
|
||||
break;
|
||||
case IMX2_WDT_WRSR:
|
||||
break;
|
||||
case IMX2_WDT_WICR:
|
||||
if (!s->pretimeout_support) {
|
||||
return;
|
||||
}
|
||||
value &= IMX2_WDT_WICR_LOCK_MASK | IMX2_WDT_WICR_WTIS;
|
||||
if (s->wicr_locked) {
|
||||
value &= IMX2_WDT_WICR_WTIS;
|
||||
value |= (s->wicr & IMX2_WDT_WICR_LOCK_MASK);
|
||||
}
|
||||
s->wicr = value | (s->wicr & IMX2_WDT_WICR_WTIS);
|
||||
if (value & IMX2_WDT_WICR_WTIS) {
|
||||
s->wicr &= ~IMX2_WDT_WICR_WTIS;
|
||||
qemu_set_irq(s->irq, 0);
|
||||
}
|
||||
imx_wdt2_update_itimer(s, true);
|
||||
s->wicr_locked = true;
|
||||
break;
|
||||
case IMX2_WDT_WMCR:
|
||||
s->wmcr = value & IMX2_WDT_WMCR_PDE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static const MemoryRegionOps imx2_wdt_ops = {
|
||||
.read = imx2_wdt_read,
|
||||
.write = imx2_wdt_write,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
.impl = {
|
||||
/*
|
||||
* Our device would not work correctly if the guest was doing
|
||||
* unaligned access. This might not be a limitation on the
|
||||
* real device but in practice there is no reason for a guest
|
||||
* to access this device unaligned.
|
||||
*/
|
||||
.min_access_size = 2,
|
||||
.max_access_size = 2,
|
||||
.unaligned = false,
|
||||
},
|
||||
};
|
||||
|
||||
static const VMStateDescription vmstate_imx2_wdt = {
|
||||
.name = "imx2.wdt",
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_PTIMER(timer, IMX2WdtState),
|
||||
VMSTATE_PTIMER(itimer, IMX2WdtState),
|
||||
VMSTATE_BOOL(wicr_locked, IMX2WdtState),
|
||||
VMSTATE_BOOL(wcr_locked, IMX2WdtState),
|
||||
VMSTATE_BOOL(wcr_wde_locked, IMX2WdtState),
|
||||
VMSTATE_BOOL(wcr_wdt_locked, IMX2WdtState),
|
||||
VMSTATE_UINT16(wcr, IMX2WdtState),
|
||||
VMSTATE_UINT16(wsr, IMX2WdtState),
|
||||
VMSTATE_UINT16(wrsr, IMX2WdtState),
|
||||
VMSTATE_UINT16(wmcr, IMX2WdtState),
|
||||
VMSTATE_UINT16(wicr, IMX2WdtState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static void imx2_wdt_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
IMX2WdtState *s = IMX2_WDT(dev);
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
|
||||
|
||||
memory_region_init_io(&s->mmio, OBJECT(dev),
|
||||
&imx2_wdt_ops, s,
|
||||
TYPE_IMX2_WDT,
|
||||
IMX2_WDT_MMIO_SIZE);
|
||||
sysbus_init_mmio(sbd, &s->mmio);
|
||||
sysbus_init_irq(sbd, &s->irq);
|
||||
|
||||
s->timer = ptimer_init(imx2_wdt_expired, s,
|
||||
PTIMER_POLICY_NO_IMMEDIATE_TRIGGER |
|
||||
PTIMER_POLICY_NO_IMMEDIATE_RELOAD |
|
||||
PTIMER_POLICY_NO_COUNTER_ROUND_DOWN);
|
||||
ptimer_transaction_begin(s->timer);
|
||||
ptimer_set_freq(s->timer, 2);
|
||||
ptimer_set_limit(s->timer, 0xff, 1);
|
||||
ptimer_transaction_commit(s->timer);
|
||||
if (s->pretimeout_support) {
|
||||
s->itimer = ptimer_init(imx2_wdt_interrupt, s,
|
||||
PTIMER_POLICY_NO_IMMEDIATE_TRIGGER |
|
||||
PTIMER_POLICY_NO_IMMEDIATE_RELOAD |
|
||||
PTIMER_POLICY_NO_COUNTER_ROUND_DOWN);
|
||||
ptimer_transaction_begin(s->itimer);
|
||||
ptimer_set_freq(s->itimer, 2);
|
||||
ptimer_set_limit(s->itimer, 0xff, 1);
|
||||
ptimer_transaction_commit(s->itimer);
|
||||
}
|
||||
}
|
||||
|
||||
static Property imx2_wdt_properties[] = {
|
||||
DEFINE_PROP_BOOL("pretimeout-support", IMX2WdtState, pretimeout_support,
|
||||
false),
|
||||
DEFINE_PROP_END_OF_LIST()
|
||||
};
|
||||
|
||||
static void imx2_wdt_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
device_class_set_props(dc, imx2_wdt_properties);
|
||||
dc->realize = imx2_wdt_realize;
|
||||
dc->reset = imx2_wdt_reset;
|
||||
dc->vmsd = &vmstate_imx2_wdt;
|
||||
dc->desc = "i.MX watchdog timer";
|
||||
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
|
||||
}
|
||||
|
||||
static const TypeInfo imx2_wdt_info = {
|
||||
.name = TYPE_IMX2_WDT,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(IMX2WdtState),
|
||||
.class_init = imx2_wdt_class_init,
|
||||
};
|
||||
|
||||
static WatchdogTimerModel model = {
|
||||
.wdt_name = "imx2-watchdog",
|
||||
.wdt_description = "i.MX2 Watchdog",
|
||||
};
|
||||
|
||||
static void imx2_wdt_register_type(void)
|
||||
{
|
||||
watchdog_add_model(&model);
|
||||
type_register_static(&imx2_wdt_info);
|
||||
}
|
||||
type_init(imx2_wdt_register_type)
|
@ -29,6 +29,7 @@
|
||||
#include "hw/gpio/imx_gpio.h"
|
||||
#include "hw/sd/sdhci.h"
|
||||
#include "hw/usb/chipidea.h"
|
||||
#include "hw/watchdog/wdt_imx2.h"
|
||||
#include "exec/memory.h"
|
||||
#include "target/arm/cpu.h"
|
||||
|
||||
@ -60,6 +61,7 @@ typedef struct FslIMX25State {
|
||||
IMXGPIOState gpio[FSL_IMX25_NUM_GPIOS];
|
||||
SDHCIState esdhc[FSL_IMX25_NUM_ESDHCS];
|
||||
ChipideaState usb[FSL_IMX25_NUM_USBS];
|
||||
IMX2WdtState wdt;
|
||||
MemoryRegion rom[2];
|
||||
MemoryRegion iram;
|
||||
MemoryRegion iram_alias;
|
||||
@ -229,6 +231,8 @@ typedef struct FslIMX25State {
|
||||
#define FSL_IMX25_GPIO1_SIZE 0x4000
|
||||
#define FSL_IMX25_GPIO2_ADDR 0x53FD0000
|
||||
#define FSL_IMX25_GPIO2_SIZE 0x4000
|
||||
#define FSL_IMX25_WDT_ADDR 0x53FDC000
|
||||
#define FSL_IMX25_WDT_SIZE 0x4000
|
||||
#define FSL_IMX25_USB1_ADDR 0x53FF4000
|
||||
#define FSL_IMX25_USB1_SIZE 0x0200
|
||||
#define FSL_IMX25_USB2_ADDR 0x53FF4400
|
||||
@ -268,5 +272,6 @@ typedef struct FslIMX25State {
|
||||
#define FSL_IMX25_ESDHC2_IRQ 8
|
||||
#define FSL_IMX25_USB1_IRQ 37
|
||||
#define FSL_IMX25_USB2_IRQ 35
|
||||
#define FSL_IMX25_WDT_IRQ 55
|
||||
|
||||
#endif /* FSL_IMX25_H */
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "hw/timer/imx_epit.h"
|
||||
#include "hw/i2c/imx_i2c.h"
|
||||
#include "hw/gpio/imx_gpio.h"
|
||||
#include "hw/watchdog/wdt_imx2.h"
|
||||
#include "exec/memory.h"
|
||||
#include "target/arm/cpu.h"
|
||||
|
||||
@ -49,6 +50,7 @@ typedef struct FslIMX31State {
|
||||
IMXEPITState epit[FSL_IMX31_NUM_EPITS];
|
||||
IMXI2CState i2c[FSL_IMX31_NUM_I2CS];
|
||||
IMXGPIOState gpio[FSL_IMX31_NUM_GPIOS];
|
||||
IMX2WdtState wdt;
|
||||
MemoryRegion secure_rom;
|
||||
MemoryRegion rom;
|
||||
MemoryRegion iram;
|
||||
@ -87,6 +89,8 @@ typedef struct FslIMX31State {
|
||||
#define FSL_IMX31_GPIO1_SIZE 0x4000
|
||||
#define FSL_IMX31_GPIO2_ADDR 0x53FD0000
|
||||
#define FSL_IMX31_GPIO2_SIZE 0x4000
|
||||
#define FSL_IMX31_WDT_ADDR 0x53FDC000
|
||||
#define FSL_IMX31_WDT_SIZE 0x4000
|
||||
#define FSL_IMX31_AVIC_ADDR 0x68000000
|
||||
#define FSL_IMX31_AVIC_SIZE 0x100
|
||||
#define FSL_IMX31_SDRAM0_ADDR 0x80000000
|
||||
|
@ -21,7 +21,7 @@
|
||||
#include "hw/cpu/a9mpcore.h"
|
||||
#include "hw/misc/imx6_ccm.h"
|
||||
#include "hw/misc/imx6_src.h"
|
||||
#include "hw/misc/imx2_wdt.h"
|
||||
#include "hw/watchdog/wdt_imx2.h"
|
||||
#include "hw/char/imx_serial.h"
|
||||
#include "hw/timer/imx_gpt.h"
|
||||
#include "hw/timer/imx_epit.h"
|
||||
|
@ -24,7 +24,7 @@
|
||||
#include "hw/misc/imx7_snvs.h"
|
||||
#include "hw/misc/imx7_gpr.h"
|
||||
#include "hw/intc/imx_gpcv2.h"
|
||||
#include "hw/misc/imx2_wdt.h"
|
||||
#include "hw/watchdog/wdt_imx2.h"
|
||||
#include "hw/gpio/imx_gpio.h"
|
||||
#include "hw/char/imx_serial.h"
|
||||
#include "hw/timer/imx_gpt.h"
|
||||
|
@ -26,7 +26,7 @@
|
||||
#include "hw/misc/imx7_snvs.h"
|
||||
#include "hw/misc/imx7_gpr.h"
|
||||
#include "hw/misc/imx6_src.h"
|
||||
#include "hw/misc/imx2_wdt.h"
|
||||
#include "hw/watchdog/wdt_imx2.h"
|
||||
#include "hw/gpio/imx_gpio.h"
|
||||
#include "hw/char/imx_serial.h"
|
||||
#include "hw/timer/imx_gpt.h"
|
||||
@ -113,6 +113,9 @@ enum FslIMX7MemoryMap {
|
||||
FSL_IMX7_IOMUXC_GPR_ADDR = 0x30340000,
|
||||
FSL_IMX7_IOMUXCn_SIZE = 0x1000,
|
||||
|
||||
FSL_IMX7_OCOTP_ADDR = 0x30350000,
|
||||
FSL_IMX7_OCOTP_SIZE = 0x10000,
|
||||
|
||||
FSL_IMX7_ANALOG_ADDR = 0x30360000,
|
||||
FSL_IMX7_SNVS_ADDR = 0x30370000,
|
||||
FSL_IMX7_CCM_ADDR = 0x30380000,
|
||||
@ -124,11 +127,24 @@ enum FslIMX7MemoryMap {
|
||||
FSL_IMX7_ADC2_ADDR = 0x30620000,
|
||||
FSL_IMX7_ADCn_SIZE = 0x1000,
|
||||
|
||||
FSL_IMX7_PWM1_ADDR = 0x30660000,
|
||||
FSL_IMX7_PWM2_ADDR = 0x30670000,
|
||||
FSL_IMX7_PWM3_ADDR = 0x30680000,
|
||||
FSL_IMX7_PWM4_ADDR = 0x30690000,
|
||||
FSL_IMX7_PWMn_SIZE = 0x10000,
|
||||
|
||||
FSL_IMX7_PCIE_PHY_ADDR = 0x306D0000,
|
||||
FSL_IMX7_PCIE_PHY_SIZE = 0x10000,
|
||||
|
||||
FSL_IMX7_GPC_ADDR = 0x303A0000,
|
||||
|
||||
FSL_IMX7_CAAM_ADDR = 0x30900000,
|
||||
FSL_IMX7_CAAM_SIZE = 0x40000,
|
||||
|
||||
FSL_IMX7_CAN1_ADDR = 0x30A00000,
|
||||
FSL_IMX7_CAN2_ADDR = 0x30A10000,
|
||||
FSL_IMX7_CANn_SIZE = 0x10000,
|
||||
|
||||
FSL_IMX7_I2C1_ADDR = 0x30A20000,
|
||||
FSL_IMX7_I2C2_ADDR = 0x30A30000,
|
||||
FSL_IMX7_I2C3_ADDR = 0x30A40000,
|
||||
@ -212,6 +228,11 @@ enum FslIMX7IRQs {
|
||||
FSL_IMX7_USB2_IRQ = 42,
|
||||
FSL_IMX7_USB3_IRQ = 40,
|
||||
|
||||
FSL_IMX7_WDOG1_IRQ = 78,
|
||||
FSL_IMX7_WDOG2_IRQ = 79,
|
||||
FSL_IMX7_WDOG3_IRQ = 10,
|
||||
FSL_IMX7_WDOG4_IRQ = 109,
|
||||
|
||||
FSL_IMX7_PCI_INTA_IRQ = 125,
|
||||
FSL_IMX7_PCI_INTB_IRQ = 124,
|
||||
FSL_IMX7_PCI_INTC_IRQ = 123,
|
||||
|
@ -1,33 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Impinj, Inc.
|
||||
*
|
||||
* i.MX2 Watchdog IP block
|
||||
*
|
||||
* Author: Andrey Smirnov <andrew.smirnov@gmail.com>
|
||||
*
|
||||
* 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 IMX2_WDT_H
|
||||
#define IMX2_WDT_H
|
||||
|
||||
#include "hw/sysbus.h"
|
||||
|
||||
#define TYPE_IMX2_WDT "imx2.wdt"
|
||||
#define IMX2_WDT(obj) OBJECT_CHECK(IMX2WdtState, (obj), TYPE_IMX2_WDT)
|
||||
|
||||
enum IMX2WdtRegisters {
|
||||
IMX2_WDT_WCR = 0x0000,
|
||||
IMX2_WDT_REG_NUM = 0x0008 / sizeof(uint16_t) + 1,
|
||||
};
|
||||
|
||||
|
||||
typedef struct IMX2WdtState {
|
||||
/* <private> */
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
MemoryRegion mmio;
|
||||
} IMX2WdtState;
|
||||
|
||||
#endif /* IMX2_WDT_H */
|
90
include/hw/watchdog/wdt_imx2.h
Normal file
90
include/hw/watchdog/wdt_imx2.h
Normal file
@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Impinj, Inc.
|
||||
*
|
||||
* i.MX2 Watchdog IP block
|
||||
*
|
||||
* Author: Andrey Smirnov <andrew.smirnov@gmail.com>
|
||||
*
|
||||
* 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 IMX2_WDT_H
|
||||
#define IMX2_WDT_H
|
||||
|
||||
#include "qemu/bitops.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/irq.h"
|
||||
#include "hw/ptimer.h"
|
||||
|
||||
#define TYPE_IMX2_WDT "imx2.wdt"
|
||||
#define IMX2_WDT(obj) OBJECT_CHECK(IMX2WdtState, (obj), TYPE_IMX2_WDT)
|
||||
|
||||
enum IMX2WdtRegisters {
|
||||
IMX2_WDT_WCR = 0x0000, /* Control Register */
|
||||
IMX2_WDT_WSR = 0x0002, /* Service Register */
|
||||
IMX2_WDT_WRSR = 0x0004, /* Reset Status Register */
|
||||
IMX2_WDT_WICR = 0x0006, /* Interrupt Control Register */
|
||||
IMX2_WDT_WMCR = 0x0008, /* Misc Register */
|
||||
};
|
||||
|
||||
#define IMX2_WDT_MMIO_SIZE 0x000a
|
||||
|
||||
/* Control Register definitions */
|
||||
#define IMX2_WDT_WCR_WT (0xFF << 8) /* Watchdog Timeout Field */
|
||||
#define IMX2_WDT_WCR_WDW BIT(7) /* WDOG Disable for Wait */
|
||||
#define IMX2_WDT_WCR_WDA BIT(5) /* WDOG Assertion */
|
||||
#define IMX2_WDT_WCR_SRS BIT(4) /* Software Reset Signal */
|
||||
#define IMX2_WDT_WCR_WDT BIT(3) /* WDOG Timeout Assertion */
|
||||
#define IMX2_WDT_WCR_WDE BIT(2) /* Watchdog Enable */
|
||||
#define IMX2_WDT_WCR_WDBG BIT(1) /* Watchdog Debug Enable */
|
||||
#define IMX2_WDT_WCR_WDZST BIT(0) /* Watchdog Timer Suspend */
|
||||
|
||||
#define IMX2_WDT_WCR_LOCK_MASK (IMX2_WDT_WCR_WDZST | IMX2_WDT_WCR_WDBG \
|
||||
| IMX2_WDT_WCR_WDW)
|
||||
|
||||
/* Service Register definitions */
|
||||
#define IMX2_WDT_SEQ1 0x5555 /* service sequence 1 */
|
||||
#define IMX2_WDT_SEQ2 0xAAAA /* service sequence 2 */
|
||||
|
||||
/* Reset Status Register definitions */
|
||||
#define IMX2_WDT_WRSR_TOUT BIT(1) /* Reset due to Timeout */
|
||||
#define IMX2_WDT_WRSR_SFTW BIT(0) /* Reset due to software reset */
|
||||
|
||||
/* Interrupt Control Register definitions */
|
||||
#define IMX2_WDT_WICR_WIE BIT(15) /* Interrupt Enable */
|
||||
#define IMX2_WDT_WICR_WTIS BIT(14) /* Interrupt Status */
|
||||
#define IMX2_WDT_WICR_WICT 0xff /* Interrupt Timeout */
|
||||
#define IMX2_WDT_WICR_WICT_DEF 0x04 /* Default interrupt timeout (2s) */
|
||||
|
||||
#define IMX2_WDT_WICR_LOCK_MASK (IMX2_WDT_WICR_WIE | IMX2_WDT_WICR_WICT)
|
||||
|
||||
/* Misc Control Register definitions */
|
||||
#define IMX2_WDT_WMCR_PDE BIT(0) /* Power-Down Enable */
|
||||
|
||||
typedef struct IMX2WdtState {
|
||||
/* <private> */
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
/*< public >*/
|
||||
MemoryRegion mmio;
|
||||
qemu_irq irq;
|
||||
|
||||
struct ptimer_state *timer;
|
||||
struct ptimer_state *itimer;
|
||||
|
||||
bool pretimeout_support;
|
||||
bool wicr_locked;
|
||||
|
||||
uint16_t wcr;
|
||||
uint16_t wsr;
|
||||
uint16_t wrsr;
|
||||
uint16_t wicr;
|
||||
uint16_t wmcr;
|
||||
|
||||
bool wcr_locked; /* affects WDZST, WDBG, and WDW */
|
||||
bool wcr_wde_locked; /* affects WDE */
|
||||
bool wcr_wdt_locked; /* affects WDT (never cleared) */
|
||||
} IMX2WdtState;
|
||||
|
||||
#endif /* IMX2_WDT_H */
|
@ -295,84 +295,100 @@ void cpu_loop(CPUARMState *env)
|
||||
}
|
||||
break;
|
||||
case EXCP_SWI:
|
||||
case EXCP_BKPT:
|
||||
{
|
||||
env->eabi = 1;
|
||||
/* system call */
|
||||
if (trapnr == EXCP_BKPT) {
|
||||
if (env->thumb) {
|
||||
/* FIXME - what to do if get_user() fails? */
|
||||
get_user_code_u16(insn, env->regs[15], env);
|
||||
n = insn & 0xff;
|
||||
env->regs[15] += 2;
|
||||
} else {
|
||||
/* FIXME - what to do if get_user() fails? */
|
||||
get_user_code_u32(insn, env->regs[15], env);
|
||||
n = (insn & 0xf) | ((insn >> 4) & 0xff0);
|
||||
env->regs[15] += 4;
|
||||
}
|
||||
if (env->thumb) {
|
||||
/* Thumb is always EABI style with syscall number in r7 */
|
||||
n = env->regs[7];
|
||||
} else {
|
||||
if (env->thumb) {
|
||||
/* FIXME - what to do if get_user() fails? */
|
||||
get_user_code_u16(insn, env->regs[15] - 2, env);
|
||||
n = insn & 0xff;
|
||||
/*
|
||||
* Equivalent of kernel CONFIG_OABI_COMPAT: read the
|
||||
* Arm SVC insn to extract the immediate, which is the
|
||||
* syscall number in OABI.
|
||||
*/
|
||||
/* FIXME - what to do if get_user() fails? */
|
||||
get_user_code_u32(insn, env->regs[15] - 4, env);
|
||||
n = insn & 0xffffff;
|
||||
if (n == 0) {
|
||||
/* zero immediate: EABI, syscall number in r7 */
|
||||
n = env->regs[7];
|
||||
} else {
|
||||
/* FIXME - what to do if get_user() fails? */
|
||||
get_user_code_u32(insn, env->regs[15] - 4, env);
|
||||
n = insn & 0xffffff;
|
||||
/*
|
||||
* This XOR matches the kernel code: an immediate
|
||||
* in the valid range (0x900000 .. 0x9fffff) is
|
||||
* converted into the correct EABI-style syscall
|
||||
* number; invalid immediates end up as values
|
||||
* > 0xfffff and are handled below as out-of-range.
|
||||
*/
|
||||
n ^= ARM_SYSCALL_BASE;
|
||||
env->eabi = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (n == ARM_NR_cacheflush) {
|
||||
/* nop */
|
||||
} else if (n == 0 || n >= ARM_SYSCALL_BASE || env->thumb) {
|
||||
/* linux syscall */
|
||||
if (env->thumb || n == 0) {
|
||||
n = env->regs[7];
|
||||
} else {
|
||||
n -= ARM_SYSCALL_BASE;
|
||||
env->eabi = 0;
|
||||
}
|
||||
if ( n > ARM_NR_BASE) {
|
||||
switch (n) {
|
||||
case ARM_NR_cacheflush:
|
||||
/* nop */
|
||||
break;
|
||||
case ARM_NR_set_tls:
|
||||
cpu_set_tls(env, env->regs[0]);
|
||||
env->regs[0] = 0;
|
||||
break;
|
||||
case ARM_NR_breakpoint:
|
||||
env->regs[15] -= env->thumb ? 2 : 4;
|
||||
goto excp_debug;
|
||||
case ARM_NR_get_tls:
|
||||
env->regs[0] = cpu_get_tls(env);
|
||||
break;
|
||||
default:
|
||||
if (n > ARM_NR_BASE) {
|
||||
switch (n) {
|
||||
case ARM_NR_cacheflush:
|
||||
/* nop */
|
||||
break;
|
||||
case ARM_NR_set_tls:
|
||||
cpu_set_tls(env, env->regs[0]);
|
||||
env->regs[0] = 0;
|
||||
break;
|
||||
case ARM_NR_breakpoint:
|
||||
env->regs[15] -= env->thumb ? 2 : 4;
|
||||
goto excp_debug;
|
||||
case ARM_NR_get_tls:
|
||||
env->regs[0] = cpu_get_tls(env);
|
||||
break;
|
||||
default:
|
||||
if (n < 0xf0800) {
|
||||
/*
|
||||
* Syscalls 0xf0000..0xf07ff (or 0x9f0000..
|
||||
* 0x9f07ff in OABI numbering) are defined
|
||||
* to return -ENOSYS rather than raising
|
||||
* SIGILL. Note that we have already
|
||||
* removed the 0x900000 prefix.
|
||||
*/
|
||||
qemu_log_mask(LOG_UNIMP,
|
||||
"qemu: Unsupported ARM syscall: 0x%x\n",
|
||||
"qemu: Unsupported ARM syscall: 0x%x\n",
|
||||
n);
|
||||
env->regs[0] = -TARGET_ENOSYS;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
ret = do_syscall(env,
|
||||
n,
|
||||
env->regs[0],
|
||||
env->regs[1],
|
||||
env->regs[2],
|
||||
env->regs[3],
|
||||
env->regs[4],
|
||||
env->regs[5],
|
||||
0, 0);
|
||||
if (ret == -TARGET_ERESTARTSYS) {
|
||||
env->regs[15] -= env->thumb ? 2 : 4;
|
||||
} else if (ret != -TARGET_QEMU_ESIGRETURN) {
|
||||
env->regs[0] = ret;
|
||||
} else {
|
||||
/*
|
||||
* Otherwise SIGILL. This includes any SWI with
|
||||
* immediate not originally 0x9fxxxx, because
|
||||
* of the earlier XOR.
|
||||
*/
|
||||
info.si_signo = TARGET_SIGILL;
|
||||
info.si_errno = 0;
|
||||
info.si_code = TARGET_ILL_ILLTRP;
|
||||
info._sifields._sigfault._addr = env->regs[15];
|
||||
if (env->thumb) {
|
||||
info._sifields._sigfault._addr -= 2;
|
||||
} else {
|
||||
info._sifields._sigfault._addr -= 4;
|
||||
}
|
||||
queue_signal(env, info.si_signo,
|
||||
QEMU_SI_FAULT, &info);
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
goto error;
|
||||
ret = do_syscall(env,
|
||||
n,
|
||||
env->regs[0],
|
||||
env->regs[1],
|
||||
env->regs[2],
|
||||
env->regs[3],
|
||||
env->regs[4],
|
||||
env->regs[5],
|
||||
0, 0);
|
||||
if (ret == -TARGET_ERESTARTSYS) {
|
||||
env->regs[15] -= env->thumb ? 2 : 4;
|
||||
} else if (ret != -TARGET_QEMU_ESIGRETURN) {
|
||||
env->regs[0] = ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -396,6 +412,7 @@ void cpu_loop(CPUARMState *env)
|
||||
}
|
||||
break;
|
||||
case EXCP_DEBUG:
|
||||
case EXCP_BKPT:
|
||||
excp_debug:
|
||||
info.si_signo = TARGET_SIGTRAP;
|
||||
info.si_errno = 0;
|
||||
|
@ -126,8 +126,6 @@ struct rt_sigframe_v2
|
||||
abi_ulong retcode[4];
|
||||
};
|
||||
|
||||
#define TARGET_CONFIG_CPU_32 1
|
||||
|
||||
/*
|
||||
* For ARM syscalls, we encode the syscall number into the instruction.
|
||||
*/
|
||||
@ -187,9 +185,7 @@ setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/
|
||||
__put_user(env->regs[13], &sc->arm_sp);
|
||||
__put_user(env->regs[14], &sc->arm_lr);
|
||||
__put_user(env->regs[15], &sc->arm_pc);
|
||||
#ifdef TARGET_CONFIG_CPU_32
|
||||
__put_user(cpsr_read(env), &sc->arm_cpsr);
|
||||
#endif
|
||||
|
||||
__put_user(/* current->thread.trap_no */ 0, &sc->trap_no);
|
||||
__put_user(/* current->thread.error_code */ 0, &sc->error_code);
|
||||
@ -244,6 +240,11 @@ setup_return(CPUARMState *env, struct target_sigaction *ka,
|
||||
} else {
|
||||
cpsr &= ~CPSR_T;
|
||||
}
|
||||
if (env->cp15.sctlr_el[1] & SCTLR_E0E) {
|
||||
cpsr |= CPSR_E;
|
||||
} else {
|
||||
cpsr &= ~CPSR_E;
|
||||
}
|
||||
|
||||
if (ka->sa_flags & TARGET_SA_RESTORER) {
|
||||
if (is_fdpic) {
|
||||
@ -287,7 +288,8 @@ setup_return(CPUARMState *env, struct target_sigaction *ka,
|
||||
env->regs[13] = frame_addr;
|
||||
env->regs[14] = retcode;
|
||||
env->regs[15] = handler & (thumb ? ~1 : ~3);
|
||||
cpsr_write(env, cpsr, CPSR_IT | CPSR_T, CPSRWriteByInstr);
|
||||
cpsr_write(env, cpsr, CPSR_IT | CPSR_T | CPSR_E, CPSRWriteByInstr);
|
||||
arm_rebuild_hflags(env);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -543,10 +545,9 @@ restore_sigcontext(CPUARMState *env, struct target_sigcontext *sc)
|
||||
__get_user(env->regs[13], &sc->arm_sp);
|
||||
__get_user(env->regs[14], &sc->arm_lr);
|
||||
__get_user(env->regs[15], &sc->arm_pc);
|
||||
#ifdef TARGET_CONFIG_CPU_32
|
||||
__get_user(cpsr, &sc->arm_cpsr);
|
||||
cpsr_write(env, cpsr, CPSR_USER | CPSR_EXEC, CPSRWriteByInstr);
|
||||
#endif
|
||||
arm_rebuild_hflags(env);
|
||||
|
||||
err |= !valid_user_regs(env);
|
||||
|
||||
|
@ -1230,7 +1230,7 @@ void pmu_init(ARMCPU *cpu);
|
||||
#define CACHED_CPSR_BITS (CPSR_T | CPSR_AIF | CPSR_GE | CPSR_IT | CPSR_Q \
|
||||
| CPSR_NZCV)
|
||||
/* Bits writable in user mode. */
|
||||
#define CPSR_USER (CPSR_NZCV | CPSR_Q | CPSR_GE)
|
||||
#define CPSR_USER (CPSR_NZCV | CPSR_Q | CPSR_GE | CPSR_E)
|
||||
/* Execution state bits. MRS read as zero, MSR writes ignored. */
|
||||
#define CPSR_EXEC (CPSR_T | CPSR_IT | CPSR_J | CPSR_IL)
|
||||
|
||||
|
@ -496,14 +496,8 @@ static void clear_vec_high(DisasContext *s, bool is_q, int rd)
|
||||
unsigned ofs = fp_reg_offset(s, rd, MO_64);
|
||||
unsigned vsz = vec_full_reg_size(s);
|
||||
|
||||
if (!is_q) {
|
||||
TCGv_i64 tcg_zero = tcg_const_i64(0);
|
||||
tcg_gen_st_i64(tcg_zero, cpu_env, ofs + 8);
|
||||
tcg_temp_free_i64(tcg_zero);
|
||||
}
|
||||
if (vsz > 16) {
|
||||
tcg_gen_gvec_dup_imm(MO_64, ofs + 16, vsz - 16, vsz - 16, 0);
|
||||
}
|
||||
/* Nop move, with side effect of clearing the tail. */
|
||||
tcg_gen_gvec_mov(MO_64, ofs, ofs, is_q ? 16 : 8, vsz);
|
||||
}
|
||||
|
||||
void write_fp_dreg(DisasContext *s, int reg, TCGv_i64 v)
|
||||
@ -906,11 +900,10 @@ static void do_fp_ld(DisasContext *s, int destidx, TCGv_i64 tcg_addr, int size)
|
||||
{
|
||||
/* This always zero-extends and writes to a full 128 bit wide vector */
|
||||
TCGv_i64 tmplo = tcg_temp_new_i64();
|
||||
TCGv_i64 tmphi;
|
||||
TCGv_i64 tmphi = NULL;
|
||||
|
||||
if (size < 4) {
|
||||
MemOp memop = s->be_data + size;
|
||||
tmphi = tcg_const_i64(0);
|
||||
tcg_gen_qemu_ld_i64(tmplo, tcg_addr, get_mem_index(s), memop);
|
||||
} else {
|
||||
bool be = s->be_data == MO_BE;
|
||||
@ -928,12 +921,13 @@ static void do_fp_ld(DisasContext *s, int destidx, TCGv_i64 tcg_addr, int size)
|
||||
}
|
||||
|
||||
tcg_gen_st_i64(tmplo, cpu_env, fp_reg_offset(s, destidx, MO_64));
|
||||
tcg_gen_st_i64(tmphi, cpu_env, fp_reg_hi_offset(s, destidx));
|
||||
|
||||
tcg_temp_free_i64(tmplo);
|
||||
tcg_temp_free_i64(tmphi);
|
||||
|
||||
clear_vec_high(s, true, destidx);
|
||||
if (tmphi) {
|
||||
tcg_gen_st_i64(tmphi, cpu_env, fp_reg_hi_offset(s, destidx));
|
||||
tcg_temp_free_i64(tmphi);
|
||||
}
|
||||
clear_vec_high(s, tmphi != NULL, destidx);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -6940,7 +6934,6 @@ static void disas_simd_ext(DisasContext *s, uint32_t insn)
|
||||
read_vec_element(s, tcg_resh, rm, 0, MO_64);
|
||||
do_ext64(s, tcg_resh, tcg_resl, pos);
|
||||
}
|
||||
tcg_gen_movi_i64(tcg_resh, 0);
|
||||
} else {
|
||||
TCGv_i64 tcg_hh;
|
||||
typedef struct {
|
||||
@ -6970,9 +6963,11 @@ static void disas_simd_ext(DisasContext *s, uint32_t insn)
|
||||
|
||||
write_vec_element(s, tcg_resl, rd, 0, MO_64);
|
||||
tcg_temp_free_i64(tcg_resl);
|
||||
write_vec_element(s, tcg_resh, rd, 1, MO_64);
|
||||
if (is_q) {
|
||||
write_vec_element(s, tcg_resh, rd, 1, MO_64);
|
||||
}
|
||||
tcg_temp_free_i64(tcg_resh);
|
||||
clear_vec_high(s, true, rd);
|
||||
clear_vec_high(s, is_q, rd);
|
||||
}
|
||||
|
||||
/* TBL/TBX
|
||||
@ -7009,17 +7004,21 @@ static void disas_simd_tb(DisasContext *s, uint32_t insn)
|
||||
* the input.
|
||||
*/
|
||||
tcg_resl = tcg_temp_new_i64();
|
||||
tcg_resh = tcg_temp_new_i64();
|
||||
tcg_resh = NULL;
|
||||
|
||||
if (is_tblx) {
|
||||
read_vec_element(s, tcg_resl, rd, 0, MO_64);
|
||||
} else {
|
||||
tcg_gen_movi_i64(tcg_resl, 0);
|
||||
}
|
||||
if (is_tblx && is_q) {
|
||||
read_vec_element(s, tcg_resh, rd, 1, MO_64);
|
||||
} else {
|
||||
tcg_gen_movi_i64(tcg_resh, 0);
|
||||
|
||||
if (is_q) {
|
||||
tcg_resh = tcg_temp_new_i64();
|
||||
if (is_tblx) {
|
||||
read_vec_element(s, tcg_resh, rd, 1, MO_64);
|
||||
} else {
|
||||
tcg_gen_movi_i64(tcg_resh, 0);
|
||||
}
|
||||
}
|
||||
|
||||
tcg_idx = tcg_temp_new_i64();
|
||||
@ -7039,9 +7038,12 @@ static void disas_simd_tb(DisasContext *s, uint32_t insn)
|
||||
|
||||
write_vec_element(s, tcg_resl, rd, 0, MO_64);
|
||||
tcg_temp_free_i64(tcg_resl);
|
||||
write_vec_element(s, tcg_resh, rd, 1, MO_64);
|
||||
tcg_temp_free_i64(tcg_resh);
|
||||
clear_vec_high(s, true, rd);
|
||||
|
||||
if (is_q) {
|
||||
write_vec_element(s, tcg_resh, rd, 1, MO_64);
|
||||
tcg_temp_free_i64(tcg_resh);
|
||||
}
|
||||
clear_vec_high(s, is_q, rd);
|
||||
}
|
||||
|
||||
/* ZIP/UZP/TRN
|
||||
@ -7078,7 +7080,7 @@ static void disas_simd_zip_trn(DisasContext *s, uint32_t insn)
|
||||
}
|
||||
|
||||
tcg_resl = tcg_const_i64(0);
|
||||
tcg_resh = tcg_const_i64(0);
|
||||
tcg_resh = is_q ? tcg_const_i64(0) : NULL;
|
||||
tcg_res = tcg_temp_new_i64();
|
||||
|
||||
for (i = 0; i < elements; i++) {
|
||||
@ -7129,9 +7131,12 @@ static void disas_simd_zip_trn(DisasContext *s, uint32_t insn)
|
||||
|
||||
write_vec_element(s, tcg_resl, rd, 0, MO_64);
|
||||
tcg_temp_free_i64(tcg_resl);
|
||||
write_vec_element(s, tcg_resh, rd, 1, MO_64);
|
||||
tcg_temp_free_i64(tcg_resh);
|
||||
clear_vec_high(s, true, rd);
|
||||
|
||||
if (is_q) {
|
||||
write_vec_element(s, tcg_resh, rd, 1, MO_64);
|
||||
tcg_temp_free_i64(tcg_resh);
|
||||
}
|
||||
clear_vec_high(s, is_q, rd);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -3034,29 +3034,6 @@ static inline void gen_neon_rsb(int size, TCGv_i32 t0, TCGv_i32 t1)
|
||||
default: return 1; \
|
||||
}} while (0)
|
||||
|
||||
#define GEN_NEON_INTEGER_OP(name) do { \
|
||||
switch ((size << 1) | u) { \
|
||||
case 0: \
|
||||
gen_helper_neon_##name##_s8(tmp, tmp, tmp2); \
|
||||
break; \
|
||||
case 1: \
|
||||
gen_helper_neon_##name##_u8(tmp, tmp, tmp2); \
|
||||
break; \
|
||||
case 2: \
|
||||
gen_helper_neon_##name##_s16(tmp, tmp, tmp2); \
|
||||
break; \
|
||||
case 3: \
|
||||
gen_helper_neon_##name##_u16(tmp, tmp, tmp2); \
|
||||
break; \
|
||||
case 4: \
|
||||
gen_helper_neon_##name##_s32(tmp, tmp, tmp2); \
|
||||
break; \
|
||||
case 5: \
|
||||
gen_helper_neon_##name##_u32(tmp, tmp, tmp2); \
|
||||
break; \
|
||||
default: return 1; \
|
||||
}} while (0)
|
||||
|
||||
static TCGv_i32 neon_load_scratch(int scratch)
|
||||
{
|
||||
TCGv_i32 tmp = tcg_temp_new_i32();
|
||||
|
35
tests/acceptance/machine_arm_canona1100.py
Normal file
35
tests/acceptance/machine_arm_canona1100.py
Normal file
@ -0,0 +1,35 @@
|
||||
# Functional test that boots the canon-a1100 machine with firmware
|
||||
#
|
||||
# Copyright (c) 2020 Red Hat, Inc.
|
||||
#
|
||||
# Author:
|
||||
# Thomas Huth <thuth@redhat.com>
|
||||
#
|
||||
# This work is licensed under the terms of the GNU GPL, version 2 or
|
||||
# later. See the COPYING file in the top-level directory.
|
||||
|
||||
from avocado_qemu import Test
|
||||
from avocado_qemu import wait_for_console_pattern
|
||||
from avocado.utils import archive
|
||||
|
||||
class CanonA1100Machine(Test):
|
||||
"""Boots the barebox firmware and checks that the console is operational"""
|
||||
|
||||
timeout = 90
|
||||
|
||||
def test_arm_canona1100(self):
|
||||
"""
|
||||
:avocado: tags=arch:arm
|
||||
:avocado: tags=machine:canon-a1100
|
||||
:avocado: tags=device:pflash_cfi02
|
||||
"""
|
||||
tar_url = ('https://www.qemu-advent-calendar.org'
|
||||
'/2018/download/day18.tar.xz')
|
||||
tar_hash = '068b5fc4242b29381acee94713509f8a876e9db6'
|
||||
file_path = self.fetch_asset(tar_url, asset_hash=tar_hash)
|
||||
archive.extract(file_path, self.workdir)
|
||||
self.vm.set_console()
|
||||
self.vm.add_args('-bios',
|
||||
self.workdir + '/day18/barebox.canon-a1100.bin')
|
||||
self.vm.launch()
|
||||
wait_for_console_pattern(self, 'running /env/bin/init')
|
Loading…
Reference in New Issue
Block a user