mirror of
https://gitlab.com/qemu-project/qemu
synced 2024-07-08 20:17:27 +00:00
target-arm queue:
* Implement FEAT_NMI and NMI support in the GICv3 * hw/dma: avoid apparent overflow in soc_dma_set_request * linux-user/flatload.c: Remove unused bFLT shared-library and ZFLAT code * Add ResetType argument to Resettable hold and exit phase methods * Add RESET_TYPE_SNAPSHOT_LOAD ResetType * Implement STM32L4x5 USART -----BEGIN PGP SIGNATURE----- iQJNBAABCAA3FiEE4aXFk81BneKOgxXPPCUl7RQ2DN4FAmYqMhMZHHBldGVyLm1h eWRlbGxAbGluYXJvLm9yZwAKCRA8JSXtFDYM3uVlD/47U3zYP33y4+wJcRScC0QI jYd82jS7GhD5YP5QPrIEMaSbDwtYGi4Rez1taaHvZ2fWLg2gE973iixmTaM2mXCd xPEqMsRXkFrQnC89K5/v9uR04AvHxoM8J2mD2OKnUT0RVBs38WxCUMLETBsD18/q obs1RzDRhEs5BnwwPMm5HI1iQeVvDRe/39O3w3rZfA8DuqerrNOQWuJd43asHYjO Gc1QzCGhALlXDoqk11IzjhJ7es8WbJ5XGvrSNe9QLGNJwNsu9oi1Ez+5WK2Eht9r eRvGNFjH4kQY1YCShZjhWpdzU9KT0+80KLirMJFcI3vUztrYZ027/rMyKLHVOybw YAqgEUELwoGVzacpaJg73f77uknKoXrfTH25DfoLX0yFCB35JHOPcjU4Uq1z1pfV I80ZcJBDJ95mXPfyKLrO+0IyVBztLybufedK2aiH16waEGDpgsJv66FB2QRuQBYW O0i6/4DEUZmfSpOmr8ct+julz7wCWSjbvo6JFWxzzxvD0M5T3AFKXZI244g1SMdh LS8V7WVCVzVJ5mK8Ujp2fVaIIxiBzlXVZrQftWv5rhyDOiIIeP8pdekmPlI6p5HK 3/2efzSYNL2UCDZToIq24El/3md/7vHR6DBfBT1/pagxWUstqqLgkJO42jQtTG0E JY1cZ/EQY7cqXGrww8lhWA== =WEsU -----END PGP SIGNATURE----- Merge tag 'pull-target-arm-20240425' of https://git.linaro.org/people/pmaydell/qemu-arm into staging target-arm queue: * Implement FEAT_NMI and NMI support in the GICv3 * hw/dma: avoid apparent overflow in soc_dma_set_request * linux-user/flatload.c: Remove unused bFLT shared-library and ZFLAT code * Add ResetType argument to Resettable hold and exit phase methods * Add RESET_TYPE_SNAPSHOT_LOAD ResetType * Implement STM32L4x5 USART # -----BEGIN PGP SIGNATURE----- # # iQJNBAABCAA3FiEE4aXFk81BneKOgxXPPCUl7RQ2DN4FAmYqMhMZHHBldGVyLm1h # eWRlbGxAbGluYXJvLm9yZwAKCRA8JSXtFDYM3uVlD/47U3zYP33y4+wJcRScC0QI # jYd82jS7GhD5YP5QPrIEMaSbDwtYGi4Rez1taaHvZ2fWLg2gE973iixmTaM2mXCd # xPEqMsRXkFrQnC89K5/v9uR04AvHxoM8J2mD2OKnUT0RVBs38WxCUMLETBsD18/q # obs1RzDRhEs5BnwwPMm5HI1iQeVvDRe/39O3w3rZfA8DuqerrNOQWuJd43asHYjO # Gc1QzCGhALlXDoqk11IzjhJ7es8WbJ5XGvrSNe9QLGNJwNsu9oi1Ez+5WK2Eht9r # eRvGNFjH4kQY1YCShZjhWpdzU9KT0+80KLirMJFcI3vUztrYZ027/rMyKLHVOybw # YAqgEUELwoGVzacpaJg73f77uknKoXrfTH25DfoLX0yFCB35JHOPcjU4Uq1z1pfV # I80ZcJBDJ95mXPfyKLrO+0IyVBztLybufedK2aiH16waEGDpgsJv66FB2QRuQBYW # O0i6/4DEUZmfSpOmr8ct+julz7wCWSjbvo6JFWxzzxvD0M5T3AFKXZI244g1SMdh # LS8V7WVCVzVJ5mK8Ujp2fVaIIxiBzlXVZrQftWv5rhyDOiIIeP8pdekmPlI6p5HK # 3/2efzSYNL2UCDZToIq24El/3md/7vHR6DBfBT1/pagxWUstqqLgkJO42jQtTG0E # JY1cZ/EQY7cqXGrww8lhWA== # =WEsU # -----END PGP SIGNATURE----- # gpg: Signature made Thu 25 Apr 2024 03:36:03 AM PDT # gpg: using RSA key E1A5C593CD419DE28E8315CF3C2525ED14360CDE # gpg: issuer "peter.maydell@linaro.org" # gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" [full] # gpg: aka "Peter Maydell <pmaydell@gmail.com>" [full] # gpg: aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>" [full] # gpg: aka "Peter Maydell <peter@archaic.org.uk>" [unknown] * tag 'pull-target-arm-20240425' of https://git.linaro.org/people/pmaydell/qemu-arm: (37 commits) tests/qtest: Add tests for the STM32L4x5 USART hw/arm: Add the USART to the stm32l4x5 SoC hw/char/stm32l4x5_usart: Add options for serial parameters setting hw/char/stm32l4x5_usart: Enable serial read and write hw/char: Implement STM32L4x5 USART skeleton reset: Add RESET_TYPE_SNAPSHOT_LOAD docs/devel/reset: Update to new API for hold and exit phase methods hw, target: Add ResetType argument to hold and exit phase methods scripts/coccinelle: New script to add ResetType to hold and exit phases allwinner-i2c, adm1272: Use device_cold_reset() for software-triggered reset hw/misc: Don't special case RESET_TYPE_COLD in npcm7xx_clk, gcr linux-user/flatload.c: Remove unused bFLT shared-library and ZFLAT code hw/dma: avoid apparent overflow in soc_dma_set_request hw/arm/virt: Enable NMI support in the GIC if the CPU has FEAT_NMI target/arm: Add FEAT_NMI to max hw/intc/arm_gicv3: Report the VINMI interrupt hw/intc/arm_gicv3: Report the NMI interrupt in gicv3_cpuif_update() hw/intc/arm_gicv3: Implement NMI interrupt priority hw/intc/arm_gicv3: Handle icv_nmiar1_read() for icc_nmiar1_read() hw/intc/arm_gicv3: Add NMI handling CPU interface registers ... Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
commit
83baec642a
|
@ -1115,6 +1115,7 @@ M: Inès Varhol <ines.varhol@telecom-paris.fr>
|
|||
L: qemu-arm@nongnu.org
|
||||
S: Maintained
|
||||
F: hw/arm/stm32l4x5_soc.c
|
||||
F: hw/char/stm32l4x5_usart.c
|
||||
F: hw/misc/stm32l4x5_exti.c
|
||||
F: hw/misc/stm32l4x5_syscfg.c
|
||||
F: hw/misc/stm32l4x5_rcc.c
|
||||
|
|
|
@ -27,9 +27,7 @@ instantly reset an object, without keeping it in reset state, just call
|
|||
``resettable_reset()``. These functions take two parameters: a pointer to the
|
||||
object to reset and a reset type.
|
||||
|
||||
Several types of reset will be supported. For now only cold reset is defined;
|
||||
others may be added later. The Resettable interface handles reset types with an
|
||||
enum:
|
||||
The Resettable interface handles reset types with an enum ``ResetType``:
|
||||
|
||||
``RESET_TYPE_COLD``
|
||||
Cold reset is supported by every resettable object. In QEMU, it means we reset
|
||||
|
@ -37,6 +35,19 @@ enum:
|
|||
from what is a real hardware cold reset. It differs from other resets (like
|
||||
warm or bus resets) which may keep certain parts untouched.
|
||||
|
||||
``RESET_TYPE_SNAPSHOT_LOAD``
|
||||
This is called for a reset which is being done to put the system into a
|
||||
clean state prior to loading a snapshot. (This corresponds to a reset
|
||||
with ``SHUTDOWN_CAUSE_SNAPSHOT_LOAD``.) Almost all devices should treat
|
||||
this the same as ``RESET_TYPE_COLD``. The main exception is devices which
|
||||
have some non-deterministic state they want to reinitialize to a different
|
||||
value on each cold reset, such as RNG seed information, and which they
|
||||
must not reinitialize on a snapshot-load reset.
|
||||
|
||||
Devices which implement reset methods must treat any unknown ``ResetType``
|
||||
as equivalent to ``RESET_TYPE_COLD``; this will reduce the amount of
|
||||
existing code we need to change if we add more types in future.
|
||||
|
||||
Calling ``resettable_reset()`` is equivalent to calling
|
||||
``resettable_assert_reset()`` then ``resettable_release_reset()``. It is
|
||||
possible to interleave multiple calls to these three functions. There may
|
||||
|
@ -150,25 +161,25 @@ in reset.
|
|||
mydev->var = 0;
|
||||
}
|
||||
|
||||
static void mydev_reset_hold(Object *obj)
|
||||
static void mydev_reset_hold(Object *obj, ResetType type)
|
||||
{
|
||||
MyDevClass *myclass = MYDEV_GET_CLASS(obj);
|
||||
MyDevState *mydev = MYDEV(obj);
|
||||
/* call parent class hold phase */
|
||||
if (myclass->parent_phases.hold) {
|
||||
myclass->parent_phases.hold(obj);
|
||||
myclass->parent_phases.hold(obj, type);
|
||||
}
|
||||
/* set an IO */
|
||||
qemu_set_irq(mydev->irq, 1);
|
||||
}
|
||||
|
||||
static void mydev_reset_exit(Object *obj)
|
||||
static void mydev_reset_exit(Object *obj, ResetType type)
|
||||
{
|
||||
MyDevClass *myclass = MYDEV_GET_CLASS(obj);
|
||||
MyDevState *mydev = MYDEV(obj);
|
||||
/* call parent class exit phase */
|
||||
if (myclass->parent_phases.exit) {
|
||||
myclass->parent_phases.exit(obj);
|
||||
myclass->parent_phases.exit(obj, type);
|
||||
}
|
||||
/* clear an IO */
|
||||
qemu_set_irq(mydev->irq, 0);
|
||||
|
|
|
@ -19,13 +19,13 @@ Currently B-L475E-IOT01A machine's only supports the following devices:
|
|||
- STM32L4x5 SYSCFG (System configuration controller)
|
||||
- STM32L4x5 RCC (Reset and clock control)
|
||||
- STM32L4x5 GPIOs (General-purpose I/Os)
|
||||
- STM32L4x5 USARTs, UARTs and LPUART (Serial ports)
|
||||
|
||||
Missing devices
|
||||
"""""""""""""""
|
||||
|
||||
The B-L475E-IOT01A does *not* support the following devices:
|
||||
|
||||
- Serial ports (UART)
|
||||
- Analog to Digital Converter (ADC)
|
||||
- SPI controller
|
||||
- Timer controller (TIMER)
|
||||
|
|
|
@ -64,6 +64,7 @@ the following architecture extensions:
|
|||
- FEAT_MTE (Memory Tagging Extension)
|
||||
- FEAT_MTE2 (Memory Tagging Extension)
|
||||
- FEAT_MTE3 (MTE Asymmetric Fault Handling)
|
||||
- FEAT_NMI (Non-maskable Interrupt)
|
||||
- FEAT_NV (Nested Virtualization)
|
||||
- FEAT_NV2 (Enhanced nested virtualization support)
|
||||
- FEAT_PACIMP (Pointer authentication - IMPLEMENTATION DEFINED algorithm)
|
||||
|
|
|
@ -218,7 +218,7 @@ static void npcm7xx_adc_enter_reset(Object *obj, ResetType type)
|
|||
npcm7xx_adc_reset(s);
|
||||
}
|
||||
|
||||
static void npcm7xx_adc_hold_reset(Object *obj)
|
||||
static void npcm7xx_adc_hold_reset(Object *obj, ResetType type)
|
||||
{
|
||||
NPCM7xxADCState *s = NPCM7XX_ADC(obj);
|
||||
|
||||
|
|
|
@ -477,6 +477,7 @@ config STM32L4X5_SOC
|
|||
select STM32L4X5_SYSCFG
|
||||
select STM32L4X5_RCC
|
||||
select STM32L4X5_GPIO
|
||||
select STM32L4X5_USART
|
||||
|
||||
config XLNX_ZYNQMP_ARM
|
||||
bool
|
||||
|
|
|
@ -272,7 +272,7 @@ static int pxa2xx_pic_post_load(void *opaque, int version_id)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void pxa2xx_pic_reset_hold(Object *obj)
|
||||
static void pxa2xx_pic_reset_hold(Object *obj, ResetType type)
|
||||
{
|
||||
PXA2xxPICState *s = PXA2XX_PIC(obj);
|
||||
|
||||
|
|
|
@ -682,7 +682,7 @@ static void smmu_base_realize(DeviceState *dev, Error **errp)
|
|||
}
|
||||
}
|
||||
|
||||
static void smmu_base_reset_hold(Object *obj)
|
||||
static void smmu_base_reset_hold(Object *obj, ResetType type)
|
||||
{
|
||||
SMMUState *s = ARM_SMMU(obj);
|
||||
|
||||
|
|
|
@ -1727,13 +1727,13 @@ static void smmu_init_irq(SMMUv3State *s, SysBusDevice *dev)
|
|||
}
|
||||
}
|
||||
|
||||
static void smmu_reset_hold(Object *obj)
|
||||
static void smmu_reset_hold(Object *obj, ResetType type)
|
||||
{
|
||||
SMMUv3State *s = ARM_SMMUV3(obj);
|
||||
SMMUv3Class *c = ARM_SMMUV3_GET_CLASS(s);
|
||||
|
||||
if (c->parent_phases.hold) {
|
||||
c->parent_phases.hold(obj);
|
||||
c->parent_phases.hold(obj, type);
|
||||
}
|
||||
|
||||
smmuv3_init_regs(s);
|
||||
|
|
|
@ -394,7 +394,7 @@ static void stellaris_sys_reset_enter(Object *obj, ResetType type)
|
|||
s->dcgc[0] = 1;
|
||||
}
|
||||
|
||||
static void stellaris_sys_reset_hold(Object *obj)
|
||||
static void stellaris_sys_reset_hold(Object *obj, ResetType type)
|
||||
{
|
||||
ssys_state *s = STELLARIS_SYS(obj);
|
||||
|
||||
|
@ -402,7 +402,7 @@ static void stellaris_sys_reset_hold(Object *obj)
|
|||
ssys_calculate_system_clock(s, true);
|
||||
}
|
||||
|
||||
static void stellaris_sys_reset_exit(Object *obj)
|
||||
static void stellaris_sys_reset_exit(Object *obj, ResetType type)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -618,7 +618,7 @@ static void stellaris_i2c_reset_enter(Object *obj, ResetType type)
|
|||
i2c_end_transfer(s->bus);
|
||||
}
|
||||
|
||||
static void stellaris_i2c_reset_hold(Object *obj)
|
||||
static void stellaris_i2c_reset_hold(Object *obj, ResetType type)
|
||||
{
|
||||
stellaris_i2c_state *s = STELLARIS_I2C(obj);
|
||||
|
||||
|
@ -631,7 +631,7 @@ static void stellaris_i2c_reset_hold(Object *obj)
|
|||
s->mcr = 0;
|
||||
}
|
||||
|
||||
static void stellaris_i2c_reset_exit(Object *obj)
|
||||
static void stellaris_i2c_reset_exit(Object *obj, ResetType type)
|
||||
{
|
||||
stellaris_i2c_state *s = STELLARIS_I2C(obj);
|
||||
|
||||
|
@ -787,7 +787,7 @@ static void stellaris_adc_trigger(void *opaque, int irq, int level)
|
|||
}
|
||||
}
|
||||
|
||||
static void stellaris_adc_reset_hold(Object *obj)
|
||||
static void stellaris_adc_reset_hold(Object *obj, ResetType type)
|
||||
{
|
||||
StellarisADCState *s = STELLARIS_ADC(obj);
|
||||
int n;
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include "sysemu/sysemu.h"
|
||||
#include "hw/or-irq.h"
|
||||
#include "hw/arm/stm32l4x5_soc.h"
|
||||
#include "hw/char/stm32l4x5_usart.h"
|
||||
#include "hw/gpio/stm32l4x5_gpio.h"
|
||||
#include "hw/qdev-clock.h"
|
||||
#include "hw/misc/unimp.h"
|
||||
|
@ -116,6 +117,22 @@ static const struct {
|
|||
{ 0x48001C00, 0x0000000F, 0x00000000, 0x00000000 },
|
||||
};
|
||||
|
||||
static const hwaddr usart_addr[] = {
|
||||
0x40013800, /* "USART1", 0x400 */
|
||||
0x40004400, /* "USART2", 0x400 */
|
||||
0x40004800, /* "USART3", 0x400 */
|
||||
};
|
||||
static const hwaddr uart_addr[] = {
|
||||
0x40004C00, /* "UART4" , 0x400 */
|
||||
0x40005000 /* "UART5" , 0x400 */
|
||||
};
|
||||
|
||||
#define LPUART_BASE_ADDRESS 0x40008000
|
||||
|
||||
static const int usart_irq[] = { 37, 38, 39 };
|
||||
static const int uart_irq[] = { 52, 53 };
|
||||
#define LPUART_IRQ 70
|
||||
|
||||
static void stm32l4x5_soc_initfn(Object *obj)
|
||||
{
|
||||
Stm32l4x5SocState *s = STM32L4X5_SOC(obj);
|
||||
|
@ -132,6 +149,18 @@ static void stm32l4x5_soc_initfn(Object *obj)
|
|||
g_autofree char *name = g_strdup_printf("gpio%c", 'a' + i);
|
||||
object_initialize_child(obj, name, &s->gpio[i], TYPE_STM32L4X5_GPIO);
|
||||
}
|
||||
|
||||
for (int i = 0; i < STM_NUM_USARTS; i++) {
|
||||
object_initialize_child(obj, "usart[*]", &s->usart[i],
|
||||
TYPE_STM32L4X5_USART);
|
||||
}
|
||||
|
||||
for (int i = 0; i < STM_NUM_UARTS; i++) {
|
||||
object_initialize_child(obj, "uart[*]", &s->uart[i],
|
||||
TYPE_STM32L4X5_UART);
|
||||
}
|
||||
object_initialize_child(obj, "lpuart1", &s->lpuart,
|
||||
TYPE_STM32L4X5_LPUART);
|
||||
}
|
||||
|
||||
static void stm32l4x5_soc_realize(DeviceState *dev_soc, Error **errp)
|
||||
|
@ -279,6 +308,54 @@ static void stm32l4x5_soc_realize(DeviceState *dev_soc, Error **errp)
|
|||
sysbus_mmio_map(busdev, 0, RCC_BASE_ADDRESS);
|
||||
sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(armv7m, RCC_IRQ));
|
||||
|
||||
/* USART devices */
|
||||
for (int i = 0; i < STM_NUM_USARTS; i++) {
|
||||
g_autofree char *name = g_strdup_printf("usart%d-out", i + 1);
|
||||
dev = DEVICE(&(s->usart[i]));
|
||||
qdev_prop_set_chr(dev, "chardev", serial_hd(i));
|
||||
qdev_connect_clock_in(dev, "clk",
|
||||
qdev_get_clock_out(DEVICE(&(s->rcc)), name));
|
||||
busdev = SYS_BUS_DEVICE(dev);
|
||||
if (!sysbus_realize(busdev, errp)) {
|
||||
return;
|
||||
}
|
||||
sysbus_mmio_map(busdev, 0, usart_addr[i]);
|
||||
sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(armv7m, usart_irq[i]));
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO: Connect the USARTs, UARTs and LPUART to the EXTI once the EXTI
|
||||
* can handle other gpio-in than the gpios. (e.g. Direct Lines for the
|
||||
* usarts)
|
||||
*/
|
||||
|
||||
/* UART devices */
|
||||
for (int i = 0; i < STM_NUM_UARTS; i++) {
|
||||
g_autofree char *name = g_strdup_printf("uart%d-out", STM_NUM_USARTS + i + 1);
|
||||
dev = DEVICE(&(s->uart[i]));
|
||||
qdev_prop_set_chr(dev, "chardev", serial_hd(STM_NUM_USARTS + i));
|
||||
qdev_connect_clock_in(dev, "clk",
|
||||
qdev_get_clock_out(DEVICE(&(s->rcc)), name));
|
||||
busdev = SYS_BUS_DEVICE(dev);
|
||||
if (!sysbus_realize(busdev, errp)) {
|
||||
return;
|
||||
}
|
||||
sysbus_mmio_map(busdev, 0, uart_addr[i]);
|
||||
sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(armv7m, uart_irq[i]));
|
||||
}
|
||||
|
||||
/* LPUART device*/
|
||||
dev = DEVICE(&(s->lpuart));
|
||||
qdev_prop_set_chr(dev, "chardev", serial_hd(STM_NUM_USARTS + STM_NUM_UARTS));
|
||||
qdev_connect_clock_in(dev, "clk",
|
||||
qdev_get_clock_out(DEVICE(&(s->rcc)), "lpuart1-out"));
|
||||
busdev = SYS_BUS_DEVICE(dev);
|
||||
if (!sysbus_realize(busdev, errp)) {
|
||||
return;
|
||||
}
|
||||
sysbus_mmio_map(busdev, 0, LPUART_BASE_ADDRESS);
|
||||
sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(armv7m, LPUART_IRQ));
|
||||
|
||||
/* APB1 BUS */
|
||||
create_unimplemented_device("TIM2", 0x40000000, 0x400);
|
||||
create_unimplemented_device("TIM3", 0x40000400, 0x400);
|
||||
|
@ -294,10 +371,6 @@ static void stm32l4x5_soc_realize(DeviceState *dev_soc, Error **errp)
|
|||
create_unimplemented_device("SPI2", 0x40003800, 0x400);
|
||||
create_unimplemented_device("SPI3", 0x40003C00, 0x400);
|
||||
/* RESERVED: 0x40004000, 0x400 */
|
||||
create_unimplemented_device("USART2", 0x40004400, 0x400);
|
||||
create_unimplemented_device("USART3", 0x40004800, 0x400);
|
||||
create_unimplemented_device("UART4", 0x40004C00, 0x400);
|
||||
create_unimplemented_device("UART5", 0x40005000, 0x400);
|
||||
create_unimplemented_device("I2C1", 0x40005400, 0x400);
|
||||
create_unimplemented_device("I2C2", 0x40005800, 0x400);
|
||||
create_unimplemented_device("I2C3", 0x40005C00, 0x400);
|
||||
|
@ -308,7 +381,6 @@ static void stm32l4x5_soc_realize(DeviceState *dev_soc, Error **errp)
|
|||
create_unimplemented_device("DAC1", 0x40007400, 0x400);
|
||||
create_unimplemented_device("OPAMP", 0x40007800, 0x400);
|
||||
create_unimplemented_device("LPTIM1", 0x40007C00, 0x400);
|
||||
create_unimplemented_device("LPUART1", 0x40008000, 0x400);
|
||||
/* RESERVED: 0x40008400, 0x400 */
|
||||
create_unimplemented_device("SWPMI1", 0x40008800, 0x400);
|
||||
/* RESERVED: 0x40008C00, 0x800 */
|
||||
|
@ -325,7 +397,6 @@ static void stm32l4x5_soc_realize(DeviceState *dev_soc, Error **errp)
|
|||
create_unimplemented_device("TIM1", 0x40012C00, 0x400);
|
||||
create_unimplemented_device("SPI1", 0x40013000, 0x400);
|
||||
create_unimplemented_device("TIM8", 0x40013400, 0x400);
|
||||
create_unimplemented_device("USART1", 0x40013800, 0x400);
|
||||
/* RESERVED: 0x40013C00, 0x400 */
|
||||
create_unimplemented_device("TIM15", 0x40014000, 0x400);
|
||||
create_unimplemented_device("TIM16", 0x40014400, 0x400);
|
||||
|
|
|
@ -729,6 +729,20 @@ static void create_v2m(VirtMachineState *vms)
|
|||
vms->msi_controller = VIRT_MSI_CTRL_GICV2M;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the CPU has FEAT_NMI, then turn on the NMI support in the GICv3 too.
|
||||
* It's permitted to have a configuration with NMI in the CPU (and thus the
|
||||
* GICv3 CPU interface) but not in the distributor/redistributors, but it's
|
||||
* not very useful.
|
||||
*/
|
||||
static bool gicv3_nmi_present(VirtMachineState *vms)
|
||||
{
|
||||
ARMCPU *cpu = ARM_CPU(qemu_get_cpu(0));
|
||||
|
||||
return tcg_enabled() && cpu_isar_feature(aa64_nmi, cpu) &&
|
||||
(vms->gic_version != VIRT_GIC_VERSION_2);
|
||||
}
|
||||
|
||||
static void create_gic(VirtMachineState *vms, MemoryRegion *mem)
|
||||
{
|
||||
MachineState *ms = MACHINE(vms);
|
||||
|
@ -802,6 +816,11 @@ static void create_gic(VirtMachineState *vms, MemoryRegion *mem)
|
|||
vms->virt);
|
||||
}
|
||||
}
|
||||
|
||||
if (gicv3_nmi_present(vms)) {
|
||||
qdev_prop_set_bit(vms->gic, "has-nmi", true);
|
||||
}
|
||||
|
||||
gicbusdev = SYS_BUS_DEVICE(vms->gic);
|
||||
sysbus_realize_and_unref(gicbusdev, &error_fatal);
|
||||
sysbus_mmio_map(gicbusdev, 0, vms->memmap[VIRT_GIC_DIST].base);
|
||||
|
@ -821,7 +840,8 @@ static void create_gic(VirtMachineState *vms, MemoryRegion *mem)
|
|||
|
||||
/* Wire the outputs from each CPU's generic timer and the GICv3
|
||||
* maintenance interrupt signal to the appropriate GIC PPI inputs,
|
||||
* and the GIC's IRQ/FIQ/VIRQ/VFIQ interrupt outputs to the CPU's inputs.
|
||||
* and the GIC's IRQ/FIQ/VIRQ/VFIQ/NMI/VINMI interrupt outputs to the
|
||||
* CPU's inputs.
|
||||
*/
|
||||
for (i = 0; i < smp_cpus; i++) {
|
||||
DeviceState *cpudev = DEVICE(qemu_get_cpu(i));
|
||||
|
@ -865,6 +885,13 @@ static void create_gic(VirtMachineState *vms, MemoryRegion *mem)
|
|||
qdev_get_gpio_in(cpudev, ARM_CPU_VIRQ));
|
||||
sysbus_connect_irq(gicbusdev, i + 3 * smp_cpus,
|
||||
qdev_get_gpio_in(cpudev, ARM_CPU_VFIQ));
|
||||
|
||||
if (vms->gic_version != VIRT_GIC_VERSION_2) {
|
||||
sysbus_connect_irq(gicbusdev, i + 4 * smp_cpus,
|
||||
qdev_get_gpio_in(cpudev, ARM_CPU_NMI));
|
||||
sysbus_connect_irq(gicbusdev, i + 5 * smp_cpus,
|
||||
qdev_get_gpio_in(cpudev, ARM_CPU_VINMI));
|
||||
}
|
||||
}
|
||||
|
||||
fdt_add_gic_node(vms);
|
||||
|
|
|
@ -610,7 +610,7 @@ static void asc_fifo_init(ASCFIFOState *fs, int index)
|
|||
g_free(name);
|
||||
}
|
||||
|
||||
static void asc_reset_hold(Object *obj)
|
||||
static void asc_reset_hold(Object *obj, ResetType type)
|
||||
{
|
||||
ASCState *s = ASC(obj);
|
||||
|
||||
|
|
|
@ -41,6 +41,9 @@ config VIRTIO_SERIAL
|
|||
config STM32F2XX_USART
|
||||
bool
|
||||
|
||||
config STM32L4X5_USART
|
||||
bool
|
||||
|
||||
config CMSDK_APB_UART
|
||||
bool
|
||||
|
||||
|
|
|
@ -525,7 +525,7 @@ static void cadence_uart_reset_init(Object *obj, ResetType type)
|
|||
s->r[R_TTRIG] = 0x00000020;
|
||||
}
|
||||
|
||||
static void cadence_uart_reset_hold(Object *obj)
|
||||
static void cadence_uart_reset_hold(Object *obj, ResetType type)
|
||||
{
|
||||
CadenceUARTState *s = CADENCE_UART(obj);
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@ system_ss.add(when: 'CONFIG_RENESAS_SCI', if_true: files('renesas_sci.c'))
|
|||
system_ss.add(when: 'CONFIG_SIFIVE_UART', if_true: files('sifive_uart.c'))
|
||||
system_ss.add(when: 'CONFIG_SH_SCI', if_true: files('sh_serial.c'))
|
||||
system_ss.add(when: 'CONFIG_STM32F2XX_USART', if_true: files('stm32f2xx_usart.c'))
|
||||
system_ss.add(when: 'CONFIG_STM32L4X5_USART', if_true: files('stm32l4x5_usart.c'))
|
||||
system_ss.add(when: 'CONFIG_MCHP_PFSOC_MMUART', if_true: files('mchp_pfsoc_mmuart.c'))
|
||||
system_ss.add(when: 'CONFIG_HTIF', if_true: files('riscv_htif.c'))
|
||||
system_ss.add(when: 'CONFIG_GOLDFISH_TTY', if_true: files('goldfish_tty.c'))
|
||||
|
|
|
@ -214,7 +214,7 @@ static void sifive_uart_reset_enter(Object *obj, ResetType type)
|
|||
s->rx_fifo_len = 0;
|
||||
}
|
||||
|
||||
static void sifive_uart_reset_hold(Object *obj)
|
||||
static void sifive_uart_reset_hold(Object *obj, ResetType type)
|
||||
{
|
||||
SiFiveUARTState *s = SIFIVE_UART(obj);
|
||||
qemu_irq_lower(s->irq);
|
||||
|
|
637
hw/char/stm32l4x5_usart.c
Normal file
637
hw/char/stm32l4x5_usart.c
Normal file
|
@ -0,0 +1,637 @@
|
|||
/*
|
||||
* STM32L4X5 USART (Universal Synchronous Asynchronous Receiver Transmitter)
|
||||
*
|
||||
* Copyright (c) 2023 Arnaud Minier <arnaud.minier@telecom-paris.fr>
|
||||
* Copyright (c) 2023 Inès Varhol <ines.varhol@telecom-paris.fr>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*
|
||||
* The STM32L4X5 USART is heavily inspired by the stm32f2xx_usart
|
||||
* by Alistair Francis.
|
||||
* The reference used is the STMicroElectronics RM0351 Reference manual
|
||||
* for STM32L4x5 and STM32L4x6 advanced Arm ® -based 32-bit MCUs.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/log.h"
|
||||
#include "qemu/module.h"
|
||||
#include "qapi/error.h"
|
||||
#include "chardev/char-fe.h"
|
||||
#include "chardev/char-serial.h"
|
||||
#include "migration/vmstate.h"
|
||||
#include "hw/char/stm32l4x5_usart.h"
|
||||
#include "hw/clock.h"
|
||||
#include "hw/irq.h"
|
||||
#include "hw/qdev-clock.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "hw/qdev-properties-system.h"
|
||||
#include "hw/registerfields.h"
|
||||
#include "trace.h"
|
||||
|
||||
|
||||
REG32(CR1, 0x00)
|
||||
FIELD(CR1, M1, 28, 1) /* Word length (part 2, see M0) */
|
||||
FIELD(CR1, EOBIE, 27, 1) /* End of Block interrupt enable */
|
||||
FIELD(CR1, RTOIE, 26, 1) /* Receiver timeout interrupt enable */
|
||||
FIELD(CR1, DEAT, 21, 5) /* Driver Enable assertion time */
|
||||
FIELD(CR1, DEDT, 16, 5) /* Driver Enable de-assertion time */
|
||||
FIELD(CR1, OVER8, 15, 1) /* Oversampling mode */
|
||||
FIELD(CR1, CMIE, 14, 1) /* Character match interrupt enable */
|
||||
FIELD(CR1, MME, 13, 1) /* Mute mode enable */
|
||||
FIELD(CR1, M0, 12, 1) /* Word length (part 1, see M1) */
|
||||
FIELD(CR1, WAKE, 11, 1) /* Receiver wakeup method */
|
||||
FIELD(CR1, PCE, 10, 1) /* Parity control enable */
|
||||
FIELD(CR1, PS, 9, 1) /* Parity selection */
|
||||
FIELD(CR1, PEIE, 8, 1) /* PE interrupt enable */
|
||||
FIELD(CR1, TXEIE, 7, 1) /* TXE interrupt enable */
|
||||
FIELD(CR1, TCIE, 6, 1) /* Transmission complete interrupt enable */
|
||||
FIELD(CR1, RXNEIE, 5, 1) /* RXNE interrupt enable */
|
||||
FIELD(CR1, IDLEIE, 4, 1) /* IDLE interrupt enable */
|
||||
FIELD(CR1, TE, 3, 1) /* Transmitter enable */
|
||||
FIELD(CR1, RE, 2, 1) /* Receiver enable */
|
||||
FIELD(CR1, UESM, 1, 1) /* USART enable in Stop mode */
|
||||
FIELD(CR1, UE, 0, 1) /* USART enable */
|
||||
REG32(CR2, 0x04)
|
||||
FIELD(CR2, ADD_1, 28, 4) /* ADD[7:4] */
|
||||
FIELD(CR2, ADD_0, 24, 1) /* ADD[3:0] */
|
||||
FIELD(CR2, RTOEN, 23, 1) /* Receiver timeout enable */
|
||||
FIELD(CR2, ABRMOD, 21, 2) /* Auto baud rate mode */
|
||||
FIELD(CR2, ABREN, 20, 1) /* Auto baud rate enable */
|
||||
FIELD(CR2, MSBFIRST, 19, 1) /* Most significant bit first */
|
||||
FIELD(CR2, DATAINV, 18, 1) /* Binary data inversion */
|
||||
FIELD(CR2, TXINV, 17, 1) /* TX pin active level inversion */
|
||||
FIELD(CR2, RXINV, 16, 1) /* RX pin active level inversion */
|
||||
FIELD(CR2, SWAP, 15, 1) /* Swap RX/TX pins */
|
||||
FIELD(CR2, LINEN, 14, 1) /* LIN mode enable */
|
||||
FIELD(CR2, STOP, 12, 2) /* STOP bits */
|
||||
FIELD(CR2, CLKEN, 11, 1) /* Clock enable */
|
||||
FIELD(CR2, CPOL, 10, 1) /* Clock polarity */
|
||||
FIELD(CR2, CPHA, 9, 1) /* Clock phase */
|
||||
FIELD(CR2, LBCL, 8, 1) /* Last bit clock pulse */
|
||||
FIELD(CR2, LBDIE, 6, 1) /* LIN break detection interrupt enable */
|
||||
FIELD(CR2, LBDL, 5, 1) /* LIN break detection length */
|
||||
FIELD(CR2, ADDM7, 4, 1) /* 7-bit / 4-bit Address Detection */
|
||||
|
||||
REG32(CR3, 0x08)
|
||||
/* TCBGTIE only on STM32L496xx/4A6xx devices */
|
||||
FIELD(CR3, UCESM, 23, 1) /* USART Clock Enable in Stop Mode */
|
||||
FIELD(CR3, WUFIE, 22, 1) /* Wakeup from Stop mode interrupt enable */
|
||||
FIELD(CR3, WUS, 20, 2) /* Wakeup from Stop mode interrupt flag selection */
|
||||
FIELD(CR3, SCARCNT, 17, 3) /* Smartcard auto-retry count */
|
||||
FIELD(CR3, DEP, 15, 1) /* Driver enable polarity selection */
|
||||
FIELD(CR3, DEM, 14, 1) /* Driver enable mode */
|
||||
FIELD(CR3, DDRE, 13, 1) /* DMA Disable on Reception Error */
|
||||
FIELD(CR3, OVRDIS, 12, 1) /* Overrun Disable */
|
||||
FIELD(CR3, ONEBIT, 11, 1) /* One sample bit method enable */
|
||||
FIELD(CR3, CTSIE, 10, 1) /* CTS interrupt enable */
|
||||
FIELD(CR3, CTSE, 9, 1) /* CTS enable */
|
||||
FIELD(CR3, RTSE, 8, 1) /* RTS enable */
|
||||
FIELD(CR3, DMAT, 7, 1) /* DMA enable transmitter */
|
||||
FIELD(CR3, DMAR, 6, 1) /* DMA enable receiver */
|
||||
FIELD(CR3, SCEN, 5, 1) /* Smartcard mode enable */
|
||||
FIELD(CR3, NACK, 4, 1) /* Smartcard NACK enable */
|
||||
FIELD(CR3, HDSEL, 3, 1) /* Half-duplex selection */
|
||||
FIELD(CR3, IRLP, 2, 1) /* IrDA low-power */
|
||||
FIELD(CR3, IREN, 1, 1) /* IrDA mode enable */
|
||||
FIELD(CR3, EIE, 0, 1) /* Error interrupt enable */
|
||||
REG32(BRR, 0x0C)
|
||||
FIELD(BRR, BRR, 0, 16)
|
||||
REG32(GTPR, 0x10)
|
||||
FIELD(GTPR, GT, 8, 8) /* Guard time value */
|
||||
FIELD(GTPR, PSC, 0, 8) /* Prescaler value */
|
||||
REG32(RTOR, 0x14)
|
||||
FIELD(RTOR, BLEN, 24, 8) /* Block Length */
|
||||
FIELD(RTOR, RTO, 0, 24) /* Receiver timeout value */
|
||||
REG32(RQR, 0x18)
|
||||
FIELD(RQR, TXFRQ, 4, 1) /* Transmit data flush request */
|
||||
FIELD(RQR, RXFRQ, 3, 1) /* Receive data flush request */
|
||||
FIELD(RQR, MMRQ, 2, 1) /* Mute mode request */
|
||||
FIELD(RQR, SBKRQ, 1, 1) /* Send break request */
|
||||
FIELD(RQR, ABBRRQ, 0, 1) /* Auto baud rate request */
|
||||
REG32(ISR, 0x1C)
|
||||
/* TCBGT only for STM32L475xx/476xx/486xx devices */
|
||||
FIELD(ISR, REACK, 22, 1) /* Receive enable acknowledge flag */
|
||||
FIELD(ISR, TEACK, 21, 1) /* Transmit enable acknowledge flag */
|
||||
FIELD(ISR, WUF, 20, 1) /* Wakeup from Stop mode flag */
|
||||
FIELD(ISR, RWU, 19, 1) /* Receiver wakeup from Mute mode */
|
||||
FIELD(ISR, SBKF, 18, 1) /* Send break flag */
|
||||
FIELD(ISR, CMF, 17, 1) /* Character match flag */
|
||||
FIELD(ISR, BUSY, 16, 1) /* Busy flag */
|
||||
FIELD(ISR, ABRF, 15, 1) /* Auto Baud rate flag */
|
||||
FIELD(ISR, ABRE, 14, 1) /* Auto Baud rate error */
|
||||
FIELD(ISR, EOBF, 12, 1) /* End of block flag */
|
||||
FIELD(ISR, RTOF, 11, 1) /* Receiver timeout */
|
||||
FIELD(ISR, CTS, 10, 1) /* CTS flag */
|
||||
FIELD(ISR, CTSIF, 9, 1) /* CTS interrupt flag */
|
||||
FIELD(ISR, LBDF, 8, 1) /* LIN break detection flag */
|
||||
FIELD(ISR, TXE, 7, 1) /* Transmit data register empty */
|
||||
FIELD(ISR, TC, 6, 1) /* Transmission complete */
|
||||
FIELD(ISR, RXNE, 5, 1) /* Read data register not empty */
|
||||
FIELD(ISR, IDLE, 4, 1) /* Idle line detected */
|
||||
FIELD(ISR, ORE, 3, 1) /* Overrun error */
|
||||
FIELD(ISR, NF, 2, 1) /* START bit Noise detection flag */
|
||||
FIELD(ISR, FE, 1, 1) /* Framing Error */
|
||||
FIELD(ISR, PE, 0, 1) /* Parity Error */
|
||||
REG32(ICR, 0x20)
|
||||
FIELD(ICR, WUCF, 20, 1) /* Wakeup from Stop mode clear flag */
|
||||
FIELD(ICR, CMCF, 17, 1) /* Character match clear flag */
|
||||
FIELD(ICR, EOBCF, 12, 1) /* End of block clear flag */
|
||||
FIELD(ICR, RTOCF, 11, 1) /* Receiver timeout clear flag */
|
||||
FIELD(ICR, CTSCF, 9, 1) /* CTS clear flag */
|
||||
FIELD(ICR, LBDCF, 8, 1) /* LIN break detection clear flag */
|
||||
/* TCBGTCF only on STM32L496xx/4A6xx devices */
|
||||
FIELD(ICR, TCCF, 6, 1) /* Transmission complete clear flag */
|
||||
FIELD(ICR, IDLECF, 4, 1) /* Idle line detected clear flag */
|
||||
FIELD(ICR, ORECF, 3, 1) /* Overrun error clear flag */
|
||||
FIELD(ICR, NCF, 2, 1) /* Noise detected clear flag */
|
||||
FIELD(ICR, FECF, 1, 1) /* Framing error clear flag */
|
||||
FIELD(ICR, PECF, 0, 1) /* Parity error clear flag */
|
||||
REG32(RDR, 0x24)
|
||||
FIELD(RDR, RDR, 0, 9)
|
||||
REG32(TDR, 0x28)
|
||||
FIELD(TDR, TDR, 0, 9)
|
||||
|
||||
static void stm32l4x5_update_irq(Stm32l4x5UsartBaseState *s)
|
||||
{
|
||||
if (((s->isr & R_ISR_WUF_MASK) && (s->cr3 & R_CR3_WUFIE_MASK)) ||
|
||||
((s->isr & R_ISR_CMF_MASK) && (s->cr1 & R_CR1_CMIE_MASK)) ||
|
||||
((s->isr & R_ISR_ABRF_MASK) && (s->cr1 & R_CR1_RXNEIE_MASK)) ||
|
||||
((s->isr & R_ISR_EOBF_MASK) && (s->cr1 & R_CR1_EOBIE_MASK)) ||
|
||||
((s->isr & R_ISR_RTOF_MASK) && (s->cr1 & R_CR1_RTOIE_MASK)) ||
|
||||
((s->isr & R_ISR_CTSIF_MASK) && (s->cr3 & R_CR3_CTSIE_MASK)) ||
|
||||
((s->isr & R_ISR_LBDF_MASK) && (s->cr2 & R_CR2_LBDIE_MASK)) ||
|
||||
((s->isr & R_ISR_TXE_MASK) && (s->cr1 & R_CR1_TXEIE_MASK)) ||
|
||||
((s->isr & R_ISR_TC_MASK) && (s->cr1 & R_CR1_TCIE_MASK)) ||
|
||||
((s->isr & R_ISR_RXNE_MASK) && (s->cr1 & R_CR1_RXNEIE_MASK)) ||
|
||||
((s->isr & R_ISR_IDLE_MASK) && (s->cr1 & R_CR1_IDLEIE_MASK)) ||
|
||||
((s->isr & R_ISR_ORE_MASK) &&
|
||||
((s->cr1 & R_CR1_RXNEIE_MASK) || (s->cr3 & R_CR3_EIE_MASK))) ||
|
||||
/* TODO: Handle NF ? */
|
||||
((s->isr & R_ISR_FE_MASK) && (s->cr3 & R_CR3_EIE_MASK)) ||
|
||||
((s->isr & R_ISR_PE_MASK) && (s->cr1 & R_CR1_PEIE_MASK))) {
|
||||
qemu_irq_raise(s->irq);
|
||||
trace_stm32l4x5_usart_irq_raised(s->isr);
|
||||
} else {
|
||||
qemu_irq_lower(s->irq);
|
||||
trace_stm32l4x5_usart_irq_lowered();
|
||||
}
|
||||
}
|
||||
|
||||
static int stm32l4x5_usart_base_can_receive(void *opaque)
|
||||
{
|
||||
Stm32l4x5UsartBaseState *s = opaque;
|
||||
|
||||
if (!(s->isr & R_ISR_RXNE_MASK)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void stm32l4x5_usart_base_receive(void *opaque, const uint8_t *buf,
|
||||
int size)
|
||||
{
|
||||
Stm32l4x5UsartBaseState *s = opaque;
|
||||
|
||||
if (!((s->cr1 & R_CR1_UE_MASK) && (s->cr1 & R_CR1_RE_MASK))) {
|
||||
trace_stm32l4x5_usart_receiver_not_enabled(
|
||||
FIELD_EX32(s->cr1, CR1, UE), FIELD_EX32(s->cr1, CR1, RE));
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check if overrun detection is enabled and if there is an overrun */
|
||||
if (!(s->cr3 & R_CR3_OVRDIS_MASK) && (s->isr & R_ISR_RXNE_MASK)) {
|
||||
/*
|
||||
* A character has been received while
|
||||
* the previous has not been read = Overrun.
|
||||
*/
|
||||
s->isr |= R_ISR_ORE_MASK;
|
||||
trace_stm32l4x5_usart_overrun_detected(s->rdr, *buf);
|
||||
} else {
|
||||
/* No overrun */
|
||||
s->rdr = *buf;
|
||||
s->isr |= R_ISR_RXNE_MASK;
|
||||
trace_stm32l4x5_usart_rx(s->rdr);
|
||||
}
|
||||
|
||||
stm32l4x5_update_irq(s);
|
||||
}
|
||||
|
||||
/*
|
||||
* Try to send tx data, and arrange to be called back later if
|
||||
* we can't (ie the char backend is busy/blocking).
|
||||
*/
|
||||
static gboolean usart_transmit(void *do_not_use, GIOCondition cond,
|
||||
void *opaque)
|
||||
{
|
||||
Stm32l4x5UsartBaseState *s = STM32L4X5_USART_BASE(opaque);
|
||||
int ret;
|
||||
/* TODO: Handle 9 bits transmission */
|
||||
uint8_t ch = s->tdr;
|
||||
|
||||
s->watch_tag = 0;
|
||||
|
||||
if (!(s->cr1 & R_CR1_TE_MASK) || (s->isr & R_ISR_TXE_MASK)) {
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
ret = qemu_chr_fe_write(&s->chr, &ch, 1);
|
||||
if (ret <= 0) {
|
||||
s->watch_tag = qemu_chr_fe_add_watch(&s->chr, G_IO_OUT | G_IO_HUP,
|
||||
usart_transmit, s);
|
||||
if (!s->watch_tag) {
|
||||
/*
|
||||
* Most common reason to be here is "no chardev backend":
|
||||
* just insta-drain the buffer, so the serial output
|
||||
* goes into a void, rather than blocking the guest.
|
||||
*/
|
||||
goto buffer_drained;
|
||||
}
|
||||
/* Transmit pending */
|
||||
trace_stm32l4x5_usart_tx_pending();
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
buffer_drained:
|
||||
/* Character successfully sent */
|
||||
trace_stm32l4x5_usart_tx(ch);
|
||||
s->isr |= R_ISR_TC_MASK | R_ISR_TXE_MASK;
|
||||
stm32l4x5_update_irq(s);
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static void usart_cancel_transmit(Stm32l4x5UsartBaseState *s)
|
||||
{
|
||||
if (s->watch_tag) {
|
||||
g_source_remove(s->watch_tag);
|
||||
s->watch_tag = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void stm32l4x5_update_params(Stm32l4x5UsartBaseState *s)
|
||||
{
|
||||
int speed, parity, data_bits, stop_bits;
|
||||
uint32_t value, usart_div;
|
||||
QEMUSerialSetParams ssp;
|
||||
|
||||
/* Select the parity type */
|
||||
if (s->cr1 & R_CR1_PCE_MASK) {
|
||||
if (s->cr1 & R_CR1_PS_MASK) {
|
||||
parity = 'O';
|
||||
} else {
|
||||
parity = 'E';
|
||||
}
|
||||
} else {
|
||||
parity = 'N';
|
||||
}
|
||||
|
||||
/* Select the number of stop bits */
|
||||
switch (FIELD_EX32(s->cr2, CR2, STOP)) {
|
||||
case 0:
|
||||
stop_bits = 1;
|
||||
break;
|
||||
case 2:
|
||||
stop_bits = 2;
|
||||
break;
|
||||
default:
|
||||
qemu_log_mask(LOG_UNIMP,
|
||||
"UNIMPLEMENTED: fractionnal stop bits; CR2[13:12] = %u",
|
||||
FIELD_EX32(s->cr2, CR2, STOP));
|
||||
return;
|
||||
}
|
||||
|
||||
/* Select the length of the word */
|
||||
switch ((FIELD_EX32(s->cr1, CR1, M1) << 1) | FIELD_EX32(s->cr1, CR1, M0)) {
|
||||
case 0:
|
||||
data_bits = 8;
|
||||
break;
|
||||
case 1:
|
||||
data_bits = 9;
|
||||
break;
|
||||
case 2:
|
||||
data_bits = 7;
|
||||
break;
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"UNDEFINED: invalid word length, CR1.M = 0b11");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Select the baud rate */
|
||||
value = FIELD_EX32(s->brr, BRR, BRR);
|
||||
if (value < 16) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"UNDEFINED: BRR less than 16: %u", value);
|
||||
return;
|
||||
}
|
||||
|
||||
if (FIELD_EX32(s->cr1, CR1, OVER8) == 0) {
|
||||
/*
|
||||
* Oversampling by 16
|
||||
* BRR = USARTDIV
|
||||
*/
|
||||
usart_div = value;
|
||||
} else {
|
||||
/*
|
||||
* Oversampling by 8
|
||||
* - BRR[2:0] = USARTDIV[3:0] shifted 1 bit to the right.
|
||||
* - BRR[3] must be kept cleared.
|
||||
* - BRR[15:4] = USARTDIV[15:4]
|
||||
* - The frequency is multiplied by 2
|
||||
*/
|
||||
usart_div = ((value & 0xFFF0) | ((value & 0x0007) << 1)) / 2;
|
||||
}
|
||||
|
||||
speed = clock_get_hz(s->clk) / usart_div;
|
||||
|
||||
ssp.speed = speed;
|
||||
ssp.parity = parity;
|
||||
ssp.data_bits = data_bits;
|
||||
ssp.stop_bits = stop_bits;
|
||||
|
||||
qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
|
||||
|
||||
trace_stm32l4x5_usart_update_params(speed, parity, data_bits, stop_bits);
|
||||
}
|
||||
|
||||
static void stm32l4x5_usart_base_reset_hold(Object *obj, ResetType type)
|
||||
{
|
||||
Stm32l4x5UsartBaseState *s = STM32L4X5_USART_BASE(obj);
|
||||
|
||||
s->cr1 = 0x00000000;
|
||||
s->cr2 = 0x00000000;
|
||||
s->cr3 = 0x00000000;
|
||||
s->brr = 0x00000000;
|
||||
s->gtpr = 0x00000000;
|
||||
s->rtor = 0x00000000;
|
||||
s->isr = 0x020000C0;
|
||||
s->rdr = 0x00000000;
|
||||
s->tdr = 0x00000000;
|
||||
|
||||
usart_cancel_transmit(s);
|
||||
stm32l4x5_update_irq(s);
|
||||
}
|
||||
|
||||
static void usart_update_rqr(Stm32l4x5UsartBaseState *s, uint32_t value)
|
||||
{
|
||||
/* TXFRQ */
|
||||
/* Reset RXNE flag */
|
||||
if (value & R_RQR_RXFRQ_MASK) {
|
||||
s->isr &= ~R_ISR_RXNE_MASK;
|
||||
}
|
||||
/* MMRQ */
|
||||
/* SBKRQ */
|
||||
/* ABRRQ */
|
||||
stm32l4x5_update_irq(s);
|
||||
}
|
||||
|
||||
static uint64_t stm32l4x5_usart_base_read(void *opaque, hwaddr addr,
|
||||
unsigned int size)
|
||||
{
|
||||
Stm32l4x5UsartBaseState *s = opaque;
|
||||
uint64_t retvalue = 0;
|
||||
|
||||
switch (addr) {
|
||||
case A_CR1:
|
||||
retvalue = s->cr1;
|
||||
break;
|
||||
case A_CR2:
|
||||
retvalue = s->cr2;
|
||||
break;
|
||||
case A_CR3:
|
||||
retvalue = s->cr3;
|
||||
break;
|
||||
case A_BRR:
|
||||
retvalue = FIELD_EX32(s->brr, BRR, BRR);
|
||||
break;
|
||||
case A_GTPR:
|
||||
retvalue = s->gtpr;
|
||||
break;
|
||||
case A_RTOR:
|
||||
retvalue = s->rtor;
|
||||
break;
|
||||
case A_RQR:
|
||||
/* RQR is a write only register */
|
||||
retvalue = 0x00000000;
|
||||
break;
|
||||
case A_ISR:
|
||||
retvalue = s->isr;
|
||||
break;
|
||||
case A_ICR:
|
||||
/* ICR is a clear register */
|
||||
retvalue = 0x00000000;
|
||||
break;
|
||||
case A_RDR:
|
||||
retvalue = FIELD_EX32(s->rdr, RDR, RDR);
|
||||
/* Reset RXNE flag */
|
||||
s->isr &= ~R_ISR_RXNE_MASK;
|
||||
stm32l4x5_update_irq(s);
|
||||
break;
|
||||
case A_TDR:
|
||||
retvalue = FIELD_EX32(s->tdr, TDR, TDR);
|
||||
break;
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr);
|
||||
break;
|
||||
}
|
||||
|
||||
trace_stm32l4x5_usart_read(addr, retvalue);
|
||||
|
||||
return retvalue;
|
||||
}
|
||||
|
||||
static void stm32l4x5_usart_base_write(void *opaque, hwaddr addr,
|
||||
uint64_t val64, unsigned int size)
|
||||
{
|
||||
Stm32l4x5UsartBaseState *s = opaque;
|
||||
const uint32_t value = val64;
|
||||
|
||||
trace_stm32l4x5_usart_write(addr, value);
|
||||
|
||||
switch (addr) {
|
||||
case A_CR1:
|
||||
s->cr1 = value;
|
||||
stm32l4x5_update_params(s);
|
||||
stm32l4x5_update_irq(s);
|
||||
return;
|
||||
case A_CR2:
|
||||
s->cr2 = value;
|
||||
stm32l4x5_update_params(s);
|
||||
return;
|
||||
case A_CR3:
|
||||
s->cr3 = value;
|
||||
return;
|
||||
case A_BRR:
|
||||
s->brr = value;
|
||||
stm32l4x5_update_params(s);
|
||||
return;
|
||||
case A_GTPR:
|
||||
s->gtpr = value;
|
||||
return;
|
||||
case A_RTOR:
|
||||
s->rtor = value;
|
||||
return;
|
||||
case A_RQR:
|
||||
usart_update_rqr(s, value);
|
||||
return;
|
||||
case A_ISR:
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: ISR is read only !\n", __func__);
|
||||
return;
|
||||
case A_ICR:
|
||||
/* Clear the status flags */
|
||||
s->isr &= ~value;
|
||||
stm32l4x5_update_irq(s);
|
||||
return;
|
||||
case A_RDR:
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: RDR is read only !\n", __func__);
|
||||
return;
|
||||
case A_TDR:
|
||||
s->tdr = value;
|
||||
s->isr &= ~R_ISR_TXE_MASK;
|
||||
usart_transmit(NULL, G_IO_OUT, s);
|
||||
return;
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr);
|
||||
}
|
||||
}
|
||||
|
||||
static const MemoryRegionOps stm32l4x5_usart_base_ops = {
|
||||
.read = stm32l4x5_usart_base_read,
|
||||
.write = stm32l4x5_usart_base_write,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
.valid = {
|
||||
.max_access_size = 4,
|
||||
.min_access_size = 4,
|
||||
.unaligned = false
|
||||
},
|
||||
.impl = {
|
||||
.max_access_size = 4,
|
||||
.min_access_size = 4,
|
||||
.unaligned = false
|
||||
},
|
||||
};
|
||||
|
||||
static Property stm32l4x5_usart_base_properties[] = {
|
||||
DEFINE_PROP_CHR("chardev", Stm32l4x5UsartBaseState, chr),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void stm32l4x5_usart_base_init(Object *obj)
|
||||
{
|
||||
Stm32l4x5UsartBaseState *s = STM32L4X5_USART_BASE(obj);
|
||||
|
||||
sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq);
|
||||
|
||||
memory_region_init_io(&s->mmio, obj, &stm32l4x5_usart_base_ops, s,
|
||||
TYPE_STM32L4X5_USART_BASE, 0x400);
|
||||
sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
|
||||
|
||||
s->clk = qdev_init_clock_in(DEVICE(s), "clk", NULL, s, 0);
|
||||
}
|
||||
|
||||
static int stm32l4x5_usart_base_post_load(void *opaque, int version_id)
|
||||
{
|
||||
Stm32l4x5UsartBaseState *s = (Stm32l4x5UsartBaseState *)opaque;
|
||||
|
||||
stm32l4x5_update_params(s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_stm32l4x5_usart_base = {
|
||||
.name = TYPE_STM32L4X5_USART_BASE,
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.post_load = stm32l4x5_usart_base_post_load,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32(cr1, Stm32l4x5UsartBaseState),
|
||||
VMSTATE_UINT32(cr2, Stm32l4x5UsartBaseState),
|
||||
VMSTATE_UINT32(cr3, Stm32l4x5UsartBaseState),
|
||||
VMSTATE_UINT32(brr, Stm32l4x5UsartBaseState),
|
||||
VMSTATE_UINT32(gtpr, Stm32l4x5UsartBaseState),
|
||||
VMSTATE_UINT32(rtor, Stm32l4x5UsartBaseState),
|
||||
VMSTATE_UINT32(isr, Stm32l4x5UsartBaseState),
|
||||
VMSTATE_UINT32(rdr, Stm32l4x5UsartBaseState),
|
||||
VMSTATE_UINT32(tdr, Stm32l4x5UsartBaseState),
|
||||
VMSTATE_CLOCK(clk, Stm32l4x5UsartBaseState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
static void stm32l4x5_usart_base_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
ERRP_GUARD();
|
||||
Stm32l4x5UsartBaseState *s = STM32L4X5_USART_BASE(dev);
|
||||
if (!clock_has_source(s->clk)) {
|
||||
error_setg(errp, "USART clock must be wired up by SoC code");
|
||||
return;
|
||||
}
|
||||
|
||||
qemu_chr_fe_set_handlers(&s->chr, stm32l4x5_usart_base_can_receive,
|
||||
stm32l4x5_usart_base_receive, NULL, NULL,
|
||||
s, NULL, true);
|
||||
}
|
||||
|
||||
static void stm32l4x5_usart_base_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
ResettableClass *rc = RESETTABLE_CLASS(klass);
|
||||
|
||||
rc->phases.hold = stm32l4x5_usart_base_reset_hold;
|
||||
device_class_set_props(dc, stm32l4x5_usart_base_properties);
|
||||
dc->realize = stm32l4x5_usart_base_realize;
|
||||
dc->vmsd = &vmstate_stm32l4x5_usart_base;
|
||||
}
|
||||
|
||||
static void stm32l4x5_usart_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
Stm32l4x5UsartBaseClass *subc = STM32L4X5_USART_BASE_CLASS(oc);
|
||||
|
||||
subc->type = STM32L4x5_USART;
|
||||
}
|
||||
|
||||
static void stm32l4x5_uart_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
Stm32l4x5UsartBaseClass *subc = STM32L4X5_USART_BASE_CLASS(oc);
|
||||
|
||||
subc->type = STM32L4x5_UART;
|
||||
}
|
||||
|
||||
static void stm32l4x5_lpuart_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
Stm32l4x5UsartBaseClass *subc = STM32L4X5_USART_BASE_CLASS(oc);
|
||||
|
||||
subc->type = STM32L4x5_LPUART;
|
||||
}
|
||||
|
||||
static const TypeInfo stm32l4x5_usart_types[] = {
|
||||
{
|
||||
.name = TYPE_STM32L4X5_USART_BASE,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(Stm32l4x5UsartBaseState),
|
||||
.instance_init = stm32l4x5_usart_base_init,
|
||||
.class_init = stm32l4x5_usart_base_class_init,
|
||||
.abstract = true,
|
||||
}, {
|
||||
.name = TYPE_STM32L4X5_USART,
|
||||
.parent = TYPE_STM32L4X5_USART_BASE,
|
||||
.class_init = stm32l4x5_usart_class_init,
|
||||
}, {
|
||||
.name = TYPE_STM32L4X5_UART,
|
||||
.parent = TYPE_STM32L4X5_USART_BASE,
|
||||
.class_init = stm32l4x5_uart_class_init,
|
||||
}, {
|
||||
.name = TYPE_STM32L4X5_LPUART,
|
||||
.parent = TYPE_STM32L4X5_USART_BASE,
|
||||
.class_init = stm32l4x5_lpuart_class_init,
|
||||
}
|
||||
};
|
||||
|
||||
DEFINE_TYPES(stm32l4x5_usart_types)
|
|
@ -106,6 +106,18 @@ cadence_uart_baudrate(unsigned baudrate) "baudrate %u"
|
|||
sh_serial_read(char *id, unsigned size, uint64_t offs, uint64_t val) " %s size %d offs 0x%02" PRIx64 " -> 0x%02" PRIx64
|
||||
sh_serial_write(char *id, unsigned size, uint64_t offs, uint64_t val) "%s size %d offs 0x%02" PRIx64 " <- 0x%02" PRIx64
|
||||
|
||||
# stm32l4x5_usart.c
|
||||
stm32l4x5_usart_read(uint64_t addr, uint32_t data) "USART: Read <0x%" PRIx64 "> -> 0x%" PRIx32 ""
|
||||
stm32l4x5_usart_write(uint64_t addr, uint32_t data) "USART: Write <0x%" PRIx64 "> <- 0x%" PRIx32 ""
|
||||
stm32l4x5_usart_rx(uint8_t c) "USART: got character 0x%x from backend"
|
||||
stm32l4x5_usart_tx(uint8_t c) "USART: character 0x%x sent to backend"
|
||||
stm32l4x5_usart_tx_pending(void) "USART: character send to backend pending"
|
||||
stm32l4x5_usart_irq_raised(uint32_t reg) "USART: IRQ raised: 0x%08"PRIx32
|
||||
stm32l4x5_usart_irq_lowered(void) "USART: IRQ lowered"
|
||||
stm32l4x5_usart_overrun_detected(uint8_t current, uint8_t received) "USART: Overrun detected, RDR='0x%x', received 0x%x"
|
||||
stm32l4x5_usart_receiver_not_enabled(uint8_t ue_bit, uint8_t re_bit) "USART: Receiver not enabled, UE=0x%x, RE=0x%x"
|
||||
stm32l4x5_usart_update_params(int speed, uint8_t parity, int data, int stop) "USART: speed: %d, parity: %c, data bits: %d, stop bits: %d"
|
||||
|
||||
# xen_console.c
|
||||
xen_console_connect(unsigned int idx, unsigned int ring_ref, unsigned int port, unsigned int limit) "idx %u ring_ref %u port %u limit %u"
|
||||
xen_console_disconnect(unsigned int idx) "idx %u"
|
||||
|
|
|
@ -113,7 +113,7 @@ void cpu_reset(CPUState *cpu)
|
|||
trace_cpu_reset(cpu->cpu_index);
|
||||
}
|
||||
|
||||
static void cpu_common_reset_hold(Object *obj)
|
||||
static void cpu_common_reset_hold(Object *obj, ResetType type)
|
||||
{
|
||||
CPUState *cpu = CPU(obj);
|
||||
CPUClass *cc = CPU_GET_CLASS(cpu);
|
||||
|
|
|
@ -760,10 +760,10 @@ static void device_phases_reset(DeviceState *dev)
|
|||
rc->phases.enter(OBJECT(dev), RESET_TYPE_COLD);
|
||||
}
|
||||
if (rc->phases.hold) {
|
||||
rc->phases.hold(OBJECT(dev));
|
||||
rc->phases.hold(OBJECT(dev), RESET_TYPE_COLD);
|
||||
}
|
||||
if (rc->phases.exit) {
|
||||
rc->phases.exit(OBJECT(dev));
|
||||
rc->phases.exit(OBJECT(dev), RESET_TYPE_COLD);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -43,13 +43,6 @@ static ResettableContainer *get_root_reset_container(void)
|
|||
return root_reset_container;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reason why the currently in-progress qemu_devices_reset() was called.
|
||||
* If we made at least SHUTDOWN_CAUSE_SNAPSHOT_LOAD have a corresponding
|
||||
* ResetType we could perhaps avoid the need for this global.
|
||||
*/
|
||||
static ShutdownCause device_reset_reason;
|
||||
|
||||
/*
|
||||
* This is an Object which implements Resettable simply to call the
|
||||
* callback function in the hold phase.
|
||||
|
@ -73,12 +66,11 @@ static ResettableState *legacy_reset_get_state(Object *obj)
|
|||
return &lr->reset_state;
|
||||
}
|
||||
|
||||
static void legacy_reset_hold(Object *obj)
|
||||
static void legacy_reset_hold(Object *obj, ResetType type)
|
||||
{
|
||||
LegacyReset *lr = LEGACY_RESET(obj);
|
||||
|
||||
if (device_reset_reason == SHUTDOWN_CAUSE_SNAPSHOT_LOAD &&
|
||||
lr->skip_on_snapshot_load) {
|
||||
if (type == RESET_TYPE_SNAPSHOT_LOAD && lr->skip_on_snapshot_load) {
|
||||
return;
|
||||
}
|
||||
lr->func(lr->opaque);
|
||||
|
@ -180,8 +172,9 @@ void qemu_unregister_resettable(Object *obj)
|
|||
|
||||
void qemu_devices_reset(ShutdownCause reason)
|
||||
{
|
||||
device_reset_reason = reason;
|
||||
ResetType type = (reason == SHUTDOWN_CAUSE_SNAPSHOT_LOAD) ?
|
||||
RESET_TYPE_SNAPSHOT_LOAD : RESET_TYPE_COLD;
|
||||
|
||||
/* Reset the simulation */
|
||||
resettable_reset(OBJECT(get_root_reset_container()), RESET_TYPE_COLD);
|
||||
resettable_reset(OBJECT(get_root_reset_container()), type);
|
||||
}
|
||||
|
|
|
@ -48,8 +48,6 @@ void resettable_reset(Object *obj, ResetType type)
|
|||
|
||||
void resettable_assert_reset(Object *obj, ResetType type)
|
||||
{
|
||||
/* TODO: change this assert when adding support for other reset types */
|
||||
assert(type == RESET_TYPE_COLD);
|
||||
trace_resettable_reset_assert_begin(obj, type);
|
||||
assert(!enter_phase_in_progress);
|
||||
|
||||
|
@ -64,8 +62,6 @@ void resettable_assert_reset(Object *obj, ResetType type)
|
|||
|
||||
void resettable_release_reset(Object *obj, ResetType type)
|
||||
{
|
||||
/* TODO: change this assert when adding support for other reset types */
|
||||
assert(type == RESET_TYPE_COLD);
|
||||
trace_resettable_reset_release_begin(obj, type);
|
||||
assert(!enter_phase_in_progress);
|
||||
|
||||
|
@ -181,7 +177,7 @@ static void resettable_phase_hold(Object *obj, void *opaque, ResetType type)
|
|||
trace_resettable_transitional_function(obj, obj_typename);
|
||||
tr_func(obj);
|
||||
} else if (rc->phases.hold) {
|
||||
rc->phases.hold(obj);
|
||||
rc->phases.hold(obj, type);
|
||||
}
|
||||
}
|
||||
trace_resettable_phase_hold_end(obj, obj_typename, s->count);
|
||||
|
@ -204,7 +200,7 @@ static void resettable_phase_exit(Object *obj, void *opaque, ResetType type)
|
|||
if (--s->count == 0) {
|
||||
trace_resettable_phase_exit_exec(obj, obj_typename, !!rc->phases.exit);
|
||||
if (rc->phases.exit && !resettable_get_tr_func(rc, obj)) {
|
||||
rc->phases.exit(obj);
|
||||
rc->phases.exit(obj, type);
|
||||
}
|
||||
}
|
||||
s->exit_phase_in_progress = false;
|
||||
|
|
|
@ -180,14 +180,14 @@ static void virtio_vga_base_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
|
|||
}
|
||||
}
|
||||
|
||||
static void virtio_vga_base_reset_hold(Object *obj)
|
||||
static void virtio_vga_base_reset_hold(Object *obj, ResetType type)
|
||||
{
|
||||
VirtIOVGABaseClass *klass = VIRTIO_VGA_BASE_GET_CLASS(obj);
|
||||
VirtIOVGABase *vvga = VIRTIO_VGA_BASE(obj);
|
||||
|
||||
/* reset virtio-gpu */
|
||||
if (klass->parent_phases.hold) {
|
||||
klass->parent_phases.hold(obj);
|
||||
klass->parent_phases.hold(obj, type);
|
||||
}
|
||||
|
||||
/* reset vga */
|
||||
|
|
|
@ -209,9 +209,9 @@ void soc_dma_set_request(struct soc_dma_ch_s *ch, int level)
|
|||
dma->enabled_count += level - ch->enable;
|
||||
|
||||
if (level)
|
||||
dma->ch_enable_mask |= 1 << ch->num;
|
||||
dma->ch_enable_mask |= (uint64_t)1 << ch->num;
|
||||
else
|
||||
dma->ch_enable_mask &= ~(1 << ch->num);
|
||||
dma->ch_enable_mask &= ~((uint64_t)1 << ch->num);
|
||||
|
||||
if (level != ch->enable) {
|
||||
soc_dma_ch_freq_update(dma);
|
||||
|
|
|
@ -352,7 +352,7 @@ static void npcm7xx_gpio_enter_reset(Object *obj, ResetType type)
|
|||
s->regs[NPCM7XX_GPIO_ODSC] = s->reset_odsc;
|
||||
}
|
||||
|
||||
static void npcm7xx_gpio_hold_reset(Object *obj)
|
||||
static void npcm7xx_gpio_hold_reset(Object *obj, ResetType type)
|
||||
{
|
||||
NPCM7xxGPIOState *s = NPCM7XX_GPIO(obj);
|
||||
|
||||
|
|
|
@ -484,7 +484,7 @@ static void pl061_enter_reset(Object *obj, ResetType type)
|
|||
s->amsel = 0;
|
||||
}
|
||||
|
||||
static void pl061_hold_reset(Object *obj)
|
||||
static void pl061_hold_reset(Object *obj, ResetType type)
|
||||
{
|
||||
PL061State *s = PL061(obj);
|
||||
int i, level;
|
||||
|
|
|
@ -70,7 +70,7 @@ static bool is_push_pull(Stm32l4x5GpioState *s, unsigned pin)
|
|||
return extract32(s->otyper, pin, 1) == 0;
|
||||
}
|
||||
|
||||
static void stm32l4x5_gpio_reset_hold(Object *obj)
|
||||
static void stm32l4x5_gpio_reset_hold(Object *obj, ResetType type)
|
||||
{
|
||||
Stm32l4x5GpioState *s = STM32L4X5_GPIO(obj);
|
||||
|
||||
|
|
|
@ -2453,7 +2453,7 @@ static void vmbus_unrealize(BusState *bus)
|
|||
qemu_mutex_destroy(&vmbus->rx_queue_lock);
|
||||
}
|
||||
|
||||
static void vmbus_reset_hold(Object *obj)
|
||||
static void vmbus_reset_hold(Object *obj, ResetType type)
|
||||
{
|
||||
vmbus_deinit(VMBUS(obj));
|
||||
}
|
||||
|
|
|
@ -170,7 +170,7 @@ static inline bool allwinner_i2c_interrupt_is_enabled(AWI2CState *s)
|
|||
return s->cntr & TWI_CNTR_INT_EN;
|
||||
}
|
||||
|
||||
static void allwinner_i2c_reset_hold(Object *obj)
|
||||
static void allwinner_i2c_reset_hold(Object *obj, ResetType type)
|
||||
{
|
||||
AWI2CState *s = AW_I2C(obj);
|
||||
|
||||
|
@ -385,8 +385,7 @@ static void allwinner_i2c_write(void *opaque, hwaddr offset,
|
|||
break;
|
||||
case TWI_SRST_REG:
|
||||
if (((value & TWI_SRST_MASK) == 0) && (s->srst & TWI_SRST_MASK)) {
|
||||
/* Perform reset */
|
||||
allwinner_i2c_reset_hold(OBJECT(s));
|
||||
device_cold_reset(DEVICE(s));
|
||||
}
|
||||
s->srst = value & TWI_SRST_MASK;
|
||||
break;
|
||||
|
|
|
@ -1022,7 +1022,7 @@ static void npcm7xx_smbus_enter_reset(Object *obj, ResetType type)
|
|||
s->rx_cur = 0;
|
||||
}
|
||||
|
||||
static void npcm7xx_smbus_hold_reset(Object *obj)
|
||||
static void npcm7xx_smbus_hold_reset(Object *obj, ResetType type)
|
||||
{
|
||||
NPCM7xxSMBusState *s = NPCM7XX_SMBUS(obj);
|
||||
|
||||
|
|
|
@ -231,7 +231,7 @@ static const VMStateDescription vmstate_adb_bus = {
|
|||
}
|
||||
};
|
||||
|
||||
static void adb_bus_reset_hold(Object *obj)
|
||||
static void adb_bus_reset_hold(Object *obj, ResetType type)
|
||||
{
|
||||
ADBBusState *adb_bus = ADB_BUS(obj);
|
||||
|
||||
|
|
|
@ -1007,7 +1007,7 @@ void ps2_write_mouse(PS2MouseState *s, int val)
|
|||
}
|
||||
}
|
||||
|
||||
static void ps2_reset_hold(Object *obj)
|
||||
static void ps2_reset_hold(Object *obj, ResetType type)
|
||||
{
|
||||
PS2State *s = PS2_DEVICE(obj);
|
||||
|
||||
|
@ -1015,7 +1015,7 @@ static void ps2_reset_hold(Object *obj)
|
|||
ps2_reset_queue(s);
|
||||
}
|
||||
|
||||
static void ps2_reset_exit(Object *obj)
|
||||
static void ps2_reset_exit(Object *obj, ResetType type)
|
||||
{
|
||||
PS2State *s = PS2_DEVICE(obj);
|
||||
|
||||
|
@ -1048,7 +1048,7 @@ static void ps2_common_post_load(PS2State *s)
|
|||
q->cwptr = ccount ? (q->rptr + ccount) & (PS2_BUFFER_SIZE - 1) : -1;
|
||||
}
|
||||
|
||||
static void ps2_kbd_reset_hold(Object *obj)
|
||||
static void ps2_kbd_reset_hold(Object *obj, ResetType type)
|
||||
{
|
||||
PS2DeviceClass *ps2dc = PS2_DEVICE_GET_CLASS(obj);
|
||||
PS2KbdState *s = PS2_KBD_DEVICE(obj);
|
||||
|
@ -1056,7 +1056,7 @@ static void ps2_kbd_reset_hold(Object *obj)
|
|||
trace_ps2_kbd_reset(s);
|
||||
|
||||
if (ps2dc->parent_phases.hold) {
|
||||
ps2dc->parent_phases.hold(obj);
|
||||
ps2dc->parent_phases.hold(obj, type);
|
||||
}
|
||||
|
||||
s->scan_enabled = 1;
|
||||
|
@ -1065,7 +1065,7 @@ static void ps2_kbd_reset_hold(Object *obj)
|
|||
s->modifiers = 0;
|
||||
}
|
||||
|
||||
static void ps2_mouse_reset_hold(Object *obj)
|
||||
static void ps2_mouse_reset_hold(Object *obj, ResetType type)
|
||||
{
|
||||
PS2DeviceClass *ps2dc = PS2_DEVICE_GET_CLASS(obj);
|
||||
PS2MouseState *s = PS2_MOUSE_DEVICE(obj);
|
||||
|
@ -1073,7 +1073,7 @@ static void ps2_mouse_reset_hold(Object *obj)
|
|||
trace_ps2_mouse_reset(s);
|
||||
|
||||
if (ps2dc->parent_phases.hold) {
|
||||
ps2dc->parent_phases.hold(obj);
|
||||
ps2dc->parent_phases.hold(obj, type);
|
||||
}
|
||||
|
||||
s->mouse_status = 0;
|
||||
|
|
|
@ -263,7 +263,7 @@ static inline void arm_gic_common_reset_irq_state(GICState *s, int cidx,
|
|||
}
|
||||
}
|
||||
|
||||
static void arm_gic_common_reset_hold(Object *obj)
|
||||
static void arm_gic_common_reset_hold(Object *obj, ResetType type)
|
||||
{
|
||||
GICState *s = ARM_GIC_COMMON(obj);
|
||||
int i, j;
|
||||
|
|
|
@ -473,13 +473,13 @@ static void kvm_arm_gic_get(GICState *s)
|
|||
}
|
||||
}
|
||||
|
||||
static void kvm_arm_gic_reset_hold(Object *obj)
|
||||
static void kvm_arm_gic_reset_hold(Object *obj, ResetType type)
|
||||
{
|
||||
GICState *s = ARM_GIC_COMMON(obj);
|
||||
KVMARMGICClass *kgc = KVM_ARM_GIC_GET_CLASS(s);
|
||||
|
||||
if (kgc->parent_phases.hold) {
|
||||
kgc->parent_phases.hold(obj);
|
||||
kgc->parent_phases.hold(obj, type);
|
||||
}
|
||||
|
||||
if (kvm_arm_gic_can_save_restore(s)) {
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
#include "hw/intc/arm_gicv3.h"
|
||||
#include "gicv3_internal.h"
|
||||
|
||||
static bool irqbetter(GICv3CPUState *cs, int irq, uint8_t prio)
|
||||
static bool irqbetter(GICv3CPUState *cs, int irq, uint8_t prio, bool nmi)
|
||||
{
|
||||
/* Return true if this IRQ at this priority should take
|
||||
* precedence over the current recorded highest priority
|
||||
|
@ -30,14 +30,23 @@ static bool irqbetter(GICv3CPUState *cs, int irq, uint8_t prio)
|
|||
* is the same as this one (a property which the calling code
|
||||
* relies on).
|
||||
*/
|
||||
if (prio < cs->hppi.prio) {
|
||||
return true;
|
||||
if (prio != cs->hppi.prio) {
|
||||
return prio < cs->hppi.prio;
|
||||
}
|
||||
|
||||
/*
|
||||
* The same priority IRQ with non-maskable property should signal to
|
||||
* the CPU as it have the priority higher than the labelled 0x80 or 0x00.
|
||||
*/
|
||||
if (nmi != cs->hppi.nmi) {
|
||||
return nmi;
|
||||
}
|
||||
|
||||
/* If multiple pending interrupts have the same priority then it is an
|
||||
* IMPDEF choice which of them to signal to the CPU. We choose to
|
||||
* signal the one with the lowest interrupt number.
|
||||
*/
|
||||
if (prio == cs->hppi.prio && irq <= cs->hppi.irq) {
|
||||
if (irq <= cs->hppi.irq) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -129,6 +138,40 @@ static uint32_t gicr_int_pending(GICv3CPUState *cs)
|
|||
return pend;
|
||||
}
|
||||
|
||||
static bool gicv3_get_priority(GICv3CPUState *cs, bool is_redist, int irq,
|
||||
uint8_t *prio)
|
||||
{
|
||||
uint32_t nmi = 0x0;
|
||||
|
||||
if (is_redist) {
|
||||
nmi = extract32(cs->gicr_inmir0, irq, 1);
|
||||
} else {
|
||||
nmi = *gic_bmp_ptr32(cs->gic->nmi, irq);
|
||||
nmi = nmi & (1 << (irq & 0x1f));
|
||||
}
|
||||
|
||||
if (nmi) {
|
||||
/* DS = 0 & Non-secure NMI */
|
||||
if (!(cs->gic->gicd_ctlr & GICD_CTLR_DS) &&
|
||||
((is_redist && extract32(cs->gicr_igroupr0, irq, 1)) ||
|
||||
(!is_redist && gicv3_gicd_group_test(cs->gic, irq)))) {
|
||||
*prio = 0x80;
|
||||
} else {
|
||||
*prio = 0x0;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (is_redist) {
|
||||
*prio = cs->gicr_ipriorityr[irq];
|
||||
} else {
|
||||
*prio = cs->gic->gicd_ipriority[irq];
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Update the interrupt status after state in a redistributor
|
||||
* or CPU interface has changed, but don't tell the CPU i/f.
|
||||
*/
|
||||
|
@ -141,6 +184,7 @@ static void gicv3_redist_update_noirqset(GICv3CPUState *cs)
|
|||
uint8_t prio;
|
||||
int i;
|
||||
uint32_t pend;
|
||||
bool nmi = false;
|
||||
|
||||
/* Find out which redistributor interrupts are eligible to be
|
||||
* signaled to the CPU interface.
|
||||
|
@ -152,10 +196,11 @@ static void gicv3_redist_update_noirqset(GICv3CPUState *cs)
|
|||
if (!(pend & (1 << i))) {
|
||||
continue;
|
||||
}
|
||||
prio = cs->gicr_ipriorityr[i];
|
||||
if (irqbetter(cs, i, prio)) {
|
||||
nmi = gicv3_get_priority(cs, true, i, &prio);
|
||||
if (irqbetter(cs, i, prio, nmi)) {
|
||||
cs->hppi.irq = i;
|
||||
cs->hppi.prio = prio;
|
||||
cs->hppi.nmi = nmi;
|
||||
seenbetter = true;
|
||||
}
|
||||
}
|
||||
|
@ -168,9 +213,10 @@ static void gicv3_redist_update_noirqset(GICv3CPUState *cs)
|
|||
if ((cs->gicr_ctlr & GICR_CTLR_ENABLE_LPIS) && cs->gic->lpi_enable &&
|
||||
(cs->gic->gicd_ctlr & GICD_CTLR_EN_GRP1NS) &&
|
||||
(cs->hpplpi.prio != 0xff)) {
|
||||
if (irqbetter(cs, cs->hpplpi.irq, cs->hpplpi.prio)) {
|
||||
if (irqbetter(cs, cs->hpplpi.irq, cs->hpplpi.prio, cs->hpplpi.nmi)) {
|
||||
cs->hppi.irq = cs->hpplpi.irq;
|
||||
cs->hppi.prio = cs->hpplpi.prio;
|
||||
cs->hppi.nmi = cs->hpplpi.nmi;
|
||||
cs->hppi.grp = cs->hpplpi.grp;
|
||||
seenbetter = true;
|
||||
}
|
||||
|
@ -213,6 +259,7 @@ static void gicv3_update_noirqset(GICv3State *s, int start, int len)
|
|||
int i;
|
||||
uint8_t prio;
|
||||
uint32_t pend = 0;
|
||||
bool nmi = false;
|
||||
|
||||
assert(start >= GIC_INTERNAL);
|
||||
assert(len > 0);
|
||||
|
@ -240,10 +287,11 @@ static void gicv3_update_noirqset(GICv3State *s, int start, int len)
|
|||
*/
|
||||
continue;
|
||||
}
|
||||
prio = s->gicd_ipriority[i];
|
||||
if (irqbetter(cs, i, prio)) {
|
||||
nmi = gicv3_get_priority(cs, false, i, &prio);
|
||||
if (irqbetter(cs, i, prio, nmi)) {
|
||||
cs->hppi.irq = i;
|
||||
cs->hppi.prio = prio;
|
||||
cs->hppi.nmi = nmi;
|
||||
cs->seenbetter = true;
|
||||
}
|
||||
}
|
||||
|
@ -293,6 +341,7 @@ void gicv3_full_update_noirqset(GICv3State *s)
|
|||
|
||||
for (i = 0; i < s->num_cpu; i++) {
|
||||
s->cpu[i].hppi.prio = 0xff;
|
||||
s->cpu[i].hppi.nmi = false;
|
||||
}
|
||||
|
||||
/* Note that we can guarantee that these functions will not
|
||||
|
|
|
@ -164,6 +164,24 @@ const VMStateDescription vmstate_gicv3_gicv4 = {
|
|||
}
|
||||
};
|
||||
|
||||
static bool gicv3_cpu_nmi_needed(void *opaque)
|
||||
{
|
||||
GICv3CPUState *cs = opaque;
|
||||
|
||||
return cs->gic->nmi_support;
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_gicv3_cpu_nmi = {
|
||||
.name = "arm_gicv3_cpu/nmi",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.needed = gicv3_cpu_nmi_needed,
|
||||
.fields = (const VMStateField[]) {
|
||||
VMSTATE_UINT32(gicr_inmir0, GICv3CPUState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static const VMStateDescription vmstate_gicv3_cpu = {
|
||||
.name = "arm_gicv3_cpu",
|
||||
.version_id = 1,
|
||||
|
@ -196,6 +214,7 @@ static const VMStateDescription vmstate_gicv3_cpu = {
|
|||
&vmstate_gicv3_cpu_virt,
|
||||
&vmstate_gicv3_cpu_sre_el1,
|
||||
&vmstate_gicv3_gicv4,
|
||||
&vmstate_gicv3_cpu_nmi,
|
||||
NULL
|
||||
}
|
||||
};
|
||||
|
@ -238,6 +257,24 @@ const VMStateDescription vmstate_gicv3_gicd_no_migration_shift_bug = {
|
|||
}
|
||||
};
|
||||
|
||||
static bool gicv3_nmi_needed(void *opaque)
|
||||
{
|
||||
GICv3State *cs = opaque;
|
||||
|
||||
return cs->nmi_support;
|
||||
}
|
||||
|
||||
const VMStateDescription vmstate_gicv3_gicd_nmi = {
|
||||
.name = "arm_gicv3/gicd_nmi",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.needed = gicv3_nmi_needed,
|
||||
.fields = (const VMStateField[]) {
|
||||
VMSTATE_UINT32_ARRAY(nmi, GICv3State, GICV3_BMP_SIZE),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static const VMStateDescription vmstate_gicv3 = {
|
||||
.name = "arm_gicv3",
|
||||
.version_id = 1,
|
||||
|
@ -266,6 +303,7 @@ static const VMStateDescription vmstate_gicv3 = {
|
|||
},
|
||||
.subsections = (const VMStateDescription * const []) {
|
||||
&vmstate_gicv3_gicd_no_migration_shift_bug,
|
||||
&vmstate_gicv3_gicd_nmi,
|
||||
NULL
|
||||
}
|
||||
};
|
||||
|
@ -299,6 +337,12 @@ void gicv3_init_irqs_and_mmio(GICv3State *s, qemu_irq_handler handler,
|
|||
for (i = 0; i < s->num_cpu; i++) {
|
||||
sysbus_init_irq(sbd, &s->cpu[i].parent_vfiq);
|
||||
}
|
||||
for (i = 0; i < s->num_cpu; i++) {
|
||||
sysbus_init_irq(sbd, &s->cpu[i].parent_nmi);
|
||||
}
|
||||
for (i = 0; i < s->num_cpu; i++) {
|
||||
sysbus_init_irq(sbd, &s->cpu[i].parent_vnmi);
|
||||
}
|
||||
|
||||
memory_region_init_io(&s->iomem_dist, OBJECT(s), ops, s,
|
||||
"gicv3_dist", 0x10000);
|
||||
|
@ -451,7 +495,7 @@ static void arm_gicv3_finalize(Object *obj)
|
|||
g_free(s->redist_region_count);
|
||||
}
|
||||
|
||||
static void arm_gicv3_common_reset_hold(Object *obj)
|
||||
static void arm_gicv3_common_reset_hold(Object *obj, ResetType type)
|
||||
{
|
||||
GICv3State *s = ARM_GICV3_COMMON(obj);
|
||||
int i;
|
||||
|
@ -492,8 +536,11 @@ static void arm_gicv3_common_reset_hold(Object *obj)
|
|||
memset(cs->gicr_ipriorityr, 0, sizeof(cs->gicr_ipriorityr));
|
||||
|
||||
cs->hppi.prio = 0xff;
|
||||
cs->hppi.nmi = false;
|
||||
cs->hpplpi.prio = 0xff;
|
||||
cs->hpplpi.nmi = false;
|
||||
cs->hppvlpi.prio = 0xff;
|
||||
cs->hppvlpi.nmi = false;
|
||||
|
||||
/* State in the CPU interface must *not* be reset here, because it
|
||||
* is part of the CPU's reset domain, not the GIC device's.
|
||||
|
@ -563,6 +610,7 @@ static Property arm_gicv3_common_properties[] = {
|
|||
DEFINE_PROP_UINT32("num-irq", GICv3State, num_irq, 32),
|
||||
DEFINE_PROP_UINT32("revision", GICv3State, revision, 3),
|
||||
DEFINE_PROP_BOOL("has-lpi", GICv3State, lpi_enable, 0),
|
||||
DEFINE_PROP_BOOL("has-nmi", GICv3State, nmi_support, 0),
|
||||
DEFINE_PROP_BOOL("has-security-extensions", GICv3State, security_extn, 0),
|
||||
/*
|
||||
* Compatibility property: force 8 bits of physical priority, even
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "hw/irq.h"
|
||||
#include "cpu.h"
|
||||
#include "target/arm/cpregs.h"
|
||||
#include "target/arm/cpu-features.h"
|
||||
#include "sysemu/tcg.h"
|
||||
#include "sysemu/qtest.h"
|
||||
|
||||
|
@ -157,6 +158,10 @@ static int ich_highest_active_virt_prio(GICv3CPUState *cs)
|
|||
int i;
|
||||
int aprmax = ich_num_aprs(cs);
|
||||
|
||||
if (cs->ich_apr[GICV3_G1NS][0] & ICV_AP1R_EL1_NMI) {
|
||||
return 0x0;
|
||||
}
|
||||
|
||||
for (i = 0; i < aprmax; i++) {
|
||||
uint32_t apr = cs->ich_apr[GICV3_G0][i] |
|
||||
cs->ich_apr[GICV3_G1NS][i];
|
||||
|
@ -191,6 +196,7 @@ static int hppvi_index(GICv3CPUState *cs)
|
|||
* correct behaviour.
|
||||
*/
|
||||
int prio = 0xff;
|
||||
bool nmi = false;
|
||||
|
||||
if (!(cs->ich_vmcr_el2 & (ICH_VMCR_EL2_VENG0 | ICH_VMCR_EL2_VENG1))) {
|
||||
/* Both groups disabled, definitely nothing to do */
|
||||
|
@ -199,6 +205,7 @@ static int hppvi_index(GICv3CPUState *cs)
|
|||
|
||||
for (i = 0; i < cs->num_list_regs; i++) {
|
||||
uint64_t lr = cs->ich_lr_el2[i];
|
||||
bool thisnmi;
|
||||
int thisprio;
|
||||
|
||||
if (ich_lr_state(lr) != ICH_LR_EL2_STATE_PENDING) {
|
||||
|
@ -217,10 +224,12 @@ static int hppvi_index(GICv3CPUState *cs)
|
|||
}
|
||||
}
|
||||
|
||||
thisnmi = lr & ICH_LR_EL2_NMI;
|
||||
thisprio = ich_lr_prio(lr);
|
||||
|
||||
if (thisprio < prio) {
|
||||
if ((thisprio < prio) || ((thisprio == prio) && (thisnmi & (!nmi)))) {
|
||||
prio = thisprio;
|
||||
nmi = thisnmi;
|
||||
idx = i;
|
||||
}
|
||||
}
|
||||
|
@ -289,6 +298,7 @@ static bool icv_hppi_can_preempt(GICv3CPUState *cs, uint64_t lr)
|
|||
* equivalent of these checks.
|
||||
*/
|
||||
int grp;
|
||||
bool is_nmi;
|
||||
uint32_t mask, prio, rprio, vpmr;
|
||||
|
||||
if (!(cs->ich_hcr_el2 & ICH_HCR_EL2_EN)) {
|
||||
|
@ -301,10 +311,11 @@ static bool icv_hppi_can_preempt(GICv3CPUState *cs, uint64_t lr)
|
|||
*/
|
||||
|
||||
prio = ich_lr_prio(lr);
|
||||
is_nmi = lr & ICH_LR_EL2_NMI;
|
||||
vpmr = extract64(cs->ich_vmcr_el2, ICH_VMCR_EL2_VPMR_SHIFT,
|
||||
ICH_VMCR_EL2_VPMR_LENGTH);
|
||||
|
||||
if (prio >= vpmr) {
|
||||
if (!is_nmi && prio >= vpmr) {
|
||||
/* Priority mask masks this interrupt */
|
||||
return false;
|
||||
}
|
||||
|
@ -326,6 +337,11 @@ static bool icv_hppi_can_preempt(GICv3CPUState *cs, uint64_t lr)
|
|||
return true;
|
||||
}
|
||||
|
||||
if ((prio & mask) == (rprio & mask) && is_nmi &&
|
||||
!(cs->ich_apr[GICV3_G1NS][0] & ICV_AP1R_EL1_NMI)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -465,6 +481,7 @@ void gicv3_cpuif_virt_irq_fiq_update(GICv3CPUState *cs)
|
|||
int idx;
|
||||
int irqlevel = 0;
|
||||
int fiqlevel = 0;
|
||||
int nmilevel = 0;
|
||||
|
||||
idx = hppvi_index(cs);
|
||||
trace_gicv3_cpuif_virt_update(gicv3_redist_affid(cs), idx,
|
||||
|
@ -482,9 +499,17 @@ void gicv3_cpuif_virt_irq_fiq_update(GICv3CPUState *cs)
|
|||
uint64_t lr = cs->ich_lr_el2[idx];
|
||||
|
||||
if (icv_hppi_can_preempt(cs, lr)) {
|
||||
/* Virtual interrupts are simple: G0 are always FIQ, and G1 IRQ */
|
||||
/*
|
||||
* Virtual interrupts are simple: G0 are always FIQ, and G1 are
|
||||
* IRQ or NMI which depends on the ICH_LR<n>_EL2.NMI to have
|
||||
* non-maskable property.
|
||||
*/
|
||||
if (lr & ICH_LR_EL2_GROUP) {
|
||||
irqlevel = 1;
|
||||
if (lr & ICH_LR_EL2_NMI) {
|
||||
nmilevel = 1;
|
||||
} else {
|
||||
irqlevel = 1;
|
||||
}
|
||||
} else {
|
||||
fiqlevel = 1;
|
||||
}
|
||||
|
@ -494,6 +519,7 @@ void gicv3_cpuif_virt_irq_fiq_update(GICv3CPUState *cs)
|
|||
trace_gicv3_cpuif_virt_set_irqs(gicv3_redist_affid(cs), fiqlevel, irqlevel);
|
||||
qemu_set_irq(cs->parent_vfiq, fiqlevel);
|
||||
qemu_set_irq(cs->parent_virq, irqlevel);
|
||||
qemu_set_irq(cs->parent_vnmi, nmilevel);
|
||||
}
|
||||
|
||||
static void gicv3_cpuif_virt_update(GICv3CPUState *cs)
|
||||
|
@ -550,7 +576,11 @@ static void icv_ap_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
|||
|
||||
trace_gicv3_icv_ap_write(ri->crm & 1, regno, gicv3_redist_affid(cs), value);
|
||||
|
||||
cs->ich_apr[grp][regno] = value & 0xFFFFFFFFU;
|
||||
if (cs->nmi_support) {
|
||||
cs->ich_apr[grp][regno] = value & (0xFFFFFFFFU | ICV_AP1R_EL1_NMI);
|
||||
} else {
|
||||
cs->ich_apr[grp][regno] = value & 0xFFFFFFFFU;
|
||||
}
|
||||
|
||||
gicv3_cpuif_virt_irq_fiq_update(cs);
|
||||
return;
|
||||
|
@ -697,7 +727,11 @@ static void icv_ctlr_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
|||
static uint64_t icv_rpr_read(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||
{
|
||||
GICv3CPUState *cs = icc_cs_from_env(env);
|
||||
int prio = ich_highest_active_virt_prio(cs);
|
||||
uint64_t prio = ich_highest_active_virt_prio(cs);
|
||||
|
||||
if (cs->ich_apr[GICV3_G1NS][0] & ICV_AP1R_EL1_NMI) {
|
||||
prio |= ICV_RPR_EL1_NMI;
|
||||
}
|
||||
|
||||
trace_gicv3_icv_rpr_read(gicv3_redist_affid(cs), prio);
|
||||
return prio;
|
||||
|
@ -736,13 +770,19 @@ static void icv_activate_irq(GICv3CPUState *cs, int idx, int grp)
|
|||
*/
|
||||
uint32_t mask = icv_gprio_mask(cs, grp);
|
||||
int prio = ich_lr_prio(cs->ich_lr_el2[idx]) & mask;
|
||||
bool nmi = cs->ich_lr_el2[idx] & ICH_LR_EL2_NMI;
|
||||
int aprbit = prio >> (8 - cs->vprebits);
|
||||
int regno = aprbit / 32;
|
||||
int regbit = aprbit % 32;
|
||||
|
||||
cs->ich_lr_el2[idx] &= ~ICH_LR_EL2_STATE_PENDING_BIT;
|
||||
cs->ich_lr_el2[idx] |= ICH_LR_EL2_STATE_ACTIVE_BIT;
|
||||
cs->ich_apr[grp][regno] |= (1 << regbit);
|
||||
|
||||
if (nmi) {
|
||||
cs->ich_apr[grp][regno] |= ICV_AP1R_EL1_NMI;
|
||||
} else {
|
||||
cs->ich_apr[grp][regno] |= (1 << regbit);
|
||||
}
|
||||
}
|
||||
|
||||
static void icv_activate_vlpi(GICv3CPUState *cs)
|
||||
|
@ -763,6 +803,7 @@ static uint64_t icv_iar_read(CPUARMState *env, const ARMCPRegInfo *ri)
|
|||
int grp = ri->crm == 8 ? GICV3_G0 : GICV3_G1NS;
|
||||
int idx = hppvi_index(cs);
|
||||
uint64_t intid = INTID_SPURIOUS;
|
||||
int el = arm_current_el(env);
|
||||
|
||||
if (idx == HPPVI_INDEX_VLPI) {
|
||||
if (cs->hppvlpi.grp == grp && icv_hppvlpi_can_preempt(cs)) {
|
||||
|
@ -772,11 +813,16 @@ static uint64_t icv_iar_read(CPUARMState *env, const ARMCPRegInfo *ri)
|
|||
} else if (idx >= 0) {
|
||||
uint64_t lr = cs->ich_lr_el2[idx];
|
||||
int thisgrp = (lr & ICH_LR_EL2_GROUP) ? GICV3_G1NS : GICV3_G0;
|
||||
bool nmi = env->cp15.sctlr_el[el] & SCTLR_NMI && lr & ICH_LR_EL2_NMI;
|
||||
|
||||
if (thisgrp == grp && icv_hppi_can_preempt(cs, lr)) {
|
||||
intid = ich_lr_vintid(lr);
|
||||
if (!gicv3_intid_is_special(intid)) {
|
||||
icv_activate_irq(cs, idx, grp);
|
||||
if (!nmi) {
|
||||
icv_activate_irq(cs, idx, grp);
|
||||
} else {
|
||||
intid = INTID_NMI;
|
||||
}
|
||||
} else {
|
||||
/* Interrupt goes from Pending to Invalid */
|
||||
cs->ich_lr_el2[idx] &= ~ICH_LR_EL2_STATE_PENDING_BIT;
|
||||
|
@ -795,6 +841,42 @@ static uint64_t icv_iar_read(CPUARMState *env, const ARMCPRegInfo *ri)
|
|||
return intid;
|
||||
}
|
||||
|
||||
static uint64_t icv_nmiar1_read(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||
{
|
||||
GICv3CPUState *cs = icc_cs_from_env(env);
|
||||
int idx = hppvi_index(cs);
|
||||
uint64_t intid = INTID_SPURIOUS;
|
||||
|
||||
if (idx >= 0 && idx != HPPVI_INDEX_VLPI) {
|
||||
uint64_t lr = cs->ich_lr_el2[idx];
|
||||
int thisgrp = (lr & ICH_LR_EL2_GROUP) ? GICV3_G1NS : GICV3_G0;
|
||||
|
||||
if ((thisgrp == GICV3_G1NS) && icv_hppi_can_preempt(cs, lr)) {
|
||||
intid = ich_lr_vintid(lr);
|
||||
if (!gicv3_intid_is_special(intid)) {
|
||||
if (lr & ICH_LR_EL2_NMI) {
|
||||
icv_activate_irq(cs, idx, GICV3_G1NS);
|
||||
} else {
|
||||
intid = INTID_SPURIOUS;
|
||||
}
|
||||
} else {
|
||||
/* Interrupt goes from Pending to Invalid */
|
||||
cs->ich_lr_el2[idx] &= ~ICH_LR_EL2_STATE_PENDING_BIT;
|
||||
/*
|
||||
* We will now return the (bogus) ID from the list register,
|
||||
* as per the pseudocode.
|
||||
*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
trace_gicv3_icv_nmiar1_read(gicv3_redist_affid(cs), intid);
|
||||
|
||||
gicv3_cpuif_virt_update(cs);
|
||||
|
||||
return intid;
|
||||
}
|
||||
|
||||
static uint32_t icc_fullprio_mask(GICv3CPUState *cs)
|
||||
{
|
||||
/*
|
||||
|
@ -832,6 +914,23 @@ static int icc_highest_active_prio(GICv3CPUState *cs)
|
|||
*/
|
||||
int i;
|
||||
|
||||
if (cs->nmi_support) {
|
||||
/*
|
||||
* If an NMI is active this takes precedence over anything else
|
||||
* for priority purposes; the NMI bit is only in the AP1R0 bit.
|
||||
* We return here the effective priority of the NMI, which is
|
||||
* either 0x0 or 0x80. Callers will need to check NMI again for
|
||||
* purposes of either setting the RPR register bits or for
|
||||
* prioritization of NMI vs non-NMI.
|
||||
*/
|
||||
if (cs->icc_apr[GICV3_G1][0] & ICC_AP1R_EL1_NMI) {
|
||||
return 0;
|
||||
}
|
||||
if (cs->icc_apr[GICV3_G1NS][0] & ICC_AP1R_EL1_NMI) {
|
||||
return (cs->gic->gicd_ctlr & GICD_CTLR_DS) ? 0 : 0x80;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < icc_num_aprs(cs); i++) {
|
||||
uint32_t apr = cs->icc_apr[GICV3_G0][i] |
|
||||
cs->icc_apr[GICV3_G1][i] | cs->icc_apr[GICV3_G1NS][i];
|
||||
|
@ -898,12 +997,24 @@ static bool icc_hppi_can_preempt(GICv3CPUState *cs)
|
|||
*/
|
||||
int rprio;
|
||||
uint32_t mask;
|
||||
ARMCPU *cpu = ARM_CPU(cs->cpu);
|
||||
CPUARMState *env = &cpu->env;
|
||||
|
||||
if (icc_no_enabled_hppi(cs)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cs->hppi.prio >= cs->icc_pmr_el1) {
|
||||
if (cs->hppi.nmi) {
|
||||
if (!(cs->gic->gicd_ctlr & GICD_CTLR_DS) &&
|
||||
cs->hppi.grp == GICV3_G1NS) {
|
||||
if (cs->icc_pmr_el1 < 0x80) {
|
||||
return false;
|
||||
}
|
||||
if (arm_is_secure(env) && cs->icc_pmr_el1 == 0x80) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else if (cs->hppi.prio >= cs->icc_pmr_el1) {
|
||||
/* Priority mask masks this interrupt */
|
||||
return false;
|
||||
}
|
||||
|
@ -923,6 +1034,12 @@ static bool icc_hppi_can_preempt(GICv3CPUState *cs)
|
|||
return true;
|
||||
}
|
||||
|
||||
if (cs->hppi.nmi && (cs->hppi.prio & mask) == (rprio & mask)) {
|
||||
if (!(cs->icc_apr[cs->hppi.grp][0] & ICC_AP1R_EL1_NMI)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -931,6 +1048,7 @@ void gicv3_cpuif_update(GICv3CPUState *cs)
|
|||
/* Tell the CPU about its highest priority pending interrupt */
|
||||
int irqlevel = 0;
|
||||
int fiqlevel = 0;
|
||||
int nmilevel = 0;
|
||||
ARMCPU *cpu = ARM_CPU(cs->cpu);
|
||||
CPUARMState *env = &cpu->env;
|
||||
|
||||
|
@ -969,6 +1087,8 @@ void gicv3_cpuif_update(GICv3CPUState *cs)
|
|||
|
||||
if (isfiq) {
|
||||
fiqlevel = 1;
|
||||
} else if (cs->hppi.nmi) {
|
||||
nmilevel = 1;
|
||||
} else {
|
||||
irqlevel = 1;
|
||||
}
|
||||
|
@ -978,6 +1098,7 @@ void gicv3_cpuif_update(GICv3CPUState *cs)
|
|||
|
||||
qemu_set_irq(cs->parent_fiq, fiqlevel);
|
||||
qemu_set_irq(cs->parent_irq, irqlevel);
|
||||
qemu_set_irq(cs->parent_nmi, nmilevel);
|
||||
}
|
||||
|
||||
static uint64_t icc_pmr_read(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||
|
@ -1044,8 +1165,13 @@ static void icc_activate_irq(GICv3CPUState *cs, int irq)
|
|||
int aprbit = prio >> (8 - cs->prebits);
|
||||
int regno = aprbit / 32;
|
||||
int regbit = aprbit % 32;
|
||||
bool nmi = cs->hppi.nmi;
|
||||
|
||||
cs->icc_apr[cs->hppi.grp][regno] |= (1 << regbit);
|
||||
if (nmi) {
|
||||
cs->icc_apr[cs->hppi.grp][regno] |= ICC_AP1R_EL1_NMI;
|
||||
} else {
|
||||
cs->icc_apr[cs->hppi.grp][regno] |= (1 << regbit);
|
||||
}
|
||||
|
||||
if (irq < GIC_INTERNAL) {
|
||||
cs->gicr_iactiver0 = deposit32(cs->gicr_iactiver0, irq, 1, 1);
|
||||
|
@ -1159,6 +1285,7 @@ static uint64_t icc_iar0_read(CPUARMState *env, const ARMCPRegInfo *ri)
|
|||
static uint64_t icc_iar1_read(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||
{
|
||||
GICv3CPUState *cs = icc_cs_from_env(env);
|
||||
int el = arm_current_el(env);
|
||||
uint64_t intid;
|
||||
|
||||
if (icv_access(env, HCR_IMO)) {
|
||||
|
@ -1172,13 +1299,44 @@ static uint64_t icc_iar1_read(CPUARMState *env, const ARMCPRegInfo *ri)
|
|||
}
|
||||
|
||||
if (!gicv3_intid_is_special(intid)) {
|
||||
icc_activate_irq(cs, intid);
|
||||
if (cs->hppi.nmi && env->cp15.sctlr_el[el] & SCTLR_NMI) {
|
||||
intid = INTID_NMI;
|
||||
} else {
|
||||
icc_activate_irq(cs, intid);
|
||||
}
|
||||
}
|
||||
|
||||
trace_gicv3_icc_iar1_read(gicv3_redist_affid(cs), intid);
|
||||
return intid;
|
||||
}
|
||||
|
||||
static uint64_t icc_nmiar1_read(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||
{
|
||||
GICv3CPUState *cs = icc_cs_from_env(env);
|
||||
uint64_t intid;
|
||||
|
||||
if (icv_access(env, HCR_IMO)) {
|
||||
return icv_nmiar1_read(env, ri);
|
||||
}
|
||||
|
||||
if (!icc_hppi_can_preempt(cs)) {
|
||||
intid = INTID_SPURIOUS;
|
||||
} else {
|
||||
intid = icc_hppir1_value(cs, env);
|
||||
}
|
||||
|
||||
if (!gicv3_intid_is_special(intid)) {
|
||||
if (!cs->hppi.nmi) {
|
||||
intid = INTID_SPURIOUS;
|
||||
} else {
|
||||
icc_activate_irq(cs, intid);
|
||||
}
|
||||
}
|
||||
|
||||
trace_gicv3_icc_nmiar1_read(gicv3_redist_affid(cs), intid);
|
||||
return intid;
|
||||
}
|
||||
|
||||
static void icc_drop_prio(GICv3CPUState *cs, int grp)
|
||||
{
|
||||
/* Drop the priority of the currently active interrupt in
|
||||
|
@ -1205,6 +1363,12 @@ static void icc_drop_prio(GICv3CPUState *cs, int grp)
|
|||
if (!*papr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (i == 0 && cs->nmi_support && (*papr & ICC_AP1R_EL1_NMI)) {
|
||||
*papr &= (~ICC_AP1R_EL1_NMI);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Clear the lowest set bit */
|
||||
*papr &= *papr - 1;
|
||||
break;
|
||||
|
@ -1239,6 +1403,15 @@ static int icc_highest_active_group(GICv3CPUState *cs)
|
|||
*/
|
||||
int i;
|
||||
|
||||
if (cs->nmi_support) {
|
||||
if (cs->icc_apr[GICV3_G1][0] & ICC_AP1R_EL1_NMI) {
|
||||
return GICV3_G1;
|
||||
}
|
||||
if (cs->icc_apr[GICV3_G1NS][0] & ICC_AP1R_EL1_NMI) {
|
||||
return GICV3_G1NS;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(cs->icc_apr[0]); i++) {
|
||||
int g0ctz = ctz32(cs->icc_apr[GICV3_G0][i]);
|
||||
int g1ctz = ctz32(cs->icc_apr[GICV3_G1][i]);
|
||||
|
@ -1329,7 +1502,7 @@ static void icv_increment_eoicount(GICv3CPUState *cs)
|
|||
ICH_HCR_EL2_EOICOUNT_LENGTH, eoicount + 1);
|
||||
}
|
||||
|
||||
static int icv_drop_prio(GICv3CPUState *cs)
|
||||
static int icv_drop_prio(GICv3CPUState *cs, bool *nmi)
|
||||
{
|
||||
/* Drop the priority of the currently active virtual interrupt
|
||||
* (favouring group 0 if there is a set active bit at
|
||||
|
@ -1351,6 +1524,12 @@ static int icv_drop_prio(GICv3CPUState *cs)
|
|||
continue;
|
||||
}
|
||||
|
||||
if (i == 0 && cs->nmi_support && (*papr1 & ICV_AP1R_EL1_NMI)) {
|
||||
*papr1 &= (~ICV_AP1R_EL1_NMI);
|
||||
*nmi = true;
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
/* We can't just use the bit-twiddling hack icc_drop_prio() does
|
||||
* because we need to return the bit number we cleared so
|
||||
* it can be compared against the list register's priority field.
|
||||
|
@ -1410,6 +1589,7 @@ static void icv_eoir_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
|||
int irq = value & 0xffffff;
|
||||
int grp = ri->crm == 8 ? GICV3_G0 : GICV3_G1NS;
|
||||
int idx, dropprio;
|
||||
bool nmi = false;
|
||||
|
||||
trace_gicv3_icv_eoir_write(ri->crm == 8 ? 0 : 1,
|
||||
gicv3_redist_affid(cs), value);
|
||||
|
@ -1422,8 +1602,8 @@ static void icv_eoir_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
|||
* error checks" (because that lets us avoid scanning the AP
|
||||
* registers twice).
|
||||
*/
|
||||
dropprio = icv_drop_prio(cs);
|
||||
if (dropprio == 0xff) {
|
||||
dropprio = icv_drop_prio(cs, &nmi);
|
||||
if (dropprio == 0xff && !nmi) {
|
||||
/* No active interrupt. It is CONSTRAINED UNPREDICTABLE
|
||||
* whether the list registers are checked in this
|
||||
* situation; we choose not to.
|
||||
|
@ -1445,8 +1625,9 @@ static void icv_eoir_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
|||
uint64_t lr = cs->ich_lr_el2[idx];
|
||||
int thisgrp = (lr & ICH_LR_EL2_GROUP) ? GICV3_G1NS : GICV3_G0;
|
||||
int lr_gprio = ich_lr_prio(lr) & icv_gprio_mask(cs, grp);
|
||||
bool thisnmi = lr & ICH_LR_EL2_NMI;
|
||||
|
||||
if (thisgrp == grp && lr_gprio == dropprio) {
|
||||
if (thisgrp == grp && (lr_gprio == dropprio || (thisnmi & nmi))) {
|
||||
if (!icv_eoi_split(env, cs) || irq >= GICV3_LPI_INTID_START) {
|
||||
/*
|
||||
* Priority drop and deactivate not split: deactivate irq now.
|
||||
|
@ -1693,7 +1874,11 @@ static void icc_ap_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
|||
return;
|
||||
}
|
||||
|
||||
cs->icc_apr[grp][regno] = value & 0xFFFFFFFFU;
|
||||
if (cs->nmi_support) {
|
||||
cs->icc_apr[grp][regno] = value & (0xFFFFFFFFU | ICC_AP1R_EL1_NMI);
|
||||
} else {
|
||||
cs->icc_apr[grp][regno] = value & 0xFFFFFFFFU;
|
||||
}
|
||||
gicv3_cpuif_update(cs);
|
||||
}
|
||||
|
||||
|
@ -1783,7 +1968,7 @@ static void icc_dir_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
|||
static uint64_t icc_rpr_read(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||
{
|
||||
GICv3CPUState *cs = icc_cs_from_env(env);
|
||||
int prio;
|
||||
uint64_t prio;
|
||||
|
||||
if (icv_access(env, HCR_FMO | HCR_IMO)) {
|
||||
return icv_rpr_read(env, ri);
|
||||
|
@ -1803,6 +1988,22 @@ static uint64_t icc_rpr_read(CPUARMState *env, const ARMCPRegInfo *ri)
|
|||
}
|
||||
}
|
||||
|
||||
if (cs->nmi_support) {
|
||||
/* NMI info is reported in the high bits of RPR */
|
||||
if (arm_feature(env, ARM_FEATURE_EL3) && !arm_is_secure(env)) {
|
||||
if (cs->icc_apr[GICV3_G1NS][0] & ICC_AP1R_EL1_NMI) {
|
||||
prio |= ICC_RPR_EL1_NMI;
|
||||
}
|
||||
} else {
|
||||
if (cs->icc_apr[GICV3_G1NS][0] & ICC_AP1R_EL1_NMI) {
|
||||
prio |= ICC_RPR_EL1_NSNMI;
|
||||
}
|
||||
if (cs->icc_apr[GICV3_G1][0] & ICC_AP1R_EL1_NMI) {
|
||||
prio |= ICC_RPR_EL1_NMI;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
trace_gicv3_icc_rpr_read(gicv3_redist_affid(cs), prio);
|
||||
return prio;
|
||||
}
|
||||
|
@ -2482,6 +2683,15 @@ static const ARMCPRegInfo gicv3_cpuif_icc_apxr23_reginfo[] = {
|
|||
},
|
||||
};
|
||||
|
||||
static const ARMCPRegInfo gicv3_cpuif_gicv3_nmi_reginfo[] = {
|
||||
{ .name = "ICC_NMIAR1_EL1", .state = ARM_CP_STATE_BOTH,
|
||||
.opc0 = 3, .opc1 = 0, .crn = 12, .crm = 9, .opc2 = 5,
|
||||
.type = ARM_CP_IO | ARM_CP_NO_RAW,
|
||||
.access = PL1_R, .accessfn = gicv3_irq_access,
|
||||
.readfn = icc_nmiar1_read,
|
||||
},
|
||||
};
|
||||
|
||||
static uint64_t ich_ap_read(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||
{
|
||||
GICv3CPUState *cs = icc_cs_from_env(env);
|
||||
|
@ -2503,7 +2713,11 @@ static void ich_ap_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
|||
|
||||
trace_gicv3_ich_ap_write(ri->crm & 1, regno, gicv3_redist_affid(cs), value);
|
||||
|
||||
cs->ich_apr[grp][regno] = value & 0xFFFFFFFFU;
|
||||
if (cs->nmi_support) {
|
||||
cs->ich_apr[grp][regno] = value & (0xFFFFFFFFU | ICV_AP1R_EL1_NMI);
|
||||
} else {
|
||||
cs->ich_apr[grp][regno] = value & 0xFFFFFFFFU;
|
||||
}
|
||||
gicv3_cpuif_virt_irq_fiq_update(cs);
|
||||
}
|
||||
|
||||
|
@ -2620,6 +2834,11 @@ static void ich_lr_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
|||
8 - cs->vpribits, 0);
|
||||
}
|
||||
|
||||
/* Enforce RES0 bit in NMI field when FEAT_GICv3_NMI is not implemented */
|
||||
if (!cs->nmi_support) {
|
||||
value &= ~ICH_LR_EL2_NMI;
|
||||
}
|
||||
|
||||
cs->ich_lr_el2[regno] = value;
|
||||
gicv3_cpuif_virt_update(cs);
|
||||
}
|
||||
|
@ -2838,6 +3057,19 @@ void gicv3_init_cpuif(GICv3State *s)
|
|||
*/
|
||||
define_arm_cp_regs(cpu, gicv3_cpuif_reginfo);
|
||||
|
||||
/*
|
||||
* If the CPU implements FEAT_NMI and FEAT_GICv3 it must also
|
||||
* implement FEAT_GICv3_NMI, which is the CPU interface part
|
||||
* of NMI support. This is distinct from whether the GIC proper
|
||||
* (redistributors and distributor) have NMI support. In QEMU
|
||||
* that is a property of the GIC device in s->nmi_support;
|
||||
* cs->nmi_support indicates the CPU interface's support.
|
||||
*/
|
||||
if (cpu_isar_feature(aa64_nmi, cpu)) {
|
||||
cs->nmi_support = true;
|
||||
define_arm_cp_regs(cpu, gicv3_cpuif_gicv3_nmi_reginfo);
|
||||
}
|
||||
|
||||
/*
|
||||
* The CPU implementation specifies the number of supported
|
||||
* bits of physical priority. For backwards compatibility
|
||||
|
|
|
@ -89,6 +89,29 @@ static int gicd_ns_access(GICv3State *s, int irq)
|
|||
return extract32(s->gicd_nsacr[irq / 16], (irq % 16) * 2, 2);
|
||||
}
|
||||
|
||||
static void gicd_write_bitmap_reg(GICv3State *s, MemTxAttrs attrs,
|
||||
uint32_t *bmp, maskfn *maskfn,
|
||||
int offset, uint32_t val)
|
||||
{
|
||||
/*
|
||||
* Helper routine to implement writing to a "set" register
|
||||
* (GICD_INMIR, etc).
|
||||
* Semantics implemented here:
|
||||
* RAZ/WI for SGIs, PPIs, unimplemented IRQs
|
||||
* Bits corresponding to Group 0 or Secure Group 1 interrupts RAZ/WI.
|
||||
* offset should be the offset in bytes of the register from the start
|
||||
* of its group.
|
||||
*/
|
||||
int irq = offset * 8;
|
||||
|
||||
if (irq < GIC_INTERNAL || irq >= s->num_irq) {
|
||||
return;
|
||||
}
|
||||
val &= mask_group_and_nsacr(s, attrs, maskfn, irq);
|
||||
*gic_bmp_ptr32(bmp, irq) = val;
|
||||
gicv3_update(s, irq, 32);
|
||||
}
|
||||
|
||||
static void gicd_write_set_bitmap_reg(GICv3State *s, MemTxAttrs attrs,
|
||||
uint32_t *bmp,
|
||||
maskfn *maskfn,
|
||||
|
@ -389,6 +412,7 @@ static bool gicd_readl(GICv3State *s, hwaddr offset,
|
|||
* by GICD_TYPER.IDbits)
|
||||
* MBIS == 0 (message-based SPIs not supported)
|
||||
* SecurityExtn == 1 if security extns supported
|
||||
* NMI = 1 if Non-maskable interrupt property is supported
|
||||
* CPUNumber == 0 since for us ARE is always 1
|
||||
* ITLinesNumber == (((max SPI IntID + 1) / 32) - 1)
|
||||
*/
|
||||
|
@ -402,6 +426,7 @@ static bool gicd_readl(GICv3State *s, hwaddr offset,
|
|||
bool dvis = s->revision >= 4;
|
||||
|
||||
*data = (1 << 25) | (1 << 24) | (dvis << 18) | (sec_extn << 10) |
|
||||
(s->nmi_support << GICD_TYPER_NMI_SHIFT) |
|
||||
(s->lpi_enable << GICD_TYPER_LPIS_SHIFT) |
|
||||
(0xf << 19) | itlinesnumber;
|
||||
return true;
|
||||
|
@ -543,6 +568,11 @@ static bool gicd_readl(GICv3State *s, hwaddr offset,
|
|||
/* RAZ/WI since affinity routing is always enabled */
|
||||
*data = 0;
|
||||
return true;
|
||||
case GICD_INMIR ... GICD_INMIR + 0x7f:
|
||||
*data = (!s->nmi_support) ? 0 :
|
||||
gicd_read_bitmap_reg(s, attrs, s->nmi, NULL,
|
||||
offset - GICD_INMIR);
|
||||
return true;
|
||||
case GICD_IROUTER ... GICD_IROUTER + 0x1fdf:
|
||||
{
|
||||
uint64_t r;
|
||||
|
@ -752,6 +782,12 @@ static bool gicd_writel(GICv3State *s, hwaddr offset,
|
|||
case GICD_SPENDSGIR ... GICD_SPENDSGIR + 0xf:
|
||||
/* RAZ/WI since affinity routing is always enabled */
|
||||
return true;
|
||||
case GICD_INMIR ... GICD_INMIR + 0x7f:
|
||||
if (s->nmi_support) {
|
||||
gicd_write_bitmap_reg(s, attrs, s->nmi, NULL,
|
||||
offset - GICD_INMIR, value);
|
||||
}
|
||||
return true;
|
||||
case GICD_IROUTER ... GICD_IROUTER + 0x1fdf:
|
||||
{
|
||||
uint64_t r;
|
||||
|
|
|
@ -1950,13 +1950,13 @@ static void gicv3_arm_its_realize(DeviceState *dev, Error **errp)
|
|||
}
|
||||
}
|
||||
|
||||
static void gicv3_its_reset_hold(Object *obj)
|
||||
static void gicv3_its_reset_hold(Object *obj, ResetType type)
|
||||
{
|
||||
GICv3ITSState *s = ARM_GICV3_ITS_COMMON(obj);
|
||||
GICv3ITSClass *c = ARM_GICV3_ITS_GET_CLASS(s);
|
||||
|
||||
if (c->parent_phases.hold) {
|
||||
c->parent_phases.hold(obj);
|
||||
c->parent_phases.hold(obj, type);
|
||||
}
|
||||
|
||||
/* Quiescent bit reset to 1 */
|
||||
|
|
|
@ -123,7 +123,7 @@ void gicv3_its_init_mmio(GICv3ITSState *s, const MemoryRegionOps *ops,
|
|||
msi_nonbroken = true;
|
||||
}
|
||||
|
||||
static void gicv3_its_common_reset_hold(Object *obj)
|
||||
static void gicv3_its_common_reset_hold(Object *obj, ResetType type)
|
||||
{
|
||||
GICv3ITSState *s = ARM_GICV3_ITS_COMMON(obj);
|
||||
|
||||
|
|
|
@ -197,14 +197,14 @@ static void kvm_arm_its_post_load(GICv3ITSState *s)
|
|||
GITS_CTLR, &s->ctlr, true, &error_abort);
|
||||
}
|
||||
|
||||
static void kvm_arm_its_reset_hold(Object *obj)
|
||||
static void kvm_arm_its_reset_hold(Object *obj, ResetType type)
|
||||
{
|
||||
GICv3ITSState *s = ARM_GICV3_ITS_COMMON(obj);
|
||||
KVMARMITSClass *c = KVM_ARM_ITS_GET_CLASS(s);
|
||||
int i;
|
||||
|
||||
if (c->parent_phases.hold) {
|
||||
c->parent_phases.hold(obj);
|
||||
c->parent_phases.hold(obj, type);
|
||||
}
|
||||
|
||||
if (kvm_device_check_attr(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL,
|
||||
|
|
|
@ -703,7 +703,7 @@ static void arm_gicv3_icc_reset(CPUARMState *env, const ARMCPRegInfo *ri)
|
|||
c->icc_ctlr_el1[GICV3_S] = c->icc_ctlr_el1[GICV3_NS];
|
||||
}
|
||||
|
||||
static void kvm_arm_gicv3_reset_hold(Object *obj)
|
||||
static void kvm_arm_gicv3_reset_hold(Object *obj, ResetType type)
|
||||
{
|
||||
GICv3State *s = ARM_GICV3_COMMON(obj);
|
||||
KVMARMGICv3Class *kgc = KVM_ARM_GICV3_GET_CLASS(s);
|
||||
|
@ -711,7 +711,7 @@ static void kvm_arm_gicv3_reset_hold(Object *obj)
|
|||
DPRINTF("Reset\n");
|
||||
|
||||
if (kgc->parent_phases.hold) {
|
||||
kgc->parent_phases.hold(obj);
|
||||
kgc->parent_phases.hold(obj, type);
|
||||
}
|
||||
|
||||
if (s->migration_blocker) {
|
||||
|
@ -805,6 +805,11 @@ static void kvm_arm_gicv3_realize(DeviceState *dev, Error **errp)
|
|||
return;
|
||||
}
|
||||
|
||||
if (s->nmi_support) {
|
||||
error_setg(errp, "NMI is not supported with the in-kernel GIC");
|
||||
return;
|
||||
}
|
||||
|
||||
gicv3_init_irqs_and_mmio(s, kvm_arm_gicv3_set_irq, NULL);
|
||||
|
||||
for (i = 0; i < s->num_cpu; i++) {
|
||||
|
|
|
@ -35,6 +35,15 @@ static int gicr_ns_access(GICv3CPUState *cs, int irq)
|
|||
return extract32(cs->gicr_nsacr, irq * 2, 2);
|
||||
}
|
||||
|
||||
static void gicr_write_bitmap_reg(GICv3CPUState *cs, MemTxAttrs attrs,
|
||||
uint32_t *reg, uint32_t val)
|
||||
{
|
||||
/* Helper routine to implement writing to a "set" register */
|
||||
val &= mask_group(cs, attrs);
|
||||
*reg = val;
|
||||
gicv3_redist_update(cs);
|
||||
}
|
||||
|
||||
static void gicr_write_set_bitmap_reg(GICv3CPUState *cs, MemTxAttrs attrs,
|
||||
uint32_t *reg, uint32_t val)
|
||||
{
|
||||
|
@ -111,6 +120,7 @@ static void update_for_one_lpi(GICv3CPUState *cs, int irq,
|
|||
((prio == hpp->prio) && (irq <= hpp->irq))) {
|
||||
hpp->irq = irq;
|
||||
hpp->prio = prio;
|
||||
hpp->nmi = false;
|
||||
/* LPIs and vLPIs are always non-secure Grp1 interrupts */
|
||||
hpp->grp = GICV3_G1NS;
|
||||
}
|
||||
|
@ -147,6 +157,7 @@ static void update_for_all_lpis(GICv3CPUState *cs, uint64_t ptbase,
|
|||
int i, bit;
|
||||
|
||||
hpp->prio = 0xff;
|
||||
hpp->nmi = false;
|
||||
|
||||
for (i = GICV3_LPI_INTID_START / 8; i < pendt_size / 8; i++) {
|
||||
address_space_read(as, ptbase + i, MEMTXATTRS_UNSPECIFIED, &pend, 1);
|
||||
|
@ -232,6 +243,7 @@ static void gicv3_redist_update_vlpi_only(GICv3CPUState *cs)
|
|||
|
||||
if (!FIELD_EX64(cs->gicr_vpendbaser, GICR_VPENDBASER, VALID)) {
|
||||
cs->hppvlpi.prio = 0xff;
|
||||
cs->hppvlpi.nmi = false;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -406,6 +418,10 @@ static MemTxResult gicr_readl(GICv3CPUState *cs, hwaddr offset,
|
|||
*data = value;
|
||||
return MEMTX_OK;
|
||||
}
|
||||
case GICR_INMIR0:
|
||||
*data = cs->gic->nmi_support ?
|
||||
gicr_read_bitmap_reg(cs, attrs, cs->gicr_inmir0) : 0;
|
||||
return MEMTX_OK;
|
||||
case GICR_ICFGR0:
|
||||
case GICR_ICFGR1:
|
||||
{
|
||||
|
@ -555,6 +571,12 @@ static MemTxResult gicr_writel(GICv3CPUState *cs, hwaddr offset,
|
|||
gicv3_redist_update(cs);
|
||||
return MEMTX_OK;
|
||||
}
|
||||
case GICR_INMIR0:
|
||||
if (cs->gic->nmi_support) {
|
||||
gicr_write_bitmap_reg(cs, attrs, &cs->gicr_inmir0, value);
|
||||
}
|
||||
return MEMTX_OK;
|
||||
|
||||
case GICR_ICFGR0:
|
||||
/* Register is all RAZ/WI or RAO/WI bits */
|
||||
return MEMTX_OK;
|
||||
|
|
|
@ -52,6 +52,8 @@
|
|||
#define GICD_SGIR 0x0F00
|
||||
#define GICD_CPENDSGIR 0x0F10
|
||||
#define GICD_SPENDSGIR 0x0F20
|
||||
#define GICD_INMIR 0x0F80
|
||||
#define GICD_INMIRnE 0x3B00
|
||||
#define GICD_IROUTER 0x6000
|
||||
#define GICD_IDREGS 0xFFD0
|
||||
|
||||
|
@ -68,6 +70,7 @@
|
|||
#define GICD_CTLR_E1NWF (1U << 7)
|
||||
#define GICD_CTLR_RWP (1U << 31)
|
||||
|
||||
#define GICD_TYPER_NMI_SHIFT 9
|
||||
#define GICD_TYPER_LPIS_SHIFT 17
|
||||
|
||||
/* 16 bits EventId */
|
||||
|
@ -109,6 +112,7 @@
|
|||
#define GICR_ICFGR1 (GICR_SGI_OFFSET + 0x0C04)
|
||||
#define GICR_IGRPMODR0 (GICR_SGI_OFFSET + 0x0D00)
|
||||
#define GICR_NSACR (GICR_SGI_OFFSET + 0x0E00)
|
||||
#define GICR_INMIR0 (GICR_SGI_OFFSET + 0x0F80)
|
||||
|
||||
/* VLPI redistributor registers, offsets from VLPI_base */
|
||||
#define GICR_VPROPBASER (GICR_VLPI_OFFSET + 0x70)
|
||||
|
@ -190,6 +194,10 @@ FIELD(GICR_VPENDBASER, VALID, 63, 1)
|
|||
#define ICC_CTLR_EL3_A3V (1U << 15)
|
||||
#define ICC_CTLR_EL3_NDS (1U << 17)
|
||||
|
||||
#define ICC_AP1R_EL1_NMI (1ULL << 63)
|
||||
#define ICC_RPR_EL1_NSNMI (1ULL << 62)
|
||||
#define ICC_RPR_EL1_NMI (1ULL << 63)
|
||||
|
||||
#define ICH_VMCR_EL2_VENG0_SHIFT 0
|
||||
#define ICH_VMCR_EL2_VENG0 (1U << ICH_VMCR_EL2_VENG0_SHIFT)
|
||||
#define ICH_VMCR_EL2_VENG1_SHIFT 1
|
||||
|
@ -238,6 +246,7 @@ FIELD(GICR_VPENDBASER, VALID, 63, 1)
|
|||
#define ICH_LR_EL2_PRIORITY_SHIFT 48
|
||||
#define ICH_LR_EL2_PRIORITY_LENGTH 8
|
||||
#define ICH_LR_EL2_PRIORITY_MASK (0xffULL << ICH_LR_EL2_PRIORITY_SHIFT)
|
||||
#define ICH_LR_EL2_NMI (1ULL << 59)
|
||||
#define ICH_LR_EL2_GROUP (1ULL << 60)
|
||||
#define ICH_LR_EL2_HW (1ULL << 61)
|
||||
#define ICH_LR_EL2_STATE_SHIFT 62
|
||||
|
@ -269,6 +278,9 @@ FIELD(GICR_VPENDBASER, VALID, 63, 1)
|
|||
#define ICH_VTR_EL2_PREBITS_SHIFT 26
|
||||
#define ICH_VTR_EL2_PRIBITS_SHIFT 29
|
||||
|
||||
#define ICV_AP1R_EL1_NMI (1ULL << 63)
|
||||
#define ICV_RPR_EL1_NMI (1ULL << 63)
|
||||
|
||||
/* ITS Registers */
|
||||
|
||||
FIELD(GITS_BASER, SIZE, 0, 8)
|
||||
|
@ -507,6 +519,7 @@ FIELD(VTE, RDBASE, 42, RDBASE_PROCNUM_LENGTH)
|
|||
/* Special interrupt IDs */
|
||||
#define INTID_SECURE 1020
|
||||
#define INTID_NONSECURE 1021
|
||||
#define INTID_NMI 1022
|
||||
#define INTID_SPURIOUS 1023
|
||||
|
||||
/* Functions internal to the emulated GICv3 */
|
||||
|
|
|
@ -116,6 +116,7 @@ gicv3_cpuif_set_irqs(uint32_t cpuid, int fiqlevel, int irqlevel) "GICv3 CPU i/f
|
|||
gicv3_icc_generate_sgi(uint32_t cpuid, int irq, int irm, uint32_t aff, uint32_t targetlist) "GICv3 CPU i/f 0x%x generating SGI %d IRM %d target affinity 0x%xxx targetlist 0x%x"
|
||||
gicv3_icc_iar0_read(uint32_t cpu, uint64_t val) "GICv3 ICC_IAR0 read cpu 0x%x value 0x%" PRIx64
|
||||
gicv3_icc_iar1_read(uint32_t cpu, uint64_t val) "GICv3 ICC_IAR1 read cpu 0x%x value 0x%" PRIx64
|
||||
gicv3_icc_nmiar1_read(uint32_t cpu, uint64_t val) "GICv3 ICC_NMIAR1 read cpu 0x%x value 0x%" PRIx64
|
||||
gicv3_icc_eoir_write(int grp, uint32_t cpu, uint64_t val) "GICv3 ICC_EOIR%d write cpu 0x%x value 0x%" PRIx64
|
||||
gicv3_icc_hppir0_read(uint32_t cpu, uint64_t val) "GICv3 ICC_HPPIR0 read cpu 0x%x value 0x%" PRIx64
|
||||
gicv3_icc_hppir1_read(uint32_t cpu, uint64_t val) "GICv3 ICC_HPPIR1 read cpu 0x%x value 0x%" PRIx64
|
||||
|
@ -151,6 +152,7 @@ gicv3_icv_rpr_read(uint32_t cpu, uint64_t val) "GICv3 ICV_RPR read cpu 0x%x valu
|
|||
gicv3_icv_hppir_read(int grp, uint32_t cpu, uint64_t val) "GICv3 ICV_HPPIR%d read cpu 0x%x value 0x%" PRIx64
|
||||
gicv3_icv_dir_write(uint32_t cpu, uint64_t val) "GICv3 ICV_DIR write cpu 0x%x value 0x%" PRIx64
|
||||
gicv3_icv_iar_read(int grp, uint32_t cpu, uint64_t val) "GICv3 ICV_IAR%d read cpu 0x%x value 0x%" PRIx64
|
||||
gicv3_icv_nmiar1_read(uint32_t cpu, uint64_t val) "GICv3 ICV_NMIAR1 read cpu 0x%x value 0x%" PRIx64
|
||||
gicv3_icv_eoir_write(int grp, uint32_t cpu, uint64_t val) "GICv3 ICV_EOIR%d write cpu 0x%x value 0x%" PRIx64
|
||||
gicv3_cpuif_virt_update(uint32_t cpuid, int idx, int hppvlpi, int grp, int prio) "GICv3 CPU i/f 0x%x virt HPPI update LR index %d HPPVLPI %d grp %d prio %d"
|
||||
gicv3_cpuif_virt_set_irqs(uint32_t cpuid, int fiqlevel, int irqlevel) "GICv3 CPU i/f 0x%x virt HPPI update: setting FIQ %d IRQ %d"
|
||||
|
|
|
@ -579,7 +579,7 @@ static void ics_reset_irq(ICSIRQState *irq)
|
|||
irq->saved_priority = 0xff;
|
||||
}
|
||||
|
||||
static void ics_reset_hold(Object *obj)
|
||||
static void ics_reset_hold(Object *obj, ResetType type)
|
||||
{
|
||||
ICSState *ics = ICS(obj);
|
||||
g_autofree uint8_t *flags = g_malloc(ics->nr_irqs);
|
||||
|
|
|
@ -175,7 +175,7 @@ static void glue_nmi_release(void *opaque)
|
|||
GLUE_set_irq(s, GLUE_IRQ_IN_NMI, 0);
|
||||
}
|
||||
|
||||
static void glue_reset_hold(Object *obj)
|
||||
static void glue_reset_hold(Object *obj, ResetType type)
|
||||
{
|
||||
GLUEState *s = GLUE(obj);
|
||||
|
||||
|
|
|
@ -96,7 +96,7 @@ static void djmemc_init(Object *obj)
|
|||
sysbus_init_mmio(sbd, &s->mem_regs);
|
||||
}
|
||||
|
||||
static void djmemc_reset_hold(Object *obj)
|
||||
static void djmemc_reset_hold(Object *obj, ResetType type)
|
||||
{
|
||||
DJMEMCState *s = DJMEMC(obj);
|
||||
|
||||
|
|
|
@ -81,7 +81,7 @@ static const MemoryRegionOps iosb_mmio_ops = {
|
|||
.endianness = DEVICE_BIG_ENDIAN,
|
||||
};
|
||||
|
||||
static void iosb_reset_hold(Object *obj)
|
||||
static void iosb_reset_hold(Object *obj, ResetType type)
|
||||
{
|
||||
IOSBState *s = IOSB(obj);
|
||||
|
||||
|
|
|
@ -1203,7 +1203,7 @@ static int via1_post_load(void *opaque, int version_id)
|
|||
}
|
||||
|
||||
/* VIA 1 */
|
||||
static void mos6522_q800_via1_reset_hold(Object *obj)
|
||||
static void mos6522_q800_via1_reset_hold(Object *obj, ResetType type)
|
||||
{
|
||||
MOS6522Q800VIA1State *v1s = MOS6522_Q800_VIA1(obj);
|
||||
MOS6522State *ms = MOS6522(v1s);
|
||||
|
@ -1211,7 +1211,7 @@ static void mos6522_q800_via1_reset_hold(Object *obj)
|
|||
ADBBusState *adb_bus = &v1s->adb_bus;
|
||||
|
||||
if (mdc->parent_phases.hold) {
|
||||
mdc->parent_phases.hold(obj);
|
||||
mdc->parent_phases.hold(obj, type);
|
||||
}
|
||||
|
||||
ms->timers[0].frequency = VIA_TIMER_FREQ;
|
||||
|
@ -1359,13 +1359,13 @@ static void mos6522_q800_via2_portB_write(MOS6522State *s)
|
|||
}
|
||||
}
|
||||
|
||||
static void mos6522_q800_via2_reset_hold(Object *obj)
|
||||
static void mos6522_q800_via2_reset_hold(Object *obj, ResetType type)
|
||||
{
|
||||
MOS6522State *ms = MOS6522(obj);
|
||||
MOS6522DeviceClass *mdc = MOS6522_GET_CLASS(ms);
|
||||
|
||||
if (mdc->parent_phases.hold) {
|
||||
mdc->parent_phases.hold(obj);
|
||||
mdc->parent_phases.hold(obj, type);
|
||||
}
|
||||
|
||||
ms->timers[0].frequency = VIA_TIMER_FREQ;
|
||||
|
|
|
@ -586,13 +586,13 @@ static void mos6522_cuda_portB_write(MOS6522State *s)
|
|||
cuda_update(cs);
|
||||
}
|
||||
|
||||
static void mos6522_cuda_reset_hold(Object *obj)
|
||||
static void mos6522_cuda_reset_hold(Object *obj, ResetType type)
|
||||
{
|
||||
MOS6522State *ms = MOS6522(obj);
|
||||
MOS6522DeviceClass *mdc = MOS6522_GET_CLASS(ms);
|
||||
|
||||
if (mdc->parent_phases.hold) {
|
||||
mdc->parent_phases.hold(obj);
|
||||
mdc->parent_phases.hold(obj, type);
|
||||
}
|
||||
|
||||
ms->timers[0].frequency = CUDA_TIMER_FREQ;
|
||||
|
|
|
@ -792,7 +792,7 @@ static void mos6522_pmu_portB_write(MOS6522State *s)
|
|||
pmu_update(ps);
|
||||
}
|
||||
|
||||
static void mos6522_pmu_reset_hold(Object *obj)
|
||||
static void mos6522_pmu_reset_hold(Object *obj, ResetType type)
|
||||
{
|
||||
MOS6522State *ms = MOS6522(obj);
|
||||
MOS6522PMUState *mps = container_of(ms, MOS6522PMUState, parent_obj);
|
||||
|
@ -800,7 +800,7 @@ static void mos6522_pmu_reset_hold(Object *obj)
|
|||
MOS6522DeviceClass *mdc = MOS6522_GET_CLASS(ms);
|
||||
|
||||
if (mdc->parent_phases.hold) {
|
||||
mdc->parent_phases.hold(obj);
|
||||
mdc->parent_phases.hold(obj, type);
|
||||
}
|
||||
|
||||
ms->timers[0].frequency = VIA_TIMER_FREQ;
|
||||
|
|
|
@ -642,7 +642,7 @@ const VMStateDescription vmstate_mos6522 = {
|
|||
}
|
||||
};
|
||||
|
||||
static void mos6522_reset_hold(Object *obj)
|
||||
static void mos6522_reset_hold(Object *obj, ResetType type)
|
||||
{
|
||||
MOS6522State *s = MOS6522(obj);
|
||||
|
||||
|
|
|
@ -873,20 +873,13 @@ static void npcm7xx_clk_enter_reset(Object *obj, ResetType type)
|
|||
|
||||
QEMU_BUILD_BUG_ON(sizeof(s->regs) != sizeof(cold_reset_values));
|
||||
|
||||
switch (type) {
|
||||
case RESET_TYPE_COLD:
|
||||
memcpy(s->regs, cold_reset_values, sizeof(cold_reset_values));
|
||||
s->ref_ns = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
||||
npcm7xx_clk_update_all_clocks(s);
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(s->regs, cold_reset_values, sizeof(cold_reset_values));
|
||||
s->ref_ns = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
||||
npcm7xx_clk_update_all_clocks(s);
|
||||
/*
|
||||
* A small number of registers need to be reset on a core domain reset,
|
||||
* but no such reset type exists yet.
|
||||
*/
|
||||
qemu_log_mask(LOG_UNIMP, "%s: reset type %d not implemented.",
|
||||
__func__, type);
|
||||
}
|
||||
|
||||
static void npcm7xx_clk_init_clock_hierarchy(NPCM7xxCLKState *s)
|
||||
|
|
|
@ -159,14 +159,10 @@ static void npcm7xx_gcr_enter_reset(Object *obj, ResetType type)
|
|||
|
||||
QEMU_BUILD_BUG_ON(sizeof(s->regs) != sizeof(cold_reset_values));
|
||||
|
||||
switch (type) {
|
||||
case RESET_TYPE_COLD:
|
||||
memcpy(s->regs, cold_reset_values, sizeof(s->regs));
|
||||
s->regs[NPCM7XX_GCR_PWRON] = s->reset_pwron;
|
||||
s->regs[NPCM7XX_GCR_MDLR] = s->reset_mdlr;
|
||||
s->regs[NPCM7XX_GCR_INTCR3] = s->reset_intcr3;
|
||||
break;
|
||||
}
|
||||
memcpy(s->regs, cold_reset_values, sizeof(s->regs));
|
||||
s->regs[NPCM7XX_GCR_PWRON] = s->reset_pwron;
|
||||
s->regs[NPCM7XX_GCR_MDLR] = s->reset_mdlr;
|
||||
s->regs[NPCM7XX_GCR_INTCR3] = s->reset_intcr3;
|
||||
}
|
||||
|
||||
static void npcm7xx_gcr_realize(DeviceState *dev, Error **errp)
|
||||
|
|
|
@ -467,7 +467,7 @@ static void npcm7xx_mft_enter_reset(Object *obj, ResetType type)
|
|||
npcm7xx_mft_reset(s);
|
||||
}
|
||||
|
||||
static void npcm7xx_mft_hold_reset(Object *obj)
|
||||
static void npcm7xx_mft_hold_reset(Object *obj, ResetType type)
|
||||
{
|
||||
NPCM7xxMFTState *s = NPCM7XX_MFT(obj);
|
||||
|
||||
|
|
|
@ -468,7 +468,7 @@ static void npcm7xx_pwm_enter_reset(Object *obj, ResetType type)
|
|||
s->piir = 0x00000000;
|
||||
}
|
||||
|
||||
static void npcm7xx_pwm_hold_reset(Object *obj)
|
||||
static void npcm7xx_pwm_hold_reset(Object *obj, ResetType type)
|
||||
{
|
||||
NPCM7xxPWMState *s = NPCM7XX_PWM(obj);
|
||||
int i;
|
||||
|
|
|
@ -77,7 +77,7 @@ static unsigned configurable_mask(unsigned bank)
|
|||
return valid_mask(bank) & ~exti_romask[bank];
|
||||
}
|
||||
|
||||
static void stm32l4x5_exti_reset_hold(Object *obj)
|
||||
static void stm32l4x5_exti_reset_hold(Object *obj, ResetType type)
|
||||
{
|
||||
Stm32l4x5ExtiState *s = STM32L4X5_EXTI(obj);
|
||||
|
||||
|
|
|
@ -113,13 +113,13 @@ static void clock_mux_reset_enter(Object *obj, ResetType type)
|
|||
set_clock_mux_init_info(s, s->id);
|
||||
}
|
||||
|
||||
static void clock_mux_reset_hold(Object *obj)
|
||||
static void clock_mux_reset_hold(Object *obj, ResetType type)
|
||||
{
|
||||
RccClockMuxState *s = RCC_CLOCK_MUX(obj);
|
||||
clock_mux_update(s, true);
|
||||
}
|
||||
|
||||
static void clock_mux_reset_exit(Object *obj)
|
||||
static void clock_mux_reset_exit(Object *obj, ResetType type)
|
||||
{
|
||||
RccClockMuxState *s = RCC_CLOCK_MUX(obj);
|
||||
clock_mux_update(s, false);
|
||||
|
@ -263,13 +263,13 @@ static void pll_reset_enter(Object *obj, ResetType type)
|
|||
set_pll_init_info(s, s->id);
|
||||
}
|
||||
|
||||
static void pll_reset_hold(Object *obj)
|
||||
static void pll_reset_hold(Object *obj, ResetType type)
|
||||
{
|
||||
RccPllState *s = RCC_PLL(obj);
|
||||
pll_update(s, true);
|
||||
}
|
||||
|
||||
static void pll_reset_exit(Object *obj)
|
||||
static void pll_reset_exit(Object *obj, ResetType type)
|
||||
{
|
||||
RccPllState *s = RCC_PLL(obj);
|
||||
pll_update(s, false);
|
||||
|
@ -907,7 +907,7 @@ static void rcc_update_csr(Stm32l4x5RccState *s)
|
|||
rcc_update_irq(s);
|
||||
}
|
||||
|
||||
static void stm32l4x5_rcc_reset_hold(Object *obj)
|
||||
static void stm32l4x5_rcc_reset_hold(Object *obj, ResetType type)
|
||||
{
|
||||
Stm32l4x5RccState *s = STM32L4X5_RCC(obj);
|
||||
s->cr = 0x00000063;
|
||||
|
|
|
@ -65,7 +65,7 @@
|
|||
|
||||
#define NUM_LINES_PER_EXTICR_REG 4
|
||||
|
||||
static void stm32l4x5_syscfg_hold_reset(Object *obj)
|
||||
static void stm32l4x5_syscfg_hold_reset(Object *obj, ResetType type)
|
||||
{
|
||||
Stm32l4x5SyscfgState *s = STM32L4X5_SYSCFG(obj);
|
||||
|
||||
|
|
|
@ -542,7 +542,7 @@ static void cframe_reg_reset_enter(Object *obj, ResetType type)
|
|||
}
|
||||
}
|
||||
|
||||
static void cframe_reg_reset_hold(Object *obj)
|
||||
static void cframe_reg_reset_hold(Object *obj, ResetType type)
|
||||
{
|
||||
XlnxVersalCFrameReg *s = XLNX_VERSAL_CFRAME_REG(obj);
|
||||
|
||||
|
|
|
@ -311,7 +311,7 @@ static void crl_reset_enter(Object *obj, ResetType type)
|
|||
}
|
||||
}
|
||||
|
||||
static void crl_reset_hold(Object *obj)
|
||||
static void crl_reset_hold(Object *obj, ResetType type)
|
||||
{
|
||||
XlnxVersalCRL *s = XLNX_VERSAL_CRL(obj);
|
||||
|
||||
|
|
|
@ -1350,7 +1350,7 @@ static void xlnx_versal_pmc_iou_slcr_reset_init(Object *obj, ResetType type)
|
|||
}
|
||||
}
|
||||
|
||||
static void xlnx_versal_pmc_iou_slcr_reset_hold(Object *obj)
|
||||
static void xlnx_versal_pmc_iou_slcr_reset_hold(Object *obj, ResetType type)
|
||||
{
|
||||
XlnxVersalPmcIouSlcr *s = XILINX_VERSAL_PMC_IOU_SLCR(obj);
|
||||
|
||||
|
|
|
@ -632,7 +632,7 @@ static void trng_unrealize(DeviceState *dev)
|
|||
s->prng = NULL;
|
||||
}
|
||||
|
||||
static void trng_reset_hold(Object *obj)
|
||||
static void trng_reset_hold(Object *obj, ResetType type)
|
||||
{
|
||||
trng_reset(XLNX_VERSAL_TRNG(obj));
|
||||
}
|
||||
|
|
|
@ -137,7 +137,7 @@ static void xram_ctrl_reset_enter(Object *obj, ResetType type)
|
|||
ARRAY_FIELD_DP32(s->regs, XRAM_IMP, SIZE, s->cfg.encoded_size);
|
||||
}
|
||||
|
||||
static void xram_ctrl_reset_hold(Object *obj)
|
||||
static void xram_ctrl_reset_hold(Object *obj, ResetType type)
|
||||
{
|
||||
XlnxXramCtrl *s = XLNX_XRAM_CTRL(obj);
|
||||
|
||||
|
|
|
@ -150,7 +150,7 @@ static void zynqmp_apu_reset_enter(Object *obj, ResetType type)
|
|||
s->cpu_in_wfi = 0;
|
||||
}
|
||||
|
||||
static void zynqmp_apu_reset_hold(Object *obj)
|
||||
static void zynqmp_apu_reset_hold(Object *obj, ResetType type)
|
||||
{
|
||||
XlnxZynqMPAPUCtrl *s = XLNX_ZYNQMP_APU_CTRL(obj);
|
||||
|
||||
|
|
|
@ -191,7 +191,7 @@ static void crf_reset_enter(Object *obj, ResetType type)
|
|||
}
|
||||
}
|
||||
|
||||
static void crf_reset_hold(Object *obj)
|
||||
static void crf_reset_hold(Object *obj, ResetType type)
|
||||
{
|
||||
XlnxZynqMPCRF *s = XLNX_ZYNQMP_CRF(obj);
|
||||
ir_update_irq(s);
|
||||
|
|
|
@ -416,7 +416,7 @@ static void zynq_slcr_reset_init(Object *obj, ResetType type)
|
|||
s->regs[R_DDRIOB + 12] = 0x00000021;
|
||||
}
|
||||
|
||||
static void zynq_slcr_reset_hold(Object *obj)
|
||||
static void zynq_slcr_reset_hold(Object *obj, ResetType type)
|
||||
{
|
||||
ZynqSLCRState *s = ZYNQ_SLCR(obj);
|
||||
|
||||
|
@ -425,7 +425,7 @@ static void zynq_slcr_reset_hold(Object *obj)
|
|||
zynq_slcr_propagate_clocks(s);
|
||||
}
|
||||
|
||||
static void zynq_slcr_reset_exit(Object *obj)
|
||||
static void zynq_slcr_reset_exit(Object *obj, ResetType type)
|
||||
{
|
||||
ZynqSLCRState *s = ZYNQ_SLCR(obj);
|
||||
|
||||
|
|
|
@ -1006,7 +1006,7 @@ static void xlnx_zynqmp_can_reset_init(Object *obj, ResetType type)
|
|||
ptimer_transaction_commit(s->can_timer);
|
||||
}
|
||||
|
||||
static void xlnx_zynqmp_can_reset_hold(Object *obj)
|
||||
static void xlnx_zynqmp_can_reset_hold(Object *obj, ResetType type)
|
||||
{
|
||||
XlnxZynqMPCANState *s = XLNX_ZYNQMP_CAN(obj);
|
||||
unsigned int i;
|
||||
|
|
|
@ -373,7 +373,7 @@ static bool e1000_vet_init_need(void *opaque)
|
|||
return chkflag(VET);
|
||||
}
|
||||
|
||||
static void e1000_reset_hold(Object *obj)
|
||||
static void e1000_reset_hold(Object *obj, ResetType type)
|
||||
{
|
||||
E1000State *d = E1000(obj);
|
||||
E1000BaseClass *edc = E1000_GET_CLASS(d);
|
||||
|
|
|
@ -513,7 +513,7 @@ static void e1000e_pci_uninit(PCIDevice *pci_dev)
|
|||
msi_uninit(pci_dev);
|
||||
}
|
||||
|
||||
static void e1000e_qdev_reset_hold(Object *obj)
|
||||
static void e1000e_qdev_reset_hold(Object *obj, ResetType type)
|
||||
{
|
||||
E1000EState *s = E1000E(obj);
|
||||
|
||||
|
|
|
@ -486,7 +486,7 @@ static void igb_pci_uninit(PCIDevice *pci_dev)
|
|||
msi_uninit(pci_dev);
|
||||
}
|
||||
|
||||
static void igb_qdev_reset_hold(Object *obj)
|
||||
static void igb_qdev_reset_hold(Object *obj, ResetType type)
|
||||
{
|
||||
IGBState *s = IGB(obj);
|
||||
|
||||
|
|
|
@ -282,7 +282,7 @@ static void igbvf_pci_realize(PCIDevice *dev, Error **errp)
|
|||
pcie_ari_init(dev, 0x150);
|
||||
}
|
||||
|
||||
static void igbvf_qdev_reset_hold(Object *obj)
|
||||
static void igbvf_qdev_reset_hold(Object *obj, ResetType type)
|
||||
{
|
||||
PCIDevice *vf = PCI_DEVICE(obj);
|
||||
|
||||
|
|
|
@ -417,7 +417,7 @@ static RegisterAccessInfo bbram_ctrl_regs_info[] = {
|
|||
}
|
||||
};
|
||||
|
||||
static void bbram_ctrl_reset_hold(Object *obj)
|
||||
static void bbram_ctrl_reset_hold(Object *obj, ResetType type)
|
||||
{
|
||||
XlnxBBRam *s = XLNX_BBRAM(obj);
|
||||
unsigned int i;
|
||||
|
|
|
@ -658,7 +658,7 @@ static void efuse_ctrl_register_reset(RegisterInfo *reg)
|
|||
register_reset(reg);
|
||||
}
|
||||
|
||||
static void efuse_ctrl_reset_hold(Object *obj)
|
||||
static void efuse_ctrl_reset_hold(Object *obj, ResetType type)
|
||||
{
|
||||
XlnxVersalEFuseCtrl *s = XLNX_VERSAL_EFUSE_CTRL(obj);
|
||||
unsigned int i;
|
||||
|
|
|
@ -770,7 +770,7 @@ static void zynqmp_efuse_register_reset(RegisterInfo *reg)
|
|||
register_reset(reg);
|
||||
}
|
||||
|
||||
static void zynqmp_efuse_reset_hold(Object *obj)
|
||||
static void zynqmp_efuse_reset_hold(Object *obj, ResetType type)
|
||||
{
|
||||
XlnxZynqMPEFuse *s = XLNX_ZYNQMP_EFUSE(obj);
|
||||
unsigned int i;
|
||||
|
|
|
@ -186,13 +186,13 @@ static void cxl_rp_realize(DeviceState *dev, Error **errp)
|
|||
component_bar);
|
||||
}
|
||||
|
||||
static void cxl_rp_reset_hold(Object *obj)
|
||||
static void cxl_rp_reset_hold(Object *obj, ResetType type)
|
||||
{
|
||||
PCIERootPortClass *rpc = PCIE_ROOT_PORT_GET_CLASS(obj);
|
||||
CXLRootPort *crp = CXL_ROOT_PORT(obj);
|
||||
|
||||
if (rpc->parent_phases.hold) {
|
||||
rpc->parent_phases.hold(obj);
|
||||
rpc->parent_phases.hold(obj, type);
|
||||
}
|
||||
|
||||
latch_registers(crp);
|
||||
|
|
|
@ -43,7 +43,7 @@ static void rp_write_config(PCIDevice *d, uint32_t address,
|
|||
pcie_aer_root_write_config(d, address, val, len, root_cmd);
|
||||
}
|
||||
|
||||
static void rp_reset_hold(Object *obj)
|
||||
static void rp_reset_hold(Object *obj, ResetType type)
|
||||
{
|
||||
PCIDevice *d = PCI_DEVICE(obj);
|
||||
DeviceState *qdev = DEVICE(obj);
|
||||
|
|
|
@ -590,7 +590,7 @@ static int pci_bonito_map_irq(PCIDevice *pci_dev, int irq_num)
|
|||
}
|
||||
}
|
||||
|
||||
static void bonito_reset_hold(Object *obj)
|
||||
static void bonito_reset_hold(Object *obj, ResetType type)
|
||||
{
|
||||
PCIBonitoState *s = PCI_BONITO(obj);
|
||||
uint32_t val = 0;
|
||||
|
|
|
@ -208,7 +208,7 @@ static void pnv_phb_class_init(ObjectClass *klass, void *data)
|
|||
dc->user_creatable = true;
|
||||
}
|
||||
|
||||
static void pnv_phb_root_port_reset_hold(Object *obj)
|
||||
static void pnv_phb_root_port_reset_hold(Object *obj, ResetType type)
|
||||
{
|
||||
PCIERootPortClass *rpc = PCIE_ROOT_PORT_GET_CLASS(obj);
|
||||
PnvPHBRootPort *phb_rp = PNV_PHB_ROOT_PORT(obj);
|
||||
|
@ -216,7 +216,7 @@ static void pnv_phb_root_port_reset_hold(Object *obj)
|
|||
uint8_t *conf = d->config;
|
||||
|
||||
if (rpc->parent_phases.hold) {
|
||||
rpc->parent_phases.hold(obj);
|
||||
rpc->parent_phases.hold(obj, type);
|
||||
}
|
||||
|
||||
if (phb_rp->version == 3) {
|
||||
|
|
|
@ -228,13 +228,13 @@ static void phb3_msi_resend(ICSState *ics)
|
|||
}
|
||||
}
|
||||
|
||||
static void phb3_msi_reset_hold(Object *obj)
|
||||
static void phb3_msi_reset_hold(Object *obj, ResetType type)
|
||||
{
|
||||
Phb3MsiState *msi = PHB3_MSI(obj);
|
||||
ICSStateClass *icsc = ICS_GET_CLASS(obj);
|
||||
|
||||
if (icsc->parent_phases.hold) {
|
||||
icsc->parent_phases.hold(obj);
|
||||
icsc->parent_phases.hold(obj, type);
|
||||
}
|
||||
|
||||
memset(msi->rba, 0, sizeof(msi->rba));
|
||||
|
|
|
@ -64,7 +64,7 @@ bool pci_available = true;
|
|||
|
||||
static char *pcibus_get_dev_path(DeviceState *dev);
|
||||
static char *pcibus_get_fw_dev_path(DeviceState *dev);
|
||||
static void pcibus_reset_hold(Object *obj);
|
||||
static void pcibus_reset_hold(Object *obj, ResetType type);
|
||||
static bool pcie_has_upstream_port(PCIDevice *dev);
|
||||
|
||||
static Property pci_props[] = {
|
||||
|
@ -427,7 +427,7 @@ void pci_device_reset(PCIDevice *dev)
|
|||
* Called via bus_cold_reset on RST# assert, after the devices
|
||||
* have been reset device_cold_reset-ed already.
|
||||
*/
|
||||
static void pcibus_reset_hold(Object *obj)
|
||||
static void pcibus_reset_hold(Object *obj, ResetType type)
|
||||
{
|
||||
PCIBus *bus = PCI_BUS(obj);
|
||||
int i;
|
||||
|
|
|
@ -998,7 +998,7 @@ static void rtc_reset_enter(Object *obj, ResetType type)
|
|||
}
|
||||
}
|
||||
|
||||
static void rtc_reset_hold(Object *obj)
|
||||
static void rtc_reset_hold(Object *obj, ResetType type)
|
||||
{
|
||||
MC146818RtcState *s = MC146818_RTC(obj);
|
||||
|
||||
|
|
|
@ -56,7 +56,7 @@ static void ccw_device_unplug(HotplugHandler *hotplug_dev,
|
|||
qdev_unrealize(dev);
|
||||
}
|
||||
|
||||
static void virtual_css_bus_reset_hold(Object *obj)
|
||||
static void virtual_css_bus_reset_hold(Object *obj, ResetType type)
|
||||
{
|
||||
/* This should actually be modelled via the generic css */
|
||||
css_reset();
|
||||
|
|
|
@ -76,7 +76,7 @@ static const uint8_t adm1266_ic_device_id[] = {0x03, 0x41, 0x12, 0x66};
|
|||
static const uint8_t adm1266_ic_device_rev[] = {0x08, 0x01, 0x08, 0x07, 0x0,
|
||||
0x0, 0x07, 0x41, 0x30};
|
||||
|
||||
static void adm1266_exit_reset(Object *obj)
|
||||
static void adm1266_exit_reset(Object *obj, ResetType type)
|
||||
{
|
||||
ADM1266State *s = ADM1266(obj);
|
||||
PMBusDevice *pmdev = PMBUS_DEVICE(obj);
|
||||
|
|
|
@ -185,7 +185,7 @@ static uint32_t adm1272_direct_to_watts(uint16_t value)
|
|||
return pmbus_direct_mode2data(c, value);
|
||||
}
|
||||
|
||||
static void adm1272_exit_reset(Object *obj)
|
||||
static void adm1272_exit_reset(Object *obj, ResetType type)
|
||||
{
|
||||
ADM1272State *s = ADM1272(obj);
|
||||
PMBusDevice *pmdev = PMBUS_DEVICE(obj);
|
||||
|
@ -386,7 +386,7 @@ static int adm1272_write_data(PMBusDevice *pmdev, const uint8_t *buf,
|
|||
break;
|
||||
|
||||
case ADM1272_MFR_POWER_CYCLE:
|
||||
adm1272_exit_reset((Object *)s);
|
||||
device_cold_reset(DEVICE(s));
|
||||
break;
|
||||
|
||||
case ADM1272_HYSTERESIS_LOW:
|
||||
|
|
|
@ -63,7 +63,7 @@ static void isl_pmbus_vr_set(Object *obj, Visitor *v, const char *name,
|
|||
pmbus_check_limits(pmdev);
|
||||
}
|
||||
|
||||
static void isl_pmbus_vr_exit_reset(Object *obj)
|
||||
static void isl_pmbus_vr_exit_reset(Object *obj, ResetType type)
|
||||
{
|
||||
PMBusDevice *pmdev = PMBUS_DEVICE(obj);
|
||||
|
||||
|
@ -102,11 +102,11 @@ static void isl_pmbus_vr_exit_reset(Object *obj)
|
|||
}
|
||||
|
||||
/* The raa228000 uses different direct mode coefficients from most isl devices */
|
||||
static void raa228000_exit_reset(Object *obj)
|
||||
static void raa228000_exit_reset(Object *obj, ResetType type)
|
||||
{
|
||||
PMBusDevice *pmdev = PMBUS_DEVICE(obj);
|
||||
|
||||
isl_pmbus_vr_exit_reset(obj);
|
||||
isl_pmbus_vr_exit_reset(obj, type);
|
||||
|
||||
pmdev->pages[0].read_iout = 0;
|
||||
pmdev->pages[0].read_pout = 0;
|
||||
|
@ -119,13 +119,13 @@ static void raa228000_exit_reset(Object *obj)
|
|||
pmdev->pages[0].read_temperature_3 = 0;
|
||||
}
|
||||
|
||||
static void isl69259_exit_reset(Object *obj)
|
||||
static void isl69259_exit_reset(Object *obj, ResetType type)
|
||||
{
|
||||
ISLState *s = ISL69260(obj);
|
||||
static const uint8_t ic_device_id[] = {0x04, 0x00, 0x81, 0xD2, 0x49, 0x3c};
|
||||
g_assert(sizeof(ic_device_id) <= sizeof(s->ic_device_id));
|
||||
|
||||
isl_pmbus_vr_exit_reset(obj);
|
||||
isl_pmbus_vr_exit_reset(obj, type);
|
||||
|
||||
s->ic_device_id_len = sizeof(ic_device_id);
|
||||
memcpy(s->ic_device_id, ic_device_id, sizeof(ic_device_id));
|
||||
|
|
|
@ -444,7 +444,7 @@ static int max31785_write_data(PMBusDevice *pmdev, const uint8_t *buf,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void max31785_exit_reset(Object *obj)
|
||||
static void max31785_exit_reset(Object *obj, ResetType type)
|
||||
{
|
||||
PMBusDevice *pmdev = PMBUS_DEVICE(obj);
|
||||
MAX31785State *s = MAX31785(obj);
|
||||
|
|
|
@ -608,7 +608,7 @@ static inline void *memset_word(void *s, uint16_t c, size_t n)
|
|||
return s;
|
||||
}
|
||||
|
||||
static void max34451_exit_reset(Object *obj)
|
||||
static void max34451_exit_reset(Object *obj, ResetType type)
|
||||
{
|
||||
PMBusDevice *pmdev = PMBUS_DEVICE(obj);
|
||||
MAX34451State *s = MAX34451(obj);
|
||||
|
|
|
@ -483,7 +483,7 @@ static void npcm7xx_fiu_enter_reset(Object *obj, ResetType type)
|
|||
s->regs[NPCM7XX_FIU_CFG] = 0x0000000b;
|
||||
}
|
||||
|
||||
static void npcm7xx_fiu_hold_reset(Object *obj)
|
||||
static void npcm7xx_fiu_hold_reset(Object *obj, ResetType type)
|
||||
{
|
||||
NPCM7xxFIUState *s = NPCM7XX_FIU(obj);
|
||||
int i;
|
||||
|
|
|
@ -357,7 +357,7 @@ static void etraxfs_timer_reset_enter(Object *obj, ResetType type)
|
|||
t->rw_intr_mask = 0;
|
||||
}
|
||||
|
||||
static void etraxfs_timer_reset_hold(Object *obj)
|
||||
static void etraxfs_timer_reset_hold(Object *obj, ResetType type)
|
||||
{
|
||||
ETRAXTimerState *t = ETRAX_TIMER(obj);
|
||||
|
||||
|
|
|
@ -592,7 +592,7 @@ static void npcm7xx_watchdog_timer_expired(void *opaque)
|
|||
}
|
||||
}
|
||||
|
||||
static void npcm7xx_timer_hold_reset(Object *obj)
|
||||
static void npcm7xx_timer_hold_reset(Object *obj, ResetType type)
|
||||
{
|
||||
NPCM7xxTimerCtrlState *s = NPCM7XX_TIMER(obj);
|
||||
int i;
|
||||
|
|
|
@ -1305,7 +1305,7 @@ static void dwc2_reset_enter(Object *obj, ResetType type)
|
|||
}
|
||||
}
|
||||
|
||||
static void dwc2_reset_hold(Object *obj)
|
||||
static void dwc2_reset_hold(Object *obj, ResetType type)
|
||||
{
|
||||
DWC2Class *c = DWC2_USB_GET_CLASS(obj);
|
||||
DWC2State *s = DWC2_USB(obj);
|
||||
|
@ -1313,13 +1313,13 @@ static void dwc2_reset_hold(Object *obj)
|
|||
trace_usb_dwc2_reset_hold();
|
||||
|
||||
if (c->parent_phases.hold) {
|
||||
c->parent_phases.hold(obj);
|
||||
c->parent_phases.hold(obj, type);
|
||||
}
|
||||
|
||||
dwc2_update_irq(s);
|
||||
}
|
||||
|
||||
static void dwc2_reset_exit(Object *obj)
|
||||
static void dwc2_reset_exit(Object *obj, ResetType type)
|
||||
{
|
||||
DWC2Class *c = DWC2_USB_GET_CLASS(obj);
|
||||
DWC2State *s = DWC2_USB(obj);
|
||||
|
@ -1327,7 +1327,7 @@ static void dwc2_reset_exit(Object *obj)
|
|||
trace_usb_dwc2_reset_exit();
|
||||
|
||||
if (c->parent_phases.exit) {
|
||||
c->parent_phases.exit(obj);
|
||||
c->parent_phases.exit(obj, type);
|
||||
}
|
||||
|
||||
s->hprt0 = HPRT0_PWR;
|
||||
|
|
|
@ -153,7 +153,7 @@ static void usb2_ctrl_regs_reset_init(Object *obj, ResetType type)
|
|||
}
|
||||
}
|
||||
|
||||
static void usb2_ctrl_regs_reset_hold(Object *obj)
|
||||
static void usb2_ctrl_regs_reset_hold(Object *obj, ResetType type)
|
||||
{
|
||||
VersalUsb2CtrlRegs *s = XILINX_VERSAL_USB2_CTRL_REGS(obj);
|
||||
|
||||
|
|
|
@ -2292,7 +2292,7 @@ static void virtio_pci_reset(DeviceState *qdev)
|
|||
}
|
||||
}
|
||||
|
||||
static void virtio_pci_bus_reset_hold(Object *obj)
|
||||
static void virtio_pci_bus_reset_hold(Object *obj, ResetType type)
|
||||
{
|
||||
PCIDevice *dev = PCI_DEVICE(obj);
|
||||
DeviceState *qdev = DEVICE(obj);
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include "hw/misc/stm32l4x5_exti.h"
|
||||
#include "hw/misc/stm32l4x5_rcc.h"
|
||||
#include "hw/gpio/stm32l4x5_gpio.h"
|
||||
#include "hw/char/stm32l4x5_usart.h"
|
||||
#include "qom/object.h"
|
||||
|
||||
#define TYPE_STM32L4X5_SOC "stm32l4x5-soc"
|
||||
|
@ -41,6 +42,9 @@ OBJECT_DECLARE_TYPE(Stm32l4x5SocState, Stm32l4x5SocClass, STM32L4X5_SOC)
|
|||
|
||||
#define NUM_EXTI_OR_GATES 4
|
||||
|
||||
#define STM_NUM_USARTS 3
|
||||
#define STM_NUM_UARTS 2
|
||||
|
||||
struct Stm32l4x5SocState {
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
|
@ -51,6 +55,9 @@ struct Stm32l4x5SocState {
|
|||
Stm32l4x5SyscfgState syscfg;
|
||||
Stm32l4x5RccState rcc;
|
||||
Stm32l4x5GpioState gpio[NUM_GPIOS];
|
||||
Stm32l4x5UsartBaseState usart[STM_NUM_USARTS];
|
||||
Stm32l4x5UsartBaseState uart[STM_NUM_UARTS];
|
||||
Stm32l4x5UsartBaseState lpuart;
|
||||
|
||||
MemoryRegion sram1;
|
||||
MemoryRegion sram2;
|
||||
|
|
67
include/hw/char/stm32l4x5_usart.h
Normal file
67
include/hw/char/stm32l4x5_usart.h
Normal file
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* STM32L4X5 USART (Universal Synchronous Asynchronous Receiver Transmitter)
|
||||
*
|
||||
* Copyright (c) 2023 Arnaud Minier <arnaud.minier@telecom-paris.fr>
|
||||
* Copyright (c) 2023 Inès Varhol <ines.varhol@telecom-paris.fr>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*
|
||||
* The STM32L4X5 USART is heavily inspired by the stm32f2xx_usart
|
||||
* by Alistair Francis.
|
||||
* The reference used is the STMicroElectronics RM0351 Reference manual
|
||||
* for STM32L4x5 and STM32L4x6 advanced Arm ® -based 32-bit MCUs.
|
||||
*/
|
||||
|
||||
#ifndef HW_STM32L4X5_USART_H
|
||||
#define HW_STM32L4X5_USART_H
|
||||
|
||||
#include "hw/sysbus.h"
|
||||
#include "chardev/char-fe.h"
|
||||
#include "qom/object.h"
|
||||
|
||||
#define TYPE_STM32L4X5_USART_BASE "stm32l4x5-usart-base"
|
||||
#define TYPE_STM32L4X5_USART "stm32l4x5-usart"
|
||||
#define TYPE_STM32L4X5_UART "stm32l4x5-uart"
|
||||
#define TYPE_STM32L4X5_LPUART "stm32l4x5-lpuart"
|
||||
OBJECT_DECLARE_TYPE(Stm32l4x5UsartBaseState, Stm32l4x5UsartBaseClass,
|
||||
STM32L4X5_USART_BASE)
|
||||
|
||||
typedef enum {
|
||||
STM32L4x5_USART,
|
||||
STM32L4x5_UART,
|
||||
STM32L4x5_LPUART,
|
||||
} Stm32l4x5UsartType;
|
||||
|
||||
struct Stm32l4x5UsartBaseState {
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
MemoryRegion mmio;
|
||||
|
||||
uint32_t cr1;
|
||||
uint32_t cr2;
|
||||
uint32_t cr3;
|
||||
uint32_t brr;
|
||||
uint32_t gtpr;
|
||||
uint32_t rtor;
|
||||
/* rqr is write-only */
|
||||
uint32_t isr;
|
||||
/* icr is a clear register */
|
||||
uint32_t rdr;
|
||||
uint32_t tdr;
|
||||
|
||||
Clock *clk;
|
||||
CharBackend chr;
|
||||
qemu_irq irq;
|
||||
guint watch_tag;
|
||||
};
|
||||
|
||||
struct Stm32l4x5UsartBaseClass {
|
||||
SysBusDeviceClass parent_class;
|
||||
|
||||
Stm32l4x5UsartType type;
|
||||
};
|
||||
|
||||
#endif /* HW_STM32L4X5_USART_H */
|
|
@ -71,6 +71,8 @@ struct GICState {
|
|||
qemu_irq parent_fiq[GIC_NCPU];
|
||||
qemu_irq parent_virq[GIC_NCPU];
|
||||
qemu_irq parent_vfiq[GIC_NCPU];
|
||||
qemu_irq parent_nmi[GIC_NCPU];
|
||||
qemu_irq parent_vnmi[GIC_NCPU];
|
||||
qemu_irq maintenance_irq[GIC_NCPU];
|
||||
|
||||
/* GICD_CTLR; for a GIC with the security extensions the NS banked version
|
||||
|
|
|
@ -146,6 +146,7 @@ typedef struct {
|
|||
int irq;
|
||||
uint8_t prio;
|
||||
int grp;
|
||||
bool nmi;
|
||||
} PendingIrq;
|
||||
|
||||
struct GICv3CPUState {
|
||||
|
@ -155,6 +156,8 @@ struct GICv3CPUState {
|
|||
qemu_irq parent_fiq;
|
||||
qemu_irq parent_virq;
|
||||
qemu_irq parent_vfiq;
|
||||
qemu_irq parent_nmi;
|
||||
qemu_irq parent_vnmi;
|
||||
|
||||
/* Redistributor */
|
||||
uint32_t level; /* Current IRQ level */
|
||||
|
@ -170,6 +173,7 @@ struct GICv3CPUState {
|
|||
uint32_t gicr_ienabler0;
|
||||
uint32_t gicr_ipendr0;
|
||||
uint32_t gicr_iactiver0;
|
||||
uint32_t gicr_inmir0;
|
||||
uint32_t edge_trigger; /* ICFGR0 and ICFGR1 even bits */
|
||||
uint32_t gicr_igrpmodr0;
|
||||
uint32_t gicr_nsacr;
|
||||
|
@ -221,6 +225,13 @@ struct GICv3CPUState {
|
|||
|
||||
/* This is temporary working state, to avoid a malloc in gicv3_update() */
|
||||
bool seenbetter;
|
||||
|
||||
/*
|
||||
* Whether the CPU interface has NMI support (FEAT_GICv3_NMI). The
|
||||
* CPU interface may support NMIs even when the GIC proper (what the
|
||||
* spec calls the IRI; the redistributors and distributor) does not.
|
||||
*/
|
||||
bool nmi_support;
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -247,6 +258,7 @@ struct GICv3State {
|
|||
uint32_t num_irq;
|
||||
uint32_t revision;
|
||||
bool lpi_enable;
|
||||
bool nmi_support;
|
||||
bool security_extn;
|
||||
bool force_8bit_prio;
|
||||
bool irq_reset_nonsecure;
|
||||
|
@ -272,6 +284,7 @@ struct GICv3State {
|
|||
GIC_DECLARE_BITMAP(active); /* GICD_ISACTIVER */
|
||||
GIC_DECLARE_BITMAP(level); /* Current level */
|
||||
GIC_DECLARE_BITMAP(edge_trigger); /* GICD_ICFGR even bits */
|
||||
GIC_DECLARE_BITMAP(nmi); /* GICD_INMIR */
|
||||
uint8_t gicd_ipriority[GICV3_MAXIRQ];
|
||||
uint64_t gicd_irouter[GICV3_MAXIRQ];
|
||||
/* Cached information: pointer to the cpu i/f for the CPUs specified
|
||||
|
@ -311,6 +324,7 @@ GICV3_BITMAP_ACCESSORS(pending)
|
|||
GICV3_BITMAP_ACCESSORS(active)
|
||||
GICV3_BITMAP_ACCESSORS(level)
|
||||
GICV3_BITMAP_ACCESSORS(edge_trigger)
|
||||
GICV3_BITMAP_ACCESSORS(nmi)
|
||||
|
||||
#define TYPE_ARM_GICV3_COMMON "arm-gicv3-common"
|
||||
typedef struct ARMGICv3CommonClass ARMGICv3CommonClass;
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user