target-arm queue:
* Netduino 2 improvements (SPI, ADC devices) * fix some Mainstone key mappings * vmstateify tsc210x, tsc2005 * virt: add 2.8 machine type * virt: support in-kernel GICv3 ITS * generic-loader device * A64: fix iss_sf decoding in disas_ld_lit * correctly handle 'sub pc, pc, 1' for ARMv6 -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABCAAGBQJX86N+AAoJEDwlJe0UNgzesFgP/2/wL7t+PCZh1ugZWGxfwg5S 5+pHPqeWm+d0TIZLMN64c+CJ0F5ZCu+aTafNRMoSzLWCbPDxPw0wTwKxK/r0Caao 0IBJdlND7oJ8HchyjECKqagS1CEcC3147ZqNRoC1YAJABdIiObiDkeJy4Y9WF+kA ibTdnOluea24o7UniPKcWW9Ly4k0bUl49tPa4fMt8ks1Nx1h+esvE7g7OWNBhCB2 DEMezJcDtYgU1s7ozt2K+hRszSh7sg6VaXnHLExXJAenfcZUvmg8wwxNPpaOMf01 mwc8OPd5Jk9nkUOWBK1mwOYfNpLQJLCBpprSZZQfY2jj51Tc2QpQ3pIfICr8+smG sCNXZXugqVqey9SXjX+Mh3J8KskzqvDZXDyeOTSsdmBYZ7eoI52cVw2j9stDtl23 ITEyQ7CDjKKlkUGK+7xPe37jgXaG3ja9r2O2Zot9sZDnwuyESfbhkjhHOgsAtKEe aNzecoB/e6vntUDis4nq0eNkG3dGMcb1WiK6RAXLxokDgThQdLPpY2L3aMiLQSEU Al5n5fCI4DTEejyYH5gb8P8Q9t7oG/ol+FBXWG0TYfDrb2lJ0FQkf1fNKWomEZfV j9BTlnSC8j4G5wpn1+m+yfqARPnUkHRr9eZU/FhcbPNnnZ+Lb353deiIGftD8gTo eMCYd6vcmOMr/ybNFHzE =WxlQ -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20161004' into staging target-arm queue: * Netduino 2 improvements (SPI, ADC devices) * fix some Mainstone key mappings * vmstateify tsc210x, tsc2005 * virt: add 2.8 machine type * virt: support in-kernel GICv3 ITS * generic-loader device * A64: fix iss_sf decoding in disas_ld_lit * correctly handle 'sub pc, pc, 1' for ARMv6 # gpg: Signature made Tue 04 Oct 2016 13:41:34 BST # gpg: using RSA key 0x3C2525ED14360CDE # gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" # gpg: aka "Peter Maydell <pmaydell@gmail.com>" # gpg: aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>" # Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83 15CF 3C25 25ED 1436 0CDE * remotes/pmaydell/tags/pull-target-arm-20161004: (27 commits) target-arm: Correctly handle 'sub pc, pc, 1' for ARMv6 target-arm: A64: Fix decoding of iss_sf in disas_ld_lit cadence_gem: Fix priority queue out of bounds access docs: Add a generic loader explanation document generic-loader: Add a generic loader ARM: Virt: ACPI: Add GIC ITS description in ACPI MADT table ACPI: Add GIC Interrupt Translation Service Structure definition arm/virt: Add ITS to the virt board hw/intc/arm_gicv3_its: Implement support for in-kernel ITS emulation kvm-all: Pass requester ID to MSI routing functions target-arm: move gicv3_class_name from machine to kvm_arm.h hw/intc/arm_gicv3_its: Implement ITS base class hw/intc/arm_gic(v3)_kvm: Initialize gsi routing hw/arm/virt: add 2.8 machine type vmstateify tsc210x vmstateify tsc2005 hw/arm: Fix Integrator/CM initialization mainstone: Add mapping for dot, slash and backspace. mainstone: Fix incorrect key mapping for Enter key. MAINTAINERS: Add Alistair to the maintainers list ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
6e11eb2d2b
21
MAINTAINERS
21
MAINTAINERS
|
@ -479,6 +479,21 @@ S: Maintained
|
|||
F: hw/arm/virt-acpi-build.c
|
||||
F: include/hw/arm/virt-acpi-build.h
|
||||
|
||||
STM32F205
|
||||
M: Alistair Francis <alistair@alistair23.me>
|
||||
S: Maintained
|
||||
F: hw/arm/stm32f205_soc.c
|
||||
F: hw/misc/stm32f2xx_syscfg.c
|
||||
F: hw/char/stm32f2xx_usart.c
|
||||
F: hw/timer/stm32f2xx_timer.c
|
||||
F: hw/adc/*
|
||||
F: hw/ssi/stm32f2xx_spi.c
|
||||
|
||||
Netduino 2
|
||||
M: Alistair Francis <alistair@alistair23.me>
|
||||
S: Maintained
|
||||
F: hw/arm/netduino2.c
|
||||
|
||||
CRIS Machines
|
||||
-------------
|
||||
Axis Dev88
|
||||
|
@ -1014,6 +1029,12 @@ M: Dmitry Fleytman <dmitry@daynix.com>
|
|||
S: Maintained
|
||||
F: hw/net/e1000e*
|
||||
|
||||
Generic Loader
|
||||
M: Alistair Francis <alistair.francis@xilinx.com>
|
||||
S: Maintained
|
||||
F: hw/core/generic-loader.c
|
||||
F: include/hw/core/generic-loader.h
|
||||
|
||||
Subsystems
|
||||
----------
|
||||
Audio
|
||||
|
|
|
@ -86,6 +86,8 @@ CONFIG_ZYNQ=y
|
|||
CONFIG_STM32F2XX_TIMER=y
|
||||
CONFIG_STM32F2XX_USART=y
|
||||
CONFIG_STM32F2XX_SYSCFG=y
|
||||
CONFIG_STM32F2XX_ADC=y
|
||||
CONFIG_STM32F2XX_SPI=y
|
||||
CONFIG_STM32F205_SOC=y
|
||||
|
||||
CONFIG_VERSATILE_PCI=y
|
||||
|
|
84
docs/generic-loader.txt
Normal file
84
docs/generic-loader.txt
Normal file
|
@ -0,0 +1,84 @@
|
|||
Copyright (c) 2016 Xilinx Inc.
|
||||
|
||||
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 'loader' device allows the user to load multiple images or values into
|
||||
QEMU at startup.
|
||||
|
||||
Loading Data into Memory Values
|
||||
---------------------
|
||||
The loader device allows memory values to be set from the command line. This
|
||||
can be done by following the syntax below:
|
||||
|
||||
-device loader,addr=<addr>,data=<data>,data-len=<data-len>
|
||||
[,data-be=<data-be>][,cpu-num=<cpu-num>]
|
||||
|
||||
<addr> - The address to store the data in.
|
||||
<data> - The value to be written to the address. The maximum size of
|
||||
the data is 8 bytes.
|
||||
<data-len> - The length of the data in bytes. This argument must be
|
||||
included if the data argument is.
|
||||
<data-be> - Set to true if the data to be stored on the guest should be
|
||||
written as big endian data. The default is to write little
|
||||
endian data.
|
||||
<cpu-num> - The number of the CPU's address space where the data should
|
||||
be loaded. If not specified the address space of the first
|
||||
CPU is used.
|
||||
|
||||
All values are parsed using the standard QemuOps parsing. This allows the user
|
||||
to specify any values in any format supported. By default the values
|
||||
will be parsed as decimal. To use hex values the user should prefix the number
|
||||
with a '0x'.
|
||||
|
||||
An example of loading value 0x8000000e to address 0xfd1a0104 is:
|
||||
-device loader,addr=0xfd1a0104,data=0x8000000e,data-len=4
|
||||
|
||||
Setting a CPU's Program Counter
|
||||
---------------------
|
||||
The loader device allows the CPU's PC to be set from the command line. This
|
||||
can be done by following the syntax below:
|
||||
|
||||
-device loader,addr=<addr>,cpu-num=<cpu-num>
|
||||
|
||||
<addr> - The value to use as the CPU's PC.
|
||||
<cpu-num> - The number of the CPU whose PC should be set to the
|
||||
specified value.
|
||||
|
||||
All values are parsed using the standard QemuOps parsing. This allows the user
|
||||
to specify any values in any format supported. By default the values
|
||||
will be parsed as decimal. To use hex values the user should prefix the number
|
||||
with a '0x'.
|
||||
|
||||
An example of setting CPU 0's PC to 0x8000 is:
|
||||
-device loader,addr=0x8000,cpu-num=0
|
||||
|
||||
Loading Files
|
||||
---------------------
|
||||
The loader device also allows files to be loaded into memory. This can be done
|
||||
similarly to setting memory values. The syntax is shown below:
|
||||
|
||||
-device loader,file=<file>[,addr=<addr>][,cpu-num=<cpu-num>][,force-raw=<raw>]
|
||||
|
||||
<file> - A file to be loaded into memory
|
||||
<addr> - The addr in memory that the file should be loaded. This is
|
||||
ignored if you are using an ELF (unless force-raw is true).
|
||||
This is required if you aren't loading an ELF.
|
||||
<cpu-num> - This specifies the CPU that should be used. This is an
|
||||
optional argument and will cause the CPU's PC to be set to
|
||||
where the image is stored or in the case of an ELF file to
|
||||
the value in the header. This option should only be used
|
||||
for the boot image.
|
||||
This will also cause the image to be written to the specified
|
||||
CPU's address space. If not specified, the default is CPU 0.
|
||||
<force-raw> - Forces the file to be treated as a raw image. This can be
|
||||
used to specify the load address of ELF files.
|
||||
|
||||
All values are parsed using the standard QemuOps parsing. This allows the user
|
||||
to specify any values in any format supported. By default the values
|
||||
will be parsed as decimal. To use hex values the user should prefix the number
|
||||
with a '0x'.
|
||||
|
||||
An example of loading an ELF file which CPU0 will boot is shown below:
|
||||
-device loader,file=./images/boot.elf,cpu-num=0
|
|
@ -1,5 +1,6 @@
|
|||
devices-dirs-$(call land, $(CONFIG_VIRTIO),$(call land,$(CONFIG_VIRTFS),$(CONFIG_PCI))) += 9pfs/
|
||||
devices-dirs-$(CONFIG_ACPI) += acpi/
|
||||
devices-dirs-$(CONFIG_SOFTMMU) += adc/
|
||||
devices-dirs-$(CONFIG_SOFTMMU) += audio/
|
||||
devices-dirs-$(CONFIG_SOFTMMU) += block/
|
||||
devices-dirs-$(CONFIG_SOFTMMU) += bt/
|
||||
|
|
1
hw/adc/Makefile.objs
Normal file
1
hw/adc/Makefile.objs
Normal file
|
@ -0,0 +1 @@
|
|||
obj-$(CONFIG_STM32F2XX_ADC) += stm32f2xx_adc.o
|
306
hw/adc/stm32f2xx_adc.c
Normal file
306
hw/adc/stm32f2xx_adc.c
Normal file
|
@ -0,0 +1,306 @@
|
|||
/*
|
||||
* STM32F2XX ADC
|
||||
*
|
||||
* Copyright (c) 2014 Alistair Francis <alistair@alistair23.me>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/hw.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/log.h"
|
||||
#include "hw/adc/stm32f2xx_adc.h"
|
||||
|
||||
#ifndef STM_ADC_ERR_DEBUG
|
||||
#define STM_ADC_ERR_DEBUG 0
|
||||
#endif
|
||||
|
||||
#define DB_PRINT_L(lvl, fmt, args...) do { \
|
||||
if (STM_ADC_ERR_DEBUG >= lvl) { \
|
||||
qemu_log("%s: " fmt, __func__, ## args); \
|
||||
} \
|
||||
} while (0);
|
||||
|
||||
#define DB_PRINT(fmt, args...) DB_PRINT_L(1, fmt, ## args)
|
||||
|
||||
static void stm32f2xx_adc_reset(DeviceState *dev)
|
||||
{
|
||||
STM32F2XXADCState *s = STM32F2XX_ADC(dev);
|
||||
|
||||
s->adc_sr = 0x00000000;
|
||||
s->adc_cr1 = 0x00000000;
|
||||
s->adc_cr2 = 0x00000000;
|
||||
s->adc_smpr1 = 0x00000000;
|
||||
s->adc_smpr2 = 0x00000000;
|
||||
s->adc_jofr[0] = 0x00000000;
|
||||
s->adc_jofr[1] = 0x00000000;
|
||||
s->adc_jofr[2] = 0x00000000;
|
||||
s->adc_jofr[3] = 0x00000000;
|
||||
s->adc_htr = 0x00000FFF;
|
||||
s->adc_ltr = 0x00000000;
|
||||
s->adc_sqr1 = 0x00000000;
|
||||
s->adc_sqr2 = 0x00000000;
|
||||
s->adc_sqr3 = 0x00000000;
|
||||
s->adc_jsqr = 0x00000000;
|
||||
s->adc_jdr[0] = 0x00000000;
|
||||
s->adc_jdr[1] = 0x00000000;
|
||||
s->adc_jdr[2] = 0x00000000;
|
||||
s->adc_jdr[3] = 0x00000000;
|
||||
s->adc_dr = 0x00000000;
|
||||
}
|
||||
|
||||
static uint32_t stm32f2xx_adc_generate_value(STM32F2XXADCState *s)
|
||||
{
|
||||
/* Attempts to fake some ADC values */
|
||||
s->adc_dr = s->adc_dr + 7;
|
||||
|
||||
switch ((s->adc_cr1 & ADC_CR1_RES) >> 24) {
|
||||
case 0:
|
||||
/* 12-bit */
|
||||
s->adc_dr &= 0xFFF;
|
||||
break;
|
||||
case 1:
|
||||
/* 10-bit */
|
||||
s->adc_dr &= 0x3FF;
|
||||
break;
|
||||
case 2:
|
||||
/* 8-bit */
|
||||
s->adc_dr &= 0xFF;
|
||||
break;
|
||||
default:
|
||||
/* 6-bit */
|
||||
s->adc_dr &= 0x3F;
|
||||
}
|
||||
|
||||
if (s->adc_cr2 & ADC_CR2_ALIGN) {
|
||||
return (s->adc_dr << 1) & 0xFFF0;
|
||||
} else {
|
||||
return s->adc_dr;
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t stm32f2xx_adc_read(void *opaque, hwaddr addr,
|
||||
unsigned int size)
|
||||
{
|
||||
STM32F2XXADCState *s = opaque;
|
||||
|
||||
DB_PRINT("Address: 0x%" HWADDR_PRIx "\n", addr);
|
||||
|
||||
if (addr >= ADC_COMMON_ADDRESS) {
|
||||
qemu_log_mask(LOG_UNIMP,
|
||||
"%s: ADC Common Register Unsupported\n", __func__);
|
||||
}
|
||||
|
||||
switch (addr) {
|
||||
case ADC_SR:
|
||||
return s->adc_sr;
|
||||
case ADC_CR1:
|
||||
return s->adc_cr1;
|
||||
case ADC_CR2:
|
||||
return s->adc_cr2 & 0xFFFFFFF;
|
||||
case ADC_SMPR1:
|
||||
return s->adc_smpr1;
|
||||
case ADC_SMPR2:
|
||||
return s->adc_smpr2;
|
||||
case ADC_JOFR1:
|
||||
case ADC_JOFR2:
|
||||
case ADC_JOFR3:
|
||||
case ADC_JOFR4:
|
||||
qemu_log_mask(LOG_UNIMP, "%s: " \
|
||||
"Injection ADC is not implemented, the registers are " \
|
||||
"included for compatibility\n", __func__);
|
||||
return s->adc_jofr[(addr - ADC_JOFR1) / 4];
|
||||
case ADC_HTR:
|
||||
return s->adc_htr;
|
||||
case ADC_LTR:
|
||||
return s->adc_ltr;
|
||||
case ADC_SQR1:
|
||||
return s->adc_sqr1;
|
||||
case ADC_SQR2:
|
||||
return s->adc_sqr2;
|
||||
case ADC_SQR3:
|
||||
return s->adc_sqr3;
|
||||
case ADC_JSQR:
|
||||
qemu_log_mask(LOG_UNIMP, "%s: " \
|
||||
"Injection ADC is not implemented, the registers are " \
|
||||
"included for compatibility\n", __func__);
|
||||
return s->adc_jsqr;
|
||||
case ADC_JDR1:
|
||||
case ADC_JDR2:
|
||||
case ADC_JDR3:
|
||||
case ADC_JDR4:
|
||||
qemu_log_mask(LOG_UNIMP, "%s: " \
|
||||
"Injection ADC is not implemented, the registers are " \
|
||||
"included for compatibility\n", __func__);
|
||||
return s->adc_jdr[(addr - ADC_JDR1) / 4] -
|
||||
s->adc_jofr[(addr - ADC_JDR1) / 4];
|
||||
case ADC_DR:
|
||||
if ((s->adc_cr2 & ADC_CR2_ADON) && (s->adc_cr2 & ADC_CR2_SWSTART)) {
|
||||
s->adc_cr2 ^= ADC_CR2_SWSTART;
|
||||
return stm32f2xx_adc_generate_value(s);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: Bad offset 0x%" HWADDR_PRIx "\n", __func__, addr);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void stm32f2xx_adc_write(void *opaque, hwaddr addr,
|
||||
uint64_t val64, unsigned int size)
|
||||
{
|
||||
STM32F2XXADCState *s = opaque;
|
||||
uint32_t value = (uint32_t) val64;
|
||||
|
||||
DB_PRINT("Address: 0x%" HWADDR_PRIx ", Value: 0x%x\n",
|
||||
addr, value);
|
||||
|
||||
if (addr >= 0x100) {
|
||||
qemu_log_mask(LOG_UNIMP,
|
||||
"%s: ADC Common Register Unsupported\n", __func__);
|
||||
}
|
||||
|
||||
switch (addr) {
|
||||
case ADC_SR:
|
||||
s->adc_sr &= (value & 0x3F);
|
||||
break;
|
||||
case ADC_CR1:
|
||||
s->adc_cr1 = value;
|
||||
break;
|
||||
case ADC_CR2:
|
||||
s->adc_cr2 = value;
|
||||
break;
|
||||
case ADC_SMPR1:
|
||||
s->adc_smpr1 = value;
|
||||
break;
|
||||
case ADC_SMPR2:
|
||||
s->adc_smpr2 = value;
|
||||
break;
|
||||
case ADC_JOFR1:
|
||||
case ADC_JOFR2:
|
||||
case ADC_JOFR3:
|
||||
case ADC_JOFR4:
|
||||
s->adc_jofr[(addr - ADC_JOFR1) / 4] = (value & 0xFFF);
|
||||
qemu_log_mask(LOG_UNIMP, "%s: " \
|
||||
"Injection ADC is not implemented, the registers are " \
|
||||
"included for compatibility\n", __func__);
|
||||
break;
|
||||
case ADC_HTR:
|
||||
s->adc_htr = value;
|
||||
break;
|
||||
case ADC_LTR:
|
||||
s->adc_ltr = value;
|
||||
break;
|
||||
case ADC_SQR1:
|
||||
s->adc_sqr1 = value;
|
||||
break;
|
||||
case ADC_SQR2:
|
||||
s->adc_sqr2 = value;
|
||||
break;
|
||||
case ADC_SQR3:
|
||||
s->adc_sqr3 = value;
|
||||
break;
|
||||
case ADC_JSQR:
|
||||
s->adc_jsqr = value;
|
||||
qemu_log_mask(LOG_UNIMP, "%s: " \
|
||||
"Injection ADC is not implemented, the registers are " \
|
||||
"included for compatibility\n", __func__);
|
||||
break;
|
||||
case ADC_JDR1:
|
||||
case ADC_JDR2:
|
||||
case ADC_JDR3:
|
||||
case ADC_JDR4:
|
||||
s->adc_jdr[(addr - ADC_JDR1) / 4] = value;
|
||||
qemu_log_mask(LOG_UNIMP, "%s: " \
|
||||
"Injection ADC is not implemented, the registers are " \
|
||||
"included for compatibility\n", __func__);
|
||||
break;
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: Bad offset 0x%" HWADDR_PRIx "\n", __func__, addr);
|
||||
}
|
||||
}
|
||||
|
||||
static const MemoryRegionOps stm32f2xx_adc_ops = {
|
||||
.read = stm32f2xx_adc_read,
|
||||
.write = stm32f2xx_adc_write,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
static const VMStateDescription vmstate_stm32f2xx_adc = {
|
||||
.name = TYPE_STM32F2XX_ADC,
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32(adc_sr, STM32F2XXADCState),
|
||||
VMSTATE_UINT32(adc_cr1, STM32F2XXADCState),
|
||||
VMSTATE_UINT32(adc_cr2, STM32F2XXADCState),
|
||||
VMSTATE_UINT32(adc_smpr1, STM32F2XXADCState),
|
||||
VMSTATE_UINT32(adc_smpr2, STM32F2XXADCState),
|
||||
VMSTATE_UINT32_ARRAY(adc_jofr, STM32F2XXADCState, 4),
|
||||
VMSTATE_UINT32(adc_htr, STM32F2XXADCState),
|
||||
VMSTATE_UINT32(adc_ltr, STM32F2XXADCState),
|
||||
VMSTATE_UINT32(adc_sqr1, STM32F2XXADCState),
|
||||
VMSTATE_UINT32(adc_sqr2, STM32F2XXADCState),
|
||||
VMSTATE_UINT32(adc_sqr3, STM32F2XXADCState),
|
||||
VMSTATE_UINT32(adc_jsqr, STM32F2XXADCState),
|
||||
VMSTATE_UINT32_ARRAY(adc_jdr, STM32F2XXADCState, 4),
|
||||
VMSTATE_UINT32(adc_dr, STM32F2XXADCState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static void stm32f2xx_adc_init(Object *obj)
|
||||
{
|
||||
STM32F2XXADCState *s = STM32F2XX_ADC(obj);
|
||||
|
||||
sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq);
|
||||
|
||||
memory_region_init_io(&s->mmio, obj, &stm32f2xx_adc_ops, s,
|
||||
TYPE_STM32F2XX_ADC, 0xFF);
|
||||
sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
|
||||
}
|
||||
|
||||
static void stm32f2xx_adc_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->reset = stm32f2xx_adc_reset;
|
||||
dc->vmsd = &vmstate_stm32f2xx_adc;
|
||||
}
|
||||
|
||||
static const TypeInfo stm32f2xx_adc_info = {
|
||||
.name = TYPE_STM32F2XX_ADC,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(STM32F2XXADCState),
|
||||
.instance_init = stm32f2xx_adc_init,
|
||||
.class_init = stm32f2xx_adc_class_init,
|
||||
};
|
||||
|
||||
static void stm32f2xx_adc_register_types(void)
|
||||
{
|
||||
type_register_static(&stm32f2xx_adc_info);
|
||||
}
|
||||
|
||||
type_init(stm32f2xx_adc_register_types)
|
|
@ -252,6 +252,26 @@ static void integratorcm_init(Object *obj)
|
|||
/* ??? What should the high bits of this value be? */
|
||||
s->cm_auxosc = 0x0007feff;
|
||||
s->cm_sdram = 0x00011122;
|
||||
memcpy(integrator_spd + 73, "QEMU-MEMORY", 11);
|
||||
s->cm_init = 0x00000112;
|
||||
s->cm_refcnt_offset = muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 24,
|
||||
1000);
|
||||
memory_region_init_ram(&s->flash, obj, "integrator.flash", 0x100000,
|
||||
&error_fatal);
|
||||
vmstate_register_ram_global(&s->flash);
|
||||
|
||||
memory_region_init_io(&s->iomem, obj, &integratorcm_ops, s,
|
||||
"integratorcm", 0x00800000);
|
||||
sysbus_init_mmio(dev, &s->iomem);
|
||||
|
||||
integratorcm_do_remap(s);
|
||||
/* ??? Save/restore. */
|
||||
}
|
||||
|
||||
static void integratorcm_realize(DeviceState *d, Error **errp)
|
||||
{
|
||||
IntegratorCMState *s = INTEGRATOR_CM(d);
|
||||
|
||||
if (s->memsz >= 256) {
|
||||
integrator_spd[31] = 64;
|
||||
s->cm_sdram |= 0x10;
|
||||
|
@ -267,20 +287,6 @@ static void integratorcm_init(Object *obj)
|
|||
} else {
|
||||
integrator_spd[31] = 2;
|
||||
}
|
||||
memcpy(integrator_spd + 73, "QEMU-MEMORY", 11);
|
||||
s->cm_init = 0x00000112;
|
||||
s->cm_refcnt_offset = muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 24,
|
||||
1000);
|
||||
memory_region_init_ram(&s->flash, obj, "integrator.flash", 0x100000,
|
||||
&error_fatal);
|
||||
vmstate_register_ram_global(&s->flash);
|
||||
|
||||
memory_region_init_io(&s->iomem, obj, &integratorcm_ops, s,
|
||||
"integratorcm", 0x00800000);
|
||||
sysbus_init_mmio(dev, &s->iomem);
|
||||
|
||||
integratorcm_do_remap(s);
|
||||
/* ??? Save/restore. */
|
||||
}
|
||||
|
||||
/* Integrator/CP hardware emulation. */
|
||||
|
@ -633,6 +639,7 @@ static void core_class_init(ObjectClass *klass, void *data)
|
|||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->props = core_properties;
|
||||
dc->realize = integratorcm_realize;
|
||||
}
|
||||
|
||||
static const TypeInfo core_info = {
|
||||
|
|
|
@ -73,8 +73,10 @@ static const struct keymap map[0xE0] = {
|
|||
[0x2f] = {3,3}, /* v */
|
||||
[0x11] = {3,4}, /* w */
|
||||
[0x2d] = {3,5}, /* x */
|
||||
[0x34] = {4,0}, /* . */
|
||||
[0x15] = {4,2}, /* y */
|
||||
[0x2c] = {4,3}, /* z */
|
||||
[0x35] = {4,4}, /* / */
|
||||
[0xc7] = {5,0}, /* Home */
|
||||
[0x2a] = {5,1}, /* shift */
|
||||
/*
|
||||
|
@ -88,7 +90,8 @@ static const struct keymap map[0xE0] = {
|
|||
* Matrix position {5,4} and other keys are missing here.
|
||||
* TODO: Compare with Linux code and test real hardware.
|
||||
*/
|
||||
[0x1c] = {5,5}, /* enter (TODO: might be wrong) */
|
||||
[0x1c] = {5,4}, /* enter */
|
||||
[0x0e] = {5,5}, /* backspace */
|
||||
[0xc8] = {6,0}, /* up */
|
||||
[0xd0] = {6,1}, /* down */
|
||||
[0xcb] = {6,2}, /* left */
|
||||
|
|
|
@ -34,9 +34,15 @@ static const uint32_t timer_addr[STM_NUM_TIMERS] = { 0x40000000, 0x40000400,
|
|||
0x40000800, 0x40000C00 };
|
||||
static const uint32_t usart_addr[STM_NUM_USARTS] = { 0x40011000, 0x40004400,
|
||||
0x40004800, 0x40004C00, 0x40005000, 0x40011400 };
|
||||
static const uint32_t adc_addr[STM_NUM_ADCS] = { 0x40012000, 0x40012100,
|
||||
0x40012200 };
|
||||
static const uint32_t spi_addr[STM_NUM_SPIS] = { 0x40013000, 0x40003800,
|
||||
0x40003C00 };
|
||||
|
||||
static const int timer_irq[STM_NUM_TIMERS] = {28, 29, 30, 50};
|
||||
static const int usart_irq[STM_NUM_USARTS] = {37, 38, 39, 52, 53, 71};
|
||||
#define ADC_IRQ 18
|
||||
static const int spi_irq[STM_NUM_SPIS] = {35, 36, 51};
|
||||
|
||||
static void stm32f205_soc_initfn(Object *obj)
|
||||
{
|
||||
|
@ -57,13 +63,27 @@ static void stm32f205_soc_initfn(Object *obj)
|
|||
TYPE_STM32F2XX_TIMER);
|
||||
qdev_set_parent_bus(DEVICE(&s->timer[i]), sysbus_get_default());
|
||||
}
|
||||
|
||||
s->adc_irqs = OR_IRQ(object_new(TYPE_OR_IRQ));
|
||||
|
||||
for (i = 0; i < STM_NUM_ADCS; i++) {
|
||||
object_initialize(&s->adc[i], sizeof(s->adc[i]),
|
||||
TYPE_STM32F2XX_ADC);
|
||||
qdev_set_parent_bus(DEVICE(&s->adc[i]), sysbus_get_default());
|
||||
}
|
||||
|
||||
for (i = 0; i < STM_NUM_SPIS; i++) {
|
||||
object_initialize(&s->spi[i], sizeof(s->spi[i]),
|
||||
TYPE_STM32F2XX_SPI);
|
||||
qdev_set_parent_bus(DEVICE(&s->spi[i]), sysbus_get_default());
|
||||
}
|
||||
}
|
||||
|
||||
static void stm32f205_soc_realize(DeviceState *dev_soc, Error **errp)
|
||||
{
|
||||
STM32F205State *s = STM32F205_SOC(dev_soc);
|
||||
DeviceState *syscfgdev, *usartdev, *timerdev, *nvic;
|
||||
SysBusDevice *syscfgbusdev, *usartbusdev, *timerbusdev;
|
||||
DeviceState *dev, *nvic;
|
||||
SysBusDevice *busdev;
|
||||
Error *err = NULL;
|
||||
int i;
|
||||
|
||||
|
@ -94,44 +114,80 @@ static void stm32f205_soc_realize(DeviceState *dev_soc, Error **errp)
|
|||
s->kernel_filename, s->cpu_model);
|
||||
|
||||
/* System configuration controller */
|
||||
syscfgdev = DEVICE(&s->syscfg);
|
||||
dev = DEVICE(&s->syscfg);
|
||||
object_property_set_bool(OBJECT(&s->syscfg), true, "realized", &err);
|
||||
if (err != NULL) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
syscfgbusdev = SYS_BUS_DEVICE(syscfgdev);
|
||||
sysbus_mmio_map(syscfgbusdev, 0, 0x40013800);
|
||||
sysbus_connect_irq(syscfgbusdev, 0, qdev_get_gpio_in(nvic, 71));
|
||||
busdev = SYS_BUS_DEVICE(dev);
|
||||
sysbus_mmio_map(busdev, 0, 0x40013800);
|
||||
sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(nvic, 71));
|
||||
|
||||
/* Attach UART (uses USART registers) and USART controllers */
|
||||
for (i = 0; i < STM_NUM_USARTS; i++) {
|
||||
usartdev = DEVICE(&(s->usart[i]));
|
||||
qdev_prop_set_chr(usartdev, "chardev", i < MAX_SERIAL_PORTS ? serial_hds[i] : NULL);
|
||||
dev = DEVICE(&(s->usart[i]));
|
||||
qdev_prop_set_chr(dev, "chardev",
|
||||
i < MAX_SERIAL_PORTS ? serial_hds[i] : NULL);
|
||||
object_property_set_bool(OBJECT(&s->usart[i]), true, "realized", &err);
|
||||
if (err != NULL) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
usartbusdev = SYS_BUS_DEVICE(usartdev);
|
||||
sysbus_mmio_map(usartbusdev, 0, usart_addr[i]);
|
||||
sysbus_connect_irq(usartbusdev, 0,
|
||||
qdev_get_gpio_in(nvic, usart_irq[i]));
|
||||
busdev = SYS_BUS_DEVICE(dev);
|
||||
sysbus_mmio_map(busdev, 0, usart_addr[i]);
|
||||
sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(nvic, usart_irq[i]));
|
||||
}
|
||||
|
||||
/* Timer 2 to 5 */
|
||||
for (i = 0; i < STM_NUM_TIMERS; i++) {
|
||||
timerdev = DEVICE(&(s->timer[i]));
|
||||
qdev_prop_set_uint64(timerdev, "clock-frequency", 1000000000);
|
||||
dev = DEVICE(&(s->timer[i]));
|
||||
qdev_prop_set_uint64(dev, "clock-frequency", 1000000000);
|
||||
object_property_set_bool(OBJECT(&s->timer[i]), true, "realized", &err);
|
||||
if (err != NULL) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
timerbusdev = SYS_BUS_DEVICE(timerdev);
|
||||
sysbus_mmio_map(timerbusdev, 0, timer_addr[i]);
|
||||
sysbus_connect_irq(timerbusdev, 0,
|
||||
qdev_get_gpio_in(nvic, timer_irq[i]));
|
||||
busdev = SYS_BUS_DEVICE(dev);
|
||||
sysbus_mmio_map(busdev, 0, timer_addr[i]);
|
||||
sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(nvic, timer_irq[i]));
|
||||
}
|
||||
|
||||
/* ADC 1 to 3 */
|
||||
object_property_set_int(OBJECT(s->adc_irqs), STM_NUM_ADCS,
|
||||
"num-lines", &err);
|
||||
object_property_set_bool(OBJECT(s->adc_irqs), true, "realized", &err);
|
||||
if (err != NULL) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
qdev_connect_gpio_out(DEVICE(s->adc_irqs), 0,
|
||||
qdev_get_gpio_in(nvic, ADC_IRQ));
|
||||
|
||||
for (i = 0; i < STM_NUM_ADCS; i++) {
|
||||
dev = DEVICE(&(s->adc[i]));
|
||||
object_property_set_bool(OBJECT(&s->adc[i]), true, "realized", &err);
|
||||
if (err != NULL) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
busdev = SYS_BUS_DEVICE(dev);
|
||||
sysbus_mmio_map(busdev, 0, adc_addr[i]);
|
||||
sysbus_connect_irq(busdev, 0,
|
||||
qdev_get_gpio_in(DEVICE(s->adc_irqs), i));
|
||||
}
|
||||
|
||||
/* SPI 1 and 2 */
|
||||
for (i = 0; i < STM_NUM_SPIS; i++) {
|
||||
dev = DEVICE(&(s->spi[i]));
|
||||
object_property_set_bool(OBJECT(&s->spi[i]), true, "realized", &err);
|
||||
if (err != NULL) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
busdev = SYS_BUS_DEVICE(dev);
|
||||
sysbus_mmio_map(busdev, 0, spi_addr[i]);
|
||||
sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(nvic, spi_irq[i]));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
#include "hw/pci/pcie_host.h"
|
||||
#include "hw/pci/pci.h"
|
||||
#include "sysemu/numa.h"
|
||||
#include "kvm_arm.h"
|
||||
|
||||
#define ARM_SPI_BASE 32
|
||||
#define ACPI_POWER_BUTTON_DEVICE "PWRB"
|
||||
|
@ -546,6 +547,7 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info)
|
|||
}
|
||||
|
||||
if (guest_info->gic_version == 3) {
|
||||
AcpiMadtGenericTranslator *gic_its;
|
||||
AcpiMadtGenericRedistributor *gicr = acpi_data_push(table_data,
|
||||
sizeof *gicr);
|
||||
|
||||
|
@ -553,6 +555,16 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info)
|
|||
gicr->length = sizeof(*gicr);
|
||||
gicr->base_address = cpu_to_le64(memmap[VIRT_GIC_REDIST].base);
|
||||
gicr->range_length = cpu_to_le32(memmap[VIRT_GIC_REDIST].size);
|
||||
|
||||
if (!its_class_name()) {
|
||||
return;
|
||||
}
|
||||
|
||||
gic_its = acpi_data_push(table_data, sizeof *gic_its);
|
||||
gic_its->type = ACPI_APIC_GENERIC_TRANSLATOR;
|
||||
gic_its->length = sizeof(*gic_its);
|
||||
gic_its->translation_id = 0;
|
||||
gic_its->base_address = cpu_to_le64(memmap[VIRT_GIC_ITS].base);
|
||||
} else {
|
||||
gic_msi = acpi_data_push(table_data, sizeof *gic_msi);
|
||||
gic_msi->type = ACPI_APIC_GENERIC_MSI_FRAME;
|
||||
|
|
|
@ -76,7 +76,7 @@ typedef struct VirtBoardInfo {
|
|||
int fdt_size;
|
||||
uint32_t clock_phandle;
|
||||
uint32_t gic_phandle;
|
||||
uint32_t v2m_phandle;
|
||||
uint32_t msi_phandle;
|
||||
bool using_psci;
|
||||
} VirtBoardInfo;
|
||||
|
||||
|
@ -423,9 +423,22 @@ static void fdt_add_cpu_nodes(const VirtBoardInfo *vbi)
|
|||
}
|
||||
}
|
||||
|
||||
static void fdt_add_its_gic_node(VirtBoardInfo *vbi)
|
||||
{
|
||||
vbi->msi_phandle = qemu_fdt_alloc_phandle(vbi->fdt);
|
||||
qemu_fdt_add_subnode(vbi->fdt, "/intc/its");
|
||||
qemu_fdt_setprop_string(vbi->fdt, "/intc/its", "compatible",
|
||||
"arm,gic-v3-its");
|
||||
qemu_fdt_setprop(vbi->fdt, "/intc/its", "msi-controller", NULL, 0);
|
||||
qemu_fdt_setprop_sized_cells(vbi->fdt, "/intc/its", "reg",
|
||||
2, vbi->memmap[VIRT_GIC_ITS].base,
|
||||
2, vbi->memmap[VIRT_GIC_ITS].size);
|
||||
qemu_fdt_setprop_cell(vbi->fdt, "/intc/its", "phandle", vbi->msi_phandle);
|
||||
}
|
||||
|
||||
static void fdt_add_v2m_gic_node(VirtBoardInfo *vbi)
|
||||
{
|
||||
vbi->v2m_phandle = qemu_fdt_alloc_phandle(vbi->fdt);
|
||||
vbi->msi_phandle = qemu_fdt_alloc_phandle(vbi->fdt);
|
||||
qemu_fdt_add_subnode(vbi->fdt, "/intc/v2m");
|
||||
qemu_fdt_setprop_string(vbi->fdt, "/intc/v2m", "compatible",
|
||||
"arm,gic-v2m-frame");
|
||||
|
@ -433,7 +446,7 @@ static void fdt_add_v2m_gic_node(VirtBoardInfo *vbi)
|
|||
qemu_fdt_setprop_sized_cells(vbi->fdt, "/intc/v2m", "reg",
|
||||
2, vbi->memmap[VIRT_GIC_V2M].base,
|
||||
2, vbi->memmap[VIRT_GIC_V2M].size);
|
||||
qemu_fdt_setprop_cell(vbi->fdt, "/intc/v2m", "phandle", vbi->v2m_phandle);
|
||||
qemu_fdt_setprop_cell(vbi->fdt, "/intc/v2m", "phandle", vbi->msi_phandle);
|
||||
}
|
||||
|
||||
static void fdt_add_gic_node(VirtBoardInfo *vbi, int type)
|
||||
|
@ -500,6 +513,26 @@ static void fdt_add_pmu_nodes(const VirtBoardInfo *vbi, int gictype)
|
|||
}
|
||||
}
|
||||
|
||||
static void create_its(VirtBoardInfo *vbi, DeviceState *gicdev)
|
||||
{
|
||||
const char *itsclass = its_class_name();
|
||||
DeviceState *dev;
|
||||
|
||||
if (!itsclass) {
|
||||
/* Do nothing if not supported */
|
||||
return;
|
||||
}
|
||||
|
||||
dev = qdev_create(NULL, itsclass);
|
||||
|
||||
object_property_set_link(OBJECT(dev), OBJECT(gicdev), "parent-gicv3",
|
||||
&error_abort);
|
||||
qdev_init_nofail(dev);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, vbi->memmap[VIRT_GIC_ITS].base);
|
||||
|
||||
fdt_add_its_gic_node(vbi);
|
||||
}
|
||||
|
||||
static void create_v2m(VirtBoardInfo *vbi, qemu_irq *pic)
|
||||
{
|
||||
int i;
|
||||
|
@ -583,7 +616,9 @@ static void create_gic(VirtBoardInfo *vbi, qemu_irq *pic, int type, bool secure)
|
|||
|
||||
fdt_add_gic_node(vbi, type);
|
||||
|
||||
if (type == 2) {
|
||||
if (type == 3) {
|
||||
create_its(vbi, gicdev);
|
||||
} else {
|
||||
create_v2m(vbi, pic);
|
||||
}
|
||||
}
|
||||
|
@ -1025,9 +1060,9 @@ static void create_pcie(const VirtBoardInfo *vbi, qemu_irq *pic,
|
|||
nr_pcie_buses - 1);
|
||||
qemu_fdt_setprop(vbi->fdt, nodename, "dma-coherent", NULL, 0);
|
||||
|
||||
if (vbi->v2m_phandle) {
|
||||
if (vbi->msi_phandle) {
|
||||
qemu_fdt_setprop_cells(vbi->fdt, nodename, "msi-parent",
|
||||
vbi->v2m_phandle);
|
||||
vbi->msi_phandle);
|
||||
}
|
||||
|
||||
qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg",
|
||||
|
@ -1479,7 +1514,7 @@ static void machvirt_machine_init(void)
|
|||
}
|
||||
type_init(machvirt_machine_init);
|
||||
|
||||
static void virt_2_7_instance_init(Object *obj)
|
||||
static void virt_2_8_instance_init(Object *obj)
|
||||
{
|
||||
VirtMachineState *vms = VIRT_MACHINE(obj);
|
||||
|
||||
|
@ -1512,10 +1547,25 @@ static void virt_2_7_instance_init(Object *obj)
|
|||
"Valid values are 2, 3 and host", NULL);
|
||||
}
|
||||
|
||||
static void virt_machine_2_7_options(MachineClass *mc)
|
||||
static void virt_machine_2_8_options(MachineClass *mc)
|
||||
{
|
||||
}
|
||||
DEFINE_VIRT_MACHINE_AS_LATEST(2, 7)
|
||||
DEFINE_VIRT_MACHINE_AS_LATEST(2, 8)
|
||||
|
||||
#define VIRT_COMPAT_2_7 \
|
||||
HW_COMPAT_2_7
|
||||
|
||||
static void virt_2_7_instance_init(Object *obj)
|
||||
{
|
||||
virt_2_8_instance_init(obj);
|
||||
}
|
||||
|
||||
static void virt_machine_2_7_options(MachineClass *mc)
|
||||
{
|
||||
virt_machine_2_8_options(mc);
|
||||
SET_MACHINE_COMPAT(mc, VIRT_COMPAT_2_7);
|
||||
}
|
||||
DEFINE_VIRT_MACHINE(2, 7)
|
||||
|
||||
#define VIRT_COMPAT_2_6 \
|
||||
HW_COMPAT_2_6
|
||||
|
|
|
@ -16,4 +16,7 @@ common-obj-$(CONFIG_SOFTMMU) += null-machine.o
|
|||
common-obj-$(CONFIG_SOFTMMU) += loader.o
|
||||
common-obj-$(CONFIG_SOFTMMU) += qdev-properties-system.o
|
||||
common-obj-$(CONFIG_SOFTMMU) += register.o
|
||||
common-obj-$(CONFIG_SOFTMMU) += or-irq.o
|
||||
common-obj-$(CONFIG_PLATFORM_BUS) += platform-bus.o
|
||||
|
||||
obj-$(CONFIG_SOFTMMU) += generic-loader.o
|
||||
|
|
211
hw/core/generic-loader.c
Normal file
211
hw/core/generic-loader.c
Normal file
|
@ -0,0 +1,211 @@
|
|||
/*
|
||||
* Generic Loader
|
||||
*
|
||||
* Copyright (C) 2014 Li Guang
|
||||
* Copyright (C) 2016 Xilinx Inc.
|
||||
* Written by Li Guang <lig.fnst@cn.fujitsu.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Internally inside QEMU this is a device. It is a strange device that
|
||||
* provides no hardware interface but allows QEMU to monkey patch memory
|
||||
* specified when it is created. To be able to do this it has a reset
|
||||
* callback that does the memory operations.
|
||||
|
||||
* This device allows the user to monkey patch memory. To be able to do
|
||||
* this it needs a backend to manage the datas, the same as other
|
||||
* memory-related devices. In this case as the backend is so trivial we
|
||||
* have merged it with the frontend instead of creating and maintaining a
|
||||
* seperate backend.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qom/cpu.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "sysemu/dma.h"
|
||||
#include "hw/loader.h"
|
||||
#include "qapi/error.h"
|
||||
#include "hw/core/generic-loader.h"
|
||||
|
||||
#define CPU_NONE 0xFFFFFFFF
|
||||
|
||||
static void generic_loader_reset(void *opaque)
|
||||
{
|
||||
GenericLoaderState *s = GENERIC_LOADER(opaque);
|
||||
|
||||
if (s->set_pc) {
|
||||
CPUClass *cc = CPU_GET_CLASS(s->cpu);
|
||||
cpu_reset(s->cpu);
|
||||
if (cc) {
|
||||
cc->set_pc(s->cpu, s->addr);
|
||||
}
|
||||
}
|
||||
|
||||
if (s->data_len) {
|
||||
assert(s->data_len < sizeof(s->data));
|
||||
dma_memory_write(s->cpu->as, s->addr, &s->data, s->data_len);
|
||||
}
|
||||
}
|
||||
|
||||
static void generic_loader_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
GenericLoaderState *s = GENERIC_LOADER(dev);
|
||||
hwaddr entry;
|
||||
int big_endian;
|
||||
int size = 0;
|
||||
|
||||
s->set_pc = false;
|
||||
|
||||
/* Perform some error checking on the user's options */
|
||||
if (s->data || s->data_len || s->data_be) {
|
||||
/* User is loading memory values */
|
||||
if (s->file) {
|
||||
error_setg(errp, "Specifying a file is not supported when loading "
|
||||
"memory values");
|
||||
return;
|
||||
} else if (s->force_raw) {
|
||||
error_setg(errp, "Specifying force-raw is not supported when "
|
||||
"loading memory values");
|
||||
return;
|
||||
} else if (!s->data_len) {
|
||||
/* We cant' check for !data here as a value of 0 is still valid. */
|
||||
error_setg(errp, "Both data and data-len must be specified");
|
||||
return;
|
||||
} else if (s->data_len > 8) {
|
||||
error_setg(errp, "data-len cannot be greater then 8 bytes");
|
||||
return;
|
||||
}
|
||||
} else if (s->file || s->force_raw) {
|
||||
/* User is loading an image */
|
||||
if (s->data || s->data_len || s->data_be) {
|
||||
error_setg(errp, "data can not be specified when loading an "
|
||||
"image");
|
||||
return;
|
||||
}
|
||||
s->set_pc = true;
|
||||
} else if (s->addr) {
|
||||
/* User is setting the PC */
|
||||
if (s->data || s->data_len || s->data_be) {
|
||||
error_setg(errp, "data can not be specified when setting a "
|
||||
"program counter");
|
||||
return;
|
||||
} else if (!s->cpu_num) {
|
||||
error_setg(errp, "cpu_num must be specified when setting a "
|
||||
"program counter");
|
||||
return;
|
||||
}
|
||||
s->set_pc = true;
|
||||
} else {
|
||||
/* Did the user specify anything? */
|
||||
error_setg(errp, "please include valid arguments");
|
||||
return;
|
||||
}
|
||||
|
||||
qemu_register_reset(generic_loader_reset, dev);
|
||||
|
||||
if (s->cpu_num != CPU_NONE) {
|
||||
s->cpu = qemu_get_cpu(s->cpu_num);
|
||||
if (!s->cpu) {
|
||||
error_setg(errp, "Specified boot CPU#%d is nonexistent",
|
||||
s->cpu_num);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
s->cpu = first_cpu;
|
||||
}
|
||||
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
big_endian = 1;
|
||||
#else
|
||||
big_endian = 0;
|
||||
#endif
|
||||
|
||||
if (s->file) {
|
||||
if (!s->force_raw) {
|
||||
size = load_elf_as(s->file, NULL, NULL, &entry, NULL, NULL,
|
||||
big_endian, 0, 0, 0, s->cpu->as);
|
||||
|
||||
if (size < 0) {
|
||||
size = load_uimage_as(s->file, &entry, NULL, NULL, NULL, NULL,
|
||||
s->cpu->as);
|
||||
}
|
||||
}
|
||||
|
||||
if (size < 0 || s->force_raw) {
|
||||
/* Default to the maximum size being the machine's ram size */
|
||||
size = load_image_targphys_as(s->file, s->addr, ram_size,
|
||||
s->cpu->as);
|
||||
} else {
|
||||
s->addr = entry;
|
||||
}
|
||||
|
||||
if (size < 0) {
|
||||
error_setg(errp, "Cannot load specified image %s", s->file);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Convert the data endiannes */
|
||||
if (s->data_be) {
|
||||
s->data = cpu_to_be64(s->data);
|
||||
} else {
|
||||
s->data = cpu_to_le64(s->data);
|
||||
}
|
||||
}
|
||||
|
||||
static void generic_loader_unrealize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
qemu_unregister_reset(generic_loader_reset, dev);
|
||||
}
|
||||
|
||||
static Property generic_loader_props[] = {
|
||||
DEFINE_PROP_UINT64("addr", GenericLoaderState, addr, 0),
|
||||
DEFINE_PROP_UINT64("data", GenericLoaderState, data, 0),
|
||||
DEFINE_PROP_UINT8("data-len", GenericLoaderState, data_len, 0),
|
||||
DEFINE_PROP_BOOL("data-be", GenericLoaderState, data_be, false),
|
||||
DEFINE_PROP_UINT32("cpu-num", GenericLoaderState, cpu_num, CPU_NONE),
|
||||
DEFINE_PROP_BOOL("force-raw", GenericLoaderState, force_raw, false),
|
||||
DEFINE_PROP_STRING("file", GenericLoaderState, file),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void generic_loader_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
/* The reset function is not registered here and is instead registered in
|
||||
* the realize function to allow this device to be added via the device_add
|
||||
* command in the QEMU monitor.
|
||||
* TODO: Improve the device_add functionality to allow resets to be
|
||||
* connected
|
||||
*/
|
||||
dc->realize = generic_loader_realize;
|
||||
dc->unrealize = generic_loader_unrealize;
|
||||
dc->props = generic_loader_props;
|
||||
dc->desc = "Generic Loader";
|
||||
}
|
||||
|
||||
static TypeInfo generic_loader_info = {
|
||||
.name = TYPE_GENERIC_LOADER,
|
||||
.parent = TYPE_DEVICE,
|
||||
.instance_size = sizeof(GenericLoaderState),
|
||||
.class_init = generic_loader_class_init,
|
||||
};
|
||||
|
||||
static void generic_loader_register_type(void)
|
||||
{
|
||||
type_register_static(&generic_loader_info);
|
||||
}
|
||||
|
||||
type_init(generic_loader_register_type)
|
107
hw/core/or-irq.c
Normal file
107
hw/core/or-irq.c
Normal file
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
* QEMU IRQ/GPIO common code.
|
||||
*
|
||||
* Copyright (c) 2016 Alistair Francis <alistair@alistair23.me>.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/or-irq.h"
|
||||
|
||||
static void or_irq_handler(void *opaque, int n, int level)
|
||||
{
|
||||
qemu_or_irq *s = OR_IRQ(opaque);
|
||||
int or_level = 0;
|
||||
int i;
|
||||
|
||||
s->levels[n] = level;
|
||||
|
||||
for (i = 0; i < s->num_lines; i++) {
|
||||
or_level |= s->levels[i];
|
||||
}
|
||||
|
||||
qemu_set_irq(s->out_irq, or_level);
|
||||
}
|
||||
|
||||
static void or_irq_reset(DeviceState *dev)
|
||||
{
|
||||
qemu_or_irq *s = OR_IRQ(dev);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_OR_LINES; i++) {
|
||||
s->levels[i] = false;
|
||||
}
|
||||
}
|
||||
|
||||
static void or_irq_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
qemu_or_irq *s = OR_IRQ(dev);
|
||||
|
||||
assert(s->num_lines < MAX_OR_LINES);
|
||||
|
||||
qdev_init_gpio_in(dev, or_irq_handler, s->num_lines);
|
||||
}
|
||||
|
||||
static void or_irq_init(Object *obj)
|
||||
{
|
||||
qemu_or_irq *s = OR_IRQ(obj);
|
||||
|
||||
qdev_init_gpio_out(DEVICE(obj), &s->out_irq, 1);
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_or_irq = {
|
||||
.name = TYPE_OR_IRQ,
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_BOOL_ARRAY(levels, qemu_or_irq, MAX_OR_LINES),
|
||||
VMSTATE_END_OF_LIST(),
|
||||
}
|
||||
};
|
||||
|
||||
static Property or_irq_properties[] = {
|
||||
DEFINE_PROP_UINT16("num-lines", qemu_or_irq, num_lines, 1),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void or_irq_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->reset = or_irq_reset;
|
||||
dc->props = or_irq_properties;
|
||||
dc->realize = or_irq_realize;
|
||||
dc->vmsd = &vmstate_or_irq;
|
||||
}
|
||||
|
||||
static const TypeInfo or_irq_type_info = {
|
||||
.name = TYPE_OR_IRQ,
|
||||
.parent = TYPE_DEVICE,
|
||||
.instance_size = sizeof(qemu_or_irq),
|
||||
.instance_init = or_irq_init,
|
||||
.class_init = or_irq_class_init,
|
||||
};
|
||||
|
||||
static void or_irq_register_types(void)
|
||||
{
|
||||
type_register_static(&or_irq_type_info);
|
||||
}
|
||||
|
||||
type_init(or_irq_register_types)
|
|
@ -31,30 +31,31 @@ typedef struct {
|
|||
QEMUTimer *timer;
|
||||
uint16_t model;
|
||||
|
||||
int x, y;
|
||||
int pressure;
|
||||
int32_t x, y;
|
||||
bool pressure;
|
||||
|
||||
int state, reg, irq, command;
|
||||
uint8_t reg, state;
|
||||
bool irq, command;
|
||||
uint16_t data, dav;
|
||||
|
||||
int busy;
|
||||
int enabled;
|
||||
int host_mode;
|
||||
int function;
|
||||
int nextfunction;
|
||||
int precision;
|
||||
int nextprecision;
|
||||
int filter;
|
||||
int pin_func;
|
||||
int timing[2];
|
||||
int noise;
|
||||
int reset;
|
||||
int pdst;
|
||||
int pnd0;
|
||||
bool busy;
|
||||
bool enabled;
|
||||
bool host_mode;
|
||||
int8_t function;
|
||||
int8_t nextfunction;
|
||||
bool precision;
|
||||
bool nextprecision;
|
||||
uint16_t filter;
|
||||
uint8_t pin_func;
|
||||
uint16_t timing[2];
|
||||
uint8_t noise;
|
||||
bool reset;
|
||||
bool pdst;
|
||||
bool pnd0;
|
||||
uint16_t temp_thr[2];
|
||||
uint16_t aux_thr[2];
|
||||
|
||||
int tr[8];
|
||||
int32_t tr[8];
|
||||
} TSC2005State;
|
||||
|
||||
enum {
|
||||
|
@ -149,7 +150,7 @@ static uint16_t tsc2005_read(TSC2005State *s, int reg)
|
|||
ret = s->dav | (s->reset << 7) | (s->pdst << 2) | 0x0;
|
||||
s->dav &= ~(mode_regs[TSC_MODE_X_TEST] | mode_regs[TSC_MODE_Y_TEST] |
|
||||
mode_regs[TSC_MODE_TS_TEST]);
|
||||
s->reset = 1;
|
||||
s->reset = true;
|
||||
return ret;
|
||||
|
||||
case 0x8: /* AUX high treshold */
|
||||
|
@ -196,14 +197,14 @@ static void tsc2005_write(TSC2005State *s, int reg, uint16_t data)
|
|||
break;
|
||||
|
||||
case 0xc: /* CFR0 */
|
||||
s->host_mode = data >> 15;
|
||||
s->host_mode = (data >> 15) != 0;
|
||||
if (s->enabled != !(data & 0x4000)) {
|
||||
s->enabled = !(data & 0x4000);
|
||||
fprintf(stderr, "%s: touchscreen sense %sabled\n",
|
||||
__FUNCTION__, s->enabled ? "en" : "dis");
|
||||
if (s->busy && !s->enabled)
|
||||
timer_del(s->timer);
|
||||
s->busy &= s->enabled;
|
||||
s->busy = s->busy && s->enabled;
|
||||
}
|
||||
s->nextprecision = (data >> 13) & 1;
|
||||
s->timing[0] = data & 0x1fff;
|
||||
|
@ -229,7 +230,7 @@ static void tsc2005_write(TSC2005State *s, int reg, uint16_t data)
|
|||
static void tsc2005_pin_update(TSC2005State *s)
|
||||
{
|
||||
int64_t expires;
|
||||
int pin_state;
|
||||
bool pin_state;
|
||||
|
||||
switch (s->pin_func) {
|
||||
case 0:
|
||||
|
@ -253,7 +254,7 @@ static void tsc2005_pin_update(TSC2005State *s)
|
|||
case TSC_MODE_XYZ_SCAN:
|
||||
case TSC_MODE_XY_SCAN:
|
||||
if (!s->host_mode && s->dav)
|
||||
s->enabled = 0;
|
||||
s->enabled = false;
|
||||
if (!s->pressure)
|
||||
return;
|
||||
/* Fall through */
|
||||
|
@ -273,7 +274,7 @@ static void tsc2005_pin_update(TSC2005State *s)
|
|||
case TSC_MODE_Y_TEST:
|
||||
case TSC_MODE_TS_TEST:
|
||||
if (s->dav)
|
||||
s->enabled = 0;
|
||||
s->enabled = false;
|
||||
break;
|
||||
|
||||
case TSC_MODE_RESERVED:
|
||||
|
@ -287,7 +288,7 @@ static void tsc2005_pin_update(TSC2005State *s)
|
|||
if (!s->enabled || s->busy)
|
||||
return;
|
||||
|
||||
s->busy = 1;
|
||||
s->busy = true;
|
||||
s->precision = s->nextprecision;
|
||||
s->function = s->nextfunction;
|
||||
s->pdst = !s->pnd0; /* Synchronised on internal clock */
|
||||
|
@ -300,17 +301,17 @@ static void tsc2005_reset(TSC2005State *s)
|
|||
{
|
||||
s->state = 0;
|
||||
s->pin_func = 0;
|
||||
s->enabled = 0;
|
||||
s->busy = 0;
|
||||
s->nextprecision = 0;
|
||||
s->enabled = false;
|
||||
s->busy = false;
|
||||
s->nextprecision = false;
|
||||
s->nextfunction = 0;
|
||||
s->timing[0] = 0;
|
||||
s->timing[1] = 0;
|
||||
s->irq = 0;
|
||||
s->irq = false;
|
||||
s->dav = 0;
|
||||
s->reset = 0;
|
||||
s->pdst = 1;
|
||||
s->pnd0 = 0;
|
||||
s->reset = false;
|
||||
s->pdst = true;
|
||||
s->pnd0 = false;
|
||||
s->function = -1;
|
||||
s->temp_thr[0] = 0x000;
|
||||
s->temp_thr[1] = 0xfff;
|
||||
|
@ -340,7 +341,7 @@ static uint8_t tsc2005_txrx_word(void *opaque, uint8_t value)
|
|||
__FUNCTION__, s->enabled ? "en" : "dis");
|
||||
if (s->busy && !s->enabled)
|
||||
timer_del(s->timer);
|
||||
s->busy &= s->enabled;
|
||||
s->busy = s->busy && s->enabled;
|
||||
}
|
||||
tsc2005_pin_update(s);
|
||||
}
|
||||
|
@ -407,7 +408,7 @@ static void tsc2005_timer_tick(void *opaque)
|
|||
if (!s->busy)
|
||||
return;
|
||||
|
||||
s->busy = 0;
|
||||
s->busy = false;
|
||||
s->dav |= mode_regs[s->function];
|
||||
s->function = -1;
|
||||
tsc2005_pin_update(s);
|
||||
|
@ -434,86 +435,9 @@ static void tsc2005_touchscreen_event(void *opaque,
|
|||
tsc2005_pin_update(s);
|
||||
}
|
||||
|
||||
static void tsc2005_save(QEMUFile *f, void *opaque)
|
||||
static int tsc2005_post_load(void *opaque, int version_id)
|
||||
{
|
||||
TSC2005State *s = (TSC2005State *) opaque;
|
||||
int i;
|
||||
|
||||
qemu_put_be16(f, s->x);
|
||||
qemu_put_be16(f, s->y);
|
||||
qemu_put_byte(f, s->pressure);
|
||||
|
||||
qemu_put_byte(f, s->state);
|
||||
qemu_put_byte(f, s->reg);
|
||||
qemu_put_byte(f, s->command);
|
||||
|
||||
qemu_put_byte(f, s->irq);
|
||||
qemu_put_be16s(f, &s->dav);
|
||||
qemu_put_be16s(f, &s->data);
|
||||
|
||||
timer_put(f, s->timer);
|
||||
qemu_put_byte(f, s->enabled);
|
||||
qemu_put_byte(f, s->host_mode);
|
||||
qemu_put_byte(f, s->function);
|
||||
qemu_put_byte(f, s->nextfunction);
|
||||
qemu_put_byte(f, s->precision);
|
||||
qemu_put_byte(f, s->nextprecision);
|
||||
qemu_put_be16(f, s->filter);
|
||||
qemu_put_byte(f, s->pin_func);
|
||||
qemu_put_be16(f, s->timing[0]);
|
||||
qemu_put_be16(f, s->timing[1]);
|
||||
qemu_put_be16s(f, &s->temp_thr[0]);
|
||||
qemu_put_be16s(f, &s->temp_thr[1]);
|
||||
qemu_put_be16s(f, &s->aux_thr[0]);
|
||||
qemu_put_be16s(f, &s->aux_thr[1]);
|
||||
qemu_put_be32(f, s->noise);
|
||||
qemu_put_byte(f, s->reset);
|
||||
qemu_put_byte(f, s->pdst);
|
||||
qemu_put_byte(f, s->pnd0);
|
||||
|
||||
for (i = 0; i < 8; i ++)
|
||||
qemu_put_be32(f, s->tr[i]);
|
||||
}
|
||||
|
||||
static int tsc2005_load(QEMUFile *f, void *opaque, int version_id)
|
||||
{
|
||||
TSC2005State *s = (TSC2005State *) opaque;
|
||||
int i;
|
||||
|
||||
s->x = qemu_get_be16(f);
|
||||
s->y = qemu_get_be16(f);
|
||||
s->pressure = qemu_get_byte(f);
|
||||
|
||||
s->state = qemu_get_byte(f);
|
||||
s->reg = qemu_get_byte(f);
|
||||
s->command = qemu_get_byte(f);
|
||||
|
||||
s->irq = qemu_get_byte(f);
|
||||
qemu_get_be16s(f, &s->dav);
|
||||
qemu_get_be16s(f, &s->data);
|
||||
|
||||
timer_get(f, s->timer);
|
||||
s->enabled = qemu_get_byte(f);
|
||||
s->host_mode = qemu_get_byte(f);
|
||||
s->function = qemu_get_byte(f);
|
||||
s->nextfunction = qemu_get_byte(f);
|
||||
s->precision = qemu_get_byte(f);
|
||||
s->nextprecision = qemu_get_byte(f);
|
||||
s->filter = qemu_get_be16(f);
|
||||
s->pin_func = qemu_get_byte(f);
|
||||
s->timing[0] = qemu_get_be16(f);
|
||||
s->timing[1] = qemu_get_be16(f);
|
||||
qemu_get_be16s(f, &s->temp_thr[0]);
|
||||
qemu_get_be16s(f, &s->temp_thr[1]);
|
||||
qemu_get_be16s(f, &s->aux_thr[0]);
|
||||
qemu_get_be16s(f, &s->aux_thr[1]);
|
||||
s->noise = qemu_get_be32(f);
|
||||
s->reset = qemu_get_byte(f);
|
||||
s->pdst = qemu_get_byte(f);
|
||||
s->pnd0 = qemu_get_byte(f);
|
||||
|
||||
for (i = 0; i < 8; i ++)
|
||||
s->tr[i] = qemu_get_be32(f);
|
||||
|
||||
s->busy = timer_pending(s->timer);
|
||||
tsc2005_pin_update(s);
|
||||
|
@ -521,6 +445,42 @@ static int tsc2005_load(QEMUFile *f, void *opaque, int version_id)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_tsc2005 = {
|
||||
.name = "tsc2005",
|
||||
.version_id = 2,
|
||||
.minimum_version_id = 2,
|
||||
.post_load = tsc2005_post_load,
|
||||
.fields = (VMStateField []) {
|
||||
VMSTATE_BOOL(pressure, TSC2005State),
|
||||
VMSTATE_BOOL(irq, TSC2005State),
|
||||
VMSTATE_BOOL(command, TSC2005State),
|
||||
VMSTATE_BOOL(enabled, TSC2005State),
|
||||
VMSTATE_BOOL(host_mode, TSC2005State),
|
||||
VMSTATE_BOOL(reset, TSC2005State),
|
||||
VMSTATE_BOOL(pdst, TSC2005State),
|
||||
VMSTATE_BOOL(pnd0, TSC2005State),
|
||||
VMSTATE_BOOL(precision, TSC2005State),
|
||||
VMSTATE_BOOL(nextprecision, TSC2005State),
|
||||
VMSTATE_UINT8(reg, TSC2005State),
|
||||
VMSTATE_UINT8(state, TSC2005State),
|
||||
VMSTATE_UINT16(data, TSC2005State),
|
||||
VMSTATE_UINT16(dav, TSC2005State),
|
||||
VMSTATE_UINT16(filter, TSC2005State),
|
||||
VMSTATE_INT8(nextfunction, TSC2005State),
|
||||
VMSTATE_INT8(function, TSC2005State),
|
||||
VMSTATE_INT32(x, TSC2005State),
|
||||
VMSTATE_INT32(y, TSC2005State),
|
||||
VMSTATE_TIMER_PTR(timer, TSC2005State),
|
||||
VMSTATE_UINT8(pin_func, TSC2005State),
|
||||
VMSTATE_UINT16_ARRAY(timing, TSC2005State, 2),
|
||||
VMSTATE_UINT8(noise, TSC2005State),
|
||||
VMSTATE_UINT16_ARRAY(temp_thr, TSC2005State, 2),
|
||||
VMSTATE_UINT16_ARRAY(aux_thr, TSC2005State, 2),
|
||||
VMSTATE_INT32_ARRAY(tr, TSC2005State, 8),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
void *tsc2005_init(qemu_irq pintdav)
|
||||
{
|
||||
TSC2005State *s;
|
||||
|
@ -529,8 +489,8 @@ void *tsc2005_init(qemu_irq pintdav)
|
|||
g_malloc0(sizeof(TSC2005State));
|
||||
s->x = 400;
|
||||
s->y = 240;
|
||||
s->pressure = 0;
|
||||
s->precision = s->nextprecision = 0;
|
||||
s->pressure = false;
|
||||
s->precision = s->nextprecision = false;
|
||||
s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, tsc2005_timer_tick, s);
|
||||
s->pint = pintdav;
|
||||
s->model = 0x2005;
|
||||
|
@ -550,7 +510,7 @@ void *tsc2005_init(qemu_irq pintdav)
|
|||
"QEMU TSC2005-driven Touchscreen");
|
||||
|
||||
qemu_register_reset((void *) tsc2005_reset, s);
|
||||
register_savevm(NULL, "tsc2005", -1, 0, tsc2005_save, tsc2005_load, s);
|
||||
vmstate_register(NULL, 0, &vmstate_tsc2005, s);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
|
|
@ -47,24 +47,25 @@ typedef struct {
|
|||
uint8_t out_fifo[16384];
|
||||
uint16_t model;
|
||||
|
||||
int x, y;
|
||||
int pressure;
|
||||
int32_t x, y;
|
||||
bool pressure;
|
||||
|
||||
int state, page, offset, irq;
|
||||
uint16_t command, dav;
|
||||
uint8_t page, offset;
|
||||
uint16_t dav;
|
||||
|
||||
int busy;
|
||||
int enabled;
|
||||
int host_mode;
|
||||
int function;
|
||||
int nextfunction;
|
||||
int precision;
|
||||
int nextprecision;
|
||||
int filter;
|
||||
int pin_func;
|
||||
int ref;
|
||||
int timing;
|
||||
int noise;
|
||||
bool state;
|
||||
bool irq;
|
||||
bool command;
|
||||
bool busy;
|
||||
bool enabled;
|
||||
bool host_mode;
|
||||
uint8_t function, nextfunction;
|
||||
uint8_t precision, nextprecision;
|
||||
uint8_t filter;
|
||||
uint8_t pin_func;
|
||||
uint8_t ref;
|
||||
uint8_t timing;
|
||||
uint8_t noise;
|
||||
|
||||
uint16_t audio_ctrl1;
|
||||
uint16_t audio_ctrl2;
|
||||
|
@ -72,7 +73,7 @@ typedef struct {
|
|||
uint16_t pll[3];
|
||||
uint16_t volume;
|
||||
int64_t volume_change;
|
||||
int softstep;
|
||||
bool softstep;
|
||||
uint16_t dac_power;
|
||||
int64_t powerdown;
|
||||
uint16_t filter_data[0x14];
|
||||
|
@ -93,6 +94,7 @@ typedef struct {
|
|||
int mode;
|
||||
int intr;
|
||||
} kb;
|
||||
int64_t now; /* Time at migration */
|
||||
} TSC210xState;
|
||||
|
||||
static const int resolution[4] = { 12, 8, 10, 12 };
|
||||
|
@ -154,14 +156,14 @@ static const uint16_t mode_regs[16] = {
|
|||
|
||||
static void tsc210x_reset(TSC210xState *s)
|
||||
{
|
||||
s->state = 0;
|
||||
s->state = false;
|
||||
s->pin_func = 2;
|
||||
s->enabled = 0;
|
||||
s->busy = 0;
|
||||
s->enabled = false;
|
||||
s->busy = false;
|
||||
s->nextfunction = 0;
|
||||
s->ref = 0;
|
||||
s->timing = 0;
|
||||
s->irq = 0;
|
||||
s->irq = false;
|
||||
s->dav = 0;
|
||||
|
||||
s->audio_ctrl1 = 0x0000;
|
||||
|
@ -172,7 +174,7 @@ static void tsc210x_reset(TSC210xState *s)
|
|||
s->pll[2] = 0x1fff;
|
||||
s->volume = 0xffff;
|
||||
s->dac_power = 0x8540;
|
||||
s->softstep = 1;
|
||||
s->softstep = true;
|
||||
s->volume_change = 0;
|
||||
s->powerdown = 0;
|
||||
s->filter_data[0x00] = 0x6be3;
|
||||
|
@ -566,7 +568,7 @@ static void tsc2102_control_register_write(
|
|||
s->enabled = !(value & 0x4000);
|
||||
if (s->busy && !s->enabled)
|
||||
timer_del(s->timer);
|
||||
s->busy &= s->enabled;
|
||||
s->busy = s->busy && s->enabled;
|
||||
s->nextfunction = (value >> 10) & 0xf;
|
||||
s->nextprecision = (value >> 8) & 3;
|
||||
s->filter = value & 0xff;
|
||||
|
@ -773,7 +775,7 @@ static void tsc2102_audio_register_write(
|
|||
static void tsc210x_pin_update(TSC210xState *s)
|
||||
{
|
||||
int64_t expires;
|
||||
int pin_state;
|
||||
bool pin_state;
|
||||
|
||||
switch (s->pin_func) {
|
||||
case 0:
|
||||
|
@ -788,7 +790,7 @@ static void tsc210x_pin_update(TSC210xState *s)
|
|||
}
|
||||
|
||||
if (!s->enabled)
|
||||
pin_state = 0;
|
||||
pin_state = false;
|
||||
|
||||
if (pin_state != s->irq) {
|
||||
s->irq = pin_state;
|
||||
|
@ -814,7 +816,7 @@ static void tsc210x_pin_update(TSC210xState *s)
|
|||
case TSC_MODE_TEMP1:
|
||||
case TSC_MODE_TEMP2:
|
||||
if (s->dav)
|
||||
s->enabled = 0;
|
||||
s->enabled = false;
|
||||
break;
|
||||
|
||||
case TSC_MODE_AUX_SCAN:
|
||||
|
@ -832,7 +834,7 @@ static void tsc210x_pin_update(TSC210xState *s)
|
|||
if (!s->enabled || s->busy || s->dav)
|
||||
return;
|
||||
|
||||
s->busy = 1;
|
||||
s->busy = true;
|
||||
s->precision = s->nextprecision;
|
||||
s->function = s->nextfunction;
|
||||
expires = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
|
||||
|
@ -867,7 +869,7 @@ static uint16_t tsc210x_read(TSC210xState *s)
|
|||
|
||||
/* Allow sequential reads. */
|
||||
s->offset ++;
|
||||
s->state = 0;
|
||||
s->state = false;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -878,10 +880,10 @@ static void tsc210x_write(TSC210xState *s, uint16_t value)
|
|||
* command and data every second time.
|
||||
*/
|
||||
if (!s->state) {
|
||||
s->command = value >> 15;
|
||||
s->command = (value >> 15) != 0;
|
||||
s->page = (value >> 11) & 0x0f;
|
||||
s->offset = (value >> 5) & 0x3f;
|
||||
s->state = 1;
|
||||
s->state = true;
|
||||
} else {
|
||||
if (s->command)
|
||||
fprintf(stderr, "tsc210x_write: SPI overrun!\n");
|
||||
|
@ -901,7 +903,7 @@ static void tsc210x_write(TSC210xState *s, uint16_t value)
|
|||
}
|
||||
|
||||
tsc210x_pin_update(s);
|
||||
s->state = 0;
|
||||
s->state = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -933,7 +935,7 @@ static void tsc210x_timer_tick(void *opaque)
|
|||
if (!s->busy)
|
||||
return;
|
||||
|
||||
s->busy = 0;
|
||||
s->busy = false;
|
||||
s->dav |= mode_regs[s->function];
|
||||
tsc210x_pin_update(s);
|
||||
qemu_irq_lower(s->davint);
|
||||
|
@ -974,108 +976,34 @@ static void tsc210x_i2s_set_rate(TSC210xState *s, int in, int out)
|
|||
s->i2s_rx_rate = in;
|
||||
}
|
||||
|
||||
static void tsc210x_save(QEMUFile *f, void *opaque)
|
||||
static void tsc210x_pre_save(void *opaque)
|
||||
{
|
||||
TSC210xState *s = (TSC210xState *) opaque;
|
||||
int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
||||
int i;
|
||||
|
||||
qemu_put_be16(f, s->x);
|
||||
qemu_put_be16(f, s->y);
|
||||
qemu_put_byte(f, s->pressure);
|
||||
|
||||
qemu_put_byte(f, s->state);
|
||||
qemu_put_byte(f, s->page);
|
||||
qemu_put_byte(f, s->offset);
|
||||
qemu_put_byte(f, s->command);
|
||||
|
||||
qemu_put_byte(f, s->irq);
|
||||
qemu_put_be16s(f, &s->dav);
|
||||
|
||||
timer_put(f, s->timer);
|
||||
qemu_put_byte(f, s->enabled);
|
||||
qemu_put_byte(f, s->host_mode);
|
||||
qemu_put_byte(f, s->function);
|
||||
qemu_put_byte(f, s->nextfunction);
|
||||
qemu_put_byte(f, s->precision);
|
||||
qemu_put_byte(f, s->nextprecision);
|
||||
qemu_put_byte(f, s->filter);
|
||||
qemu_put_byte(f, s->pin_func);
|
||||
qemu_put_byte(f, s->ref);
|
||||
qemu_put_byte(f, s->timing);
|
||||
qemu_put_be32(f, s->noise);
|
||||
|
||||
qemu_put_be16s(f, &s->audio_ctrl1);
|
||||
qemu_put_be16s(f, &s->audio_ctrl2);
|
||||
qemu_put_be16s(f, &s->audio_ctrl3);
|
||||
qemu_put_be16s(f, &s->pll[0]);
|
||||
qemu_put_be16s(f, &s->pll[1]);
|
||||
qemu_put_be16s(f, &s->volume);
|
||||
qemu_put_sbe64(f, (s->volume_change - now));
|
||||
qemu_put_sbe64(f, (s->powerdown - now));
|
||||
qemu_put_byte(f, s->softstep);
|
||||
qemu_put_be16s(f, &s->dac_power);
|
||||
|
||||
for (i = 0; i < 0x14; i ++)
|
||||
qemu_put_be16s(f, &s->filter_data[i]);
|
||||
s->now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
||||
}
|
||||
|
||||
static int tsc210x_load(QEMUFile *f, void *opaque, int version_id)
|
||||
static int tsc210x_post_load(void *opaque, int version_id)
|
||||
{
|
||||
TSC210xState *s = (TSC210xState *) opaque;
|
||||
int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
||||
int i;
|
||||
|
||||
s->x = qemu_get_be16(f);
|
||||
s->y = qemu_get_be16(f);
|
||||
s->pressure = qemu_get_byte(f);
|
||||
|
||||
s->state = qemu_get_byte(f);
|
||||
s->page = qemu_get_byte(f);
|
||||
s->offset = qemu_get_byte(f);
|
||||
s->command = qemu_get_byte(f);
|
||||
|
||||
s->irq = qemu_get_byte(f);
|
||||
qemu_get_be16s(f, &s->dav);
|
||||
|
||||
timer_get(f, s->timer);
|
||||
s->enabled = qemu_get_byte(f);
|
||||
s->host_mode = qemu_get_byte(f);
|
||||
s->function = qemu_get_byte(f);
|
||||
if (s->function < 0 || s->function >= ARRAY_SIZE(mode_regs)) {
|
||||
if (s->function >= ARRAY_SIZE(mode_regs)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
s->nextfunction = qemu_get_byte(f);
|
||||
if (s->nextfunction < 0 || s->nextfunction >= ARRAY_SIZE(mode_regs)) {
|
||||
if (s->nextfunction >= ARRAY_SIZE(mode_regs)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
s->precision = qemu_get_byte(f);
|
||||
if (s->precision < 0 || s->precision >= ARRAY_SIZE(resolution)) {
|
||||
if (s->precision >= ARRAY_SIZE(resolution)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
s->nextprecision = qemu_get_byte(f);
|
||||
if (s->nextprecision < 0 || s->nextprecision >= ARRAY_SIZE(resolution)) {
|
||||
if (s->nextprecision >= ARRAY_SIZE(resolution)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
s->filter = qemu_get_byte(f);
|
||||
s->pin_func = qemu_get_byte(f);
|
||||
s->ref = qemu_get_byte(f);
|
||||
s->timing = qemu_get_byte(f);
|
||||
s->noise = qemu_get_be32(f);
|
||||
|
||||
qemu_get_be16s(f, &s->audio_ctrl1);
|
||||
qemu_get_be16s(f, &s->audio_ctrl2);
|
||||
qemu_get_be16s(f, &s->audio_ctrl3);
|
||||
qemu_get_be16s(f, &s->pll[0]);
|
||||
qemu_get_be16s(f, &s->pll[1]);
|
||||
qemu_get_be16s(f, &s->volume);
|
||||
s->volume_change = qemu_get_sbe64(f) + now;
|
||||
s->powerdown = qemu_get_sbe64(f) + now;
|
||||
s->softstep = qemu_get_byte(f);
|
||||
qemu_get_be16s(f, &s->dac_power);
|
||||
|
||||
for (i = 0; i < 0x14; i ++)
|
||||
qemu_get_be16s(f, &s->filter_data[i]);
|
||||
s->volume_change -= s->now;
|
||||
s->volume_change += now;
|
||||
s->powerdown -= s->now;
|
||||
s->powerdown += now;
|
||||
|
||||
s->busy = timer_pending(s->timer);
|
||||
qemu_set_irq(s->pint, !s->irq);
|
||||
|
@ -1084,6 +1012,60 @@ static int tsc210x_load(QEMUFile *f, void *opaque, int version_id)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static VMStateField vmstatefields_tsc210x[] = {
|
||||
VMSTATE_BOOL(enabled, TSC210xState),
|
||||
VMSTATE_BOOL(host_mode, TSC210xState),
|
||||
VMSTATE_BOOL(irq, TSC210xState),
|
||||
VMSTATE_BOOL(command, TSC210xState),
|
||||
VMSTATE_BOOL(pressure, TSC210xState),
|
||||
VMSTATE_BOOL(softstep, TSC210xState),
|
||||
VMSTATE_BOOL(state, TSC210xState),
|
||||
VMSTATE_UINT16(dav, TSC210xState),
|
||||
VMSTATE_INT32(x, TSC210xState),
|
||||
VMSTATE_INT32(y, TSC210xState),
|
||||
VMSTATE_UINT8(offset, TSC210xState),
|
||||
VMSTATE_UINT8(page, TSC210xState),
|
||||
VMSTATE_UINT8(filter, TSC210xState),
|
||||
VMSTATE_UINT8(pin_func, TSC210xState),
|
||||
VMSTATE_UINT8(ref, TSC210xState),
|
||||
VMSTATE_UINT8(timing, TSC210xState),
|
||||
VMSTATE_UINT8(noise, TSC210xState),
|
||||
VMSTATE_UINT8(function, TSC210xState),
|
||||
VMSTATE_UINT8(nextfunction, TSC210xState),
|
||||
VMSTATE_UINT8(precision, TSC210xState),
|
||||
VMSTATE_UINT8(nextprecision, TSC210xState),
|
||||
VMSTATE_UINT16(audio_ctrl1, TSC210xState),
|
||||
VMSTATE_UINT16(audio_ctrl2, TSC210xState),
|
||||
VMSTATE_UINT16(audio_ctrl3, TSC210xState),
|
||||
VMSTATE_UINT16_ARRAY(pll, TSC210xState, 3),
|
||||
VMSTATE_UINT16(volume, TSC210xState),
|
||||
VMSTATE_UINT16(dac_power, TSC210xState),
|
||||
VMSTATE_INT64(volume_change, TSC210xState),
|
||||
VMSTATE_INT64(powerdown, TSC210xState),
|
||||
VMSTATE_INT64(now, TSC210xState),
|
||||
VMSTATE_UINT16_ARRAY(filter_data, TSC210xState, 0x14),
|
||||
VMSTATE_TIMER_PTR(timer, TSC210xState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
};
|
||||
|
||||
static const VMStateDescription vmstate_tsc2102 = {
|
||||
.name = "tsc2102",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.pre_save = tsc210x_pre_save,
|
||||
.post_load = tsc210x_post_load,
|
||||
.fields = vmstatefields_tsc210x,
|
||||
};
|
||||
|
||||
static const VMStateDescription vmstate_tsc2301 = {
|
||||
.name = "tsc2301",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.pre_save = tsc210x_pre_save,
|
||||
.post_load = tsc210x_post_load,
|
||||
.fields = vmstatefields_tsc210x,
|
||||
};
|
||||
|
||||
uWireSlave *tsc2102_init(qemu_irq pint)
|
||||
{
|
||||
TSC210xState *s;
|
||||
|
@ -1125,8 +1107,7 @@ uWireSlave *tsc2102_init(qemu_irq pint)
|
|||
AUD_register_card(s->name, &s->card);
|
||||
|
||||
qemu_register_reset((void *) tsc210x_reset, s);
|
||||
register_savevm(NULL, s->name, -1, 0,
|
||||
tsc210x_save, tsc210x_load, s);
|
||||
vmstate_register(NULL, 0, &vmstate_tsc2102, s);
|
||||
|
||||
return &s->chip;
|
||||
}
|
||||
|
@ -1174,7 +1155,7 @@ uWireSlave *tsc2301_init(qemu_irq penirq, qemu_irq kbirq, qemu_irq dav)
|
|||
AUD_register_card(s->name, &s->card);
|
||||
|
||||
qemu_register_reset((void *) tsc210x_reset, s);
|
||||
register_savevm(NULL, s->name, -1, 0, tsc210x_save, tsc210x_load, s);
|
||||
vmstate_register(NULL, 0, &vmstate_tsc2301, s);
|
||||
|
||||
return &s->chip;
|
||||
}
|
||||
|
|
|
@ -16,11 +16,13 @@ common-obj-$(CONFIG_ARM_GIC) += arm_gicv3_common.o
|
|||
common-obj-$(CONFIG_ARM_GIC) += arm_gicv3.o
|
||||
common-obj-$(CONFIG_ARM_GIC) += arm_gicv3_dist.o
|
||||
common-obj-$(CONFIG_ARM_GIC) += arm_gicv3_redist.o
|
||||
common-obj-$(CONFIG_ARM_GIC) += arm_gicv3_its_common.o
|
||||
common-obj-$(CONFIG_OPENPIC) += openpic.o
|
||||
|
||||
obj-$(CONFIG_APIC) += apic.o apic_common.o
|
||||
obj-$(CONFIG_ARM_GIC_KVM) += arm_gic_kvm.o
|
||||
obj-$(call land,$(CONFIG_ARM_GIC_KVM),$(TARGET_AARCH64)) += arm_gicv3_kvm.o
|
||||
obj-$(call land,$(CONFIG_ARM_GIC_KVM),$(TARGET_AARCH64)) += arm_gicv3_its_kvm.o
|
||||
obj-$(CONFIG_STELLARIS) += armv7m_nvic.o
|
||||
obj-$(CONFIG_EXYNOS4) += exynos4210_gic.o exynos4210_combiner.o
|
||||
obj-$(CONFIG_GRLIB) += grlib_irqmp.o
|
||||
|
|
|
@ -577,6 +577,18 @@ static void kvm_arm_gic_realize(DeviceState *dev, Error **errp)
|
|||
"not support vGICv2 migration");
|
||||
migrate_add_blocker(s->migration_blocker);
|
||||
}
|
||||
|
||||
if (kvm_has_gsi_routing()) {
|
||||
/* set up irq routing */
|
||||
kvm_init_irq_routing(kvm_state);
|
||||
for (i = 0; i < s->num_irq - GIC_INTERNAL; ++i) {
|
||||
kvm_irqchip_add_irq_route(kvm_state, i, 0, i);
|
||||
}
|
||||
|
||||
kvm_gsi_routing_allowed = true;
|
||||
|
||||
kvm_irqchip_commit_routes(kvm_state);
|
||||
}
|
||||
}
|
||||
|
||||
static void kvm_arm_gic_class_init(ObjectClass *klass, void *data)
|
||||
|
|
148
hw/intc/arm_gicv3_its_common.c
Normal file
148
hw/intc/arm_gicv3_its_common.c
Normal file
|
@ -0,0 +1,148 @@
|
|||
/*
|
||||
* ITS base class for a GICv3-based system
|
||||
*
|
||||
* Copyright (c) 2015 Samsung Electronics Co., Ltd.
|
||||
* Written by Pavel Fedin
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/pci/msi.h"
|
||||
#include "hw/intc/arm_gicv3_its_common.h"
|
||||
#include "qemu/log.h"
|
||||
|
||||
static void gicv3_its_pre_save(void *opaque)
|
||||
{
|
||||
GICv3ITSState *s = (GICv3ITSState *)opaque;
|
||||
GICv3ITSCommonClass *c = ARM_GICV3_ITS_COMMON_GET_CLASS(s);
|
||||
|
||||
if (c->pre_save) {
|
||||
c->pre_save(s);
|
||||
}
|
||||
}
|
||||
|
||||
static int gicv3_its_post_load(void *opaque, int version_id)
|
||||
{
|
||||
GICv3ITSState *s = (GICv3ITSState *)opaque;
|
||||
GICv3ITSCommonClass *c = ARM_GICV3_ITS_COMMON_GET_CLASS(s);
|
||||
|
||||
if (c->post_load) {
|
||||
c->post_load(s);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_its = {
|
||||
.name = "arm_gicv3_its",
|
||||
.pre_save = gicv3_its_pre_save,
|
||||
.post_load = gicv3_its_post_load,
|
||||
.unmigratable = true,
|
||||
};
|
||||
|
||||
static MemTxResult gicv3_its_trans_read(void *opaque, hwaddr offset,
|
||||
uint64_t *data, unsigned size,
|
||||
MemTxAttrs attrs)
|
||||
{
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "ITS read at offset 0x%"PRIx64"\n", offset);
|
||||
return MEMTX_ERROR;
|
||||
}
|
||||
|
||||
static MemTxResult gicv3_its_trans_write(void *opaque, hwaddr offset,
|
||||
uint64_t value, unsigned size,
|
||||
MemTxAttrs attrs)
|
||||
{
|
||||
if (offset == 0x0040 && ((size == 2) || (size == 4))) {
|
||||
GICv3ITSState *s = ARM_GICV3_ITS_COMMON(opaque);
|
||||
GICv3ITSCommonClass *c = ARM_GICV3_ITS_COMMON_GET_CLASS(s);
|
||||
int ret = c->send_msi(s, le64_to_cpu(value), attrs.requester_id);
|
||||
|
||||
if (ret <= 0) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"ITS: Error sending MSI: %s\n", strerror(-ret));
|
||||
return MEMTX_DECODE_ERROR;
|
||||
}
|
||||
|
||||
return MEMTX_OK;
|
||||
} else {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"ITS write at bad offset 0x%"PRIx64"\n", offset);
|
||||
return MEMTX_DECODE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
static const MemoryRegionOps gicv3_its_trans_ops = {
|
||||
.read_with_attrs = gicv3_its_trans_read,
|
||||
.write_with_attrs = gicv3_its_trans_write,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
void gicv3_its_init_mmio(GICv3ITSState *s, const MemoryRegionOps *ops)
|
||||
{
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(s);
|
||||
|
||||
memory_region_init_io(&s->iomem_its_cntrl, OBJECT(s), ops, s,
|
||||
"control", ITS_CONTROL_SIZE);
|
||||
memory_region_init_io(&s->iomem_its_translation, OBJECT(s),
|
||||
&gicv3_its_trans_ops, s,
|
||||
"translation", ITS_TRANS_SIZE);
|
||||
|
||||
/* Our two regions are always adjacent, therefore we now combine them
|
||||
* into a single one in order to make our users' life easier.
|
||||
*/
|
||||
memory_region_init(&s->iomem_main, OBJECT(s), "gicv3_its", ITS_SIZE);
|
||||
memory_region_add_subregion(&s->iomem_main, 0, &s->iomem_its_cntrl);
|
||||
memory_region_add_subregion(&s->iomem_main, ITS_CONTROL_SIZE,
|
||||
&s->iomem_its_translation);
|
||||
sysbus_init_mmio(sbd, &s->iomem_main);
|
||||
|
||||
msi_nonbroken = true;
|
||||
}
|
||||
|
||||
static void gicv3_its_common_reset(DeviceState *dev)
|
||||
{
|
||||
GICv3ITSState *s = ARM_GICV3_ITS_COMMON(dev);
|
||||
|
||||
s->ctlr = 0;
|
||||
s->cbaser = 0;
|
||||
s->cwriter = 0;
|
||||
s->creadr = 0;
|
||||
memset(&s->baser, 0, sizeof(s->baser));
|
||||
|
||||
gicv3_its_post_load(s, 0);
|
||||
}
|
||||
|
||||
static void gicv3_its_common_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->reset = gicv3_its_common_reset;
|
||||
dc->vmsd = &vmstate_its;
|
||||
}
|
||||
|
||||
static const TypeInfo gicv3_its_common_info = {
|
||||
.name = TYPE_ARM_GICV3_ITS_COMMON,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(GICv3ITSState),
|
||||
.class_size = sizeof(GICv3ITSCommonClass),
|
||||
.class_init = gicv3_its_common_class_init,
|
||||
.abstract = true,
|
||||
};
|
||||
|
||||
static void gicv3_its_common_register_types(void)
|
||||
{
|
||||
type_register_static(&gicv3_its_common_info);
|
||||
}
|
||||
|
||||
type_init(gicv3_its_common_register_types)
|
121
hw/intc/arm_gicv3_its_kvm.c
Normal file
121
hw/intc/arm_gicv3_its_kvm.c
Normal file
|
@ -0,0 +1,121 @@
|
|||
/*
|
||||
* KVM-based ITS implementation for a GICv3-based system
|
||||
*
|
||||
* Copyright (c) 2015 Samsung Electronics Co., Ltd.
|
||||
* Written by Pavel Fedin <p.fedin@samsung.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "hw/intc/arm_gicv3_its_common.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "sysemu/kvm.h"
|
||||
#include "kvm_arm.h"
|
||||
#include "migration/migration.h"
|
||||
|
||||
#define TYPE_KVM_ARM_ITS "arm-its-kvm"
|
||||
#define KVM_ARM_ITS(obj) OBJECT_CHECK(GICv3ITSState, (obj), TYPE_KVM_ARM_ITS)
|
||||
|
||||
static int kvm_its_send_msi(GICv3ITSState *s, uint32_t value, uint16_t devid)
|
||||
{
|
||||
struct kvm_msi msi;
|
||||
|
||||
if (unlikely(!s->translater_gpa_known)) {
|
||||
MemoryRegion *mr = &s->iomem_its_translation;
|
||||
MemoryRegionSection mrs;
|
||||
|
||||
mrs = memory_region_find(mr, 0, 1);
|
||||
memory_region_unref(mrs.mr);
|
||||
s->gits_translater_gpa = mrs.offset_within_address_space + 0x40;
|
||||
s->translater_gpa_known = true;
|
||||
}
|
||||
|
||||
msi.address_lo = extract64(s->gits_translater_gpa, 0, 32);
|
||||
msi.address_hi = extract64(s->gits_translater_gpa, 32, 32);
|
||||
msi.data = le32_to_cpu(value);
|
||||
msi.flags = KVM_MSI_VALID_DEVID;
|
||||
msi.devid = devid;
|
||||
memset(msi.pad, 0, sizeof(msi.pad));
|
||||
|
||||
return kvm_vm_ioctl(kvm_state, KVM_SIGNAL_MSI, &msi);
|
||||
}
|
||||
|
||||
static void kvm_arm_its_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
GICv3ITSState *s = ARM_GICV3_ITS_COMMON(dev);
|
||||
|
||||
s->dev_fd = kvm_create_device(kvm_state, KVM_DEV_TYPE_ARM_VGIC_ITS, false);
|
||||
if (s->dev_fd < 0) {
|
||||
error_setg_errno(errp, -s->dev_fd, "error creating in-kernel ITS");
|
||||
return;
|
||||
}
|
||||
|
||||
/* explicit init of the ITS */
|
||||
kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL,
|
||||
KVM_DEV_ARM_VGIC_CTRL_INIT, NULL, true);
|
||||
|
||||
/* register the base address */
|
||||
kvm_arm_register_device(&s->iomem_its_cntrl, -1, KVM_DEV_ARM_VGIC_GRP_ADDR,
|
||||
KVM_VGIC_ITS_ADDR_TYPE, s->dev_fd);
|
||||
|
||||
gicv3_its_init_mmio(s, NULL);
|
||||
|
||||
/*
|
||||
* Block migration of a KVM GICv3 ITS device: the API for saving and
|
||||
* restoring the state in the kernel is not yet available
|
||||
*/
|
||||
error_setg(&s->migration_blocker, "vITS migration is not implemented");
|
||||
migrate_add_blocker(s->migration_blocker);
|
||||
|
||||
kvm_msi_use_devid = true;
|
||||
kvm_gsi_direct_mapping = false;
|
||||
kvm_msi_via_irqfd_allowed = kvm_irqfds_enabled();
|
||||
}
|
||||
|
||||
static void kvm_arm_its_init(Object *obj)
|
||||
{
|
||||
GICv3ITSState *s = KVM_ARM_ITS(obj);
|
||||
|
||||
object_property_add_link(obj, "parent-gicv3",
|
||||
"kvm-arm-gicv3", (Object **)&s->gicv3,
|
||||
object_property_allow_set_link,
|
||||
OBJ_PROP_LINK_UNREF_ON_RELEASE,
|
||||
&error_abort);
|
||||
}
|
||||
|
||||
static void kvm_arm_its_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
GICv3ITSCommonClass *icc = ARM_GICV3_ITS_COMMON_CLASS(klass);
|
||||
|
||||
dc->realize = kvm_arm_its_realize;
|
||||
icc->send_msi = kvm_its_send_msi;
|
||||
}
|
||||
|
||||
static const TypeInfo kvm_arm_its_info = {
|
||||
.name = TYPE_KVM_ARM_ITS,
|
||||
.parent = TYPE_ARM_GICV3_ITS_COMMON,
|
||||
.instance_size = sizeof(GICv3ITSState),
|
||||
.instance_init = kvm_arm_its_init,
|
||||
.class_init = kvm_arm_its_class_init,
|
||||
};
|
||||
|
||||
static void kvm_arm_its_register_types(void)
|
||||
{
|
||||
type_register_static(&kvm_arm_its_info);
|
||||
}
|
||||
|
||||
type_init(kvm_arm_its_register_types)
|
|
@ -85,6 +85,7 @@ static void kvm_arm_gicv3_realize(DeviceState *dev, Error **errp)
|
|||
GICv3State *s = KVM_ARM_GICV3(dev);
|
||||
KVMARMGICv3Class *kgc = KVM_ARM_GICV3_GET_CLASS(s);
|
||||
Error *local_err = NULL;
|
||||
int i;
|
||||
|
||||
DPRINTF("kvm_arm_gicv3_realize\n");
|
||||
|
||||
|
@ -127,6 +128,18 @@ static void kvm_arm_gicv3_realize(DeviceState *dev, Error **errp)
|
|||
*/
|
||||
error_setg(&s->migration_blocker, "vGICv3 migration is not implemented");
|
||||
migrate_add_blocker(s->migration_blocker);
|
||||
|
||||
if (kvm_has_gsi_routing()) {
|
||||
/* set up irq routing */
|
||||
kvm_init_irq_routing(kvm_state);
|
||||
for (i = 0; i < s->num_irq - GIC_INTERNAL; ++i) {
|
||||
kvm_irqchip_add_irq_route(kvm_state, i, 0, i);
|
||||
}
|
||||
|
||||
kvm_gsi_routing_allowed = true;
|
||||
|
||||
kvm_irqchip_commit_routes(kvm_state);
|
||||
}
|
||||
}
|
||||
|
||||
static void kvm_arm_gicv3_class_init(ObjectClass *klass, void *data)
|
||||
|
|
|
@ -147,25 +147,19 @@
|
|||
#define GEM_INT_Q1_MASK (0x00000640 / 4)
|
||||
|
||||
#define GEM_TRANSMIT_Q1_PTR (0x00000440 / 4)
|
||||
#define GEM_TRANSMIT_Q15_PTR (GEM_TRANSMIT_Q1_PTR + 14)
|
||||
#define GEM_TRANSMIT_Q7_PTR (GEM_TRANSMIT_Q1_PTR + 6)
|
||||
|
||||
#define GEM_RECEIVE_Q1_PTR (0x00000480 / 4)
|
||||
#define GEM_RECEIVE_Q15_PTR (GEM_RECEIVE_Q1_PTR + 14)
|
||||
#define GEM_RECEIVE_Q7_PTR (GEM_RECEIVE_Q1_PTR + 6)
|
||||
|
||||
#define GEM_INT_Q1_ENABLE (0x00000600 / 4)
|
||||
#define GEM_INT_Q7_ENABLE (GEM_INT_Q1_ENABLE + 6)
|
||||
#define GEM_INT_Q8_ENABLE (0x00000660 / 4)
|
||||
#define GEM_INT_Q15_ENABLE (GEM_INT_Q8_ENABLE + 7)
|
||||
|
||||
#define GEM_INT_Q1_DISABLE (0x00000620 / 4)
|
||||
#define GEM_INT_Q7_DISABLE (GEM_INT_Q1_DISABLE + 6)
|
||||
#define GEM_INT_Q8_DISABLE (0x00000680 / 4)
|
||||
#define GEM_INT_Q15_DISABLE (GEM_INT_Q8_DISABLE + 7)
|
||||
|
||||
#define GEM_INT_Q1_MASK (0x00000640 / 4)
|
||||
#define GEM_INT_Q7_MASK (GEM_INT_Q1_MASK + 6)
|
||||
#define GEM_INT_Q8_MASK (0x000006A0 / 4)
|
||||
#define GEM_INT_Q15_MASK (GEM_INT_Q8_MASK + 7)
|
||||
|
||||
#define GEM_SCREENING_TYPE1_REGISTER_0 (0x00000500 / 4)
|
||||
|
||||
|
@ -1372,13 +1366,13 @@ static void gem_write(void *opaque, hwaddr offset, uint64_t val,
|
|||
case GEM_RXQBASE:
|
||||
s->rx_desc_addr[0] = val;
|
||||
break;
|
||||
case GEM_RECEIVE_Q1_PTR ... GEM_RECEIVE_Q15_PTR:
|
||||
case GEM_RECEIVE_Q1_PTR ... GEM_RECEIVE_Q7_PTR:
|
||||
s->rx_desc_addr[offset - GEM_RECEIVE_Q1_PTR + 1] = val;
|
||||
break;
|
||||
case GEM_TXQBASE:
|
||||
s->tx_desc_addr[0] = val;
|
||||
break;
|
||||
case GEM_TRANSMIT_Q1_PTR ... GEM_TRANSMIT_Q15_PTR:
|
||||
case GEM_TRANSMIT_Q1_PTR ... GEM_TRANSMIT_Q7_PTR:
|
||||
s->tx_desc_addr[offset - GEM_TRANSMIT_Q1_PTR + 1] = val;
|
||||
break;
|
||||
case GEM_RXSTATUS:
|
||||
|
@ -1392,10 +1386,6 @@ static void gem_write(void *opaque, hwaddr offset, uint64_t val,
|
|||
s->regs[GEM_INT_Q1_MASK + offset - GEM_INT_Q1_ENABLE] &= ~val;
|
||||
gem_update_int_status(s);
|
||||
break;
|
||||
case GEM_INT_Q8_ENABLE ... GEM_INT_Q15_ENABLE:
|
||||
s->regs[GEM_INT_Q8_MASK + offset - GEM_INT_Q8_ENABLE] &= ~val;
|
||||
gem_update_int_status(s);
|
||||
break;
|
||||
case GEM_IDR:
|
||||
s->regs[GEM_IMR] |= val;
|
||||
gem_update_int_status(s);
|
||||
|
@ -1404,10 +1394,6 @@ static void gem_write(void *opaque, hwaddr offset, uint64_t val,
|
|||
s->regs[GEM_INT_Q1_MASK + offset - GEM_INT_Q1_DISABLE] |= val;
|
||||
gem_update_int_status(s);
|
||||
break;
|
||||
case GEM_INT_Q8_DISABLE ... GEM_INT_Q15_DISABLE:
|
||||
s->regs[GEM_INT_Q8_MASK + offset - GEM_INT_Q8_DISABLE] |= val;
|
||||
gem_update_int_status(s);
|
||||
break;
|
||||
case GEM_SPADDR1LO:
|
||||
case GEM_SPADDR2LO:
|
||||
case GEM_SPADDR3LO:
|
||||
|
|
|
@ -3,6 +3,7 @@ common-obj-$(CONFIG_SSI) += ssi.o
|
|||
common-obj-$(CONFIG_XILINX_SPI) += xilinx_spi.o
|
||||
common-obj-$(CONFIG_XILINX_SPIPS) += xilinx_spips.o
|
||||
common-obj-$(CONFIG_ASPEED_SOC) += aspeed_smc.o
|
||||
common-obj-$(CONFIG_STM32F2XX_SPI) += stm32f2xx_spi.o
|
||||
|
||||
obj-$(CONFIG_OMAP) += omap_spi.o
|
||||
obj-$(CONFIG_IMX) += imx_spi.o
|
||||
|
|
225
hw/ssi/stm32f2xx_spi.c
Normal file
225
hw/ssi/stm32f2xx_spi.c
Normal file
|
@ -0,0 +1,225 @@
|
|||
/*
|
||||
* STM32F405 SPI
|
||||
*
|
||||
* Copyright (c) 2014 Alistair Francis <alistair@alistair23.me>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/log.h"
|
||||
#include "hw/ssi/stm32f2xx_spi.h"
|
||||
|
||||
#ifndef STM_SPI_ERR_DEBUG
|
||||
#define STM_SPI_ERR_DEBUG 0
|
||||
#endif
|
||||
|
||||
#define DB_PRINT_L(lvl, fmt, args...) do { \
|
||||
if (STM_SPI_ERR_DEBUG >= lvl) { \
|
||||
qemu_log("%s: " fmt, __func__, ## args); \
|
||||
} \
|
||||
} while (0);
|
||||
|
||||
#define DB_PRINT(fmt, args...) DB_PRINT_L(1, fmt, ## args)
|
||||
|
||||
static void stm32f2xx_spi_reset(DeviceState *dev)
|
||||
{
|
||||
STM32F2XXSPIState *s = STM32F2XX_SPI(dev);
|
||||
|
||||
s->spi_cr1 = 0x00000000;
|
||||
s->spi_cr2 = 0x00000000;
|
||||
s->spi_sr = 0x0000000A;
|
||||
s->spi_dr = 0x0000000C;
|
||||
s->spi_crcpr = 0x00000007;
|
||||
s->spi_rxcrcr = 0x00000000;
|
||||
s->spi_txcrcr = 0x00000000;
|
||||
s->spi_i2scfgr = 0x00000000;
|
||||
s->spi_i2spr = 0x00000002;
|
||||
}
|
||||
|
||||
static void stm32f2xx_spi_transfer(STM32F2XXSPIState *s)
|
||||
{
|
||||
DB_PRINT("Data to send: 0x%x\n", s->spi_dr);
|
||||
|
||||
s->spi_dr = ssi_transfer(s->ssi, s->spi_dr);
|
||||
s->spi_sr |= STM_SPI_SR_RXNE;
|
||||
|
||||
DB_PRINT("Data received: 0x%x\n", s->spi_dr);
|
||||
}
|
||||
|
||||
static uint64_t stm32f2xx_spi_read(void *opaque, hwaddr addr,
|
||||
unsigned int size)
|
||||
{
|
||||
STM32F2XXSPIState *s = opaque;
|
||||
|
||||
DB_PRINT("Address: 0x%" HWADDR_PRIx "\n", addr);
|
||||
|
||||
switch (addr) {
|
||||
case STM_SPI_CR1:
|
||||
return s->spi_cr1;
|
||||
case STM_SPI_CR2:
|
||||
qemu_log_mask(LOG_UNIMP, "%s: Interrupts and DMA are not implemented\n",
|
||||
__func__);
|
||||
return s->spi_cr2;
|
||||
case STM_SPI_SR:
|
||||
return s->spi_sr;
|
||||
case STM_SPI_DR:
|
||||
stm32f2xx_spi_transfer(s);
|
||||
s->spi_sr &= ~STM_SPI_SR_RXNE;
|
||||
return s->spi_dr;
|
||||
case STM_SPI_CRCPR:
|
||||
qemu_log_mask(LOG_UNIMP, "%s: CRC is not implemented, the registers " \
|
||||
"are included for compatibility\n", __func__);
|
||||
return s->spi_crcpr;
|
||||
case STM_SPI_RXCRCR:
|
||||
qemu_log_mask(LOG_UNIMP, "%s: CRC is not implemented, the registers " \
|
||||
"are included for compatibility\n", __func__);
|
||||
return s->spi_rxcrcr;
|
||||
case STM_SPI_TXCRCR:
|
||||
qemu_log_mask(LOG_UNIMP, "%s: CRC is not implemented, the registers " \
|
||||
"are included for compatibility\n", __func__);
|
||||
return s->spi_txcrcr;
|
||||
case STM_SPI_I2SCFGR:
|
||||
qemu_log_mask(LOG_UNIMP, "%s: I2S is not implemented, the registers " \
|
||||
"are included for compatibility\n", __func__);
|
||||
return s->spi_i2scfgr;
|
||||
case STM_SPI_I2SPR:
|
||||
qemu_log_mask(LOG_UNIMP, "%s: I2S is not implemented, the registers " \
|
||||
"are included for compatibility\n", __func__);
|
||||
return s->spi_i2spr;
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n",
|
||||
__func__, addr);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void stm32f2xx_spi_write(void *opaque, hwaddr addr,
|
||||
uint64_t val64, unsigned int size)
|
||||
{
|
||||
STM32F2XXSPIState *s = opaque;
|
||||
uint32_t value = val64;
|
||||
|
||||
DB_PRINT("Address: 0x%" HWADDR_PRIx ", Value: 0x%x\n", addr, value);
|
||||
|
||||
switch (addr) {
|
||||
case STM_SPI_CR1:
|
||||
s->spi_cr1 = value;
|
||||
return;
|
||||
case STM_SPI_CR2:
|
||||
qemu_log_mask(LOG_UNIMP, "%s: " \
|
||||
"Interrupts and DMA are not implemented\n", __func__);
|
||||
s->spi_cr2 = value;
|
||||
return;
|
||||
case STM_SPI_SR:
|
||||
/* Read only register, except for clearing the CRCERR bit, which
|
||||
* is not supported
|
||||
*/
|
||||
return;
|
||||
case STM_SPI_DR:
|
||||
s->spi_dr = value;
|
||||
stm32f2xx_spi_transfer(s);
|
||||
return;
|
||||
case STM_SPI_CRCPR:
|
||||
qemu_log_mask(LOG_UNIMP, "%s: CRC is not implemented\n", __func__);
|
||||
return;
|
||||
case STM_SPI_RXCRCR:
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: Read only register: " \
|
||||
"0x%" HWADDR_PRIx "\n", __func__, addr);
|
||||
return;
|
||||
case STM_SPI_TXCRCR:
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: Read only register: " \
|
||||
"0x%" HWADDR_PRIx "\n", __func__, addr);
|
||||
return;
|
||||
case STM_SPI_I2SCFGR:
|
||||
qemu_log_mask(LOG_UNIMP, "%s: " \
|
||||
"I2S is not implemented\n", __func__);
|
||||
return;
|
||||
case STM_SPI_I2SPR:
|
||||
qemu_log_mask(LOG_UNIMP, "%s: " \
|
||||
"I2S is not implemented\n", __func__);
|
||||
return;
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: Bad offset 0x%" HWADDR_PRIx "\n", __func__, addr);
|
||||
}
|
||||
}
|
||||
|
||||
static const MemoryRegionOps stm32f2xx_spi_ops = {
|
||||
.read = stm32f2xx_spi_read,
|
||||
.write = stm32f2xx_spi_write,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
static const VMStateDescription vmstate_stm32f2xx_spi = {
|
||||
.name = TYPE_STM32F2XX_SPI,
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32(spi_cr1, STM32F2XXSPIState),
|
||||
VMSTATE_UINT32(spi_cr2, STM32F2XXSPIState),
|
||||
VMSTATE_UINT32(spi_sr, STM32F2XXSPIState),
|
||||
VMSTATE_UINT32(spi_dr, STM32F2XXSPIState),
|
||||
VMSTATE_UINT32(spi_crcpr, STM32F2XXSPIState),
|
||||
VMSTATE_UINT32(spi_rxcrcr, STM32F2XXSPIState),
|
||||
VMSTATE_UINT32(spi_txcrcr, STM32F2XXSPIState),
|
||||
VMSTATE_UINT32(spi_i2scfgr, STM32F2XXSPIState),
|
||||
VMSTATE_UINT32(spi_i2spr, STM32F2XXSPIState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static void stm32f2xx_spi_init(Object *obj)
|
||||
{
|
||||
STM32F2XXSPIState *s = STM32F2XX_SPI(obj);
|
||||
DeviceState *dev = DEVICE(obj);
|
||||
|
||||
memory_region_init_io(&s->mmio, obj, &stm32f2xx_spi_ops, s,
|
||||
TYPE_STM32F2XX_SPI, 0x400);
|
||||
sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
|
||||
|
||||
sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq);
|
||||
|
||||
s->ssi = ssi_create_bus(dev, "ssi");
|
||||
}
|
||||
|
||||
static void stm32f2xx_spi_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->reset = stm32f2xx_spi_reset;
|
||||
dc->vmsd = &vmstate_stm32f2xx_spi;
|
||||
}
|
||||
|
||||
static const TypeInfo stm32f2xx_spi_info = {
|
||||
.name = TYPE_STM32F2XX_SPI,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(STM32F2XXSPIState),
|
||||
.instance_init = stm32f2xx_spi_init,
|
||||
.class_init = stm32f2xx_spi_class_init,
|
||||
};
|
||||
|
||||
static void stm32f2xx_spi_register_types(void)
|
||||
{
|
||||
type_register_static(&stm32f2xx_spi_info);
|
||||
}
|
||||
|
||||
type_init(stm32f2xx_spi_register_types)
|
|
@ -51,6 +51,15 @@ static void stm32f2xx_timer_interrupt(void *opaque)
|
|||
qemu_irq_pulse(s->irq);
|
||||
stm32f2xx_timer_set_alarm(s, s->hit_time);
|
||||
}
|
||||
|
||||
if (s->tim_ccmr1 & (TIM_CCMR1_OC2M2 | TIM_CCMR1_OC2M1) &&
|
||||
!(s->tim_ccmr1 & TIM_CCMR1_OC2M0) &&
|
||||
s->tim_ccmr1 & TIM_CCMR1_OC2PE &&
|
||||
s->tim_ccer & TIM_CCER_CC2E) {
|
||||
/* PWM 2 - Mode 1 */
|
||||
DB_PRINT("PWM2 Duty Cycle: %d%%\n",
|
||||
s->tim_ccr2 / (100 * (s->tim_psc + 1)));
|
||||
}
|
||||
}
|
||||
|
||||
static inline int64_t stm32f2xx_ns_to_ticks(STM32F2XXTimerState *s, int64_t t)
|
||||
|
|
|
@ -294,7 +294,8 @@ typedef struct AcpiMultipleApicTable AcpiMultipleApicTable;
|
|||
#define ACPI_APIC_GENERIC_DISTRIBUTOR 12
|
||||
#define ACPI_APIC_GENERIC_MSI_FRAME 13
|
||||
#define ACPI_APIC_GENERIC_REDISTRIBUTOR 14
|
||||
#define ACPI_APIC_RESERVED 15 /* 15 and greater are reserved */
|
||||
#define ACPI_APIC_GENERIC_TRANSLATOR 15
|
||||
#define ACPI_APIC_RESERVED 16 /* 16 and greater are reserved */
|
||||
|
||||
/*
|
||||
* MADT sub-structures (Follow MULTIPLE_APIC_DESCRIPTION_TABLE)
|
||||
|
@ -395,6 +396,16 @@ struct AcpiMadtGenericRedistributor {
|
|||
|
||||
typedef struct AcpiMadtGenericRedistributor AcpiMadtGenericRedistributor;
|
||||
|
||||
struct AcpiMadtGenericTranslator {
|
||||
ACPI_SUB_HEADER_DEF
|
||||
uint16_t reserved;
|
||||
uint32_t translation_id;
|
||||
uint64_t base_address;
|
||||
uint32_t reserved2;
|
||||
} QEMU_PACKED;
|
||||
|
||||
typedef struct AcpiMadtGenericTranslator AcpiMadtGenericTranslator;
|
||||
|
||||
/*
|
||||
* Generic Timer Description Table (GTDT)
|
||||
*/
|
||||
|
|
87
include/hw/adc/stm32f2xx_adc.h
Normal file
87
include/hw/adc/stm32f2xx_adc.h
Normal file
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* STM32F2XX ADC
|
||||
*
|
||||
* Copyright (c) 2014 Alistair Francis <alistair@alistair23.me>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef HW_STM32F2XX_ADC_H
|
||||
#define HW_STM32F2XX_ADC_H
|
||||
|
||||
#define ADC_SR 0x00
|
||||
#define ADC_CR1 0x04
|
||||
#define ADC_CR2 0x08
|
||||
#define ADC_SMPR1 0x0C
|
||||
#define ADC_SMPR2 0x10
|
||||
#define ADC_JOFR1 0x14
|
||||
#define ADC_JOFR2 0x18
|
||||
#define ADC_JOFR3 0x1C
|
||||
#define ADC_JOFR4 0x20
|
||||
#define ADC_HTR 0x24
|
||||
#define ADC_LTR 0x28
|
||||
#define ADC_SQR1 0x2C
|
||||
#define ADC_SQR2 0x30
|
||||
#define ADC_SQR3 0x34
|
||||
#define ADC_JSQR 0x38
|
||||
#define ADC_JDR1 0x3C
|
||||
#define ADC_JDR2 0x40
|
||||
#define ADC_JDR3 0x44
|
||||
#define ADC_JDR4 0x48
|
||||
#define ADC_DR 0x4C
|
||||
|
||||
#define ADC_CR2_ADON 0x01
|
||||
#define ADC_CR2_CONT 0x02
|
||||
#define ADC_CR2_ALIGN 0x800
|
||||
#define ADC_CR2_SWSTART 0x40000000
|
||||
|
||||
#define ADC_CR1_RES 0x3000000
|
||||
|
||||
#define ADC_COMMON_ADDRESS 0x100
|
||||
|
||||
#define TYPE_STM32F2XX_ADC "stm32f2xx-adc"
|
||||
#define STM32F2XX_ADC(obj) \
|
||||
OBJECT_CHECK(STM32F2XXADCState, (obj), TYPE_STM32F2XX_ADC)
|
||||
|
||||
typedef struct {
|
||||
/* <private> */
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
/* <public> */
|
||||
MemoryRegion mmio;
|
||||
|
||||
uint32_t adc_sr;
|
||||
uint32_t adc_cr1;
|
||||
uint32_t adc_cr2;
|
||||
uint32_t adc_smpr1;
|
||||
uint32_t adc_smpr2;
|
||||
uint32_t adc_jofr[4];
|
||||
uint32_t adc_htr;
|
||||
uint32_t adc_ltr;
|
||||
uint32_t adc_sqr1;
|
||||
uint32_t adc_sqr2;
|
||||
uint32_t adc_sqr3;
|
||||
uint32_t adc_jsqr;
|
||||
uint32_t adc_jdr[4];
|
||||
uint32_t adc_dr;
|
||||
|
||||
qemu_irq irq;
|
||||
} STM32F2XXADCState;
|
||||
|
||||
#endif /* HW_STM32F2XX_ADC_H */
|
|
@ -28,6 +28,9 @@
|
|||
#include "hw/misc/stm32f2xx_syscfg.h"
|
||||
#include "hw/timer/stm32f2xx_timer.h"
|
||||
#include "hw/char/stm32f2xx_usart.h"
|
||||
#include "hw/adc/stm32f2xx_adc.h"
|
||||
#include "hw/or-irq.h"
|
||||
#include "hw/ssi/stm32f2xx_spi.h"
|
||||
|
||||
#define TYPE_STM32F205_SOC "stm32f205-soc"
|
||||
#define STM32F205_SOC(obj) \
|
||||
|
@ -35,6 +38,8 @@
|
|||
|
||||
#define STM_NUM_USARTS 6
|
||||
#define STM_NUM_TIMERS 4
|
||||
#define STM_NUM_ADCS 3
|
||||
#define STM_NUM_SPIS 3
|
||||
|
||||
#define FLASH_BASE_ADDRESS 0x08000000
|
||||
#define FLASH_SIZE (1024 * 1024)
|
||||
|
@ -52,6 +57,10 @@ typedef struct STM32F205State {
|
|||
STM32F2XXSyscfgState syscfg;
|
||||
STM32F2XXUsartState usart[STM_NUM_USARTS];
|
||||
STM32F2XXTimerState timer[STM_NUM_TIMERS];
|
||||
STM32F2XXADCState adc[STM_NUM_ADCS];
|
||||
STM32F2XXSPIState spi[STM_NUM_SPIS];
|
||||
|
||||
qemu_or_irq *adc_irqs;
|
||||
} STM32F205State;
|
||||
|
||||
#endif
|
||||
|
|
46
include/hw/core/generic-loader.h
Normal file
46
include/hw/core/generic-loader.h
Normal file
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Generic Loader
|
||||
*
|
||||
* Copyright (C) 2014 Li Guang
|
||||
* Written by Li Guang <lig.fnst@cn.fujitsu.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#ifndef GENERIC_LOADER_H
|
||||
#define GENERIC_LOADER_H
|
||||
|
||||
#include "elf.h"
|
||||
|
||||
typedef struct GenericLoaderState {
|
||||
/* <private> */
|
||||
DeviceState parent_obj;
|
||||
|
||||
/* <public> */
|
||||
CPUState *cpu;
|
||||
|
||||
uint64_t addr;
|
||||
uint64_t data;
|
||||
uint8_t data_len;
|
||||
uint32_t cpu_num;
|
||||
|
||||
char *file;
|
||||
|
||||
bool force_raw;
|
||||
bool data_be;
|
||||
bool set_pc;
|
||||
} GenericLoaderState;
|
||||
|
||||
#define TYPE_GENERIC_LOADER "loader"
|
||||
#define GENERIC_LOADER(obj) OBJECT_CHECK(GenericLoaderState, (obj), \
|
||||
TYPE_GENERIC_LOADER)
|
||||
|
||||
#endif
|
78
include/hw/intc/arm_gicv3_its_common.h
Normal file
78
include/hw/intc/arm_gicv3_its_common.h
Normal file
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
* ITS support for ARM GICv3
|
||||
*
|
||||
* Copyright (c) 2015 Samsung Electronics Co., Ltd.
|
||||
* Written by Pavel Fedin
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef QEMU_ARM_GICV3_ITS_COMMON_H
|
||||
#define QEMU_ARM_GICV3_ITS_COMMON_H
|
||||
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/intc/arm_gicv3_common.h"
|
||||
|
||||
#define ITS_CONTROL_SIZE 0x10000
|
||||
#define ITS_TRANS_SIZE 0x10000
|
||||
#define ITS_SIZE (ITS_CONTROL_SIZE + ITS_TRANS_SIZE)
|
||||
|
||||
struct GICv3ITSState {
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
MemoryRegion iomem_main;
|
||||
MemoryRegion iomem_its_cntrl;
|
||||
MemoryRegion iomem_its_translation;
|
||||
|
||||
GICv3State *gicv3;
|
||||
|
||||
int dev_fd; /* kvm device fd if backed by kvm vgic support */
|
||||
uint64_t gits_translater_gpa;
|
||||
bool translater_gpa_known;
|
||||
|
||||
/* Registers */
|
||||
uint32_t ctlr;
|
||||
uint64_t cbaser;
|
||||
uint64_t cwriter;
|
||||
uint64_t creadr;
|
||||
uint64_t baser[8];
|
||||
|
||||
Error *migration_blocker;
|
||||
};
|
||||
|
||||
typedef struct GICv3ITSState GICv3ITSState;
|
||||
|
||||
void gicv3_its_init_mmio(GICv3ITSState *s, const MemoryRegionOps *ops);
|
||||
|
||||
#define TYPE_ARM_GICV3_ITS_COMMON "arm-gicv3-its-common"
|
||||
#define ARM_GICV3_ITS_COMMON(obj) \
|
||||
OBJECT_CHECK(GICv3ITSState, (obj), TYPE_ARM_GICV3_ITS_COMMON)
|
||||
#define ARM_GICV3_ITS_COMMON_CLASS(klass) \
|
||||
OBJECT_CLASS_CHECK(GICv3ITSCommonClass, (klass), TYPE_ARM_GICV3_ITS_COMMON)
|
||||
#define ARM_GICV3_ITS_COMMON_GET_CLASS(obj) \
|
||||
OBJECT_GET_CLASS(GICv3ITSCommonClass, (obj), TYPE_ARM_GICV3_ITS_COMMON)
|
||||
|
||||
struct GICv3ITSCommonClass {
|
||||
/*< private >*/
|
||||
SysBusDeviceClass parent_class;
|
||||
/*< public >*/
|
||||
|
||||
int (*send_msi)(GICv3ITSState *s, uint32_t data, uint16_t devid);
|
||||
void (*pre_save)(GICv3ITSState *s);
|
||||
void (*post_load)(GICv3ITSState *s);
|
||||
};
|
||||
|
||||
typedef struct GICv3ITSCommonClass GICv3ITSCommonClass;
|
||||
|
||||
#endif
|
44
include/hw/or-irq.h
Normal file
44
include/hw/or-irq.h
Normal file
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* QEMU IRQ/GPIO common code.
|
||||
*
|
||||
* Copyright (c) 2016 Alistair Francis <alistair@alistair23.me>.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "hw/irq.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "qom/object.h"
|
||||
|
||||
#define TYPE_OR_IRQ "or-irq"
|
||||
|
||||
#define MAX_OR_LINES 16
|
||||
|
||||
typedef struct OrIRQState qemu_or_irq;
|
||||
|
||||
#define OR_IRQ(obj) OBJECT_CHECK(qemu_or_irq, (obj), TYPE_OR_IRQ)
|
||||
|
||||
struct OrIRQState {
|
||||
DeviceState parent_obj;
|
||||
|
||||
qemu_irq out_irq;
|
||||
qemu_irq *in_irqs;
|
||||
bool levels[MAX_OR_LINES];
|
||||
uint16_t num_lines;
|
||||
};
|
72
include/hw/ssi/stm32f2xx_spi.h
Normal file
72
include/hw/ssi/stm32f2xx_spi.h
Normal file
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* STM32F2XX SPI
|
||||
*
|
||||
* Copyright (c) 2014 Alistair Francis <alistair@alistair23.me>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef HW_STM32F2XX_SPI_H
|
||||
#define HW_STM32F2XX_SPI_H
|
||||
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/hw.h"
|
||||
#include "hw/ssi/ssi.h"
|
||||
|
||||
#define STM_SPI_CR1 0x00
|
||||
#define STM_SPI_CR2 0x04
|
||||
#define STM_SPI_SR 0x08
|
||||
#define STM_SPI_DR 0x0C
|
||||
#define STM_SPI_CRCPR 0x10
|
||||
#define STM_SPI_RXCRCR 0x14
|
||||
#define STM_SPI_TXCRCR 0x18
|
||||
#define STM_SPI_I2SCFGR 0x1C
|
||||
#define STM_SPI_I2SPR 0x20
|
||||
|
||||
#define STM_SPI_CR1_SPE (1 << 6)
|
||||
#define STM_SPI_CR1_MSTR (1 << 2)
|
||||
|
||||
#define STM_SPI_SR_RXNE 1
|
||||
|
||||
#define TYPE_STM32F2XX_SPI "stm32f2xx-spi"
|
||||
#define STM32F2XX_SPI(obj) \
|
||||
OBJECT_CHECK(STM32F2XXSPIState, (obj), TYPE_STM32F2XX_SPI)
|
||||
|
||||
typedef struct {
|
||||
/* <private> */
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
/* <public> */
|
||||
MemoryRegion mmio;
|
||||
|
||||
uint32_t spi_cr1;
|
||||
uint32_t spi_cr2;
|
||||
uint32_t spi_sr;
|
||||
uint32_t spi_dr;
|
||||
uint32_t spi_crcpr;
|
||||
uint32_t spi_rxcrcr;
|
||||
uint32_t spi_txcrcr;
|
||||
uint32_t spi_i2scfgr;
|
||||
uint32_t spi_i2spr;
|
||||
|
||||
qemu_irq irq;
|
||||
SSIBus *ssi;
|
||||
} STM32F2XXSPIState;
|
||||
|
||||
#endif /* HW_STM32F2XX_SPI_H */
|
|
@ -53,6 +53,7 @@ extern bool kvm_gsi_direct_mapping;
|
|||
extern bool kvm_readonly_mem_allowed;
|
||||
extern bool kvm_direct_msi_allowed;
|
||||
extern bool kvm_ioeventfd_any_length_allowed;
|
||||
extern bool kvm_msi_use_devid;
|
||||
|
||||
#if defined CONFIG_KVM || !defined NEED_CPU_H
|
||||
#define kvm_enabled() (kvm_allowed)
|
||||
|
@ -169,6 +170,13 @@ extern bool kvm_ioeventfd_any_length_allowed;
|
|||
*/
|
||||
#define kvm_ioeventfd_any_length_enabled() (kvm_ioeventfd_any_length_allowed)
|
||||
|
||||
/**
|
||||
* kvm_msi_devid_required:
|
||||
* Returns: true if KVM requires a device id to be provided while
|
||||
* defining an MSI routing entry.
|
||||
*/
|
||||
#define kvm_msi_devid_required() (kvm_msi_use_devid)
|
||||
|
||||
#else
|
||||
#define kvm_enabled() (0)
|
||||
#define kvm_irqchip_in_kernel() (false)
|
||||
|
@ -184,6 +192,7 @@ extern bool kvm_ioeventfd_any_length_allowed;
|
|||
#define kvm_readonly_mem_enabled() (false)
|
||||
#define kvm_direct_msi_enabled() (false)
|
||||
#define kvm_ioeventfd_any_length_enabled() (false)
|
||||
#define kvm_msi_devid_required() (false)
|
||||
#endif
|
||||
|
||||
struct kvm_run;
|
||||
|
|
|
@ -119,6 +119,7 @@ bool kvm_readonly_mem_allowed;
|
|||
bool kvm_vm_attributes_allowed;
|
||||
bool kvm_direct_msi_allowed;
|
||||
bool kvm_ioeventfd_any_length_allowed;
|
||||
bool kvm_msi_use_devid;
|
||||
|
||||
static const KVMCapabilityInfo kvm_required_capabilites[] = {
|
||||
KVM_CAP_INFO(USER_MEMORY),
|
||||
|
@ -1275,6 +1276,10 @@ int kvm_irqchip_add_msi_route(KVMState *s, int vector, PCIDevice *dev)
|
|||
kroute.u.msi.address_lo = (uint32_t)msg.address;
|
||||
kroute.u.msi.address_hi = msg.address >> 32;
|
||||
kroute.u.msi.data = le32_to_cpu(msg.data);
|
||||
if (kvm_msi_devid_required()) {
|
||||
kroute.flags = KVM_MSI_VALID_DEVID;
|
||||
kroute.u.msi.devid = pci_requester_id(dev);
|
||||
}
|
||||
if (kvm_arch_fixup_msi_route(&kroute, msg.address, msg.data, dev)) {
|
||||
kvm_irqchip_release_virq(s, virq);
|
||||
return -EINVAL;
|
||||
|
@ -1308,6 +1313,10 @@ int kvm_irqchip_update_msi_route(KVMState *s, int virq, MSIMessage msg,
|
|||
kroute.u.msi.address_lo = (uint32_t)msg.address;
|
||||
kroute.u.msi.address_hi = msg.address >> 32;
|
||||
kroute.u.msi.data = le32_to_cpu(msg.data);
|
||||
if (kvm_msi_devid_required()) {
|
||||
kroute.flags = KVM_MSI_VALID_DEVID;
|
||||
kroute.u.msi.devid = pci_requester_id(dev);
|
||||
}
|
||||
if (kvm_arch_fixup_msi_route(&kroute, msg.address, msg.data, dev)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ bool kvm_gsi_direct_mapping;
|
|||
bool kvm_allowed;
|
||||
bool kvm_readonly_mem_allowed;
|
||||
bool kvm_ioeventfd_any_length_allowed;
|
||||
bool kvm_msi_use_devid;
|
||||
|
||||
int kvm_destroy_vcpu(CPUState *cpu)
|
||||
{
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
|
||||
#include "sysemu/kvm.h"
|
||||
#include "exec/memory.h"
|
||||
#include "qemu/error-report.h"
|
||||
|
||||
/**
|
||||
* kvm_arm_vcpu_init:
|
||||
|
@ -223,7 +224,20 @@ static inline const char *gic_class_name(void)
|
|||
*
|
||||
* Returns: class name to use
|
||||
*/
|
||||
const char *gicv3_class_name(void);
|
||||
static inline const char *gicv3_class_name(void)
|
||||
{
|
||||
if (kvm_irqchip_in_kernel()) {
|
||||
#ifdef TARGET_AARCH64
|
||||
return "kvm-arm-gicv3";
|
||||
#else
|
||||
error_report("KVM GICv3 acceleration is not supported on this "
|
||||
"platform");
|
||||
exit(1);
|
||||
#endif
|
||||
} else {
|
||||
return "arm-gicv3";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* kvm_arm_handle_debug:
|
||||
|
@ -255,4 +269,23 @@ struct kvm_guest_debug_arch;
|
|||
|
||||
void kvm_arm_copy_hw_debug_data(struct kvm_guest_debug_arch *ptr);
|
||||
|
||||
/**
|
||||
* its_class_name
|
||||
*
|
||||
* Return the ITS class name to use depending on whether KVM acceleration
|
||||
* and KVM CAP_SIGNAL_MSI are supported
|
||||
*
|
||||
* Returns: class name to use or NULL
|
||||
*/
|
||||
static inline const char *its_class_name(void)
|
||||
{
|
||||
if (kvm_irqchip_in_kernel()) {
|
||||
/* KVM implementation requires this capability */
|
||||
return kvm_direct_msi_enabled() ? "arm-its-kvm" : NULL;
|
||||
} else {
|
||||
/* Software emulation is not implemented yet */
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -331,18 +331,3 @@ const VMStateDescription vmstate_arm_cpu = {
|
|||
NULL
|
||||
}
|
||||
};
|
||||
|
||||
const char *gicv3_class_name(void)
|
||||
{
|
||||
if (kvm_irqchip_in_kernel()) {
|
||||
#ifdef TARGET_AARCH64
|
||||
return "kvm-arm-gicv3";
|
||||
#else
|
||||
error_report("KVM GICv3 acceleration is not supported on this "
|
||||
"platform");
|
||||
exit(1);
|
||||
#endif
|
||||
} else {
|
||||
return "arm-gicv3";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2025,7 +2025,7 @@ static void disas_ld_lit(DisasContext *s, uint32_t insn)
|
|||
do_fp_ld(s, rt, tcg_addr, size);
|
||||
} else {
|
||||
/* Only unsigned 32bit loads target 32bit registers. */
|
||||
bool iss_sf = opc == 0 ? 32 : 64;
|
||||
bool iss_sf = opc != 0;
|
||||
|
||||
do_gpr_ld(s, tcg_rt, tcg_addr, size, is_signed, false,
|
||||
true, rt, iss_sf, false);
|
||||
|
|
|
@ -180,7 +180,12 @@ static inline TCGv_i32 load_reg(DisasContext *s, int reg)
|
|||
static void store_reg(DisasContext *s, int reg, TCGv_i32 var)
|
||||
{
|
||||
if (reg == 15) {
|
||||
tcg_gen_andi_i32(var, var, ~1);
|
||||
/* In Thumb mode, we must ignore bit 0.
|
||||
* In ARM mode, for ARMv4 and ARMv5, it is UNPREDICTABLE if bits [1:0]
|
||||
* are not 0b00, but for ARMv6 and above, we must ignore bits [1:0].
|
||||
* We choose to ignore [1:0] in ARM mode for all architecture versions.
|
||||
*/
|
||||
tcg_gen_andi_i32(var, var, s->thumb ? ~1 : ~3);
|
||||
s->is_jmp = DISAS_JUMP;
|
||||
}
|
||||
tcg_gen_mov_i32(cpu_R[reg], var);
|
||||
|
|
Loading…
Reference in a new issue