target-arm queue:
* blizzard, omap_lcdc: code cleanup to remove DEPTH != 32 dead code * QOMify various ARM devices * bcm2835_property: use cached values when querying framebuffer * hw/arm/nseries: don't allocate large sized array on the stack * fix LPAE descriptor address masking (only visible for EL2) * fix stage 2 exec permission handling for AArch32 * first part of supporting syndrome info for data aborts to EL2 * virt: NUMA support * work towards i.MX6 support * avoid unnecessary TLB flush on TCR_EL2, TCR_EL3 writes -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABCAAGBQJXNIUqAAoJEDwlJe0UNgzeYmMP/05g/rzOekjL4c41MvN8zUrB z8CFRmySbTNda/gyY/o8DDUvJOq637g1Arw82o3jYJBTVx/EjFTK4ENe7zN99Xay fzzUtOp+TY40k9ZUQ3FtdAiN/Y54WHuozX3CKOu47W7hErkNn4/GVG68IW93AHe7 AIxVDUrNUCsMPGFy0YBOTWM5u9kwrosH6vb+EvBSDXJTrdALidf0CWBGp58Ik79g T3dAKE9EuVTWVKnR3J6QTxD97Xmvsj/2dVtNOGXRw7ZL/utmtCG/uO1V06VMmf8R 5LPY56RemhhF4CftYnk9+kzdftFJKt2kHsmfoEHSfsrhpp51Ro9/3WnFGstOjjQL OUFwpmHKpaINRTs6zudMTiUoI3JtzNI7cefSWuu0+O8ErLnqxfJEQgnZStUpi/JG V/YAoEiA+ZYTv8gm3X7a6+cb+g/DiqLlPorpE4xFFR4gbzIujjAsFQMmsqlTisNl j0yjflQAcUCTgo9wzoi5DxHZ69OfpZXL6gAU4HKhTum+w0436WyPLtVxD7bCxe71 ki0Mol61Hh62p0swUkBv9YHNOj2PKghQwVFTOtxtUs4jPfOTItg795A/cDJGXGe8 zcAUNdwnKp/OsbaVMEOirko02qlS+F3FaOcg/qAchDgCZcOliUlSQTKoNnMyKMhC PjQVUfYpU/59r+ESJ6OL =RL/g -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20160512' into staging target-arm queue: * blizzard, omap_lcdc: code cleanup to remove DEPTH != 32 dead code * QOMify various ARM devices * bcm2835_property: use cached values when querying framebuffer * hw/arm/nseries: don't allocate large sized array on the stack * fix LPAE descriptor address masking (only visible for EL2) * fix stage 2 exec permission handling for AArch32 * first part of supporting syndrome info for data aborts to EL2 * virt: NUMA support * work towards i.MX6 support * avoid unnecessary TLB flush on TCR_EL2, TCR_EL3 writes # gpg: Signature made Thu 12 May 2016 14:29:14 BST using RSA key ID 14360CDE # 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>" * remotes/pmaydell/tags/pull-target-arm-20160512: (43 commits) hw/arm: QOM'ify versatilepb.c hw/arm: QOM'ify strongarm.c hw/arm: QOM'ify stellaris.c hw/arm: QOM'ify spitz.c hw/arm: QOM'ify pxa2xx_pic.c hw/arm: QOM'ify pxa2xx.c hw/arm: QOM'ify integratorcp.c hw/arm: QOM'ify highbank.c hw/arm: QOM'ify armv7m.c target-arm: Avoid unnecessary TLB flush on TCR_EL2, TCR_EL3 writes hw/display/blizzard: Remove blizzard_template.h hw/display/blizzard: Expand out macros i.MX: Add sabrelite i.MX6 emulation. i.MX: Add i.MX6 SOC implementation. i.MX: Add the Freescale SPI Controller FIFO: Add a FIFO32 implementation i.MX: Add i.MX6 System Reset Controller device. ARM: Factor out ARM on/off PSCI control functions ACPI: Virt: Generate SRAT table ACPI: move acpi_build_srat_memory to common place ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
e4f70d6358
|
@ -100,6 +100,7 @@ CONFIG_ALLWINNER_A10_PIT=y
|
|||
CONFIG_ALLWINNER_A10_PIC=y
|
||||
CONFIG_ALLWINNER_A10=y
|
||||
|
||||
CONFIG_FSL_IMX6=y
|
||||
CONFIG_FSL_IMX31=y
|
||||
CONFIG_FSL_IMX25=y
|
||||
|
||||
|
|
|
@ -1563,3 +1563,14 @@ build_rsdt(GArray *table_data, GArray *linker, GArray *table_offsets,
|
|||
build_header(linker, table_data,
|
||||
(void *)rsdt, "RSDT", rsdt_len, 1, oem_id, oem_table_id);
|
||||
}
|
||||
|
||||
void build_srat_memory(AcpiSratMemoryAffinity *numamem, uint64_t base,
|
||||
uint64_t len, int node, MemoryAffinityFlags flags)
|
||||
{
|
||||
numamem->type = ACPI_SRAT_MEMORY;
|
||||
numamem->length = sizeof(*numamem);
|
||||
numamem->proximity = cpu_to_le32(node);
|
||||
numamem->flags = cpu_to_le32(flags);
|
||||
numamem->base_addr = cpu_to_le64(base);
|
||||
numamem->range_length = cpu_to_le64(len);
|
||||
}
|
||||
|
|
|
@ -16,4 +16,5 @@ obj-$(CONFIG_STM32F205_SOC) += stm32f205_soc.o
|
|||
obj-$(CONFIG_XLNX_ZYNQMP) += xlnx-zynqmp.o xlnx-ep108.o
|
||||
obj-$(CONFIG_FSL_IMX25) += fsl-imx25.o imx25_pdk.o
|
||||
obj-$(CONFIG_FSL_IMX31) += fsl-imx31.o kzm.o
|
||||
obj-$(CONFIG_FSL_IMX6) += fsl-imx6.o sabrelite.o
|
||||
obj-$(CONFIG_ASPEED_SOC) += ast2400.o palmetto-bmc.o
|
||||
|
|
|
@ -132,14 +132,14 @@ typedef struct {
|
|||
uint32_t base;
|
||||
} BitBandState;
|
||||
|
||||
static int bitband_init(SysBusDevice *dev)
|
||||
static void bitband_init(Object *obj)
|
||||
{
|
||||
BitBandState *s = BITBAND(dev);
|
||||
BitBandState *s = BITBAND(obj);
|
||||
SysBusDevice *dev = SYS_BUS_DEVICE(obj);
|
||||
|
||||
memory_region_init_io(&s->iomem, OBJECT(s), &bitband_ops, &s->base,
|
||||
memory_region_init_io(&s->iomem, obj, &bitband_ops, &s->base,
|
||||
"bitband", 0x02000000);
|
||||
sysbus_init_mmio(dev, &s->iomem);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void armv7m_bitband_init(void)
|
||||
|
@ -244,9 +244,7 @@ static Property bitband_properties[] = {
|
|||
static void bitband_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
|
||||
|
||||
k->init = bitband_init;
|
||||
dc->props = bitband_properties;
|
||||
}
|
||||
|
||||
|
@ -254,6 +252,7 @@ static const TypeInfo bitband_info = {
|
|||
.name = TYPE_BITBAND,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(BitBandState),
|
||||
.instance_init = bitband_init,
|
||||
.class_init = bitband_class_init,
|
||||
};
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "hw/arm/linux-boot-if.h"
|
||||
#include "sysemu/kvm.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "sysemu/numa.h"
|
||||
#include "hw/boards.h"
|
||||
#include "hw/loader.h"
|
||||
#include "elf.h"
|
||||
|
@ -405,6 +406,9 @@ static int load_dtb(hwaddr addr, const struct arm_boot_info *binfo,
|
|||
void *fdt = NULL;
|
||||
int size, rc;
|
||||
uint32_t acells, scells;
|
||||
char *nodename;
|
||||
unsigned int i;
|
||||
hwaddr mem_base, mem_len;
|
||||
|
||||
if (binfo->dtb_filename) {
|
||||
char *filename;
|
||||
|
@ -456,12 +460,39 @@ static int load_dtb(hwaddr addr, const struct arm_boot_info *binfo,
|
|||
goto fail;
|
||||
}
|
||||
|
||||
rc = qemu_fdt_setprop_sized_cells(fdt, "/memory", "reg",
|
||||
acells, binfo->loader_start,
|
||||
scells, binfo->ram_size);
|
||||
if (rc < 0) {
|
||||
fprintf(stderr, "couldn't set /memory/reg\n");
|
||||
goto fail;
|
||||
if (nb_numa_nodes > 0) {
|
||||
/*
|
||||
* Turn the /memory node created before into a NOP node, then create
|
||||
* /memory@addr nodes for all numa nodes respectively.
|
||||
*/
|
||||
qemu_fdt_nop_node(fdt, "/memory");
|
||||
mem_base = binfo->loader_start;
|
||||
for (i = 0; i < nb_numa_nodes; i++) {
|
||||
mem_len = numa_info[i].node_mem;
|
||||
nodename = g_strdup_printf("/memory@%" PRIx64, mem_base);
|
||||
qemu_fdt_add_subnode(fdt, nodename);
|
||||
qemu_fdt_setprop_string(fdt, nodename, "device_type", "memory");
|
||||
rc = qemu_fdt_setprop_sized_cells(fdt, nodename, "reg",
|
||||
acells, mem_base,
|
||||
scells, mem_len);
|
||||
if (rc < 0) {
|
||||
fprintf(stderr, "couldn't set %s/reg for node %d\n", nodename,
|
||||
i);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
qemu_fdt_setprop_cell(fdt, nodename, "numa-node-id", i);
|
||||
mem_base += mem_len;
|
||||
g_free(nodename);
|
||||
}
|
||||
} else {
|
||||
rc = qemu_fdt_setprop_sized_cells(fdt, "/memory", "reg",
|
||||
acells, binfo->loader_start,
|
||||
scells, binfo->ram_size);
|
||||
if (rc < 0) {
|
||||
fprintf(stderr, "couldn't set /memory/reg\n");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
if (binfo->kernel_cmdline && *binfo->kernel_cmdline) {
|
||||
|
|
449
hw/arm/fsl-imx6.c
Normal file
449
hw/arm/fsl-imx6.c
Normal file
|
@ -0,0 +1,449 @@
|
|||
/*
|
||||
* Copyright (c) 2015 Jean-Christophe Dubois <jcd@tribudubois.net>
|
||||
*
|
||||
* i.MX6 SOC emulation.
|
||||
*
|
||||
* Based on hw/arm/fsl-imx31.c
|
||||
*
|
||||
* 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 "qapi/error.h"
|
||||
#include "qemu-common.h"
|
||||
#include "hw/arm/fsl-imx6.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "sysemu/char.h"
|
||||
#include "qemu/error-report.h"
|
||||
|
||||
#define NAME_SIZE 20
|
||||
|
||||
static void fsl_imx6_init(Object *obj)
|
||||
{
|
||||
FslIMX6State *s = FSL_IMX6(obj);
|
||||
char name[NAME_SIZE];
|
||||
int i;
|
||||
|
||||
if (smp_cpus > FSL_IMX6_NUM_CPUS) {
|
||||
error_report("%s: Only %d CPUs are supported (%d requested)",
|
||||
TYPE_FSL_IMX6, FSL_IMX6_NUM_CPUS, smp_cpus);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for (i = 0; i < smp_cpus; i++) {
|
||||
object_initialize(&s->cpu[i], sizeof(s->cpu[i]),
|
||||
"cortex-a9-" TYPE_ARM_CPU);
|
||||
snprintf(name, NAME_SIZE, "cpu%d", i);
|
||||
object_property_add_child(obj, name, OBJECT(&s->cpu[i]), NULL);
|
||||
}
|
||||
|
||||
object_initialize(&s->a9mpcore, sizeof(s->a9mpcore), TYPE_A9MPCORE_PRIV);
|
||||
qdev_set_parent_bus(DEVICE(&s->a9mpcore), sysbus_get_default());
|
||||
object_property_add_child(obj, "a9mpcore", OBJECT(&s->a9mpcore), NULL);
|
||||
|
||||
object_initialize(&s->ccm, sizeof(s->ccm), TYPE_IMX6_CCM);
|
||||
qdev_set_parent_bus(DEVICE(&s->ccm), sysbus_get_default());
|
||||
object_property_add_child(obj, "ccm", OBJECT(&s->ccm), NULL);
|
||||
|
||||
object_initialize(&s->src, sizeof(s->src), TYPE_IMX6_SRC);
|
||||
qdev_set_parent_bus(DEVICE(&s->src), sysbus_get_default());
|
||||
object_property_add_child(obj, "src", OBJECT(&s->src), NULL);
|
||||
|
||||
for (i = 0; i < FSL_IMX6_NUM_UARTS; i++) {
|
||||
object_initialize(&s->uart[i], sizeof(s->uart[i]), TYPE_IMX_SERIAL);
|
||||
qdev_set_parent_bus(DEVICE(&s->uart[i]), sysbus_get_default());
|
||||
snprintf(name, NAME_SIZE, "uart%d", i + 1);
|
||||
object_property_add_child(obj, name, OBJECT(&s->uart[i]), NULL);
|
||||
}
|
||||
|
||||
object_initialize(&s->gpt, sizeof(s->gpt), TYPE_IMX_GPT);
|
||||
qdev_set_parent_bus(DEVICE(&s->gpt), sysbus_get_default());
|
||||
object_property_add_child(obj, "gpt", OBJECT(&s->gpt), NULL);
|
||||
|
||||
for (i = 0; i < FSL_IMX6_NUM_EPITS; i++) {
|
||||
object_initialize(&s->epit[i], sizeof(s->epit[i]), TYPE_IMX_EPIT);
|
||||
qdev_set_parent_bus(DEVICE(&s->epit[i]), sysbus_get_default());
|
||||
snprintf(name, NAME_SIZE, "epit%d", i + 1);
|
||||
object_property_add_child(obj, name, OBJECT(&s->epit[i]), NULL);
|
||||
}
|
||||
|
||||
for (i = 0; i < FSL_IMX6_NUM_I2CS; i++) {
|
||||
object_initialize(&s->i2c[i], sizeof(s->i2c[i]), TYPE_IMX_I2C);
|
||||
qdev_set_parent_bus(DEVICE(&s->i2c[i]), sysbus_get_default());
|
||||
snprintf(name, NAME_SIZE, "i2c%d", i + 1);
|
||||
object_property_add_child(obj, name, OBJECT(&s->i2c[i]), NULL);
|
||||
}
|
||||
|
||||
for (i = 0; i < FSL_IMX6_NUM_GPIOS; i++) {
|
||||
object_initialize(&s->gpio[i], sizeof(s->gpio[i]), TYPE_IMX_GPIO);
|
||||
qdev_set_parent_bus(DEVICE(&s->gpio[i]), sysbus_get_default());
|
||||
snprintf(name, NAME_SIZE, "gpio%d", i + 1);
|
||||
object_property_add_child(obj, name, OBJECT(&s->gpio[i]), NULL);
|
||||
}
|
||||
|
||||
for (i = 0; i < FSL_IMX6_NUM_ESDHCS; i++) {
|
||||
object_initialize(&s->esdhc[i], sizeof(s->esdhc[i]), TYPE_SYSBUS_SDHCI);
|
||||
qdev_set_parent_bus(DEVICE(&s->esdhc[i]), sysbus_get_default());
|
||||
snprintf(name, NAME_SIZE, "sdhc%d", i + 1);
|
||||
object_property_add_child(obj, name, OBJECT(&s->esdhc[i]), NULL);
|
||||
}
|
||||
|
||||
for (i = 0; i < FSL_IMX6_NUM_ECSPIS; i++) {
|
||||
object_initialize(&s->spi[i], sizeof(s->spi[i]), TYPE_IMX_SPI);
|
||||
qdev_set_parent_bus(DEVICE(&s->spi[i]), sysbus_get_default());
|
||||
snprintf(name, NAME_SIZE, "spi%d", i + 1);
|
||||
object_property_add_child(obj, name, OBJECT(&s->spi[i]), NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void fsl_imx6_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
FslIMX6State *s = FSL_IMX6(dev);
|
||||
uint16_t i;
|
||||
Error *err = NULL;
|
||||
|
||||
for (i = 0; i < smp_cpus; i++) {
|
||||
|
||||
/* On uniprocessor, the CBAR is set to 0 */
|
||||
if (smp_cpus > 1) {
|
||||
object_property_set_int(OBJECT(&s->cpu[i]), FSL_IMX6_A9MPCORE_ADDR,
|
||||
"reset-cbar", &error_abort);
|
||||
}
|
||||
|
||||
/* All CPU but CPU 0 start in power off mode */
|
||||
if (i) {
|
||||
object_property_set_bool(OBJECT(&s->cpu[i]), true,
|
||||
"start-powered-off", &error_abort);
|
||||
}
|
||||
|
||||
object_property_set_bool(OBJECT(&s->cpu[i]), true, "realized", &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
object_property_set_int(OBJECT(&s->a9mpcore), smp_cpus, "num-cpu",
|
||||
&error_abort);
|
||||
|
||||
object_property_set_int(OBJECT(&s->a9mpcore),
|
||||
FSL_IMX6_MAX_IRQ + GIC_INTERNAL, "num-irq",
|
||||
&error_abort);
|
||||
|
||||
object_property_set_bool(OBJECT(&s->a9mpcore), true, "realized", &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->a9mpcore), 0, FSL_IMX6_A9MPCORE_ADDR);
|
||||
|
||||
for (i = 0; i < smp_cpus; i++) {
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(&s->a9mpcore), i,
|
||||
qdev_get_gpio_in(DEVICE(&s->cpu[i]), ARM_CPU_IRQ));
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(&s->a9mpcore), i + smp_cpus,
|
||||
qdev_get_gpio_in(DEVICE(&s->cpu[i]), ARM_CPU_FIQ));
|
||||
}
|
||||
|
||||
object_property_set_bool(OBJECT(&s->ccm), true, "realized", &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->ccm), 0, FSL_IMX6_CCM_ADDR);
|
||||
|
||||
object_property_set_bool(OBJECT(&s->src), true, "realized", &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->src), 0, FSL_IMX6_SRC_ADDR);
|
||||
|
||||
/* Initialize all UARTs */
|
||||
for (i = 0; i < FSL_IMX6_NUM_UARTS; i++) {
|
||||
static const struct {
|
||||
hwaddr addr;
|
||||
unsigned int irq;
|
||||
} serial_table[FSL_IMX6_NUM_UARTS] = {
|
||||
{ FSL_IMX6_UART1_ADDR, FSL_IMX6_UART1_IRQ },
|
||||
{ FSL_IMX6_UART2_ADDR, FSL_IMX6_UART2_IRQ },
|
||||
{ FSL_IMX6_UART3_ADDR, FSL_IMX6_UART3_IRQ },
|
||||
{ FSL_IMX6_UART4_ADDR, FSL_IMX6_UART4_IRQ },
|
||||
{ FSL_IMX6_UART5_ADDR, FSL_IMX6_UART5_IRQ },
|
||||
};
|
||||
|
||||
if (i < MAX_SERIAL_PORTS) {
|
||||
CharDriverState *chr;
|
||||
|
||||
chr = serial_hds[i];
|
||||
|
||||
if (!chr) {
|
||||
char *label = g_strdup_printf("imx6.uart%d", i + 1);
|
||||
chr = qemu_chr_new(label, "null", NULL);
|
||||
g_free(label);
|
||||
serial_hds[i] = chr;
|
||||
}
|
||||
|
||||
qdev_prop_set_chr(DEVICE(&s->uart[i]), "chardev", chr);
|
||||
}
|
||||
|
||||
object_property_set_bool(OBJECT(&s->uart[i]), true, "realized", &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->uart[i]), 0, serial_table[i].addr);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(&s->uart[i]), 0,
|
||||
qdev_get_gpio_in(DEVICE(&s->a9mpcore),
|
||||
serial_table[i].irq));
|
||||
}
|
||||
|
||||
s->gpt.ccm = IMX_CCM(&s->ccm);
|
||||
|
||||
object_property_set_bool(OBJECT(&s->gpt), true, "realized", &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpt), 0, FSL_IMX6_GPT_ADDR);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpt), 0,
|
||||
qdev_get_gpio_in(DEVICE(&s->a9mpcore),
|
||||
FSL_IMX6_GPT_IRQ));
|
||||
|
||||
/* Initialize all EPIT timers */
|
||||
for (i = 0; i < FSL_IMX6_NUM_EPITS; i++) {
|
||||
static const struct {
|
||||
hwaddr addr;
|
||||
unsigned int irq;
|
||||
} epit_table[FSL_IMX6_NUM_EPITS] = {
|
||||
{ FSL_IMX6_EPIT1_ADDR, FSL_IMX6_EPIT1_IRQ },
|
||||
{ FSL_IMX6_EPIT2_ADDR, FSL_IMX6_EPIT2_IRQ },
|
||||
};
|
||||
|
||||
s->epit[i].ccm = IMX_CCM(&s->ccm);
|
||||
|
||||
object_property_set_bool(OBJECT(&s->epit[i]), true, "realized", &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->epit[i]), 0, epit_table[i].addr);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(&s->epit[i]), 0,
|
||||
qdev_get_gpio_in(DEVICE(&s->a9mpcore),
|
||||
epit_table[i].irq));
|
||||
}
|
||||
|
||||
/* Initialize all I2C */
|
||||
for (i = 0; i < FSL_IMX6_NUM_I2CS; i++) {
|
||||
static const struct {
|
||||
hwaddr addr;
|
||||
unsigned int irq;
|
||||
} i2c_table[FSL_IMX6_NUM_I2CS] = {
|
||||
{ FSL_IMX6_I2C1_ADDR, FSL_IMX6_I2C1_IRQ },
|
||||
{ FSL_IMX6_I2C2_ADDR, FSL_IMX6_I2C2_IRQ },
|
||||
{ FSL_IMX6_I2C3_ADDR, FSL_IMX6_I2C3_IRQ }
|
||||
};
|
||||
|
||||
object_property_set_bool(OBJECT(&s->i2c[i]), true, "realized", &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->i2c[i]), 0, i2c_table[i].addr);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c[i]), 0,
|
||||
qdev_get_gpio_in(DEVICE(&s->a9mpcore),
|
||||
i2c_table[i].irq));
|
||||
}
|
||||
|
||||
/* Initialize all GPIOs */
|
||||
for (i = 0; i < FSL_IMX6_NUM_GPIOS; i++) {
|
||||
static const struct {
|
||||
hwaddr addr;
|
||||
unsigned int irq_low;
|
||||
unsigned int irq_high;
|
||||
} gpio_table[FSL_IMX6_NUM_GPIOS] = {
|
||||
{
|
||||
FSL_IMX6_GPIO1_ADDR,
|
||||
FSL_IMX6_GPIO1_LOW_IRQ,
|
||||
FSL_IMX6_GPIO1_HIGH_IRQ
|
||||
},
|
||||
{
|
||||
FSL_IMX6_GPIO2_ADDR,
|
||||
FSL_IMX6_GPIO2_LOW_IRQ,
|
||||
FSL_IMX6_GPIO2_HIGH_IRQ
|
||||
},
|
||||
{
|
||||
FSL_IMX6_GPIO3_ADDR,
|
||||
FSL_IMX6_GPIO3_LOW_IRQ,
|
||||
FSL_IMX6_GPIO3_HIGH_IRQ
|
||||
},
|
||||
{
|
||||
FSL_IMX6_GPIO4_ADDR,
|
||||
FSL_IMX6_GPIO4_LOW_IRQ,
|
||||
FSL_IMX6_GPIO4_HIGH_IRQ
|
||||
},
|
||||
{
|
||||
FSL_IMX6_GPIO5_ADDR,
|
||||
FSL_IMX6_GPIO5_LOW_IRQ,
|
||||
FSL_IMX6_GPIO5_HIGH_IRQ
|
||||
},
|
||||
{
|
||||
FSL_IMX6_GPIO6_ADDR,
|
||||
FSL_IMX6_GPIO6_LOW_IRQ,
|
||||
FSL_IMX6_GPIO6_HIGH_IRQ
|
||||
},
|
||||
{
|
||||
FSL_IMX6_GPIO7_ADDR,
|
||||
FSL_IMX6_GPIO7_LOW_IRQ,
|
||||
FSL_IMX6_GPIO7_HIGH_IRQ
|
||||
},
|
||||
};
|
||||
|
||||
object_property_set_bool(OBJECT(&s->gpio[i]), true, "has-edge-sel",
|
||||
&error_abort);
|
||||
object_property_set_bool(OBJECT(&s->gpio[i]), true, "has-upper-pin-irq",
|
||||
&error_abort);
|
||||
object_property_set_bool(OBJECT(&s->gpio[i]), true, "realized", &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpio[i]), 0, gpio_table[i].addr);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio[i]), 0,
|
||||
qdev_get_gpio_in(DEVICE(&s->a9mpcore),
|
||||
gpio_table[i].irq_low));
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio[i]), 1,
|
||||
qdev_get_gpio_in(DEVICE(&s->a9mpcore),
|
||||
gpio_table[i].irq_high));
|
||||
}
|
||||
|
||||
/* Initialize all SDHC */
|
||||
for (i = 0; i < FSL_IMX6_NUM_ESDHCS; i++) {
|
||||
static const struct {
|
||||
hwaddr addr;
|
||||
unsigned int irq;
|
||||
} esdhc_table[FSL_IMX6_NUM_ESDHCS] = {
|
||||
{ FSL_IMX6_uSDHC1_ADDR, FSL_IMX6_uSDHC1_IRQ },
|
||||
{ FSL_IMX6_uSDHC2_ADDR, FSL_IMX6_uSDHC2_IRQ },
|
||||
{ FSL_IMX6_uSDHC3_ADDR, FSL_IMX6_uSDHC3_IRQ },
|
||||
{ FSL_IMX6_uSDHC4_ADDR, FSL_IMX6_uSDHC4_IRQ },
|
||||
};
|
||||
|
||||
object_property_set_bool(OBJECT(&s->esdhc[i]), true, "realized", &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->esdhc[i]), 0, esdhc_table[i].addr);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(&s->esdhc[i]), 0,
|
||||
qdev_get_gpio_in(DEVICE(&s->a9mpcore),
|
||||
esdhc_table[i].irq));
|
||||
}
|
||||
|
||||
/* Initialize all ECSPI */
|
||||
for (i = 0; i < FSL_IMX6_NUM_ECSPIS; i++) {
|
||||
static const struct {
|
||||
hwaddr addr;
|
||||
unsigned int irq;
|
||||
} spi_table[FSL_IMX6_NUM_ECSPIS] = {
|
||||
{ FSL_IMX6_eCSPI1_ADDR, FSL_IMX6_ECSPI1_IRQ },
|
||||
{ FSL_IMX6_eCSPI2_ADDR, FSL_IMX6_ECSPI2_IRQ },
|
||||
{ FSL_IMX6_eCSPI3_ADDR, FSL_IMX6_ECSPI3_IRQ },
|
||||
{ FSL_IMX6_eCSPI4_ADDR, FSL_IMX6_ECSPI4_IRQ },
|
||||
{ FSL_IMX6_eCSPI5_ADDR, FSL_IMX6_ECSPI5_IRQ },
|
||||
};
|
||||
|
||||
/* Initialize the SPI */
|
||||
object_property_set_bool(OBJECT(&s->spi[i]), true, "realized", &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi[i]), 0, spi_table[i].addr);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(&s->spi[i]), 0,
|
||||
qdev_get_gpio_in(DEVICE(&s->a9mpcore),
|
||||
spi_table[i].irq));
|
||||
}
|
||||
|
||||
/* ROM memory */
|
||||
memory_region_init_rom_device(&s->rom, NULL, NULL, NULL, "imx6.rom",
|
||||
FSL_IMX6_ROM_SIZE, &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
memory_region_add_subregion(get_system_memory(), FSL_IMX6_ROM_ADDR,
|
||||
&s->rom);
|
||||
|
||||
/* CAAM memory */
|
||||
memory_region_init_rom_device(&s->caam, NULL, NULL, NULL, "imx6.caam",
|
||||
FSL_IMX6_CAAM_MEM_SIZE, &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
memory_region_add_subregion(get_system_memory(), FSL_IMX6_CAAM_MEM_ADDR,
|
||||
&s->caam);
|
||||
|
||||
/* OCRAM memory */
|
||||
memory_region_init_ram(&s->ocram, NULL, "imx6.ocram", FSL_IMX6_OCRAM_SIZE,
|
||||
&err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
memory_region_add_subregion(get_system_memory(), FSL_IMX6_OCRAM_ADDR,
|
||||
&s->ocram);
|
||||
vmstate_register_ram_global(&s->ocram);
|
||||
|
||||
/* internal OCRAM (256 KB) is aliased over 1 MB */
|
||||
memory_region_init_alias(&s->ocram_alias, NULL, "imx6.ocram_alias",
|
||||
&s->ocram, 0, FSL_IMX6_OCRAM_ALIAS_SIZE);
|
||||
memory_region_add_subregion(get_system_memory(), FSL_IMX6_OCRAM_ALIAS_ADDR,
|
||||
&s->ocram_alias);
|
||||
}
|
||||
|
||||
static void fsl_imx6_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(oc);
|
||||
|
||||
dc->realize = fsl_imx6_realize;
|
||||
|
||||
/*
|
||||
* Reason: creates an ARM CPU, thus use after free(), see
|
||||
* arm_cpu_class_init()
|
||||
*/
|
||||
dc->cannot_destroy_with_object_finalize_yet = true;
|
||||
dc->desc = "i.MX6 SOC";
|
||||
}
|
||||
|
||||
static const TypeInfo fsl_imx6_type_info = {
|
||||
.name = TYPE_FSL_IMX6,
|
||||
.parent = TYPE_DEVICE,
|
||||
.instance_size = sizeof(FslIMX6State),
|
||||
.instance_init = fsl_imx6_init,
|
||||
.class_init = fsl_imx6_class_init,
|
||||
};
|
||||
|
||||
static void fsl_imx6_register_types(void)
|
||||
{
|
||||
type_register_static(&fsl_imx6_type_info);
|
||||
}
|
||||
|
||||
type_init(fsl_imx6_register_types)
|
|
@ -168,23 +168,20 @@ static void highbank_regs_reset(DeviceState *dev)
|
|||
s->regs[0x43] = 0x05F40121;
|
||||
}
|
||||
|
||||
static int highbank_regs_init(SysBusDevice *dev)
|
||||
static void highbank_regs_init(Object *obj)
|
||||
{
|
||||
HighbankRegsState *s = HIGHBANK_REGISTERS(dev);
|
||||
HighbankRegsState *s = HIGHBANK_REGISTERS(obj);
|
||||
SysBusDevice *dev = SYS_BUS_DEVICE(obj);
|
||||
|
||||
memory_region_init_io(&s->iomem, OBJECT(s), &hb_mem_ops, s->regs,
|
||||
memory_region_init_io(&s->iomem, obj, &hb_mem_ops, s->regs,
|
||||
"highbank_regs", 0x1000);
|
||||
sysbus_init_mmio(dev, &s->iomem);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void highbank_regs_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass);
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
sbc->init = highbank_regs_init;
|
||||
dc->desc = "Calxeda Highbank registers";
|
||||
dc->vmsd = &vmstate_highbank_regs;
|
||||
dc->reset = highbank_regs_reset;
|
||||
|
@ -194,6 +191,7 @@ static const TypeInfo highbank_regs_info = {
|
|||
.name = TYPE_HIGHBANK_REGISTERS,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(HighbankRegsState),
|
||||
.instance_init = highbank_regs_init,
|
||||
.class_init = highbank_regs_class_init,
|
||||
};
|
||||
|
||||
|
|
|
@ -242,9 +242,10 @@ static const MemoryRegionOps integratorcm_ops = {
|
|||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
static int integratorcm_init(SysBusDevice *dev)
|
||||
static void integratorcm_init(Object *obj)
|
||||
{
|
||||
IntegratorCMState *s = INTEGRATOR_CM(dev);
|
||||
IntegratorCMState *s = INTEGRATOR_CM(obj);
|
||||
SysBusDevice *dev = SYS_BUS_DEVICE(obj);
|
||||
|
||||
s->cm_osc = 0x01000048;
|
||||
/* ??? What should the high bits of this value be? */
|
||||
|
@ -269,17 +270,16 @@ static int integratorcm_init(SysBusDevice *dev)
|
|||
s->cm_init = 0x00000112;
|
||||
s->cm_refcnt_offset = muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 24,
|
||||
1000);
|
||||
memory_region_init_ram(&s->flash, OBJECT(s), "integrator.flash", 0x100000,
|
||||
memory_region_init_ram(&s->flash, obj, "integrator.flash", 0x100000,
|
||||
&error_fatal);
|
||||
vmstate_register_ram_global(&s->flash);
|
||||
|
||||
memory_region_init_io(&s->iomem, OBJECT(s), &integratorcm_ops, s,
|
||||
memory_region_init_io(&s->iomem, obj, &integratorcm_ops, s,
|
||||
"integratorcm", 0x00800000);
|
||||
sysbus_init_mmio(dev, &s->iomem);
|
||||
|
||||
integratorcm_do_remap(s);
|
||||
/* ??? Save/restore. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Integrator/CP hardware emulation. */
|
||||
|
@ -394,18 +394,18 @@ static const MemoryRegionOps icp_pic_ops = {
|
|||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
static int icp_pic_init(SysBusDevice *sbd)
|
||||
static void icp_pic_init(Object *obj)
|
||||
{
|
||||
DeviceState *dev = DEVICE(sbd);
|
||||
icp_pic_state *s = INTEGRATOR_PIC(dev);
|
||||
DeviceState *dev = DEVICE(obj);
|
||||
icp_pic_state *s = INTEGRATOR_PIC(obj);
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
||||
|
||||
qdev_init_gpio_in(dev, icp_pic_set_irq, 32);
|
||||
sysbus_init_irq(sbd, &s->parent_irq);
|
||||
sysbus_init_irq(sbd, &s->parent_fiq);
|
||||
memory_region_init_io(&s->iomem, OBJECT(s), &icp_pic_ops, s,
|
||||
memory_region_init_io(&s->iomem, obj, &icp_pic_ops, s,
|
||||
"icp-pic", 0x00800000);
|
||||
sysbus_init_mmio(sbd, &s->iomem);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* CP control registers. */
|
||||
|
@ -630,9 +630,7 @@ static Property core_properties[] = {
|
|||
static void core_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
|
||||
|
||||
k->init = integratorcm_init;
|
||||
dc->props = core_properties;
|
||||
}
|
||||
|
||||
|
@ -640,21 +638,15 @@ static const TypeInfo core_info = {
|
|||
.name = TYPE_INTEGRATOR_CM,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(IntegratorCMState),
|
||||
.instance_init = integratorcm_init,
|
||||
.class_init = core_class_init,
|
||||
};
|
||||
|
||||
static void icp_pic_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
|
||||
|
||||
sdc->init = icp_pic_init;
|
||||
}
|
||||
|
||||
static const TypeInfo icp_pic_info = {
|
||||
.name = TYPE_INTEGRATOR_PIC,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(icp_pic_state),
|
||||
.class_init = icp_pic_class_init,
|
||||
.instance_init = icp_pic_init,
|
||||
};
|
||||
|
||||
static const TypeInfo icp_ctrl_regs_info = {
|
||||
|
|
|
@ -1364,7 +1364,7 @@ static void n8x0_init(MachineState *machine,
|
|||
|
||||
if (option_rom[0].name &&
|
||||
(machine->boot_order[0] == 'n' || !machine->kernel_filename)) {
|
||||
uint8_t nolo_tags[0x10000];
|
||||
uint8_t *nolo_tags = g_new(uint8_t, 0x10000);
|
||||
/* No, wait, better start at the ROM. */
|
||||
s->mpu->cpu->env.regs[15] = OMAP2_Q2_BASE + 0x400000;
|
||||
|
||||
|
@ -1383,6 +1383,7 @@ static void n8x0_init(MachineState *machine,
|
|||
|
||||
n800_setup_nolo_tags(nolo_tags);
|
||||
cpu_physical_memory_write(OMAP2_SRAM_BASE, nolo_tags, 0x10000);
|
||||
g_free(nolo_tags);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1107,9 +1107,10 @@ static const MemoryRegionOps pxa2xx_rtc_ops = {
|
|||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
static int pxa2xx_rtc_init(SysBusDevice *dev)
|
||||
static void pxa2xx_rtc_init(Object *obj)
|
||||
{
|
||||
PXA2xxRTCState *s = PXA2XX_RTC(dev);
|
||||
PXA2xxRTCState *s = PXA2XX_RTC(obj);
|
||||
SysBusDevice *dev = SYS_BUS_DEVICE(obj);
|
||||
struct tm tm;
|
||||
int wom;
|
||||
|
||||
|
@ -1138,11 +1139,9 @@ static int pxa2xx_rtc_init(SysBusDevice *dev)
|
|||
|
||||
sysbus_init_irq(dev, &s->rtc_irq);
|
||||
|
||||
memory_region_init_io(&s->iomem, OBJECT(s), &pxa2xx_rtc_ops, s,
|
||||
memory_region_init_io(&s->iomem, obj, &pxa2xx_rtc_ops, s,
|
||||
"pxa2xx-rtc", 0x10000);
|
||||
sysbus_init_mmio(dev, &s->iomem);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pxa2xx_rtc_pre_save(void *opaque)
|
||||
|
@ -1195,9 +1194,7 @@ static const VMStateDescription vmstate_pxa2xx_rtc_regs = {
|
|||
static void pxa2xx_rtc_sysbus_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
|
||||
|
||||
k->init = pxa2xx_rtc_init;
|
||||
dc->desc = "PXA2xx RTC Controller";
|
||||
dc->vmsd = &vmstate_pxa2xx_rtc_regs;
|
||||
}
|
||||
|
@ -1206,6 +1203,7 @@ static const TypeInfo pxa2xx_rtc_sysbus_info = {
|
|||
.name = TYPE_PXA2XX_RTC,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(PXA2xxRTCState),
|
||||
.instance_init = pxa2xx_rtc_init,
|
||||
.class_init = pxa2xx_rtc_sysbus_class_init,
|
||||
};
|
||||
|
||||
|
@ -1501,19 +1499,18 @@ PXA2xxI2CState *pxa2xx_i2c_init(hwaddr base,
|
|||
return s;
|
||||
}
|
||||
|
||||
static int pxa2xx_i2c_initfn(SysBusDevice *sbd)
|
||||
static void pxa2xx_i2c_initfn(Object *obj)
|
||||
{
|
||||
DeviceState *dev = DEVICE(sbd);
|
||||
PXA2xxI2CState *s = PXA2XX_I2C(dev);
|
||||
DeviceState *dev = DEVICE(obj);
|
||||
PXA2xxI2CState *s = PXA2XX_I2C(obj);
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
||||
|
||||
s->bus = i2c_init_bus(dev, "i2c");
|
||||
|
||||
memory_region_init_io(&s->iomem, OBJECT(s), &pxa2xx_i2c_ops, s,
|
||||
memory_region_init_io(&s->iomem, obj, &pxa2xx_i2c_ops, s,
|
||||
"pxa2xx-i2c", s->region_size);
|
||||
sysbus_init_mmio(sbd, &s->iomem);
|
||||
sysbus_init_irq(sbd, &s->irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
I2CBus *pxa2xx_i2c_bus(PXA2xxI2CState *s)
|
||||
|
@ -1530,9 +1527,7 @@ static Property pxa2xx_i2c_properties[] = {
|
|||
static void pxa2xx_i2c_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
|
||||
|
||||
k->init = pxa2xx_i2c_initfn;
|
||||
dc->desc = "PXA2xx I2C Bus Controller";
|
||||
dc->vmsd = &vmstate_pxa2xx_i2c;
|
||||
dc->props = pxa2xx_i2c_properties;
|
||||
|
@ -1542,6 +1537,7 @@ static const TypeInfo pxa2xx_i2c_info = {
|
|||
.name = TYPE_PXA2XX_I2C,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(PXA2xxI2CState),
|
||||
.instance_init = pxa2xx_i2c_initfn,
|
||||
.class_init = pxa2xx_i2c_class_init,
|
||||
};
|
||||
|
||||
|
|
|
@ -310,17 +310,10 @@ static VMStateDescription vmstate_pxa2xx_pic_regs = {
|
|||
},
|
||||
};
|
||||
|
||||
static int pxa2xx_pic_initfn(SysBusDevice *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pxa2xx_pic_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
|
||||
|
||||
k->init = pxa2xx_pic_initfn;
|
||||
dc->desc = "PXA2xx PIC";
|
||||
dc->vmsd = &vmstate_pxa2xx_pic_regs;
|
||||
}
|
||||
|
|
121
hw/arm/sabrelite.c
Normal file
121
hw/arm/sabrelite.c
Normal file
|
@ -0,0 +1,121 @@
|
|||
/*
|
||||
* SABRELITE Board System emulation.
|
||||
*
|
||||
* Copyright (c) 2015 Jean-Christophe Dubois <jcd@tribudubois.net>
|
||||
*
|
||||
* This code is licensed under the GPL, version 2 or later.
|
||||
* See the file `COPYING' in the top level directory.
|
||||
*
|
||||
* It (partially) emulates a sabrelite board, with a Freescale
|
||||
* i.MX6 SoC
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu-common.h"
|
||||
#include "hw/arm/fsl-imx6.h"
|
||||
#include "hw/boards.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "sysemu/qtest.h"
|
||||
|
||||
typedef struct IMX6Sabrelite {
|
||||
FslIMX6State soc;
|
||||
MemoryRegion ram;
|
||||
} IMX6Sabrelite;
|
||||
|
||||
static struct arm_boot_info sabrelite_binfo = {
|
||||
/* DDR memory start */
|
||||
.loader_start = FSL_IMX6_MMDC_ADDR,
|
||||
/* No board ID, we boot from DT tree */
|
||||
.board_id = -1,
|
||||
};
|
||||
|
||||
/* No need to do any particular setup for secondary boot */
|
||||
static void sabrelite_write_secondary(ARMCPU *cpu,
|
||||
const struct arm_boot_info *info)
|
||||
{
|
||||
}
|
||||
|
||||
/* Secondary cores are reset through SRC device */
|
||||
static void sabrelite_reset_secondary(ARMCPU *cpu,
|
||||
const struct arm_boot_info *info)
|
||||
{
|
||||
}
|
||||
|
||||
static void sabrelite_init(MachineState *machine)
|
||||
{
|
||||
IMX6Sabrelite *s = g_new0(IMX6Sabrelite, 1);
|
||||
Error *err = NULL;
|
||||
|
||||
/* Check the amount of memory is compatible with the SOC */
|
||||
if (machine->ram_size > FSL_IMX6_MMDC_SIZE) {
|
||||
error_report("RAM size " RAM_ADDR_FMT " above max supported (%08x)",
|
||||
machine->ram_size, FSL_IMX6_MMDC_SIZE);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
object_initialize(&s->soc, sizeof(s->soc), TYPE_FSL_IMX6);
|
||||
object_property_add_child(OBJECT(machine), "soc", OBJECT(&s->soc),
|
||||
&error_abort);
|
||||
|
||||
object_property_set_bool(OBJECT(&s->soc), true, "realized", &err);
|
||||
if (err != NULL) {
|
||||
error_report("%s", error_get_pretty(err));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
memory_region_allocate_system_memory(&s->ram, NULL, "sabrelite.ram",
|
||||
machine->ram_size);
|
||||
memory_region_add_subregion(get_system_memory(), FSL_IMX6_MMDC_ADDR,
|
||||
&s->ram);
|
||||
|
||||
{
|
||||
/*
|
||||
* TODO: Ideally we would expose the chip select and spi bus on the
|
||||
* SoC object using alias properties; then we would not need to
|
||||
* directly access the underlying spi device object.
|
||||
*/
|
||||
/* Add the sst25vf016b NOR FLASH memory to first SPI */
|
||||
Object *spi_dev;
|
||||
|
||||
spi_dev = object_resolve_path_component(OBJECT(&s->soc), "spi1");
|
||||
if (spi_dev) {
|
||||
SSIBus *spi_bus;
|
||||
|
||||
spi_bus = (SSIBus *)qdev_get_child_bus(DEVICE(spi_dev), "spi");
|
||||
if (spi_bus) {
|
||||
DeviceState *flash_dev;
|
||||
|
||||
flash_dev = ssi_create_slave(spi_bus, "sst25vf016b");
|
||||
if (flash_dev) {
|
||||
qemu_irq cs_line = qdev_get_gpio_in_named(flash_dev,
|
||||
SSI_GPIO_CS, 0);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(spi_dev), 1, cs_line);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sabrelite_binfo.ram_size = machine->ram_size;
|
||||
sabrelite_binfo.kernel_filename = machine->kernel_filename;
|
||||
sabrelite_binfo.kernel_cmdline = machine->kernel_cmdline;
|
||||
sabrelite_binfo.initrd_filename = machine->initrd_filename;
|
||||
sabrelite_binfo.nb_cpus = smp_cpus;
|
||||
sabrelite_binfo.secure_boot = true;
|
||||
sabrelite_binfo.write_secondary_boot = sabrelite_write_secondary;
|
||||
sabrelite_binfo.secondary_cpu_reset_hook = sabrelite_reset_secondary;
|
||||
|
||||
if (!qtest_enabled()) {
|
||||
arm_load_kernel(&s->soc.cpu[0], &sabrelite_binfo);
|
||||
}
|
||||
}
|
||||
|
||||
static void sabrelite_machine_init(MachineClass *mc)
|
||||
{
|
||||
mc->desc = "Freescale i.MX6 Quad SABRE Lite Board (Cortex A9)";
|
||||
mc->init = sabrelite_init;
|
||||
mc->max_cpus = FSL_IMX6_NUM_CPUS;
|
||||
}
|
||||
|
||||
DEFINE_MACHINE("sabrelite", sabrelite_machine_init)
|
|
@ -164,9 +164,10 @@ static void sl_flash_register(PXA2xxState *cpu, int size)
|
|||
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, FLASH_BASE);
|
||||
}
|
||||
|
||||
static int sl_nand_init(SysBusDevice *dev)
|
||||
static void sl_nand_init(Object *obj)
|
||||
{
|
||||
SLNANDState *s = SL_NAND(dev);
|
||||
SLNANDState *s = SL_NAND(obj);
|
||||
SysBusDevice *dev = SYS_BUS_DEVICE(obj);
|
||||
DriveInfo *nand;
|
||||
|
||||
s->ctl = 0;
|
||||
|
@ -175,10 +176,8 @@ static int sl_nand_init(SysBusDevice *dev)
|
|||
s->nand = nand_init(nand ? blk_by_legacy_dinfo(nand) : NULL,
|
||||
s->manf_id, s->chip_id);
|
||||
|
||||
memory_region_init_io(&s->iomem, OBJECT(s), &sl_ops, s, "sl", 0x40);
|
||||
memory_region_init_io(&s->iomem, obj, &sl_ops, s, "sl", 0x40);
|
||||
sysbus_init_mmio(dev, &s->iomem);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Spitz Keyboard */
|
||||
|
@ -501,10 +500,10 @@ static void spitz_keyboard_register(PXA2xxState *cpu)
|
|||
qemu_add_kbd_event_handler(spitz_keyboard_handler, s);
|
||||
}
|
||||
|
||||
static int spitz_keyboard_init(SysBusDevice *sbd)
|
||||
static void spitz_keyboard_init(Object *obj)
|
||||
{
|
||||
DeviceState *dev = DEVICE(sbd);
|
||||
SpitzKeyboardState *s = SPITZ_KEYBOARD(dev);
|
||||
DeviceState *dev = DEVICE(obj);
|
||||
SpitzKeyboardState *s = SPITZ_KEYBOARD(obj);
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < 0x80; i ++)
|
||||
|
@ -519,8 +518,6 @@ static int spitz_keyboard_init(SysBusDevice *sbd)
|
|||
s->kbdtimer = timer_new_ns(QEMU_CLOCK_VIRTUAL, spitz_keyboard_tick, s);
|
||||
qdev_init_gpio_in(dev, spitz_keyboard_strobe, SPITZ_KEY_STROBE_NUM);
|
||||
qdev_init_gpio_out(dev, s->sense, SPITZ_KEY_SENSE_NUM);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* LCD backlight controller */
|
||||
|
@ -1065,9 +1062,7 @@ static Property sl_nand_properties[] = {
|
|||
static void sl_nand_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
|
||||
|
||||
k->init = sl_nand_init;
|
||||
dc->vmsd = &vmstate_sl_nand_info;
|
||||
dc->props = sl_nand_properties;
|
||||
/* Reason: init() method uses drive_get() */
|
||||
|
@ -1078,6 +1073,7 @@ static const TypeInfo sl_nand_info = {
|
|||
.name = TYPE_SL_NAND,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(SLNANDState),
|
||||
.instance_init = sl_nand_init,
|
||||
.class_init = sl_nand_class_init,
|
||||
};
|
||||
|
||||
|
@ -1097,9 +1093,7 @@ static VMStateDescription vmstate_spitz_kbd = {
|
|||
static void spitz_keyboard_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
|
||||
|
||||
k->init = spitz_keyboard_init;
|
||||
dc->vmsd = &vmstate_spitz_kbd;
|
||||
}
|
||||
|
||||
|
@ -1107,6 +1101,7 @@ static const TypeInfo spitz_keyboard_info = {
|
|||
.name = TYPE_SPITZ_KEYBOARD,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(SpitzKeyboardState),
|
||||
.instance_init = spitz_keyboard_init,
|
||||
.class_init = spitz_keyboard_class_init,
|
||||
};
|
||||
|
||||
|
|
|
@ -316,23 +316,22 @@ static const VMStateDescription vmstate_stellaris_gptm = {
|
|||
}
|
||||
};
|
||||
|
||||
static int stellaris_gptm_init(SysBusDevice *sbd)
|
||||
static void stellaris_gptm_init(Object *obj)
|
||||
{
|
||||
DeviceState *dev = DEVICE(sbd);
|
||||
gptm_state *s = STELLARIS_GPTM(dev);
|
||||
DeviceState *dev = DEVICE(obj);
|
||||
gptm_state *s = STELLARIS_GPTM(obj);
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
||||
|
||||
sysbus_init_irq(sbd, &s->irq);
|
||||
qdev_init_gpio_out(dev, &s->trigger, 1);
|
||||
|
||||
memory_region_init_io(&s->iomem, OBJECT(s), &gptm_ops, s,
|
||||
memory_region_init_io(&s->iomem, obj, &gptm_ops, s,
|
||||
"gptm", 0x1000);
|
||||
sysbus_init_mmio(sbd, &s->iomem);
|
||||
|
||||
s->opaque[0] = s->opaque[1] = s;
|
||||
s->timer[0] = timer_new_ns(QEMU_CLOCK_VIRTUAL, gptm_tick, &s->opaque[0]);
|
||||
s->timer[1] = timer_new_ns(QEMU_CLOCK_VIRTUAL, gptm_tick, &s->opaque[1]);
|
||||
vmstate_register(dev, -1, &vmstate_stellaris_gptm, s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
@ -873,23 +872,22 @@ static const VMStateDescription vmstate_stellaris_i2c = {
|
|||
}
|
||||
};
|
||||
|
||||
static int stellaris_i2c_init(SysBusDevice *sbd)
|
||||
static void stellaris_i2c_init(Object *obj)
|
||||
{
|
||||
DeviceState *dev = DEVICE(sbd);
|
||||
stellaris_i2c_state *s = STELLARIS_I2C(dev);
|
||||
DeviceState *dev = DEVICE(obj);
|
||||
stellaris_i2c_state *s = STELLARIS_I2C(obj);
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
||||
I2CBus *bus;
|
||||
|
||||
sysbus_init_irq(sbd, &s->irq);
|
||||
bus = i2c_init_bus(dev, "i2c");
|
||||
s->bus = bus;
|
||||
|
||||
memory_region_init_io(&s->iomem, OBJECT(s), &stellaris_i2c_ops, s,
|
||||
memory_region_init_io(&s->iomem, obj, &stellaris_i2c_ops, s,
|
||||
"i2c", 0x1000);
|
||||
sysbus_init_mmio(sbd, &s->iomem);
|
||||
/* ??? For now we only implement the master interface. */
|
||||
stellaris_i2c_reset(s);
|
||||
vmstate_register(dev, -1, &vmstate_stellaris_i2c, s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Analogue to Digital Converter. This is only partially implemented,
|
||||
|
@ -1160,23 +1158,22 @@ static const VMStateDescription vmstate_stellaris_adc = {
|
|||
}
|
||||
};
|
||||
|
||||
static int stellaris_adc_init(SysBusDevice *sbd)
|
||||
static void stellaris_adc_init(Object *obj)
|
||||
{
|
||||
DeviceState *dev = DEVICE(sbd);
|
||||
stellaris_adc_state *s = STELLARIS_ADC(dev);
|
||||
DeviceState *dev = DEVICE(obj);
|
||||
stellaris_adc_state *s = STELLARIS_ADC(obj);
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
||||
int n;
|
||||
|
||||
for (n = 0; n < 4; n++) {
|
||||
sysbus_init_irq(sbd, &s->irq[n]);
|
||||
}
|
||||
|
||||
memory_region_init_io(&s->iomem, OBJECT(s), &stellaris_adc_ops, s,
|
||||
memory_region_init_io(&s->iomem, obj, &stellaris_adc_ops, s,
|
||||
"adc", 0x1000);
|
||||
sysbus_init_mmio(sbd, &s->iomem);
|
||||
stellaris_adc_reset(s);
|
||||
qdev_init_gpio_in(dev, stellaris_adc_trigger, 1);
|
||||
vmstate_register(dev, -1, &vmstate_stellaris_adc, s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
|
@ -1425,43 +1422,46 @@ type_init(stellaris_machine_init)
|
|||
|
||||
static void stellaris_i2c_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
sdc->init = stellaris_i2c_init;
|
||||
dc->vmsd = &vmstate_stellaris_i2c;
|
||||
}
|
||||
|
||||
static const TypeInfo stellaris_i2c_info = {
|
||||
.name = TYPE_STELLARIS_I2C,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(stellaris_i2c_state),
|
||||
.instance_init = stellaris_i2c_init,
|
||||
.class_init = stellaris_i2c_class_init,
|
||||
};
|
||||
|
||||
static void stellaris_gptm_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
sdc->init = stellaris_gptm_init;
|
||||
dc->vmsd = &vmstate_stellaris_gptm;
|
||||
}
|
||||
|
||||
static const TypeInfo stellaris_gptm_info = {
|
||||
.name = TYPE_STELLARIS_GPTM,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(gptm_state),
|
||||
.instance_init = stellaris_gptm_init,
|
||||
.class_init = stellaris_gptm_class_init,
|
||||
};
|
||||
|
||||
static void stellaris_adc_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
sdc->init = stellaris_adc_init;
|
||||
dc->vmsd = &vmstate_stellaris_adc;
|
||||
}
|
||||
|
||||
static const TypeInfo stellaris_adc_info = {
|
||||
.name = TYPE_STELLARIS_ADC,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(stellaris_adc_state),
|
||||
.instance_init = stellaris_adc_init,
|
||||
.class_init = stellaris_adc_class_init,
|
||||
};
|
||||
|
||||
|
|
|
@ -179,19 +179,18 @@ static const MemoryRegionOps strongarm_pic_ops = {
|
|||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
static int strongarm_pic_initfn(SysBusDevice *sbd)
|
||||
static void strongarm_pic_initfn(Object *obj)
|
||||
{
|
||||
DeviceState *dev = DEVICE(sbd);
|
||||
StrongARMPICState *s = STRONGARM_PIC(dev);
|
||||
DeviceState *dev = DEVICE(obj);
|
||||
StrongARMPICState *s = STRONGARM_PIC(obj);
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
||||
|
||||
qdev_init_gpio_in(dev, strongarm_pic_set_irq, SA_PIC_SRCS);
|
||||
memory_region_init_io(&s->iomem, OBJECT(s), &strongarm_pic_ops, s,
|
||||
memory_region_init_io(&s->iomem, obj, &strongarm_pic_ops, s,
|
||||
"pic", 0x1000);
|
||||
sysbus_init_mmio(sbd, &s->iomem);
|
||||
sysbus_init_irq(sbd, &s->irq);
|
||||
sysbus_init_irq(sbd, &s->fiq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int strongarm_pic_post_load(void *opaque, int version_id)
|
||||
|
@ -217,9 +216,7 @@ static VMStateDescription vmstate_strongarm_pic_regs = {
|
|||
static void strongarm_pic_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
|
||||
|
||||
k->init = strongarm_pic_initfn;
|
||||
dc->desc = "StrongARM PIC";
|
||||
dc->vmsd = &vmstate_strongarm_pic_regs;
|
||||
}
|
||||
|
@ -228,6 +225,7 @@ static const TypeInfo strongarm_pic_info = {
|
|||
.name = TYPE_STRONGARM_PIC,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(StrongARMPICState),
|
||||
.instance_init = strongarm_pic_initfn,
|
||||
.class_init = strongarm_pic_class_init,
|
||||
};
|
||||
|
||||
|
@ -381,9 +379,10 @@ static const MemoryRegionOps strongarm_rtc_ops = {
|
|||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
static int strongarm_rtc_init(SysBusDevice *dev)
|
||||
static void strongarm_rtc_init(Object *obj)
|
||||
{
|
||||
StrongARMRTCState *s = STRONGARM_RTC(dev);
|
||||
StrongARMRTCState *s = STRONGARM_RTC(obj);
|
||||
SysBusDevice *dev = SYS_BUS_DEVICE(obj);
|
||||
struct tm tm;
|
||||
|
||||
s->rttr = 0x0;
|
||||
|
@ -400,11 +399,9 @@ static int strongarm_rtc_init(SysBusDevice *dev)
|
|||
sysbus_init_irq(dev, &s->rtc_irq);
|
||||
sysbus_init_irq(dev, &s->rtc_hz_irq);
|
||||
|
||||
memory_region_init_io(&s->iomem, OBJECT(s), &strongarm_rtc_ops, s,
|
||||
memory_region_init_io(&s->iomem, obj, &strongarm_rtc_ops, s,
|
||||
"rtc", 0x10000);
|
||||
sysbus_init_mmio(dev, &s->iomem);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void strongarm_rtc_pre_save(void *opaque)
|
||||
|
@ -443,9 +440,7 @@ static const VMStateDescription vmstate_strongarm_rtc_regs = {
|
|||
static void strongarm_rtc_sysbus_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
|
||||
|
||||
k->init = strongarm_rtc_init;
|
||||
dc->desc = "StrongARM RTC Controller";
|
||||
dc->vmsd = &vmstate_strongarm_rtc_regs;
|
||||
}
|
||||
|
@ -454,6 +449,7 @@ static const TypeInfo strongarm_rtc_sysbus_info = {
|
|||
.name = TYPE_STRONGARM_RTC,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(StrongARMRTCState),
|
||||
.instance_init = strongarm_rtc_init,
|
||||
.class_init = strongarm_rtc_sysbus_class_init,
|
||||
};
|
||||
|
||||
|
@ -646,16 +642,17 @@ static DeviceState *strongarm_gpio_init(hwaddr base,
|
|||
return dev;
|
||||
}
|
||||
|
||||
static int strongarm_gpio_initfn(SysBusDevice *sbd)
|
||||
static void strongarm_gpio_initfn(Object *obj)
|
||||
{
|
||||
DeviceState *dev = DEVICE(sbd);
|
||||
StrongARMGPIOInfo *s = STRONGARM_GPIO(dev);
|
||||
DeviceState *dev = DEVICE(obj);
|
||||
StrongARMGPIOInfo *s = STRONGARM_GPIO(obj);
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
||||
int i;
|
||||
|
||||
qdev_init_gpio_in(dev, strongarm_gpio_set, 28);
|
||||
qdev_init_gpio_out(dev, s->handler, 28);
|
||||
|
||||
memory_region_init_io(&s->iomem, OBJECT(s), &strongarm_gpio_ops, s,
|
||||
memory_region_init_io(&s->iomem, obj, &strongarm_gpio_ops, s,
|
||||
"gpio", 0x1000);
|
||||
|
||||
sysbus_init_mmio(sbd, &s->iomem);
|
||||
|
@ -663,8 +660,6 @@ static int strongarm_gpio_initfn(SysBusDevice *sbd)
|
|||
sysbus_init_irq(sbd, &s->irqs[i]);
|
||||
}
|
||||
sysbus_init_irq(sbd, &s->irqX);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_strongarm_gpio_regs = {
|
||||
|
@ -687,9 +682,7 @@ static const VMStateDescription vmstate_strongarm_gpio_regs = {
|
|||
static void strongarm_gpio_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
|
||||
|
||||
k->init = strongarm_gpio_initfn;
|
||||
dc->desc = "StrongARM GPIO controller";
|
||||
dc->vmsd = &vmstate_strongarm_gpio_regs;
|
||||
}
|
||||
|
@ -698,6 +691,7 @@ static const TypeInfo strongarm_gpio_info = {
|
|||
.name = TYPE_STRONGARM_GPIO,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(StrongARMGPIOInfo),
|
||||
.instance_init = strongarm_gpio_initfn,
|
||||
.class_init = strongarm_gpio_class_init,
|
||||
};
|
||||
|
||||
|
@ -824,20 +818,19 @@ static const MemoryRegionOps strongarm_ppc_ops = {
|
|||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
static int strongarm_ppc_init(SysBusDevice *sbd)
|
||||
static void strongarm_ppc_init(Object *obj)
|
||||
{
|
||||
DeviceState *dev = DEVICE(sbd);
|
||||
StrongARMPPCInfo *s = STRONGARM_PPC(dev);
|
||||
DeviceState *dev = DEVICE(obj);
|
||||
StrongARMPPCInfo *s = STRONGARM_PPC(obj);
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
||||
|
||||
qdev_init_gpio_in(dev, strongarm_ppc_set, 22);
|
||||
qdev_init_gpio_out(dev, s->handler, 22);
|
||||
|
||||
memory_region_init_io(&s->iomem, OBJECT(s), &strongarm_ppc_ops, s,
|
||||
memory_region_init_io(&s->iomem, obj, &strongarm_ppc_ops, s,
|
||||
"ppc", 0x1000);
|
||||
|
||||
sysbus_init_mmio(sbd, &s->iomem);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_strongarm_ppc_regs = {
|
||||
|
@ -859,9 +852,7 @@ static const VMStateDescription vmstate_strongarm_ppc_regs = {
|
|||
static void strongarm_ppc_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
|
||||
|
||||
k->init = strongarm_ppc_init;
|
||||
dc->desc = "StrongARM PPC controller";
|
||||
dc->vmsd = &vmstate_strongarm_ppc_regs;
|
||||
}
|
||||
|
@ -870,6 +861,7 @@ static const TypeInfo strongarm_ppc_info = {
|
|||
.name = TYPE_STRONGARM_PPC,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(StrongARMPPCInfo),
|
||||
.instance_init = strongarm_ppc_init,
|
||||
.class_init = strongarm_ppc_class_init,
|
||||
};
|
||||
|
||||
|
@ -1231,11 +1223,12 @@ static const MemoryRegionOps strongarm_uart_ops = {
|
|||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
static int strongarm_uart_init(SysBusDevice *dev)
|
||||
static void strongarm_uart_init(Object *obj)
|
||||
{
|
||||
StrongARMUARTState *s = STRONGARM_UART(dev);
|
||||
StrongARMUARTState *s = STRONGARM_UART(obj);
|
||||
SysBusDevice *dev = SYS_BUS_DEVICE(obj);
|
||||
|
||||
memory_region_init_io(&s->iomem, OBJECT(s), &strongarm_uart_ops, s,
|
||||
memory_region_init_io(&s->iomem, obj, &strongarm_uart_ops, s,
|
||||
"uart", 0x10000);
|
||||
sysbus_init_mmio(dev, &s->iomem);
|
||||
sysbus_init_irq(dev, &s->irq);
|
||||
|
@ -1250,8 +1243,6 @@ static int strongarm_uart_init(SysBusDevice *dev)
|
|||
strongarm_uart_event,
|
||||
s);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void strongarm_uart_reset(DeviceState *dev)
|
||||
|
@ -1321,9 +1312,7 @@ static Property strongarm_uart_properties[] = {
|
|||
static void strongarm_uart_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
|
||||
|
||||
k->init = strongarm_uart_init;
|
||||
dc->desc = "StrongARM UART controller";
|
||||
dc->reset = strongarm_uart_reset;
|
||||
dc->vmsd = &vmstate_strongarm_uart_regs;
|
||||
|
@ -1334,6 +1323,7 @@ static const TypeInfo strongarm_uart_info = {
|
|||
.name = TYPE_STRONGARM_UART,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(StrongARMUARTState),
|
||||
.instance_init = strongarm_uart_init,
|
||||
.class_init = strongarm_uart_class_init,
|
||||
};
|
||||
|
||||
|
|
|
@ -153,10 +153,11 @@ static const MemoryRegionOps vpb_sic_ops = {
|
|||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
static int vpb_sic_init(SysBusDevice *sbd)
|
||||
static void vpb_sic_init(Object *obj)
|
||||
{
|
||||
DeviceState *dev = DEVICE(sbd);
|
||||
vpb_sic_state *s = VERSATILE_PB_SIC(dev);
|
||||
DeviceState *dev = DEVICE(obj);
|
||||
vpb_sic_state *s = VERSATILE_PB_SIC(obj);
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
||||
int i;
|
||||
|
||||
qdev_init_gpio_in(dev, vpb_sic_set_irq, 32);
|
||||
|
@ -164,10 +165,9 @@ static int vpb_sic_init(SysBusDevice *sbd)
|
|||
sysbus_init_irq(sbd, &s->parent[i]);
|
||||
}
|
||||
s->irq = 31;
|
||||
memory_region_init_io(&s->iomem, OBJECT(s), &vpb_sic_ops, s,
|
||||
memory_region_init_io(&s->iomem, obj, &vpb_sic_ops, s,
|
||||
"vpb-sic", 0x1000);
|
||||
sysbus_init_mmio(sbd, &s->iomem);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Board init. */
|
||||
|
@ -427,9 +427,7 @@ type_init(versatile_machine_init)
|
|||
static void vpb_sic_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
|
||||
|
||||
k->init = vpb_sic_init;
|
||||
dc->vmsd = &vmstate_vpb_sic;
|
||||
}
|
||||
|
||||
|
@ -437,6 +435,7 @@ static const TypeInfo vpb_sic_info = {
|
|||
.name = TYPE_VERSATILE_PB_SIC,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(vpb_sic_state),
|
||||
.instance_init = vpb_sic_init,
|
||||
.class_init = vpb_sic_class_init,
|
||||
};
|
||||
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
#include "hw/acpi/aml-build.h"
|
||||
#include "hw/pci/pcie_host.h"
|
||||
#include "hw/pci/pci.h"
|
||||
#include "sysemu/numa.h"
|
||||
|
||||
#define ARM_SPI_BASE 32
|
||||
#define ACPI_POWER_BUTTON_DEVICE "PWRB"
|
||||
|
@ -413,6 +414,52 @@ build_spcr(GArray *table_data, GArray *linker, VirtGuestInfo *guest_info)
|
|||
NULL, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
build_srat(GArray *table_data, GArray *linker, VirtGuestInfo *guest_info)
|
||||
{
|
||||
AcpiSystemResourceAffinityTable *srat;
|
||||
AcpiSratProcessorGiccAffinity *core;
|
||||
AcpiSratMemoryAffinity *numamem;
|
||||
int i, j, srat_start;
|
||||
uint64_t mem_base;
|
||||
uint32_t *cpu_node = g_malloc0(guest_info->smp_cpus * sizeof(uint32_t));
|
||||
|
||||
for (i = 0; i < guest_info->smp_cpus; i++) {
|
||||
for (j = 0; j < nb_numa_nodes; j++) {
|
||||
if (test_bit(i, numa_info[j].node_cpu)) {
|
||||
cpu_node[i] = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
srat_start = table_data->len;
|
||||
srat = acpi_data_push(table_data, sizeof(*srat));
|
||||
srat->reserved1 = cpu_to_le32(1);
|
||||
|
||||
for (i = 0; i < guest_info->smp_cpus; ++i) {
|
||||
core = acpi_data_push(table_data, sizeof(*core));
|
||||
core->type = ACPI_SRAT_PROCESSOR_GICC;
|
||||
core->length = sizeof(*core);
|
||||
core->proximity = cpu_to_le32(cpu_node[i]);
|
||||
core->acpi_processor_uid = cpu_to_le32(i);
|
||||
core->flags = cpu_to_le32(1);
|
||||
}
|
||||
g_free(cpu_node);
|
||||
|
||||
mem_base = guest_info->memmap[VIRT_MEM].base;
|
||||
for (i = 0; i < nb_numa_nodes; ++i) {
|
||||
numamem = acpi_data_push(table_data, sizeof(*numamem));
|
||||
build_srat_memory(numamem, mem_base, numa_info[i].node_mem, i,
|
||||
MEM_AFFINITY_ENABLED);
|
||||
mem_base += numa_info[i].node_mem;
|
||||
}
|
||||
|
||||
build_header(linker, table_data,
|
||||
(void *)(table_data->data + srat_start), "SRAT",
|
||||
table_data->len - srat_start, 3, NULL, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
build_mcfg(GArray *table_data, GArray *linker, VirtGuestInfo *guest_info)
|
||||
{
|
||||
|
@ -638,6 +685,11 @@ void virt_acpi_build(VirtGuestInfo *guest_info, AcpiBuildTables *tables)
|
|||
acpi_add_table(table_offsets, tables_blob);
|
||||
build_spcr(tables_blob, tables->linker, guest_info);
|
||||
|
||||
if (nb_numa_nodes > 0) {
|
||||
acpi_add_table(table_offsets, tables_blob);
|
||||
build_srat(tables_blob, tables->linker, guest_info);
|
||||
}
|
||||
|
||||
/* RSDT is pointed to by RSDP */
|
||||
rsdt = tables_blob->len;
|
||||
build_rsdt(tables_blob, tables->linker, table_offsets, NULL, NULL);
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
#include "net/net.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "sysemu/device_tree.h"
|
||||
#include "sysemu/numa.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "sysemu/kvm.h"
|
||||
#include "hw/boards.h"
|
||||
|
@ -329,6 +330,7 @@ static void fdt_add_cpu_nodes(const VirtBoardInfo *vbi)
|
|||
{
|
||||
int cpu;
|
||||
int addr_cells = 1;
|
||||
unsigned int i;
|
||||
|
||||
/*
|
||||
* From Documentation/devicetree/bindings/arm/cpus.txt
|
||||
|
@ -378,6 +380,12 @@ static void fdt_add_cpu_nodes(const VirtBoardInfo *vbi)
|
|||
armcpu->mp_affinity);
|
||||
}
|
||||
|
||||
for (i = 0; i < nb_numa_nodes; i++) {
|
||||
if (test_bit(cpu, numa_info[i].node_cpu)) {
|
||||
qemu_fdt_setprop_cell(vbi->fdt, nodename, "numa-node-id", i);
|
||||
}
|
||||
}
|
||||
|
||||
g_free(nodename);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -925,16 +925,83 @@ static void blizzard_update_display(void *opaque)
|
|||
s->my[1] = 0;
|
||||
}
|
||||
|
||||
#define DEPTH 8
|
||||
#include "blizzard_template.h"
|
||||
#define DEPTH 15
|
||||
#include "blizzard_template.h"
|
||||
#define DEPTH 16
|
||||
#include "blizzard_template.h"
|
||||
#define DEPTH 24
|
||||
#include "blizzard_template.h"
|
||||
#define DEPTH 32
|
||||
#include "blizzard_template.h"
|
||||
static void blizzard_draw_line16_32(uint32_t *dest,
|
||||
const uint16_t *src, unsigned int width)
|
||||
{
|
||||
uint16_t data;
|
||||
unsigned int r, g, b;
|
||||
const uint16_t *end = (const void *) src + width;
|
||||
while (src < end) {
|
||||
data = *src ++;
|
||||
b = (data & 0x1f) << 3;
|
||||
data >>= 5;
|
||||
g = (data & 0x3f) << 2;
|
||||
data >>= 6;
|
||||
r = (data & 0x1f) << 3;
|
||||
data >>= 5;
|
||||
*dest++ = rgb_to_pixel32(r, g, b);
|
||||
}
|
||||
}
|
||||
|
||||
static void blizzard_draw_line24mode1_32(uint32_t *dest,
|
||||
const uint8_t *src, unsigned int width)
|
||||
{
|
||||
/* TODO: check if SDL 24-bit planes are not in the same format and
|
||||
* if so, use memcpy */
|
||||
unsigned int r[2], g[2], b[2];
|
||||
const uint8_t *end = src + width;
|
||||
while (src < end) {
|
||||
g[0] = *src ++;
|
||||
r[0] = *src ++;
|
||||
r[1] = *src ++;
|
||||
b[0] = *src ++;
|
||||
*dest++ = rgb_to_pixel32(r[0], g[0], b[0]);
|
||||
b[1] = *src ++;
|
||||
g[1] = *src ++;
|
||||
*dest++ = rgb_to_pixel32(r[1], g[1], b[1]);
|
||||
}
|
||||
}
|
||||
|
||||
static void blizzard_draw_line24mode2_32(uint32_t *dest,
|
||||
const uint8_t *src, unsigned int width)
|
||||
{
|
||||
unsigned int r, g, b;
|
||||
const uint8_t *end = src + width;
|
||||
while (src < end) {
|
||||
r = *src ++;
|
||||
src ++;
|
||||
b = *src ++;
|
||||
g = *src ++;
|
||||
*dest++ = rgb_to_pixel32(r, g, b);
|
||||
}
|
||||
}
|
||||
|
||||
/* No rotation */
|
||||
static blizzard_fn_t blizzard_draw_fn_32[0x10] = {
|
||||
NULL,
|
||||
/* RGB 5:6:5*/
|
||||
(blizzard_fn_t) blizzard_draw_line16_32,
|
||||
/* RGB 6:6:6 mode 1 */
|
||||
(blizzard_fn_t) blizzard_draw_line24mode1_32,
|
||||
/* RGB 8:8:8 mode 1 */
|
||||
(blizzard_fn_t) blizzard_draw_line24mode1_32,
|
||||
NULL, NULL,
|
||||
/* RGB 6:6:6 mode 2 */
|
||||
(blizzard_fn_t) blizzard_draw_line24mode2_32,
|
||||
/* RGB 8:8:8 mode 2 */
|
||||
(blizzard_fn_t) blizzard_draw_line24mode2_32,
|
||||
/* YUV 4:2:2 */
|
||||
NULL,
|
||||
/* YUV 4:2:0 */
|
||||
NULL,
|
||||
NULL, NULL, NULL, NULL, NULL, NULL,
|
||||
};
|
||||
|
||||
/* 90deg, 180deg and 270deg rotation */
|
||||
static blizzard_fn_t blizzard_draw_fn_r_32[0x10] = {
|
||||
/* TODO */
|
||||
[0 ... 0xf] = NULL,
|
||||
};
|
||||
|
||||
static const GraphicHwOps blizzard_ops = {
|
||||
.invalidate = blizzard_invalidate_display,
|
||||
|
@ -951,35 +1018,10 @@ void *s1d13745_init(qemu_irq gpio_int)
|
|||
s->con = graphic_console_init(NULL, 0, &blizzard_ops, s);
|
||||
surface = qemu_console_surface(s->con);
|
||||
|
||||
switch (surface_bits_per_pixel(surface)) {
|
||||
case 0:
|
||||
s->line_fn_tab[0] = s->line_fn_tab[1] =
|
||||
g_malloc0(sizeof(blizzard_fn_t) * 0x10);
|
||||
break;
|
||||
case 8:
|
||||
s->line_fn_tab[0] = blizzard_draw_fn_8;
|
||||
s->line_fn_tab[1] = blizzard_draw_fn_r_8;
|
||||
break;
|
||||
case 15:
|
||||
s->line_fn_tab[0] = blizzard_draw_fn_15;
|
||||
s->line_fn_tab[1] = blizzard_draw_fn_r_15;
|
||||
break;
|
||||
case 16:
|
||||
s->line_fn_tab[0] = blizzard_draw_fn_16;
|
||||
s->line_fn_tab[1] = blizzard_draw_fn_r_16;
|
||||
break;
|
||||
case 24:
|
||||
s->line_fn_tab[0] = blizzard_draw_fn_24;
|
||||
s->line_fn_tab[1] = blizzard_draw_fn_r_24;
|
||||
break;
|
||||
case 32:
|
||||
s->line_fn_tab[0] = blizzard_draw_fn_32;
|
||||
s->line_fn_tab[1] = blizzard_draw_fn_r_32;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "%s: Bad color depth\n", __FUNCTION__);
|
||||
exit(1);
|
||||
}
|
||||
assert(surface_bits_per_pixel(surface) == 32);
|
||||
|
||||
s->line_fn_tab[0] = blizzard_draw_fn_32;
|
||||
s->line_fn_tab[1] = blizzard_draw_fn_r_32;
|
||||
|
||||
blizzard_reset(s);
|
||||
|
||||
|
|
|
@ -1,146 +0,0 @@
|
|||
/*
|
||||
* QEMU Epson S1D13744/S1D13745 templates
|
||||
*
|
||||
* Copyright (C) 2008 Nokia Corporation
|
||||
* Written by Andrzej Zaborowski <andrew@openedhand.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 or
|
||||
* (at your option) version 3 of the License.
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#define SKIP_PIXEL(to) (to += deststep)
|
||||
#if DEPTH == 8
|
||||
# define PIXEL_TYPE uint8_t
|
||||
# define COPY_PIXEL(to, from) do { *to = from; SKIP_PIXEL(to); } while (0)
|
||||
# define COPY_PIXEL1(to, from) (*to++ = from)
|
||||
#elif DEPTH == 15 || DEPTH == 16
|
||||
# define PIXEL_TYPE uint16_t
|
||||
# define COPY_PIXEL(to, from) do { *to = from; SKIP_PIXEL(to); } while (0)
|
||||
# define COPY_PIXEL1(to, from) (*to++ = from)
|
||||
#elif DEPTH == 24
|
||||
# define PIXEL_TYPE uint8_t
|
||||
# define COPY_PIXEL(to, from) \
|
||||
do { \
|
||||
to[0] = from; \
|
||||
to[1] = (from) >> 8; \
|
||||
to[2] = (from) >> 16; \
|
||||
SKIP_PIXEL(to); \
|
||||
} while (0)
|
||||
|
||||
# define COPY_PIXEL1(to, from) \
|
||||
do { \
|
||||
*to++ = from; \
|
||||
*to++ = (from) >> 8; \
|
||||
*to++ = (from) >> 16; \
|
||||
} while (0)
|
||||
#elif DEPTH == 32
|
||||
# define PIXEL_TYPE uint32_t
|
||||
# define COPY_PIXEL(to, from) do { *to = from; SKIP_PIXEL(to); } while (0)
|
||||
# define COPY_PIXEL1(to, from) (*to++ = from)
|
||||
#else
|
||||
# error unknown bit depth
|
||||
#endif
|
||||
|
||||
#ifdef HOST_WORDS_BIGENDIAN
|
||||
# define SWAP_WORDS 1
|
||||
#endif
|
||||
|
||||
static void glue(blizzard_draw_line16_, DEPTH)(PIXEL_TYPE *dest,
|
||||
const uint16_t *src, unsigned int width)
|
||||
{
|
||||
#if !defined(SWAP_WORDS) && DEPTH == 16
|
||||
memcpy(dest, src, width);
|
||||
#else
|
||||
uint16_t data;
|
||||
unsigned int r, g, b;
|
||||
const uint16_t *end = (const void *) src + width;
|
||||
while (src < end) {
|
||||
data = *src ++;
|
||||
b = (data & 0x1f) << 3;
|
||||
data >>= 5;
|
||||
g = (data & 0x3f) << 2;
|
||||
data >>= 6;
|
||||
r = (data & 0x1f) << 3;
|
||||
data >>= 5;
|
||||
COPY_PIXEL1(dest, glue(rgb_to_pixel, DEPTH)(r, g, b));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void glue(blizzard_draw_line24mode1_, DEPTH)(PIXEL_TYPE *dest,
|
||||
const uint8_t *src, unsigned int width)
|
||||
{
|
||||
/* TODO: check if SDL 24-bit planes are not in the same format and
|
||||
* if so, use memcpy */
|
||||
unsigned int r[2], g[2], b[2];
|
||||
const uint8_t *end = src + width;
|
||||
while (src < end) {
|
||||
g[0] = *src ++;
|
||||
r[0] = *src ++;
|
||||
r[1] = *src ++;
|
||||
b[0] = *src ++;
|
||||
COPY_PIXEL1(dest, glue(rgb_to_pixel, DEPTH)(r[0], g[0], b[0]));
|
||||
b[1] = *src ++;
|
||||
g[1] = *src ++;
|
||||
COPY_PIXEL1(dest, glue(rgb_to_pixel, DEPTH)(r[1], g[1], b[1]));
|
||||
}
|
||||
}
|
||||
|
||||
static void glue(blizzard_draw_line24mode2_, DEPTH)(PIXEL_TYPE *dest,
|
||||
const uint8_t *src, unsigned int width)
|
||||
{
|
||||
unsigned int r, g, b;
|
||||
const uint8_t *end = src + width;
|
||||
while (src < end) {
|
||||
r = *src ++;
|
||||
src ++;
|
||||
b = *src ++;
|
||||
g = *src ++;
|
||||
COPY_PIXEL1(dest, glue(rgb_to_pixel, DEPTH)(r, g, b));
|
||||
}
|
||||
}
|
||||
|
||||
/* No rotation */
|
||||
static blizzard_fn_t glue(blizzard_draw_fn_, DEPTH)[0x10] = {
|
||||
NULL,
|
||||
/* RGB 5:6:5*/
|
||||
(blizzard_fn_t) glue(blizzard_draw_line16_, DEPTH),
|
||||
/* RGB 6:6:6 mode 1 */
|
||||
(blizzard_fn_t) glue(blizzard_draw_line24mode1_, DEPTH),
|
||||
/* RGB 8:8:8 mode 1 */
|
||||
(blizzard_fn_t) glue(blizzard_draw_line24mode1_, DEPTH),
|
||||
NULL, NULL,
|
||||
/* RGB 6:6:6 mode 2 */
|
||||
(blizzard_fn_t) glue(blizzard_draw_line24mode2_, DEPTH),
|
||||
/* RGB 8:8:8 mode 2 */
|
||||
(blizzard_fn_t) glue(blizzard_draw_line24mode2_, DEPTH),
|
||||
/* YUV 4:2:2 */
|
||||
NULL,
|
||||
/* YUV 4:2:0 */
|
||||
NULL,
|
||||
NULL, NULL, NULL, NULL, NULL, NULL,
|
||||
};
|
||||
|
||||
/* 90deg, 180deg and 270deg rotation */
|
||||
static blizzard_fn_t glue(blizzard_draw_fn_r_, DEPTH)[0x10] = {
|
||||
/* TODO */
|
||||
[0 ... 0xf] = NULL,
|
||||
};
|
||||
|
||||
#undef DEPTH
|
||||
#undef SKIP_PIXEL
|
||||
#undef COPY_PIXEL
|
||||
#undef COPY_PIXEL1
|
||||
#undef PIXEL_TYPE
|
||||
|
||||
#undef SWAP_WORDS
|
|
@ -1909,9 +1909,10 @@ static const GraphicHwOps exynos4210_fimd_ops = {
|
|||
.gfx_update = exynos4210_fimd_update,
|
||||
};
|
||||
|
||||
static int exynos4210_fimd_init(SysBusDevice *dev)
|
||||
static void exynos4210_fimd_init(Object *obj)
|
||||
{
|
||||
Exynos4210fimdState *s = EXYNOS4210_FIMD(dev);
|
||||
Exynos4210fimdState *s = EXYNOS4210_FIMD(obj);
|
||||
SysBusDevice *dev = SYS_BUS_DEVICE(obj);
|
||||
|
||||
s->ifb = NULL;
|
||||
|
||||
|
@ -1919,28 +1920,32 @@ static int exynos4210_fimd_init(SysBusDevice *dev)
|
|||
sysbus_init_irq(dev, &s->irq[1]);
|
||||
sysbus_init_irq(dev, &s->irq[2]);
|
||||
|
||||
memory_region_init_io(&s->iomem, OBJECT(s), &exynos4210_fimd_mmio_ops, s,
|
||||
memory_region_init_io(&s->iomem, obj, &exynos4210_fimd_mmio_ops, s,
|
||||
"exynos4210.fimd", FIMD_REGS_SIZE);
|
||||
sysbus_init_mmio(dev, &s->iomem);
|
||||
s->console = graphic_console_init(DEVICE(dev), 0, &exynos4210_fimd_ops, s);
|
||||
}
|
||||
|
||||
return 0;
|
||||
static void exynos4210_fimd_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
Exynos4210fimdState *s = EXYNOS4210_FIMD(dev);
|
||||
|
||||
s->console = graphic_console_init(dev, 0, &exynos4210_fimd_ops, s);
|
||||
}
|
||||
|
||||
static void exynos4210_fimd_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
|
||||
|
||||
dc->vmsd = &exynos4210_fimd_vmstate;
|
||||
dc->reset = exynos4210_fimd_reset;
|
||||
k->init = exynos4210_fimd_init;
|
||||
dc->realize = exynos4210_fimd_realize;
|
||||
}
|
||||
|
||||
static const TypeInfo exynos4210_fimd_info = {
|
||||
.name = TYPE_EXYNOS4210_FIMD,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(Exynos4210fimdState),
|
||||
.instance_init = exynos4210_fimd_init,
|
||||
.class_init = exynos4210_fimd_class_init,
|
||||
};
|
||||
|
||||
|
|
|
@ -27,13 +27,7 @@
|
|||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#if DEPTH == 8
|
||||
# define BPP 1
|
||||
# define PIXEL_TYPE uint8_t
|
||||
#elif DEPTH == 15 || DEPTH == 16
|
||||
# define BPP 2
|
||||
# define PIXEL_TYPE uint16_t
|
||||
#elif DEPTH == 32
|
||||
#if DEPTH == 32
|
||||
# define BPP 4
|
||||
# define PIXEL_TYPE uint32_t
|
||||
#else
|
||||
|
@ -152,7 +146,7 @@ static void glue(draw_line12_, DEPTH)(void *opaque,
|
|||
static void glue(draw_line16_, DEPTH)(void *opaque,
|
||||
uint8_t *d, const uint8_t *s, int width, int deststep)
|
||||
{
|
||||
#if DEPTH == 16 && defined(HOST_WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
|
||||
#if defined(HOST_WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
|
||||
memcpy(d, s, width * 2);
|
||||
#else
|
||||
uint16_t v;
|
||||
|
|
|
@ -71,47 +71,9 @@ static void omap_lcd_interrupts(struct omap_lcd_panel_s *s)
|
|||
|
||||
#define draw_line_func drawfn
|
||||
|
||||
#define DEPTH 8
|
||||
#include "omap_lcd_template.h"
|
||||
#define DEPTH 15
|
||||
#include "omap_lcd_template.h"
|
||||
#define DEPTH 16
|
||||
#include "omap_lcd_template.h"
|
||||
#define DEPTH 32
|
||||
#include "omap_lcd_template.h"
|
||||
|
||||
static draw_line_func draw_line_table2[33] = {
|
||||
[0 ... 32] = NULL,
|
||||
[8] = draw_line2_8,
|
||||
[15] = draw_line2_15,
|
||||
[16] = draw_line2_16,
|
||||
[32] = draw_line2_32,
|
||||
}, draw_line_table4[33] = {
|
||||
[0 ... 32] = NULL,
|
||||
[8] = draw_line4_8,
|
||||
[15] = draw_line4_15,
|
||||
[16] = draw_line4_16,
|
||||
[32] = draw_line4_32,
|
||||
}, draw_line_table8[33] = {
|
||||
[0 ... 32] = NULL,
|
||||
[8] = draw_line8_8,
|
||||
[15] = draw_line8_15,
|
||||
[16] = draw_line8_16,
|
||||
[32] = draw_line8_32,
|
||||
}, draw_line_table12[33] = {
|
||||
[0 ... 32] = NULL,
|
||||
[8] = draw_line12_8,
|
||||
[15] = draw_line12_15,
|
||||
[16] = draw_line12_16,
|
||||
[32] = draw_line12_32,
|
||||
}, draw_line_table16[33] = {
|
||||
[0 ... 32] = NULL,
|
||||
[8] = draw_line16_8,
|
||||
[15] = draw_line16_15,
|
||||
[16] = draw_line16_16,
|
||||
[32] = draw_line16_32,
|
||||
};
|
||||
|
||||
static void omap_update_display(void *opaque)
|
||||
{
|
||||
struct omap_lcd_panel_s *omap_lcd = (struct omap_lcd_panel_s *) opaque;
|
||||
|
@ -143,25 +105,25 @@ static void omap_update_display(void *opaque)
|
|||
/* Colour depth */
|
||||
switch ((omap_lcd->palette[0] >> 12) & 7) {
|
||||
case 1:
|
||||
draw_line = draw_line_table2[surface_bits_per_pixel(surface)];
|
||||
draw_line = draw_line2_32;
|
||||
bpp = 2;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
draw_line = draw_line_table4[surface_bits_per_pixel(surface)];
|
||||
draw_line = draw_line4_32;
|
||||
bpp = 4;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
draw_line = draw_line_table8[surface_bits_per_pixel(surface)];
|
||||
draw_line = draw_line8_32;
|
||||
bpp = 8;
|
||||
break;
|
||||
|
||||
case 4 ... 7:
|
||||
if (!omap_lcd->tft)
|
||||
draw_line = draw_line_table12[surface_bits_per_pixel(surface)];
|
||||
draw_line = draw_line12_32;
|
||||
else
|
||||
draw_line = draw_line_table16[surface_bits_per_pixel(surface)];
|
||||
draw_line = draw_line16_32;
|
||||
bpp = 16;
|
||||
break;
|
||||
|
||||
|
|
|
@ -2427,26 +2427,6 @@ build_tpm2(GArray *table_data, GArray *linker)
|
|||
(void *)tpm2_ptr, "TPM2", sizeof(*tpm2_ptr), 4, NULL, NULL);
|
||||
}
|
||||
|
||||
typedef enum {
|
||||
MEM_AFFINITY_NOFLAGS = 0,
|
||||
MEM_AFFINITY_ENABLED = (1 << 0),
|
||||
MEM_AFFINITY_HOTPLUGGABLE = (1 << 1),
|
||||
MEM_AFFINITY_NON_VOLATILE = (1 << 2),
|
||||
} MemoryAffinityFlags;
|
||||
|
||||
static void
|
||||
acpi_build_srat_memory(AcpiSratMemoryAffinity *numamem, uint64_t base,
|
||||
uint64_t len, int node, MemoryAffinityFlags flags)
|
||||
{
|
||||
numamem->type = ACPI_SRAT_MEMORY;
|
||||
numamem->length = sizeof(*numamem);
|
||||
memset(numamem->proximity, 0, 4);
|
||||
numamem->proximity[0] = node;
|
||||
numamem->flags = cpu_to_le32(flags);
|
||||
numamem->base_addr = cpu_to_le64(base);
|
||||
numamem->range_length = cpu_to_le64(len);
|
||||
}
|
||||
|
||||
static void
|
||||
build_srat(GArray *table_data, GArray *linker, MachineState *machine)
|
||||
{
|
||||
|
@ -2474,7 +2454,7 @@ build_srat(GArray *table_data, GArray *linker, MachineState *machine)
|
|||
int apic_id = apic_ids->cpus[i].arch_id;
|
||||
|
||||
core = acpi_data_push(table_data, sizeof *core);
|
||||
core->type = ACPI_SRAT_PROCESSOR;
|
||||
core->type = ACPI_SRAT_PROCESSOR_APIC;
|
||||
core->length = sizeof(*core);
|
||||
core->local_apic_id = apic_id;
|
||||
curnode = pcms->node_cpu[apic_id];
|
||||
|
@ -2492,7 +2472,7 @@ build_srat(GArray *table_data, GArray *linker, MachineState *machine)
|
|||
numa_start = table_data->len;
|
||||
|
||||
numamem = acpi_data_push(table_data, sizeof *numamem);
|
||||
acpi_build_srat_memory(numamem, 0, 640*1024, 0, MEM_AFFINITY_ENABLED);
|
||||
build_srat_memory(numamem, 0, 640 * 1024, 0, MEM_AFFINITY_ENABLED);
|
||||
next_base = 1024 * 1024;
|
||||
for (i = 1; i < pcms->numa_nodes + 1; ++i) {
|
||||
mem_base = next_base;
|
||||
|
@ -2508,21 +2488,21 @@ build_srat(GArray *table_data, GArray *linker, MachineState *machine)
|
|||
mem_len -= next_base - pcms->below_4g_mem_size;
|
||||
if (mem_len > 0) {
|
||||
numamem = acpi_data_push(table_data, sizeof *numamem);
|
||||
acpi_build_srat_memory(numamem, mem_base, mem_len, i - 1,
|
||||
MEM_AFFINITY_ENABLED);
|
||||
build_srat_memory(numamem, mem_base, mem_len, i - 1,
|
||||
MEM_AFFINITY_ENABLED);
|
||||
}
|
||||
mem_base = 1ULL << 32;
|
||||
mem_len = next_base - pcms->below_4g_mem_size;
|
||||
next_base += (1ULL << 32) - pcms->below_4g_mem_size;
|
||||
}
|
||||
numamem = acpi_data_push(table_data, sizeof *numamem);
|
||||
acpi_build_srat_memory(numamem, mem_base, mem_len, i - 1,
|
||||
MEM_AFFINITY_ENABLED);
|
||||
build_srat_memory(numamem, mem_base, mem_len, i - 1,
|
||||
MEM_AFFINITY_ENABLED);
|
||||
}
|
||||
slots = (table_data->len - numa_start) / sizeof *numamem;
|
||||
for (; slots < pcms->numa_nodes + 2; slots++) {
|
||||
numamem = acpi_data_push(table_data, sizeof *numamem);
|
||||
acpi_build_srat_memory(numamem, 0, 0, 0, MEM_AFFINITY_NOFLAGS);
|
||||
build_srat_memory(numamem, 0, 0, 0, MEM_AFFINITY_NOFLAGS);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -2532,10 +2512,9 @@ build_srat(GArray *table_data, GArray *linker, MachineState *machine)
|
|||
*/
|
||||
if (hotplugabble_address_space_size) {
|
||||
numamem = acpi_data_push(table_data, sizeof *numamem);
|
||||
acpi_build_srat_memory(numamem, pcms->hotplug_memory.base,
|
||||
hotplugabble_address_space_size, 0,
|
||||
MEM_AFFINITY_HOTPLUGGABLE |
|
||||
MEM_AFFINITY_ENABLED);
|
||||
build_srat_memory(numamem, pcms->hotplug_memory.base,
|
||||
hotplugabble_address_space_size, 0,
|
||||
MEM_AFFINITY_HOTPLUGGABLE | MEM_AFFINITY_ENABLED);
|
||||
}
|
||||
|
||||
build_header(linker, table_data,
|
||||
|
|
|
@ -146,19 +146,19 @@ static void irq_handler(void *opaque, int irq, int level)
|
|||
pic_update(fs);
|
||||
}
|
||||
|
||||
static int etraxfs_pic_init(SysBusDevice *sbd)
|
||||
static void etraxfs_pic_init(Object *obj)
|
||||
{
|
||||
DeviceState *dev = DEVICE(sbd);
|
||||
struct etrax_pic *s = ETRAX_FS_PIC(dev);
|
||||
DeviceState *dev = DEVICE(obj);
|
||||
struct etrax_pic *s = ETRAX_FS_PIC(obj);
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
||||
|
||||
qdev_init_gpio_in(dev, irq_handler, 32);
|
||||
sysbus_init_irq(sbd, &s->parent_irq);
|
||||
sysbus_init_irq(sbd, &s->parent_nmi);
|
||||
|
||||
memory_region_init_io(&s->mmio, OBJECT(s), &pic_ops, s,
|
||||
memory_region_init_io(&s->mmio, obj, &pic_ops, s,
|
||||
"etraxfs-pic", R_MAX * 4);
|
||||
sysbus_init_mmio(sbd, &s->mmio);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static Property etraxfs_pic_properties[] = {
|
||||
|
@ -169,9 +169,7 @@ static Property etraxfs_pic_properties[] = {
|
|||
static void etraxfs_pic_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
|
||||
|
||||
k->init = etraxfs_pic_init;
|
||||
dc->props = etraxfs_pic_properties;
|
||||
/*
|
||||
* Note: pointer property "interrupt_vector" may remain null, thus
|
||||
|
@ -183,6 +181,7 @@ static const TypeInfo etraxfs_pic_info = {
|
|||
.name = TYPE_ETRAX_FS_PIC,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(struct etrax_pic),
|
||||
.instance_init = etraxfs_pic_init,
|
||||
.class_init = etraxfs_pic_class_init,
|
||||
};
|
||||
|
||||
|
|
|
@ -406,10 +406,11 @@ static const MemoryRegionOps exynos4210_combiner_ops = {
|
|||
/*
|
||||
* Internal Combiner initialization.
|
||||
*/
|
||||
static int exynos4210_combiner_init(SysBusDevice *sbd)
|
||||
static void exynos4210_combiner_init(Object *obj)
|
||||
{
|
||||
DeviceState *dev = DEVICE(sbd);
|
||||
Exynos4210CombinerState *s = EXYNOS4210_COMBINER(dev);
|
||||
DeviceState *dev = DEVICE(obj);
|
||||
Exynos4210CombinerState *s = EXYNOS4210_COMBINER(obj);
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
||||
unsigned int i;
|
||||
|
||||
/* Allocate general purpose input signals and connect a handler to each of
|
||||
|
@ -421,11 +422,9 @@ static int exynos4210_combiner_init(SysBusDevice *sbd)
|
|||
sysbus_init_irq(sbd, &s->output_irq[i]);
|
||||
}
|
||||
|
||||
memory_region_init_io(&s->iomem, OBJECT(s), &exynos4210_combiner_ops, s,
|
||||
memory_region_init_io(&s->iomem, obj, &exynos4210_combiner_ops, s,
|
||||
"exynos4210-combiner", IIC_REGION_SIZE);
|
||||
sysbus_init_mmio(sbd, &s->iomem);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static Property exynos4210_combiner_properties[] = {
|
||||
|
@ -436,9 +435,7 @@ static Property exynos4210_combiner_properties[] = {
|
|||
static void exynos4210_combiner_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
|
||||
|
||||
k->init = exynos4210_combiner_init;
|
||||
dc->reset = exynos4210_combiner_reset;
|
||||
dc->props = exynos4210_combiner_properties;
|
||||
dc->vmsd = &vmstate_exynos4210_combiner;
|
||||
|
@ -448,6 +445,7 @@ static const TypeInfo exynos4210_combiner_info = {
|
|||
.name = TYPE_EXYNOS4210_COMBINER,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(Exynos4210CombinerState),
|
||||
.instance_init = exynos4210_combiner_init,
|
||||
.class_init = exynos4210_combiner_class_init,
|
||||
};
|
||||
|
||||
|
|
|
@ -281,10 +281,11 @@ static void exynos4210_gic_set_irq(void *opaque, int irq, int level)
|
|||
qemu_set_irq(qdev_get_gpio_in(s->gic, irq), level);
|
||||
}
|
||||
|
||||
static int exynos4210_gic_init(SysBusDevice *sbd)
|
||||
static void exynos4210_gic_init(Object *obj)
|
||||
{
|
||||
DeviceState *dev = DEVICE(sbd);
|
||||
Exynos4210GicState *s = EXYNOS4210_GIC(dev);
|
||||
DeviceState *dev = DEVICE(obj);
|
||||
Exynos4210GicState *s = EXYNOS4210_GIC(obj);
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
||||
uint32_t i;
|
||||
const char cpu_prefix[] = "exynos4210-gic-alias_cpu";
|
||||
const char dist_prefix[] = "exynos4210-gic-alias_dist";
|
||||
|
@ -305,15 +306,15 @@ static int exynos4210_gic_init(SysBusDevice *sbd)
|
|||
qdev_init_gpio_in(dev, exynos4210_gic_set_irq,
|
||||
EXYNOS4210_GIC_NIRQ - 32);
|
||||
|
||||
memory_region_init(&s->cpu_container, OBJECT(s), "exynos4210-cpu-container",
|
||||
memory_region_init(&s->cpu_container, obj, "exynos4210-cpu-container",
|
||||
EXYNOS4210_EXT_GIC_CPU_REGION_SIZE);
|
||||
memory_region_init(&s->dist_container, OBJECT(s), "exynos4210-dist-container",
|
||||
memory_region_init(&s->dist_container, obj, "exynos4210-dist-container",
|
||||
EXYNOS4210_EXT_GIC_DIST_REGION_SIZE);
|
||||
|
||||
for (i = 0; i < s->num_cpu; i++) {
|
||||
/* Map CPU interface per SMP Core */
|
||||
sprintf(cpu_alias_name, "%s%x", cpu_prefix, i);
|
||||
memory_region_init_alias(&s->cpu_alias[i], OBJECT(s),
|
||||
memory_region_init_alias(&s->cpu_alias[i], obj,
|
||||
cpu_alias_name,
|
||||
sysbus_mmio_get_region(busdev, 1),
|
||||
0,
|
||||
|
@ -323,7 +324,7 @@ static int exynos4210_gic_init(SysBusDevice *sbd)
|
|||
|
||||
/* Map Distributor per SMP Core */
|
||||
sprintf(dist_alias_name, "%s%x", dist_prefix, i);
|
||||
memory_region_init_alias(&s->dist_alias[i], OBJECT(s),
|
||||
memory_region_init_alias(&s->dist_alias[i], obj,
|
||||
dist_alias_name,
|
||||
sysbus_mmio_get_region(busdev, 0),
|
||||
0,
|
||||
|
@ -334,8 +335,6 @@ static int exynos4210_gic_init(SysBusDevice *sbd)
|
|||
|
||||
sysbus_init_mmio(sbd, &s->cpu_container);
|
||||
sysbus_init_mmio(sbd, &s->dist_container);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static Property exynos4210_gic_properties[] = {
|
||||
|
@ -346,9 +345,7 @@ static Property exynos4210_gic_properties[] = {
|
|||
static void exynos4210_gic_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
|
||||
|
||||
k->init = exynos4210_gic_init;
|
||||
dc->props = exynos4210_gic_properties;
|
||||
}
|
||||
|
||||
|
@ -356,6 +353,7 @@ static const TypeInfo exynos4210_gic_info = {
|
|||
.name = TYPE_EXYNOS4210_GIC,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(Exynos4210GicState),
|
||||
.instance_init = exynos4210_gic_init,
|
||||
.class_init = exynos4210_gic_class_init,
|
||||
};
|
||||
|
||||
|
@ -430,9 +428,16 @@ static void exynos4210_irq_gate_reset(DeviceState *d)
|
|||
/*
|
||||
* IRQ Gate initialization.
|
||||
*/
|
||||
static int exynos4210_irq_gate_init(SysBusDevice *sbd)
|
||||
static void exynos4210_irq_gate_init(Object *obj)
|
||||
{
|
||||
Exynos4210IRQGateState *s = EXYNOS4210_IRQ_GATE(obj);
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
||||
|
||||
sysbus_init_irq(sbd, &s->out);
|
||||
}
|
||||
|
||||
static void exynos4210_irq_gate_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
DeviceState *dev = DEVICE(sbd);
|
||||
Exynos4210IRQGateState *s = EXYNOS4210_IRQ_GATE(dev);
|
||||
|
||||
/* Allocate general purpose input signals and connect a handler to each of
|
||||
|
@ -440,27 +445,23 @@ static int exynos4210_irq_gate_init(SysBusDevice *sbd)
|
|||
qdev_init_gpio_in(dev, exynos4210_irq_gate_handler, s->n_in);
|
||||
|
||||
s->level = g_malloc0(s->n_in * sizeof(*s->level));
|
||||
|
||||
sysbus_init_irq(sbd, &s->out);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void exynos4210_irq_gate_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
|
||||
|
||||
k->init = exynos4210_irq_gate_init;
|
||||
dc->reset = exynos4210_irq_gate_reset;
|
||||
dc->vmsd = &vmstate_exynos4210_irq_gate;
|
||||
dc->props = exynos4210_irq_gate_properties;
|
||||
dc->realize = exynos4210_irq_gate_realize;
|
||||
}
|
||||
|
||||
static const TypeInfo exynos4210_irq_gate_info = {
|
||||
.name = TYPE_EXYNOS4210_IRQ_GATE,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(Exynos4210IRQGateState),
|
||||
.instance_init = exynos4210_irq_gate_init,
|
||||
.class_init = exynos4210_irq_gate_class_init,
|
||||
};
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include "hw/sparc/grlib.h"
|
||||
|
||||
#include "trace.h"
|
||||
#include "qapi/error.h"
|
||||
|
||||
#define IRQMP_MAX_CPU 16
|
||||
#define IRQMP_REG_SIZE 256 /* Size of memory mapped registers */
|
||||
|
@ -323,23 +324,27 @@ static void grlib_irqmp_reset(DeviceState *d)
|
|||
irqmp->state->parent = irqmp;
|
||||
}
|
||||
|
||||
static int grlib_irqmp_init(SysBusDevice *dev)
|
||||
static void grlib_irqmp_init(Object *obj)
|
||||
{
|
||||
IRQMP *irqmp = GRLIB_IRQMP(dev);
|
||||
IRQMP *irqmp = GRLIB_IRQMP(obj);
|
||||
SysBusDevice *dev = SYS_BUS_DEVICE(obj);
|
||||
|
||||
/* Check parameters */
|
||||
if (irqmp->set_pil_in == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
memory_region_init_io(&irqmp->iomem, OBJECT(dev), &grlib_irqmp_ops, irqmp,
|
||||
memory_region_init_io(&irqmp->iomem, obj, &grlib_irqmp_ops, irqmp,
|
||||
"irqmp", IRQMP_REG_SIZE);
|
||||
|
||||
irqmp->state = g_malloc0(sizeof *irqmp->state);
|
||||
|
||||
sysbus_init_mmio(dev, &irqmp->iomem);
|
||||
}
|
||||
|
||||
return 0;
|
||||
static void grlib_irqmp_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
IRQMP *irqmp = GRLIB_IRQMP(dev);
|
||||
|
||||
/* Check parameters */
|
||||
if (irqmp->set_pil_in == NULL) {
|
||||
error_setg(errp, "set_pil_in cannot be NULL.");
|
||||
}
|
||||
}
|
||||
|
||||
static Property grlib_irqmp_properties[] = {
|
||||
|
@ -351,19 +356,19 @@ static Property grlib_irqmp_properties[] = {
|
|||
static void grlib_irqmp_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
|
||||
|
||||
k->init = grlib_irqmp_init;
|
||||
dc->reset = grlib_irqmp_reset;
|
||||
dc->props = grlib_irqmp_properties;
|
||||
/* Reason: pointer properties "set_pil_in", "set_pil_in_opaque" */
|
||||
dc->cannot_instantiate_with_device_add_yet = true;
|
||||
dc->realize = grlib_irqmp_realize;
|
||||
}
|
||||
|
||||
static const TypeInfo grlib_irqmp_info = {
|
||||
.name = TYPE_GRLIB_IRQMP,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(IRQMP),
|
||||
.instance_init = grlib_irqmp_init,
|
||||
.class_init = grlib_irqmp_class_init,
|
||||
};
|
||||
|
||||
|
|
|
@ -321,28 +321,26 @@ static void imx_avic_reset(DeviceState *dev)
|
|||
memset(s->prio, 0, sizeof s->prio);
|
||||
}
|
||||
|
||||
static int imx_avic_init(SysBusDevice *sbd)
|
||||
static void imx_avic_init(Object *obj)
|
||||
{
|
||||
DeviceState *dev = DEVICE(sbd);
|
||||
IMXAVICState *s = IMX_AVIC(dev);
|
||||
DeviceState *dev = DEVICE(obj);
|
||||
IMXAVICState *s = IMX_AVIC(obj);
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
||||
|
||||
memory_region_init_io(&s->iomem, OBJECT(s), &imx_avic_ops, s,
|
||||
memory_region_init_io(&s->iomem, obj, &imx_avic_ops, s,
|
||||
TYPE_IMX_AVIC, 0x1000);
|
||||
sysbus_init_mmio(sbd, &s->iomem);
|
||||
|
||||
qdev_init_gpio_in(dev, imx_avic_set_irq, IMX_AVIC_NUM_IRQS);
|
||||
sysbus_init_irq(sbd, &s->irq);
|
||||
sysbus_init_irq(sbd, &s->fiq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void imx_avic_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
|
||||
k->init = imx_avic_init;
|
||||
|
||||
dc->vmsd = &vmstate_imx_avic;
|
||||
dc->reset = imx_avic_reset;
|
||||
dc->desc = "i.MX Advanced Vector Interrupt Controller";
|
||||
|
@ -352,6 +350,7 @@ static const TypeInfo imx_avic_info = {
|
|||
.name = TYPE_IMX_AVIC,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(IMXAVICState),
|
||||
.instance_init = imx_avic_init,
|
||||
.class_init = imx_avic_class_init,
|
||||
};
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "hw/arm/omap.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qapi/error.h"
|
||||
|
||||
/* Interrupt Handlers */
|
||||
struct omap_intr_handler_bank_s {
|
||||
|
@ -363,23 +364,28 @@ static void omap_inth_reset(DeviceState *dev)
|
|||
qemu_set_irq(s->parent_intr[1], 0);
|
||||
}
|
||||
|
||||
static int omap_intc_init(SysBusDevice *sbd)
|
||||
static void omap_intc_init(Object *obj)
|
||||
{
|
||||
DeviceState *dev = DEVICE(sbd);
|
||||
struct omap_intr_handler_s *s = OMAP_INTC(dev);
|
||||
DeviceState *dev = DEVICE(obj);
|
||||
struct omap_intr_handler_s *s = OMAP_INTC(obj);
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
||||
|
||||
if (!s->iclk) {
|
||||
error_report("omap-intc: clk not connected");
|
||||
return -1;
|
||||
}
|
||||
s->nbanks = 1;
|
||||
sysbus_init_irq(sbd, &s->parent_intr[0]);
|
||||
sysbus_init_irq(sbd, &s->parent_intr[1]);
|
||||
qdev_init_gpio_in(dev, omap_set_intr, s->nbanks * 32);
|
||||
memory_region_init_io(&s->mmio, OBJECT(s), &omap_inth_mem_ops, s,
|
||||
memory_region_init_io(&s->mmio, obj, &omap_inth_mem_ops, s,
|
||||
"omap-intc", s->size);
|
||||
sysbus_init_mmio(sbd, &s->mmio);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void omap_intc_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
struct omap_intr_handler_s *s = OMAP_INTC(dev);
|
||||
|
||||
if (!s->iclk) {
|
||||
error_setg(errp, "omap-intc: clk not connected");
|
||||
}
|
||||
}
|
||||
|
||||
static Property omap_intc_properties[] = {
|
||||
|
@ -391,18 +397,18 @@ static Property omap_intc_properties[] = {
|
|||
static void omap_intc_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
|
||||
|
||||
k->init = omap_intc_init;
|
||||
dc->reset = omap_inth_reset;
|
||||
dc->props = omap_intc_properties;
|
||||
/* Reason: pointer property "clk" */
|
||||
dc->cannot_instantiate_with_device_add_yet = true;
|
||||
dc->realize = omap_intc_realize;
|
||||
}
|
||||
|
||||
static const TypeInfo omap_intc_info = {
|
||||
.name = "omap-intc",
|
||||
.parent = TYPE_OMAP_INTC,
|
||||
.instance_init = omap_intc_init,
|
||||
.class_init = omap_intc_class_init,
|
||||
};
|
||||
|
||||
|
@ -605,28 +611,34 @@ static const MemoryRegionOps omap2_inth_mem_ops = {
|
|||
},
|
||||
};
|
||||
|
||||
static int omap2_intc_init(SysBusDevice *sbd)
|
||||
static void omap2_intc_init(Object *obj)
|
||||
{
|
||||
DeviceState *dev = DEVICE(sbd);
|
||||
struct omap_intr_handler_s *s = OMAP_INTC(dev);
|
||||
DeviceState *dev = DEVICE(obj);
|
||||
struct omap_intr_handler_s *s = OMAP_INTC(obj);
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
||||
|
||||
if (!s->iclk) {
|
||||
error_report("omap2-intc: iclk not connected");
|
||||
return -1;
|
||||
}
|
||||
if (!s->fclk) {
|
||||
error_report("omap2-intc: fclk not connected");
|
||||
return -1;
|
||||
}
|
||||
s->level_only = 1;
|
||||
s->nbanks = 3;
|
||||
sysbus_init_irq(sbd, &s->parent_intr[0]);
|
||||
sysbus_init_irq(sbd, &s->parent_intr[1]);
|
||||
qdev_init_gpio_in(dev, omap_set_intr_noedge, s->nbanks * 32);
|
||||
memory_region_init_io(&s->mmio, OBJECT(s), &omap2_inth_mem_ops, s,
|
||||
memory_region_init_io(&s->mmio, obj, &omap2_inth_mem_ops, s,
|
||||
"omap2-intc", 0x1000);
|
||||
sysbus_init_mmio(sbd, &s->mmio);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void omap2_intc_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
struct omap_intr_handler_s *s = OMAP_INTC(dev);
|
||||
|
||||
if (!s->iclk) {
|
||||
error_setg(errp, "omap2-intc: iclk not connected");
|
||||
return;
|
||||
}
|
||||
if (!s->fclk) {
|
||||
error_setg(errp, "omap2-intc: fclk not connected");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static Property omap2_intc_properties[] = {
|
||||
|
@ -640,18 +652,18 @@ static Property omap2_intc_properties[] = {
|
|||
static void omap2_intc_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
|
||||
|
||||
k->init = omap2_intc_init;
|
||||
dc->reset = omap_inth_reset;
|
||||
dc->props = omap2_intc_properties;
|
||||
/* Reason: pointer property "iclk", "fclk" */
|
||||
dc->cannot_instantiate_with_device_add_yet = true;
|
||||
dc->realize = omap2_intc_realize;
|
||||
}
|
||||
|
||||
static const TypeInfo omap2_intc_info = {
|
||||
.name = "omap2-intc",
|
||||
.parent = TYPE_OMAP_INTC,
|
||||
.instance_init = omap2_intc_init,
|
||||
.class_init = omap2_intc_class_init,
|
||||
};
|
||||
|
||||
|
|
|
@ -236,17 +236,17 @@ static void pl190_reset(DeviceState *d)
|
|||
pl190_update_vectors(s);
|
||||
}
|
||||
|
||||
static int pl190_init(SysBusDevice *sbd)
|
||||
static void pl190_init(Object *obj)
|
||||
{
|
||||
DeviceState *dev = DEVICE(sbd);
|
||||
PL190State *s = PL190(dev);
|
||||
DeviceState *dev = DEVICE(obj);
|
||||
PL190State *s = PL190(obj);
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
||||
|
||||
memory_region_init_io(&s->iomem, OBJECT(s), &pl190_ops, s, "pl190", 0x1000);
|
||||
memory_region_init_io(&s->iomem, obj, &pl190_ops, s, "pl190", 0x1000);
|
||||
sysbus_init_mmio(sbd, &s->iomem);
|
||||
qdev_init_gpio_in(dev, pl190_set_irq, 32);
|
||||
sysbus_init_irq(sbd, &s->irq);
|
||||
sysbus_init_irq(sbd, &s->fiq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_pl190 = {
|
||||
|
@ -271,9 +271,7 @@ static const VMStateDescription vmstate_pl190 = {
|
|||
static void pl190_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
|
||||
|
||||
k->init = pl190_init;
|
||||
dc->reset = pl190_reset;
|
||||
dc->vmsd = &vmstate_pl190;
|
||||
}
|
||||
|
@ -282,6 +280,7 @@ static const TypeInfo pl190_info = {
|
|||
.name = TYPE_PL190,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(PL190State),
|
||||
.instance_init = pl190_init,
|
||||
.class_init = pl190_class_init,
|
||||
};
|
||||
|
||||
|
|
|
@ -418,15 +418,16 @@ static void slavio_intctl_reset(DeviceState *d)
|
|||
slavio_check_interrupts(s, 0);
|
||||
}
|
||||
|
||||
static int slavio_intctl_init1(SysBusDevice *sbd)
|
||||
static void slavio_intctl_init(Object *obj)
|
||||
{
|
||||
DeviceState *dev = DEVICE(sbd);
|
||||
SLAVIO_INTCTLState *s = SLAVIO_INTCTL(dev);
|
||||
DeviceState *dev = DEVICE(obj);
|
||||
SLAVIO_INTCTLState *s = SLAVIO_INTCTL(obj);
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
||||
unsigned int i, j;
|
||||
char slave_name[45];
|
||||
|
||||
qdev_init_gpio_in(dev, slavio_set_irq_all, 32 + MAX_CPUS);
|
||||
memory_region_init_io(&s->iomem, OBJECT(s), &slavio_intctlm_mem_ops, s,
|
||||
memory_region_init_io(&s->iomem, obj, &slavio_intctlm_mem_ops, s,
|
||||
"master-interrupt-controller", INTCTLM_SIZE);
|
||||
sysbus_init_mmio(sbd, &s->iomem);
|
||||
|
||||
|
@ -443,16 +444,12 @@ static int slavio_intctl_init1(SysBusDevice *sbd)
|
|||
s->slaves[i].cpu = i;
|
||||
s->slaves[i].master = s;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void slavio_intctl_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
|
||||
|
||||
k->init = slavio_intctl_init1;
|
||||
dc->reset = slavio_intctl_reset;
|
||||
dc->vmsd = &vmstate_intctl;
|
||||
}
|
||||
|
@ -461,6 +458,7 @@ static const TypeInfo slavio_intctl_info = {
|
|||
.name = TYPE_SLAVIO_INTCTL,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(SLAVIO_INTCTLState),
|
||||
.instance_init = slavio_intctl_init,
|
||||
.class_init = slavio_intctl_class_init,
|
||||
};
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@ obj-$(CONFIG_IMX) += imx_ccm.o
|
|||
obj-$(CONFIG_IMX) += imx31_ccm.o
|
||||
obj-$(CONFIG_IMX) += imx25_ccm.o
|
||||
obj-$(CONFIG_IMX) += imx6_ccm.o
|
||||
obj-$(CONFIG_IMX) += imx6_src.o
|
||||
obj-$(CONFIG_MILKYMIST) += milkymist-hpdmc.o
|
||||
obj-$(CONFIG_MILKYMIST) += milkymist-pfpu.o
|
||||
obj-$(CONFIG_MAINSTONE) += mst_fpga.o
|
||||
|
|
|
@ -21,6 +21,8 @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value)
|
|||
int n;
|
||||
uint32_t offset, length, color;
|
||||
uint32_t xres, yres, xoffset, yoffset, bpp, pixo, alpha;
|
||||
uint32_t tmp_xres, tmp_yres, tmp_xoffset, tmp_yoffset;
|
||||
uint32_t tmp_bpp, tmp_pixo, tmp_alpha;
|
||||
uint32_t *newxres = NULL, *newyres = NULL, *newxoffset = NULL,
|
||||
*newyoffset = NULL, *newbpp = NULL, *newpixo = NULL, *newalpha = NULL;
|
||||
|
||||
|
@ -139,7 +141,11 @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value)
|
|||
|
||||
case 0x00040001: /* Allocate buffer */
|
||||
stl_le_phys(&s->dma_as, value + 12, s->fbdev->base);
|
||||
stl_le_phys(&s->dma_as, value + 16, s->fbdev->size);
|
||||
tmp_xres = newxres != NULL ? *newxres : s->fbdev->xres;
|
||||
tmp_yres = newyres != NULL ? *newyres : s->fbdev->yres;
|
||||
tmp_bpp = newbpp != NULL ? *newbpp : s->fbdev->bpp;
|
||||
stl_le_phys(&s->dma_as, value + 16,
|
||||
tmp_xres * tmp_yres * tmp_bpp / 8);
|
||||
resplen = 8;
|
||||
break;
|
||||
case 0x00048001: /* Release buffer */
|
||||
|
@ -150,8 +156,10 @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value)
|
|||
break;
|
||||
case 0x00040003: /* Get display width/height */
|
||||
case 0x00040004:
|
||||
stl_le_phys(&s->dma_as, value + 12, s->fbdev->xres);
|
||||
stl_le_phys(&s->dma_as, value + 16, s->fbdev->yres);
|
||||
tmp_xres = newxres != NULL ? *newxres : s->fbdev->xres;
|
||||
tmp_yres = newyres != NULL ? *newyres : s->fbdev->yres;
|
||||
stl_le_phys(&s->dma_as, value + 12, tmp_xres);
|
||||
stl_le_phys(&s->dma_as, value + 16, tmp_yres);
|
||||
resplen = 8;
|
||||
break;
|
||||
case 0x00044003: /* Test display width/height */
|
||||
|
@ -167,7 +175,8 @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value)
|
|||
resplen = 8;
|
||||
break;
|
||||
case 0x00040005: /* Get depth */
|
||||
stl_le_phys(&s->dma_as, value + 12, s->fbdev->bpp);
|
||||
tmp_bpp = newbpp != NULL ? *newbpp : s->fbdev->bpp;
|
||||
stl_le_phys(&s->dma_as, value + 12, tmp_bpp);
|
||||
resplen = 4;
|
||||
break;
|
||||
case 0x00044005: /* Test depth */
|
||||
|
@ -179,7 +188,8 @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value)
|
|||
resplen = 4;
|
||||
break;
|
||||
case 0x00040006: /* Get pixel order */
|
||||
stl_le_phys(&s->dma_as, value + 12, s->fbdev->pixo);
|
||||
tmp_pixo = newpixo != NULL ? *newpixo : s->fbdev->pixo;
|
||||
stl_le_phys(&s->dma_as, value + 12, tmp_pixo);
|
||||
resplen = 4;
|
||||
break;
|
||||
case 0x00044006: /* Test pixel order */
|
||||
|
@ -191,7 +201,8 @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value)
|
|||
resplen = 4;
|
||||
break;
|
||||
case 0x00040007: /* Get alpha */
|
||||
stl_le_phys(&s->dma_as, value + 12, s->fbdev->alpha);
|
||||
tmp_alpha = newalpha != NULL ? *newalpha : s->fbdev->alpha;
|
||||
stl_le_phys(&s->dma_as, value + 12, tmp_alpha);
|
||||
resplen = 4;
|
||||
break;
|
||||
case 0x00044007: /* Test pixel alpha */
|
||||
|
@ -203,12 +214,16 @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value)
|
|||
resplen = 4;
|
||||
break;
|
||||
case 0x00040008: /* Get pitch */
|
||||
stl_le_phys(&s->dma_as, value + 12, s->fbdev->pitch);
|
||||
tmp_xres = newxres != NULL ? *newxres : s->fbdev->xres;
|
||||
tmp_bpp = newbpp != NULL ? *newbpp : s->fbdev->bpp;
|
||||
stl_le_phys(&s->dma_as, value + 12, tmp_xres * tmp_bpp / 8);
|
||||
resplen = 4;
|
||||
break;
|
||||
case 0x00040009: /* Get virtual offset */
|
||||
stl_le_phys(&s->dma_as, value + 12, s->fbdev->xoffset);
|
||||
stl_le_phys(&s->dma_as, value + 16, s->fbdev->yoffset);
|
||||
tmp_xoffset = newxoffset != NULL ? *newxoffset : s->fbdev->xoffset;
|
||||
tmp_yoffset = newyoffset != NULL ? *newyoffset : s->fbdev->yoffset;
|
||||
stl_le_phys(&s->dma_as, value + 12, tmp_xoffset);
|
||||
stl_le_phys(&s->dma_as, value + 16, tmp_yoffset);
|
||||
resplen = 8;
|
||||
break;
|
||||
case 0x00044009: /* Test virtual offset */
|
||||
|
|
264
hw/misc/imx6_src.c
Normal file
264
hw/misc/imx6_src.c
Normal file
|
@ -0,0 +1,264 @@
|
|||
/*
|
||||
* IMX6 System Reset Controller
|
||||
*
|
||||
* Copyright (c) 2015 Jean-Christophe Dubois <jcd@tribudubois.net>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/misc/imx6_src.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "qemu/bitops.h"
|
||||
#include "arm-powerctl.h"
|
||||
|
||||
#ifndef DEBUG_IMX6_SRC
|
||||
#define DEBUG_IMX6_SRC 0
|
||||
#endif
|
||||
|
||||
#define DPRINTF(fmt, args...) \
|
||||
do { \
|
||||
if (DEBUG_IMX6_SRC) { \
|
||||
fprintf(stderr, "[%s]%s: " fmt , TYPE_IMX6_SRC, \
|
||||
__func__, ##args); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static char const *imx6_src_reg_name(uint32_t reg)
|
||||
{
|
||||
static char unknown[20];
|
||||
|
||||
switch (reg) {
|
||||
case SRC_SCR:
|
||||
return "SRC_SCR";
|
||||
case SRC_SBMR1:
|
||||
return "SRC_SBMR1";
|
||||
case SRC_SRSR:
|
||||
return "SRC_SRSR";
|
||||
case SRC_SISR:
|
||||
return "SRC_SISR";
|
||||
case SRC_SIMR:
|
||||
return "SRC_SIMR";
|
||||
case SRC_SBMR2:
|
||||
return "SRC_SBMR2";
|
||||
case SRC_GPR1:
|
||||
return "SRC_GPR1";
|
||||
case SRC_GPR2:
|
||||
return "SRC_GPR2";
|
||||
case SRC_GPR3:
|
||||
return "SRC_GPR3";
|
||||
case SRC_GPR4:
|
||||
return "SRC_GPR4";
|
||||
case SRC_GPR5:
|
||||
return "SRC_GPR5";
|
||||
case SRC_GPR6:
|
||||
return "SRC_GPR6";
|
||||
case SRC_GPR7:
|
||||
return "SRC_GPR7";
|
||||
case SRC_GPR8:
|
||||
return "SRC_GPR8";
|
||||
case SRC_GPR9:
|
||||
return "SRC_GPR9";
|
||||
case SRC_GPR10:
|
||||
return "SRC_GPR10";
|
||||
default:
|
||||
sprintf(unknown, "%d ?", reg);
|
||||
return unknown;
|
||||
}
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_imx6_src = {
|
||||
.name = TYPE_IMX6_SRC,
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32_ARRAY(regs, IMX6SRCState, SRC_MAX),
|
||||
VMSTATE_END_OF_LIST()
|
||||
},
|
||||
};
|
||||
|
||||
static void imx6_src_reset(DeviceState *dev)
|
||||
{
|
||||
IMX6SRCState *s = IMX6_SRC(dev);
|
||||
|
||||
DPRINTF("\n");
|
||||
|
||||
memset(s->regs, 0, sizeof(s->regs));
|
||||
|
||||
/* Set reset values */
|
||||
s->regs[SRC_SCR] = 0x521;
|
||||
s->regs[SRC_SRSR] = 0x1;
|
||||
s->regs[SRC_SIMR] = 0x1F;
|
||||
}
|
||||
|
||||
static uint64_t imx6_src_read(void *opaque, hwaddr offset, unsigned size)
|
||||
{
|
||||
uint32_t value = 0;
|
||||
IMX6SRCState *s = (IMX6SRCState *)opaque;
|
||||
uint32_t index = offset >> 2;
|
||||
|
||||
if (index < SRC_MAX) {
|
||||
value = s->regs[index];
|
||||
} else {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%"
|
||||
HWADDR_PRIx "\n", TYPE_IMX6_SRC, __func__, offset);
|
||||
|
||||
}
|
||||
|
||||
DPRINTF("reg[%s] => 0x%" PRIx32 "\n", imx6_src_reg_name(index), value);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
static void imx6_src_write(void *opaque, hwaddr offset, uint64_t value,
|
||||
unsigned size)
|
||||
{
|
||||
IMX6SRCState *s = (IMX6SRCState *)opaque;
|
||||
uint32_t index = offset >> 2;
|
||||
unsigned long change_mask;
|
||||
unsigned long current_value = value;
|
||||
|
||||
if (index >= SRC_MAX) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%"
|
||||
HWADDR_PRIx "\n", TYPE_IMX6_SRC, __func__, offset);
|
||||
return;
|
||||
}
|
||||
|
||||
DPRINTF("reg[%s] <= 0x%" PRIx32 "\n", imx6_src_reg_name(index),
|
||||
(uint32_t)current_value);
|
||||
|
||||
change_mask = s->regs[index] ^ (uint32_t)current_value;
|
||||
|
||||
switch (index) {
|
||||
case SRC_SCR:
|
||||
/*
|
||||
* On real hardware when the system reset controller starts a
|
||||
* secondary CPU it runs through some boot ROM code which reads
|
||||
* the SRC_GPRX registers controlling the start address and branches
|
||||
* to it.
|
||||
* Here we are taking a short cut and branching directly to the
|
||||
* requested address (we don't want to run the boot ROM code inside
|
||||
* QEMU)
|
||||
*/
|
||||
if (EXTRACT(change_mask, CORE3_ENABLE)) {
|
||||
if (EXTRACT(current_value, CORE3_ENABLE)) {
|
||||
/* CORE 3 is brought up */
|
||||
arm_set_cpu_on(3, s->regs[SRC_GPR7], s->regs[SRC_GPR8],
|
||||
3, false);
|
||||
} else {
|
||||
/* CORE 3 is shut down */
|
||||
arm_set_cpu_off(3);
|
||||
}
|
||||
/* We clear the reset bits as the processor changed state */
|
||||
clear_bit(CORE3_RST_SHIFT, ¤t_value);
|
||||
clear_bit(CORE3_RST_SHIFT, &change_mask);
|
||||
}
|
||||
if (EXTRACT(change_mask, CORE2_ENABLE)) {
|
||||
if (EXTRACT(current_value, CORE2_ENABLE)) {
|
||||
/* CORE 2 is brought up */
|
||||
arm_set_cpu_on(2, s->regs[SRC_GPR5], s->regs[SRC_GPR6],
|
||||
3, false);
|
||||
} else {
|
||||
/* CORE 3 is shut down */
|
||||
arm_set_cpu_off(2);
|
||||
}
|
||||
/* We clear the reset bits as the processor changed state */
|
||||
clear_bit(CORE2_RST_SHIFT, ¤t_value);
|
||||
clear_bit(CORE2_RST_SHIFT, &change_mask);
|
||||
}
|
||||
if (EXTRACT(change_mask, CORE1_ENABLE)) {
|
||||
if (EXTRACT(current_value, CORE1_ENABLE)) {
|
||||
/* CORE 1 is brought up */
|
||||
arm_set_cpu_on(1, s->regs[SRC_GPR3], s->regs[SRC_GPR4],
|
||||
3, false);
|
||||
} else {
|
||||
/* CORE 3 is shut down */
|
||||
arm_set_cpu_off(1);
|
||||
}
|
||||
/* We clear the reset bits as the processor changed state */
|
||||
clear_bit(CORE1_RST_SHIFT, ¤t_value);
|
||||
clear_bit(CORE1_RST_SHIFT, &change_mask);
|
||||
}
|
||||
if (EXTRACT(change_mask, CORE0_RST)) {
|
||||
arm_reset_cpu(0);
|
||||
clear_bit(CORE0_RST_SHIFT, ¤t_value);
|
||||
}
|
||||
if (EXTRACT(change_mask, CORE1_RST)) {
|
||||
arm_reset_cpu(1);
|
||||
clear_bit(CORE1_RST_SHIFT, ¤t_value);
|
||||
}
|
||||
if (EXTRACT(change_mask, CORE2_RST)) {
|
||||
arm_reset_cpu(2);
|
||||
clear_bit(CORE2_RST_SHIFT, ¤t_value);
|
||||
}
|
||||
if (EXTRACT(change_mask, CORE3_RST)) {
|
||||
arm_reset_cpu(3);
|
||||
clear_bit(CORE3_RST_SHIFT, ¤t_value);
|
||||
}
|
||||
if (EXTRACT(change_mask, SW_IPU2_RST)) {
|
||||
/* We pretend the IPU2 is reset */
|
||||
clear_bit(SW_IPU2_RST_SHIFT, ¤t_value);
|
||||
}
|
||||
if (EXTRACT(change_mask, SW_IPU1_RST)) {
|
||||
/* We pretend the IPU1 is reset */
|
||||
clear_bit(SW_IPU1_RST_SHIFT, ¤t_value);
|
||||
}
|
||||
s->regs[index] = current_value;
|
||||
break;
|
||||
default:
|
||||
s->regs[index] = current_value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct MemoryRegionOps imx6_src_ops = {
|
||||
.read = imx6_src_read,
|
||||
.write = imx6_src_write,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
.valid = {
|
||||
/*
|
||||
* Our device would not work correctly if the guest was doing
|
||||
* unaligned access. This might not be a limitation on the real
|
||||
* device but in practice there is no reason for a guest to access
|
||||
* this device unaligned.
|
||||
*/
|
||||
.min_access_size = 4,
|
||||
.max_access_size = 4,
|
||||
.unaligned = false,
|
||||
},
|
||||
};
|
||||
|
||||
static void imx6_src_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
IMX6SRCState *s = IMX6_SRC(dev);
|
||||
|
||||
memory_region_init_io(&s->iomem, OBJECT(dev), &imx6_src_ops, s,
|
||||
TYPE_IMX6_SRC, 0x1000);
|
||||
sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
|
||||
}
|
||||
|
||||
static void imx6_src_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->realize = imx6_src_realize;
|
||||
dc->reset = imx6_src_reset;
|
||||
dc->vmsd = &vmstate_imx6_src;
|
||||
dc->desc = "i.MX6 System Reset Controller";
|
||||
}
|
||||
|
||||
static const TypeInfo imx6_src_info = {
|
||||
.name = TYPE_IMX6_SRC,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(IMX6SRCState),
|
||||
.class_init = imx6_src_class_init,
|
||||
};
|
||||
|
||||
static void imx6_src_register_types(void)
|
||||
{
|
||||
type_register_static(&imx6_src_info);
|
||||
}
|
||||
|
||||
type_init(imx6_src_register_types)
|
|
@ -4,3 +4,4 @@ common-obj-$(CONFIG_XILINX_SPI) += xilinx_spi.o
|
|||
common-obj-$(CONFIG_XILINX_SPIPS) += xilinx_spips.o
|
||||
|
||||
obj-$(CONFIG_OMAP) += omap_spi.o
|
||||
obj-$(CONFIG_IMX) += imx_spi.o
|
||||
|
|
454
hw/ssi/imx_spi.c
Normal file
454
hw/ssi/imx_spi.c
Normal file
|
@ -0,0 +1,454 @@
|
|||
/*
|
||||
* IMX SPI Controller
|
||||
*
|
||||
* Copyright (c) 2016 Jean-Christophe Dubois <jcd@tribudubois.net>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/ssi/imx_spi.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
|
||||
#ifndef DEBUG_IMX_SPI
|
||||
#define DEBUG_IMX_SPI 0
|
||||
#endif
|
||||
|
||||
#define DPRINTF(fmt, args...) \
|
||||
do { \
|
||||
if (DEBUG_IMX_SPI) { \
|
||||
fprintf(stderr, "[%s]%s: " fmt , TYPE_IMX_SPI, \
|
||||
__func__, ##args); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static char const *imx_spi_reg_name(uint32_t reg)
|
||||
{
|
||||
static char unknown[20];
|
||||
|
||||
switch (reg) {
|
||||
case ECSPI_RXDATA:
|
||||
return "ECSPI_RXDATA";
|
||||
case ECSPI_TXDATA:
|
||||
return "ECSPI_TXDATA";
|
||||
case ECSPI_CONREG:
|
||||
return "ECSPI_CONREG";
|
||||
case ECSPI_CONFIGREG:
|
||||
return "ECSPI_CONFIGREG";
|
||||
case ECSPI_INTREG:
|
||||
return "ECSPI_INTREG";
|
||||
case ECSPI_DMAREG:
|
||||
return "ECSPI_DMAREG";
|
||||
case ECSPI_STATREG:
|
||||
return "ECSPI_STATREG";
|
||||
case ECSPI_PERIODREG:
|
||||
return "ECSPI_PERIODREG";
|
||||
case ECSPI_TESTREG:
|
||||
return "ECSPI_TESTREG";
|
||||
case ECSPI_MSGDATA:
|
||||
return "ECSPI_MSGDATA";
|
||||
default:
|
||||
sprintf(unknown, "%d ?", reg);
|
||||
return unknown;
|
||||
}
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_imx_spi = {
|
||||
.name = TYPE_IMX_SPI,
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_FIFO32(tx_fifo, IMXSPIState),
|
||||
VMSTATE_FIFO32(rx_fifo, IMXSPIState),
|
||||
VMSTATE_INT16(burst_length, IMXSPIState),
|
||||
VMSTATE_UINT32_ARRAY(regs, IMXSPIState, ECSPI_MAX),
|
||||
VMSTATE_END_OF_LIST()
|
||||
},
|
||||
};
|
||||
|
||||
static void imx_spi_txfifo_reset(IMXSPIState *s)
|
||||
{
|
||||
fifo32_reset(&s->tx_fifo);
|
||||
s->regs[ECSPI_STATREG] |= ECSPI_STATREG_TE;
|
||||
s->regs[ECSPI_STATREG] &= ~ECSPI_STATREG_TF;
|
||||
}
|
||||
|
||||
static void imx_spi_rxfifo_reset(IMXSPIState *s)
|
||||
{
|
||||
fifo32_reset(&s->rx_fifo);
|
||||
s->regs[ECSPI_STATREG] &= ~ECSPI_STATREG_RR;
|
||||
s->regs[ECSPI_STATREG] &= ~ECSPI_STATREG_RF;
|
||||
s->regs[ECSPI_STATREG] &= ~ECSPI_STATREG_RO;
|
||||
}
|
||||
|
||||
static void imx_spi_update_irq(IMXSPIState *s)
|
||||
{
|
||||
int level;
|
||||
|
||||
if (fifo32_is_empty(&s->rx_fifo)) {
|
||||
s->regs[ECSPI_STATREG] &= ~ECSPI_STATREG_RR;
|
||||
} else {
|
||||
s->regs[ECSPI_STATREG] |= ECSPI_STATREG_RR;
|
||||
}
|
||||
|
||||
if (fifo32_is_full(&s->rx_fifo)) {
|
||||
s->regs[ECSPI_STATREG] |= ECSPI_STATREG_RF;
|
||||
} else {
|
||||
s->regs[ECSPI_STATREG] &= ~ECSPI_STATREG_RF;
|
||||
}
|
||||
|
||||
if (fifo32_is_empty(&s->tx_fifo)) {
|
||||
s->regs[ECSPI_STATREG] |= ECSPI_STATREG_TE;
|
||||
} else {
|
||||
s->regs[ECSPI_STATREG] &= ~ECSPI_STATREG_TE;
|
||||
}
|
||||
|
||||
if (fifo32_is_full(&s->tx_fifo)) {
|
||||
s->regs[ECSPI_STATREG] |= ECSPI_STATREG_TF;
|
||||
} else {
|
||||
s->regs[ECSPI_STATREG] &= ~ECSPI_STATREG_TF;
|
||||
}
|
||||
|
||||
level = s->regs[ECSPI_STATREG] & s->regs[ECSPI_INTREG] ? 1 : 0;
|
||||
|
||||
qemu_set_irq(s->irq, level);
|
||||
|
||||
DPRINTF("IRQ level is %d\n", level);
|
||||
}
|
||||
|
||||
static uint8_t imx_spi_selected_channel(IMXSPIState *s)
|
||||
{
|
||||
return EXTRACT(s->regs[ECSPI_CONREG], ECSPI_CONREG_CHANNEL_SELECT);
|
||||
}
|
||||
|
||||
static uint32_t imx_spi_burst_length(IMXSPIState *s)
|
||||
{
|
||||
return EXTRACT(s->regs[ECSPI_CONREG], ECSPI_CONREG_BURST_LENGTH) + 1;
|
||||
}
|
||||
|
||||
static bool imx_spi_is_enabled(IMXSPIState *s)
|
||||
{
|
||||
return s->regs[ECSPI_CONREG] & ECSPI_CONREG_EN;
|
||||
}
|
||||
|
||||
static bool imx_spi_channel_is_master(IMXSPIState *s)
|
||||
{
|
||||
uint8_t mode = EXTRACT(s->regs[ECSPI_CONREG], ECSPI_CONREG_CHANNEL_MODE);
|
||||
|
||||
return (mode & (1 << imx_spi_selected_channel(s))) ? true : false;
|
||||
}
|
||||
|
||||
static bool imx_spi_is_multiple_master_burst(IMXSPIState *s)
|
||||
{
|
||||
uint8_t wave = EXTRACT(s->regs[ECSPI_CONFIGREG], ECSPI_CONFIGREG_SS_CTL);
|
||||
|
||||
return imx_spi_channel_is_master(s) &&
|
||||
!(s->regs[ECSPI_CONREG] & ECSPI_CONREG_SMC) &&
|
||||
((wave & (1 << imx_spi_selected_channel(s))) ? true : false);
|
||||
}
|
||||
|
||||
static void imx_spi_flush_txfifo(IMXSPIState *s)
|
||||
{
|
||||
uint32_t tx;
|
||||
uint32_t rx;
|
||||
|
||||
DPRINTF("Begin: TX Fifo Size = %d, RX Fifo Size = %d\n",
|
||||
fifo32_num_used(&s->tx_fifo), fifo32_num_used(&s->rx_fifo));
|
||||
|
||||
while (!fifo32_is_empty(&s->tx_fifo)) {
|
||||
int tx_burst = 0;
|
||||
int index = 0;
|
||||
|
||||
if (s->burst_length <= 0) {
|
||||
s->burst_length = imx_spi_burst_length(s);
|
||||
|
||||
DPRINTF("Burst length = %d\n", s->burst_length);
|
||||
|
||||
if (imx_spi_is_multiple_master_burst(s)) {
|
||||
s->regs[ECSPI_CONREG] |= ECSPI_CONREG_XCH;
|
||||
}
|
||||
}
|
||||
|
||||
tx = fifo32_pop(&s->tx_fifo);
|
||||
|
||||
DPRINTF("data tx:0x%08x\n", tx);
|
||||
|
||||
tx_burst = MIN(s->burst_length, 32);
|
||||
|
||||
rx = 0;
|
||||
|
||||
while (tx_burst) {
|
||||
uint8_t byte = tx & 0xff;
|
||||
|
||||
DPRINTF("writing 0x%02x\n", (uint32_t)byte);
|
||||
|
||||
/* We need to write one byte at a time */
|
||||
byte = ssi_transfer(s->bus, byte);
|
||||
|
||||
DPRINTF("0x%02x read\n", (uint32_t)byte);
|
||||
|
||||
tx = tx >> 8;
|
||||
rx |= (byte << (index * 8));
|
||||
|
||||
/* Remove 8 bits from the actual burst */
|
||||
tx_burst -= 8;
|
||||
s->burst_length -= 8;
|
||||
index++;
|
||||
}
|
||||
|
||||
DPRINTF("data rx:0x%08x\n", rx);
|
||||
|
||||
if (fifo32_is_full(&s->rx_fifo)) {
|
||||
s->regs[ECSPI_STATREG] |= ECSPI_STATREG_RO;
|
||||
} else {
|
||||
fifo32_push(&s->rx_fifo, (uint8_t)rx);
|
||||
}
|
||||
|
||||
if (s->burst_length <= 0) {
|
||||
s->regs[ECSPI_CONREG] &= ~ECSPI_CONREG_XCH;
|
||||
|
||||
if (!imx_spi_is_multiple_master_burst(s)) {
|
||||
s->regs[ECSPI_STATREG] |= ECSPI_STATREG_TC;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (fifo32_is_empty(&s->tx_fifo)) {
|
||||
s->regs[ECSPI_STATREG] |= ECSPI_STATREG_TC;
|
||||
}
|
||||
|
||||
/* TODO: We should also use TDR and RDR bits */
|
||||
|
||||
DPRINTF("End: TX Fifo Size = %d, RX Fifo Size = %d\n",
|
||||
fifo32_num_used(&s->tx_fifo), fifo32_num_used(&s->rx_fifo));
|
||||
}
|
||||
|
||||
static void imx_spi_reset(DeviceState *dev)
|
||||
{
|
||||
IMXSPIState *s = IMX_SPI(dev);
|
||||
|
||||
DPRINTF("\n");
|
||||
|
||||
memset(s->regs, 0, sizeof(s->regs));
|
||||
|
||||
s->regs[ECSPI_STATREG] = 0x00000003;
|
||||
|
||||
imx_spi_rxfifo_reset(s);
|
||||
imx_spi_txfifo_reset(s);
|
||||
|
||||
imx_spi_update_irq(s);
|
||||
|
||||
s->burst_length = 0;
|
||||
}
|
||||
|
||||
static uint64_t imx_spi_read(void *opaque, hwaddr offset, unsigned size)
|
||||
{
|
||||
uint32_t value = 0;
|
||||
IMXSPIState *s = opaque;
|
||||
uint32_t index = offset >> 2;
|
||||
|
||||
if (index >= ECSPI_MAX) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%"
|
||||
HWADDR_PRIx "\n", TYPE_IMX_SPI, __func__, offset);
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (index) {
|
||||
case ECSPI_RXDATA:
|
||||
if (!imx_spi_is_enabled(s)) {
|
||||
value = 0;
|
||||
} else if (fifo32_is_empty(&s->rx_fifo)) {
|
||||
/* value is undefined */
|
||||
value = 0xdeadbeef;
|
||||
} else {
|
||||
/* read from the RX FIFO */
|
||||
value = fifo32_pop(&s->rx_fifo);
|
||||
}
|
||||
|
||||
break;
|
||||
case ECSPI_TXDATA:
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Trying to read from TX FIFO\n",
|
||||
TYPE_IMX_SPI, __func__);
|
||||
|
||||
/* Reading from TXDATA gives 0 */
|
||||
|
||||
break;
|
||||
case ECSPI_MSGDATA:
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Trying to read from MSG FIFO\n",
|
||||
TYPE_IMX_SPI, __func__);
|
||||
|
||||
/* Reading from MSGDATA gives 0 */
|
||||
|
||||
break;
|
||||
default:
|
||||
value = s->regs[index];
|
||||
break;
|
||||
}
|
||||
|
||||
DPRINTF("reg[%s] => 0x%" PRIx32 "\n", imx_spi_reg_name(index), value);
|
||||
|
||||
imx_spi_update_irq(s);
|
||||
|
||||
return (uint64_t)value;
|
||||
}
|
||||
|
||||
static void imx_spi_write(void *opaque, hwaddr offset, uint64_t value,
|
||||
unsigned size)
|
||||
{
|
||||
IMXSPIState *s = opaque;
|
||||
uint32_t index = offset >> 2;
|
||||
uint32_t change_mask;
|
||||
|
||||
if (index >= ECSPI_MAX) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%"
|
||||
HWADDR_PRIx "\n", TYPE_IMX_SPI, __func__, offset);
|
||||
return;
|
||||
}
|
||||
|
||||
DPRINTF("reg[%s] <= 0x%" PRIx32 "\n", imx_spi_reg_name(index),
|
||||
(uint32_t)value);
|
||||
|
||||
change_mask = s->regs[index] ^ value;
|
||||
|
||||
switch (index) {
|
||||
case ECSPI_RXDATA:
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Trying to write to RX FIFO\n",
|
||||
TYPE_IMX_SPI, __func__);
|
||||
break;
|
||||
case ECSPI_TXDATA:
|
||||
case ECSPI_MSGDATA:
|
||||
/* Is there any difference between TXDATA and MSGDATA ? */
|
||||
/* I'll have to look in the linux driver */
|
||||
if (!imx_spi_is_enabled(s)) {
|
||||
/* Ignore writes if device is disabled */
|
||||
break;
|
||||
} else if (fifo32_is_full(&s->tx_fifo)) {
|
||||
/* Ignore writes if queue is full */
|
||||
break;
|
||||
}
|
||||
|
||||
fifo32_push(&s->tx_fifo, (uint32_t)value);
|
||||
|
||||
if (imx_spi_channel_is_master(s) &&
|
||||
(s->regs[ECSPI_CONREG] & ECSPI_CONREG_SMC)) {
|
||||
/*
|
||||
* Start emitting if current channel is master and SMC bit is
|
||||
* set.
|
||||
*/
|
||||
imx_spi_flush_txfifo(s);
|
||||
}
|
||||
|
||||
break;
|
||||
case ECSPI_STATREG:
|
||||
/* the RO and TC bits are write-one-to-clear */
|
||||
value &= ECSPI_STATREG_RO | ECSPI_STATREG_TC;
|
||||
s->regs[ECSPI_STATREG] &= ~value;
|
||||
|
||||
break;
|
||||
case ECSPI_CONREG:
|
||||
s->regs[ECSPI_CONREG] = value;
|
||||
|
||||
if (!imx_spi_is_enabled(s)) {
|
||||
/* device is disabled, so this is a reset */
|
||||
imx_spi_reset(DEVICE(s));
|
||||
return;
|
||||
}
|
||||
|
||||
if (imx_spi_channel_is_master(s)) {
|
||||
int i;
|
||||
|
||||
/* We are in master mode */
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
qemu_set_irq(s->cs_lines[i],
|
||||
i == imx_spi_selected_channel(s) ? 0 : 1);
|
||||
}
|
||||
|
||||
if ((value & change_mask & ECSPI_CONREG_SMC) &&
|
||||
!fifo32_is_empty(&s->tx_fifo)) {
|
||||
/* SMC bit is set and TX FIFO has some slots filled in */
|
||||
imx_spi_flush_txfifo(s);
|
||||
} else if ((value & change_mask & ECSPI_CONREG_XCH) &&
|
||||
!(value & ECSPI_CONREG_SMC)) {
|
||||
/* This is a request to start emitting */
|
||||
imx_spi_flush_txfifo(s);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
s->regs[index] = value;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
imx_spi_update_irq(s);
|
||||
}
|
||||
|
||||
static const struct MemoryRegionOps imx_spi_ops = {
|
||||
.read = imx_spi_read,
|
||||
.write = imx_spi_write,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
.valid = {
|
||||
/*
|
||||
* Our device would not work correctly if the guest was doing
|
||||
* unaligned access. This might not be a limitation on the real
|
||||
* device but in practice there is no reason for a guest to access
|
||||
* this device unaligned.
|
||||
*/
|
||||
.min_access_size = 4,
|
||||
.max_access_size = 4,
|
||||
.unaligned = false,
|
||||
},
|
||||
};
|
||||
|
||||
static void imx_spi_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
IMXSPIState *s = IMX_SPI(dev);
|
||||
int i;
|
||||
|
||||
s->bus = ssi_create_bus(dev, "spi");
|
||||
|
||||
memory_region_init_io(&s->iomem, OBJECT(dev), &imx_spi_ops, s,
|
||||
TYPE_IMX_SPI, 0x1000);
|
||||
sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
|
||||
sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq);
|
||||
|
||||
ssi_auto_connect_slaves(dev, s->cs_lines, s->bus);
|
||||
|
||||
for (i = 0; i < 4; ++i) {
|
||||
sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->cs_lines[i]);
|
||||
}
|
||||
|
||||
s->burst_length = 0;
|
||||
|
||||
fifo32_create(&s->tx_fifo, ECSPI_FIFO_SIZE);
|
||||
fifo32_create(&s->rx_fifo, ECSPI_FIFO_SIZE);
|
||||
}
|
||||
|
||||
static void imx_spi_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->realize = imx_spi_realize;
|
||||
dc->vmsd = &vmstate_imx_spi;
|
||||
dc->reset = imx_spi_reset;
|
||||
dc->desc = "i.MX SPI Controller";
|
||||
}
|
||||
|
||||
static const TypeInfo imx_spi_info = {
|
||||
.name = TYPE_IMX_SPI,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(IMXSPIState),
|
||||
.class_init = imx_spi_class_init,
|
||||
};
|
||||
|
||||
static void imx_spi_register_types(void)
|
||||
{
|
||||
type_register_static(&imx_spi_info);
|
||||
}
|
||||
|
||||
type_init(imx_spi_register_types)
|
|
@ -5,14 +5,13 @@
|
|||
|
||||
/* Helpers for instruction counting code generation. */
|
||||
|
||||
static TCGArg *icount_arg;
|
||||
static int icount_start_insn_idx;
|
||||
static TCGLabel *icount_label;
|
||||
static TCGLabel *exitreq_label;
|
||||
|
||||
static inline void gen_tb_start(TranslationBlock *tb)
|
||||
{
|
||||
TCGv_i32 count, flag, imm;
|
||||
int i;
|
||||
|
||||
exitreq_label = gen_new_label();
|
||||
flag = tcg_temp_new_i32();
|
||||
|
@ -31,13 +30,12 @@ static inline void gen_tb_start(TranslationBlock *tb)
|
|||
-ENV_OFFSET + offsetof(CPUState, icount_decr.u32));
|
||||
|
||||
imm = tcg_temp_new_i32();
|
||||
/* We emit a movi with a dummy immediate argument. Keep the insn index
|
||||
* of the movi so that we later (when we know the actual insn count)
|
||||
* can update the immediate argument with the actual insn count. */
|
||||
icount_start_insn_idx = tcg_op_buf_count();
|
||||
tcg_gen_movi_i32(imm, 0xdeadbeef);
|
||||
|
||||
/* This is a horrid hack to allow fixing up the value later. */
|
||||
i = tcg_ctx.gen_last_op_idx;
|
||||
i = tcg_ctx.gen_op_buf[i].args;
|
||||
icount_arg = &tcg_ctx.gen_opparam_buf[i + 1];
|
||||
|
||||
tcg_gen_sub_i32(count, count, imm);
|
||||
tcg_temp_free_i32(imm);
|
||||
|
||||
|
@ -53,7 +51,9 @@ static void gen_tb_end(TranslationBlock *tb, int num_insns)
|
|||
tcg_gen_exit_tb((uintptr_t)tb + TB_EXIT_REQUESTED);
|
||||
|
||||
if (tb->cflags & CF_USE_ICOUNT) {
|
||||
*icount_arg = num_insns;
|
||||
/* Update the num_insn immediate parameter now that we know
|
||||
* the actual insn count. */
|
||||
tcg_set_insn_param(icount_start_insn_idx, 1, num_insns);
|
||||
gen_set_label(icount_label);
|
||||
tcg_gen_exit_tb((uintptr_t)tb + TB_EXIT_ICOUNT_EXPIRED);
|
||||
}
|
||||
|
|
|
@ -455,8 +455,10 @@ struct AcpiSystemResourceAffinityTable
|
|||
} QEMU_PACKED;
|
||||
typedef struct AcpiSystemResourceAffinityTable AcpiSystemResourceAffinityTable;
|
||||
|
||||
#define ACPI_SRAT_PROCESSOR 0
|
||||
#define ACPI_SRAT_PROCESSOR_APIC 0
|
||||
#define ACPI_SRAT_MEMORY 1
|
||||
#define ACPI_SRAT_PROCESSOR_x2APIC 2
|
||||
#define ACPI_SRAT_PROCESSOR_GICC 3
|
||||
|
||||
struct AcpiSratProcessorAffinity
|
||||
{
|
||||
|
@ -473,7 +475,7 @@ typedef struct AcpiSratProcessorAffinity AcpiSratProcessorAffinity;
|
|||
struct AcpiSratMemoryAffinity
|
||||
{
|
||||
ACPI_SUB_HEADER_DEF
|
||||
uint8_t proximity[4];
|
||||
uint32_t proximity;
|
||||
uint16_t reserved1;
|
||||
uint64_t base_addr;
|
||||
uint64_t range_length;
|
||||
|
@ -483,6 +485,17 @@ struct AcpiSratMemoryAffinity
|
|||
} QEMU_PACKED;
|
||||
typedef struct AcpiSratMemoryAffinity AcpiSratMemoryAffinity;
|
||||
|
||||
struct AcpiSratProcessorGiccAffinity
|
||||
{
|
||||
ACPI_SUB_HEADER_DEF
|
||||
uint32_t proximity;
|
||||
uint32_t acpi_processor_uid;
|
||||
uint32_t flags;
|
||||
uint32_t clock_domain;
|
||||
} QEMU_PACKED;
|
||||
|
||||
typedef struct AcpiSratProcessorGiccAffinity AcpiSratProcessorGiccAffinity;
|
||||
|
||||
/* PCI fw r3.0 MCFG table. */
|
||||
/* Subtable */
|
||||
struct AcpiMcfgAllocation {
|
||||
|
|
|
@ -198,6 +198,13 @@ typedef enum {
|
|||
AML_PULL_NONE = 3,
|
||||
} AmlPinConfig;
|
||||
|
||||
typedef enum {
|
||||
MEM_AFFINITY_NOFLAGS = 0,
|
||||
MEM_AFFINITY_ENABLED = (1 << 0),
|
||||
MEM_AFFINITY_HOTPLUGGABLE = (1 << 1),
|
||||
MEM_AFFINITY_NON_VOLATILE = (1 << 2),
|
||||
} MemoryAffinityFlags;
|
||||
|
||||
typedef
|
||||
struct AcpiBuildTables {
|
||||
GArray *table_data;
|
||||
|
@ -372,4 +379,7 @@ int
|
|||
build_append_named_dword(GArray *array, const char *name_format, ...)
|
||||
GCC_FMT_ATTR(2, 3);
|
||||
|
||||
void build_srat_memory(AcpiSratMemoryAffinity *numamem, uint64_t base,
|
||||
uint64_t len, int node, MemoryAffinityFlags flags);
|
||||
|
||||
#endif
|
||||
|
|
450
include/hw/arm/fsl-imx6.h
Normal file
450
include/hw/arm/fsl-imx6.h
Normal file
|
@ -0,0 +1,450 @@
|
|||
/*
|
||||
* Freescale i.MX31 SoC emulation
|
||||
*
|
||||
* Copyright (C) 2015 Jean-Christophe Dubois <jcd@tribudubois.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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 FSL_IMX6_H
|
||||
#define FSL_IMX6_H
|
||||
|
||||
#include "hw/arm/arm.h"
|
||||
#include "hw/cpu/a9mpcore.h"
|
||||
#include "hw/misc/imx6_ccm.h"
|
||||
#include "hw/misc/imx6_src.h"
|
||||
#include "hw/char/imx_serial.h"
|
||||
#include "hw/timer/imx_gpt.h"
|
||||
#include "hw/timer/imx_epit.h"
|
||||
#include "hw/i2c/imx_i2c.h"
|
||||
#include "hw/gpio/imx_gpio.h"
|
||||
#include "hw/sd/sdhci.h"
|
||||
#include "hw/ssi/imx_spi.h"
|
||||
#include "exec/memory.h"
|
||||
|
||||
#define TYPE_FSL_IMX6 "fsl,imx6"
|
||||
#define FSL_IMX6(obj) OBJECT_CHECK(FslIMX6State, (obj), TYPE_FSL_IMX6)
|
||||
|
||||
#define FSL_IMX6_NUM_CPUS 4
|
||||
#define FSL_IMX6_NUM_UARTS 5
|
||||
#define FSL_IMX6_NUM_EPITS 2
|
||||
#define FSL_IMX6_NUM_I2CS 3
|
||||
#define FSL_IMX6_NUM_GPIOS 7
|
||||
#define FSL_IMX6_NUM_ESDHCS 4
|
||||
#define FSL_IMX6_NUM_ECSPIS 5
|
||||
|
||||
typedef struct FslIMX6State {
|
||||
/*< private >*/
|
||||
DeviceState parent_obj;
|
||||
|
||||
/*< public >*/
|
||||
ARMCPU cpu[FSL_IMX6_NUM_CPUS];
|
||||
A9MPPrivState a9mpcore;
|
||||
IMX6CCMState ccm;
|
||||
IMX6SRCState src;
|
||||
IMXSerialState uart[FSL_IMX6_NUM_UARTS];
|
||||
IMXGPTState gpt;
|
||||
IMXEPITState epit[FSL_IMX6_NUM_EPITS];
|
||||
IMXI2CState i2c[FSL_IMX6_NUM_I2CS];
|
||||
IMXGPIOState gpio[FSL_IMX6_NUM_GPIOS];
|
||||
SDHCIState esdhc[FSL_IMX6_NUM_ESDHCS];
|
||||
IMXSPIState spi[FSL_IMX6_NUM_ECSPIS];
|
||||
MemoryRegion rom;
|
||||
MemoryRegion caam;
|
||||
MemoryRegion ocram;
|
||||
MemoryRegion ocram_alias;
|
||||
} FslIMX6State;
|
||||
|
||||
|
||||
#define FSL_IMX6_MMDC_ADDR 0x10000000
|
||||
#define FSL_IMX6_MMDC_SIZE 0xF0000000
|
||||
#define FSL_IMX6_EIM_MEM_ADDR 0x08000000
|
||||
#define FSL_IMX6_EIM_MEM_SIZE 0x8000000
|
||||
#define FSL_IMX6_IPU_2_ADDR 0x02800000
|
||||
#define FSL_IMX6_IPU_2_SIZE 0x400000
|
||||
#define FSL_IMX6_IPU_1_ADDR 0x02400000
|
||||
#define FSL_IMX6_IPU_1_SIZE 0x400000
|
||||
#define FSL_IMX6_MIPI_HSI_ADDR 0x02208000
|
||||
#define FSL_IMX6_MIPI_HSI_SIZE 0x4000
|
||||
#define FSL_IMX6_OPENVG_ADDR 0x02204000
|
||||
#define FSL_IMX6_OPENVG_SIZE 0x4000
|
||||
#define FSL_IMX6_SATA_ADDR 0x02200000
|
||||
#define FSL_IMX6_SATA_SIZE 0x4000
|
||||
#define FSL_IMX6_AIPS_2_ADDR 0x02100000
|
||||
#define FSL_IMX6_AIPS_2_SIZE 0x100000
|
||||
/* AIPS2 */
|
||||
#define FSL_IMX6_UART5_ADDR 0x021F4000
|
||||
#define FSL_IMX6_UART5_SIZE 0x4000
|
||||
#define FSL_IMX6_UART4_ADDR 0x021F0000
|
||||
#define FSL_IMX6_UART4_SIZE 0x4000
|
||||
#define FSL_IMX6_UART3_ADDR 0x021EC000
|
||||
#define FSL_IMX6_UART3_SIZE 0x4000
|
||||
#define FSL_IMX6_UART2_ADDR 0x021E8000
|
||||
#define FSL_IMX6_UART2_SIZE 0x4000
|
||||
#define FSL_IMX6_VDOA_ADDR 0x021E4000
|
||||
#define FSL_IMX6_VDOA_SIZE 0x4000
|
||||
#define FSL_IMX6_MIPI_DSI_ADDR 0x021E0000
|
||||
#define FSL_IMX6_MIPI_DSI_SIZE 0x4000
|
||||
#define FSL_IMX6_MIPI_CSI_ADDR 0x021DC000
|
||||
#define FSL_IMX6_MIPI_CSI_SIZE 0x4000
|
||||
#define FSL_IMX6_AUDMUX_ADDR 0x021D8000
|
||||
#define FSL_IMX6_AUDMUX_SIZE 0x4000
|
||||
#define FSL_IMX6_TZASC2_ADDR 0x021D4000
|
||||
#define FSL_IMX6_TZASC2_SIZE 0x4000
|
||||
#define FSL_IMX6_TZASC1_ADDR 0x021D0000
|
||||
#define FSL_IMX6_TZASC1_SIZE 0x4000
|
||||
#define FSL_IMX6_CSU_ADDR 0x021C0000
|
||||
#define FSL_IMX6_CSU_SIZE 0x4000
|
||||
#define FSL_IMX6_OCOTPCTRL_ADDR 0x021BC000
|
||||
#define FSL_IMX6_OCOTPCTRL_SIZE 0x4000
|
||||
#define FSL_IMX6_EIM_ADDR 0x021B8000
|
||||
#define FSL_IMX6_EIM_SIZE 0x4000
|
||||
#define FSL_IMX6_MMDC1_ADDR 0x021B4000
|
||||
#define FSL_IMX6_MMDC1_SIZE 0x4000
|
||||
#define FSL_IMX6_MMDC0_ADDR 0x021B0000
|
||||
#define FSL_IMX6_MMDC0_SIZE 0x4000
|
||||
#define FSL_IMX6_ROMCP_ADDR 0x021AC000
|
||||
#define FSL_IMX6_ROMCP_SIZE 0x4000
|
||||
#define FSL_IMX6_I2C3_ADDR 0x021A8000
|
||||
#define FSL_IMX6_I2C3_SIZE 0x4000
|
||||
#define FSL_IMX6_I2C2_ADDR 0x021A4000
|
||||
#define FSL_IMX6_I2C2_SIZE 0x4000
|
||||
#define FSL_IMX6_I2C1_ADDR 0x021A0000
|
||||
#define FSL_IMX6_I2C1_SIZE 0x4000
|
||||
#define FSL_IMX6_uSDHC4_ADDR 0x0219C000
|
||||
#define FSL_IMX6_uSDHC4_SIZE 0x4000
|
||||
#define FSL_IMX6_uSDHC3_ADDR 0x02198000
|
||||
#define FSL_IMX6_uSDHC3_SIZE 0x4000
|
||||
#define FSL_IMX6_uSDHC2_ADDR 0x02194000
|
||||
#define FSL_IMX6_uSDHC2_SIZE 0x4000
|
||||
#define FSL_IMX6_uSDHC1_ADDR 0x02190000
|
||||
#define FSL_IMX6_uSDHC1_SIZE 0x4000
|
||||
#define FSL_IMX6_MLB150_ADDR 0x0218C000
|
||||
#define FSL_IMX6_MLB150_SIZE 0x4000
|
||||
#define FSL_IMX6_ENET_ADDR 0x02188000
|
||||
#define FSL_IMX6_ENET_SIZE 0x4000
|
||||
#define FSL_IMX6_USBOH3_USB_ADDR 0x02184000
|
||||
#define FSL_IMX6_USBOH3_USB_SIZE 0x4000
|
||||
#define FSL_IMX6_AIPS2_CFG_ADDR 0x0217C000
|
||||
#define FSL_IMX6_AIPS2_CFG_SIZE 0x4000
|
||||
/* DAP */
|
||||
#define FSL_IMX6_PTF_CTRL_ADDR 0x02160000
|
||||
#define FSL_IMX6_PTF_CTRL_SIZE 0x1000
|
||||
#define FSL_IMX6_PTM3_ADDR 0x0215F000
|
||||
#define FSL_IMX6_PTM3_SIZE 0x1000
|
||||
#define FSL_IMX6_PTM2_ADDR 0x0215E000
|
||||
#define FSL_IMX6_PTM2_SIZE 0x1000
|
||||
#define FSL_IMX6_PTM1_ADDR 0x0215D000
|
||||
#define FSL_IMX6_PTM1_SIZE 0x1000
|
||||
#define FSL_IMX6_PTM0_ADDR 0x0215C000
|
||||
#define FSL_IMX6_PTM0_SIZE 0x1000
|
||||
#define FSL_IMX6_CTI3_ADDR 0x0215B000
|
||||
#define FSL_IMX6_CTI3_SIZE 0x1000
|
||||
#define FSL_IMX6_CTI2_ADDR 0x0215A000
|
||||
#define FSL_IMX6_CTI2_SIZE 0x1000
|
||||
#define FSL_IMX6_CTI1_ADDR 0x02159000
|
||||
#define FSL_IMX6_CTI1_SIZE 0x1000
|
||||
#define FSL_IMX6_CTI0_ADDR 0x02158000
|
||||
#define FSL_IMX6_CTI0_SIZE 0x1000
|
||||
#define FSL_IMX6_CPU3_PMU_ADDR 0x02157000
|
||||
#define FSL_IMX6_CPU3_PMU_SIZE 0x1000
|
||||
#define FSL_IMX6_CPU3_DEBUG_IF_ADDR 0x02156000
|
||||
#define FSL_IMX6_CPU3_DEBUG_IF_SIZE 0x1000
|
||||
#define FSL_IMX6_CPU2_PMU_ADDR 0x02155000
|
||||
#define FSL_IMX6_CPU2_PMU_SIZE 0x1000
|
||||
#define FSL_IMX6_CPU2_DEBUG_IF_ADDR 0x02154000
|
||||
#define FSL_IMX6_CPU2_DEBUG_IF_SIZE 0x1000
|
||||
#define FSL_IMX6_CPU1_PMU_ADDR 0x02153000
|
||||
#define FSL_IMX6_CPU1_PMU_SIZE 0x1000
|
||||
#define FSL_IMX6_CPU1_DEBUG_IF_ADDR 0x02152000
|
||||
#define FSL_IMX6_CPU1_DEBUG_IF_SIZE 0x1000
|
||||
#define FSL_IMX6_CPU0_PMU_ADDR 0x02151000
|
||||
#define FSL_IMX6_CPU0_PMU_SIZE 0x1000
|
||||
#define FSL_IMX6_CPU0_DEBUG_IF_ADDR 0x02150000
|
||||
#define FSL_IMX6_CPU0_DEBUG_IF_SIZE 0x1000
|
||||
#define FSL_IMX6_CA9_INTEG_ADDR 0x0214F000
|
||||
#define FSL_IMX6_CA9_INTEG_SIZE 0x1000
|
||||
#define FSL_IMX6_FUNNEL_ADDR 0x02144000
|
||||
#define FSL_IMX6_FUNNEL_SIZE 0x1000
|
||||
#define FSL_IMX6_TPIU_ADDR 0x02143000
|
||||
#define FSL_IMX6_TPIU_SIZE 0x1000
|
||||
#define FSL_IMX6_EXT_CTI_ADDR 0x02142000
|
||||
#define FSL_IMX6_EXT_CTI_SIZE 0x1000
|
||||
#define FSL_IMX6_ETB_ADDR 0x02141000
|
||||
#define FSL_IMX6_ETB_SIZE 0x1000
|
||||
#define FSL_IMX6_DAP_ROM_TABLE_ADDR 0x02140000
|
||||
#define FSL_IMX6_DAP_ROM_TABLE_SIZE 0x1000
|
||||
/* DAP end */
|
||||
#define FSL_IMX6_CAAM_ADDR 0x02100000
|
||||
#define FSL_IMX6_CAAM_SIZE 0x10000
|
||||
/* AIPS2 end */
|
||||
#define FSL_IMX6_AIPS_1_ADDR 0x02000000
|
||||
#define FSL_IMX6_AIPS_1_SIZE 0x100000
|
||||
/* AIPS1 */
|
||||
#define FSL_IMX6_SDMA_ADDR 0x020EC000
|
||||
#define FSL_IMX6_SDMA_SIZE 0x4000
|
||||
#define FSL_IMX6_DCIC2_ADDR 0x020E8000
|
||||
#define FSL_IMX6_DCIC2_SIZE 0x4000
|
||||
#define FSL_IMX6_DCIC1_ADDR 0x020E4000
|
||||
#define FSL_IMX6_DCIC1_SIZE 0x4000
|
||||
#define FSL_IMX6_IOMUXC_ADDR 0x020E0000
|
||||
#define FSL_IMX6_IOMUXC_SIZE 0x4000
|
||||
#define FSL_IMX6_PGCARM_ADDR 0x020DCA00
|
||||
#define FSL_IMX6_PGCARM_SIZE 0x20
|
||||
#define FSL_IMX6_PGCPU_ADDR 0x020DC260
|
||||
#define FSL_IMX6_PGCPU_SIZE 0x20
|
||||
#define FSL_IMX6_GPC_ADDR 0x020DC000
|
||||
#define FSL_IMX6_GPC_SIZE 0x4000
|
||||
#define FSL_IMX6_SRC_ADDR 0x020D8000
|
||||
#define FSL_IMX6_SRC_SIZE 0x4000
|
||||
#define FSL_IMX6_EPIT2_ADDR 0x020D4000
|
||||
#define FSL_IMX6_EPIT2_SIZE 0x4000
|
||||
#define FSL_IMX6_EPIT1_ADDR 0x020D0000
|
||||
#define FSL_IMX6_EPIT1_SIZE 0x4000
|
||||
#define FSL_IMX6_SNVSHP_ADDR 0x020CC000
|
||||
#define FSL_IMX6_SNVSHP_SIZE 0x4000
|
||||
#define FSL_IMX6_USBPHY2_ADDR 0x020CA000
|
||||
#define FSL_IMX6_USBPHY2_SIZE 0x1000
|
||||
#define FSL_IMX6_USBPHY1_ADDR 0x020C9000
|
||||
#define FSL_IMX6_USBPHY1_SIZE 0x1000
|
||||
#define FSL_IMX6_ANALOG_ADDR 0x020C8000
|
||||
#define FSL_IMX6_ANALOG_SIZE 0x1000
|
||||
#define FSL_IMX6_CCM_ADDR 0x020C4000
|
||||
#define FSL_IMX6_CCM_SIZE 0x4000
|
||||
#define FSL_IMX6_WDOG2_ADDR 0x020C0000
|
||||
#define FSL_IMX6_WDOG2_SIZE 0x4000
|
||||
#define FSL_IMX6_WDOG1_ADDR 0x020BC000
|
||||
#define FSL_IMX6_WDOG1_SIZE 0x4000
|
||||
#define FSL_IMX6_KPP_ADDR 0x020B8000
|
||||
#define FSL_IMX6_KPP_SIZE 0x4000
|
||||
#define FSL_IMX6_GPIO7_ADDR 0x020B4000
|
||||
#define FSL_IMX6_GPIO7_SIZE 0x4000
|
||||
#define FSL_IMX6_GPIO6_ADDR 0x020B0000
|
||||
#define FSL_IMX6_GPIO6_SIZE 0x4000
|
||||
#define FSL_IMX6_GPIO5_ADDR 0x020AC000
|
||||
#define FSL_IMX6_GPIO5_SIZE 0x4000
|
||||
#define FSL_IMX6_GPIO4_ADDR 0x020A8000
|
||||
#define FSL_IMX6_GPIO4_SIZE 0x4000
|
||||
#define FSL_IMX6_GPIO3_ADDR 0x020A4000
|
||||
#define FSL_IMX6_GPIO3_SIZE 0x4000
|
||||
#define FSL_IMX6_GPIO2_ADDR 0x020A0000
|
||||
#define FSL_IMX6_GPIO2_SIZE 0x4000
|
||||
#define FSL_IMX6_GPIO1_ADDR 0x0209C000
|
||||
#define FSL_IMX6_GPIO1_SIZE 0x4000
|
||||
#define FSL_IMX6_GPT_ADDR 0x02098000
|
||||
#define FSL_IMX6_GPT_SIZE 0x4000
|
||||
#define FSL_IMX6_CAN2_ADDR 0x02094000
|
||||
#define FSL_IMX6_CAN2_SIZE 0x4000
|
||||
#define FSL_IMX6_CAN1_ADDR 0x02090000
|
||||
#define FSL_IMX6_CAN1_SIZE 0x4000
|
||||
#define FSL_IMX6_PWM4_ADDR 0x0208C000
|
||||
#define FSL_IMX6_PWM4_SIZE 0x4000
|
||||
#define FSL_IMX6_PWM3_ADDR 0x02088000
|
||||
#define FSL_IMX6_PWM3_SIZE 0x4000
|
||||
#define FSL_IMX6_PWM2_ADDR 0x02084000
|
||||
#define FSL_IMX6_PWM2_SIZE 0x4000
|
||||
#define FSL_IMX6_PWM1_ADDR 0x02080000
|
||||
#define FSL_IMX6_PWM1_SIZE 0x4000
|
||||
#define FSL_IMX6_AIPS1_CFG_ADDR 0x0207C000
|
||||
#define FSL_IMX6_AIPS1_CFG_SIZE 0x4000
|
||||
#define FSL_IMX6_VPU_ADDR 0x02040000
|
||||
#define FSL_IMX6_VPU_SIZE 0x3C000
|
||||
#define FSL_IMX6_AIPS1_SPBA_ADDR 0x0203C000
|
||||
#define FSL_IMX6_AIPS1_SPBA_SIZE 0x4000
|
||||
#define FSL_IMX6_ASRC_ADDR 0x02034000
|
||||
#define FSL_IMX6_ASRC_SIZE 0x4000
|
||||
#define FSL_IMX6_SSI3_ADDR 0x02030000
|
||||
#define FSL_IMX6_SSI3_SIZE 0x4000
|
||||
#define FSL_IMX6_SSI2_ADDR 0x0202C000
|
||||
#define FSL_IMX6_SSI2_SIZE 0x4000
|
||||
#define FSL_IMX6_SSI1_ADDR 0x02028000
|
||||
#define FSL_IMX6_SSI1_SIZE 0x4000
|
||||
#define FSL_IMX6_ESAI_ADDR 0x02024000
|
||||
#define FSL_IMX6_ESAI_SIZE 0x4000
|
||||
#define FSL_IMX6_UART1_ADDR 0x02020000
|
||||
#define FSL_IMX6_UART1_SIZE 0x4000
|
||||
#define FSL_IMX6_eCSPI5_ADDR 0x02018000
|
||||
#define FSL_IMX6_eCSPI5_SIZE 0x4000
|
||||
#define FSL_IMX6_eCSPI4_ADDR 0x02014000
|
||||
#define FSL_IMX6_eCSPI4_SIZE 0x4000
|
||||
#define FSL_IMX6_eCSPI3_ADDR 0x02010000
|
||||
#define FSL_IMX6_eCSPI3_SIZE 0x4000
|
||||
#define FSL_IMX6_eCSPI2_ADDR 0x0200C000
|
||||
#define FSL_IMX6_eCSPI2_SIZE 0x4000
|
||||
#define FSL_IMX6_eCSPI1_ADDR 0x02008000
|
||||
#define FSL_IMX6_eCSPI1_SIZE 0x4000
|
||||
#define FSL_IMX6_SPDIF_ADDR 0x02004000
|
||||
#define FSL_IMX6_SPDIF_SIZE 0x4000
|
||||
/* AIPS1 end */
|
||||
#define FSL_IMX6_PCIe_REG_ADDR 0x01FFC000
|
||||
#define FSL_IMX6_PCIe_REG_SIZE 0x4000
|
||||
#define FSL_IMX6_PCIe_ADDR 0x01000000
|
||||
#define FSL_IMX6_PCIe_SIZE 0xFFC000
|
||||
#define FSL_IMX6_GPV_1_PL301_CFG_ADDR 0x00C00000
|
||||
#define FSL_IMX6_GPV_1_PL301_CFG_SIZE 0x100000
|
||||
#define FSL_IMX6_GPV_0_PL301_CFG_ADDR 0x00B00000
|
||||
#define FSL_IMX6_GPV_0_PL301_CFG_SIZE 0x100000
|
||||
#define FSL_IMX6_PL310_ADDR 0x00A02000
|
||||
#define FSL_IMX6_PL310_SIZE 0x1000
|
||||
#define FSL_IMX6_A9MPCORE_ADDR 0x00A00000
|
||||
#define FSL_IMX6_A9MPCORE_SIZE 0x2000
|
||||
#define FSL_IMX6_OCRAM_ALIAS_ADDR 0x00940000
|
||||
#define FSL_IMX6_OCRAM_ALIAS_SIZE 0xC0000
|
||||
#define FSL_IMX6_OCRAM_ADDR 0x00900000
|
||||
#define FSL_IMX6_OCRAM_SIZE 0x40000
|
||||
#define FSL_IMX6_GPV_4_PL301_CFG_ADDR 0x00800000
|
||||
#define FSL_IMX6_GPV_4_PL301_CFG_SIZE 0x100000
|
||||
#define FSL_IMX6_GPV_3_PL301_CFG_ADDR 0x00300000
|
||||
#define FSL_IMX6_GPV_3_PL301_CFG_SIZE 0x100000
|
||||
#define FSL_IMX6_GPV_2_PL301_CFG_ADDR 0x00200000
|
||||
#define FSL_IMX6_GPV_2_PL301_CFG_SIZE 0x100000
|
||||
#define FSL_IMX6_DTCP_ADDR 0x00138000
|
||||
#define FSL_IMX6_DTCP_SIZE 0x4000
|
||||
#define FSL_IMX6_GPU_2D_ADDR 0x00134000
|
||||
#define FSL_IMX6_GPU_2D_SIZE 0x4000
|
||||
#define FSL_IMX6_GPU_3D_ADDR 0x00130000
|
||||
#define FSL_IMX6_GPU_3D_SIZE 0x4000
|
||||
#define FSL_IMX6_HDMI_ADDR 0x00120000
|
||||
#define FSL_IMX6_HDMI_SIZE 0x9000
|
||||
#define FSL_IMX6_BCH_ADDR 0x00114000
|
||||
#define FSL_IMX6_BCH_SIZE 0x4000
|
||||
#define FSL_IMX6_GPMI_ADDR 0x00112000
|
||||
#define FSL_IMX6_GPMI_SIZE 0x2000
|
||||
#define FSL_IMX6_APBH_BRIDGE_DMA_ADDR 0x00110000
|
||||
#define FSL_IMX6_APBH_BRIDGE_DMA_SIZE 0x2000
|
||||
#define FSL_IMX6_CAAM_MEM_ADDR 0x00100000
|
||||
#define FSL_IMX6_CAAM_MEM_SIZE 0x4000
|
||||
#define FSL_IMX6_ROM_ADDR 0x00000000
|
||||
#define FSL_IMX6_ROM_SIZE 0x18000
|
||||
|
||||
#define FSL_IMX6_IOMUXC_IRQ 0
|
||||
#define FSL_IMX6_DAP_IRQ 1
|
||||
#define FSL_IMX6_SDMA_IRQ 2
|
||||
#define FSL_IMX6_VPU_JPEG_IRQ 3
|
||||
#define FSL_IMX6_SNVS_PMIC_IRQ 4
|
||||
#define FSL_IMX6_IPU1_ERROR_IRQ 5
|
||||
#define FSL_IMX6_IPU1_SYNC_IRQ 6
|
||||
#define FSL_IMX6_IPU2_ERROR_IRQ 7
|
||||
#define FSL_IMX6_IPU2_SYNC_IRQ 8
|
||||
#define FSL_IMX6_GPU3D_IRQ 9
|
||||
#define FSL_IMX6_R2D_IRQ 10
|
||||
#define FSL_IMX6_V2D_IRQ 11
|
||||
#define FSL_IMX6_VPU_IRQ 12
|
||||
#define FSL_IMX6_APBH_BRIDGE_DMA_IRQ 13
|
||||
#define FSL_IMX6_EIM_IRQ 14
|
||||
#define FSL_IMX6_BCH_IRQ 15
|
||||
#define FSL_IMX6_GPMI_IRQ 16
|
||||
#define FSL_IMX6_DTCP_IRQ 17
|
||||
#define FSL_IMX6_VDOA_IRQ 18
|
||||
#define FSL_IMX6_SNVS_CONS_IRQ 19
|
||||
#define FSL_IMX6_SNVS_SEC_IRQ 20
|
||||
#define FSL_IMX6_CSU_IRQ 21
|
||||
#define FSL_IMX6_uSDHC1_IRQ 22
|
||||
#define FSL_IMX6_uSDHC2_IRQ 23
|
||||
#define FSL_IMX6_uSDHC3_IRQ 24
|
||||
#define FSL_IMX6_uSDHC4_IRQ 25
|
||||
#define FSL_IMX6_UART1_IRQ 26
|
||||
#define FSL_IMX6_UART2_IRQ 27
|
||||
#define FSL_IMX6_UART3_IRQ 28
|
||||
#define FSL_IMX6_UART4_IRQ 29
|
||||
#define FSL_IMX6_UART5_IRQ 30
|
||||
#define FSL_IMX6_ECSPI1_IRQ 31
|
||||
#define FSL_IMX6_ECSPI2_IRQ 32
|
||||
#define FSL_IMX6_ECSPI3_IRQ 33
|
||||
#define FSL_IMX6_ECSPI4_IRQ 34
|
||||
#define FSL_IMX6_ECSPI5_IRQ 35
|
||||
#define FSL_IMX6_I2C1_IRQ 36
|
||||
#define FSL_IMX6_I2C2_IRQ 37
|
||||
#define FSL_IMX6_I2C3_IRQ 38
|
||||
#define FSL_IMX6_SATA_IRQ 39
|
||||
#define FSL_IMX6_USB_HOST1_IRQ 40
|
||||
#define FSL_IMX6_USB_HOST2_IRQ 41
|
||||
#define FSL_IMX6_USB_HOST3_IRQ 42
|
||||
#define FSL_IMX6_USB_OTG_IRQ 43
|
||||
#define FSL_IMX6_USB_PHY_UTMI0_IRQ 44
|
||||
#define FSL_IMX6_USB_PHY_UTMI1_IRQ 45
|
||||
#define FSL_IMX6_SSI1_IRQ 46
|
||||
#define FSL_IMX6_SSI2_IRQ 47
|
||||
#define FSL_IMX6_SSI3_IRQ 48
|
||||
#define FSL_IMX6_TEMP_IRQ 49
|
||||
#define FSL_IMX6_ASRC_IRQ 50
|
||||
#define FSL_IMX6_ESAI_IRQ 51
|
||||
#define FSL_IMX6_SPDIF_IRQ 52
|
||||
#define FSL_IMX6_MLB150_IRQ 53
|
||||
#define FSL_IMX6_PMU1_IRQ 54
|
||||
#define FSL_IMX6_GPT_IRQ 55
|
||||
#define FSL_IMX6_EPIT1_IRQ 56
|
||||
#define FSL_IMX6_EPIT2_IRQ 57
|
||||
#define FSL_IMX6_GPIO1_INT7_IRQ 58
|
||||
#define FSL_IMX6_GPIO1_INT6_IRQ 59
|
||||
#define FSL_IMX6_GPIO1_INT5_IRQ 60
|
||||
#define FSL_IMX6_GPIO1_INT4_IRQ 61
|
||||
#define FSL_IMX6_GPIO1_INT3_IRQ 62
|
||||
#define FSL_IMX6_GPIO1_INT2_IRQ 63
|
||||
#define FSL_IMX6_GPIO1_INT1_IRQ 64
|
||||
#define FSL_IMX6_GPIO1_INT0_IRQ 65
|
||||
#define FSL_IMX6_GPIO1_LOW_IRQ 66
|
||||
#define FSL_IMX6_GPIO1_HIGH_IRQ 67
|
||||
#define FSL_IMX6_GPIO2_LOW_IRQ 68
|
||||
#define FSL_IMX6_GPIO2_HIGH_IRQ 69
|
||||
#define FSL_IMX6_GPIO3_LOW_IRQ 70
|
||||
#define FSL_IMX6_GPIO3_HIGH_IRQ 71
|
||||
#define FSL_IMX6_GPIO4_LOW_IRQ 72
|
||||
#define FSL_IMX6_GPIO4_HIGH_IRQ 73
|
||||
#define FSL_IMX6_GPIO5_LOW_IRQ 74
|
||||
#define FSL_IMX6_GPIO5_HIGH_IRQ 75
|
||||
#define FSL_IMX6_GPIO6_LOW_IRQ 76
|
||||
#define FSL_IMX6_GPIO6_HIGH_IRQ 77
|
||||
#define FSL_IMX6_GPIO7_LOW_IRQ 78
|
||||
#define FSL_IMX6_GPIO7_HIGH_IRQ 79
|
||||
#define FSL_IMX6_WDOG1_IRQ 80
|
||||
#define FSL_IMX6_WDOG2_IRQ 81
|
||||
#define FSL_IMX6_KPP_IRQ 82
|
||||
#define FSL_IMX6_PWM1_IRQ 83
|
||||
#define FSL_IMX6_PWM2_IRQ 84
|
||||
#define FSL_IMX6_PWM3_IRQ 85
|
||||
#define FSL_IMX6_PWM4_IRQ 86
|
||||
#define FSL_IMX6_CCM1_IRQ 87
|
||||
#define FSL_IMX6_CCM2_IRQ 88
|
||||
#define FSL_IMX6_GPC_IRQ 89
|
||||
#define FSL_IMX6_SRC_IRQ 91
|
||||
#define FSL_IMX6_CPU_L2_IRQ 92
|
||||
#define FSL_IMX6_CPU_PARITY_IRQ 93
|
||||
#define FSL_IMX6_CPU_PERF_IRQ 94
|
||||
#define FSL_IMX6_CPU_CTI_IRQ 95
|
||||
#define FSL_IMX6_SRC_COMB_IRQ 96
|
||||
#define FSL_IMX6_MIPI_CSI1_IRQ 100
|
||||
#define FSL_IMX6_MIPI_CSI2_IRQ 101
|
||||
#define FSL_IMX6_MIPI_DSI_IRQ 102
|
||||
#define FSL_IMX6_MIPI_HSI_IRQ 103
|
||||
#define FSL_IMX6_SJC_IRQ 104
|
||||
#define FSL_IMX6_CAAM0_IRQ 105
|
||||
#define FSL_IMX6_CAAM1_IRQ 106
|
||||
#define FSL_IMX6_ASC1_IRQ 108
|
||||
#define FSL_IMX6_ASC2_IRQ 109
|
||||
#define FSL_IMX6_FLEXCAN1_IRQ 110
|
||||
#define FSL_IMX6_FLEXCAN2_IRQ 111
|
||||
#define FSL_IMX6_HDMI_MASTER_IRQ 115
|
||||
#define FSL_IMX6_HDMI_CEC_IRQ 116
|
||||
#define FSL_IMX6_MLB150_LOW_IRQ 117
|
||||
#define FSL_IMX6_ENET_MAC_IRQ 118
|
||||
#define FSL_IMX6_ENET_MAC_1588_IRQ 119
|
||||
#define FSL_IMX6_PCIE1_IRQ 120
|
||||
#define FSL_IMX6_PCIE2_IRQ 121
|
||||
#define FSL_IMX6_PCIE3_IRQ 122
|
||||
#define FSL_IMX6_PCIE4_IRQ 123
|
||||
#define FSL_IMX6_DCIC1_IRQ 124
|
||||
#define FSL_IMX6_DCIC2_IRQ 125
|
||||
#define FSL_IMX6_MLB150_HIGH_IRQ 126
|
||||
#define FSL_IMX6_PMU2_IRQ 127
|
||||
#define FSL_IMX6_MAX_IRQ 128
|
||||
|
||||
#endif /* FSL_IMX6_H */
|
73
include/hw/misc/imx6_src.h
Normal file
73
include/hw/misc/imx6_src.h
Normal file
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* IMX6 System Reset Controller
|
||||
*
|
||||
* Copyright (C) 2012 NICTA
|
||||
* Updated by Jean-Christophe Dubois <jcd@tribudubois.net>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#ifndef IMX6_SRC_H
|
||||
#define IMX6_SRC_H
|
||||
|
||||
#include "hw/sysbus.h"
|
||||
#include "qemu/bitops.h"
|
||||
|
||||
#define SRC_SCR 0
|
||||
#define SRC_SBMR1 1
|
||||
#define SRC_SRSR 2
|
||||
#define SRC_SISR 5
|
||||
#define SRC_SIMR 6
|
||||
#define SRC_SBMR2 7
|
||||
#define SRC_GPR1 8
|
||||
#define SRC_GPR2 9
|
||||
#define SRC_GPR3 10
|
||||
#define SRC_GPR4 11
|
||||
#define SRC_GPR5 12
|
||||
#define SRC_GPR6 13
|
||||
#define SRC_GPR7 14
|
||||
#define SRC_GPR8 15
|
||||
#define SRC_GPR9 16
|
||||
#define SRC_GPR10 17
|
||||
#define SRC_MAX 18
|
||||
|
||||
/* SRC_SCR */
|
||||
#define CORE3_ENABLE_SHIFT 24
|
||||
#define CORE3_ENABLE_LENGTH 1
|
||||
#define CORE2_ENABLE_SHIFT 23
|
||||
#define CORE2_ENABLE_LENGTH 1
|
||||
#define CORE1_ENABLE_SHIFT 22
|
||||
#define CORE1_ENABLE_LENGTH 1
|
||||
#define CORE3_RST_SHIFT 16
|
||||
#define CORE3_RST_LENGTH 1
|
||||
#define CORE2_RST_SHIFT 15
|
||||
#define CORE2_RST_LENGTH 1
|
||||
#define CORE1_RST_SHIFT 14
|
||||
#define CORE1_RST_LENGTH 1
|
||||
#define CORE0_RST_SHIFT 13
|
||||
#define CORE0_RST_LENGTH 1
|
||||
#define SW_IPU1_RST_SHIFT 3
|
||||
#define SW_IPU1_RST_LENGTH 1
|
||||
#define SW_IPU2_RST_SHIFT 12
|
||||
#define SW_IPU2_RST_LENGTH 1
|
||||
#define WARM_RST_ENABLE_SHIFT 0
|
||||
#define WARM_RST_ENABLE_LENGTH 1
|
||||
|
||||
#define EXTRACT(value, name) extract32(value, name##_SHIFT, name##_LENGTH)
|
||||
|
||||
#define TYPE_IMX6_SRC "imx6.src"
|
||||
#define IMX6_SRC(obj) OBJECT_CHECK(IMX6SRCState, (obj), TYPE_IMX6_SRC)
|
||||
|
||||
typedef struct IMX6SRCState {
|
||||
/* <private> */
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
/* <public> */
|
||||
MemoryRegion iomem;
|
||||
|
||||
uint32_t regs[SRC_MAX];
|
||||
|
||||
} IMX6SRCState;
|
||||
|
||||
#endif /* IMX6_SRC_H */
|
103
include/hw/ssi/imx_spi.h
Normal file
103
include/hw/ssi/imx_spi.h
Normal file
|
@ -0,0 +1,103 @@
|
|||
/*
|
||||
* IMX SPI Controller
|
||||
*
|
||||
* Copyright 2016 Jean-Christophe Dubois <jcd@tribudubois.net>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#ifndef IMX_SPI_H
|
||||
#define IMX_SPI_H
|
||||
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/ssi/ssi.h"
|
||||
#include "qemu/bitops.h"
|
||||
#include "qemu/fifo32.h"
|
||||
|
||||
#define ECSPI_FIFO_SIZE 64
|
||||
|
||||
#define ECSPI_RXDATA 0
|
||||
#define ECSPI_TXDATA 1
|
||||
#define ECSPI_CONREG 2
|
||||
#define ECSPI_CONFIGREG 3
|
||||
#define ECSPI_INTREG 4
|
||||
#define ECSPI_DMAREG 5
|
||||
#define ECSPI_STATREG 6
|
||||
#define ECSPI_PERIODREG 7
|
||||
#define ECSPI_TESTREG 8
|
||||
#define ECSPI_MSGDATA 16
|
||||
#define ECSPI_MAX 17
|
||||
|
||||
/* ECSPI_CONREG */
|
||||
#define ECSPI_CONREG_EN (1 << 0)
|
||||
#define ECSPI_CONREG_HT (1 << 1)
|
||||
#define ECSPI_CONREG_XCH (1 << 2)
|
||||
#define ECSPI_CONREG_SMC (1 << 3)
|
||||
#define ECSPI_CONREG_CHANNEL_MODE_SHIFT 4
|
||||
#define ECSPI_CONREG_CHANNEL_MODE_LENGTH 4
|
||||
#define ECSPI_CONREG_DRCTL_SHIFT 16
|
||||
#define ECSPI_CONREG_DRCTL_LENGTH 2
|
||||
#define ECSPI_CONREG_CHANNEL_SELECT_SHIFT 18
|
||||
#define ECSPI_CONREG_CHANNEL_SELECT_LENGTH 2
|
||||
#define ECSPI_CONREG_BURST_LENGTH_SHIFT 20
|
||||
#define ECSPI_CONREG_BURST_LENGTH_LENGTH 12
|
||||
|
||||
/* ECSPI_CONFIGREG */
|
||||
#define ECSPI_CONFIGREG_SS_CTL_SHIFT 8
|
||||
#define ECSPI_CONFIGREG_SS_CTL_LENGTH 4
|
||||
|
||||
/* ECSPI_INTREG */
|
||||
#define ECSPI_INTREG_TEEN (1 << 0)
|
||||
#define ECSPI_INTREG_TDREN (1 << 1)
|
||||
#define ECSPI_INTREG_TFEN (1 << 2)
|
||||
#define ECSPI_INTREG_RREN (1 << 3)
|
||||
#define ECSPI_INTREG_RDREN (1 << 4)
|
||||
#define ECSPI_INTREG_RFEN (1 << 5)
|
||||
#define ECSPI_INTREG_ROEN (1 << 6)
|
||||
#define ECSPI_INTREG_TCEN (1 << 7)
|
||||
|
||||
/* ECSPI_DMAREG */
|
||||
#define ECSPI_DMAREG_RXTDEN (1 << 31)
|
||||
#define ECSPI_DMAREG_RXDEN (1 << 23)
|
||||
#define ECSPI_DMAREG_TEDEN (1 << 7)
|
||||
#define ECSPI_DMAREG_RX_THRESHOLD_SHIFT 16
|
||||
#define ECSPI_DMAREG_RX_THRESHOLD_LENGTH 6
|
||||
|
||||
/* ECSPI_STATREG */
|
||||
#define ECSPI_STATREG_TE (1 << 0)
|
||||
#define ECSPI_STATREG_TDR (1 << 1)
|
||||
#define ECSPI_STATREG_TF (1 << 2)
|
||||
#define ECSPI_STATREG_RR (1 << 3)
|
||||
#define ECSPI_STATREG_RDR (1 << 4)
|
||||
#define ECSPI_STATREG_RF (1 << 5)
|
||||
#define ECSPI_STATREG_RO (1 << 6)
|
||||
#define ECSPI_STATREG_TC (1 << 7)
|
||||
|
||||
#define EXTRACT(value, name) extract32(value, name##_SHIFT, name##_LENGTH)
|
||||
|
||||
#define TYPE_IMX_SPI "imx.spi"
|
||||
#define IMX_SPI(obj) OBJECT_CHECK(IMXSPIState, (obj), TYPE_IMX_SPI)
|
||||
|
||||
typedef struct IMXSPIState {
|
||||
/* <private> */
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
/* <public> */
|
||||
MemoryRegion iomem;
|
||||
|
||||
qemu_irq irq;
|
||||
|
||||
qemu_irq cs_lines[4];
|
||||
|
||||
SSIBus *bus;
|
||||
|
||||
uint32_t regs[ECSPI_MAX];
|
||||
|
||||
Fifo32 rx_fifo;
|
||||
Fifo32 tx_fifo;
|
||||
|
||||
int16_t burst_length;
|
||||
} IMXSPIState;
|
||||
|
||||
#endif /* IMX_SPI_H */
|
191
include/qemu/fifo32.h
Normal file
191
include/qemu/fifo32.h
Normal file
|
@ -0,0 +1,191 @@
|
|||
/*
|
||||
* Generic FIFO32 component, based on FIFO8.
|
||||
*
|
||||
* Copyright (c) 2016 Jean-Christophe Dubois
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef FIFO32_H
|
||||
#define FIFO32_H
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/fifo8.h"
|
||||
|
||||
typedef struct {
|
||||
Fifo8 fifo;
|
||||
} Fifo32;
|
||||
|
||||
/**
|
||||
* fifo32_create:
|
||||
* @fifo: struct Fifo32 to initialise with new FIFO
|
||||
* @capacity: capacity of the newly created FIFO expressed in 32 bit words
|
||||
*
|
||||
* Create a FIFO of the specified size. Clients should call fifo32_destroy()
|
||||
* when finished using the fifo. The FIFO is initially empty.
|
||||
*/
|
||||
|
||||
static inline void fifo32_create(Fifo32 *fifo, uint32_t capacity)
|
||||
{
|
||||
fifo8_create(&fifo->fifo, capacity * sizeof(uint32_t));
|
||||
}
|
||||
|
||||
/**
|
||||
* fifo32_destroy:
|
||||
* @fifo: FIFO to cleanup
|
||||
*
|
||||
* Cleanup a FIFO created with fifo32_create(). Frees memory created for FIFO
|
||||
* storage. The FIFO is no longer usable after this has been called.
|
||||
*/
|
||||
|
||||
static inline void fifo32_destroy(Fifo32 *fifo)
|
||||
{
|
||||
fifo8_destroy(&fifo->fifo);
|
||||
}
|
||||
|
||||
/**
|
||||
* fifo32_num_free:
|
||||
* @fifo: FIFO to check
|
||||
*
|
||||
* Return the number of free uint32_t slots in the FIFO.
|
||||
*
|
||||
* Returns: Number of free 32 bit words.
|
||||
*/
|
||||
|
||||
static inline uint32_t fifo32_num_free(Fifo32 *fifo)
|
||||
{
|
||||
return DIV_ROUND_UP(fifo8_num_free(&fifo->fifo), sizeof(uint32_t));
|
||||
}
|
||||
|
||||
/**
|
||||
* fifo32_num_used:
|
||||
* @fifo: FIFO to check
|
||||
*
|
||||
* Return the number of used uint32_t slots in the FIFO.
|
||||
*
|
||||
* Returns: Number of used 32 bit words.
|
||||
*/
|
||||
|
||||
static inline uint32_t fifo32_num_used(Fifo32 *fifo)
|
||||
{
|
||||
return DIV_ROUND_UP(fifo8_num_used(&fifo->fifo), sizeof(uint32_t));
|
||||
}
|
||||
|
||||
/**
|
||||
* fifo32_push:
|
||||
* @fifo: FIFO to push to
|
||||
* @data: 32 bits data word to push
|
||||
*
|
||||
* Push a 32 bits data word to the FIFO. Behaviour is undefined if the FIFO
|
||||
* is full. Clients are responsible for checking for fullness using
|
||||
* fifo32_is_full().
|
||||
*/
|
||||
|
||||
static inline void fifo32_push(Fifo32 *fifo, uint32_t data)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < sizeof(data); i++) {
|
||||
fifo8_push(&fifo->fifo, data & 0xff);
|
||||
data >>= 8;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* fifo32_push_all:
|
||||
* @fifo: FIFO to push to
|
||||
* @data: data to push
|
||||
* @size: number of 32 bit words to push
|
||||
*
|
||||
* Push a 32 bit word array to the FIFO. Behaviour is undefined if the FIFO
|
||||
* is full. Clients are responsible for checking the space left in the FIFO
|
||||
* using fifo32_num_free().
|
||||
*/
|
||||
|
||||
static inline void fifo32_push_all(Fifo32 *fifo, const uint32_t *data,
|
||||
uint32_t num)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
fifo32_push(fifo, data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* fifo32_pop:
|
||||
* @fifo: fifo to pop from
|
||||
*
|
||||
* Pop a 32 bits data word from the FIFO. Behaviour is undefined if the FIFO
|
||||
* is empty. Clients are responsible for checking for emptiness using
|
||||
* fifo32_is_empty().
|
||||
*
|
||||
* Returns: The popped 32 bits data word.
|
||||
*/
|
||||
|
||||
static inline uint32_t fifo32_pop(Fifo32 *fifo)
|
||||
{
|
||||
uint32_t ret = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < sizeof(uint32_t); i++) {
|
||||
ret |= (fifo8_pop(&fifo->fifo) << (i * 8));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* There is no fifo32_pop_buf() because the data is not stored in the buffer
|
||||
* as a set of native-order words.
|
||||
*/
|
||||
|
||||
/**
|
||||
* fifo32_reset:
|
||||
* @fifo: FIFO to reset
|
||||
*
|
||||
* Reset a FIFO. All data is discarded and the FIFO is emptied.
|
||||
*/
|
||||
|
||||
static inline void fifo32_reset(Fifo32 *fifo)
|
||||
{
|
||||
fifo8_reset(&fifo->fifo);
|
||||
}
|
||||
|
||||
/**
|
||||
* fifo32_is_empty:
|
||||
* @fifo: FIFO to check
|
||||
*
|
||||
* Check if a FIFO is empty.
|
||||
*
|
||||
* Returns: True if the fifo is empty, false otherwise.
|
||||
*/
|
||||
|
||||
static inline bool fifo32_is_empty(Fifo32 *fifo)
|
||||
{
|
||||
return fifo8_is_empty(&fifo->fifo);
|
||||
}
|
||||
|
||||
/**
|
||||
* fifo32_is_full:
|
||||
* @fifo: FIFO to check
|
||||
*
|
||||
* Check if a FIFO is full.
|
||||
*
|
||||
* Returns: True if the fifo is full, false otherwise.
|
||||
*/
|
||||
|
||||
static inline bool fifo32_is_full(Fifo32 *fifo)
|
||||
{
|
||||
return fifo8_num_free(&fifo->fifo) < sizeof(uint32_t);
|
||||
}
|
||||
|
||||
#define VMSTATE_FIFO32(_field, _state) VMSTATE_FIFO8(_field.fifo, _state)
|
||||
|
||||
#endif /* FIFO32_H */
|
|
@ -9,3 +9,4 @@ obj-y += neon_helper.o iwmmxt_helper.o
|
|||
obj-y += gdbstub.o
|
||||
obj-$(TARGET_AARCH64) += cpu64.o translate-a64.o helper-a64.o gdbstub64.o
|
||||
obj-y += crypto_helper.o
|
||||
obj-y += arm-powerctl.o
|
||||
|
|
224
target-arm/arm-powerctl.c
Normal file
224
target-arm/arm-powerctl.c
Normal file
|
@ -0,0 +1,224 @@
|
|||
/*
|
||||
* QEMU support -- ARM Power Control specific functions.
|
||||
*
|
||||
* Copyright (c) 2016 Jean-Christophe Dubois
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include <cpu.h>
|
||||
#include <cpu-qom.h>
|
||||
#include "internals.h"
|
||||
#include "arm-powerctl.h"
|
||||
|
||||
#ifndef DEBUG_ARM_POWERCTL
|
||||
#define DEBUG_ARM_POWERCTL 0
|
||||
#endif
|
||||
|
||||
#define DPRINTF(fmt, args...) \
|
||||
do { \
|
||||
if (DEBUG_ARM_POWERCTL) { \
|
||||
fprintf(stderr, "[ARM]%s: " fmt , __func__, ##args); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
CPUState *arm_get_cpu_by_id(uint64_t id)
|
||||
{
|
||||
CPUState *cpu;
|
||||
|
||||
DPRINTF("cpu %" PRId64 "\n", id);
|
||||
|
||||
CPU_FOREACH(cpu) {
|
||||
ARMCPU *armcpu = ARM_CPU(cpu);
|
||||
|
||||
if (armcpu->mp_affinity == id) {
|
||||
return cpu;
|
||||
}
|
||||
}
|
||||
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"[ARM]%s: Requesting unknown CPU %" PRId64 "\n",
|
||||
__func__, id);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int arm_set_cpu_on(uint64_t cpuid, uint64_t entry, uint64_t context_id,
|
||||
uint32_t target_el, bool target_aa64)
|
||||
{
|
||||
CPUState *target_cpu_state;
|
||||
ARMCPU *target_cpu;
|
||||
|
||||
DPRINTF("cpu %" PRId64 " (EL %d, %s) @ 0x%" PRIx64 " with R0 = 0x%" PRIx64
|
||||
"\n", cpuid, target_el, target_aa64 ? "aarch64" : "aarch32", entry,
|
||||
context_id);
|
||||
|
||||
/* requested EL level need to be in the 1 to 3 range */
|
||||
assert((target_el > 0) && (target_el < 4));
|
||||
|
||||
if (target_aa64 && (entry & 3)) {
|
||||
/*
|
||||
* if we are booting in AArch64 mode then "entry" needs to be 4 bytes
|
||||
* aligned.
|
||||
*/
|
||||
return QEMU_ARM_POWERCTL_INVALID_PARAM;
|
||||
}
|
||||
|
||||
/* Retrieve the cpu we are powering up */
|
||||
target_cpu_state = arm_get_cpu_by_id(cpuid);
|
||||
if (!target_cpu_state) {
|
||||
/* The cpu was not found */
|
||||
return QEMU_ARM_POWERCTL_INVALID_PARAM;
|
||||
}
|
||||
|
||||
target_cpu = ARM_CPU(target_cpu_state);
|
||||
if (!target_cpu->powered_off) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"[ARM]%s: CPU %" PRId64 " is already on\n",
|
||||
__func__, cpuid);
|
||||
return QEMU_ARM_POWERCTL_ALREADY_ON;
|
||||
}
|
||||
|
||||
/*
|
||||
* The newly brought CPU is requested to enter the exception level
|
||||
* "target_el" and be in the requested mode (AArch64 or AArch32).
|
||||
*/
|
||||
|
||||
if (((target_el == 3) && !arm_feature(&target_cpu->env, ARM_FEATURE_EL3)) ||
|
||||
((target_el == 2) && !arm_feature(&target_cpu->env, ARM_FEATURE_EL2))) {
|
||||
/*
|
||||
* The CPU does not support requested level
|
||||
*/
|
||||
return QEMU_ARM_POWERCTL_INVALID_PARAM;
|
||||
}
|
||||
|
||||
if (!target_aa64 && arm_feature(&target_cpu->env, ARM_FEATURE_AARCH64)) {
|
||||
/*
|
||||
* For now we don't support booting an AArch64 CPU in AArch32 mode
|
||||
* TODO: We should add this support later
|
||||
*/
|
||||
qemu_log_mask(LOG_UNIMP,
|
||||
"[ARM]%s: Starting AArch64 CPU %" PRId64
|
||||
" in AArch32 mode is not supported yet\n",
|
||||
__func__, cpuid);
|
||||
return QEMU_ARM_POWERCTL_INVALID_PARAM;
|
||||
}
|
||||
|
||||
/* Initialize the cpu we are turning on */
|
||||
cpu_reset(target_cpu_state);
|
||||
target_cpu->powered_off = false;
|
||||
target_cpu_state->halted = 0;
|
||||
|
||||
if (target_aa64) {
|
||||
if ((target_el < 3) && arm_feature(&target_cpu->env, ARM_FEATURE_EL3)) {
|
||||
/*
|
||||
* As target mode is AArch64, we need to set lower
|
||||
* exception level (the requested level 2) to AArch64
|
||||
*/
|
||||
target_cpu->env.cp15.scr_el3 |= SCR_RW;
|
||||
}
|
||||
|
||||
if ((target_el < 2) && arm_feature(&target_cpu->env, ARM_FEATURE_EL2)) {
|
||||
/*
|
||||
* As target mode is AArch64, we need to set lower
|
||||
* exception level (the requested level 1) to AArch64
|
||||
*/
|
||||
target_cpu->env.cp15.hcr_el2 |= HCR_RW;
|
||||
}
|
||||
|
||||
target_cpu->env.pstate = aarch64_pstate_mode(target_el, true);
|
||||
} else {
|
||||
/* We are requested to boot in AArch32 mode */
|
||||
static uint32_t mode_for_el[] = { 0,
|
||||
ARM_CPU_MODE_SVC,
|
||||
ARM_CPU_MODE_HYP,
|
||||
ARM_CPU_MODE_SVC };
|
||||
|
||||
cpsr_write(&target_cpu->env, mode_for_el[target_el], CPSR_M,
|
||||
CPSRWriteRaw);
|
||||
}
|
||||
|
||||
if (target_el == 3) {
|
||||
/* Processor is in secure mode */
|
||||
target_cpu->env.cp15.scr_el3 &= ~SCR_NS;
|
||||
} else {
|
||||
/* Processor is not in secure mode */
|
||||
target_cpu->env.cp15.scr_el3 |= SCR_NS;
|
||||
}
|
||||
|
||||
/* We check if the started CPU is now at the correct level */
|
||||
assert(target_el == arm_current_el(&target_cpu->env));
|
||||
|
||||
if (target_aa64) {
|
||||
target_cpu->env.xregs[0] = context_id;
|
||||
target_cpu->env.thumb = false;
|
||||
} else {
|
||||
target_cpu->env.regs[0] = context_id;
|
||||
target_cpu->env.thumb = entry & 1;
|
||||
entry &= 0xfffffffe;
|
||||
}
|
||||
|
||||
/* Start the new CPU at the requested address */
|
||||
cpu_set_pc(target_cpu_state, entry);
|
||||
|
||||
/* We are good to go */
|
||||
return QEMU_ARM_POWERCTL_RET_SUCCESS;
|
||||
}
|
||||
|
||||
int arm_set_cpu_off(uint64_t cpuid)
|
||||
{
|
||||
CPUState *target_cpu_state;
|
||||
ARMCPU *target_cpu;
|
||||
|
||||
DPRINTF("cpu %" PRId64 "\n", cpuid);
|
||||
|
||||
/* change to the cpu we are powering up */
|
||||
target_cpu_state = arm_get_cpu_by_id(cpuid);
|
||||
if (!target_cpu_state) {
|
||||
return QEMU_ARM_POWERCTL_INVALID_PARAM;
|
||||
}
|
||||
target_cpu = ARM_CPU(target_cpu_state);
|
||||
if (target_cpu->powered_off) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"[ARM]%s: CPU %" PRId64 " is already off\n",
|
||||
__func__, cpuid);
|
||||
return QEMU_ARM_POWERCTL_IS_OFF;
|
||||
}
|
||||
|
||||
target_cpu->powered_off = true;
|
||||
target_cpu_state->halted = 1;
|
||||
target_cpu_state->exception_index = EXCP_HLT;
|
||||
cpu_loop_exit(target_cpu_state);
|
||||
/* notreached */
|
||||
|
||||
return QEMU_ARM_POWERCTL_RET_SUCCESS;
|
||||
}
|
||||
|
||||
int arm_reset_cpu(uint64_t cpuid)
|
||||
{
|
||||
CPUState *target_cpu_state;
|
||||
ARMCPU *target_cpu;
|
||||
|
||||
DPRINTF("cpu %" PRId64 "\n", cpuid);
|
||||
|
||||
/* change to the cpu we are resetting */
|
||||
target_cpu_state = arm_get_cpu_by_id(cpuid);
|
||||
if (!target_cpu_state) {
|
||||
return QEMU_ARM_POWERCTL_INVALID_PARAM;
|
||||
}
|
||||
target_cpu = ARM_CPU(target_cpu_state);
|
||||
if (target_cpu->powered_off) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"[ARM]%s: CPU %" PRId64 " is off\n",
|
||||
__func__, cpuid);
|
||||
return QEMU_ARM_POWERCTL_IS_OFF;
|
||||
}
|
||||
|
||||
/* Reset the cpu */
|
||||
cpu_reset(target_cpu_state);
|
||||
|
||||
return QEMU_ARM_POWERCTL_RET_SUCCESS;
|
||||
}
|
75
target-arm/arm-powerctl.h
Normal file
75
target-arm/arm-powerctl.h
Normal file
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* QEMU support -- ARM Power Control specific functions.
|
||||
*
|
||||
* Copyright (c) 2016 Jean-Christophe Dubois
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QEMU_ARM_POWERCTL_H
|
||||
#define QEMU_ARM_POWERCTL_H
|
||||
|
||||
#include "kvm-consts.h"
|
||||
|
||||
#define QEMU_ARM_POWERCTL_RET_SUCCESS QEMU_PSCI_RET_SUCCESS
|
||||
#define QEMU_ARM_POWERCTL_INVALID_PARAM QEMU_PSCI_RET_INVALID_PARAMS
|
||||
#define QEMU_ARM_POWERCTL_ALREADY_ON QEMU_PSCI_RET_ALREADY_ON
|
||||
#define QEMU_ARM_POWERCTL_IS_OFF QEMU_PSCI_RET_DENIED
|
||||
|
||||
/*
|
||||
* arm_get_cpu_by_id:
|
||||
* @cpuid: the id of the CPU we want to retrieve the state
|
||||
*
|
||||
* Retrieve a CPUState object from its CPU ID provided in @cpuid.
|
||||
*
|
||||
* Returns: a pointer to the CPUState structure of the requested CPU.
|
||||
*/
|
||||
CPUState *arm_get_cpu_by_id(uint64_t cpuid);
|
||||
|
||||
/*
|
||||
* arm_set_cpu_on:
|
||||
* @cpuid: the id of the CPU we want to start/wake up.
|
||||
* @entry: the address the CPU shall start from.
|
||||
* @context_id: the value to put in r0/x0.
|
||||
* @target_el: The desired exception level.
|
||||
* @target_aa64: 1 if the requested mode is AArch64. 0 otherwise.
|
||||
*
|
||||
* Start the cpu designated by @cpuid in @target_el exception level. The mode
|
||||
* shall be AArch64 if @target_aa64 is set to 1. Otherwise the mode is
|
||||
* AArch32. The CPU shall start at @entry with @context_id in r0/x0.
|
||||
*
|
||||
* Returns: QEMU_ARM_POWERCTL_RET_SUCCESS on success.
|
||||
* QEMU_ARM_POWERCTL_INVALID_PARAM if bad parameters are provided.
|
||||
* QEMU_ARM_POWERCTL_ALREADY_ON if the CPU was already started.
|
||||
*/
|
||||
int arm_set_cpu_on(uint64_t cpuid, uint64_t entry, uint64_t context_id,
|
||||
uint32_t target_el, bool target_aa64);
|
||||
|
||||
/*
|
||||
* arm_set_cpu_off:
|
||||
* @cpuid: the id of the CPU we want to stop/shut down.
|
||||
*
|
||||
* Stop the cpu designated by @cpuid.
|
||||
*
|
||||
* Returns: QEMU_ARM_POWERCTL_RET_SUCCESS on success.
|
||||
* QEMU_ARM_POWERCTL_INVALID_PARAM if bad parameters are provided.
|
||||
* QEMU_ARM_POWERCTL_IS_OFF if CPU is already off
|
||||
*/
|
||||
|
||||
int arm_set_cpu_off(uint64_t cpuid);
|
||||
|
||||
/*
|
||||
* arm_reset_cpu:
|
||||
* @cpuid: the id of the CPU we want to reset.
|
||||
*
|
||||
* Reset the cpu designated by @cpuid.
|
||||
*
|
||||
* Returns: QEMU_ARM_POWERCTL_RET_SUCCESS on success.
|
||||
* QEMU_ARM_POWERCTL_INVALID_PARAM if bad parameters are provided.
|
||||
* QEMU_ARM_POWERCTL_IS_OFF if CPU is off
|
||||
*/
|
||||
int arm_reset_cpu(uint64_t cpuid);
|
||||
|
||||
#endif
|
|
@ -3559,8 +3559,10 @@ static const ARMCPRegInfo el2_cp_reginfo[] = {
|
|||
.resetvalue = 0 },
|
||||
{ .name = "TCR_EL2", .state = ARM_CP_STATE_BOTH,
|
||||
.opc0 = 3, .opc1 = 4, .crn = 2, .crm = 0, .opc2 = 2,
|
||||
.access = PL2_RW, .writefn = vmsa_tcr_el1_write,
|
||||
.resetfn = vmsa_ttbcr_reset, .raw_writefn = raw_write,
|
||||
.access = PL2_RW,
|
||||
/* no .writefn needed as this can't cause an ASID change;
|
||||
* no .raw_writefn or .resetfn needed as we never use mask/base_mask
|
||||
*/
|
||||
.fieldoffset = offsetof(CPUARMState, cp15.tcr_el[2]) },
|
||||
{ .name = "VTCR", .state = ARM_CP_STATE_AA32,
|
||||
.cp = 15, .opc1 = 4, .crn = 2, .crm = 1, .opc2 = 2,
|
||||
|
@ -3753,8 +3755,10 @@ static const ARMCPRegInfo el3_cp_reginfo[] = {
|
|||
.fieldoffset = offsetof(CPUARMState, cp15.ttbr0_el[3]) },
|
||||
{ .name = "TCR_EL3", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 3, .opc1 = 6, .crn = 2, .crm = 0, .opc2 = 2,
|
||||
.access = PL3_RW, .writefn = vmsa_tcr_el1_write,
|
||||
.resetfn = vmsa_ttbcr_reset, .raw_writefn = raw_write,
|
||||
.access = PL3_RW,
|
||||
/* no .writefn needed as this can't cause an ASID change;
|
||||
* no .raw_writefn or .resetfn needed as we never use mask/base_mask
|
||||
*/
|
||||
.fieldoffset = offsetof(CPUARMState, cp15.tcr_el[3]) },
|
||||
{ .name = "ELR_EL3", .state = ARM_CP_STATE_AA64,
|
||||
.type = ARM_CP_ALIAS,
|
||||
|
@ -6708,7 +6712,9 @@ static int get_S2prot(CPUARMState *env, int s2ap, int xn)
|
|||
prot |= PAGE_WRITE;
|
||||
}
|
||||
if (!xn) {
|
||||
prot |= PAGE_EXEC;
|
||||
if (arm_el_is_aa64(env, 2) || prot & PAGE_READ) {
|
||||
prot |= PAGE_EXEC;
|
||||
}
|
||||
}
|
||||
return prot;
|
||||
}
|
||||
|
@ -7248,7 +7254,7 @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address,
|
|||
uint32_t tg;
|
||||
uint64_t ttbr;
|
||||
int ttbr_select;
|
||||
hwaddr descaddr, descmask;
|
||||
hwaddr descaddr, indexmask, indexmask_grainsize;
|
||||
uint32_t tableattrs;
|
||||
target_ulong page_size;
|
||||
uint32_t attrs;
|
||||
|
@ -7437,28 +7443,20 @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address,
|
|||
level = startlevel;
|
||||
}
|
||||
|
||||
/* Clear the vaddr bits which aren't part of the within-region address,
|
||||
* so that we don't have to special case things when calculating the
|
||||
* first descriptor address.
|
||||
*/
|
||||
if (va_size != inputsize) {
|
||||
address &= (1ULL << inputsize) - 1;
|
||||
}
|
||||
|
||||
descmask = (1ULL << (stride + 3)) - 1;
|
||||
indexmask_grainsize = (1ULL << (stride + 3)) - 1;
|
||||
indexmask = (1ULL << (inputsize - (stride * (4 - level)))) - 1;
|
||||
|
||||
/* Now we can extract the actual base address from the TTBR */
|
||||
descaddr = extract64(ttbr, 0, 48);
|
||||
descaddr &= ~((1ULL << (inputsize - (stride * (4 - level)))) - 1);
|
||||
descaddr &= ~indexmask;
|
||||
|
||||
/* The address field in the descriptor goes up to bit 39 for ARMv7
|
||||
* but up to bit 47 for ARMv8.
|
||||
* but up to bit 47 for ARMv8, but we use the descaddrmask
|
||||
* up to bit 39 for AArch32, because we don't need other bits in that case
|
||||
* to construct next descriptor address (anyway they should be all zeroes).
|
||||
*/
|
||||
if (arm_feature(env, ARM_FEATURE_V8)) {
|
||||
descaddrmask = 0xfffffffff000ULL;
|
||||
} else {
|
||||
descaddrmask = 0xfffffff000ULL;
|
||||
}
|
||||
descaddrmask = ((1ull << (va_size == 64 ? 48 : 40)) - 1) &
|
||||
~indexmask_grainsize;
|
||||
|
||||
/* Secure accesses start with the page table in secure memory and
|
||||
* can be downgraded to non-secure at any step. Non-secure accesses
|
||||
|
@ -7470,7 +7468,7 @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address,
|
|||
uint64_t descriptor;
|
||||
bool nstable;
|
||||
|
||||
descaddr |= (address >> (stride * (4 - level))) & descmask;
|
||||
descaddr |= (address >> (stride * (4 - level))) & indexmask;
|
||||
descaddr &= ~7ULL;
|
||||
nstable = extract32(tableattrs, 4, 1);
|
||||
descriptor = arm_ldq_ptw(cs, descaddr, !nstable, mmu_idx, fsr, fi);
|
||||
|
@ -7493,6 +7491,7 @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address,
|
|||
*/
|
||||
tableattrs |= extract64(descriptor, 59, 5);
|
||||
level++;
|
||||
indexmask = indexmask_grainsize;
|
||||
continue;
|
||||
}
|
||||
/* Block entry at level 1 or 2, or page entry at level 3.
|
||||
|
|
|
@ -263,7 +263,9 @@ enum arm_exception_class {
|
|||
|
||||
#define ARM_EL_EC_SHIFT 26
|
||||
#define ARM_EL_IL_SHIFT 25
|
||||
#define ARM_EL_ISV_SHIFT 24
|
||||
#define ARM_EL_IL (1 << ARM_EL_IL_SHIFT)
|
||||
#define ARM_EL_ISV (1 << ARM_EL_ISV_SHIFT)
|
||||
|
||||
/* Utility functions for constructing various kinds of syndrome value.
|
||||
* Note that in general we follow the AArch64 syndrome values; in a
|
||||
|
@ -383,11 +385,27 @@ static inline uint32_t syn_insn_abort(int same_el, int ea, int s1ptw, int fsc)
|
|||
| (ea << 9) | (s1ptw << 7) | fsc;
|
||||
}
|
||||
|
||||
static inline uint32_t syn_data_abort(int same_el, int ea, int cm, int s1ptw,
|
||||
int wnr, int fsc)
|
||||
static inline uint32_t syn_data_abort_no_iss(int same_el,
|
||||
int ea, int cm, int s1ptw,
|
||||
int wnr, int fsc)
|
||||
{
|
||||
return (EC_DATAABORT << ARM_EL_EC_SHIFT) | (same_el << ARM_EL_EC_SHIFT)
|
||||
| (ea << 9) | (cm << 8) | (s1ptw << 7) | (wnr << 6) | fsc;
|
||||
| ARM_EL_IL
|
||||
| (ea << 9) | (cm << 8) | (s1ptw << 7) | (wnr << 6) | fsc;
|
||||
}
|
||||
|
||||
static inline uint32_t syn_data_abort_with_iss(int same_el,
|
||||
int sas, int sse, int srt,
|
||||
int sf, int ar,
|
||||
int ea, int cm, int s1ptw,
|
||||
int wnr, int fsc,
|
||||
bool is_16bit)
|
||||
{
|
||||
return (EC_DATAABORT << ARM_EL_EC_SHIFT) | (same_el << ARM_EL_EC_SHIFT)
|
||||
| (is_16bit ? 0 : ARM_EL_IL)
|
||||
| ARM_EL_ISV | (sas << 22) | (sse << 21) | (srt << 16)
|
||||
| (sf << 15) | (ar << 14)
|
||||
| (ea << 9) | (cm << 8) | (s1ptw << 7) | (wnr << 6) | fsc;
|
||||
}
|
||||
|
||||
static inline uint32_t syn_swstep(int same_el, int isv, int ex)
|
||||
|
|
|
@ -115,7 +115,8 @@ void tlb_fill(CPUState *cs, target_ulong addr, int is_write, int mmu_idx,
|
|||
syn = syn_insn_abort(same_el, 0, fi.s1ptw, syn);
|
||||
exc = EXCP_PREFETCH_ABORT;
|
||||
} else {
|
||||
syn = syn_data_abort(same_el, 0, 0, fi.s1ptw, is_write == 1, syn);
|
||||
syn = syn_data_abort_no_iss(same_el,
|
||||
0, 0, fi.s1ptw, is_write == 1, syn);
|
||||
if (is_write == 1 && arm_feature(env, ARM_FEATURE_V6)) {
|
||||
fsr |= (1 << 11);
|
||||
}
|
||||
|
@ -161,7 +162,8 @@ void arm_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr, int is_write,
|
|||
}
|
||||
|
||||
raise_exception(env, EXCP_DATA_ABORT,
|
||||
syn_data_abort(same_el, 0, 0, 0, is_write == 1, 0x21),
|
||||
syn_data_abort_no_iss(same_el,
|
||||
0, 0, 0, is_write == 1, 0x21),
|
||||
target_el);
|
||||
}
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include <kvm-consts.h>
|
||||
#include <sysemu/sysemu.h>
|
||||
#include "internals.h"
|
||||
#include "arm-powerctl.h"
|
||||
|
||||
bool arm_is_psci_call(ARMCPU *cpu, int excp_type)
|
||||
{
|
||||
|
@ -73,21 +74,6 @@ bool arm_is_psci_call(ARMCPU *cpu, int excp_type)
|
|||
}
|
||||
}
|
||||
|
||||
static CPUState *get_cpu_by_id(uint64_t id)
|
||||
{
|
||||
CPUState *cpu;
|
||||
|
||||
CPU_FOREACH(cpu) {
|
||||
ARMCPU *armcpu = ARM_CPU(cpu);
|
||||
|
||||
if (armcpu->mp_affinity == id) {
|
||||
return cpu;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void arm_handle_psci_call(ARMCPU *cpu)
|
||||
{
|
||||
/*
|
||||
|
@ -98,7 +84,6 @@ void arm_handle_psci_call(ARMCPU *cpu)
|
|||
* Additional information about the calling convention used is available in
|
||||
* the document 'SMC Calling Convention' (ARM DEN 0028)
|
||||
*/
|
||||
CPUState *cs = CPU(cpu);
|
||||
CPUARMState *env = &cpu->env;
|
||||
uint64_t param[4];
|
||||
uint64_t context_id, mpidr;
|
||||
|
@ -123,7 +108,6 @@ void arm_handle_psci_call(ARMCPU *cpu)
|
|||
switch (param[0]) {
|
||||
CPUState *target_cpu_state;
|
||||
ARMCPU *target_cpu;
|
||||
CPUClass *target_cpu_class;
|
||||
|
||||
case QEMU_PSCI_0_2_FN_PSCI_VERSION:
|
||||
ret = QEMU_PSCI_0_2_RET_VERSION_0_2;
|
||||
|
@ -137,7 +121,7 @@ void arm_handle_psci_call(ARMCPU *cpu)
|
|||
|
||||
switch (param[2]) {
|
||||
case 0:
|
||||
target_cpu_state = get_cpu_by_id(mpidr);
|
||||
target_cpu_state = arm_get_cpu_by_id(mpidr);
|
||||
if (!target_cpu_state) {
|
||||
ret = QEMU_PSCI_RET_INVALID_PARAMS;
|
||||
break;
|
||||
|
@ -167,52 +151,13 @@ void arm_handle_psci_call(ARMCPU *cpu)
|
|||
mpidr = param[1];
|
||||
entry = param[2];
|
||||
context_id = param[3];
|
||||
|
||||
/* change to the cpu we are powering up */
|
||||
target_cpu_state = get_cpu_by_id(mpidr);
|
||||
if (!target_cpu_state) {
|
||||
ret = QEMU_PSCI_RET_INVALID_PARAMS;
|
||||
break;
|
||||
}
|
||||
target_cpu = ARM_CPU(target_cpu_state);
|
||||
if (!target_cpu->powered_off) {
|
||||
ret = QEMU_PSCI_RET_ALREADY_ON;
|
||||
break;
|
||||
}
|
||||
target_cpu_class = CPU_GET_CLASS(target_cpu);
|
||||
|
||||
/* Initialize the cpu we are turning on */
|
||||
cpu_reset(target_cpu_state);
|
||||
target_cpu->powered_off = false;
|
||||
target_cpu_state->halted = 0;
|
||||
|
||||
/*
|
||||
* The PSCI spec mandates that newly brought up CPUs enter the
|
||||
* exception level of the caller in the same execution mode as
|
||||
* the caller, with context_id in x0/r0, respectively.
|
||||
*
|
||||
* For now, it is sufficient to assert() that CPUs come out of
|
||||
* reset in the same mode as the calling CPU, since we only
|
||||
* implement EL1, which means that
|
||||
* (a) there is no EL2 for the calling CPU to trap into to change
|
||||
* its state
|
||||
* (b) the newly brought up CPU enters EL1 immediately after coming
|
||||
* out of reset in the default state
|
||||
*/
|
||||
assert(is_a64(env) == is_a64(&target_cpu->env));
|
||||
if (is_a64(env)) {
|
||||
if (entry & 1) {
|
||||
ret = QEMU_PSCI_RET_INVALID_PARAMS;
|
||||
break;
|
||||
}
|
||||
target_cpu->env.xregs[0] = context_id;
|
||||
} else {
|
||||
target_cpu->env.regs[0] = context_id;
|
||||
target_cpu->env.thumb = entry & 1;
|
||||
}
|
||||
target_cpu_class->set_pc(target_cpu_state, entry);
|
||||
|
||||
ret = 0;
|
||||
ret = arm_set_cpu_on(mpidr, entry, context_id, arm_current_el(env),
|
||||
is_a64(env));
|
||||
break;
|
||||
case QEMU_PSCI_0_1_FN_CPU_OFF:
|
||||
case QEMU_PSCI_0_2_FN_CPU_OFF:
|
||||
|
@ -250,9 +195,8 @@ err:
|
|||
return;
|
||||
|
||||
cpu_off:
|
||||
cpu->powered_off = true;
|
||||
cs->halted = 1;
|
||||
cs->exception_index = EXCP_HLT;
|
||||
cpu_loop_exit(cs);
|
||||
ret = arm_set_cpu_off(cpu->mp_affinity);
|
||||
/* notreached */
|
||||
/* sanity check in case something failed */
|
||||
assert(ret == QEMU_ARM_POWERCTL_RET_SUCCESS);
|
||||
}
|
||||
|
|
|
@ -2086,19 +2086,19 @@ static void disas_ldst_pair(DisasContext *s, uint32_t insn)
|
|||
* size: 00 -> 8 bit, 01 -> 16 bit, 10 -> 32 bit, 11 -> 64bit
|
||||
* opc: 00 -> store, 01 -> loadu, 10 -> loads 64, 11 -> loads 32
|
||||
*/
|
||||
static void disas_ldst_reg_imm9(DisasContext *s, uint32_t insn)
|
||||
static void disas_ldst_reg_imm9(DisasContext *s, uint32_t insn,
|
||||
int opc,
|
||||
int size,
|
||||
int rt,
|
||||
bool is_vector)
|
||||
{
|
||||
int rt = extract32(insn, 0, 5);
|
||||
int rn = extract32(insn, 5, 5);
|
||||
int imm9 = sextract32(insn, 12, 9);
|
||||
int opc = extract32(insn, 22, 2);
|
||||
int size = extract32(insn, 30, 2);
|
||||
int idx = extract32(insn, 10, 2);
|
||||
bool is_signed = false;
|
||||
bool is_store = false;
|
||||
bool is_extended = false;
|
||||
bool is_unpriv = (idx == 2);
|
||||
bool is_vector = extract32(insn, 26, 1);
|
||||
bool post_index;
|
||||
bool writeback;
|
||||
|
||||
|
@ -2128,8 +2128,8 @@ static void disas_ldst_reg_imm9(DisasContext *s, uint32_t insn)
|
|||
return;
|
||||
}
|
||||
is_store = (opc == 0);
|
||||
is_signed = opc & (1<<1);
|
||||
is_extended = (size < 3) && (opc & 1);
|
||||
is_signed = extract32(opc, 1, 1);
|
||||
is_extended = (size < 3) && extract32(opc, 0, 1);
|
||||
}
|
||||
|
||||
switch (idx) {
|
||||
|
@ -2205,19 +2205,19 @@ static void disas_ldst_reg_imm9(DisasContext *s, uint32_t insn)
|
|||
* Rn: address register or SP for base
|
||||
* Rm: offset register or ZR for offset
|
||||
*/
|
||||
static void disas_ldst_reg_roffset(DisasContext *s, uint32_t insn)
|
||||
static void disas_ldst_reg_roffset(DisasContext *s, uint32_t insn,
|
||||
int opc,
|
||||
int size,
|
||||
int rt,
|
||||
bool is_vector)
|
||||
{
|
||||
int rt = extract32(insn, 0, 5);
|
||||
int rn = extract32(insn, 5, 5);
|
||||
int shift = extract32(insn, 12, 1);
|
||||
int rm = extract32(insn, 16, 5);
|
||||
int opc = extract32(insn, 22, 2);
|
||||
int opt = extract32(insn, 13, 3);
|
||||
int size = extract32(insn, 30, 2);
|
||||
bool is_signed = false;
|
||||
bool is_store = false;
|
||||
bool is_extended = false;
|
||||
bool is_vector = extract32(insn, 26, 1);
|
||||
|
||||
TCGv_i64 tcg_rm;
|
||||
TCGv_i64 tcg_addr;
|
||||
|
@ -2294,14 +2294,14 @@ static void disas_ldst_reg_roffset(DisasContext *s, uint32_t insn)
|
|||
* Rn: base address register (inc SP)
|
||||
* Rt: target register
|
||||
*/
|
||||
static void disas_ldst_reg_unsigned_imm(DisasContext *s, uint32_t insn)
|
||||
static void disas_ldst_reg_unsigned_imm(DisasContext *s, uint32_t insn,
|
||||
int opc,
|
||||
int size,
|
||||
int rt,
|
||||
bool is_vector)
|
||||
{
|
||||
int rt = extract32(insn, 0, 5);
|
||||
int rn = extract32(insn, 5, 5);
|
||||
unsigned int imm12 = extract32(insn, 10, 12);
|
||||
bool is_vector = extract32(insn, 26, 1);
|
||||
int size = extract32(insn, 30, 2);
|
||||
int opc = extract32(insn, 22, 2);
|
||||
unsigned int offset;
|
||||
|
||||
TCGv_i64 tcg_addr;
|
||||
|
@ -2360,20 +2360,25 @@ static void disas_ldst_reg_unsigned_imm(DisasContext *s, uint32_t insn)
|
|||
/* Load/store register (all forms) */
|
||||
static void disas_ldst_reg(DisasContext *s, uint32_t insn)
|
||||
{
|
||||
int rt = extract32(insn, 0, 5);
|
||||
int opc = extract32(insn, 22, 2);
|
||||
bool is_vector = extract32(insn, 26, 1);
|
||||
int size = extract32(insn, 30, 2);
|
||||
|
||||
switch (extract32(insn, 24, 2)) {
|
||||
case 0:
|
||||
if (extract32(insn, 21, 1) == 1 && extract32(insn, 10, 2) == 2) {
|
||||
disas_ldst_reg_roffset(s, insn);
|
||||
disas_ldst_reg_roffset(s, insn, opc, size, rt, is_vector);
|
||||
} else {
|
||||
/* Load/store register (unscaled immediate)
|
||||
* Load/store immediate pre/post-indexed
|
||||
* Load/store register unprivileged
|
||||
*/
|
||||
disas_ldst_reg_imm9(s, insn);
|
||||
disas_ldst_reg_imm9(s, insn, opc, size, rt, is_vector);
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
disas_ldst_reg_unsigned_imm(s, insn);
|
||||
disas_ldst_reg_unsigned_imm(s, insn, opc, size, rt, is_vector);
|
||||
break;
|
||||
default:
|
||||
unallocated_encoding(s);
|
||||
|
|
|
@ -595,6 +595,12 @@ struct TCGContext {
|
|||
|
||||
extern TCGContext tcg_ctx;
|
||||
|
||||
static inline void tcg_set_insn_param(int op_idx, int arg, TCGArg v)
|
||||
{
|
||||
int op_argi = tcg_ctx.gen_op_buf[op_idx].args;
|
||||
tcg_ctx.gen_opparam_buf[op_argi + arg] = v;
|
||||
}
|
||||
|
||||
/* The number of opcodes emitted so far. */
|
||||
static inline int tcg_op_buf_count(void)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue