target-arm queue:
* cleanup to use g_new() and friends * support semihosting in A64 * add SMBIOS support to mach-virt * remove hw_error() usages * fix bug in the AArch32:AArch64 register mapping * add a second PCI memory window in highmem on virt board * fix bug in arm_excp_unmasked() * add i.MX31 SoC * remove restriction on handling affinity values in virt board -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABCAAGBQJV7VugAAoJEDwlJe0UNgzeRDEP+weGwHL5bZcHESw9eecJVfmc Fv8i+dhXz9aMoOYncvWvyHliou611705nnVo5Mcj/iBimr2ELlH/joBLa4DvkDAM AFPZvTgFsAC0bhFSy6gDVI9Q3kIbZ7b4a2TQTbewE61HeE7AERjWphwB6zYp/dDb 4POeOEPx8C53I4nM61+RdQgwW1zvGMuyb04R1PUyfiAQ33CoAfM/DfH4q6JzZGnq kDEfModgo0zT4jfXJ2Pp+a5BIyan3YyuiILOrVCNvEQOcnc2Nl9jN1/IuJNYHOPG i5HXrYQya/DyCxmK3SX2JqYZdILcEqYF9q4cjpf92pmwmh3wwzIyfBAfmJ+lmi0A tjQ+Q3OVjHZ1ztVvRWofbhUpiYuqKO8y2m1pn4cR1VwR3ZHp2zRzfgfux4h3eSZF F33zfnGyPi23lHOnj0l3hvo3piWONYUQ22GJcCE7YC/Ammx4j5yG+5rsikofR3nD mqjHsxaZyqdpm/MXWv8o97tBWEMARvRg6GkJeFAxrkhaha/QMCvmNrlWLr+mnIQy ggVv4KSbs+aKlXJvCuh3P2z3tmVKoijluHJ7vHvVi9iKfe3SjY/JDpKaQXKqaSRU iqm4PZjIP7VmY9+ZboEM7leu7M+4aD/K1jjC43kvvombZgDnDdHumbsZIusjHSMD rUdXdgT140zJdWMB5dYl =VFdD -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20150907' into staging target-arm queue: * cleanup to use g_new() and friends * support semihosting in A64 * add SMBIOS support to mach-virt * remove hw_error() usages * fix bug in the AArch32:AArch64 register mapping * add a second PCI memory window in highmem on virt board * fix bug in arm_excp_unmasked() * add i.MX31 SoC * remove restriction on handling affinity values in virt board # gpg: Signature made Mon 07 Sep 2015 10:40:48 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-20150907: (27 commits) arm/virt: Add full-sized CPU affinity handling target-arm: Refactor CPU affinity handling i.MX: Add i2C devices to i.MX31 SOC i.MX: Add qtest support for I2C device emulator. i.MX: Add the i.MX25 PDK platform i.MX: Add SOC support for i.MX25 i.MX: Add FEC Ethernet Emulator i.MX: Add I2C controller emulator i.MX: KZM: use standalone i.MX31 SOC support i.MX: Add SOC support for i.MX31 target-arm: Fix arm_excp_unmasked() function hw/arm/virt: Add high MMIO PCI region, 512G in size target-arm: Fix AArch32:AArch64 general-purpose register mapping arm: Remove hw_error() usages. arm: cpu: assert() on no-EL2 virt IRQ error condition. smbios: implement smbios support for mach-virt smbios: add smbios 3.0 support target-arm: Wire up HLT 0xf000 as the A64 semihosting instruction target-arm/arm-semi.c: SYS_EXIT on A64 takes a parameter block target-arm/arm-semi.c: Implement A64 specific SyncCacheRange call ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
298fae3897
@ -28,6 +28,7 @@ CONFIG_SSI_M25P80=y
|
||||
CONFIG_LAN9118=y
|
||||
CONFIG_SMC91C111=y
|
||||
CONFIG_ALLWINNER_EMAC=y
|
||||
CONFIG_IMX_FEC=y
|
||||
CONFIG_DS1338=y
|
||||
CONFIG_PFLASH_CFI01=y
|
||||
CONFIG_PFLASH_CFI02=y
|
||||
@ -98,7 +99,13 @@ CONFIG_ALLWINNER_A10_PIT=y
|
||||
CONFIG_ALLWINNER_A10_PIC=y
|
||||
CONFIG_ALLWINNER_A10=y
|
||||
|
||||
CONFIG_FSL_IMX31=y
|
||||
CONFIG_FSL_IMX25=y
|
||||
|
||||
CONFIG_IMX_I2C=y
|
||||
|
||||
CONFIG_XIO3130=y
|
||||
CONFIG_IOH3420=y
|
||||
CONFIG_I82801B11=y
|
||||
CONFIG_ACPI=y
|
||||
CONFIG_SMBIOS=y
|
||||
|
14
gdbstub.c
14
gdbstub.c
@ -1301,9 +1301,8 @@ send_packet:
|
||||
%x - target_ulong argument printed in hex.
|
||||
%lx - 64-bit argument printed in hex.
|
||||
%s - string pointer (target_ulong) and length (int) pair. */
|
||||
void gdb_do_syscall(gdb_syscall_complete_cb cb, const char *fmt, ...)
|
||||
void gdb_do_syscallv(gdb_syscall_complete_cb cb, const char *fmt, va_list va)
|
||||
{
|
||||
va_list va;
|
||||
char *p;
|
||||
char *p_end;
|
||||
target_ulong addr;
|
||||
@ -1317,7 +1316,6 @@ void gdb_do_syscall(gdb_syscall_complete_cb cb, const char *fmt, ...)
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
vm_stop(RUN_STATE_DEBUG);
|
||||
#endif
|
||||
va_start(va, fmt);
|
||||
p = s->syscall_buf;
|
||||
p_end = &s->syscall_buf[sizeof(s->syscall_buf)];
|
||||
*(p++) = 'F';
|
||||
@ -1351,7 +1349,6 @@ void gdb_do_syscall(gdb_syscall_complete_cb cb, const char *fmt, ...)
|
||||
}
|
||||
}
|
||||
*p = 0;
|
||||
va_end(va);
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
put_packet(s, s->syscall_buf);
|
||||
gdb_handlesig(s->c_cpu, 0);
|
||||
@ -1366,6 +1363,15 @@ void gdb_do_syscall(gdb_syscall_complete_cb cb, const char *fmt, ...)
|
||||
#endif
|
||||
}
|
||||
|
||||
void gdb_do_syscall(gdb_syscall_complete_cb cb, const char *fmt, ...)
|
||||
{
|
||||
va_list va;
|
||||
|
||||
va_start(va, fmt);
|
||||
gdb_do_syscallv(cb, fmt, va);
|
||||
va_end(va);
|
||||
}
|
||||
|
||||
static void gdb_read_byte(GDBState *s, int ch)
|
||||
{
|
||||
int i, csum;
|
||||
|
@ -1,6 +1,6 @@
|
||||
obj-y += boot.o collie.o exynos4_boards.o gumstix.o highbank.o
|
||||
obj-$(CONFIG_DIGIC) += digic_boards.o
|
||||
obj-y += integratorcp.o kzm.o mainstone.o musicpal.o nseries.o
|
||||
obj-y += integratorcp.o mainstone.o musicpal.o nseries.o
|
||||
obj-y += omap_sx1.o palm.o realview.o spitz.o stellaris.o
|
||||
obj-y += tosa.o versatilepb.o vexpress.o virt.o xilinx_zynq.o z2.o
|
||||
obj-$(CONFIG_ACPI) += virt-acpi-build.o
|
||||
@ -13,3 +13,5 @@ obj-y += omap1.o omap2.o strongarm.o
|
||||
obj-$(CONFIG_ALLWINNER_A10) += allwinner-a10.o cubieboard.o
|
||||
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
|
||||
|
273
hw/arm/fsl-imx25.c
Normal file
273
hw/arm/fsl-imx25.c
Normal file
@ -0,0 +1,273 @@
|
||||
/*
|
||||
* Copyright (c) 2013 Jean-Christophe Dubois <jcd@tribudubois.net>
|
||||
*
|
||||
* i.MX25 SOC emulation.
|
||||
*
|
||||
* Based on hw/arm/xlnx-zynqmp.c
|
||||
*
|
||||
* Copyright (C) 2015 Xilinx Inc
|
||||
* Written by Peter Crosthwaite <peter.crosthwaite@xilinx.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* 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 "hw/arm/fsl-imx25.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "hw/boards.h"
|
||||
#include "sysemu/char.h"
|
||||
|
||||
static void fsl_imx25_init(Object *obj)
|
||||
{
|
||||
FslIMX25State *s = FSL_IMX25(obj);
|
||||
int i;
|
||||
|
||||
object_initialize(&s->cpu, sizeof(s->cpu), "arm926-" TYPE_ARM_CPU);
|
||||
|
||||
object_initialize(&s->avic, sizeof(s->avic), TYPE_IMX_AVIC);
|
||||
qdev_set_parent_bus(DEVICE(&s->avic), sysbus_get_default());
|
||||
|
||||
object_initialize(&s->ccm, sizeof(s->ccm), TYPE_IMX_CCM);
|
||||
qdev_set_parent_bus(DEVICE(&s->ccm), sysbus_get_default());
|
||||
|
||||
for (i = 0; i < FSL_IMX25_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());
|
||||
}
|
||||
|
||||
for (i = 0; i < FSL_IMX25_NUM_GPTS; i++) {
|
||||
object_initialize(&s->gpt[i], sizeof(s->gpt[i]), TYPE_IMX_GPT);
|
||||
qdev_set_parent_bus(DEVICE(&s->gpt[i]), sysbus_get_default());
|
||||
}
|
||||
|
||||
for (i = 0; i < FSL_IMX25_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());
|
||||
}
|
||||
|
||||
object_initialize(&s->fec, sizeof(s->fec), TYPE_IMX_FEC);
|
||||
qdev_set_parent_bus(DEVICE(&s->fec), sysbus_get_default());
|
||||
|
||||
for (i = 0; i < FSL_IMX25_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());
|
||||
}
|
||||
}
|
||||
|
||||
static void fsl_imx25_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
FslIMX25State *s = FSL_IMX25(dev);
|
||||
uint8_t i;
|
||||
Error *err = NULL;
|
||||
|
||||
object_property_set_bool(OBJECT(&s->cpu), true, "realized", &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
|
||||
object_property_set_bool(OBJECT(&s->avic), true, "realized", &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->avic), 0, FSL_IMX25_AVIC_ADDR);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(&s->avic), 0,
|
||||
qdev_get_gpio_in(DEVICE(&s->cpu), ARM_CPU_IRQ));
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(&s->avic), 1,
|
||||
qdev_get_gpio_in(DEVICE(&s->cpu), 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_IMX25_CCM_ADDR);
|
||||
|
||||
/* Initialize all UARTs */
|
||||
for (i = 0; i < FSL_IMX25_NUM_UARTS; i++) {
|
||||
static const struct {
|
||||
hwaddr addr;
|
||||
unsigned int irq;
|
||||
} serial_table[FSL_IMX25_NUM_UARTS] = {
|
||||
{ FSL_IMX25_UART1_ADDR, FSL_IMX25_UART1_IRQ },
|
||||
{ FSL_IMX25_UART2_ADDR, FSL_IMX25_UART2_IRQ },
|
||||
{ FSL_IMX25_UART3_ADDR, FSL_IMX25_UART3_IRQ },
|
||||
{ FSL_IMX25_UART4_ADDR, FSL_IMX25_UART4_IRQ },
|
||||
{ FSL_IMX25_UART5_ADDR, FSL_IMX25_UART5_IRQ }
|
||||
};
|
||||
|
||||
if (i < MAX_SERIAL_PORTS) {
|
||||
CharDriverState *chr;
|
||||
|
||||
chr = serial_hds[i];
|
||||
|
||||
if (!chr) {
|
||||
char label[20];
|
||||
snprintf(label, sizeof(label), "imx31.uart%d", i);
|
||||
chr = qemu_chr_new(label, "null", NULL);
|
||||
}
|
||||
|
||||
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->avic),
|
||||
serial_table[i].irq));
|
||||
}
|
||||
|
||||
/* Initialize all GPT timers */
|
||||
for (i = 0; i < FSL_IMX25_NUM_GPTS; i++) {
|
||||
static const struct {
|
||||
hwaddr addr;
|
||||
unsigned int irq;
|
||||
} gpt_table[FSL_IMX25_NUM_GPTS] = {
|
||||
{ FSL_IMX25_GPT1_ADDR, FSL_IMX25_GPT1_IRQ },
|
||||
{ FSL_IMX25_GPT2_ADDR, FSL_IMX25_GPT2_IRQ },
|
||||
{ FSL_IMX25_GPT3_ADDR, FSL_IMX25_GPT3_IRQ },
|
||||
{ FSL_IMX25_GPT4_ADDR, FSL_IMX25_GPT4_IRQ }
|
||||
};
|
||||
|
||||
s->gpt[i].ccm = DEVICE(&s->ccm);
|
||||
|
||||
object_property_set_bool(OBJECT(&s->gpt[i]), true, "realized", &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpt[i]), 0, gpt_table[i].addr);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpt[i]), 0,
|
||||
qdev_get_gpio_in(DEVICE(&s->avic),
|
||||
gpt_table[i].irq));
|
||||
}
|
||||
|
||||
/* Initialize all EPIT timers */
|
||||
for (i = 0; i < FSL_IMX25_NUM_EPITS; i++) {
|
||||
static const struct {
|
||||
hwaddr addr;
|
||||
unsigned int irq;
|
||||
} epit_table[FSL_IMX25_NUM_EPITS] = {
|
||||
{ FSL_IMX25_EPIT1_ADDR, FSL_IMX25_EPIT1_IRQ },
|
||||
{ FSL_IMX25_EPIT2_ADDR, FSL_IMX25_EPIT2_IRQ }
|
||||
};
|
||||
|
||||
s->epit[i].ccm = DEVICE(&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->avic),
|
||||
epit_table[i].irq));
|
||||
}
|
||||
|
||||
qdev_set_nic_properties(DEVICE(&s->fec), &nd_table[0]);
|
||||
object_property_set_bool(OBJECT(&s->fec), true, "realized", &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->fec), 0, FSL_IMX25_FEC_ADDR);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(&s->fec), 0,
|
||||
qdev_get_gpio_in(DEVICE(&s->avic), FSL_IMX25_FEC_IRQ));
|
||||
|
||||
|
||||
/* Initialize all I2C */
|
||||
for (i = 0; i < FSL_IMX25_NUM_I2CS; i++) {
|
||||
static const struct {
|
||||
hwaddr addr;
|
||||
unsigned int irq;
|
||||
} i2c_table[FSL_IMX25_NUM_I2CS] = {
|
||||
{ FSL_IMX25_I2C1_ADDR, FSL_IMX25_I2C1_IRQ },
|
||||
{ FSL_IMX25_I2C2_ADDR, FSL_IMX25_I2C2_IRQ },
|
||||
{ FSL_IMX25_I2C3_ADDR, FSL_IMX25_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->avic),
|
||||
i2c_table[i].irq));
|
||||
}
|
||||
|
||||
/* initialize 2 x 16 KB ROM */
|
||||
memory_region_init_rom_device(&s->rom[0], NULL, NULL, NULL,
|
||||
"imx25.rom0", FSL_IMX25_ROM0_SIZE, &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
memory_region_add_subregion(get_system_memory(), FSL_IMX25_ROM0_ADDR,
|
||||
&s->rom[0]);
|
||||
memory_region_init_rom_device(&s->rom[1], NULL, NULL, NULL,
|
||||
"imx25.rom1", FSL_IMX25_ROM1_SIZE, &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
memory_region_add_subregion(get_system_memory(), FSL_IMX25_ROM1_ADDR,
|
||||
&s->rom[1]);
|
||||
|
||||
/* initialize internal RAM (128 KB) */
|
||||
memory_region_init_ram(&s->iram, NULL, "imx25.iram", FSL_IMX25_IRAM_SIZE,
|
||||
&err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
memory_region_add_subregion(get_system_memory(), FSL_IMX25_IRAM_ADDR,
|
||||
&s->iram);
|
||||
vmstate_register_ram_global(&s->iram);
|
||||
|
||||
/* internal RAM (128 KB) is aliased over 128 MB - 128 KB */
|
||||
memory_region_init_alias(&s->iram_alias, NULL, "imx25.iram_alias",
|
||||
&s->iram, 0, FSL_IMX25_IRAM_ALIAS_SIZE);
|
||||
memory_region_add_subregion(get_system_memory(), FSL_IMX25_IRAM_ALIAS_ADDR,
|
||||
&s->iram_alias);
|
||||
}
|
||||
|
||||
static void fsl_imx25_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(oc);
|
||||
|
||||
dc->realize = fsl_imx25_realize;
|
||||
}
|
||||
|
||||
static const TypeInfo fsl_imx25_type_info = {
|
||||
.name = TYPE_FSL_IMX25,
|
||||
.parent = TYPE_DEVICE,
|
||||
.instance_size = sizeof(FslIMX25State),
|
||||
.instance_init = fsl_imx25_init,
|
||||
.class_init = fsl_imx25_class_init,
|
||||
};
|
||||
|
||||
static void fsl_imx25_register_types(void)
|
||||
{
|
||||
type_register_static(&fsl_imx25_type_info);
|
||||
}
|
||||
|
||||
type_init(fsl_imx25_register_types)
|
246
hw/arm/fsl-imx31.c
Normal file
246
hw/arm/fsl-imx31.c
Normal file
@ -0,0 +1,246 @@
|
||||
/*
|
||||
* Copyright (c) 2013 Jean-Christophe Dubois <jcd@tribudubois.net>
|
||||
*
|
||||
* i.MX31 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 "hw/arm/fsl-imx31.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "hw/boards.h"
|
||||
#include "sysemu/char.h"
|
||||
|
||||
static void fsl_imx31_init(Object *obj)
|
||||
{
|
||||
FslIMX31State *s = FSL_IMX31(obj);
|
||||
int i;
|
||||
|
||||
object_initialize(&s->cpu, sizeof(s->cpu), "arm1136-" TYPE_ARM_CPU);
|
||||
|
||||
object_initialize(&s->avic, sizeof(s->avic), TYPE_IMX_AVIC);
|
||||
qdev_set_parent_bus(DEVICE(&s->avic), sysbus_get_default());
|
||||
|
||||
object_initialize(&s->ccm, sizeof(s->ccm), TYPE_IMX_CCM);
|
||||
qdev_set_parent_bus(DEVICE(&s->ccm), sysbus_get_default());
|
||||
|
||||
for (i = 0; i < FSL_IMX31_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());
|
||||
}
|
||||
|
||||
object_initialize(&s->gpt, sizeof(s->gpt), TYPE_IMX_GPT);
|
||||
qdev_set_parent_bus(DEVICE(&s->gpt), sysbus_get_default());
|
||||
|
||||
for (i = 0; i < FSL_IMX31_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());
|
||||
}
|
||||
|
||||
for (i = 0; i < FSL_IMX31_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());
|
||||
}
|
||||
}
|
||||
|
||||
static void fsl_imx31_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
FslIMX31State *s = FSL_IMX31(dev);
|
||||
uint16_t i;
|
||||
Error *err = NULL;
|
||||
|
||||
object_property_set_bool(OBJECT(&s->cpu), true, "realized", &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
|
||||
object_property_set_bool(OBJECT(&s->avic), true, "realized", &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->avic), 0, FSL_IMX31_AVIC_ADDR);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(&s->avic), 0,
|
||||
qdev_get_gpio_in(DEVICE(&s->cpu), ARM_CPU_IRQ));
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(&s->avic), 1,
|
||||
qdev_get_gpio_in(DEVICE(&s->cpu), 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_IMX31_CCM_ADDR);
|
||||
|
||||
/* Initialize all UARTS */
|
||||
for (i = 0; i < FSL_IMX31_NUM_UARTS; i++) {
|
||||
static const struct {
|
||||
hwaddr addr;
|
||||
unsigned int irq;
|
||||
} serial_table[FSL_IMX31_NUM_UARTS] = {
|
||||
{ FSL_IMX31_UART1_ADDR, FSL_IMX31_UART1_IRQ },
|
||||
{ FSL_IMX31_UART2_ADDR, FSL_IMX31_UART2_IRQ },
|
||||
};
|
||||
|
||||
if (i < MAX_SERIAL_PORTS) {
|
||||
CharDriverState *chr;
|
||||
|
||||
chr = serial_hds[i];
|
||||
|
||||
if (!chr) {
|
||||
char label[20];
|
||||
snprintf(label, sizeof(label), "imx31.uart%d", i);
|
||||
chr = qemu_chr_new(label, "null", NULL);
|
||||
}
|
||||
|
||||
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->avic),
|
||||
serial_table[i].irq));
|
||||
}
|
||||
|
||||
s->gpt.ccm = DEVICE(&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_IMX31_GPT_ADDR);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpt), 0,
|
||||
qdev_get_gpio_in(DEVICE(&s->avic), FSL_IMX31_GPT_IRQ));
|
||||
|
||||
/* Initialize all EPIT timers */
|
||||
for (i = 0; i < FSL_IMX31_NUM_EPITS; i++) {
|
||||
static const struct {
|
||||
hwaddr addr;
|
||||
unsigned int irq;
|
||||
} epit_table[FSL_IMX31_NUM_EPITS] = {
|
||||
{ FSL_IMX31_EPIT1_ADDR, FSL_IMX31_EPIT1_IRQ },
|
||||
{ FSL_IMX31_EPIT2_ADDR, FSL_IMX31_EPIT2_IRQ },
|
||||
};
|
||||
|
||||
s->epit[i].ccm = DEVICE(&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->avic),
|
||||
epit_table[i].irq));
|
||||
}
|
||||
|
||||
/* Initialize all I2C */
|
||||
for (i = 0; i < FSL_IMX31_NUM_I2CS; i++) {
|
||||
static const struct {
|
||||
hwaddr addr;
|
||||
unsigned int irq;
|
||||
} i2c_table[FSL_IMX31_NUM_I2CS] = {
|
||||
{ FSL_IMX31_I2C1_ADDR, FSL_IMX31_I2C1_IRQ },
|
||||
{ FSL_IMX31_I2C2_ADDR, FSL_IMX31_I2C2_IRQ },
|
||||
{ FSL_IMX31_I2C3_ADDR, FSL_IMX31_I2C3_IRQ }
|
||||
};
|
||||
|
||||
/* Initialize the I2C */
|
||||
object_property_set_bool(OBJECT(&s->i2c[i]), true, "realized", &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
/* Map I2C memory */
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->i2c[i]), 0, i2c_table[i].addr);
|
||||
/* Connect I2C IRQ to PIC */
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c[i]), 0,
|
||||
qdev_get_gpio_in(DEVICE(&s->avic),
|
||||
i2c_table[i].irq));
|
||||
}
|
||||
|
||||
/* On a real system, the first 16k is a `secure boot rom' */
|
||||
memory_region_init_rom_device(&s->secure_rom, NULL, NULL, NULL,
|
||||
"imx31.secure_rom",
|
||||
FSL_IMX31_SECURE_ROM_SIZE, &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
memory_region_add_subregion(get_system_memory(), FSL_IMX31_SECURE_ROM_ADDR,
|
||||
&s->secure_rom);
|
||||
|
||||
/* There is also a 16k ROM */
|
||||
memory_region_init_rom_device(&s->rom, NULL, NULL, NULL, "imx31.rom",
|
||||
FSL_IMX31_ROM_SIZE, &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
memory_region_add_subregion(get_system_memory(), FSL_IMX31_ROM_ADDR,
|
||||
&s->rom);
|
||||
|
||||
/* initialize internal RAM (16 KB) */
|
||||
memory_region_init_ram(&s->iram, NULL, "imx31.iram", FSL_IMX31_IRAM_SIZE,
|
||||
&err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
memory_region_add_subregion(get_system_memory(), FSL_IMX31_IRAM_ADDR,
|
||||
&s->iram);
|
||||
vmstate_register_ram_global(&s->iram);
|
||||
|
||||
/* internal RAM (16 KB) is aliased over 256 MB - 16 KB */
|
||||
memory_region_init_alias(&s->iram_alias, NULL, "imx31.iram_alias",
|
||||
&s->iram, 0, FSL_IMX31_IRAM_ALIAS_SIZE);
|
||||
memory_region_add_subregion(get_system_memory(), FSL_IMX31_IRAM_ALIAS_ADDR,
|
||||
&s->iram_alias);
|
||||
}
|
||||
|
||||
static void fsl_imx31_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(oc);
|
||||
|
||||
dc->realize = fsl_imx31_realize;
|
||||
}
|
||||
|
||||
static const TypeInfo fsl_imx31_type_info = {
|
||||
.name = TYPE_FSL_IMX31,
|
||||
.parent = TYPE_DEVICE,
|
||||
.instance_size = sizeof(FslIMX31State),
|
||||
.instance_init = fsl_imx31_init,
|
||||
.class_init = fsl_imx31_class_init,
|
||||
};
|
||||
|
||||
static void fsl_imx31_register_types(void)
|
||||
{
|
||||
type_register_static(&fsl_imx31_type_info);
|
||||
}
|
||||
|
||||
type_init(fsl_imx31_register_types)
|
159
hw/arm/imx25_pdk.c
Normal file
159
hw/arm/imx25_pdk.c
Normal file
@ -0,0 +1,159 @@
|
||||
/*
|
||||
* Copyright (c) 2013 Jean-Christophe Dubois <jcd@tribudubois.net>
|
||||
*
|
||||
* PDK Board System emulation.
|
||||
*
|
||||
* Based on hw/arm/kzm.c
|
||||
*
|
||||
* Copyright (c) 2008 OKL and 2011 NICTA
|
||||
* Written by Hans at OK-Labs
|
||||
* Updated by Peter Chubb.
|
||||
*
|
||||
* 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 "hw/arm/fsl-imx25.h"
|
||||
#include "hw/boards.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "sysemu/qtest.h"
|
||||
#include "hw/i2c/i2c.h"
|
||||
|
||||
/* Memory map for PDK Emulation Baseboard:
|
||||
* 0x00000000-0x7fffffff See i.MX25 SOC fr support
|
||||
* 0x80000000-0x87ffffff RAM + Alias EMULATED
|
||||
* 0x90000000-0x9fffffff RAM + Alias EMULATED
|
||||
* 0xa0000000-0xa7ffffff Flash IGNORED
|
||||
* 0xa8000000-0xafffffff Flash IGNORED
|
||||
* 0xb0000000-0xb1ffffff SRAM IGNORED
|
||||
* 0xb2000000-0xb3ffffff SRAM IGNORED
|
||||
* 0xb4000000-0xb5ffffff CS4 IGNORED
|
||||
* 0xb6000000-0xb8000fff Reserved IGNORED
|
||||
* 0xb8001000-0xb8001fff SDRAM CTRL reg IGNORED
|
||||
* 0xb8002000-0xb8002fff WEIM CTRL reg IGNORED
|
||||
* 0xb8003000-0xb8003fff M3IF CTRL reg IGNORED
|
||||
* 0xb8004000-0xb8004fff EMI CTRL reg IGNORED
|
||||
* 0xb8005000-0xbaffffff Reserved IGNORED
|
||||
* 0xbb000000-0xbb000fff NAND flash area buf IGNORED
|
||||
* 0xbb001000-0xbb0011ff NAND flash reserved IGNORED
|
||||
* 0xbb001200-0xbb001dff Reserved IGNORED
|
||||
* 0xbb001e00-0xbb001fff NAN flash CTRL reg IGNORED
|
||||
* 0xbb012000-0xbfffffff Reserved IGNORED
|
||||
* 0xc0000000-0xffffffff Reserved IGNORED
|
||||
*/
|
||||
|
||||
typedef struct IMX25PDK {
|
||||
FslIMX25State soc;
|
||||
MemoryRegion ram;
|
||||
MemoryRegion ram_alias;
|
||||
} IMX25PDK;
|
||||
|
||||
static struct arm_boot_info imx25_pdk_binfo;
|
||||
|
||||
static void imx25_pdk_init(MachineState *machine)
|
||||
{
|
||||
IMX25PDK *s = g_new0(IMX25PDK, 1);
|
||||
Error *err = NULL;
|
||||
unsigned int ram_size;
|
||||
unsigned int alias_offset;
|
||||
int i;
|
||||
|
||||
object_initialize(&s->soc, sizeof(s->soc), TYPE_FSL_IMX25);
|
||||
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);
|
||||
}
|
||||
|
||||
/* We need to initialize our memory */
|
||||
if (machine->ram_size > (FSL_IMX25_SDRAM0_SIZE + FSL_IMX25_SDRAM1_SIZE)) {
|
||||
error_report("WARNING: RAM size " RAM_ADDR_FMT " above max supported, "
|
||||
"reduced to %x", machine->ram_size,
|
||||
FSL_IMX25_SDRAM0_SIZE + FSL_IMX25_SDRAM1_SIZE);
|
||||
machine->ram_size = FSL_IMX25_SDRAM0_SIZE + FSL_IMX25_SDRAM1_SIZE;
|
||||
}
|
||||
|
||||
memory_region_allocate_system_memory(&s->ram, NULL, "imx25.ram",
|
||||
machine->ram_size);
|
||||
memory_region_add_subregion(get_system_memory(), FSL_IMX25_SDRAM0_ADDR,
|
||||
&s->ram);
|
||||
|
||||
/* initialize the alias memory if any */
|
||||
for (i = 0, ram_size = machine->ram_size, alias_offset = 0;
|
||||
(i < 2) && ram_size; i++) {
|
||||
unsigned int size;
|
||||
static const struct {
|
||||
hwaddr addr;
|
||||
unsigned int size;
|
||||
} ram[2] = {
|
||||
{ FSL_IMX25_SDRAM0_ADDR, FSL_IMX25_SDRAM0_SIZE },
|
||||
{ FSL_IMX25_SDRAM1_ADDR, FSL_IMX25_SDRAM1_SIZE },
|
||||
};
|
||||
|
||||
size = MIN(ram_size, ram[i].size);
|
||||
|
||||
ram_size -= size;
|
||||
|
||||
if (size < ram[i].size) {
|
||||
memory_region_init_alias(&s->ram_alias, NULL, "ram.alias",
|
||||
&s->ram, alias_offset, ram[i].size - size);
|
||||
memory_region_add_subregion(get_system_memory(),
|
||||
ram[i].addr + size, &s->ram_alias);
|
||||
}
|
||||
|
||||
alias_offset += ram[i].size;
|
||||
}
|
||||
|
||||
imx25_pdk_binfo.ram_size = machine->ram_size;
|
||||
imx25_pdk_binfo.kernel_filename = machine->kernel_filename;
|
||||
imx25_pdk_binfo.kernel_cmdline = machine->kernel_cmdline;
|
||||
imx25_pdk_binfo.initrd_filename = machine->initrd_filename;
|
||||
imx25_pdk_binfo.loader_start = FSL_IMX25_SDRAM0_ADDR;
|
||||
imx25_pdk_binfo.board_id = 1771,
|
||||
imx25_pdk_binfo.nb_cpus = 1;
|
||||
|
||||
/*
|
||||
* We test explicitly for qtest here as it is not done (yet?) in
|
||||
* arm_load_kernel(). Without this the "make check" command would
|
||||
* fail.
|
||||
*/
|
||||
if (!qtest_enabled()) {
|
||||
arm_load_kernel(&s->soc.cpu, &imx25_pdk_binfo);
|
||||
} else {
|
||||
/*
|
||||
* This I2C device doesn't exist on the real board.
|
||||
* We add it here (only on qtest usage) to be able to do a bit
|
||||
* of simple qtest. See "make check" for details.
|
||||
*/
|
||||
i2c_create_slave((I2CBus *)qdev_get_child_bus(DEVICE(&s->soc.i2c[0]),
|
||||
"i2c"),
|
||||
"ds1338", 0x68);
|
||||
}
|
||||
}
|
||||
|
||||
static QEMUMachine imx25_pdk_machine = {
|
||||
.name = "imx25_pdk",
|
||||
.desc = "ARM i.MX25 PDK board (ARM926)",
|
||||
.init = imx25_pdk_init,
|
||||
};
|
||||
|
||||
static void imx25_pdk_machine_init(void)
|
||||
{
|
||||
qemu_register_machine(&imx25_pdk_machine);
|
||||
}
|
||||
|
||||
machine_init(imx25_pdk_machine_init)
|
189
hw/arm/kzm.c
189
hw/arm/kzm.c
@ -13,131 +13,130 @@
|
||||
* i.MX31 SoC
|
||||
*/
|
||||
|
||||
#include "hw/sysbus.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "hw/hw.h"
|
||||
#include "hw/arm/arm.h"
|
||||
#include "hw/devices.h"
|
||||
#include "net/net.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "hw/arm/fsl-imx31.h"
|
||||
#include "hw/boards.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "net/net.h"
|
||||
#include "hw/devices.h"
|
||||
#include "hw/char/serial.h"
|
||||
#include "hw/intc/imx_avic.h"
|
||||
#include "hw/arm/imx.h"
|
||||
#include "sysemu/qtest.h"
|
||||
|
||||
/* Memory map for Kzm Emulation Baseboard:
|
||||
* 0x00000000-0x00003fff 16k secure ROM IGNORED
|
||||
* 0x00004000-0x00407fff Reserved IGNORED
|
||||
* 0x00404000-0x00407fff ROM IGNORED
|
||||
* 0x00408000-0x0fffffff Reserved IGNORED
|
||||
* 0x10000000-0x1fffbfff RAM aliasing IGNORED
|
||||
* 0x1fffc000-0x1fffffff RAM EMULATED
|
||||
* 0x20000000-0x2fffffff Reserved IGNORED
|
||||
* 0x30000000-0x7fffffff I.MX31 Internal Register Space
|
||||
* 0x43f00000 IO_AREA0
|
||||
* 0x43f90000 UART1 EMULATED
|
||||
* 0x43f94000 UART2 EMULATED
|
||||
* 0x68000000 AVIC EMULATED
|
||||
* 0x53f80000 CCM EMULATED
|
||||
* 0x53f94000 PIT 1 EMULATED
|
||||
* 0x53f98000 PIT 2 EMULATED
|
||||
* 0x53f90000 GPT EMULATED
|
||||
* 0x80000000-0x87ffffff RAM EMULATED
|
||||
* 0x88000000-0x8fffffff RAM Aliasing EMULATED
|
||||
* 0xa0000000-0xafffffff NAND Flash IGNORED
|
||||
* 0xb0000000-0xb3ffffff Unavailable IGNORED
|
||||
* 0xb4000000-0xb4000fff 8-bit free space IGNORED
|
||||
* 0xb4001000-0xb400100f Board control IGNORED
|
||||
* 0xb4001003 DIP switch
|
||||
* 0xb4001010-0xb400101f 7-segment LED IGNORED
|
||||
* 0xb4001020-0xb400102f LED IGNORED
|
||||
* 0xb4001030-0xb400103f LED IGNORED
|
||||
* 0xb4001040-0xb400104f FPGA, UART EMULATED
|
||||
* 0xb4001050-0xb400105f FPGA, UART EMULATED
|
||||
* 0xb4001060-0xb40fffff FPGA IGNORED
|
||||
* 0xb6000000-0xb61fffff LAN controller EMULATED
|
||||
* 0xb6200000-0xb62fffff FPGA NAND Controller IGNORED
|
||||
* 0xb6300000-0xb7ffffff Free IGNORED
|
||||
* 0xb8000000-0xb8004fff Memory control registers IGNORED
|
||||
* 0xc0000000-0xc3ffffff PCMCIA/CF IGNORED
|
||||
* 0xc4000000-0xffffffff Reserved IGNORED
|
||||
*/
|
||||
/* Memory map for Kzm Emulation Baseboard:
|
||||
* 0x00000000-0x7fffffff See i.MX31 SOC for support
|
||||
* 0x80000000-0x8fffffff RAM EMULATED
|
||||
* 0x90000000-0x9fffffff RAM EMULATED
|
||||
* 0xa0000000-0xafffffff Flash IGNORED
|
||||
* 0xb0000000-0xb3ffffff Unavailable IGNORED
|
||||
* 0xb4000000-0xb4000fff 8-bit free space IGNORED
|
||||
* 0xb4001000-0xb400100f Board control IGNORED
|
||||
* 0xb4001003 DIP switch
|
||||
* 0xb4001010-0xb400101f 7-segment LED IGNORED
|
||||
* 0xb4001020-0xb400102f LED IGNORED
|
||||
* 0xb4001030-0xb400103f LED IGNORED
|
||||
* 0xb4001040-0xb400104f FPGA, UART EMULATED
|
||||
* 0xb4001050-0xb400105f FPGA, UART EMULATED
|
||||
* 0xb4001060-0xb40fffff FPGA IGNORED
|
||||
* 0xb6000000-0xb61fffff LAN controller EMULATED
|
||||
* 0xb6200000-0xb62fffff FPGA NAND Controller IGNORED
|
||||
* 0xb6300000-0xb7ffffff Free IGNORED
|
||||
* 0xb8000000-0xb8004fff Memory control registers IGNORED
|
||||
* 0xc0000000-0xc3ffffff PCMCIA/CF IGNORED
|
||||
* 0xc4000000-0xffffffff Reserved IGNORED
|
||||
*/
|
||||
|
||||
#define KZM_RAMADDRESS (0x80000000)
|
||||
#define KZM_FPGA (0xb4001040)
|
||||
typedef struct IMX31KZM {
|
||||
FslIMX31State soc;
|
||||
MemoryRegion ram;
|
||||
MemoryRegion ram_alias;
|
||||
} IMX31KZM;
|
||||
|
||||
#define KZM_RAM_ADDR (FSL_IMX31_SDRAM0_ADDR)
|
||||
#define KZM_FPGA_ADDR (FSL_IMX31_CS4_ADDR + 0x1040)
|
||||
#define KZM_LAN9118_ADDR (FSL_IMX31_CS5_ADDR)
|
||||
|
||||
static struct arm_boot_info kzm_binfo = {
|
||||
.loader_start = KZM_RAMADDRESS,
|
||||
.loader_start = KZM_RAM_ADDR,
|
||||
.board_id = 1722,
|
||||
};
|
||||
|
||||
static void kzm_init(MachineState *machine)
|
||||
{
|
||||
ram_addr_t ram_size = machine->ram_size;
|
||||
const char *cpu_model = machine->cpu_model;
|
||||
const char *kernel_filename = machine->kernel_filename;
|
||||
const char *kernel_cmdline = machine->kernel_cmdline;
|
||||
const char *initrd_filename = machine->initrd_filename;
|
||||
ARMCPU *cpu;
|
||||
MemoryRegion *address_space_mem = get_system_memory();
|
||||
MemoryRegion *ram = g_new(MemoryRegion, 1);
|
||||
MemoryRegion *sram = g_new(MemoryRegion, 1);
|
||||
MemoryRegion *ram_alias = g_new(MemoryRegion, 1);
|
||||
DeviceState *dev;
|
||||
DeviceState *ccm;
|
||||
IMX31KZM *s = g_new0(IMX31KZM, 1);
|
||||
Error *err = NULL;
|
||||
unsigned int ram_size;
|
||||
unsigned int alias_offset;
|
||||
unsigned int i;
|
||||
|
||||
if (!cpu_model) {
|
||||
cpu_model = "arm1136";
|
||||
}
|
||||
object_initialize(&s->soc, sizeof(s->soc), TYPE_FSL_IMX31);
|
||||
object_property_add_child(OBJECT(machine), "soc", OBJECT(&s->soc),
|
||||
&error_abort);
|
||||
|
||||
cpu = cpu_arm_init(cpu_model);
|
||||
if (!cpu) {
|
||||
fprintf(stderr, "Unable to find CPU definition\n");
|
||||
object_property_set_bool(OBJECT(&s->soc), true, "realized", &err);
|
||||
if (err != NULL) {
|
||||
error_report("%s", error_get_pretty(err));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* On a real system, the first 16k is a `secure boot rom' */
|
||||
/* Check the amount of memory is compatible with the SOC */
|
||||
if (machine->ram_size > (FSL_IMX31_SDRAM0_SIZE + FSL_IMX31_SDRAM1_SIZE)) {
|
||||
error_report("WARNING: RAM size " RAM_ADDR_FMT " above max supported, "
|
||||
"reduced to %x", machine->ram_size,
|
||||
FSL_IMX31_SDRAM0_SIZE + FSL_IMX31_SDRAM1_SIZE);
|
||||
machine->ram_size = FSL_IMX31_SDRAM0_SIZE + FSL_IMX31_SDRAM1_SIZE;
|
||||
}
|
||||
|
||||
memory_region_allocate_system_memory(ram, NULL, "kzm.ram", ram_size);
|
||||
memory_region_add_subregion(address_space_mem, KZM_RAMADDRESS, ram);
|
||||
memory_region_allocate_system_memory(&s->ram, NULL, "kzm.ram",
|
||||
machine->ram_size);
|
||||
memory_region_add_subregion(get_system_memory(), FSL_IMX31_SDRAM0_ADDR,
|
||||
&s->ram);
|
||||
|
||||
memory_region_init_alias(ram_alias, NULL, "ram.alias", ram, 0, ram_size);
|
||||
memory_region_add_subregion(address_space_mem, 0x88000000, ram_alias);
|
||||
/* initialize the alias memory if any */
|
||||
for (i = 0, ram_size = machine->ram_size, alias_offset = 0;
|
||||
(i < 2) && ram_size; i++) {
|
||||
unsigned int size;
|
||||
static const struct {
|
||||
hwaddr addr;
|
||||
unsigned int size;
|
||||
} ram[2] = {
|
||||
{ FSL_IMX31_SDRAM0_ADDR, FSL_IMX31_SDRAM0_SIZE },
|
||||
{ FSL_IMX31_SDRAM1_ADDR, FSL_IMX31_SDRAM1_SIZE },
|
||||
};
|
||||
|
||||
memory_region_init_ram(sram, NULL, "kzm.sram", 0x4000, &error_abort);
|
||||
memory_region_add_subregion(address_space_mem, 0x1FFFC000, sram);
|
||||
size = MIN(ram_size, ram[i].size);
|
||||
|
||||
dev = sysbus_create_varargs(TYPE_IMX_AVIC, 0x68000000,
|
||||
qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ),
|
||||
qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_FIQ),
|
||||
NULL);
|
||||
ram_size -= size;
|
||||
|
||||
imx_serial_create(0, 0x43f90000, qdev_get_gpio_in(dev, 45));
|
||||
imx_serial_create(1, 0x43f94000, qdev_get_gpio_in(dev, 32));
|
||||
if (size < ram[i].size) {
|
||||
memory_region_init_alias(&s->ram_alias, NULL, "ram.alias",
|
||||
&s->ram, alias_offset, ram[i].size - size);
|
||||
memory_region_add_subregion(get_system_memory(),
|
||||
ram[i].addr + size, &s->ram_alias);
|
||||
}
|
||||
|
||||
ccm = sysbus_create_simple(TYPE_IMX_CCM, 0x53f80000, NULL);
|
||||
|
||||
imx_timerp_create(0x53f94000, qdev_get_gpio_in(dev, 28), ccm);
|
||||
imx_timerp_create(0x53f98000, qdev_get_gpio_in(dev, 27), ccm);
|
||||
imx_timerg_create(0x53f90000, qdev_get_gpio_in(dev, 29), ccm);
|
||||
alias_offset += ram[i].size;
|
||||
}
|
||||
|
||||
if (nd_table[0].used) {
|
||||
lan9118_init(&nd_table[0], 0xb6000000, qdev_get_gpio_in(dev, 52));
|
||||
lan9118_init(&nd_table[0], KZM_LAN9118_ADDR,
|
||||
qdev_get_gpio_in(DEVICE(&s->soc.avic), 52));
|
||||
}
|
||||
|
||||
if (serial_hds[2]) { /* touchscreen */
|
||||
serial_mm_init(address_space_mem, KZM_FPGA+0x10, 0,
|
||||
qdev_get_gpio_in(dev, 52),
|
||||
14745600, serial_hds[2],
|
||||
DEVICE_NATIVE_ENDIAN);
|
||||
serial_mm_init(get_system_memory(), KZM_FPGA_ADDR+0x10, 0,
|
||||
qdev_get_gpio_in(DEVICE(&s->soc.avic), 52),
|
||||
14745600, serial_hds[2], DEVICE_NATIVE_ENDIAN);
|
||||
}
|
||||
|
||||
kzm_binfo.ram_size = ram_size;
|
||||
kzm_binfo.kernel_filename = kernel_filename;
|
||||
kzm_binfo.kernel_cmdline = kernel_cmdline;
|
||||
kzm_binfo.initrd_filename = initrd_filename;
|
||||
kzm_binfo.ram_size = machine->ram_size;
|
||||
kzm_binfo.kernel_filename = machine->kernel_filename;
|
||||
kzm_binfo.kernel_cmdline = machine->kernel_cmdline;
|
||||
kzm_binfo.initrd_filename = machine->initrd_filename;
|
||||
kzm_binfo.nb_cpus = 1;
|
||||
arm_load_kernel(cpu, &kzm_binfo);
|
||||
|
||||
if (!qtest_enabled()) {
|
||||
arm_load_kernel(&s->soc.cpu, &kzm_binfo);
|
||||
}
|
||||
}
|
||||
|
||||
static QEMUMachine kzm_machine = {
|
||||
|
@ -258,8 +258,7 @@ static struct omap_mpu_timer_s *omap_mpu_timer_init(MemoryRegion *system_memory,
|
||||
hwaddr base,
|
||||
qemu_irq irq, omap_clk clk)
|
||||
{
|
||||
struct omap_mpu_timer_s *s = (struct omap_mpu_timer_s *)
|
||||
g_malloc0(sizeof(struct omap_mpu_timer_s));
|
||||
struct omap_mpu_timer_s *s = g_new0(struct omap_mpu_timer_s, 1);
|
||||
|
||||
s->irq = irq;
|
||||
s->clk = clk;
|
||||
@ -388,8 +387,7 @@ static struct omap_watchdog_timer_s *omap_wd_timer_init(MemoryRegion *memory,
|
||||
hwaddr base,
|
||||
qemu_irq irq, omap_clk clk)
|
||||
{
|
||||
struct omap_watchdog_timer_s *s = (struct omap_watchdog_timer_s *)
|
||||
g_malloc0(sizeof(struct omap_watchdog_timer_s));
|
||||
struct omap_watchdog_timer_s *s = g_new0(struct omap_watchdog_timer_s, 1);
|
||||
|
||||
s->timer.irq = irq;
|
||||
s->timer.clk = clk;
|
||||
@ -495,8 +493,7 @@ static struct omap_32khz_timer_s *omap_os_timer_init(MemoryRegion *memory,
|
||||
hwaddr base,
|
||||
qemu_irq irq, omap_clk clk)
|
||||
{
|
||||
struct omap_32khz_timer_s *s = (struct omap_32khz_timer_s *)
|
||||
g_malloc0(sizeof(struct omap_32khz_timer_s));
|
||||
struct omap_32khz_timer_s *s = g_new0(struct omap_32khz_timer_s, 1);
|
||||
|
||||
s->timer.irq = irq;
|
||||
s->timer.clk = clk;
|
||||
@ -1236,8 +1233,7 @@ static struct omap_tipb_bridge_s *omap_tipb_bridge_init(
|
||||
MemoryRegion *memory, hwaddr base,
|
||||
qemu_irq abort_irq, omap_clk clk)
|
||||
{
|
||||
struct omap_tipb_bridge_s *s = (struct omap_tipb_bridge_s *)
|
||||
g_malloc0(sizeof(struct omap_tipb_bridge_s));
|
||||
struct omap_tipb_bridge_s *s = g_new0(struct omap_tipb_bridge_s, 1);
|
||||
|
||||
s->abort = abort_irq;
|
||||
omap_tipb_bridge_reset(s);
|
||||
@ -2099,8 +2095,7 @@ static struct omap_mpuio_s *omap_mpuio_init(MemoryRegion *memory,
|
||||
qemu_irq kbd_int, qemu_irq gpio_int, qemu_irq wakeup,
|
||||
omap_clk clk)
|
||||
{
|
||||
struct omap_mpuio_s *s = (struct omap_mpuio_s *)
|
||||
g_malloc0(sizeof(struct omap_mpuio_s));
|
||||
struct omap_mpuio_s *s = g_new0(struct omap_mpuio_s, 1);
|
||||
|
||||
s->irq = gpio_int;
|
||||
s->kbd_irq = kbd_int;
|
||||
@ -2292,8 +2287,7 @@ static struct omap_uwire_s *omap_uwire_init(MemoryRegion *system_memory,
|
||||
qemu_irq dma,
|
||||
omap_clk clk)
|
||||
{
|
||||
struct omap_uwire_s *s = (struct omap_uwire_s *)
|
||||
g_malloc0(sizeof(struct omap_uwire_s));
|
||||
struct omap_uwire_s *s = g_new0(struct omap_uwire_s, 1);
|
||||
|
||||
s->txirq = txirq;
|
||||
s->rxirq = rxirq;
|
||||
@ -2932,8 +2926,7 @@ static struct omap_rtc_s *omap_rtc_init(MemoryRegion *system_memory,
|
||||
qemu_irq timerirq, qemu_irq alarmirq,
|
||||
omap_clk clk)
|
||||
{
|
||||
struct omap_rtc_s *s = (struct omap_rtc_s *)
|
||||
g_malloc0(sizeof(struct omap_rtc_s));
|
||||
struct omap_rtc_s *s = g_new0(struct omap_rtc_s, 1);
|
||||
|
||||
s->irq = timerirq;
|
||||
s->alarm = alarmirq;
|
||||
@ -3468,8 +3461,7 @@ static struct omap_mcbsp_s *omap_mcbsp_init(MemoryRegion *system_memory,
|
||||
qemu_irq txirq, qemu_irq rxirq,
|
||||
qemu_irq *dma, omap_clk clk)
|
||||
{
|
||||
struct omap_mcbsp_s *s = (struct omap_mcbsp_s *)
|
||||
g_malloc0(sizeof(struct omap_mcbsp_s));
|
||||
struct omap_mcbsp_s *s = g_new0(struct omap_mcbsp_s, 1);
|
||||
|
||||
s->txirq = txirq;
|
||||
s->rxirq = rxirq;
|
||||
@ -3648,8 +3640,7 @@ static void omap_lpg_clk_update(void *opaque, int line, int on)
|
||||
static struct omap_lpg_s *omap_lpg_init(MemoryRegion *system_memory,
|
||||
hwaddr base, omap_clk clk)
|
||||
{
|
||||
struct omap_lpg_s *s = (struct omap_lpg_s *)
|
||||
g_malloc0(sizeof(struct omap_lpg_s));
|
||||
struct omap_lpg_s *s = g_new0(struct omap_lpg_s, 1);
|
||||
|
||||
s->tm = timer_new_ms(QEMU_CLOCK_VIRTUAL, omap_lpg_tick, s);
|
||||
|
||||
@ -3853,8 +3844,7 @@ struct omap_mpu_state_s *omap310_mpu_init(MemoryRegion *system_memory,
|
||||
const char *core)
|
||||
{
|
||||
int i;
|
||||
struct omap_mpu_state_s *s = (struct omap_mpu_state_s *)
|
||||
g_malloc0(sizeof(struct omap_mpu_state_s));
|
||||
struct omap_mpu_state_s *s = g_new0(struct omap_mpu_state_s, 1);
|
||||
qemu_irq dma_irqs[6];
|
||||
DriveInfo *dinfo;
|
||||
SysBusDevice *busdev;
|
||||
|
@ -596,8 +596,7 @@ static const MemoryRegionOps omap_eac_ops = {
|
||||
static struct omap_eac_s *omap_eac_init(struct omap_target_agent_s *ta,
|
||||
qemu_irq irq, qemu_irq *drq, omap_clk fclk, omap_clk iclk)
|
||||
{
|
||||
struct omap_eac_s *s = (struct omap_eac_s *)
|
||||
g_malloc0(sizeof(struct omap_eac_s));
|
||||
struct omap_eac_s *s = g_new0(struct omap_eac_s, 1);
|
||||
|
||||
s->irq = irq;
|
||||
s->codec.rxdrq = *drq ++;
|
||||
@ -788,8 +787,7 @@ static struct omap_sti_s *omap_sti_init(struct omap_target_agent_s *ta,
|
||||
hwaddr channel_base, qemu_irq irq, omap_clk clk,
|
||||
CharDriverState *chr)
|
||||
{
|
||||
struct omap_sti_s *s = (struct omap_sti_s *)
|
||||
g_malloc0(sizeof(struct omap_sti_s));
|
||||
struct omap_sti_s *s = g_new0(struct omap_sti_s, 1);
|
||||
|
||||
s->irq = irq;
|
||||
omap_sti_reset(s);
|
||||
@ -1806,8 +1804,7 @@ static struct omap_prcm_s *omap_prcm_init(struct omap_target_agent_s *ta,
|
||||
qemu_irq mpu_int, qemu_irq dsp_int, qemu_irq iva_int,
|
||||
struct omap_mpu_state_s *mpu)
|
||||
{
|
||||
struct omap_prcm_s *s = (struct omap_prcm_s *)
|
||||
g_malloc0(sizeof(struct omap_prcm_s));
|
||||
struct omap_prcm_s *s = g_new0(struct omap_prcm_s, 1);
|
||||
|
||||
s->irq[0] = mpu_int;
|
||||
s->irq[1] = dsp_int;
|
||||
@ -2185,8 +2182,7 @@ static void omap_sysctl_reset(struct omap_sysctl_s *s)
|
||||
static struct omap_sysctl_s *omap_sysctl_init(struct omap_target_agent_s *ta,
|
||||
omap_clk iclk, struct omap_mpu_state_s *mpu)
|
||||
{
|
||||
struct omap_sysctl_s *s = (struct omap_sysctl_s *)
|
||||
g_malloc0(sizeof(struct omap_sysctl_s));
|
||||
struct omap_sysctl_s *s = g_new0(struct omap_sysctl_s, 1);
|
||||
|
||||
s->mpu = mpu;
|
||||
omap_sysctl_reset(s);
|
||||
@ -2248,8 +2244,7 @@ struct omap_mpu_state_s *omap2420_mpu_init(MemoryRegion *sysmem,
|
||||
unsigned long sdram_size,
|
||||
const char *core)
|
||||
{
|
||||
struct omap_mpu_state_s *s = (struct omap_mpu_state_s *)
|
||||
g_malloc0(sizeof(struct omap_mpu_state_s));
|
||||
struct omap_mpu_state_s *s = g_new0(struct omap_mpu_state_s, 1);
|
||||
qemu_irq dma_irqs[4];
|
||||
DriveInfo *dinfo;
|
||||
int i;
|
||||
|
@ -1731,8 +1731,7 @@ static PXA2xxI2SState *pxa2xx_i2s_init(MemoryRegion *sysmem,
|
||||
hwaddr base,
|
||||
qemu_irq irq, qemu_irq rx_dma, qemu_irq tx_dma)
|
||||
{
|
||||
PXA2xxI2SState *s = (PXA2xxI2SState *)
|
||||
g_malloc0(sizeof(PXA2xxI2SState));
|
||||
PXA2xxI2SState *s = g_new0(PXA2xxI2SState, 1);
|
||||
|
||||
s->irq = irq;
|
||||
s->rx_dma = rx_dma;
|
||||
@ -2061,7 +2060,7 @@ PXA2xxState *pxa270_init(MemoryRegion *address_space,
|
||||
PXA2xxState *s;
|
||||
int i;
|
||||
DriveInfo *dinfo;
|
||||
s = (PXA2xxState *) g_malloc0(sizeof(PXA2xxState));
|
||||
s = g_new0(PXA2xxState, 1);
|
||||
|
||||
if (revision && strncmp(revision, "pxa27", 5)) {
|
||||
fprintf(stderr, "Machine requires a PXA27x processor.\n");
|
||||
@ -2157,7 +2156,7 @@ PXA2xxState *pxa270_init(MemoryRegion *address_space,
|
||||
vmstate_register(NULL, 0, &vmstate_pxa2xx_pm, s);
|
||||
|
||||
for (i = 0; pxa27x_ssp[i].io_base; i ++);
|
||||
s->ssp = (SSIBus **)g_malloc0(sizeof(SSIBus *) * i);
|
||||
s->ssp = g_new0(SSIBus *, i);
|
||||
for (i = 0; pxa27x_ssp[i].io_base; i ++) {
|
||||
DeviceState *dev;
|
||||
dev = sysbus_create_simple(TYPE_PXA2XX_SSP, pxa27x_ssp[i].io_base,
|
||||
@ -2202,7 +2201,7 @@ PXA2xxState *pxa255_init(MemoryRegion *address_space, unsigned int sdram_size)
|
||||
int i;
|
||||
DriveInfo *dinfo;
|
||||
|
||||
s = (PXA2xxState *) g_malloc0(sizeof(PXA2xxState));
|
||||
s = g_new0(PXA2xxState, 1);
|
||||
|
||||
s->cpu = cpu_arm_init("pxa255");
|
||||
if (s->cpu == NULL) {
|
||||
@ -2290,7 +2289,7 @@ PXA2xxState *pxa255_init(MemoryRegion *address_space, unsigned int sdram_size)
|
||||
vmstate_register(NULL, 0, &vmstate_pxa2xx_pm, s);
|
||||
|
||||
for (i = 0; pxa255_ssp[i].io_base; i ++);
|
||||
s->ssp = (SSIBus **)g_malloc0(sizeof(SSIBus *) * i);
|
||||
s->ssp = g_new0(SSIBus *, i);
|
||||
for (i = 0; pxa255_ssp[i].io_base; i ++) {
|
||||
DeviceState *dev;
|
||||
dev = sysbus_create_simple(TYPE_PXA2XX_SSP, pxa255_ssp[i].io_base,
|
||||
|
@ -675,7 +675,7 @@ static int stellaris_sys_init(uint32_t base, qemu_irq irq,
|
||||
{
|
||||
ssys_state *s;
|
||||
|
||||
s = (ssys_state *)g_malloc0(sizeof(ssys_state));
|
||||
s = g_new0(ssys_state, 1);
|
||||
s->irq = irq;
|
||||
s->board = board;
|
||||
/* Most devices come preprogrammed with a MAC address in the user data. */
|
||||
|
@ -1588,7 +1588,7 @@ StrongARMState *sa1110_init(MemoryRegion *sysmem,
|
||||
StrongARMState *s;
|
||||
int i;
|
||||
|
||||
s = g_malloc0(sizeof(StrongARMState));
|
||||
s = g_new0(StrongARMState, 1);
|
||||
|
||||
if (!rev) {
|
||||
rev = "sa1110-b5";
|
||||
|
@ -159,7 +159,8 @@ static void acpi_dsdt_add_virtio(Aml *scope,
|
||||
}
|
||||
}
|
||||
|
||||
static void acpi_dsdt_add_pci(Aml *scope, const MemMapEntry *memmap, int irq)
|
||||
static void acpi_dsdt_add_pci(Aml *scope, const MemMapEntry *memmap, int irq,
|
||||
bool use_highmem)
|
||||
{
|
||||
Aml *method, *crs, *ifctx, *UUID, *ifctx1, *elsectx, *buf;
|
||||
int i, bus_no;
|
||||
@ -234,6 +235,17 @@ static void acpi_dsdt_add_pci(Aml *scope, const MemMapEntry *memmap, int irq)
|
||||
AML_ENTIRE_RANGE, 0x0000, 0x0000, size_pio - 1, base_pio,
|
||||
size_pio));
|
||||
|
||||
if (use_highmem) {
|
||||
hwaddr base_mmio_high = memmap[VIRT_PCIE_MMIO_HIGH].base;
|
||||
hwaddr size_mmio_high = memmap[VIRT_PCIE_MMIO_HIGH].size;
|
||||
|
||||
aml_append(rbuf,
|
||||
aml_qword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED,
|
||||
AML_NON_CACHEABLE, AML_READ_WRITE, 0x0000,
|
||||
base_mmio_high, base_mmio_high, 0x0000,
|
||||
size_mmio_high));
|
||||
}
|
||||
|
||||
aml_append(method, aml_name_decl("RBUF", rbuf));
|
||||
aml_append(method, aml_return(rbuf));
|
||||
aml_append(dev, method);
|
||||
@ -510,7 +522,8 @@ build_dsdt(GArray *table_data, GArray *linker, VirtGuestInfo *guest_info)
|
||||
acpi_dsdt_add_flash(scope, &memmap[VIRT_FLASH]);
|
||||
acpi_dsdt_add_virtio(scope, &memmap[VIRT_MMIO],
|
||||
(irqmap[VIRT_MMIO] + ARM_SPI_BASE), NUM_VIRTIO_TRANSPORTS);
|
||||
acpi_dsdt_add_pci(scope, memmap, (irqmap[VIRT_PCIE] + ARM_SPI_BASE));
|
||||
acpi_dsdt_add_pci(scope, memmap, (irqmap[VIRT_PCIE] + ARM_SPI_BASE),
|
||||
guest_info->use_highmem);
|
||||
|
||||
aml_append(dsdt, scope);
|
||||
|
||||
|
126
hw/arm/virt.c
126
hw/arm/virt.c
@ -50,6 +50,7 @@
|
||||
#include "hw/arm/fdt.h"
|
||||
#include "hw/intc/arm_gic_common.h"
|
||||
#include "kvm_arm.h"
|
||||
#include "hw/smbios/smbios.h"
|
||||
|
||||
/* Number of external interrupt lines to configure the GIC with */
|
||||
#define NUM_IRQS 256
|
||||
@ -79,6 +80,7 @@ typedef struct {
|
||||
typedef struct {
|
||||
MachineState parent;
|
||||
bool secure;
|
||||
bool highmem;
|
||||
} VirtMachineState;
|
||||
|
||||
#define TYPE_VIRT_MACHINE "virt"
|
||||
@ -119,6 +121,8 @@ static const MemMapEntry a15memmap[] = {
|
||||
[VIRT_PCIE_PIO] = { 0x3eff0000, 0x00010000 },
|
||||
[VIRT_PCIE_ECAM] = { 0x3f000000, 0x01000000 },
|
||||
[VIRT_MEM] = { 0x40000000, 30ULL * 1024 * 1024 * 1024 },
|
||||
/* Second PCIe window, 512GB wide at the 512GB boundary */
|
||||
[VIRT_PCIE_MMIO_HIGH] = { 0x8000000000ULL, 0x8000000000ULL },
|
||||
};
|
||||
|
||||
static const int a15irqmap[] = {
|
||||
@ -284,9 +288,32 @@ static void fdt_add_timer_nodes(const VirtBoardInfo *vbi)
|
||||
static void fdt_add_cpu_nodes(const VirtBoardInfo *vbi)
|
||||
{
|
||||
int cpu;
|
||||
int addr_cells = 1;
|
||||
|
||||
/*
|
||||
* From Documentation/devicetree/bindings/arm/cpus.txt
|
||||
* On ARM v8 64-bit systems value should be set to 2,
|
||||
* that corresponds to the MPIDR_EL1 register size.
|
||||
* If MPIDR_EL1[63:32] value is equal to 0 on all CPUs
|
||||
* in the system, #address-cells can be set to 1, since
|
||||
* MPIDR_EL1[63:32] bits are not used for CPUs
|
||||
* identification.
|
||||
*
|
||||
* Here we actually don't know whether our system is 32- or 64-bit one.
|
||||
* The simplest way to go is to examine affinity IDs of all our CPUs. If
|
||||
* at least one of them has Aff3 populated, we set #address-cells to 2.
|
||||
*/
|
||||
for (cpu = 0; cpu < vbi->smp_cpus; cpu++) {
|
||||
ARMCPU *armcpu = ARM_CPU(qemu_get_cpu(cpu));
|
||||
|
||||
if (armcpu->mp_affinity & ARM_AFF3_MASK) {
|
||||
addr_cells = 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
qemu_fdt_add_subnode(vbi->fdt, "/cpus");
|
||||
qemu_fdt_setprop_cell(vbi->fdt, "/cpus", "#address-cells", 0x1);
|
||||
qemu_fdt_setprop_cell(vbi->fdt, "/cpus", "#address-cells", addr_cells);
|
||||
qemu_fdt_setprop_cell(vbi->fdt, "/cpus", "#size-cells", 0x0);
|
||||
|
||||
for (cpu = vbi->smp_cpus - 1; cpu >= 0; cpu--) {
|
||||
@ -303,7 +330,14 @@ static void fdt_add_cpu_nodes(const VirtBoardInfo *vbi)
|
||||
"enable-method", "psci");
|
||||
}
|
||||
|
||||
qemu_fdt_setprop_cell(vbi->fdt, nodename, "reg", armcpu->mp_affinity);
|
||||
if (addr_cells == 2) {
|
||||
qemu_fdt_setprop_u64(vbi->fdt, nodename, "reg",
|
||||
armcpu->mp_affinity);
|
||||
} else {
|
||||
qemu_fdt_setprop_cell(vbi->fdt, nodename, "reg",
|
||||
armcpu->mp_affinity);
|
||||
}
|
||||
|
||||
g_free(nodename);
|
||||
}
|
||||
}
|
||||
@ -666,10 +700,13 @@ static void create_pcie_irq_map(const VirtBoardInfo *vbi, uint32_t gic_phandle,
|
||||
0x7 /* PCI irq */);
|
||||
}
|
||||
|
||||
static void create_pcie(const VirtBoardInfo *vbi, qemu_irq *pic)
|
||||
static void create_pcie(const VirtBoardInfo *vbi, qemu_irq *pic,
|
||||
bool use_highmem)
|
||||
{
|
||||
hwaddr base_mmio = vbi->memmap[VIRT_PCIE_MMIO].base;
|
||||
hwaddr size_mmio = vbi->memmap[VIRT_PCIE_MMIO].size;
|
||||
hwaddr base_mmio_high = vbi->memmap[VIRT_PCIE_MMIO_HIGH].base;
|
||||
hwaddr size_mmio_high = vbi->memmap[VIRT_PCIE_MMIO_HIGH].size;
|
||||
hwaddr base_pio = vbi->memmap[VIRT_PCIE_PIO].base;
|
||||
hwaddr size_pio = vbi->memmap[VIRT_PCIE_PIO].size;
|
||||
hwaddr base_ecam = vbi->memmap[VIRT_PCIE_ECAM].base;
|
||||
@ -706,6 +743,16 @@ static void create_pcie(const VirtBoardInfo *vbi, qemu_irq *pic)
|
||||
mmio_reg, base_mmio, size_mmio);
|
||||
memory_region_add_subregion(get_system_memory(), base_mmio, mmio_alias);
|
||||
|
||||
if (use_highmem) {
|
||||
/* Map high MMIO space */
|
||||
MemoryRegion *high_mmio_alias = g_new0(MemoryRegion, 1);
|
||||
|
||||
memory_region_init_alias(high_mmio_alias, OBJECT(dev), "pcie-mmio-high",
|
||||
mmio_reg, base_mmio_high, size_mmio_high);
|
||||
memory_region_add_subregion(get_system_memory(), base_mmio_high,
|
||||
high_mmio_alias);
|
||||
}
|
||||
|
||||
/* Map IO port space */
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, base_pio);
|
||||
|
||||
@ -727,11 +774,23 @@ static void create_pcie(const VirtBoardInfo *vbi, qemu_irq *pic)
|
||||
|
||||
qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg",
|
||||
2, base_ecam, 2, size_ecam);
|
||||
qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "ranges",
|
||||
1, FDT_PCI_RANGE_IOPORT, 2, 0,
|
||||
2, base_pio, 2, size_pio,
|
||||
1, FDT_PCI_RANGE_MMIO, 2, base_mmio,
|
||||
2, base_mmio, 2, size_mmio);
|
||||
|
||||
if (use_highmem) {
|
||||
qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "ranges",
|
||||
1, FDT_PCI_RANGE_IOPORT, 2, 0,
|
||||
2, base_pio, 2, size_pio,
|
||||
1, FDT_PCI_RANGE_MMIO, 2, base_mmio,
|
||||
2, base_mmio, 2, size_mmio,
|
||||
1, FDT_PCI_RANGE_MMIO_64BIT,
|
||||
2, base_mmio_high,
|
||||
2, base_mmio_high, 2, size_mmio_high);
|
||||
} else {
|
||||
qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "ranges",
|
||||
1, FDT_PCI_RANGE_IOPORT, 2, 0,
|
||||
2, base_pio, 2, size_pio,
|
||||
1, FDT_PCI_RANGE_MMIO, 2, base_mmio,
|
||||
2, base_mmio, 2, size_mmio);
|
||||
}
|
||||
|
||||
qemu_fdt_setprop_cell(vbi->fdt, nodename, "#interrupt-cells", 1);
|
||||
create_pcie_irq_map(vbi, vbi->gic_phandle, irq, nodename);
|
||||
@ -788,12 +847,37 @@ static void *machvirt_dtb(const struct arm_boot_info *binfo, int *fdt_size)
|
||||
return board->fdt;
|
||||
}
|
||||
|
||||
static void virt_build_smbios(VirtGuestInfo *guest_info)
|
||||
{
|
||||
FWCfgState *fw_cfg = guest_info->fw_cfg;
|
||||
uint8_t *smbios_tables, *smbios_anchor;
|
||||
size_t smbios_tables_len, smbios_anchor_len;
|
||||
|
||||
if (!fw_cfg) {
|
||||
return;
|
||||
}
|
||||
|
||||
smbios_set_defaults("QEMU", "QEMU Virtual Machine",
|
||||
"1.0", false, true, SMBIOS_ENTRY_POINT_30);
|
||||
|
||||
smbios_get_tables(NULL, 0, &smbios_tables, &smbios_tables_len,
|
||||
&smbios_anchor, &smbios_anchor_len);
|
||||
|
||||
if (smbios_anchor) {
|
||||
fw_cfg_add_file(fw_cfg, "etc/smbios/smbios-tables",
|
||||
smbios_tables, smbios_tables_len);
|
||||
fw_cfg_add_file(fw_cfg, "etc/smbios/smbios-anchor",
|
||||
smbios_anchor, smbios_anchor_len);
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void virt_guest_info_machine_done(Notifier *notifier, void *data)
|
||||
{
|
||||
VirtGuestInfoState *guest_info_state = container_of(notifier,
|
||||
VirtGuestInfoState, machine_done);
|
||||
virt_acpi_setup(&guest_info_state->info);
|
||||
virt_build_smbios(&guest_info_state->info);
|
||||
}
|
||||
|
||||
static void machvirt_init(MachineState *machine)
|
||||
@ -889,7 +973,7 @@ static void machvirt_init(MachineState *machine)
|
||||
|
||||
create_rtc(vbi, pic);
|
||||
|
||||
create_pcie(vbi, pic);
|
||||
create_pcie(vbi, pic, vms->highmem);
|
||||
|
||||
/* Create mmio transports, so the user can create virtio backends
|
||||
* (which will be automatically plugged in to the transports). If
|
||||
@ -904,6 +988,7 @@ static void machvirt_init(MachineState *machine)
|
||||
guest_info->fw_cfg = fw_cfg_find();
|
||||
guest_info->memmap = vbi->memmap;
|
||||
guest_info->irqmap = vbi->irqmap;
|
||||
guest_info->use_highmem = vms->highmem;
|
||||
guest_info_state->machine_done.notify = virt_guest_info_machine_done;
|
||||
qemu_add_machine_init_done_notifier(&guest_info_state->machine_done);
|
||||
|
||||
@ -941,6 +1026,20 @@ static void virt_set_secure(Object *obj, bool value, Error **errp)
|
||||
vms->secure = value;
|
||||
}
|
||||
|
||||
static bool virt_get_highmem(Object *obj, Error **errp)
|
||||
{
|
||||
VirtMachineState *vms = VIRT_MACHINE(obj);
|
||||
|
||||
return vms->highmem;
|
||||
}
|
||||
|
||||
static void virt_set_highmem(Object *obj, bool value, Error **errp)
|
||||
{
|
||||
VirtMachineState *vms = VIRT_MACHINE(obj);
|
||||
|
||||
vms->highmem = value;
|
||||
}
|
||||
|
||||
static void virt_instance_init(Object *obj)
|
||||
{
|
||||
VirtMachineState *vms = VIRT_MACHINE(obj);
|
||||
@ -953,6 +1052,15 @@ static void virt_instance_init(Object *obj)
|
||||
"Set on/off to enable/disable the ARM "
|
||||
"Security Extensions (TrustZone)",
|
||||
NULL);
|
||||
|
||||
/* High memory is enabled by default */
|
||||
vms->highmem = true;
|
||||
object_property_add_bool(obj, "highmem", virt_get_highmem,
|
||||
virt_set_highmem, NULL);
|
||||
object_property_set_description(obj, "highmem",
|
||||
"Set on/off to enable/disable using "
|
||||
"physical address space above 32 bits",
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void virt_class_init(ObjectClass *oc, void *data)
|
||||
|
@ -21,7 +21,6 @@
|
||||
#include "hw/char/imx_serial.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "sysemu/char.h"
|
||||
#include "hw/arm/imx.h"
|
||||
|
||||
//#define DEBUG_SERIAL 1
|
||||
#ifdef DEBUG_SERIAL
|
||||
@ -334,40 +333,6 @@ static void imx_serial_init(Object *obj)
|
||||
sysbus_init_irq(sbd, &s->irq);
|
||||
}
|
||||
|
||||
void imx_serial_create(int uart, const hwaddr addr, qemu_irq irq)
|
||||
{
|
||||
DeviceState *dev;
|
||||
SysBusDevice *bus;
|
||||
CharDriverState *chr;
|
||||
const char chr_name[] = "serial";
|
||||
char label[ARRAY_SIZE(chr_name) + 1];
|
||||
|
||||
dev = qdev_create(NULL, TYPE_IMX_SERIAL);
|
||||
|
||||
if (uart >= MAX_SERIAL_PORTS) {
|
||||
hw_error("Cannot assign uart %d: QEMU supports only %d ports\n",
|
||||
uart, MAX_SERIAL_PORTS);
|
||||
}
|
||||
chr = serial_hds[uart];
|
||||
if (!chr) {
|
||||
snprintf(label, ARRAY_SIZE(label), "%s%d", chr_name, uart);
|
||||
chr = qemu_chr_new(label, "null", NULL);
|
||||
if (!(chr)) {
|
||||
hw_error("Can't assign serial port to imx-uart%d.\n", uart);
|
||||
}
|
||||
}
|
||||
|
||||
qdev_prop_set_chr(dev, "chardev", chr);
|
||||
bus = SYS_BUS_DEVICE(dev);
|
||||
qdev_init_nofail(dev);
|
||||
if (addr != (hwaddr)-1) {
|
||||
sysbus_mmio_map(bus, 0, addr);
|
||||
}
|
||||
sysbus_connect_irq(bus, 0, irq);
|
||||
|
||||
}
|
||||
|
||||
|
||||
static Property imx_serial_properties[] = {
|
||||
DEFINE_PROP_CHR("chardev", IMXSerialState, chr),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
|
@ -55,8 +55,7 @@ struct omap_uart_s *omap_uart_init(hwaddr base,
|
||||
qemu_irq txdma, qemu_irq rxdma,
|
||||
const char *label, CharDriverState *chr)
|
||||
{
|
||||
struct omap_uart_s *s = (struct omap_uart_s *)
|
||||
g_malloc0(sizeof(struct omap_uart_s));
|
||||
struct omap_uart_s *s = g_new0(struct omap_uart_s, 1);
|
||||
|
||||
s->base = base;
|
||||
s->fclk = fclk;
|
||||
|
@ -1051,8 +1051,7 @@ struct omap_dss_s *omap_dss_init(struct omap_target_agent_s *ta,
|
||||
omap_clk fck1, omap_clk fck2, omap_clk ck54m,
|
||||
omap_clk ick1, omap_clk ick2)
|
||||
{
|
||||
struct omap_dss_s *s = (struct omap_dss_s *)
|
||||
g_malloc0(sizeof(struct omap_dss_s));
|
||||
struct omap_dss_s *s = g_new0(struct omap_dss_s, 1);
|
||||
|
||||
s->irq = irq;
|
||||
s->drq = drq;
|
||||
|
@ -403,8 +403,7 @@ struct omap_lcd_panel_s *omap_lcdc_init(MemoryRegion *sysmem,
|
||||
struct omap_dma_lcd_channel_s *dma,
|
||||
omap_clk clk)
|
||||
{
|
||||
struct omap_lcd_panel_s *s = (struct omap_lcd_panel_s *)
|
||||
g_malloc0(sizeof(struct omap_lcd_panel_s));
|
||||
struct omap_lcd_panel_s *s = g_new0(struct omap_lcd_panel_s, 1);
|
||||
|
||||
s->irq = irq;
|
||||
s->dma = dma;
|
||||
|
@ -1626,8 +1626,7 @@ struct soc_dma_s *omap_dma_init(hwaddr base, qemu_irq *irqs,
|
||||
enum omap_dma_model model)
|
||||
{
|
||||
int num_irqs, memsize, i;
|
||||
struct omap_dma_s *s = (struct omap_dma_s *)
|
||||
g_malloc0(sizeof(struct omap_dma_s));
|
||||
struct omap_dma_s *s = g_new0(struct omap_dma_s, 1);
|
||||
|
||||
if (model <= omap_dma_3_1) {
|
||||
num_irqs = 6;
|
||||
@ -2061,8 +2060,7 @@ struct soc_dma_s *omap_dma4_init(hwaddr base, qemu_irq *irqs,
|
||||
int chans, omap_clk iclk, omap_clk fclk)
|
||||
{
|
||||
int i;
|
||||
struct omap_dma_s *s = (struct omap_dma_s *)
|
||||
g_malloc0(sizeof(struct omap_dma_s));
|
||||
struct omap_dma_s *s = g_new0(struct omap_dma_s, 1);
|
||||
|
||||
s->model = omap_dma_4;
|
||||
s->chans = chans;
|
||||
|
@ -710,8 +710,8 @@ static int omap2_gpio_init(SysBusDevice *sbd)
|
||||
} else {
|
||||
s->modulecount = 6;
|
||||
}
|
||||
s->modules = g_malloc0(s->modulecount * sizeof(struct omap2_gpio_s));
|
||||
s->handler = g_malloc0(s->modulecount * 32 * sizeof(qemu_irq));
|
||||
s->modules = g_new0(struct omap2_gpio_s, s->modulecount);
|
||||
s->handler = g_new0(qemu_irq, s->modulecount * 32);
|
||||
qdev_init_gpio_in(dev, omap2_gpio_set, s->modulecount * 32);
|
||||
qdev_init_gpio_out(dev, s->handler, s->modulecount * 32);
|
||||
for (i = 0; i < s->modulecount; i++) {
|
||||
|
@ -4,4 +4,5 @@ common-obj-$(CONFIG_ACPI_X86) += smbus_ich9.o
|
||||
common-obj-$(CONFIG_APM) += pm_smbus.o
|
||||
common-obj-$(CONFIG_BITBANG_I2C) += bitbang_i2c.o
|
||||
common-obj-$(CONFIG_EXYNOS4) += exynos4210_i2c.o
|
||||
common-obj-$(CONFIG_IMX_I2C) += imx_i2c.o
|
||||
obj-$(CONFIG_OMAP) += omap_i2c.o
|
||||
|
334
hw/i2c/imx_i2c.c
Normal file
334
hw/i2c/imx_i2c.c
Normal file
@ -0,0 +1,334 @@
|
||||
/*
|
||||
* i.MX I2C Bus Serial Interface Emulation
|
||||
*
|
||||
* Copyright (C) 2013 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.
|
||||
*
|
||||
* 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 "hw/i2c/imx_i2c.h"
|
||||
#include "hw/i2c/i2c.h"
|
||||
|
||||
#ifndef IMX_I2C_DEBUG
|
||||
#define IMX_I2C_DEBUG 0
|
||||
#endif
|
||||
|
||||
#if IMX_I2C_DEBUG
|
||||
#define DPRINT(fmt, args...) \
|
||||
do { fprintf(stderr, "%s: "fmt, __func__, ## args); } while (0)
|
||||
|
||||
static const char *imx_i2c_get_regname(unsigned offset)
|
||||
{
|
||||
switch (offset) {
|
||||
case IADR_ADDR:
|
||||
return "IADR";
|
||||
case IFDR_ADDR:
|
||||
return "IFDR";
|
||||
case I2CR_ADDR:
|
||||
return "I2CR";
|
||||
case I2SR_ADDR:
|
||||
return "I2SR";
|
||||
case I2DR_ADDR:
|
||||
return "I2DR";
|
||||
default:
|
||||
return "[?]";
|
||||
}
|
||||
}
|
||||
#else
|
||||
#define DPRINT(fmt, args...) do { } while (0)
|
||||
#endif
|
||||
|
||||
static inline bool imx_i2c_is_enabled(IMXI2CState *s)
|
||||
{
|
||||
return s->i2cr & I2CR_IEN;
|
||||
}
|
||||
|
||||
static inline bool imx_i2c_interrupt_is_enabled(IMXI2CState *s)
|
||||
{
|
||||
return s->i2cr & I2CR_IIEN;
|
||||
}
|
||||
|
||||
static inline bool imx_i2c_is_master(IMXI2CState *s)
|
||||
{
|
||||
return s->i2cr & I2CR_MSTA;
|
||||
}
|
||||
|
||||
static void imx_i2c_reset(DeviceState *dev)
|
||||
{
|
||||
IMXI2CState *s = IMX_I2C(dev);
|
||||
|
||||
if (s->address != ADDR_RESET) {
|
||||
i2c_end_transfer(s->bus);
|
||||
}
|
||||
|
||||
s->address = ADDR_RESET;
|
||||
s->iadr = IADR_RESET;
|
||||
s->ifdr = IFDR_RESET;
|
||||
s->i2cr = I2CR_RESET;
|
||||
s->i2sr = I2SR_RESET;
|
||||
s->i2dr_read = I2DR_RESET;
|
||||
s->i2dr_write = I2DR_RESET;
|
||||
}
|
||||
|
||||
static inline void imx_i2c_raise_interrupt(IMXI2CState *s)
|
||||
{
|
||||
/*
|
||||
* raise an interrupt if the device is enabled and it is configured
|
||||
* to generate some interrupts.
|
||||
*/
|
||||
if (imx_i2c_is_enabled(s) && imx_i2c_interrupt_is_enabled(s)) {
|
||||
s->i2sr |= I2SR_IIF;
|
||||
qemu_irq_raise(s->irq);
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t imx_i2c_read(void *opaque, hwaddr offset,
|
||||
unsigned size)
|
||||
{
|
||||
uint16_t value;
|
||||
IMXI2CState *s = IMX_I2C(opaque);
|
||||
|
||||
switch (offset) {
|
||||
case IADR_ADDR:
|
||||
value = s->iadr;
|
||||
break;
|
||||
case IFDR_ADDR:
|
||||
value = s->ifdr;
|
||||
break;
|
||||
case I2CR_ADDR:
|
||||
value = s->i2cr;
|
||||
break;
|
||||
case I2SR_ADDR:
|
||||
value = s->i2sr;
|
||||
break;
|
||||
case I2DR_ADDR:
|
||||
value = s->i2dr_read;
|
||||
|
||||
if (imx_i2c_is_master(s)) {
|
||||
int ret = 0xff;
|
||||
|
||||
if (s->address == ADDR_RESET) {
|
||||
/* something is wrong as the address is not set */
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s[%s]: Trying to read "
|
||||
"without specifying the slave address\n",
|
||||
TYPE_IMX_I2C, __func__);
|
||||
} else if (s->i2cr & I2CR_MTX) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s[%s]: Trying to read "
|
||||
"but MTX is set\n", TYPE_IMX_I2C, __func__);
|
||||
} else {
|
||||
/* get the next byte */
|
||||
ret = i2c_recv(s->bus);
|
||||
|
||||
if (ret >= 0) {
|
||||
imx_i2c_raise_interrupt(s);
|
||||
} else {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s[%s]: read failed "
|
||||
"for device 0x%02x\n", TYPE_IMX_I2C,
|
||||
__func__, s->address);
|
||||
ret = 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
s->i2dr_read = ret;
|
||||
} else {
|
||||
qemu_log_mask(LOG_UNIMP, "%s[%s]: slave mode not implemented\n",
|
||||
TYPE_IMX_I2C, __func__);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s[%s]: Bad address at offset %d\n",
|
||||
TYPE_IMX_I2C, __func__, s->address);
|
||||
value = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
DPRINT("read %s [0x%02x] -> 0x%02x\n", imx_i2c_get_regname(offset),
|
||||
(unsigned int)offset, value);
|
||||
|
||||
return (uint64_t)value;
|
||||
}
|
||||
|
||||
static void imx_i2c_write(void *opaque, hwaddr offset,
|
||||
uint64_t value, unsigned size)
|
||||
{
|
||||
IMXI2CState *s = IMX_I2C(opaque);
|
||||
|
||||
DPRINT("write %s [0x%02x] <- 0x%02x\n", imx_i2c_get_regname(offset),
|
||||
(unsigned int)offset, (int)value);
|
||||
|
||||
value &= 0xff;
|
||||
|
||||
switch (offset) {
|
||||
case IADR_ADDR:
|
||||
s->iadr = value & IADR_MASK;
|
||||
/* i2c_set_slave_address(s->bus, (uint8_t)s->iadr); */
|
||||
break;
|
||||
case IFDR_ADDR:
|
||||
s->ifdr = value & IFDR_MASK;
|
||||
break;
|
||||
case I2CR_ADDR:
|
||||
if (imx_i2c_is_enabled(s) && ((value & I2CR_IEN) == 0)) {
|
||||
/* This is a soft reset. IADR is preserved during soft resets */
|
||||
uint16_t iadr = s->iadr;
|
||||
imx_i2c_reset(DEVICE(s));
|
||||
s->iadr = iadr;
|
||||
} else { /* normal write */
|
||||
s->i2cr = value & I2CR_MASK;
|
||||
|
||||
if (imx_i2c_is_master(s)) {
|
||||
/* set the bus to busy */
|
||||
s->i2sr |= I2SR_IBB;
|
||||
} else { /* slave mode */
|
||||
/* bus is not busy anymore */
|
||||
s->i2sr &= ~I2SR_IBB;
|
||||
|
||||
/*
|
||||
* if we unset the master mode then it ends the ongoing
|
||||
* transfer if any
|
||||
*/
|
||||
if (s->address != ADDR_RESET) {
|
||||
i2c_end_transfer(s->bus);
|
||||
s->address = ADDR_RESET;
|
||||
}
|
||||
}
|
||||
|
||||
if (s->i2cr & I2CR_RSTA) { /* Restart */
|
||||
/* if this is a restart then it ends the ongoing transfer */
|
||||
if (s->address != ADDR_RESET) {
|
||||
i2c_end_transfer(s->bus);
|
||||
s->address = ADDR_RESET;
|
||||
s->i2cr &= ~I2CR_RSTA;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case I2SR_ADDR:
|
||||
/*
|
||||
* if the user writes 0 to IIF then lower the interrupt and
|
||||
* reset the bit
|
||||
*/
|
||||
if ((s->i2sr & I2SR_IIF) && !(value & I2SR_IIF)) {
|
||||
s->i2sr &= ~I2SR_IIF;
|
||||
qemu_irq_lower(s->irq);
|
||||
}
|
||||
|
||||
/*
|
||||
* if the user writes 0 to IAL, reset the bit
|
||||
*/
|
||||
if ((s->i2sr & I2SR_IAL) && !(value & I2SR_IAL)) {
|
||||
s->i2sr &= ~I2SR_IAL;
|
||||
}
|
||||
|
||||
break;
|
||||
case I2DR_ADDR:
|
||||
/* if the device is not enabled, nothing to do */
|
||||
if (!imx_i2c_is_enabled(s)) {
|
||||
break;
|
||||
}
|
||||
|
||||
s->i2dr_write = value & I2DR_MASK;
|
||||
|
||||
if (imx_i2c_is_master(s)) {
|
||||
/* If this is the first write cycle then it is the slave addr */
|
||||
if (s->address == ADDR_RESET) {
|
||||
if (i2c_start_transfer(s->bus, extract32(s->i2dr_write, 1, 7),
|
||||
extract32(s->i2dr_write, 0, 1))) {
|
||||
/* if non zero is returned, the adress is not valid */
|
||||
s->i2sr |= I2SR_RXAK;
|
||||
} else {
|
||||
s->address = s->i2dr_write;
|
||||
s->i2sr &= ~I2SR_RXAK;
|
||||
imx_i2c_raise_interrupt(s);
|
||||
}
|
||||
} else { /* This is a normal data write */
|
||||
if (i2c_send(s->bus, s->i2dr_write)) {
|
||||
/* if the target return non zero then end the transfer */
|
||||
s->i2sr |= I2SR_RXAK;
|
||||
s->address = ADDR_RESET;
|
||||
i2c_end_transfer(s->bus);
|
||||
} else {
|
||||
s->i2sr &= ~I2SR_RXAK;
|
||||
imx_i2c_raise_interrupt(s);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
qemu_log_mask(LOG_UNIMP, "%s[%s]: slave mode not implemented\n",
|
||||
TYPE_IMX_I2C, __func__);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s[%s]: Bad address at offset %d\n",
|
||||
TYPE_IMX_I2C, __func__, s->address);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static const MemoryRegionOps imx_i2c_ops = {
|
||||
.read = imx_i2c_read,
|
||||
.write = imx_i2c_write,
|
||||
.valid.min_access_size = 1,
|
||||
.valid.max_access_size = 2,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
static const VMStateDescription imx_i2c_vmstate = {
|
||||
.name = TYPE_IMX_I2C,
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT16(address, IMXI2CState),
|
||||
VMSTATE_UINT16(iadr, IMXI2CState),
|
||||
VMSTATE_UINT16(ifdr, IMXI2CState),
|
||||
VMSTATE_UINT16(i2cr, IMXI2CState),
|
||||
VMSTATE_UINT16(i2sr, IMXI2CState),
|
||||
VMSTATE_UINT16(i2dr_read, IMXI2CState),
|
||||
VMSTATE_UINT16(i2dr_write, IMXI2CState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static void imx_i2c_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
IMXI2CState *s = IMX_I2C(dev);
|
||||
|
||||
memory_region_init_io(&s->iomem, OBJECT(s), &imx_i2c_ops, s, TYPE_IMX_I2C,
|
||||
IMX_I2C_MEM_SIZE);
|
||||
sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
|
||||
sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq);
|
||||
s->bus = i2c_init_bus(DEVICE(dev), "i2c");
|
||||
}
|
||||
|
||||
static void imx_i2c_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->vmsd = &imx_i2c_vmstate;
|
||||
dc->reset = imx_i2c_reset;
|
||||
dc->realize = imx_i2c_realize;
|
||||
}
|
||||
|
||||
static const TypeInfo imx_i2c_type_info = {
|
||||
.name = TYPE_IMX_I2C,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(IMXI2CState),
|
||||
.class_init = imx_i2c_class_init,
|
||||
};
|
||||
|
||||
static void imx_i2c_register_types(void)
|
||||
{
|
||||
type_register_static(&imx_i2c_type_info);
|
||||
}
|
||||
|
||||
type_init(imx_i2c_register_types)
|
@ -173,7 +173,8 @@ static void pc_init1(MachineState *machine)
|
||||
MachineClass *mc = MACHINE_GET_CLASS(machine);
|
||||
/* These values are guest ABI, do not change */
|
||||
smbios_set_defaults("QEMU", "Standard PC (i440FX + PIIX, 1996)",
|
||||
mc->name, smbios_legacy_mode, smbios_uuid_encoded);
|
||||
mc->name, smbios_legacy_mode, smbios_uuid_encoded,
|
||||
SMBIOS_ENTRY_POINT_21);
|
||||
}
|
||||
|
||||
/* allocate ram and load rom/bios */
|
||||
|
@ -165,7 +165,8 @@ static void pc_q35_init(MachineState *machine)
|
||||
if (smbios_defaults) {
|
||||
/* These values are guest ABI, do not change */
|
||||
smbios_set_defaults("QEMU", "Standard PC (Q35 + ICH9, 2009)",
|
||||
mc->name, smbios_legacy_mode, smbios_uuid_encoded);
|
||||
mc->name, smbios_legacy_mode, smbios_uuid_encoded,
|
||||
SMBIOS_ENTRY_POINT_21);
|
||||
}
|
||||
|
||||
/* allocate ram and load rom/bios */
|
||||
|
@ -75,8 +75,8 @@ void stellaris_gamepad_init(int n, qemu_irq *irq, const int *keycode)
|
||||
gamepad_state *s;
|
||||
int i;
|
||||
|
||||
s = (gamepad_state *)g_malloc0(sizeof (gamepad_state));
|
||||
s->buttons = (gamepad_button *)g_malloc0(n * sizeof (gamepad_button));
|
||||
s = g_new0(gamepad_state, 1);
|
||||
s->buttons = g_new0(gamepad_button, n);
|
||||
for (i = 0; i < n; i++) {
|
||||
s->buttons[i].irq = irq[i];
|
||||
s->buttons[i].keycode = keycode[i];
|
||||
|
@ -1239,7 +1239,7 @@ void omap_clk_init(struct omap_mpu_state_s *mpu)
|
||||
for (i = onchip_clks, count = 0; *i; i ++)
|
||||
if ((*i)->flags & flag)
|
||||
count ++;
|
||||
mpu->clks = (struct clk *) g_malloc0(sizeof(struct clk) * (count + 1));
|
||||
mpu->clks = g_new0(struct clk, count + 1);
|
||||
for (i = onchip_clks, j = mpu->clks; *i; i ++)
|
||||
if ((*i)->flags & flag) {
|
||||
memcpy(j, *i, sizeof(struct clk));
|
||||
|
@ -826,8 +826,7 @@ struct omap_gpmc_s *omap_gpmc_init(struct omap_mpu_state_s *mpu,
|
||||
qemu_irq irq, qemu_irq drq)
|
||||
{
|
||||
int cs;
|
||||
struct omap_gpmc_s *s = (struct omap_gpmc_s *)
|
||||
g_malloc0(sizeof(struct omap_gpmc_s));
|
||||
struct omap_gpmc_s *s = g_new0(struct omap_gpmc_s, 1);
|
||||
|
||||
memory_region_init_io(&s->iomem, NULL, &omap_gpmc_ops, s, "omap-gpmc", 0x1000);
|
||||
memory_region_add_subregion(get_system_memory(), base, &s->iomem);
|
||||
|
@ -157,8 +157,7 @@ static const MemoryRegionOps omap_sdrc_ops = {
|
||||
struct omap_sdrc_s *omap_sdrc_init(MemoryRegion *sysmem,
|
||||
hwaddr base)
|
||||
{
|
||||
struct omap_sdrc_s *s = (struct omap_sdrc_s *)
|
||||
g_malloc0(sizeof(struct omap_sdrc_s));
|
||||
struct omap_sdrc_s *s = g_new0(struct omap_sdrc_s, 1);
|
||||
|
||||
omap_sdrc_reset(s);
|
||||
|
||||
|
@ -19,6 +19,7 @@ common-obj-$(CONFIG_XGMAC) += xgmac.o
|
||||
common-obj-$(CONFIG_MIPSNET) += mipsnet.o
|
||||
common-obj-$(CONFIG_XILINX_AXI) += xilinx_axienet.o
|
||||
common-obj-$(CONFIG_ALLWINNER_EMAC) += allwinner_emac.o
|
||||
common-obj-$(CONFIG_IMX_FEC) += imx_fec.o
|
||||
|
||||
common-obj-$(CONFIG_CADENCE) += cadence_gem.o
|
||||
common-obj-$(CONFIG_STELLARIS_ENET) += stellaris_enet.o
|
||||
|
709
hw/net/imx_fec.c
Normal file
709
hw/net/imx_fec.c
Normal file
@ -0,0 +1,709 @@
|
||||
/*
|
||||
* i.MX Fast Ethernet Controller emulation.
|
||||
*
|
||||
* Copyright (c) 2013 Jean-Christophe Dubois. <jcd@tribudubois.net>
|
||||
*
|
||||
* Based on Coldfire Fast Ethernet Controller emulation.
|
||||
*
|
||||
* Copyright (c) 2007 CodeSourcery.
|
||||
*
|
||||
* 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 "hw/net/imx_fec.h"
|
||||
#include "sysemu/dma.h"
|
||||
|
||||
/* For crc32 */
|
||||
#include <zlib.h>
|
||||
|
||||
#ifndef IMX_FEC_DEBUG
|
||||
#define IMX_FEC_DEBUG 0
|
||||
#endif
|
||||
|
||||
#ifndef IMX_PHY_DEBUG
|
||||
#define IMX_PHY_DEBUG 0
|
||||
#endif
|
||||
|
||||
#if IMX_FEC_DEBUG
|
||||
#define FEC_PRINTF(fmt, ...) \
|
||||
do { fprintf(stderr, "%s[%s]: " fmt , TYPE_IMX_FEC, __func__, \
|
||||
## __VA_ARGS__); \
|
||||
} while (0)
|
||||
#else
|
||||
#define FEC_PRINTF(fmt, ...) do {} while (0)
|
||||
#endif
|
||||
|
||||
#if IMX_PHY_DEBUG
|
||||
#define PHY_PRINTF(fmt, ...) \
|
||||
do { fprintf(stderr, "%s.phy[%s]: " fmt , TYPE_IMX_FEC, __func__, \
|
||||
## __VA_ARGS__); \
|
||||
} while (0)
|
||||
#else
|
||||
#define PHY_PRINTF(fmt, ...) do {} while (0)
|
||||
#endif
|
||||
|
||||
static const VMStateDescription vmstate_imx_fec = {
|
||||
.name = TYPE_IMX_FEC,
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32(irq_state, IMXFECState),
|
||||
VMSTATE_UINT32(eir, IMXFECState),
|
||||
VMSTATE_UINT32(eimr, IMXFECState),
|
||||
VMSTATE_UINT32(rx_enabled, IMXFECState),
|
||||
VMSTATE_UINT32(rx_descriptor, IMXFECState),
|
||||
VMSTATE_UINT32(tx_descriptor, IMXFECState),
|
||||
VMSTATE_UINT32(ecr, IMXFECState),
|
||||
VMSTATE_UINT32(mmfr, IMXFECState),
|
||||
VMSTATE_UINT32(mscr, IMXFECState),
|
||||
VMSTATE_UINT32(mibc, IMXFECState),
|
||||
VMSTATE_UINT32(rcr, IMXFECState),
|
||||
VMSTATE_UINT32(tcr, IMXFECState),
|
||||
VMSTATE_UINT32(tfwr, IMXFECState),
|
||||
VMSTATE_UINT32(frsr, IMXFECState),
|
||||
VMSTATE_UINT32(erdsr, IMXFECState),
|
||||
VMSTATE_UINT32(etdsr, IMXFECState),
|
||||
VMSTATE_UINT32(emrbr, IMXFECState),
|
||||
VMSTATE_UINT32(miigsk_cfgr, IMXFECState),
|
||||
VMSTATE_UINT32(miigsk_enr, IMXFECState),
|
||||
|
||||
VMSTATE_UINT32(phy_status, IMXFECState),
|
||||
VMSTATE_UINT32(phy_control, IMXFECState),
|
||||
VMSTATE_UINT32(phy_advertise, IMXFECState),
|
||||
VMSTATE_UINT32(phy_int, IMXFECState),
|
||||
VMSTATE_UINT32(phy_int_mask, IMXFECState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
#define PHY_INT_ENERGYON (1 << 7)
|
||||
#define PHY_INT_AUTONEG_COMPLETE (1 << 6)
|
||||
#define PHY_INT_FAULT (1 << 5)
|
||||
#define PHY_INT_DOWN (1 << 4)
|
||||
#define PHY_INT_AUTONEG_LP (1 << 3)
|
||||
#define PHY_INT_PARFAULT (1 << 2)
|
||||
#define PHY_INT_AUTONEG_PAGE (1 << 1)
|
||||
|
||||
static void imx_fec_update(IMXFECState *s);
|
||||
|
||||
/*
|
||||
* The MII phy could raise a GPIO to the processor which in turn
|
||||
* could be handled as an interrpt by the OS.
|
||||
* For now we don't handle any GPIO/interrupt line, so the OS will
|
||||
* have to poll for the PHY status.
|
||||
*/
|
||||
static void phy_update_irq(IMXFECState *s)
|
||||
{
|
||||
imx_fec_update(s);
|
||||
}
|
||||
|
||||
static void phy_update_link(IMXFECState *s)
|
||||
{
|
||||
/* Autonegotiation status mirrors link status. */
|
||||
if (qemu_get_queue(s->nic)->link_down) {
|
||||
PHY_PRINTF("link is down\n");
|
||||
s->phy_status &= ~0x0024;
|
||||
s->phy_int |= PHY_INT_DOWN;
|
||||
} else {
|
||||
PHY_PRINTF("link is up\n");
|
||||
s->phy_status |= 0x0024;
|
||||
s->phy_int |= PHY_INT_ENERGYON;
|
||||
s->phy_int |= PHY_INT_AUTONEG_COMPLETE;
|
||||
}
|
||||
phy_update_irq(s);
|
||||
}
|
||||
|
||||
static void imx_fec_set_link(NetClientState *nc)
|
||||
{
|
||||
phy_update_link(IMX_FEC(qemu_get_nic_opaque(nc)));
|
||||
}
|
||||
|
||||
static void phy_reset(IMXFECState *s)
|
||||
{
|
||||
s->phy_status = 0x7809;
|
||||
s->phy_control = 0x3000;
|
||||
s->phy_advertise = 0x01e1;
|
||||
s->phy_int_mask = 0;
|
||||
s->phy_int = 0;
|
||||
phy_update_link(s);
|
||||
}
|
||||
|
||||
static uint32_t do_phy_read(IMXFECState *s, int reg)
|
||||
{
|
||||
uint32_t val;
|
||||
|
||||
if (reg > 31) {
|
||||
/* we only advertise one phy */
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (reg) {
|
||||
case 0: /* Basic Control */
|
||||
val = s->phy_control;
|
||||
break;
|
||||
case 1: /* Basic Status */
|
||||
val = s->phy_status;
|
||||
break;
|
||||
case 2: /* ID1 */
|
||||
val = 0x0007;
|
||||
break;
|
||||
case 3: /* ID2 */
|
||||
val = 0xc0d1;
|
||||
break;
|
||||
case 4: /* Auto-neg advertisement */
|
||||
val = s->phy_advertise;
|
||||
break;
|
||||
case 5: /* Auto-neg Link Partner Ability */
|
||||
val = 0x0f71;
|
||||
break;
|
||||
case 6: /* Auto-neg Expansion */
|
||||
val = 1;
|
||||
break;
|
||||
case 29: /* Interrupt source. */
|
||||
val = s->phy_int;
|
||||
s->phy_int = 0;
|
||||
phy_update_irq(s);
|
||||
break;
|
||||
case 30: /* Interrupt mask */
|
||||
val = s->phy_int_mask;
|
||||
break;
|
||||
case 17:
|
||||
case 18:
|
||||
case 27:
|
||||
case 31:
|
||||
qemu_log_mask(LOG_UNIMP, "%s.phy[%s]: reg %d not implemented\n",
|
||||
TYPE_IMX_FEC, __func__, reg);
|
||||
val = 0;
|
||||
break;
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s[%s]: Bad address at offset %d\n",
|
||||
TYPE_IMX_FEC, __func__, reg);
|
||||
val = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
PHY_PRINTF("read 0x%04x @ %d\n", val, reg);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static void do_phy_write(IMXFECState *s, int reg, uint32_t val)
|
||||
{
|
||||
PHY_PRINTF("write 0x%04x @ %d\n", val, reg);
|
||||
|
||||
if (reg > 31) {
|
||||
/* we only advertise one phy */
|
||||
return;
|
||||
}
|
||||
|
||||
switch (reg) {
|
||||
case 0: /* Basic Control */
|
||||
if (val & 0x8000) {
|
||||
phy_reset(s);
|
||||
} else {
|
||||
s->phy_control = val & 0x7980;
|
||||
/* Complete autonegotiation immediately. */
|
||||
if (val & 0x1000) {
|
||||
s->phy_status |= 0x0020;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 4: /* Auto-neg advertisement */
|
||||
s->phy_advertise = (val & 0x2d7f) | 0x80;
|
||||
break;
|
||||
case 30: /* Interrupt mask */
|
||||
s->phy_int_mask = val & 0xff;
|
||||
phy_update_irq(s);
|
||||
break;
|
||||
case 17:
|
||||
case 18:
|
||||
case 27:
|
||||
case 31:
|
||||
qemu_log_mask(LOG_UNIMP, "%s.phy[%s]: reg %d not implemented\n",
|
||||
TYPE_IMX_FEC, __func__, reg);
|
||||
break;
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s.phy[%s]: Bad address at offset %d\n",
|
||||
TYPE_IMX_FEC, __func__, reg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void imx_fec_read_bd(IMXFECBufDesc *bd, dma_addr_t addr)
|
||||
{
|
||||
dma_memory_read(&address_space_memory, addr, bd, sizeof(*bd));
|
||||
}
|
||||
|
||||
static void imx_fec_write_bd(IMXFECBufDesc *bd, dma_addr_t addr)
|
||||
{
|
||||
dma_memory_write(&address_space_memory, addr, bd, sizeof(*bd));
|
||||
}
|
||||
|
||||
static void imx_fec_update(IMXFECState *s)
|
||||
{
|
||||
uint32_t active;
|
||||
uint32_t changed;
|
||||
|
||||
active = s->eir & s->eimr;
|
||||
changed = active ^ s->irq_state;
|
||||
if (changed) {
|
||||
qemu_set_irq(s->irq, active);
|
||||
}
|
||||
s->irq_state = active;
|
||||
}
|
||||
|
||||
static void imx_fec_do_tx(IMXFECState *s)
|
||||
{
|
||||
int frame_size = 0;
|
||||
uint8_t frame[FEC_MAX_FRAME_SIZE];
|
||||
uint8_t *ptr = frame;
|
||||
uint32_t addr = s->tx_descriptor;
|
||||
|
||||
while (1) {
|
||||
IMXFECBufDesc bd;
|
||||
int len;
|
||||
|
||||
imx_fec_read_bd(&bd, addr);
|
||||
FEC_PRINTF("tx_bd %x flags %04x len %d data %08x\n",
|
||||
addr, bd.flags, bd.length, bd.data);
|
||||
if ((bd.flags & FEC_BD_R) == 0) {
|
||||
/* Run out of descriptors to transmit. */
|
||||
break;
|
||||
}
|
||||
len = bd.length;
|
||||
if (frame_size + len > FEC_MAX_FRAME_SIZE) {
|
||||
len = FEC_MAX_FRAME_SIZE - frame_size;
|
||||
s->eir |= FEC_INT_BABT;
|
||||
}
|
||||
dma_memory_read(&address_space_memory, bd.data, ptr, len);
|
||||
ptr += len;
|
||||
frame_size += len;
|
||||
if (bd.flags & FEC_BD_L) {
|
||||
/* Last buffer in frame. */
|
||||
qemu_send_packet(qemu_get_queue(s->nic), frame, len);
|
||||
ptr = frame;
|
||||
frame_size = 0;
|
||||
s->eir |= FEC_INT_TXF;
|
||||
}
|
||||
s->eir |= FEC_INT_TXB;
|
||||
bd.flags &= ~FEC_BD_R;
|
||||
/* Write back the modified descriptor. */
|
||||
imx_fec_write_bd(&bd, addr);
|
||||
/* Advance to the next descriptor. */
|
||||
if ((bd.flags & FEC_BD_W) != 0) {
|
||||
addr = s->etdsr;
|
||||
} else {
|
||||
addr += 8;
|
||||
}
|
||||
}
|
||||
|
||||
s->tx_descriptor = addr;
|
||||
|
||||
imx_fec_update(s);
|
||||
}
|
||||
|
||||
static void imx_fec_enable_rx(IMXFECState *s)
|
||||
{
|
||||
IMXFECBufDesc bd;
|
||||
uint32_t tmp;
|
||||
|
||||
imx_fec_read_bd(&bd, s->rx_descriptor);
|
||||
|
||||
tmp = ((bd.flags & FEC_BD_E) != 0);
|
||||
|
||||
if (!tmp) {
|
||||
FEC_PRINTF("RX buffer full\n");
|
||||
} else if (!s->rx_enabled) {
|
||||
qemu_flush_queued_packets(qemu_get_queue(s->nic));
|
||||
}
|
||||
|
||||
s->rx_enabled = tmp;
|
||||
}
|
||||
|
||||
static void imx_fec_reset(DeviceState *d)
|
||||
{
|
||||
IMXFECState *s = IMX_FEC(d);
|
||||
|
||||
/* Reset the FEC */
|
||||
s->eir = 0;
|
||||
s->eimr = 0;
|
||||
s->rx_enabled = 0;
|
||||
s->ecr = 0;
|
||||
s->mscr = 0;
|
||||
s->mibc = 0xc0000000;
|
||||
s->rcr = 0x05ee0001;
|
||||
s->tcr = 0;
|
||||
s->tfwr = 0;
|
||||
s->frsr = 0x500;
|
||||
s->miigsk_cfgr = 0;
|
||||
s->miigsk_enr = 0x6;
|
||||
|
||||
/* We also reset the PHY */
|
||||
phy_reset(s);
|
||||
}
|
||||
|
||||
static uint64_t imx_fec_read(void *opaque, hwaddr addr, unsigned size)
|
||||
{
|
||||
IMXFECState *s = IMX_FEC(opaque);
|
||||
|
||||
FEC_PRINTF("reading from @ 0x%03x\n", (int)addr);
|
||||
|
||||
switch (addr & 0x3ff) {
|
||||
case 0x004:
|
||||
return s->eir;
|
||||
case 0x008:
|
||||
return s->eimr;
|
||||
case 0x010:
|
||||
return s->rx_enabled ? (1 << 24) : 0; /* RDAR */
|
||||
case 0x014:
|
||||
return 0; /* TDAR */
|
||||
case 0x024:
|
||||
return s->ecr;
|
||||
case 0x040:
|
||||
return s->mmfr;
|
||||
case 0x044:
|
||||
return s->mscr;
|
||||
case 0x064:
|
||||
return s->mibc; /* MIBC */
|
||||
case 0x084:
|
||||
return s->rcr;
|
||||
case 0x0c4:
|
||||
return s->tcr;
|
||||
case 0x0e4: /* PALR */
|
||||
return (s->conf.macaddr.a[0] << 24)
|
||||
| (s->conf.macaddr.a[1] << 16)
|
||||
| (s->conf.macaddr.a[2] << 8)
|
||||
| s->conf.macaddr.a[3];
|
||||
break;
|
||||
case 0x0e8: /* PAUR */
|
||||
return (s->conf.macaddr.a[4] << 24)
|
||||
| (s->conf.macaddr.a[5] << 16)
|
||||
| 0x8808;
|
||||
case 0x0ec:
|
||||
return 0x10000; /* OPD */
|
||||
case 0x118:
|
||||
return 0;
|
||||
case 0x11c:
|
||||
return 0;
|
||||
case 0x120:
|
||||
return 0;
|
||||
case 0x124:
|
||||
return 0;
|
||||
case 0x144:
|
||||
return s->tfwr;
|
||||
case 0x14c:
|
||||
return 0x600;
|
||||
case 0x150:
|
||||
return s->frsr;
|
||||
case 0x180:
|
||||
return s->erdsr;
|
||||
case 0x184:
|
||||
return s->etdsr;
|
||||
case 0x188:
|
||||
return s->emrbr;
|
||||
case 0x300:
|
||||
return s->miigsk_cfgr;
|
||||
case 0x308:
|
||||
return s->miigsk_enr;
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s[%s]: Bad address at offset %d\n",
|
||||
TYPE_IMX_FEC, __func__, (int)addr);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void imx_fec_write(void *opaque, hwaddr addr,
|
||||
uint64_t value, unsigned size)
|
||||
{
|
||||
IMXFECState *s = IMX_FEC(opaque);
|
||||
|
||||
FEC_PRINTF("writing 0x%08x @ 0x%03x\n", (int)value, (int)addr);
|
||||
|
||||
switch (addr & 0x3ff) {
|
||||
case 0x004: /* EIR */
|
||||
s->eir &= ~value;
|
||||
break;
|
||||
case 0x008: /* EIMR */
|
||||
s->eimr = value;
|
||||
break;
|
||||
case 0x010: /* RDAR */
|
||||
if ((s->ecr & FEC_EN) && !s->rx_enabled) {
|
||||
imx_fec_enable_rx(s);
|
||||
}
|
||||
break;
|
||||
case 0x014: /* TDAR */
|
||||
if (s->ecr & FEC_EN) {
|
||||
imx_fec_do_tx(s);
|
||||
}
|
||||
break;
|
||||
case 0x024: /* ECR */
|
||||
s->ecr = value;
|
||||
if (value & FEC_RESET) {
|
||||
imx_fec_reset(DEVICE(s));
|
||||
}
|
||||
if ((s->ecr & FEC_EN) == 0) {
|
||||
s->rx_enabled = 0;
|
||||
}
|
||||
break;
|
||||
case 0x040: /* MMFR */
|
||||
/* store the value */
|
||||
s->mmfr = value;
|
||||
if (extract32(value, 28, 1)) {
|
||||
do_phy_write(s, extract32(value, 18, 9), extract32(value, 0, 16));
|
||||
} else {
|
||||
s->mmfr = do_phy_read(s, extract32(value, 18, 9));
|
||||
}
|
||||
/* raise the interrupt as the PHY operation is done */
|
||||
s->eir |= FEC_INT_MII;
|
||||
break;
|
||||
case 0x044: /* MSCR */
|
||||
s->mscr = value & 0xfe;
|
||||
break;
|
||||
case 0x064: /* MIBC */
|
||||
/* TODO: Implement MIB. */
|
||||
s->mibc = (value & 0x80000000) ? 0xc0000000 : 0;
|
||||
break;
|
||||
case 0x084: /* RCR */
|
||||
s->rcr = value & 0x07ff003f;
|
||||
/* TODO: Implement LOOP mode. */
|
||||
break;
|
||||
case 0x0c4: /* TCR */
|
||||
/* We transmit immediately, so raise GRA immediately. */
|
||||
s->tcr = value;
|
||||
if (value & 1) {
|
||||
s->eir |= FEC_INT_GRA;
|
||||
}
|
||||
break;
|
||||
case 0x0e4: /* PALR */
|
||||
s->conf.macaddr.a[0] = value >> 24;
|
||||
s->conf.macaddr.a[1] = value >> 16;
|
||||
s->conf.macaddr.a[2] = value >> 8;
|
||||
s->conf.macaddr.a[3] = value;
|
||||
break;
|
||||
case 0x0e8: /* PAUR */
|
||||
s->conf.macaddr.a[4] = value >> 24;
|
||||
s->conf.macaddr.a[5] = value >> 16;
|
||||
break;
|
||||
case 0x0ec: /* OPDR */
|
||||
break;
|
||||
case 0x118: /* IAUR */
|
||||
case 0x11c: /* IALR */
|
||||
case 0x120: /* GAUR */
|
||||
case 0x124: /* GALR */
|
||||
/* TODO: implement MAC hash filtering. */
|
||||
break;
|
||||
case 0x144: /* TFWR */
|
||||
s->tfwr = value & 3;
|
||||
break;
|
||||
case 0x14c: /* FRBR */
|
||||
/* FRBR writes ignored. */
|
||||
break;
|
||||
case 0x150: /* FRSR */
|
||||
s->frsr = (value & 0x3fc) | 0x400;
|
||||
break;
|
||||
case 0x180: /* ERDSR */
|
||||
s->erdsr = value & ~3;
|
||||
s->rx_descriptor = s->erdsr;
|
||||
break;
|
||||
case 0x184: /* ETDSR */
|
||||
s->etdsr = value & ~3;
|
||||
s->tx_descriptor = s->etdsr;
|
||||
break;
|
||||
case 0x188: /* EMRBR */
|
||||
s->emrbr = value & 0x7f0;
|
||||
break;
|
||||
case 0x300: /* MIIGSK_CFGR */
|
||||
s->miigsk_cfgr = value & 0x53;
|
||||
break;
|
||||
case 0x308: /* MIIGSK_ENR */
|
||||
s->miigsk_enr = (value & 0x2) ? 0x6 : 0;
|
||||
break;
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s[%s]: Bad address at offset %d\n",
|
||||
TYPE_IMX_FEC, __func__, (int)addr);
|
||||
break;
|
||||
}
|
||||
|
||||
imx_fec_update(s);
|
||||
}
|
||||
|
||||
static int imx_fec_can_receive(NetClientState *nc)
|
||||
{
|
||||
IMXFECState *s = IMX_FEC(qemu_get_nic_opaque(nc));
|
||||
|
||||
return s->rx_enabled;
|
||||
}
|
||||
|
||||
static ssize_t imx_fec_receive(NetClientState *nc, const uint8_t *buf,
|
||||
size_t len)
|
||||
{
|
||||
IMXFECState *s = IMX_FEC(qemu_get_nic_opaque(nc));
|
||||
IMXFECBufDesc bd;
|
||||
uint32_t flags = 0;
|
||||
uint32_t addr;
|
||||
uint32_t crc;
|
||||
uint32_t buf_addr;
|
||||
uint8_t *crc_ptr;
|
||||
unsigned int buf_len;
|
||||
size_t size = len;
|
||||
|
||||
FEC_PRINTF("len %d\n", (int)size);
|
||||
|
||||
if (!s->rx_enabled) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s[%s]: Unexpected packet\n",
|
||||
TYPE_IMX_FEC, __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 4 bytes for the CRC. */
|
||||
size += 4;
|
||||
crc = cpu_to_be32(crc32(~0, buf, size));
|
||||
crc_ptr = (uint8_t *) &crc;
|
||||
|
||||
/* Huge frames are truncted. */
|
||||
if (size > FEC_MAX_FRAME_SIZE) {
|
||||
size = FEC_MAX_FRAME_SIZE;
|
||||
flags |= FEC_BD_TR | FEC_BD_LG;
|
||||
}
|
||||
|
||||
/* Frames larger than the user limit just set error flags. */
|
||||
if (size > (s->rcr >> 16)) {
|
||||
flags |= FEC_BD_LG;
|
||||
}
|
||||
|
||||
addr = s->rx_descriptor;
|
||||
while (size > 0) {
|
||||
imx_fec_read_bd(&bd, addr);
|
||||
if ((bd.flags & FEC_BD_E) == 0) {
|
||||
/* No descriptors available. Bail out. */
|
||||
/*
|
||||
* FIXME: This is wrong. We should probably either
|
||||
* save the remainder for when more RX buffers are
|
||||
* available, or flag an error.
|
||||
*/
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s[%s]: Lost end of frame\n",
|
||||
TYPE_IMX_FEC, __func__);
|
||||
break;
|
||||
}
|
||||
buf_len = (size <= s->emrbr) ? size : s->emrbr;
|
||||
bd.length = buf_len;
|
||||
size -= buf_len;
|
||||
FEC_PRINTF("rx_bd %x length %d\n", addr, bd.length);
|
||||
/* The last 4 bytes are the CRC. */
|
||||
if (size < 4) {
|
||||
buf_len += size - 4;
|
||||
}
|
||||
buf_addr = bd.data;
|
||||
dma_memory_write(&address_space_memory, buf_addr, buf, buf_len);
|
||||
buf += buf_len;
|
||||
if (size < 4) {
|
||||
dma_memory_write(&address_space_memory, buf_addr + buf_len,
|
||||
crc_ptr, 4 - size);
|
||||
crc_ptr += 4 - size;
|
||||
}
|
||||
bd.flags &= ~FEC_BD_E;
|
||||
if (size == 0) {
|
||||
/* Last buffer in frame. */
|
||||
bd.flags |= flags | FEC_BD_L;
|
||||
FEC_PRINTF("rx frame flags %04x\n", bd.flags);
|
||||
s->eir |= FEC_INT_RXF;
|
||||
} else {
|
||||
s->eir |= FEC_INT_RXB;
|
||||
}
|
||||
imx_fec_write_bd(&bd, addr);
|
||||
/* Advance to the next descriptor. */
|
||||
if ((bd.flags & FEC_BD_W) != 0) {
|
||||
addr = s->erdsr;
|
||||
} else {
|
||||
addr += 8;
|
||||
}
|
||||
}
|
||||
s->rx_descriptor = addr;
|
||||
imx_fec_enable_rx(s);
|
||||
imx_fec_update(s);
|
||||
return len;
|
||||
}
|
||||
|
||||
static const MemoryRegionOps imx_fec_ops = {
|
||||
.read = imx_fec_read,
|
||||
.write = imx_fec_write,
|
||||
.valid.min_access_size = 4,
|
||||
.valid.max_access_size = 4,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
static void imx_fec_cleanup(NetClientState *nc)
|
||||
{
|
||||
IMXFECState *s = IMX_FEC(qemu_get_nic_opaque(nc));
|
||||
|
||||
s->nic = NULL;
|
||||
}
|
||||
|
||||
static NetClientInfo net_imx_fec_info = {
|
||||
.type = NET_CLIENT_OPTIONS_KIND_NIC,
|
||||
.size = sizeof(NICState),
|
||||
.can_receive = imx_fec_can_receive,
|
||||
.receive = imx_fec_receive,
|
||||
.cleanup = imx_fec_cleanup,
|
||||
.link_status_changed = imx_fec_set_link,
|
||||
};
|
||||
|
||||
|
||||
static void imx_fec_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
IMXFECState *s = IMX_FEC(dev);
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
|
||||
|
||||
memory_region_init_io(&s->iomem, OBJECT(dev), &imx_fec_ops, s,
|
||||
TYPE_IMX_FEC, 0x400);
|
||||
sysbus_init_mmio(sbd, &s->iomem);
|
||||
sysbus_init_irq(sbd, &s->irq);
|
||||
qemu_macaddr_default_if_unset(&s->conf.macaddr);
|
||||
|
||||
s->conf.peers.ncs[0] = nd_table[0].netdev;
|
||||
|
||||
s->nic = qemu_new_nic(&net_imx_fec_info, &s->conf,
|
||||
object_get_typename(OBJECT(dev)), DEVICE(dev)->id,
|
||||
s);
|
||||
qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
|
||||
}
|
||||
|
||||
static Property imx_fec_properties[] = {
|
||||
DEFINE_NIC_PROPERTIES(IMXFECState, conf),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void imx_fec_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->vmsd = &vmstate_imx_fec;
|
||||
dc->reset = imx_fec_reset;
|
||||
dc->props = imx_fec_properties;
|
||||
dc->realize = imx_fec_realize;
|
||||
}
|
||||
|
||||
static const TypeInfo imx_fec_info = {
|
||||
.name = TYPE_IMX_FEC,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(IMXFECState),
|
||||
.class_init = imx_fec_class_init,
|
||||
};
|
||||
|
||||
static void imx_fec_register_types(void)
|
||||
{
|
||||
type_register_static(&imx_fec_info);
|
||||
}
|
||||
|
||||
type_init(imx_fec_register_types)
|
@ -578,8 +578,7 @@ struct omap_mmc_s *omap_mmc_init(hwaddr base,
|
||||
BlockBackend *blk,
|
||||
qemu_irq irq, qemu_irq dma[], omap_clk clk)
|
||||
{
|
||||
struct omap_mmc_s *s = (struct omap_mmc_s *)
|
||||
g_malloc0(sizeof(struct omap_mmc_s));
|
||||
struct omap_mmc_s *s = g_new0(struct omap_mmc_s, 1);
|
||||
|
||||
s->irq = irq;
|
||||
s->dma = dma;
|
||||
@ -605,8 +604,7 @@ struct omap_mmc_s *omap2_mmc_init(struct omap_target_agent_s *ta,
|
||||
BlockBackend *blk, qemu_irq irq, qemu_irq dma[],
|
||||
omap_clk fclk, omap_clk iclk)
|
||||
{
|
||||
struct omap_mmc_s *s = (struct omap_mmc_s *)
|
||||
g_malloc0(sizeof(struct omap_mmc_s));
|
||||
struct omap_mmc_s *s = g_new0(struct omap_mmc_s, 1);
|
||||
|
||||
s->irq = irq;
|
||||
s->dma = dma;
|
||||
|
@ -55,7 +55,9 @@ static uint8_t *smbios_tables;
|
||||
static size_t smbios_tables_len;
|
||||
static unsigned smbios_table_max;
|
||||
static unsigned smbios_table_cnt;
|
||||
static struct smbios_entry_point ep;
|
||||
static SmbiosEntryPointType smbios_ep_type = SMBIOS_ENTRY_POINT_21;
|
||||
|
||||
static SmbiosEntryPoint ep;
|
||||
|
||||
static int smbios_type4_count = 0;
|
||||
static bool smbios_immutable;
|
||||
@ -771,11 +773,12 @@ void smbios_set_cpuid(uint32_t version, uint32_t features)
|
||||
|
||||
void smbios_set_defaults(const char *manufacturer, const char *product,
|
||||
const char *version, bool legacy_mode,
|
||||
bool uuid_encoded)
|
||||
bool uuid_encoded, SmbiosEntryPointType ep_type)
|
||||
{
|
||||
smbios_have_defaults = true;
|
||||
smbios_legacy = legacy_mode;
|
||||
smbios_uuid_encoded = uuid_encoded;
|
||||
smbios_ep_type = ep_type;
|
||||
|
||||
/* drop unwanted version of command-line file blob(s) */
|
||||
if (smbios_legacy) {
|
||||
@ -808,26 +811,53 @@ void smbios_set_defaults(const char *manufacturer, const char *product,
|
||||
|
||||
static void smbios_entry_point_setup(void)
|
||||
{
|
||||
memcpy(ep.anchor_string, "_SM_", 4);
|
||||
memcpy(ep.intermediate_anchor_string, "_DMI_", 5);
|
||||
ep.length = sizeof(struct smbios_entry_point);
|
||||
ep.entry_point_revision = 0; /* formatted_area reserved, per spec v2.1+ */
|
||||
memset(ep.formatted_area, 0, 5);
|
||||
switch (smbios_ep_type) {
|
||||
case SMBIOS_ENTRY_POINT_21:
|
||||
memcpy(ep.ep21.anchor_string, "_SM_", 4);
|
||||
memcpy(ep.ep21.intermediate_anchor_string, "_DMI_", 5);
|
||||
ep.ep21.length = sizeof(struct smbios_21_entry_point);
|
||||
ep.ep21.entry_point_revision = 0; /* formatted_area reserved */
|
||||
memset(ep.ep21.formatted_area, 0, 5);
|
||||
|
||||
/* compliant with smbios spec v2.8 */
|
||||
ep.smbios_major_version = 2;
|
||||
ep.smbios_minor_version = 8;
|
||||
ep.smbios_bcd_revision = 0x28;
|
||||
/* compliant with smbios spec v2.8 */
|
||||
ep.ep21.smbios_major_version = 2;
|
||||
ep.ep21.smbios_minor_version = 8;
|
||||
ep.ep21.smbios_bcd_revision = 0x28;
|
||||
|
||||
/* set during table construction, but BIOS may override: */
|
||||
ep.structure_table_length = cpu_to_le16(smbios_tables_len);
|
||||
ep.max_structure_size = cpu_to_le16(smbios_table_max);
|
||||
ep.number_of_structures = cpu_to_le16(smbios_table_cnt);
|
||||
/* set during table construction, but BIOS may override: */
|
||||
ep.ep21.structure_table_length = cpu_to_le16(smbios_tables_len);
|
||||
ep.ep21.max_structure_size = cpu_to_le16(smbios_table_max);
|
||||
ep.ep21.number_of_structures = cpu_to_le16(smbios_table_cnt);
|
||||
|
||||
/* BIOS must recalculate: */
|
||||
ep.checksum = 0;
|
||||
ep.intermediate_checksum = 0;
|
||||
ep.structure_table_address = cpu_to_le32(0);
|
||||
/* BIOS must recalculate */
|
||||
ep.ep21.checksum = 0;
|
||||
ep.ep21.intermediate_checksum = 0;
|
||||
ep.ep21.structure_table_address = cpu_to_le32(0);
|
||||
|
||||
break;
|
||||
case SMBIOS_ENTRY_POINT_30:
|
||||
memcpy(ep.ep30.anchor_string, "_SM3_", 5);
|
||||
ep.ep30.length = sizeof(struct smbios_30_entry_point);
|
||||
ep.ep30.entry_point_revision = 1;
|
||||
ep.ep30.reserved = 0;
|
||||
|
||||
/* compliant with smbios spec 3.0 */
|
||||
ep.ep30.smbios_major_version = 3;
|
||||
ep.ep30.smbios_minor_version = 0;
|
||||
ep.ep30.smbios_doc_rev = 0;
|
||||
|
||||
/* set during table construct, but BIOS might override */
|
||||
ep.ep30.structure_table_max_size = cpu_to_le32(smbios_tables_len);
|
||||
|
||||
/* BIOS must recalculate */
|
||||
ep.ep30.checksum = 0;
|
||||
ep.ep30.structure_table_address = cpu_to_le64(0);
|
||||
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void smbios_get_tables(const struct smbios_phys_mem_area *mem_array,
|
||||
@ -885,7 +915,15 @@ void smbios_get_tables(const struct smbios_phys_mem_area *mem_array,
|
||||
*tables = smbios_tables;
|
||||
*tables_len = smbios_tables_len;
|
||||
*anchor = (uint8_t *)&ep;
|
||||
*anchor_len = sizeof(struct smbios_entry_point);
|
||||
|
||||
/* calculate length based on anchor string */
|
||||
if (!strncmp((char *)&ep, "_SM_", 4)) {
|
||||
*anchor_len = sizeof(struct smbios_21_entry_point);
|
||||
} else if (!strncmp((char *)&ep, "_SM3_", 5)) {
|
||||
*anchor_len = sizeof(struct smbios_30_entry_point);
|
||||
} else {
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
static void save_opt(const char **dest, QemuOpts *opts, const char *name)
|
||||
|
@ -342,8 +342,7 @@ static const MemoryRegionOps omap_mcspi_ops = {
|
||||
struct omap_mcspi_s *omap_mcspi_init(struct omap_target_agent_s *ta, int chnum,
|
||||
qemu_irq irq, qemu_irq *drq, omap_clk fclk, omap_clk iclk)
|
||||
{
|
||||
struct omap_mcspi_s *s = (struct omap_mcspi_s *)
|
||||
g_malloc0(sizeof(struct omap_mcspi_s));
|
||||
struct omap_mcspi_s *s = g_new0(struct omap_mcspi_s, 1);
|
||||
struct omap_mcspi_ch_s *ch = s->ch;
|
||||
|
||||
s->irq = irq;
|
||||
|
@ -12,7 +12,6 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "hw/arm/imx.h"
|
||||
#include "hw/timer/imx_epit.h"
|
||||
#include "hw/misc/imx_ccm.h"
|
||||
#include "qemu/main-loop.h"
|
||||
@ -287,16 +286,6 @@ static void imx_epit_cmp(void *opaque)
|
||||
imx_epit_update_int(s);
|
||||
}
|
||||
|
||||
void imx_timerp_create(const hwaddr addr, qemu_irq irq, DeviceState *ccm)
|
||||
{
|
||||
IMXEPITState *pp;
|
||||
DeviceState *dev;
|
||||
|
||||
dev = sysbus_create_simple(TYPE_IMX_EPIT, addr, irq);
|
||||
pp = IMX_EPIT(dev);
|
||||
pp->ccm = ccm;
|
||||
}
|
||||
|
||||
static const MemoryRegionOps imx_epit_ops = {
|
||||
.read = imx_epit_read,
|
||||
.write = imx_epit_write,
|
||||
|
@ -12,7 +12,6 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "hw/arm/imx.h"
|
||||
#include "hw/timer/imx_gpt.h"
|
||||
#include "hw/misc/imx_ccm.h"
|
||||
#include "qemu/main-loop.h"
|
||||
@ -449,16 +448,6 @@ static void imx_gpt_realize(DeviceState *dev, Error **errp)
|
||||
s->timer = ptimer_init(bh);
|
||||
}
|
||||
|
||||
void imx_timerg_create(const hwaddr addr, qemu_irq irq, DeviceState *ccm)
|
||||
{
|
||||
IMXGPTState *pp;
|
||||
DeviceState *dev;
|
||||
|
||||
dev = sysbus_create_simple(TYPE_IMX_GPT, addr, irq);
|
||||
pp = IMX_GPT(dev);
|
||||
pp->ccm = ccm;
|
||||
}
|
||||
|
||||
static void imx_gpt_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
@ -468,8 +468,7 @@ static const MemoryRegionOps omap_gp_timer_ops = {
|
||||
struct omap_gp_timer_s *omap_gp_timer_init(struct omap_target_agent_s *ta,
|
||||
qemu_irq irq, omap_clk fclk, omap_clk iclk)
|
||||
{
|
||||
struct omap_gp_timer_s *s = (struct omap_gp_timer_s *)
|
||||
g_malloc0(sizeof(struct omap_gp_timer_s));
|
||||
struct omap_gp_timer_s *s = g_new0(struct omap_gp_timer_s, 1);
|
||||
|
||||
s->ta = ta;
|
||||
s->irq = irq;
|
||||
|
@ -14,7 +14,34 @@
|
||||
typedef void (*gdb_syscall_complete_cb)(CPUState *cpu,
|
||||
target_ulong ret, target_ulong err);
|
||||
|
||||
/**
|
||||
* gdb_do_syscall:
|
||||
* @cb: function to call when the system call has completed
|
||||
* @fmt: gdb syscall format string
|
||||
* ...: list of arguments to interpolate into @fmt
|
||||
*
|
||||
* Send a GDB syscall request. This function will return immediately;
|
||||
* the callback function will be called later when the remote system
|
||||
* call has completed.
|
||||
*
|
||||
* @fmt should be in the 'call-id,parameter,parameter...' format documented
|
||||
* for the F request packet in the GDB remote protocol. A limited set of
|
||||
* printf-style format specifiers is supported:
|
||||
* %x - target_ulong argument printed in hex
|
||||
* %lx - 64-bit argument printed in hex
|
||||
* %s - string pointer (target_ulong) and length (int) pair
|
||||
*/
|
||||
void gdb_do_syscall(gdb_syscall_complete_cb cb, const char *fmt, ...);
|
||||
/**
|
||||
* gdb_do_syscallv:
|
||||
* @cb: function to call when the system call has completed
|
||||
* @fmt: gdb syscall format string
|
||||
* @va: arguments to interpolate into @fmt
|
||||
*
|
||||
* As gdb_do_syscall, but taking a va_list rather than a variable
|
||||
* argument list.
|
||||
*/
|
||||
void gdb_do_syscallv(gdb_syscall_complete_cb cb, const char *fmt, va_list va);
|
||||
int use_gdb_syscalls(void);
|
||||
void gdb_set_stop_cpu(CPUState *cpu);
|
||||
void gdb_exit(CPUArchState *, int);
|
||||
|
@ -9,6 +9,14 @@
|
||||
#ifndef SOFTMMU_SEMI_H
|
||||
#define SOFTMMU_SEMI_H 1
|
||||
|
||||
static inline uint64_t softmmu_tget64(CPUArchState *env, target_ulong addr)
|
||||
{
|
||||
uint64_t val;
|
||||
|
||||
cpu_memory_rw_debug(ENV_GET_CPU(env), addr, (uint8_t *)&val, 8, 0);
|
||||
return tswap64(val);
|
||||
}
|
||||
|
||||
static inline uint32_t softmmu_tget32(CPUArchState *env, target_ulong addr)
|
||||
{
|
||||
uint32_t val;
|
||||
@ -16,6 +24,7 @@ static inline uint32_t softmmu_tget32(CPUArchState *env, target_ulong addr)
|
||||
cpu_memory_rw_debug(ENV_GET_CPU(env), addr, (uint8_t *)&val, 4, 0);
|
||||
return tswap32(val);
|
||||
}
|
||||
|
||||
static inline uint32_t softmmu_tget8(CPUArchState *env, target_ulong addr)
|
||||
{
|
||||
uint8_t val;
|
||||
@ -24,16 +33,25 @@ static inline uint32_t softmmu_tget8(CPUArchState *env, target_ulong addr)
|
||||
return val;
|
||||
}
|
||||
|
||||
#define get_user_u64(arg, p) ({ arg = softmmu_tget64(env, p); 0; })
|
||||
#define get_user_u32(arg, p) ({ arg = softmmu_tget32(env, p) ; 0; })
|
||||
#define get_user_u8(arg, p) ({ arg = softmmu_tget8(env, p) ; 0; })
|
||||
#define get_user_ual(arg, p) get_user_u32(arg, p)
|
||||
|
||||
static inline void softmmu_tput64(CPUArchState *env,
|
||||
target_ulong addr, uint64_t val)
|
||||
{
|
||||
val = tswap64(val);
|
||||
cpu_memory_rw_debug(ENV_GET_CPU(env), addr, (uint8_t *)&val, 8, 1);
|
||||
}
|
||||
|
||||
static inline void softmmu_tput32(CPUArchState *env,
|
||||
target_ulong addr, uint32_t val)
|
||||
{
|
||||
val = tswap32(val);
|
||||
cpu_memory_rw_debug(ENV_GET_CPU(env), addr, (uint8_t *)&val, 4, 1);
|
||||
}
|
||||
#define put_user_u64(arg, p) ({ softmmu_tput64(env, p, arg) ; 0; })
|
||||
#define put_user_u32(arg, p) ({ softmmu_tput32(env, p, arg) ; 0; })
|
||||
#define put_user_ual(arg, p) put_user_u32(arg, p)
|
||||
|
||||
|
234
include/hw/arm/fsl-imx25.h
Normal file
234
include/hw/arm/fsl-imx25.h
Normal file
@ -0,0 +1,234 @@
|
||||
/*
|
||||
* Freescale i.MX25 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_IMX25_H
|
||||
#define FSL_IMX25_H
|
||||
|
||||
#include "hw/arm/arm.h"
|
||||
#include "hw/intc/imx_avic.h"
|
||||
#include "hw/misc/imx_ccm.h"
|
||||
#include "hw/char/imx_serial.h"
|
||||
#include "hw/timer/imx_gpt.h"
|
||||
#include "hw/timer/imx_epit.h"
|
||||
#include "hw/net/imx_fec.h"
|
||||
#include "hw/i2c/imx_i2c.h"
|
||||
#include "exec/memory.h"
|
||||
|
||||
#define TYPE_FSL_IMX25 "fsl,imx25"
|
||||
#define FSL_IMX25(obj) OBJECT_CHECK(FslIMX25State, (obj), TYPE_FSL_IMX25)
|
||||
|
||||
#define FSL_IMX25_NUM_UARTS 5
|
||||
#define FSL_IMX25_NUM_GPTS 4
|
||||
#define FSL_IMX25_NUM_EPITS 2
|
||||
#define FSL_IMX25_NUM_I2CS 3
|
||||
|
||||
typedef struct FslIMX25State {
|
||||
/*< private >*/
|
||||
DeviceState parent_obj;
|
||||
|
||||
/*< public >*/
|
||||
ARMCPU cpu;
|
||||
IMXAVICState avic;
|
||||
IMXCCMState ccm;
|
||||
IMXSerialState uart[FSL_IMX25_NUM_UARTS];
|
||||
IMXGPTState gpt[FSL_IMX25_NUM_GPTS];
|
||||
IMXEPITState epit[FSL_IMX25_NUM_EPITS];
|
||||
IMXFECState fec;
|
||||
IMXI2CState i2c[FSL_IMX25_NUM_I2CS];
|
||||
MemoryRegion rom[2];
|
||||
MemoryRegion iram;
|
||||
MemoryRegion iram_alias;
|
||||
} FslIMX25State;
|
||||
|
||||
/**
|
||||
* i.MX25 memory map
|
||||
****************************************************************
|
||||
* 0x0000_0000 0x0000_3FFF 16 Kbytes ROM (36 Kbytes)
|
||||
* 0x0000_4000 0x0040_3FFF 4 Mbytes Reserved
|
||||
* 0x0040_4000 0x0040_8FFF 20 Kbytes ROM (36 Kbytes)
|
||||
* 0x0040_9000 0x0FFF_FFFF 252 Mbytes (minus 36 Kbytes) Reserved
|
||||
* 0x1000_0000 0x1FFF_FFFF 256 Mbytes Reserved
|
||||
* 0x2000_0000 0x2FFF_FFFF 256 Mbytes Reserved
|
||||
* 0x3000_0000 0x3FFF_FFFF 256 Mbytes Reserved
|
||||
* 0x4000_0000 0x43EF_FFFF 63 Mbytes Reserved
|
||||
* 0x43F0_0000 0x43F0_3FFF 16 Kbytes AIPS A control registers
|
||||
* 0x43F0_4000 0x43F0_7FFF 16 Kbytes ARM926 platform MAX
|
||||
* 0x43F0_8000 0x43F0_BFFF 16 Kbytes ARM926 platform CLKCTL
|
||||
* 0x43F0_C000 0x43F0_FFFF 16 Kbytes ARM926 platform ETB registers
|
||||
* 0x43F1_0000 0x43F1_3FFF 16 Kbytes ARM926 platform ETB memory
|
||||
* 0x43F1_4000 0x43F1_7FFF 16 Kbytes ARM926 platform AAPE registers
|
||||
* 0x43F1_8000 0x43F7_FFFF 416 Kbytes Reserved
|
||||
* 0x43F8_0000 0x43F8_3FFF 16 Kbytes I2C-1
|
||||
* 0x43F8_4000 0x43F8_7FFF 16 Kbytes I2C-3
|
||||
* 0x43F8_8000 0x43F8_BFFF 16 Kbytes CAN-1
|
||||
* 0x43F8_C000 0x43F8_FFFF 16 Kbytes CAN-2
|
||||
* 0x43F9_0000 0x43F9_3FFF 16 Kbytes UART-1
|
||||
* 0x43F9_4000 0x43F9_7FFF 16 Kbytes UART-2
|
||||
* 0x43F9_8000 0x43F9_BFFF 16 Kbytes I2C-2
|
||||
* 0x43F9_C000 0x43F9_FFFF 16 Kbytes 1-Wire
|
||||
* 0x43FA_0000 0x43FA_3FFF 16 Kbytes ATA (CPU side)
|
||||
* 0x43FA_4000 0x43FA_7FFF 16 Kbytes CSPI-1
|
||||
* 0x43FA_8000 0x43FA_BFFF 16 Kbytes KPP
|
||||
* 0x43FA_C000 0x43FA_FFFF 16 Kbytes IOMUXC
|
||||
* 0x43FB_0000 0x43FB_3FFF 16 Kbytes AUDMUX
|
||||
* 0x43FB_4000 0x43FB_7FFF 16 Kbytes Reserved
|
||||
* 0x43FB_8000 0x43FB_BFFF 16 Kbytes ECT (IP BUS A)
|
||||
* 0x43FB_C000 0x43FB_FFFF 16 Kbytes ECT (IP BUS B)
|
||||
* 0x43FC_0000 0x43FF_FFFF 256 Kbytes Reserved AIPS A off-platform slots
|
||||
* 0x4400_0000 0x4FFF_FFFF 192 Mbytes Reserved
|
||||
* 0x5000_0000 0x5000_3FFF 16 Kbytes SPBA base address
|
||||
* 0x5000_4000 0x5000_7FFF 16 Kbytes CSPI-3
|
||||
* 0x5000_8000 0x5000_BFFF 16 Kbytes UART-4
|
||||
* 0x5000_C000 0x5000_FFFF 16 Kbytes UART-3
|
||||
* 0x5001_0000 0x5001_3FFF 16 Kbytes CSPI-2
|
||||
* 0x5001_4000 0x5001_7FFF 16 Kbytes SSI-2
|
||||
* 0x5001_C000 0x5001_FFFF 16 Kbytes Reserved
|
||||
* 0x5002_0000 0x5002_3FFF 16 Kbytes ATA
|
||||
* 0x5002_4000 0x5002_7FFF 16 Kbytes SIM-1
|
||||
* 0x5002_8000 0x5002_BFFF 16 Kbytes SIM-2
|
||||
* 0x5002_C000 0x5002_FFFF 16 Kbytes UART-5
|
||||
* 0x5003_0000 0x5003_3FFF 16 Kbytes TSC
|
||||
* 0x5003_4000 0x5003_7FFF 16 Kbytes SSI-1
|
||||
* 0x5003_8000 0x5003_BFFF 16 Kbytes FEC
|
||||
* 0x5003_C000 0x5003_FFFF 16 Kbytes SPBA registers
|
||||
* 0x5004_0000 0x51FF_FFFF 32 Mbytes (minus 256 Kbytes)
|
||||
* 0x5200_0000 0x53EF_FFFF 31 Mbytes Reserved
|
||||
* 0x53F0_0000 0x53F0_3FFF 16 Kbytes AIPS B control registers
|
||||
* 0x53F0_4000 0x53F7_FFFF 496 Kbytes Reserved
|
||||
* 0x53F8_0000 0x53F8_3FFF 16 Kbytes CCM
|
||||
* 0x53F8_4000 0x53F8_7FFF 16 Kbytes GPT-4
|
||||
* 0x53F8_8000 0x53F8_BFFF 16 Kbytes GPT-3
|
||||
* 0x53F8_C000 0x53F8_FFFF 16 Kbytes GPT-2
|
||||
* 0x53F9_0000 0x53F9_3FFF 16 Kbytes GPT-1
|
||||
* 0x53F9_4000 0x53F9_7FFF 16 Kbytes EPIT-1
|
||||
* 0x53F9_8000 0x53F9_BFFF 16 Kbytes EPIT-2
|
||||
* 0x53F9_C000 0x53F9_FFFF 16 Kbytes GPIO-4
|
||||
* 0x53FA_0000 0x53FA_3FFF 16 Kbytes PWM-2
|
||||
* 0x53FA_4000 0x53FA_7FFF 16 Kbytes GPIO-3
|
||||
* 0x53FA_8000 0x53FA_BFFF 16 Kbytes PWM-3
|
||||
* 0x53FA_C000 0x53FA_FFFF 16 Kbytes SCC
|
||||
* 0x53FB_0000 0x53FB_3FFF 16 Kbytes RNGB
|
||||
* 0x53FB_4000 0x53FB_7FFF 16 Kbytes eSDHC-1
|
||||
* 0x53FB_8000 0x53FB_BFFF 16 Kbytes eSDHC-2
|
||||
* 0x53FB_C000 0x53FB_FFFF 16 Kbytes LCDC
|
||||
* 0x53FC_0000 0x53FC_3FFF 16 Kbytes SLCDC
|
||||
* 0x53FC_4000 0x53FC_7FFF 16 Kbytes Reserved
|
||||
* 0x53FC_8000 0x53FC_BFFF 16 Kbytes PWM-4
|
||||
* 0x53FC_C000 0x53FC_FFFF 16 Kbytes GPIO-1
|
||||
* 0x53FD_0000 0x53FD_3FFF 16 Kbytes GPIO-2
|
||||
* 0x53FD_4000 0x53FD_7FFF 16 Kbytes SDMA
|
||||
* 0x53FD_8000 0x53FD_BFFF 16 Kbytes Reserved
|
||||
* 0x53FD_C000 0x53FD_FFFF 16 Kbytes WDOG
|
||||
* 0x53FE_0000 0x53FE_3FFF 16 Kbytes PWM-1
|
||||
* 0x53FE_4000 0x53FE_7FFF 16 Kbytes Reserved
|
||||
* 0x53FE_8000 0x53FE_BFFF 16 Kbytes Reserved
|
||||
* 0x53FE_C000 0x53FE_FFFF 16 Kbytes RTICv3
|
||||
* 0x53FF_0000 0x53FF_3FFF 16 Kbytes IIM
|
||||
* 0x53FF_4000 0x53FF_7FFF 16 Kbytes USB
|
||||
* 0x53FF_8000 0x53FF_BFFF 16 Kbytes CSI
|
||||
* 0x53FF_C000 0x53FF_FFFF 16 Kbytes DryIce
|
||||
* 0x5400_0000 0x5FFF_FFFF 192 Mbytes Reserved (aliased AIPS B slots)
|
||||
* 0x6000_0000 0x67FF_FFFF 128 Mbytes ARM926 platform ROMPATCH
|
||||
* 0x6800_0000 0x6FFF_FFFF 128 Mbytes ARM926 platform ASIC
|
||||
* 0x7000_0000 0x77FF_FFFF 128 Mbytes Reserved
|
||||
* 0x7800_0000 0x7801_FFFF 128 Kbytes RAM
|
||||
* 0x7802_0000 0x7FFF_FFFF 128 Mbytes (minus 128 Kbytes)
|
||||
* 0x8000_0000 0x8FFF_FFFF 256 Mbytes SDRAM bank 0
|
||||
* 0x9000_0000 0x9FFF_FFFF 256 Mbytes SDRAM bank 1
|
||||
* 0xA000_0000 0xA7FF_FFFF 128 Mbytes WEIM CS0 (flash 128) 1
|
||||
* 0xA800_0000 0xAFFF_FFFF 128 Mbytes WEIM CS1 (flash 64) 1
|
||||
* 0xB000_0000 0xB1FF_FFFF 32 Mbytes WEIM CS2 (SRAM)
|
||||
* 0xB200_0000 0xB3FF_FFFF 32 Mbytes WEIM CS3 (SRAM)
|
||||
* 0xB400_0000 0xB5FF_FFFF 32 Mbytes WEIM CS4
|
||||
* 0xB600_0000 0xB7FF_FFFF 32 Mbytes Reserved
|
||||
* 0xB800_0000 0xB800_0FFF 4 Kbytes Reserved
|
||||
* 0xB800_1000 0xB800_1FFF 4 Kbytes SDRAM control registers
|
||||
* 0xB800_2000 0xB800_2FFF 4 Kbytes WEIM control registers
|
||||
* 0xB800_3000 0xB800_3FFF 4 Kbytes M3IF control registers
|
||||
* 0xB800_4000 0xB800_4FFF 4 Kbytes EMI control registers
|
||||
* 0xB800_5000 0xBAFF_FFFF 32 Mbytes (minus 20 Kbytes)
|
||||
* 0xBB00_0000 0xBB00_0FFF 4 Kbytes NAND flash main area buffer
|
||||
* 0xBB00_1000 0xBB00_11FF 512 B NAND flash spare area buffer
|
||||
* 0xBB00_1200 0xBB00_1DFF 3 Kbytes Reserved
|
||||
* 0xBB00_1E00 0xBB00_1FFF 512 B NAND flash control regisers
|
||||
* 0xBB01_2000 0xBFFF_FFFF 96 Mbytes (minus 8 Kbytes) Reserved
|
||||
* 0xC000_0000 0xFFFF_FFFF 1024 Mbytes Reserved
|
||||
*/
|
||||
|
||||
#define FSL_IMX25_ROM0_ADDR 0x00000000
|
||||
#define FSL_IMX25_ROM0_SIZE 0x4000
|
||||
#define FSL_IMX25_ROM1_ADDR 0x00404000
|
||||
#define FSL_IMX25_ROM1_SIZE 0x4000
|
||||
#define FSL_IMX25_I2C1_ADDR 0x43F80000
|
||||
#define FSL_IMX25_I2C1_SIZE 0x4000
|
||||
#define FSL_IMX25_I2C3_ADDR 0x43F84000
|
||||
#define FSL_IMX25_I2C3_SIZE 0x4000
|
||||
#define FSL_IMX25_UART1_ADDR 0x43F90000
|
||||
#define FSL_IMX25_UART1_SIZE 0x4000
|
||||
#define FSL_IMX25_UART2_ADDR 0x43F94000
|
||||
#define FSL_IMX25_UART2_SIZE 0x4000
|
||||
#define FSL_IMX25_I2C2_ADDR 0x43F98000
|
||||
#define FSL_IMX25_I2C2_SIZE 0x4000
|
||||
#define FSL_IMX25_UART4_ADDR 0x50008000
|
||||
#define FSL_IMX25_UART4_SIZE 0x4000
|
||||
#define FSL_IMX25_UART3_ADDR 0x5000C000
|
||||
#define FSL_IMX25_UART3_SIZE 0x4000
|
||||
#define FSL_IMX25_UART5_ADDR 0x5002C000
|
||||
#define FSL_IMX25_UART5_SIZE 0x4000
|
||||
#define FSL_IMX25_FEC_ADDR 0x50038000
|
||||
#define FSL_IMX25_FEC_SIZE 0x4000
|
||||
#define FSL_IMX25_CCM_ADDR 0x53F80000
|
||||
#define FSL_IMX25_CCM_SIZE 0x4000
|
||||
#define FSL_IMX25_GPT4_ADDR 0x53F84000
|
||||
#define FSL_IMX25_GPT4_SIZE 0x4000
|
||||
#define FSL_IMX25_GPT3_ADDR 0x53F88000
|
||||
#define FSL_IMX25_GPT3_SIZE 0x4000
|
||||
#define FSL_IMX25_GPT2_ADDR 0x53F8C000
|
||||
#define FSL_IMX25_GPT2_SIZE 0x4000
|
||||
#define FSL_IMX25_GPT1_ADDR 0x53F90000
|
||||
#define FSL_IMX25_GPT1_SIZE 0x4000
|
||||
#define FSL_IMX25_EPIT1_ADDR 0x53F94000
|
||||
#define FSL_IMX25_EPIT1_SIZE 0x4000
|
||||
#define FSL_IMX25_EPIT2_ADDR 0x53F98000
|
||||
#define FSL_IMX25_EPIT2_SIZE 0x4000
|
||||
#define FSL_IMX25_AVIC_ADDR 0x68000000
|
||||
#define FSL_IMX25_AVIC_SIZE 0x4000
|
||||
#define FSL_IMX25_IRAM_ADDR 0x78000000
|
||||
#define FSL_IMX25_IRAM_SIZE 0x20000
|
||||
#define FSL_IMX25_IRAM_ALIAS_ADDR 0x78020000
|
||||
#define FSL_IMX25_IRAM_ALIAS_SIZE 0x7FE0000
|
||||
#define FSL_IMX25_SDRAM0_ADDR 0x80000000
|
||||
#define FSL_IMX25_SDRAM0_SIZE 0x10000000
|
||||
#define FSL_IMX25_SDRAM1_ADDR 0x90000000
|
||||
#define FSL_IMX25_SDRAM1_SIZE 0x10000000
|
||||
|
||||
#define FSL_IMX25_UART1_IRQ 45
|
||||
#define FSL_IMX25_UART2_IRQ 32
|
||||
#define FSL_IMX25_UART3_IRQ 18
|
||||
#define FSL_IMX25_UART4_IRQ 5
|
||||
#define FSL_IMX25_UART5_IRQ 40
|
||||
#define FSL_IMX25_GPT1_IRQ 54
|
||||
#define FSL_IMX25_GPT2_IRQ 53
|
||||
#define FSL_IMX25_GPT3_IRQ 29
|
||||
#define FSL_IMX25_GPT4_IRQ 1
|
||||
#define FSL_IMX25_EPIT1_IRQ 28
|
||||
#define FSL_IMX25_EPIT2_IRQ 27
|
||||
#define FSL_IMX25_FEC_IRQ 57
|
||||
#define FSL_IMX25_I2C1_IRQ 3
|
||||
#define FSL_IMX25_I2C2_IRQ 4
|
||||
#define FSL_IMX25_I2C3_IRQ 10
|
||||
|
||||
#endif /* FSL_IMX25_H */
|
110
include/hw/arm/fsl-imx31.h
Normal file
110
include/hw/arm/fsl-imx31.h
Normal file
@ -0,0 +1,110 @@
|
||||
/*
|
||||
* 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_IMX31_H
|
||||
#define FSL_IMX31_H
|
||||
|
||||
#include "hw/arm/arm.h"
|
||||
#include "hw/intc/imx_avic.h"
|
||||
#include "hw/misc/imx_ccm.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 "exec/memory.h"
|
||||
|
||||
#define TYPE_FSL_IMX31 "fsl,imx31"
|
||||
#define FSL_IMX31(obj) OBJECT_CHECK(FslIMX31State, (obj), TYPE_FSL_IMX31)
|
||||
|
||||
#define FSL_IMX31_NUM_UARTS 2
|
||||
#define FSL_IMX31_NUM_EPITS 2
|
||||
#define FSL_IMX31_NUM_I2CS 3
|
||||
|
||||
typedef struct FslIMX31State {
|
||||
/*< private >*/
|
||||
DeviceState parent_obj;
|
||||
|
||||
/*< public >*/
|
||||
ARMCPU cpu;
|
||||
IMXAVICState avic;
|
||||
IMXCCMState ccm;
|
||||
IMXSerialState uart[FSL_IMX31_NUM_UARTS];
|
||||
IMXGPTState gpt;
|
||||
IMXEPITState epit[FSL_IMX31_NUM_EPITS];
|
||||
IMXI2CState i2c[FSL_IMX31_NUM_I2CS];
|
||||
MemoryRegion secure_rom;
|
||||
MemoryRegion rom;
|
||||
MemoryRegion iram;
|
||||
MemoryRegion iram_alias;
|
||||
} FslIMX31State;
|
||||
|
||||
#define FSL_IMX31_SECURE_ROM_ADDR 0x00000000
|
||||
#define FSL_IMX31_SECURE_ROM_SIZE 0x4000
|
||||
#define FSL_IMX31_ROM_ADDR 0x00404000
|
||||
#define FSL_IMX31_ROM_SIZE 0x4000
|
||||
#define FSL_IMX31_IRAM_ALIAS_ADDR 0x10000000
|
||||
#define FSL_IMX31_IRAM_ALIAS_SIZE 0xFFC0000
|
||||
#define FSL_IMX31_IRAM_ADDR 0x1FFFC000
|
||||
#define FSL_IMX31_IRAM_SIZE 0x4000
|
||||
#define FSL_IMX31_I2C1_ADDR 0x43F80000
|
||||
#define FSL_IMX31_I2C1_SIZE 0x4000
|
||||
#define FSL_IMX31_I2C3_ADDR 0x43F84000
|
||||
#define FSL_IMX31_I2C3_SIZE 0x4000
|
||||
#define FSL_IMX31_UART1_ADDR 0x43F90000
|
||||
#define FSL_IMX31_UART1_SIZE 0x4000
|
||||
#define FSL_IMX31_UART2_ADDR 0x43F94000
|
||||
#define FSL_IMX31_UART2_SIZE 0x4000
|
||||
#define FSL_IMX31_I2C2_ADDR 0x43F98000
|
||||
#define FSL_IMX31_I2C2_SIZE 0x4000
|
||||
#define FSL_IMX31_CCM_ADDR 0x53F80000
|
||||
#define FSL_IMX31_CCM_SIZE 0x4000
|
||||
#define FSL_IMX31_GPT_ADDR 0x53F90000
|
||||
#define FSL_IMX31_GPT_SIZE 0x4000
|
||||
#define FSL_IMX31_EPIT1_ADDR 0x53F94000
|
||||
#define FSL_IMX31_EPIT1_SIZE 0x4000
|
||||
#define FSL_IMX31_EPIT2_ADDR 0x53F98000
|
||||
#define FSL_IMX31_EPIT2_SIZE 0x4000
|
||||
#define FSL_IMX31_AVIC_ADDR 0x68000000
|
||||
#define FSL_IMX31_AVIC_SIZE 0x100
|
||||
#define FSL_IMX31_SDRAM0_ADDR 0x80000000
|
||||
#define FSL_IMX31_SDRAM0_SIZE 0x10000000
|
||||
#define FSL_IMX31_SDRAM1_ADDR 0x90000000
|
||||
#define FSL_IMX31_SDRAM1_SIZE 0x10000000
|
||||
#define FSL_IMX31_FLASH0_ADDR 0xA0000000
|
||||
#define FSL_IMX31_FLASH0_SIZE 0x8000000
|
||||
#define FSL_IMX31_FLASH1_ADDR 0xA8000000
|
||||
#define FSL_IMX31_FLASH1_SIZE 0x8000000
|
||||
#define FSL_IMX31_CS2_ADDR 0xB0000000
|
||||
#define FSL_IMX31_CS2_SIZE 0x2000000
|
||||
#define FSL_IMX31_CS3_ADDR 0xB2000000
|
||||
#define FSL_IMX31_CS3_SIZE 0x2000000
|
||||
#define FSL_IMX31_CS4_ADDR 0xB4000000
|
||||
#define FSL_IMX31_CS4_SIZE 0x2000000
|
||||
#define FSL_IMX31_CS5_ADDR 0xB6000000
|
||||
#define FSL_IMX31_CS5_SIZE 0x2000000
|
||||
#define FSL_IMX31_NAND_ADDR 0xB8000000
|
||||
#define FSL_IMX31_NAND_SIZE 0x1000
|
||||
|
||||
#define FSL_IMX31_EPIT2_IRQ 27
|
||||
#define FSL_IMX31_EPIT1_IRQ 28
|
||||
#define FSL_IMX31_GPT_IRQ 29
|
||||
#define FSL_IMX31_UART2_IRQ 32
|
||||
#define FSL_IMX31_UART1_IRQ 45
|
||||
#define FSL_IMX31_I2C1_IRQ 10
|
||||
#define FSL_IMX31_I2C2_IRQ 4
|
||||
#define FSL_IMX31_I2C3_IRQ 3
|
||||
|
||||
#endif /* FSL_IMX31_H */
|
@ -1,26 +0,0 @@
|
||||
/*
|
||||
* i.MX31 emulation
|
||||
*
|
||||
* Copyright (C) 2012 Peter Chubb
|
||||
* NICTA
|
||||
*
|
||||
* This code is released under the GPL, version 2.0 or later
|
||||
* See the file `../COPYING' for details.
|
||||
*/
|
||||
|
||||
#ifndef IMX_H
|
||||
#define IMX_H
|
||||
|
||||
#include "hw/misc/imx_ccm.h"
|
||||
|
||||
void imx_serial_create(int uart, const hwaddr addr, qemu_irq irq);
|
||||
|
||||
void imx_timerp_create(const hwaddr addr,
|
||||
qemu_irq irq,
|
||||
DeviceState *ccm);
|
||||
void imx_timerg_create(const hwaddr addr,
|
||||
qemu_irq irq,
|
||||
DeviceState *ccm);
|
||||
|
||||
|
||||
#endif /* IMX_H */
|
@ -31,6 +31,7 @@ typedef struct VirtGuestInfo {
|
||||
FWCfgState *fw_cfg;
|
||||
const MemMapEntry *memmap;
|
||||
const int *irqmap;
|
||||
bool use_highmem;
|
||||
} VirtGuestInfo;
|
||||
|
||||
|
||||
|
@ -56,6 +56,7 @@ enum {
|
||||
VIRT_PCIE_ECAM,
|
||||
VIRT_GIC_V2M,
|
||||
VIRT_PLATFORM_BUS,
|
||||
VIRT_PCIE_MMIO_HIGH,
|
||||
};
|
||||
|
||||
typedef struct MemMapEntry {
|
||||
|
87
include/hw/i2c/imx_i2c.h
Normal file
87
include/hw/i2c/imx_i2c.h
Normal file
@ -0,0 +1,87 @@
|
||||
/*
|
||||
* i.MX I2C Bus Serial Interface registers definition
|
||||
*
|
||||
* Copyright (C) 2013 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.
|
||||
*
|
||||
* 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 __IMX_I2C_H_
|
||||
#define __IMX_I2C_H_
|
||||
|
||||
#include <hw/sysbus.h>
|
||||
|
||||
#define TYPE_IMX_I2C "imx.i2c"
|
||||
#define IMX_I2C(obj) OBJECT_CHECK(IMXI2CState, (obj), TYPE_IMX_I2C)
|
||||
|
||||
#define IMX_I2C_MEM_SIZE 0x14
|
||||
|
||||
/* i.MX I2C memory map */
|
||||
#define IADR_ADDR 0x00 /* address register */
|
||||
#define IFDR_ADDR 0x04 /* frequency divider register */
|
||||
#define I2CR_ADDR 0x08 /* control register */
|
||||
#define I2SR_ADDR 0x0c /* status register */
|
||||
#define I2DR_ADDR 0x10 /* data register */
|
||||
|
||||
#define IADR_MASK 0xFE
|
||||
#define IADR_RESET 0
|
||||
|
||||
#define IFDR_MASK 0x3F
|
||||
#define IFDR_RESET 0
|
||||
|
||||
#define I2CR_IEN (1 << 7)
|
||||
#define I2CR_IIEN (1 << 6)
|
||||
#define I2CR_MSTA (1 << 5)
|
||||
#define I2CR_MTX (1 << 4)
|
||||
#define I2CR_TXAK (1 << 3)
|
||||
#define I2CR_RSTA (1 << 2)
|
||||
#define I2CR_MASK 0xFC
|
||||
#define I2CR_RESET 0
|
||||
|
||||
#define I2SR_ICF (1 << 7)
|
||||
#define I2SR_IAAF (1 << 6)
|
||||
#define I2SR_IBB (1 << 5)
|
||||
#define I2SR_IAL (1 << 4)
|
||||
#define I2SR_SRW (1 << 2)
|
||||
#define I2SR_IIF (1 << 1)
|
||||
#define I2SR_RXAK (1 << 0)
|
||||
#define I2SR_MASK 0xE9
|
||||
#define I2SR_RESET 0x81
|
||||
|
||||
#define I2DR_MASK 0xFF
|
||||
#define I2DR_RESET 0
|
||||
|
||||
#define ADDR_RESET 0xFF00
|
||||
|
||||
typedef struct IMXI2CState {
|
||||
/*< private >*/
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
/*< public >*/
|
||||
MemoryRegion iomem;
|
||||
I2CBus *bus;
|
||||
qemu_irq irq;
|
||||
|
||||
uint16_t address;
|
||||
|
||||
uint16_t iadr;
|
||||
uint16_t ifdr;
|
||||
uint16_t i2cr;
|
||||
uint16_t i2sr;
|
||||
uint16_t i2dr_read;
|
||||
uint16_t i2dr_write;
|
||||
} IMXI2CState;
|
||||
|
||||
#endif /* __IMX_I2C_H_ */
|
113
include/hw/net/imx_fec.h
Normal file
113
include/hw/net/imx_fec.h
Normal file
@ -0,0 +1,113 @@
|
||||
/*
|
||||
* i.MX Fast Ethernet Controller emulation.
|
||||
*
|
||||
* Copyright (c) 2013 Jean-Christophe Dubois. <jcd@tribudubois.net>
|
||||
*
|
||||
* Based on Coldfire Fast Ethernet Controller emulation.
|
||||
*
|
||||
* Copyright (c) 2007 CodeSourcery.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef IMX_FEC_H
|
||||
#define IMX_FEC_H
|
||||
|
||||
#define TYPE_IMX_FEC "imx.fec"
|
||||
#define IMX_FEC(obj) OBJECT_CHECK(IMXFECState, (obj), TYPE_IMX_FEC)
|
||||
|
||||
#include "hw/sysbus.h"
|
||||
#include "net/net.h"
|
||||
|
||||
#define FEC_MAX_FRAME_SIZE 2032
|
||||
|
||||
#define FEC_INT_HB (1 << 31)
|
||||
#define FEC_INT_BABR (1 << 30)
|
||||
#define FEC_INT_BABT (1 << 29)
|
||||
#define FEC_INT_GRA (1 << 28)
|
||||
#define FEC_INT_TXF (1 << 27)
|
||||
#define FEC_INT_TXB (1 << 26)
|
||||
#define FEC_INT_RXF (1 << 25)
|
||||
#define FEC_INT_RXB (1 << 24)
|
||||
#define FEC_INT_MII (1 << 23)
|
||||
#define FEC_INT_EBERR (1 << 22)
|
||||
#define FEC_INT_LC (1 << 21)
|
||||
#define FEC_INT_RL (1 << 20)
|
||||
#define FEC_INT_UN (1 << 19)
|
||||
|
||||
#define FEC_EN 2
|
||||
#define FEC_RESET 1
|
||||
|
||||
/* Buffer Descriptor. */
|
||||
typedef struct {
|
||||
uint16_t length;
|
||||
uint16_t flags;
|
||||
uint32_t data;
|
||||
} IMXFECBufDesc;
|
||||
|
||||
#define FEC_BD_R (1 << 15)
|
||||
#define FEC_BD_E (1 << 15)
|
||||
#define FEC_BD_O1 (1 << 14)
|
||||
#define FEC_BD_W (1 << 13)
|
||||
#define FEC_BD_O2 (1 << 12)
|
||||
#define FEC_BD_L (1 << 11)
|
||||
#define FEC_BD_TC (1 << 10)
|
||||
#define FEC_BD_ABC (1 << 9)
|
||||
#define FEC_BD_M (1 << 8)
|
||||
#define FEC_BD_BC (1 << 7)
|
||||
#define FEC_BD_MC (1 << 6)
|
||||
#define FEC_BD_LG (1 << 5)
|
||||
#define FEC_BD_NO (1 << 4)
|
||||
#define FEC_BD_CR (1 << 2)
|
||||
#define FEC_BD_OV (1 << 1)
|
||||
#define FEC_BD_TR (1 << 0)
|
||||
|
||||
typedef struct IMXFECState {
|
||||
/*< private >*/
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
/*< public >*/
|
||||
NICState *nic;
|
||||
NICConf conf;
|
||||
qemu_irq irq;
|
||||
MemoryRegion iomem;
|
||||
|
||||
uint32_t irq_state;
|
||||
uint32_t eir;
|
||||
uint32_t eimr;
|
||||
uint32_t rx_enabled;
|
||||
uint32_t rx_descriptor;
|
||||
uint32_t tx_descriptor;
|
||||
uint32_t ecr;
|
||||
uint32_t mmfr;
|
||||
uint32_t mscr;
|
||||
uint32_t mibc;
|
||||
uint32_t rcr;
|
||||
uint32_t tcr;
|
||||
uint32_t tfwr;
|
||||
uint32_t frsr;
|
||||
uint32_t erdsr;
|
||||
uint32_t etdsr;
|
||||
uint32_t emrbr;
|
||||
uint32_t miigsk_cfgr;
|
||||
uint32_t miigsk_enr;
|
||||
|
||||
uint32_t phy_status;
|
||||
uint32_t phy_control;
|
||||
uint32_t phy_advertise;
|
||||
uint32_t phy_int;
|
||||
uint32_t phy_int_mask;
|
||||
} IMXFECState;
|
||||
|
||||
#endif
|
@ -23,25 +23,27 @@ struct smbios_phys_mem_area {
|
||||
uint64_t length;
|
||||
};
|
||||
|
||||
void smbios_entry_add(QemuOpts *opts);
|
||||
void smbios_set_cpuid(uint32_t version, uint32_t features);
|
||||
void smbios_set_defaults(const char *manufacturer, const char *product,
|
||||
const char *version, bool legacy_mode,
|
||||
bool uuid_encoded);
|
||||
uint8_t *smbios_get_table_legacy(size_t *length);
|
||||
void smbios_get_tables(const struct smbios_phys_mem_area *mem_array,
|
||||
const unsigned int mem_array_size,
|
||||
uint8_t **tables, size_t *tables_len,
|
||||
uint8_t **anchor, size_t *anchor_len);
|
||||
|
||||
/*
|
||||
* SMBIOS spec defined tables
|
||||
*/
|
||||
typedef enum SmbiosEntryPointType {
|
||||
SMBIOS_ENTRY_POINT_21,
|
||||
SMBIOS_ENTRY_POINT_30,
|
||||
} SmbiosEntryPointType;
|
||||
|
||||
/* SMBIOS entry point (anchor).
|
||||
* BIOS must place this at a 16-bit-aligned address between 0xf0000 and 0xfffff.
|
||||
/* SMBIOS Entry Point
|
||||
* There are two types of entry points defined in the SMBIOS specification
|
||||
* (see below). BIOS must place the entry point(s) at a 16-bit-aligned
|
||||
* address between 0xf0000 and 0xfffff. Note that either entry point type
|
||||
* can be used in a 64-bit target system, except that SMBIOS 2.1 entry point
|
||||
* only allows the SMBIOS struct table to reside below 4GB address space.
|
||||
*/
|
||||
struct smbios_entry_point {
|
||||
|
||||
/* SMBIOS 2.1 (32-bit) Entry Point
|
||||
* - introduced since SMBIOS 2.1
|
||||
* - supports structure table below 4GB only
|
||||
*/
|
||||
struct smbios_21_entry_point {
|
||||
uint8_t anchor_string[4];
|
||||
uint8_t checksum;
|
||||
uint8_t length;
|
||||
@ -58,6 +60,28 @@ struct smbios_entry_point {
|
||||
uint8_t smbios_bcd_revision;
|
||||
} QEMU_PACKED;
|
||||
|
||||
/* SMBIOS 3.0 (64-bit) Entry Point
|
||||
* - introduced since SMBIOS 3.0
|
||||
* - supports structure table at 64-bit address space
|
||||
*/
|
||||
struct smbios_30_entry_point {
|
||||
uint8_t anchor_string[5];
|
||||
uint8_t checksum;
|
||||
uint8_t length;
|
||||
uint8_t smbios_major_version;
|
||||
uint8_t smbios_minor_version;
|
||||
uint8_t smbios_doc_rev;
|
||||
uint8_t entry_point_revision;
|
||||
uint8_t reserved;
|
||||
uint32_t structure_table_max_size;
|
||||
uint64_t structure_table_address;
|
||||
} QEMU_PACKED;
|
||||
|
||||
typedef union {
|
||||
struct smbios_21_entry_point ep21;
|
||||
struct smbios_30_entry_point ep30;
|
||||
} QEMU_PACKED SmbiosEntryPoint;
|
||||
|
||||
/* This goes at the beginning of every SMBIOS structure. */
|
||||
struct smbios_structure_header {
|
||||
uint8_t type;
|
||||
@ -232,4 +256,14 @@ struct smbios_type_127 {
|
||||
struct smbios_structure_header header;
|
||||
} QEMU_PACKED;
|
||||
|
||||
void smbios_entry_add(QemuOpts *opts);
|
||||
void smbios_set_cpuid(uint32_t version, uint32_t features);
|
||||
void smbios_set_defaults(const char *manufacturer, const char *product,
|
||||
const char *version, bool legacy_mode,
|
||||
bool uuid_encoded, SmbiosEntryPointType ep_type);
|
||||
uint8_t *smbios_get_table_legacy(size_t *length);
|
||||
void smbios_get_tables(const struct smbios_phys_mem_area *mem_array,
|
||||
const unsigned int mem_array_size,
|
||||
uint8_t **tables, size_t *tables_len,
|
||||
uint8_t **anchor, size_t *anchor_len);
|
||||
#endif /*QEMU_SMBIOS_H */
|
||||
|
@ -1052,6 +1052,9 @@ void cpu_loop(CPUARMState *env)
|
||||
queue_signal(env, info.si_signo, &info);
|
||||
}
|
||||
break;
|
||||
case EXCP_SEMIHOST:
|
||||
env->xregs[0] = do_arm_semihosting(env);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n",
|
||||
trapnr);
|
||||
|
@ -1412,7 +1412,7 @@ DEF("smbios", HAS_ARG, QEMU_OPTION_smbios,
|
||||
"-smbios type=17[,loc_pfx=str][,bank=str][,manufacturer=str][,serial=str]\n"
|
||||
" [,asset=str][,part=str][,speed=%d]\n"
|
||||
" specify SMBIOS type 17 fields\n",
|
||||
QEMU_ARCH_I386)
|
||||
QEMU_ARCH_I386 | QEMU_ARCH_ARM)
|
||||
STEXI
|
||||
@item -smbios file=@var{binary}
|
||||
@findex -smbios
|
||||
|
@ -58,6 +58,7 @@
|
||||
#define TARGET_SYS_GET_CMDLINE 0x15
|
||||
#define TARGET_SYS_HEAPINFO 0x16
|
||||
#define TARGET_SYS_EXIT 0x18
|
||||
#define TARGET_SYS_SYNCCACHE 0x19
|
||||
|
||||
/* ADP_Stopped_ApplicationExit is used for exit(0),
|
||||
* anything else is implemented as exit(1) */
|
||||
@ -134,6 +135,7 @@ static void arm_semi_cb(CPUState *cs, target_ulong ret, target_ulong err)
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
TaskState *ts = cs->opaque;
|
||||
#endif
|
||||
target_ulong reg0 = is_a64(env) ? env->xregs[0] : env->regs[0];
|
||||
|
||||
if (ret == (target_ulong)-1) {
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
@ -141,22 +143,46 @@ static void arm_semi_cb(CPUState *cs, target_ulong ret, target_ulong err)
|
||||
#else
|
||||
syscall_err = err;
|
||||
#endif
|
||||
env->regs[0] = ret;
|
||||
reg0 = ret;
|
||||
} else {
|
||||
/* Fixup syscalls that use nonstardard return conventions. */
|
||||
switch (env->regs[0]) {
|
||||
switch (reg0) {
|
||||
case TARGET_SYS_WRITE:
|
||||
case TARGET_SYS_READ:
|
||||
env->regs[0] = arm_semi_syscall_len - ret;
|
||||
reg0 = arm_semi_syscall_len - ret;
|
||||
break;
|
||||
case TARGET_SYS_SEEK:
|
||||
env->regs[0] = 0;
|
||||
reg0 = 0;
|
||||
break;
|
||||
default:
|
||||
env->regs[0] = ret;
|
||||
reg0 = ret;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (is_a64(env)) {
|
||||
env->xregs[0] = reg0;
|
||||
} else {
|
||||
env->regs[0] = reg0;
|
||||
}
|
||||
}
|
||||
|
||||
static target_ulong arm_flen_buf(ARMCPU *cpu)
|
||||
{
|
||||
/* Return an address in target memory of 64 bytes where the remote
|
||||
* gdb should write its stat struct. (The format of this structure
|
||||
* is defined by GDB's remote protocol and is not target-specific.)
|
||||
* We put this on the guest's stack just below SP.
|
||||
*/
|
||||
CPUARMState *env = &cpu->env;
|
||||
target_ulong sp;
|
||||
|
||||
if (is_a64(env)) {
|
||||
sp = env->xregs[31];
|
||||
} else {
|
||||
sp = env->regs[13];
|
||||
}
|
||||
|
||||
return sp - 64;
|
||||
}
|
||||
|
||||
static void arm_semi_flen_cb(CPUState *cs, target_ulong ret, target_ulong err)
|
||||
@ -166,8 +192,13 @@ static void arm_semi_flen_cb(CPUState *cs, target_ulong ret, target_ulong err)
|
||||
/* The size is always stored in big-endian order, extract
|
||||
the value. We assume the size always fit in 32 bits. */
|
||||
uint32_t size;
|
||||
cpu_memory_rw_debug(cs, env->regs[13]-64+32, (uint8_t *)&size, 4, 0);
|
||||
env->regs[0] = be32_to_cpu(size);
|
||||
cpu_memory_rw_debug(cs, arm_flen_buf(cpu) + 32, (uint8_t *)&size, 4, 0);
|
||||
size = be32_to_cpu(size);
|
||||
if (is_a64(env)) {
|
||||
env->xregs[0] = size;
|
||||
} else {
|
||||
env->regs[0] = size;
|
||||
}
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
((TaskState *)cs->opaque)->swi_errno = err;
|
||||
#else
|
||||
@ -175,17 +206,46 @@ static void arm_semi_flen_cb(CPUState *cs, target_ulong ret, target_ulong err)
|
||||
#endif
|
||||
}
|
||||
|
||||
static target_ulong arm_gdb_syscall(ARMCPU *cpu, gdb_syscall_complete_cb cb,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
va_list va;
|
||||
CPUARMState *env = &cpu->env;
|
||||
|
||||
va_start(va, fmt);
|
||||
gdb_do_syscallv(cb, fmt, va);
|
||||
va_end(va);
|
||||
|
||||
/* FIXME: we are implicitly relying on the syscall completing
|
||||
* before this point, which is not guaranteed. We should
|
||||
* put in an explicit synchronization between this and
|
||||
* the callback function.
|
||||
*/
|
||||
|
||||
return is_a64(env) ? env->xregs[0] : env->regs[0];
|
||||
}
|
||||
|
||||
/* Read the input value from the argument block; fail the semihosting
|
||||
* call if the memory read fails.
|
||||
*/
|
||||
#define GET_ARG(n) do { \
|
||||
if (get_user_ual(arg ## n, args + (n) * 4)) { \
|
||||
return (uint32_t)-1; \
|
||||
if (is_a64(env)) { \
|
||||
if (get_user_u64(arg ## n, args + (n) * 8)) { \
|
||||
return -1; \
|
||||
} \
|
||||
} else { \
|
||||
if (get_user_u32(arg ## n, args + (n) * 4)) { \
|
||||
return -1; \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define SET_ARG(n, val) put_user_ual(val, args + (n) * 4)
|
||||
uint32_t do_arm_semihosting(CPUARMState *env)
|
||||
#define SET_ARG(n, val) \
|
||||
(is_a64(env) ? \
|
||||
put_user_u64(val, args + (n) * 8) : \
|
||||
put_user_u32(val, args + (n) * 4))
|
||||
|
||||
target_ulong do_arm_semihosting(CPUARMState *env)
|
||||
{
|
||||
ARMCPU *cpu = arm_env_get_cpu(env);
|
||||
CPUState *cs = CPU(cpu);
|
||||
@ -201,8 +261,15 @@ uint32_t do_arm_semihosting(CPUARMState *env)
|
||||
CPUARMState *ts = env;
|
||||
#endif
|
||||
|
||||
nr = env->regs[0];
|
||||
args = env->regs[1];
|
||||
if (is_a64(env)) {
|
||||
/* Note that the syscall number is in W0, not X0 */
|
||||
nr = env->xregs[0] & 0xffffffffU;
|
||||
args = env->xregs[1];
|
||||
} else {
|
||||
nr = env->regs[0];
|
||||
args = env->regs[1];
|
||||
}
|
||||
|
||||
switch (nr) {
|
||||
case TARGET_SYS_OPEN:
|
||||
GET_ARG(0);
|
||||
@ -223,9 +290,8 @@ uint32_t do_arm_semihosting(CPUARMState *env)
|
||||
return result_fileno;
|
||||
}
|
||||
if (use_gdb_syscalls()) {
|
||||
gdb_do_syscall(arm_semi_cb, "open,%s,%x,1a4", arg0,
|
||||
(int)arg2+1, gdb_open_modeflags[arg1]);
|
||||
ret = env->regs[0];
|
||||
ret = arm_gdb_syscall(cpu, arm_semi_cb, "open,%s,%x,1a4", arg0,
|
||||
(int)arg2+1, gdb_open_modeflags[arg1]);
|
||||
} else {
|
||||
ret = set_swi_errno(ts, open(s, open_modeflags[arg1], 0644));
|
||||
}
|
||||
@ -234,8 +300,7 @@ uint32_t do_arm_semihosting(CPUARMState *env)
|
||||
case TARGET_SYS_CLOSE:
|
||||
GET_ARG(0);
|
||||
if (use_gdb_syscalls()) {
|
||||
gdb_do_syscall(arm_semi_cb, "close,%x", arg0);
|
||||
return env->regs[0];
|
||||
return arm_gdb_syscall(cpu, arm_semi_cb, "close,%x", arg0);
|
||||
} else {
|
||||
return set_swi_errno(ts, close(arg0));
|
||||
}
|
||||
@ -248,8 +313,7 @@ uint32_t do_arm_semihosting(CPUARMState *env)
|
||||
return (uint32_t)-1;
|
||||
/* Write to debug console. stderr is near enough. */
|
||||
if (use_gdb_syscalls()) {
|
||||
gdb_do_syscall(arm_semi_cb, "write,2,%x,1", args);
|
||||
return env->regs[0];
|
||||
return arm_gdb_syscall(cpu, arm_semi_cb, "write,2,%x,1", args);
|
||||
} else {
|
||||
return write(STDERR_FILENO, &c, 1);
|
||||
}
|
||||
@ -260,8 +324,8 @@ uint32_t do_arm_semihosting(CPUARMState *env)
|
||||
return (uint32_t)-1;
|
||||
len = strlen(s);
|
||||
if (use_gdb_syscalls()) {
|
||||
gdb_do_syscall(arm_semi_cb, "write,2,%x,%x\n", args, len);
|
||||
ret = env->regs[0];
|
||||
return arm_gdb_syscall(cpu, arm_semi_cb, "write,2,%x,%x",
|
||||
args, len);
|
||||
} else {
|
||||
ret = write(STDERR_FILENO, s, len);
|
||||
}
|
||||
@ -274,8 +338,8 @@ uint32_t do_arm_semihosting(CPUARMState *env)
|
||||
len = arg2;
|
||||
if (use_gdb_syscalls()) {
|
||||
arm_semi_syscall_len = len;
|
||||
gdb_do_syscall(arm_semi_cb, "write,%x,%x,%x", arg0, arg1, len);
|
||||
return env->regs[0];
|
||||
return arm_gdb_syscall(cpu, arm_semi_cb, "write,%x,%x,%x",
|
||||
arg0, arg1, len);
|
||||
} else {
|
||||
s = lock_user(VERIFY_READ, arg1, len, 1);
|
||||
if (!s) {
|
||||
@ -295,8 +359,8 @@ uint32_t do_arm_semihosting(CPUARMState *env)
|
||||
len = arg2;
|
||||
if (use_gdb_syscalls()) {
|
||||
arm_semi_syscall_len = len;
|
||||
gdb_do_syscall(arm_semi_cb, "read,%x,%x,%x", arg0, arg1, len);
|
||||
return env->regs[0];
|
||||
return arm_gdb_syscall(cpu, arm_semi_cb, "read,%x,%x,%x",
|
||||
arg0, arg1, len);
|
||||
} else {
|
||||
s = lock_user(VERIFY_WRITE, arg1, len, 0);
|
||||
if (!s) {
|
||||
@ -317,8 +381,7 @@ uint32_t do_arm_semihosting(CPUARMState *env)
|
||||
case TARGET_SYS_ISTTY:
|
||||
GET_ARG(0);
|
||||
if (use_gdb_syscalls()) {
|
||||
gdb_do_syscall(arm_semi_cb, "isatty,%x", arg0);
|
||||
return env->regs[0];
|
||||
return arm_gdb_syscall(cpu, arm_semi_cb, "isatty,%x", arg0);
|
||||
} else {
|
||||
return isatty(arg0);
|
||||
}
|
||||
@ -326,8 +389,8 @@ uint32_t do_arm_semihosting(CPUARMState *env)
|
||||
GET_ARG(0);
|
||||
GET_ARG(1);
|
||||
if (use_gdb_syscalls()) {
|
||||
gdb_do_syscall(arm_semi_cb, "lseek,%x,%x,0", arg0, arg1);
|
||||
return env->regs[0];
|
||||
return arm_gdb_syscall(cpu, arm_semi_cb, "lseek,%x,%x,0",
|
||||
arg0, arg1);
|
||||
} else {
|
||||
ret = set_swi_errno(ts, lseek(arg0, arg1, SEEK_SET));
|
||||
if (ret == (uint32_t)-1)
|
||||
@ -337,9 +400,8 @@ uint32_t do_arm_semihosting(CPUARMState *env)
|
||||
case TARGET_SYS_FLEN:
|
||||
GET_ARG(0);
|
||||
if (use_gdb_syscalls()) {
|
||||
gdb_do_syscall(arm_semi_flen_cb, "fstat,%x,%x",
|
||||
arg0, env->regs[13]-64);
|
||||
return env->regs[0];
|
||||
return arm_gdb_syscall(cpu, arm_semi_flen_cb, "fstat,%x,%x",
|
||||
arg0, arm_flen_buf(cpu));
|
||||
} else {
|
||||
struct stat buf;
|
||||
ret = set_swi_errno(ts, fstat(arg0, &buf));
|
||||
@ -354,8 +416,8 @@ uint32_t do_arm_semihosting(CPUARMState *env)
|
||||
GET_ARG(0);
|
||||
GET_ARG(1);
|
||||
if (use_gdb_syscalls()) {
|
||||
gdb_do_syscall(arm_semi_cb, "unlink,%s", arg0, (int)arg1+1);
|
||||
ret = env->regs[0];
|
||||
ret = arm_gdb_syscall(cpu, arm_semi_cb, "unlink,%s",
|
||||
arg0, (int)arg1+1);
|
||||
} else {
|
||||
s = lock_user_string(arg0);
|
||||
if (!s) {
|
||||
@ -372,9 +434,8 @@ uint32_t do_arm_semihosting(CPUARMState *env)
|
||||
GET_ARG(2);
|
||||
GET_ARG(3);
|
||||
if (use_gdb_syscalls()) {
|
||||
gdb_do_syscall(arm_semi_cb, "rename,%s,%s",
|
||||
arg0, (int)arg1+1, arg2, (int)arg3+1);
|
||||
return env->regs[0];
|
||||
return arm_gdb_syscall(cpu, arm_semi_cb, "rename,%s,%s",
|
||||
arg0, (int)arg1+1, arg2, (int)arg3+1);
|
||||
} else {
|
||||
char *s2;
|
||||
s = lock_user_string(arg0);
|
||||
@ -398,8 +459,8 @@ uint32_t do_arm_semihosting(CPUARMState *env)
|
||||
GET_ARG(0);
|
||||
GET_ARG(1);
|
||||
if (use_gdb_syscalls()) {
|
||||
gdb_do_syscall(arm_semi_cb, "system,%s", arg0, (int)arg1+1);
|
||||
return env->regs[0];
|
||||
return arm_gdb_syscall(cpu, arm_semi_cb, "system,%s",
|
||||
arg0, (int)arg1+1);
|
||||
} else {
|
||||
s = lock_user_string(arg0);
|
||||
if (!s) {
|
||||
@ -558,11 +619,35 @@ uint32_t do_arm_semihosting(CPUARMState *env)
|
||||
return 0;
|
||||
}
|
||||
case TARGET_SYS_EXIT:
|
||||
/* ARM specifies only Stopped_ApplicationExit as normal
|
||||
* exit, everything else is considered an error */
|
||||
ret = (args == ADP_Stopped_ApplicationExit) ? 0 : 1;
|
||||
if (is_a64(env)) {
|
||||
/* The A64 version of this call takes a parameter block,
|
||||
* so the application-exit type can return a subcode which
|
||||
* is the exit status code from the application.
|
||||
*/
|
||||
GET_ARG(0);
|
||||
GET_ARG(1);
|
||||
|
||||
if (arg0 == ADP_Stopped_ApplicationExit) {
|
||||
ret = arg1;
|
||||
} else {
|
||||
ret = 1;
|
||||
}
|
||||
} else {
|
||||
/* ARM specifies only Stopped_ApplicationExit as normal
|
||||
* exit, everything else is considered an error */
|
||||
ret = (args == ADP_Stopped_ApplicationExit) ? 0 : 1;
|
||||
}
|
||||
gdb_exit(env, ret);
|
||||
exit(ret);
|
||||
case TARGET_SYS_SYNCCACHE:
|
||||
/* Clean the D-cache and invalidate the I-cache for the specified
|
||||
* virtual address range. This is a nop for us since we don't
|
||||
* implement caches. This is only present on A64.
|
||||
*/
|
||||
if (is_a64(env)) {
|
||||
return 0;
|
||||
}
|
||||
/* fall through -- invalid for A32/T32 */
|
||||
default:
|
||||
fprintf(stderr, "qemu: Unsupported SemiHosting SWI 0x%02x\n", nr);
|
||||
cpu_dump_state(cs, stderr, fprintf, 0);
|
||||
|
@ -227,6 +227,19 @@ void arm_gt_vtimer_cb(void *opaque);
|
||||
void arm_gt_htimer_cb(void *opaque);
|
||||
void arm_gt_stimer_cb(void *opaque);
|
||||
|
||||
#define ARM_AFF0_SHIFT 0
|
||||
#define ARM_AFF0_MASK (0xFFULL << ARM_AFF0_SHIFT)
|
||||
#define ARM_AFF1_SHIFT 8
|
||||
#define ARM_AFF1_MASK (0xFFULL << ARM_AFF1_SHIFT)
|
||||
#define ARM_AFF2_SHIFT 16
|
||||
#define ARM_AFF2_MASK (0xFFULL << ARM_AFF2_SHIFT)
|
||||
#define ARM_AFF3_SHIFT 32
|
||||
#define ARM_AFF3_MASK (0xFFULL << ARM_AFF3_SHIFT)
|
||||
|
||||
#define ARM32_AFFINITY_MASK (ARM_AFF0_MASK|ARM_AFF1_MASK|ARM_AFF2_MASK)
|
||||
#define ARM64_AFFINITY_MASK \
|
||||
(ARM_AFF0_MASK|ARM_AFF1_MASK|ARM_AFF2_MASK|ARM_AFF3_MASK)
|
||||
|
||||
#ifdef TARGET_AARCH64
|
||||
int aarch64_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
|
||||
int aarch64_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
|
||||
|
@ -331,10 +331,7 @@ static void arm_cpu_set_irq(void *opaque, int irq, int level)
|
||||
switch (irq) {
|
||||
case ARM_CPU_VIRQ:
|
||||
case ARM_CPU_VFIQ:
|
||||
if (!arm_feature(env, ARM_FEATURE_EL2)) {
|
||||
hw_error("%s: Virtual interrupt line %d with no EL2 support\n",
|
||||
__func__, irq);
|
||||
}
|
||||
assert(arm_feature(env, ARM_FEATURE_EL2));
|
||||
/* fall through */
|
||||
case ARM_CPU_IRQ:
|
||||
case ARM_CPU_FIQ:
|
||||
@ -345,7 +342,7 @@ static void arm_cpu_set_irq(void *opaque, int irq, int level)
|
||||
}
|
||||
break;
|
||||
default:
|
||||
hw_error("arm_cpu_set_irq: Bad interrupt line %d\n", irq);
|
||||
g_assert_not_reached();
|
||||
}
|
||||
}
|
||||
|
||||
@ -364,7 +361,7 @@ static void arm_cpu_kvm_set_irq(void *opaque, int irq, int level)
|
||||
kvm_irq |= KVM_ARM_IRQ_CPU_FIQ;
|
||||
break;
|
||||
default:
|
||||
hw_error("arm_cpu_kvm_set_irq: Bad interrupt line %d\n", irq);
|
||||
g_assert_not_reached();
|
||||
}
|
||||
kvm_irq |= cs->cpu_index << KVM_ARM_IRQ_VCPU_SHIFT;
|
||||
kvm_set_irq(kvm_state, kvm_irq, level ? 1 : 0);
|
||||
@ -459,7 +456,7 @@ static void arm_cpu_initfn(Object *obj)
|
||||
*/
|
||||
Aff1 = cs->cpu_index / ARM_CPUS_PER_CLUSTER;
|
||||
Aff0 = cs->cpu_index % ARM_CPUS_PER_CLUSTER;
|
||||
cpu->mp_affinity = (Aff1 << 8) | Aff0;
|
||||
cpu->mp_affinity = (Aff1 << ARM_AFF1_SHIFT) | Aff0;
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
/* Our inbound IRQ and FIQ lines */
|
||||
|
@ -56,6 +56,7 @@
|
||||
#define EXCP_SMC 13 /* Secure Monitor Call */
|
||||
#define EXCP_VIRQ 14
|
||||
#define EXCP_VFIQ 15
|
||||
#define EXCP_SEMIHOST 16 /* semihosting call (A64 only) */
|
||||
|
||||
#define ARMV7M_EXCP_RESET 1
|
||||
#define ARMV7M_EXCP_NMI 2
|
||||
@ -504,7 +505,7 @@ typedef struct CPUARMState {
|
||||
|
||||
ARMCPU *cpu_arm_init(const char *cpu_model);
|
||||
int cpu_arm_exec(CPUState *cpu);
|
||||
uint32_t do_arm_semihosting(CPUARMState *env);
|
||||
target_ulong do_arm_semihosting(CPUARMState *env);
|
||||
void aarch64_sync_32_to_64(CPUARMState *env);
|
||||
void aarch64_sync_64_to_32(CPUARMState *env);
|
||||
|
||||
@ -1519,8 +1520,8 @@ static inline bool arm_excp_unmasked(CPUState *cs, unsigned int excp_idx,
|
||||
CPUARMState *env = cs->env_ptr;
|
||||
unsigned int cur_el = arm_current_el(env);
|
||||
bool secure = arm_is_secure(env);
|
||||
uint32_t scr;
|
||||
uint32_t hcr;
|
||||
bool scr;
|
||||
bool hcr;
|
||||
bool pstate_unmasked;
|
||||
int8_t unmasked = 0;
|
||||
|
||||
@ -1547,7 +1548,7 @@ static inline bool arm_excp_unmasked(CPUState *cs, unsigned int excp_idx,
|
||||
* set then FIQs can be masked by CPSR.F when non-secure but only
|
||||
* when FIQs are only routed to EL3.
|
||||
*/
|
||||
scr &= !((env->cp15.scr_el3 & SCR_FW) && !hcr);
|
||||
scr = scr && !((env->cp15.scr_el3 & SCR_FW) && !hcr);
|
||||
pstate_unmasked = !(env->daif & PSTATE_F);
|
||||
break;
|
||||
|
||||
|
@ -514,6 +514,12 @@ void aarch64_cpu_do_interrupt(CPUState *cs)
|
||||
case EXCP_VFIQ:
|
||||
addr += 0x100;
|
||||
break;
|
||||
case EXCP_SEMIHOST:
|
||||
qemu_log_mask(CPU_LOG_INT,
|
||||
"...handling as semihosting call 0x%" PRIx64 "\n",
|
||||
env->xregs[0]);
|
||||
env->xregs[0] = do_arm_semihosting(env);
|
||||
return;
|
||||
default:
|
||||
cpu_abort(cs, "Unhandled exception 0x%x\n", cs->exception_index);
|
||||
}
|
||||
|
@ -4990,7 +4990,7 @@ int bank_number(int mode)
|
||||
case ARM_CPU_MODE_MON:
|
||||
return 7;
|
||||
}
|
||||
hw_error("bank number requested for bad CPSR mode value 0x%x\n", mode);
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
void switch_mode(CPUARMState *env, int mode)
|
||||
@ -5228,8 +5228,10 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs)
|
||||
nr = arm_lduw_code(env, env->regs[15], env->bswap_code) & 0xff;
|
||||
if (nr == 0xab) {
|
||||
env->regs[15] += 2;
|
||||
qemu_log_mask(CPU_LOG_INT,
|
||||
"...handling as semihosting call 0x%x\n",
|
||||
env->regs[0]);
|
||||
env->regs[0] = do_arm_semihosting(env);
|
||||
qemu_log_mask(CPU_LOG_INT, "...handled as semihosting call\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -5322,35 +5324,35 @@ void aarch64_sync_32_to_64(CPUARMState *env)
|
||||
}
|
||||
|
||||
if (mode == ARM_CPU_MODE_IRQ) {
|
||||
env->xregs[16] = env->regs[13];
|
||||
env->xregs[17] = env->regs[14];
|
||||
env->xregs[16] = env->regs[14];
|
||||
env->xregs[17] = env->regs[13];
|
||||
} else {
|
||||
env->xregs[16] = env->banked_r13[bank_number(ARM_CPU_MODE_IRQ)];
|
||||
env->xregs[17] = env->banked_r14[bank_number(ARM_CPU_MODE_IRQ)];
|
||||
env->xregs[16] = env->banked_r14[bank_number(ARM_CPU_MODE_IRQ)];
|
||||
env->xregs[17] = env->banked_r13[bank_number(ARM_CPU_MODE_IRQ)];
|
||||
}
|
||||
|
||||
if (mode == ARM_CPU_MODE_SVC) {
|
||||
env->xregs[18] = env->regs[13];
|
||||
env->xregs[19] = env->regs[14];
|
||||
env->xregs[18] = env->regs[14];
|
||||
env->xregs[19] = env->regs[13];
|
||||
} else {
|
||||
env->xregs[18] = env->banked_r13[bank_number(ARM_CPU_MODE_SVC)];
|
||||
env->xregs[19] = env->banked_r14[bank_number(ARM_CPU_MODE_SVC)];
|
||||
env->xregs[18] = env->banked_r14[bank_number(ARM_CPU_MODE_SVC)];
|
||||
env->xregs[19] = env->banked_r13[bank_number(ARM_CPU_MODE_SVC)];
|
||||
}
|
||||
|
||||
if (mode == ARM_CPU_MODE_ABT) {
|
||||
env->xregs[20] = env->regs[13];
|
||||
env->xregs[21] = env->regs[14];
|
||||
env->xregs[20] = env->regs[14];
|
||||
env->xregs[21] = env->regs[13];
|
||||
} else {
|
||||
env->xregs[20] = env->banked_r13[bank_number(ARM_CPU_MODE_ABT)];
|
||||
env->xregs[21] = env->banked_r14[bank_number(ARM_CPU_MODE_ABT)];
|
||||
env->xregs[20] = env->banked_r14[bank_number(ARM_CPU_MODE_ABT)];
|
||||
env->xregs[21] = env->banked_r13[bank_number(ARM_CPU_MODE_ABT)];
|
||||
}
|
||||
|
||||
if (mode == ARM_CPU_MODE_UND) {
|
||||
env->xregs[22] = env->regs[13];
|
||||
env->xregs[23] = env->regs[14];
|
||||
env->xregs[22] = env->regs[14];
|
||||
env->xregs[23] = env->regs[13];
|
||||
} else {
|
||||
env->xregs[22] = env->banked_r13[bank_number(ARM_CPU_MODE_UND)];
|
||||
env->xregs[23] = env->banked_r14[bank_number(ARM_CPU_MODE_UND)];
|
||||
env->xregs[22] = env->banked_r14[bank_number(ARM_CPU_MODE_UND)];
|
||||
env->xregs[23] = env->banked_r13[bank_number(ARM_CPU_MODE_UND)];
|
||||
}
|
||||
|
||||
/* Registers x24-x30 are mapped to r8-r14 in FIQ mode. If we are in FIQ
|
||||
@ -5427,35 +5429,35 @@ void aarch64_sync_64_to_32(CPUARMState *env)
|
||||
}
|
||||
|
||||
if (mode == ARM_CPU_MODE_IRQ) {
|
||||
env->regs[13] = env->xregs[16];
|
||||
env->regs[14] = env->xregs[17];
|
||||
env->regs[14] = env->xregs[16];
|
||||
env->regs[13] = env->xregs[17];
|
||||
} else {
|
||||
env->banked_r13[bank_number(ARM_CPU_MODE_IRQ)] = env->xregs[16];
|
||||
env->banked_r14[bank_number(ARM_CPU_MODE_IRQ)] = env->xregs[17];
|
||||
env->banked_r14[bank_number(ARM_CPU_MODE_IRQ)] = env->xregs[16];
|
||||
env->banked_r13[bank_number(ARM_CPU_MODE_IRQ)] = env->xregs[17];
|
||||
}
|
||||
|
||||
if (mode == ARM_CPU_MODE_SVC) {
|
||||
env->regs[13] = env->xregs[18];
|
||||
env->regs[14] = env->xregs[19];
|
||||
env->regs[14] = env->xregs[18];
|
||||
env->regs[13] = env->xregs[19];
|
||||
} else {
|
||||
env->banked_r13[bank_number(ARM_CPU_MODE_SVC)] = env->xregs[18];
|
||||
env->banked_r14[bank_number(ARM_CPU_MODE_SVC)] = env->xregs[19];
|
||||
env->banked_r14[bank_number(ARM_CPU_MODE_SVC)] = env->xregs[18];
|
||||
env->banked_r13[bank_number(ARM_CPU_MODE_SVC)] = env->xregs[19];
|
||||
}
|
||||
|
||||
if (mode == ARM_CPU_MODE_ABT) {
|
||||
env->regs[13] = env->xregs[20];
|
||||
env->regs[14] = env->xregs[21];
|
||||
env->regs[14] = env->xregs[20];
|
||||
env->regs[13] = env->xregs[21];
|
||||
} else {
|
||||
env->banked_r13[bank_number(ARM_CPU_MODE_ABT)] = env->xregs[20];
|
||||
env->banked_r14[bank_number(ARM_CPU_MODE_ABT)] = env->xregs[21];
|
||||
env->banked_r14[bank_number(ARM_CPU_MODE_ABT)] = env->xregs[20];
|
||||
env->banked_r13[bank_number(ARM_CPU_MODE_ABT)] = env->xregs[21];
|
||||
}
|
||||
|
||||
if (mode == ARM_CPU_MODE_UND) {
|
||||
env->regs[13] = env->xregs[22];
|
||||
env->regs[14] = env->xregs[23];
|
||||
env->regs[14] = env->xregs[22];
|
||||
env->regs[13] = env->xregs[23];
|
||||
} else {
|
||||
env->banked_r13[bank_number(ARM_CPU_MODE_UND)] = env->xregs[22];
|
||||
env->banked_r14[bank_number(ARM_CPU_MODE_UND)] = env->xregs[23];
|
||||
env->banked_r14[bank_number(ARM_CPU_MODE_UND)] = env->xregs[22];
|
||||
env->banked_r13[bank_number(ARM_CPU_MODE_UND)] = env->xregs[23];
|
||||
}
|
||||
|
||||
/* Registers x24-x30 are mapped to r8-r14 in FIQ mode. If we are in FIQ
|
||||
@ -5549,8 +5551,10 @@ void arm_cpu_do_interrupt(CPUState *cs)
|
||||
if (((mask == 0x123456 && !env->thumb)
|
||||
|| (mask == 0xab && env->thumb))
|
||||
&& (env->uncached_cpsr & CPSR_M) != ARM_CPU_MODE_USR) {
|
||||
qemu_log_mask(CPU_LOG_INT,
|
||||
"...handling as semihosting call 0x%x\n",
|
||||
env->regs[0]);
|
||||
env->regs[0] = do_arm_semihosting(env);
|
||||
qemu_log_mask(CPU_LOG_INT, "...handled as semihosting call\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -5567,8 +5571,10 @@ void arm_cpu_do_interrupt(CPUState *cs)
|
||||
if (mask == 0xab
|
||||
&& (env->uncached_cpsr & CPSR_M) != ARM_CPU_MODE_USR) {
|
||||
env->regs[15] += 2;
|
||||
qemu_log_mask(CPU_LOG_INT,
|
||||
"...handling as semihosting call 0x%x\n",
|
||||
env->regs[0]);
|
||||
env->regs[0] = do_arm_semihosting(env);
|
||||
qemu_log_mask(CPU_LOG_INT, "...handled as semihosting call\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -36,6 +36,7 @@ static inline bool excp_is_internal(int excp)
|
||||
|| excp == EXCP_HALTED
|
||||
|| excp == EXCP_EXCEPTION_EXIT
|
||||
|| excp == EXCP_KERNEL_TRAP
|
||||
|| excp == EXCP_SEMIHOST
|
||||
|| excp == EXCP_STREX;
|
||||
}
|
||||
|
||||
@ -58,6 +59,7 @@ static const char * const excnames[] = {
|
||||
[EXCP_SMC] = "Secure Monitor Call",
|
||||
[EXCP_VIRQ] = "Virtual IRQ",
|
||||
[EXCP_VFIQ] = "Virtual FIQ",
|
||||
[EXCP_SEMIHOST] = "Semihosting call",
|
||||
};
|
||||
|
||||
static inline void arm_log_exception(int idx)
|
||||
|
@ -181,7 +181,6 @@ int kvm_arm_cpreg_level(uint64_t regidx)
|
||||
return KVM_PUT_RUNTIME_STATE;
|
||||
}
|
||||
|
||||
#define ARM_MPIDR_HWID_BITMASK 0xFFFFFF
|
||||
#define ARM_CPU_ID_MPIDR 0, 0, 0, 5
|
||||
|
||||
int kvm_arch_init_vcpu(CPUState *cs)
|
||||
@ -234,7 +233,7 @@ int kvm_arch_init_vcpu(CPUState *cs)
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
cpu->mp_affinity = mpidr & ARM_MPIDR_HWID_BITMASK;
|
||||
cpu->mp_affinity = mpidr & ARM32_AFFINITY_MASK;
|
||||
|
||||
return kvm_arm_init_cpreg_list(cpu);
|
||||
}
|
||||
|
@ -77,7 +77,6 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUClass *ahcc)
|
||||
return true;
|
||||
}
|
||||
|
||||
#define ARM_MPIDR_HWID_BITMASK 0xFF00FFFFFFULL
|
||||
#define ARM_CPU_ID_MPIDR 3, 0, 0, 0, 5
|
||||
|
||||
int kvm_arch_init_vcpu(CPUState *cs)
|
||||
@ -120,7 +119,7 @@ int kvm_arch_init_vcpu(CPUState *cs)
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
cpu->mp_affinity = mpidr & ARM_MPIDR_HWID_BITMASK;
|
||||
cpu->mp_affinity = mpidr & ARM64_AFFINITY_MASK;
|
||||
|
||||
return kvm_arm_init_cpreg_list(cpu);
|
||||
}
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include "internals.h"
|
||||
#include "qemu/host-utils.h"
|
||||
|
||||
#include "exec/semihost.h"
|
||||
#include "exec/gen-icount.h"
|
||||
|
||||
#include "exec/helper-proto.h"
|
||||
@ -1553,8 +1554,27 @@ static void disas_exc(DisasContext *s, uint32_t insn)
|
||||
unallocated_encoding(s);
|
||||
break;
|
||||
}
|
||||
/* HLT */
|
||||
unsupported_encoding(s, insn);
|
||||
/* HLT. This has two purposes.
|
||||
* Architecturally, it is an external halting debug instruction.
|
||||
* Since QEMU doesn't implement external debug, we treat this as
|
||||
* it is required for halting debug disabled: it will UNDEF.
|
||||
* Secondly, "HLT 0xf000" is the A64 semihosting syscall instruction.
|
||||
*/
|
||||
if (semihosting_enabled() && imm16 == 0xf000) {
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
/* In system mode, don't allow userspace access to semihosting,
|
||||
* to provide some semblance of security (and for consistency
|
||||
* with our 32-bit semihosting).
|
||||
*/
|
||||
if (s->current_el == 0) {
|
||||
unsupported_encoding(s, insn);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
gen_exception_internal_insn(s, 0, EXCP_SEMIHOST);
|
||||
} else {
|
||||
unsupported_encoding(s, insn);
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
if (op2_ll < 1 || op2_ll > 3) {
|
||||
|
@ -201,6 +201,7 @@ check-qtest-sparc64-y = tests/endianness-test$(EXESUF)
|
||||
gcov-files-sparc-y += hw/timer/m48t59.c
|
||||
gcov-files-sparc64-y += hw/timer/m48t59.c
|
||||
check-qtest-arm-y = tests/tmp105-test$(EXESUF)
|
||||
check-qtest-arm-y = tests/ds1338-test$(EXESUF)
|
||||
gcov-files-arm-y += hw/misc/tmp105.c
|
||||
check-qtest-arm-y += tests/virtio-blk-test$(EXESUF)
|
||||
gcov-files-arm-y += arm-softmmu/hw/block/virtio-blk.c
|
||||
@ -358,6 +359,7 @@ libqos-pc-obj-y = $(libqos-obj-y) tests/libqos/pci-pc.o
|
||||
libqos-pc-obj-y += tests/libqos/malloc-pc.o tests/libqos/libqos-pc.o
|
||||
libqos-pc-obj-y += tests/libqos/ahci.o
|
||||
libqos-omap-obj-y = $(libqos-obj-y) tests/libqos/i2c-omap.o
|
||||
libqos-imx-obj-y = $(libqos-obj-y) tests/libqos/i2c-imx.o
|
||||
libqos-usb-obj-y = $(libqos-pc-obj-y) tests/libqos/usb.o
|
||||
libqos-virtio-obj-y = $(libqos-pc-obj-y) tests/libqos/virtio.o tests/libqos/virtio-pci.o tests/libqos/virtio-mmio.o tests/libqos/malloc-generic.o
|
||||
|
||||
@ -372,6 +374,7 @@ tests/hd-geo-test$(EXESUF): tests/hd-geo-test.o
|
||||
tests/boot-order-test$(EXESUF): tests/boot-order-test.o $(libqos-obj-y)
|
||||
tests/bios-tables-test$(EXESUF): tests/bios-tables-test.o $(libqos-obj-y)
|
||||
tests/tmp105-test$(EXESUF): tests/tmp105-test.o $(libqos-omap-obj-y)
|
||||
tests/ds1338-test$(EXESUF): tests/ds1338-test.o $(libqos-imx-obj-y)
|
||||
tests/i440fx-test$(EXESUF): tests/i440fx-test.o $(libqos-pc-obj-y)
|
||||
tests/q35-test$(EXESUF): tests/q35-test.o $(libqos-pc-obj-y)
|
||||
tests/fw_cfg-test$(EXESUF): tests/fw_cfg-test.o $(libqos-pc-obj-y)
|
||||
|
@ -50,7 +50,7 @@ typedef struct {
|
||||
int rsdt_tables_nr;
|
||||
GArray *tables;
|
||||
uint32_t smbios_ep_addr;
|
||||
struct smbios_entry_point smbios_ep_table;
|
||||
struct smbios_21_entry_point smbios_ep_table;
|
||||
} test_data;
|
||||
|
||||
#define LOW(x) ((x) & 0xff)
|
||||
@ -601,7 +601,7 @@ static void test_acpi_asl(test_data *data)
|
||||
|
||||
static bool smbios_ep_table_ok(test_data *data)
|
||||
{
|
||||
struct smbios_entry_point *ep_table = &data->smbios_ep_table;
|
||||
struct smbios_21_entry_point *ep_table = &data->smbios_ep_table;
|
||||
uint32_t addr = data->smbios_ep_addr;
|
||||
|
||||
ACPI_READ_ARRAY(ep_table->anchor_string, addr);
|
||||
@ -681,7 +681,7 @@ static inline bool smbios_single_instance(uint8_t type)
|
||||
static void test_smbios_structs(test_data *data)
|
||||
{
|
||||
DECLARE_BITMAP(struct_bitmap, SMBIOS_MAX_TYPE+1) = { 0 };
|
||||
struct smbios_entry_point *ep_table = &data->smbios_ep_table;
|
||||
struct smbios_21_entry_point *ep_table = &data->smbios_ep_table;
|
||||
uint32_t addr = ep_table->structure_table_address;
|
||||
int i, len, max_len = 0;
|
||||
uint8_t type, prv, crt;
|
||||
|
78
tests/ds1338-test.c
Normal file
78
tests/ds1338-test.c
Normal file
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* QTest testcase for the DS1338 RTC
|
||||
*
|
||||
* Copyright (c) 2013 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.
|
||||
*
|
||||
* 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 "libqtest.h"
|
||||
#include "libqos/i2c.h"
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#define IMX25_I2C_0_BASE 0x43F80000
|
||||
|
||||
#define DS1338_ADDR 0x68
|
||||
|
||||
static I2CAdapter *i2c;
|
||||
static uint8_t addr;
|
||||
|
||||
static inline uint8_t bcd2bin(uint8_t x)
|
||||
{
|
||||
return ((x) & 0x0f) + ((x) >> 4) * 10;
|
||||
}
|
||||
|
||||
static void send_and_receive(void)
|
||||
{
|
||||
uint8_t cmd[1];
|
||||
uint8_t resp[7];
|
||||
time_t now = time(NULL);
|
||||
struct tm *tm_ptr = gmtime(&now);
|
||||
|
||||
/* reset the index in the RTC memory */
|
||||
cmd[0] = 0;
|
||||
i2c_send(i2c, addr, cmd, 1);
|
||||
|
||||
/* retrieve the date */
|
||||
i2c_recv(i2c, addr, resp, 7);
|
||||
|
||||
/* check retrieved time againt local time */
|
||||
g_assert_cmpuint(bcd2bin(resp[4]), == , tm_ptr->tm_mday);
|
||||
g_assert_cmpuint(bcd2bin(resp[5]), == , 1 + tm_ptr->tm_mon);
|
||||
g_assert_cmpuint(2000 + bcd2bin(resp[6]), == , 1900 + tm_ptr->tm_year);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
QTestState *s = NULL;
|
||||
int ret;
|
||||
|
||||
g_test_init(&argc, &argv, NULL);
|
||||
|
||||
s = qtest_start("-display none -machine imx25_pdk");
|
||||
i2c = imx_i2c_create(IMX25_I2C_0_BASE);
|
||||
addr = DS1338_ADDR;
|
||||
|
||||
qtest_add_func("/ds1338/tx-rx", send_and_receive);
|
||||
|
||||
ret = g_test_run();
|
||||
|
||||
if (s) {
|
||||
qtest_quit(s);
|
||||
}
|
||||
g_free(i2c);
|
||||
|
||||
return ret;
|
||||
}
|
209
tests/libqos/i2c-imx.c
Normal file
209
tests/libqos/i2c-imx.c
Normal file
@ -0,0 +1,209 @@
|
||||
/*
|
||||
* QTest i.MX I2C driver
|
||||
*
|
||||
* Copyright (c) 2013 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.
|
||||
*
|
||||
* 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 "libqos/i2c.h"
|
||||
|
||||
#include <glib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "libqtest.h"
|
||||
|
||||
#include "hw/i2c/imx_i2c.h"
|
||||
|
||||
enum IMXI2CDirection {
|
||||
IMX_I2C_READ,
|
||||
IMX_I2C_WRITE,
|
||||
};
|
||||
|
||||
typedef struct IMXI2C {
|
||||
I2CAdapter parent;
|
||||
|
||||
uint64_t addr;
|
||||
} IMXI2C;
|
||||
|
||||
|
||||
static void imx_i2c_set_slave_addr(IMXI2C *s, uint8_t addr,
|
||||
enum IMXI2CDirection direction)
|
||||
{
|
||||
writeb(s->addr + I2DR_ADDR, (addr << 1) |
|
||||
(direction == IMX_I2C_READ ? 1 : 0));
|
||||
}
|
||||
|
||||
static void imx_i2c_send(I2CAdapter *i2c, uint8_t addr,
|
||||
const uint8_t *buf, uint16_t len)
|
||||
{
|
||||
IMXI2C *s = (IMXI2C *)i2c;
|
||||
uint8_t data;
|
||||
uint8_t status;
|
||||
uint16_t size = 0;
|
||||
|
||||
if (!len) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* set the bus for write */
|
||||
data = I2CR_IEN |
|
||||
I2CR_IIEN |
|
||||
I2CR_MSTA |
|
||||
I2CR_MTX |
|
||||
I2CR_TXAK;
|
||||
|
||||
writeb(s->addr + I2CR_ADDR, data);
|
||||
status = readb(s->addr + I2SR_ADDR);
|
||||
g_assert((status & I2SR_IBB) != 0);
|
||||
|
||||
/* set the slave address */
|
||||
imx_i2c_set_slave_addr(s, addr, IMX_I2C_WRITE);
|
||||
status = readb(s->addr + I2SR_ADDR);
|
||||
g_assert((status & I2SR_IIF) != 0);
|
||||
g_assert((status & I2SR_RXAK) == 0);
|
||||
|
||||
/* ack the interrupt */
|
||||
writeb(s->addr + I2SR_ADDR, 0);
|
||||
status = readb(s->addr + I2SR_ADDR);
|
||||
g_assert((status & I2SR_IIF) == 0);
|
||||
|
||||
while (size < len) {
|
||||
/* check we are still busy */
|
||||
status = readb(s->addr + I2SR_ADDR);
|
||||
g_assert((status & I2SR_IBB) != 0);
|
||||
|
||||
/* write the data */
|
||||
writeb(s->addr + I2DR_ADDR, buf[size]);
|
||||
status = readb(s->addr + I2SR_ADDR);
|
||||
g_assert((status & I2SR_IIF) != 0);
|
||||
g_assert((status & I2SR_RXAK) == 0);
|
||||
|
||||
/* ack the interrupt */
|
||||
writeb(s->addr + I2SR_ADDR, 0);
|
||||
status = readb(s->addr + I2SR_ADDR);
|
||||
g_assert((status & I2SR_IIF) == 0);
|
||||
|
||||
size++;
|
||||
}
|
||||
|
||||
/* release the bus */
|
||||
data &= ~(I2CR_MSTA | I2CR_MTX);
|
||||
writeb(s->addr + I2CR_ADDR, data);
|
||||
status = readb(s->addr + I2SR_ADDR);
|
||||
g_assert((status & I2SR_IBB) == 0);
|
||||
}
|
||||
|
||||
static void imx_i2c_recv(I2CAdapter *i2c, uint8_t addr,
|
||||
uint8_t *buf, uint16_t len)
|
||||
{
|
||||
IMXI2C *s = (IMXI2C *)i2c;
|
||||
uint8_t data;
|
||||
uint8_t status;
|
||||
uint16_t size = 0;
|
||||
|
||||
if (!len) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* set the bus for write */
|
||||
data = I2CR_IEN |
|
||||
I2CR_IIEN |
|
||||
I2CR_MSTA |
|
||||
I2CR_MTX |
|
||||
I2CR_TXAK;
|
||||
|
||||
writeb(s->addr + I2CR_ADDR, data);
|
||||
status = readb(s->addr + I2SR_ADDR);
|
||||
g_assert((status & I2SR_IBB) != 0);
|
||||
|
||||
/* set the slave address */
|
||||
imx_i2c_set_slave_addr(s, addr, IMX_I2C_READ);
|
||||
status = readb(s->addr + I2SR_ADDR);
|
||||
g_assert((status & I2SR_IIF) != 0);
|
||||
g_assert((status & I2SR_RXAK) == 0);
|
||||
|
||||
/* ack the interrupt */
|
||||
writeb(s->addr + I2SR_ADDR, 0);
|
||||
status = readb(s->addr + I2SR_ADDR);
|
||||
g_assert((status & I2SR_IIF) == 0);
|
||||
|
||||
/* set the bus for read */
|
||||
data &= ~I2CR_MTX;
|
||||
/* if only one byte don't ack */
|
||||
if (len != 1) {
|
||||
data &= ~I2CR_TXAK;
|
||||
}
|
||||
writeb(s->addr + I2CR_ADDR, data);
|
||||
status = readb(s->addr + I2SR_ADDR);
|
||||
g_assert((status & I2SR_IBB) != 0);
|
||||
|
||||
/* dummy read */
|
||||
readb(s->addr + I2DR_ADDR);
|
||||
status = readb(s->addr + I2SR_ADDR);
|
||||
g_assert((status & I2SR_IIF) != 0);
|
||||
|
||||
/* ack the interrupt */
|
||||
writeb(s->addr + I2SR_ADDR, 0);
|
||||
status = readb(s->addr + I2SR_ADDR);
|
||||
g_assert((status & I2SR_IIF) == 0);
|
||||
|
||||
while (size < len) {
|
||||
/* check we are still busy */
|
||||
status = readb(s->addr + I2SR_ADDR);
|
||||
g_assert((status & I2SR_IBB) != 0);
|
||||
|
||||
if (size == (len - 1)) {
|
||||
/* stop the read transaction */
|
||||
data &= ~(I2CR_MSTA | I2CR_MTX);
|
||||
} else {
|
||||
/* ack the data read */
|
||||
data |= I2CR_TXAK;
|
||||
}
|
||||
writeb(s->addr + I2CR_ADDR, data);
|
||||
|
||||
/* read the data */
|
||||
buf[size] = readb(s->addr + I2DR_ADDR);
|
||||
|
||||
if (size != (len - 1)) {
|
||||
status = readb(s->addr + I2SR_ADDR);
|
||||
g_assert((status & I2SR_IIF) != 0);
|
||||
|
||||
/* ack the interrupt */
|
||||
writeb(s->addr + I2SR_ADDR, 0);
|
||||
}
|
||||
|
||||
status = readb(s->addr + I2SR_ADDR);
|
||||
g_assert((status & I2SR_IIF) == 0);
|
||||
|
||||
size++;
|
||||
}
|
||||
|
||||
status = readb(s->addr + I2SR_ADDR);
|
||||
g_assert((status & I2SR_IBB) == 0);
|
||||
}
|
||||
|
||||
I2CAdapter *imx_i2c_create(uint64_t addr)
|
||||
{
|
||||
IMXI2C *s = g_malloc0(sizeof(*s));
|
||||
I2CAdapter *i2c = (I2CAdapter *)s;
|
||||
|
||||
s->addr = addr;
|
||||
|
||||
i2c->send = imx_i2c_send;
|
||||
i2c->recv = imx_i2c_recv;
|
||||
|
||||
return i2c;
|
||||
}
|
@ -27,4 +27,7 @@ void i2c_recv(I2CAdapter *i2c, uint8_t addr,
|
||||
/* libi2c-omap.c */
|
||||
I2CAdapter *omap_i2c_create(uint64_t addr);
|
||||
|
||||
/* libi2c-imx.c */
|
||||
I2CAdapter *imx_i2c_create(uint64_t addr);
|
||||
|
||||
#endif
|
||||
|
Loading…
x
Reference in New Issue
Block a user