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:
Peter Maydell 2016-10-04 13:48:25 +01:00
commit 6e11eb2d2b
39 changed files with 2025 additions and 314 deletions

View File

@ -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

View File

@ -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
View 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

View File

@ -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
View File

@ -0,0 +1 @@
obj-$(CONFIG_STM32F2XX_ADC) += stm32f2xx_adc.o

306
hw/adc/stm32f2xx_adc.c Normal file
View 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)

View File

@ -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 = {

View File

@ -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 */

View File

@ -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]));
}
}

View File

@ -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;

View File

@ -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

View File

@ -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
View 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
View 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)

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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

View File

@ -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)

View 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
View 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)

View File

@ -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)

View File

@ -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:

View File

@ -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
View 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)

View File

@ -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)

View File

@ -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)
*/

View 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 */

View File

@ -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

View 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

View 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
View 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;
};

View 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 */

View File

@ -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;

View File

@ -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;
}

View File

@ -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)
{

View File

@ -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

View File

@ -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";
}
}

View File

@ -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);

View File

@ -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);