Add nuvoton sd module for NPCM7XX
Add gdb-xml for MVE More uses of tcg_constant_* in target/arm Fix parameter naming for default-bus-bypass-iommu Ignore cache operations to mmio in HVF -----BEGIN PGP SIGNATURE----- iQFRBAABCgA7FiEEekgeeIaLTbaoWgXAZN846K9+IV8FAmGBgjkdHHJpY2hhcmQu aGVuZGVyc29uQGxpbmFyby5vcmcACgkQZN846K9+IV8sAAgAsHaW2sHH/W4TzCwl DfqFar4u047Q+ZtQHjNehGHF9Bxp4NS4A0qL52vk0hVoqeWlyF1N29MOnewgVDqY q1x+uxJtG9xjTse7oEEshEEFF/7J8eB8dN4E78TFn/6IhvVhGiUeeRu29s44Ot6N E2KABcXfd+4gEdqhepLGEbi5n0TnA8ARmmeffZNWVEbsxQjHnMQQYmqGmllB3xV3 qPpnp3avvD1015zMwrLVmlDO+tSRr/1bed7k3k26ebga2B/zitxcpXFNCDlgePx0 LNT5QYvBDpE7HOruGQjf4iXPJHfYw5VMtopK7K++rY9KWiJgBVSjQUcB462sdCPk wNAp0g== =vlZ5 -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/rth/tags/pull-arm-20211102-2' into staging Add nuvoton sd module for NPCM7XX Add gdb-xml for MVE More uses of tcg_constant_* in target/arm Fix parameter naming for default-bus-bypass-iommu Ignore cache operations to mmio in HVF # gpg: Signature made Tue 02 Nov 2021 02:23:53 PM EDT # gpg: using RSA key 7A481E78868B4DB6A85A05C064DF38E8AF7E215F # gpg: issuer "richard.henderson@linaro.org" # gpg: Good signature from "Richard Henderson <richard.henderson@linaro.org>" [ultimate] * remotes/rth/tags/pull-arm-20211102-2: hvf: arm: Ignore cache operations on MMIO hw/arm/virt: Rename default_bus_bypass_iommu target/arm: Use tcg_constant_i32() in gen_rev16() target/arm: Use tcg_constant_i64() in do_sat_addsub_64() target/arm: Use the constant variant of store_cpu_field() when possible target/arm: Introduce store_cpu_field_constant() helper target/arm: Use tcg_constant_i32() in op_smlad() target/arm: Advertise MVE to gdb when present tests/qtest/libqos: add SDHCI commands hw/arm: Attach MMC to quanta-gbs-bmc hw/arm: Add Nuvoton SD module to board hw/sd: add nuvoton MMC Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
commit
cc23377516
@ -1,5 +1,5 @@
|
|||||||
TARGET_ARCH=aarch64
|
TARGET_ARCH=aarch64
|
||||||
TARGET_BASE_ARCH=arm
|
TARGET_BASE_ARCH=arm
|
||||||
TARGET_SUPPORTS_MTTCG=y
|
TARGET_SUPPORTS_MTTCG=y
|
||||||
TARGET_XML_FILES= gdb-xml/aarch64-core.xml gdb-xml/aarch64-fpu.xml gdb-xml/arm-core.xml gdb-xml/arm-vfp.xml gdb-xml/arm-vfp3.xml gdb-xml/arm-vfp-sysregs.xml gdb-xml/arm-neon.xml gdb-xml/arm-m-profile.xml
|
TARGET_XML_FILES= gdb-xml/aarch64-core.xml gdb-xml/aarch64-fpu.xml gdb-xml/arm-core.xml gdb-xml/arm-vfp.xml gdb-xml/arm-vfp3.xml gdb-xml/arm-vfp-sysregs.xml gdb-xml/arm-neon.xml gdb-xml/arm-m-profile.xml gdb-xml/arm-m-profile-mve.xml
|
||||||
TARGET_NEED_FDT=y
|
TARGET_NEED_FDT=y
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
TARGET_ARCH=arm
|
TARGET_ARCH=arm
|
||||||
TARGET_SYSTBL_ABI=common,oabi
|
TARGET_SYSTBL_ABI=common,oabi
|
||||||
TARGET_SYSTBL=syscall.tbl
|
TARGET_SYSTBL=syscall.tbl
|
||||||
TARGET_XML_FILES= gdb-xml/arm-core.xml gdb-xml/arm-vfp.xml gdb-xml/arm-vfp3.xml gdb-xml/arm-vfp-sysregs.xml gdb-xml/arm-neon.xml gdb-xml/arm-m-profile.xml
|
TARGET_XML_FILES= gdb-xml/arm-core.xml gdb-xml/arm-vfp.xml gdb-xml/arm-vfp3.xml gdb-xml/arm-vfp-sysregs.xml gdb-xml/arm-neon.xml gdb-xml/arm-m-profile.xml gdb-xml/arm-m-profile-mve.xml
|
||||||
TARGET_HAS_BFLT=y
|
TARGET_HAS_BFLT=y
|
||||||
CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y
|
CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
TARGET_ARCH=arm
|
TARGET_ARCH=arm
|
||||||
TARGET_SUPPORTS_MTTCG=y
|
TARGET_SUPPORTS_MTTCG=y
|
||||||
TARGET_XML_FILES= gdb-xml/arm-core.xml gdb-xml/arm-vfp.xml gdb-xml/arm-vfp3.xml gdb-xml/arm-vfp-sysregs.xml gdb-xml/arm-neon.xml gdb-xml/arm-m-profile.xml
|
TARGET_XML_FILES= gdb-xml/arm-core.xml gdb-xml/arm-vfp.xml gdb-xml/arm-vfp3.xml gdb-xml/arm-vfp-sysregs.xml gdb-xml/arm-neon.xml gdb-xml/arm-m-profile.xml gdb-xml/arm-m-profile-mve.xml
|
||||||
TARGET_NEED_FDT=y
|
TARGET_NEED_FDT=y
|
||||||
|
@ -2,6 +2,6 @@ TARGET_ARCH=arm
|
|||||||
TARGET_SYSTBL_ABI=common,oabi
|
TARGET_SYSTBL_ABI=common,oabi
|
||||||
TARGET_SYSTBL=syscall.tbl
|
TARGET_SYSTBL=syscall.tbl
|
||||||
TARGET_WORDS_BIGENDIAN=y
|
TARGET_WORDS_BIGENDIAN=y
|
||||||
TARGET_XML_FILES= gdb-xml/arm-core.xml gdb-xml/arm-vfp.xml gdb-xml/arm-vfp3.xml gdb-xml/arm-vfp-sysregs.xml gdb-xml/arm-neon.xml gdb-xml/arm-m-profile.xml
|
TARGET_XML_FILES= gdb-xml/arm-core.xml gdb-xml/arm-vfp.xml gdb-xml/arm-vfp3.xml gdb-xml/arm-vfp-sysregs.xml gdb-xml/arm-neon.xml gdb-xml/arm-m-profile.xml gdb-xml/arm-m-profile-mve.xml
|
||||||
TARGET_HAS_BFLT=y
|
TARGET_HAS_BFLT=y
|
||||||
CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y
|
CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y
|
||||||
|
19
gdb-xml/arm-m-profile-mve.xml
Normal file
19
gdb-xml/arm-m-profile-mve.xml
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<?xml version="1.0"?>
|
||||||
|
<!-- Copyright (C) 2021 Free Software Foundation, Inc.
|
||||||
|
|
||||||
|
Copying and distribution of this file, with or without modification,
|
||||||
|
are permitted in any medium without royalty provided the copyright
|
||||||
|
notice and this notice are preserved. -->
|
||||||
|
|
||||||
|
<!DOCTYPE feature SYSTEM "gdb-target.dtd">
|
||||||
|
<feature name="org.gnu.gdb.arm.m-profile-mve">
|
||||||
|
<flags id="vpr_reg" size="4">
|
||||||
|
<!-- ARMv8.1-M and MVE: Unprivileged and privileged Access. -->
|
||||||
|
<field name="P0" start="0" end="15"/>
|
||||||
|
<!-- ARMv8.1-M: Privileged Access only. -->
|
||||||
|
<field name="MASK01" start="16" end="19"/>
|
||||||
|
<!-- ARMv8.1-M: Privileged Access only. -->
|
||||||
|
<field name="MASK23" start="20" end="23"/>
|
||||||
|
</flags>
|
||||||
|
<reg name="vpr" bitsize="32" type="vpr_reg"/>
|
||||||
|
</feature>
|
@ -63,6 +63,8 @@
|
|||||||
#define NPCM7XX_ROM_BA (0xffff0000)
|
#define NPCM7XX_ROM_BA (0xffff0000)
|
||||||
#define NPCM7XX_ROM_SZ (64 * KiB)
|
#define NPCM7XX_ROM_SZ (64 * KiB)
|
||||||
|
|
||||||
|
/* SDHCI Modules */
|
||||||
|
#define NPCM7XX_MMC_BA (0xf0842000)
|
||||||
|
|
||||||
/* Clock configuration values to be fixed up when bypassing bootloader */
|
/* Clock configuration values to be fixed up when bypassing bootloader */
|
||||||
|
|
||||||
@ -83,6 +85,7 @@ enum NPCM7xxInterrupt {
|
|||||||
NPCM7XX_UART3_IRQ,
|
NPCM7XX_UART3_IRQ,
|
||||||
NPCM7XX_EMC1RX_IRQ = 15,
|
NPCM7XX_EMC1RX_IRQ = 15,
|
||||||
NPCM7XX_EMC1TX_IRQ,
|
NPCM7XX_EMC1TX_IRQ,
|
||||||
|
NPCM7XX_MMC_IRQ = 26,
|
||||||
NPCM7XX_TIMER0_IRQ = 32, /* Timer Module 0 */
|
NPCM7XX_TIMER0_IRQ = 32, /* Timer Module 0 */
|
||||||
NPCM7XX_TIMER1_IRQ,
|
NPCM7XX_TIMER1_IRQ,
|
||||||
NPCM7XX_TIMER2_IRQ,
|
NPCM7XX_TIMER2_IRQ,
|
||||||
@ -443,6 +446,8 @@ static void npcm7xx_init(Object *obj)
|
|||||||
for (i = 0; i < ARRAY_SIZE(s->emc); i++) {
|
for (i = 0; i < ARRAY_SIZE(s->emc); i++) {
|
||||||
object_initialize_child(obj, "emc[*]", &s->emc[i], TYPE_NPCM7XX_EMC);
|
object_initialize_child(obj, "emc[*]", &s->emc[i], TYPE_NPCM7XX_EMC);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
object_initialize_child(obj, "mmc", &s->mmc, TYPE_NPCM7XX_SDHCI);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void npcm7xx_realize(DeviceState *dev, Error **errp)
|
static void npcm7xx_realize(DeviceState *dev, Error **errp)
|
||||||
@ -707,6 +712,12 @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
|
|||||||
&error_abort);
|
&error_abort);
|
||||||
memory_region_add_subregion(get_system_memory(), NPCM7XX_ROM_BA, &s->irom);
|
memory_region_add_subregion(get_system_memory(), NPCM7XX_ROM_BA, &s->irom);
|
||||||
|
|
||||||
|
/* SDHCI */
|
||||||
|
sysbus_realize(SYS_BUS_DEVICE(&s->mmc), &error_abort);
|
||||||
|
sysbus_mmio_map(SYS_BUS_DEVICE(&s->mmc), 0, NPCM7XX_MMC_BA);
|
||||||
|
sysbus_connect_irq(SYS_BUS_DEVICE(&s->mmc), 0,
|
||||||
|
npcm7xx_irq(s, NPCM7XX_MMC_IRQ));
|
||||||
|
|
||||||
create_unimplemented_device("npcm7xx.shm", 0xc0001000, 4 * KiB);
|
create_unimplemented_device("npcm7xx.shm", 0xc0001000, 4 * KiB);
|
||||||
create_unimplemented_device("npcm7xx.vdmx", 0xe0800000, 4 * KiB);
|
create_unimplemented_device("npcm7xx.vdmx", 0xe0800000, 4 * KiB);
|
||||||
create_unimplemented_device("npcm7xx.pcierc", 0xe1000000, 64 * KiB);
|
create_unimplemented_device("npcm7xx.pcierc", 0xe1000000, 64 * KiB);
|
||||||
@ -736,7 +747,6 @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
|
|||||||
create_unimplemented_device("npcm7xx.usbd[8]", 0xf0838000, 4 * KiB);
|
create_unimplemented_device("npcm7xx.usbd[8]", 0xf0838000, 4 * KiB);
|
||||||
create_unimplemented_device("npcm7xx.usbd[9]", 0xf0839000, 4 * KiB);
|
create_unimplemented_device("npcm7xx.usbd[9]", 0xf0839000, 4 * KiB);
|
||||||
create_unimplemented_device("npcm7xx.sd", 0xf0840000, 8 * KiB);
|
create_unimplemented_device("npcm7xx.sd", 0xf0840000, 8 * KiB);
|
||||||
create_unimplemented_device("npcm7xx.mmc", 0xf0842000, 8 * KiB);
|
|
||||||
create_unimplemented_device("npcm7xx.pcimbx", 0xf0848000, 512 * KiB);
|
create_unimplemented_device("npcm7xx.pcimbx", 0xf0848000, 512 * KiB);
|
||||||
create_unimplemented_device("npcm7xx.aes", 0xf0858000, 4 * KiB);
|
create_unimplemented_device("npcm7xx.aes", 0xf0858000, 4 * KiB);
|
||||||
create_unimplemented_device("npcm7xx.des", 0xf0859000, 4 * KiB);
|
create_unimplemented_device("npcm7xx.des", 0xf0859000, 4 * KiB);
|
||||||
|
@ -27,6 +27,9 @@
|
|||||||
#include "qemu-common.h"
|
#include "qemu-common.h"
|
||||||
#include "qemu/datadir.h"
|
#include "qemu/datadir.h"
|
||||||
#include "qemu/units.h"
|
#include "qemu/units.h"
|
||||||
|
#include "sysemu/blockdev.h"
|
||||||
|
#include "sysemu/sysemu.h"
|
||||||
|
#include "sysemu/block-backend.h"
|
||||||
|
|
||||||
#define NPCM750_EVB_POWER_ON_STRAPS 0x00001ff7
|
#define NPCM750_EVB_POWER_ON_STRAPS 0x00001ff7
|
||||||
#define QUANTA_GSJ_POWER_ON_STRAPS 0x00001fff
|
#define QUANTA_GSJ_POWER_ON_STRAPS 0x00001fff
|
||||||
@ -81,6 +84,22 @@ static void npcm7xx_connect_dram(NPCM7xxState *soc, MemoryRegion *dram)
|
|||||||
&error_abort);
|
&error_abort);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void sdhci_attach_drive(SDHCIState *sdhci)
|
||||||
|
{
|
||||||
|
DriveInfo *di = drive_get_next(IF_SD);
|
||||||
|
BlockBackend *blk = di ? blk_by_legacy_dinfo(di) : NULL;
|
||||||
|
|
||||||
|
BusState *bus = qdev_get_child_bus(DEVICE(sdhci), "sd-bus");
|
||||||
|
if (bus == NULL) {
|
||||||
|
error_report("No SD bus found in SOC object");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
DeviceState *carddev = qdev_new(TYPE_SD_CARD);
|
||||||
|
qdev_prop_set_drive_err(carddev, "drive", blk, &error_fatal);
|
||||||
|
qdev_realize_and_unref(carddev, bus, &error_fatal);
|
||||||
|
}
|
||||||
|
|
||||||
static NPCM7xxState *npcm7xx_create_soc(MachineState *machine,
|
static NPCM7xxState *npcm7xx_create_soc(MachineState *machine,
|
||||||
uint32_t hw_straps)
|
uint32_t hw_straps)
|
||||||
{
|
{
|
||||||
@ -355,6 +374,7 @@ static void quanta_gbs_init(MachineState *machine)
|
|||||||
drive_get(IF_MTD, 0, 0));
|
drive_get(IF_MTD, 0, 0));
|
||||||
|
|
||||||
quanta_gbs_i2c_init(soc);
|
quanta_gbs_i2c_init(soc);
|
||||||
|
sdhci_attach_drive(&soc->mmc.sdhci);
|
||||||
npcm7xx_load_kernel(machine, soc);
|
npcm7xx_load_kernel(machine, soc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2737,10 +2737,10 @@ static void virt_machine_class_init(ObjectClass *oc, void *data)
|
|||||||
"Set the IOMMU type. "
|
"Set the IOMMU type. "
|
||||||
"Valid values are none and smmuv3");
|
"Valid values are none and smmuv3");
|
||||||
|
|
||||||
object_class_property_add_bool(oc, "default_bus_bypass_iommu",
|
object_class_property_add_bool(oc, "default-bus-bypass-iommu",
|
||||||
virt_get_default_bus_bypass_iommu,
|
virt_get_default_bus_bypass_iommu,
|
||||||
virt_set_default_bus_bypass_iommu);
|
virt_set_default_bus_bypass_iommu);
|
||||||
object_class_property_set_description(oc, "default_bus_bypass_iommu",
|
object_class_property_set_description(oc, "default-bus-bypass-iommu",
|
||||||
"Set on/off to enable/disable "
|
"Set on/off to enable/disable "
|
||||||
"bypass_iommu for default root bus");
|
"bypass_iommu for default root bus");
|
||||||
|
|
||||||
|
@ -9,4 +9,5 @@ softmmu_ss.add(when: 'CONFIG_PXA2XX', if_true: files('pxa2xx_mmci.c'))
|
|||||||
softmmu_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2835_sdhost.c'))
|
softmmu_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2835_sdhost.c'))
|
||||||
softmmu_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files('aspeed_sdhci.c'))
|
softmmu_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files('aspeed_sdhci.c'))
|
||||||
softmmu_ss.add(when: 'CONFIG_ALLWINNER_H3', if_true: files('allwinner-sdhost.c'))
|
softmmu_ss.add(when: 'CONFIG_ALLWINNER_H3', if_true: files('allwinner-sdhost.c'))
|
||||||
|
softmmu_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_sdhci.c'))
|
||||||
softmmu_ss.add(when: 'CONFIG_CADENCE_SDHCI', if_true: files('cadence_sdhci.c'))
|
softmmu_ss.add(when: 'CONFIG_CADENCE_SDHCI', if_true: files('cadence_sdhci.c'))
|
||||||
|
182
hw/sd/npcm7xx_sdhci.c
Normal file
182
hw/sd/npcm7xx_sdhci.c
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
/*
|
||||||
|
* NPCM7xx SD-3.0 / eMMC-4.51 Host Controller
|
||||||
|
*
|
||||||
|
* Copyright (c) 2021 Google LLC
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "qemu/osdep.h"
|
||||||
|
|
||||||
|
#include "hw/sd/npcm7xx_sdhci.h"
|
||||||
|
#include "migration/vmstate.h"
|
||||||
|
#include "sdhci-internal.h"
|
||||||
|
#include "qemu/log.h"
|
||||||
|
|
||||||
|
static uint64_t npcm7xx_sdhci_read(void *opaque, hwaddr addr, unsigned int size)
|
||||||
|
{
|
||||||
|
NPCM7xxSDHCIState *s = opaque;
|
||||||
|
uint64_t val = 0;
|
||||||
|
|
||||||
|
switch (addr) {
|
||||||
|
case NPCM7XX_PRSTVALS_0:
|
||||||
|
case NPCM7XX_PRSTVALS_1:
|
||||||
|
case NPCM7XX_PRSTVALS_2:
|
||||||
|
case NPCM7XX_PRSTVALS_3:
|
||||||
|
case NPCM7XX_PRSTVALS_4:
|
||||||
|
case NPCM7XX_PRSTVALS_5:
|
||||||
|
val = s->regs.prstvals[(addr - NPCM7XX_PRSTVALS_0) / 2];
|
||||||
|
break;
|
||||||
|
case NPCM7XX_BOOTTOCTRL:
|
||||||
|
val = s->regs.boottoctrl;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
qemu_log_mask(LOG_GUEST_ERROR, "SDHCI read of nonexistent reg: 0x%02"
|
||||||
|
HWADDR_PRIx, addr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void npcm7xx_sdhci_write(void *opaque, hwaddr addr, uint64_t val,
|
||||||
|
unsigned int size)
|
||||||
|
{
|
||||||
|
NPCM7xxSDHCIState *s = opaque;
|
||||||
|
|
||||||
|
switch (addr) {
|
||||||
|
case NPCM7XX_BOOTTOCTRL:
|
||||||
|
s->regs.boottoctrl = val;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
qemu_log_mask(LOG_GUEST_ERROR, "SDHCI write of nonexistent reg: 0x%02"
|
||||||
|
HWADDR_PRIx, addr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool npcm7xx_sdhci_check_mem_op(void *opaque, hwaddr addr,
|
||||||
|
unsigned size, bool is_write,
|
||||||
|
MemTxAttrs attrs)
|
||||||
|
{
|
||||||
|
switch (addr) {
|
||||||
|
case NPCM7XX_PRSTVALS_0:
|
||||||
|
case NPCM7XX_PRSTVALS_1:
|
||||||
|
case NPCM7XX_PRSTVALS_2:
|
||||||
|
case NPCM7XX_PRSTVALS_3:
|
||||||
|
case NPCM7XX_PRSTVALS_4:
|
||||||
|
case NPCM7XX_PRSTVALS_5:
|
||||||
|
/* RO Word */
|
||||||
|
return !is_write && size == 2;
|
||||||
|
case NPCM7XX_BOOTTOCTRL:
|
||||||
|
/* R/W Dword */
|
||||||
|
return size == 4;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const MemoryRegionOps npcm7xx_sdhci_ops = {
|
||||||
|
.read = npcm7xx_sdhci_read,
|
||||||
|
.write = npcm7xx_sdhci_write,
|
||||||
|
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||||
|
.valid = {
|
||||||
|
.min_access_size = 1,
|
||||||
|
.max_access_size = 4,
|
||||||
|
.unaligned = false,
|
||||||
|
.accepts = npcm7xx_sdhci_check_mem_op,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static void npcm7xx_sdhci_realize(DeviceState *dev, Error **errp)
|
||||||
|
{
|
||||||
|
NPCM7xxSDHCIState *s = NPCM7XX_SDHCI(dev);
|
||||||
|
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
|
||||||
|
SysBusDevice *sbd_sdhci = SYS_BUS_DEVICE(&s->sdhci);
|
||||||
|
|
||||||
|
memory_region_init(&s->container, OBJECT(s),
|
||||||
|
"npcm7xx.sdhci-container", 0x1000);
|
||||||
|
sysbus_init_mmio(sbd, &s->container);
|
||||||
|
|
||||||
|
memory_region_init_io(&s->iomem, OBJECT(s), &npcm7xx_sdhci_ops, s,
|
||||||
|
TYPE_NPCM7XX_SDHCI, NPCM7XX_SDHCI_REGSIZE);
|
||||||
|
memory_region_add_subregion_overlap(&s->container, NPCM7XX_PRSTVALS,
|
||||||
|
&s->iomem, 1);
|
||||||
|
|
||||||
|
sysbus_realize(sbd_sdhci, errp);
|
||||||
|
memory_region_add_subregion(&s->container, 0,
|
||||||
|
sysbus_mmio_get_region(sbd_sdhci, 0));
|
||||||
|
|
||||||
|
/* propagate irq and "sd-bus" from generic-sdhci */
|
||||||
|
sysbus_pass_irq(sbd, sbd_sdhci);
|
||||||
|
s->bus = qdev_get_child_bus(DEVICE(sbd_sdhci), "sd-bus");
|
||||||
|
|
||||||
|
/* Set the read only preset values. */
|
||||||
|
memset(s->regs.prstvals, 0, sizeof(s->regs.prstvals));
|
||||||
|
s->regs.prstvals[0] = NPCM7XX_PRSTVALS_0_RESET;
|
||||||
|
s->regs.prstvals[1] = NPCM7XX_PRSTVALS_1_RESET;
|
||||||
|
s->regs.prstvals[3] = NPCM7XX_PRSTVALS_3_RESET;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void npcm7xx_sdhci_reset(DeviceState *dev)
|
||||||
|
{
|
||||||
|
NPCM7xxSDHCIState *s = NPCM7XX_SDHCI(dev);
|
||||||
|
device_cold_reset(DEVICE(&s->sdhci));
|
||||||
|
s->regs.boottoctrl = 0;
|
||||||
|
|
||||||
|
s->sdhci.prnsts = NPCM7XX_PRSNTS_RESET;
|
||||||
|
s->sdhci.blkgap = NPCM7XX_BLKGAP_RESET;
|
||||||
|
s->sdhci.capareg = NPCM7XX_CAPAB_RESET;
|
||||||
|
s->sdhci.maxcurr = NPCM7XX_MAXCURR_RESET;
|
||||||
|
s->sdhci.version = NPCM7XX_HCVER_RESET;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const VMStateDescription vmstate_npcm7xx_sdhci = {
|
||||||
|
.name = TYPE_NPCM7XX_SDHCI,
|
||||||
|
.version_id = 0,
|
||||||
|
.fields = (VMStateField[]) {
|
||||||
|
VMSTATE_UINT32(regs.boottoctrl, NPCM7xxSDHCIState),
|
||||||
|
VMSTATE_END_OF_LIST(),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static void npcm7xx_sdhci_class_init(ObjectClass *classp, void *data)
|
||||||
|
{
|
||||||
|
DeviceClass *dc = DEVICE_CLASS(classp);
|
||||||
|
|
||||||
|
dc->desc = "NPCM7xx SD/eMMC Host Controller";
|
||||||
|
dc->realize = npcm7xx_sdhci_realize;
|
||||||
|
dc->reset = npcm7xx_sdhci_reset;
|
||||||
|
dc->vmsd = &vmstate_npcm7xx_sdhci;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void npcm7xx_sdhci_instance_init(Object *obj)
|
||||||
|
{
|
||||||
|
NPCM7xxSDHCIState *s = NPCM7XX_SDHCI(obj);
|
||||||
|
|
||||||
|
object_initialize_child(OBJECT(s), "generic-sdhci", &s->sdhci,
|
||||||
|
TYPE_SYSBUS_SDHCI);
|
||||||
|
}
|
||||||
|
|
||||||
|
static TypeInfo npcm7xx_sdhci_info = {
|
||||||
|
.name = TYPE_NPCM7XX_SDHCI,
|
||||||
|
.parent = TYPE_SYS_BUS_DEVICE,
|
||||||
|
.instance_size = sizeof(NPCM7xxSDHCIState),
|
||||||
|
.instance_init = npcm7xx_sdhci_instance_init,
|
||||||
|
.class_init = npcm7xx_sdhci_class_init,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void npcm7xx_sdhci_register_types(void)
|
||||||
|
{
|
||||||
|
type_register_static(&npcm7xx_sdhci_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
type_init(npcm7xx_sdhci_register_types)
|
@ -35,6 +35,7 @@
|
|||||||
#include "hw/usb/hcd-ehci.h"
|
#include "hw/usb/hcd-ehci.h"
|
||||||
#include "hw/usb/hcd-ohci.h"
|
#include "hw/usb/hcd-ohci.h"
|
||||||
#include "target/arm/cpu.h"
|
#include "target/arm/cpu.h"
|
||||||
|
#include "hw/sd/npcm7xx_sdhci.h"
|
||||||
|
|
||||||
#define NPCM7XX_MAX_NUM_CPUS (2)
|
#define NPCM7XX_MAX_NUM_CPUS (2)
|
||||||
|
|
||||||
@ -103,6 +104,7 @@ typedef struct NPCM7xxState {
|
|||||||
OHCISysBusState ohci;
|
OHCISysBusState ohci;
|
||||||
NPCM7xxFIUState fiu[2];
|
NPCM7xxFIUState fiu[2];
|
||||||
NPCM7xxEMCState emc[2];
|
NPCM7xxEMCState emc[2];
|
||||||
|
NPCM7xxSDHCIState mmc;
|
||||||
} NPCM7xxState;
|
} NPCM7xxState;
|
||||||
|
|
||||||
#define TYPE_NPCM7XX "npcm7xx"
|
#define TYPE_NPCM7XX "npcm7xx"
|
||||||
|
65
include/hw/sd/npcm7xx_sdhci.h
Normal file
65
include/hw/sd/npcm7xx_sdhci.h
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
* NPCM7xx SD-3.0 / eMMC-4.51 Host Controller
|
||||||
|
*
|
||||||
|
* Copyright (c) 2021 Google LLC
|
||||||
|
*
|
||||||
|
* 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 NPCM7XX_SDHCI_H
|
||||||
|
#define NPCM7XX_SDHCI_H
|
||||||
|
|
||||||
|
#include "hw/sd/sdhci.h"
|
||||||
|
#include "qom/object.h"
|
||||||
|
|
||||||
|
#define TYPE_NPCM7XX_SDHCI "npcm7xx.sdhci"
|
||||||
|
#define NPCM7XX_PRSTVALS_SIZE 6
|
||||||
|
#define NPCM7XX_PRSTVALS 0x60
|
||||||
|
#define NPCM7XX_PRSTVALS_0 0x0
|
||||||
|
#define NPCM7XX_PRSTVALS_1 0x2
|
||||||
|
#define NPCM7XX_PRSTVALS_2 0x4
|
||||||
|
#define NPCM7XX_PRSTVALS_3 0x6
|
||||||
|
#define NPCM7XX_PRSTVALS_4 0x8
|
||||||
|
#define NPCM7XX_PRSTVALS_5 0xA
|
||||||
|
#define NPCM7XX_BOOTTOCTRL 0x10
|
||||||
|
#define NPCM7XX_SDHCI_REGSIZE 0x20
|
||||||
|
|
||||||
|
#define NPCM7XX_PRSNTS_RESET 0x04A00000
|
||||||
|
#define NPCM7XX_BLKGAP_RESET 0x80
|
||||||
|
#define NPCM7XX_CAPAB_RESET 0x0100200161EE0399
|
||||||
|
#define NPCM7XX_MAXCURR_RESET 0x0000000000000005
|
||||||
|
#define NPCM7XX_HCVER_RESET 0x1002
|
||||||
|
|
||||||
|
#define NPCM7XX_PRSTVALS_0_RESET 0x0040
|
||||||
|
#define NPCM7XX_PRSTVALS_1_RESET 0x0001
|
||||||
|
#define NPCM7XX_PRSTVALS_3_RESET 0x0001
|
||||||
|
|
||||||
|
OBJECT_DECLARE_SIMPLE_TYPE(NPCM7xxSDHCIState, NPCM7XX_SDHCI)
|
||||||
|
|
||||||
|
typedef struct NPCM7xxRegs {
|
||||||
|
/* Preset Values Register Field, read-only */
|
||||||
|
uint16_t prstvals[NPCM7XX_PRSTVALS_SIZE];
|
||||||
|
/* Boot Timeout Control Register, read-write */
|
||||||
|
uint32_t boottoctrl;
|
||||||
|
} NPCM7xxRegisters;
|
||||||
|
|
||||||
|
typedef struct NPCM7xxSDHCIState {
|
||||||
|
SysBusDevice parent;
|
||||||
|
|
||||||
|
MemoryRegion container;
|
||||||
|
MemoryRegion iomem;
|
||||||
|
BusState *bus;
|
||||||
|
NPCM7xxRegisters regs;
|
||||||
|
|
||||||
|
SDHCIState sdhci;
|
||||||
|
} NPCM7xxSDHCIState;
|
||||||
|
|
||||||
|
#endif /* NPCM7XX_SDHCI_H */
|
@ -199,6 +199,27 @@ static int vfp_gdb_set_sysreg(CPUARMState *env, uint8_t *buf, int reg)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int mve_gdb_get_reg(CPUARMState *env, GByteArray *buf, int reg)
|
||||||
|
{
|
||||||
|
switch (reg) {
|
||||||
|
case 0:
|
||||||
|
return gdb_get_reg32(buf, env->v7m.vpr);
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mve_gdb_set_reg(CPUARMState *env, uint8_t *buf, int reg)
|
||||||
|
{
|
||||||
|
switch (reg) {
|
||||||
|
case 0:
|
||||||
|
env->v7m.vpr = ldl_p(buf);
|
||||||
|
return 4;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* arm_get/set_gdb_*: get/set a gdb register
|
* arm_get/set_gdb_*: get/set a gdb register
|
||||||
* @env: the CPU state
|
* @env: the CPU state
|
||||||
@ -468,6 +489,10 @@ void arm_cpu_register_gdb_regs_for_features(ARMCPU *cpu)
|
|||||||
2, "arm-vfp-sysregs.xml", 0);
|
2, "arm-vfp-sysregs.xml", 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (cpu_isar_feature(aa32_mve, cpu)) {
|
||||||
|
gdb_register_coprocessor(cs, mve_gdb_get_reg, mve_gdb_set_reg,
|
||||||
|
1, "arm-m-profile-mve.xml", 0);
|
||||||
|
}
|
||||||
gdb_register_coprocessor(cs, arm_gdb_get_sysreg, arm_gdb_set_sysreg,
|
gdb_register_coprocessor(cs, arm_gdb_get_sysreg, arm_gdb_set_sysreg,
|
||||||
arm_gen_dynamic_sysreg_xml(cs, cs->gdb_num_regs),
|
arm_gen_dynamic_sysreg_xml(cs, cs->gdb_num_regs),
|
||||||
"system-registers.xml", 0);
|
"system-registers.xml", 0);
|
||||||
|
@ -1150,12 +1150,19 @@ int hvf_vcpu_exec(CPUState *cpu)
|
|||||||
uint32_t sas = (syndrome >> 22) & 3;
|
uint32_t sas = (syndrome >> 22) & 3;
|
||||||
uint32_t len = 1 << sas;
|
uint32_t len = 1 << sas;
|
||||||
uint32_t srt = (syndrome >> 16) & 0x1f;
|
uint32_t srt = (syndrome >> 16) & 0x1f;
|
||||||
|
uint32_t cm = (syndrome >> 8) & 0x1;
|
||||||
uint64_t val = 0;
|
uint64_t val = 0;
|
||||||
|
|
||||||
trace_hvf_data_abort(env->pc, hvf_exit->exception.virtual_address,
|
trace_hvf_data_abort(env->pc, hvf_exit->exception.virtual_address,
|
||||||
hvf_exit->exception.physical_address, isv,
|
hvf_exit->exception.physical_address, isv,
|
||||||
iswrite, s1ptw, len, srt);
|
iswrite, s1ptw, len, srt);
|
||||||
|
|
||||||
|
if (cm) {
|
||||||
|
/* We don't cache MMIO regions */
|
||||||
|
advance_pc = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
assert(isv);
|
assert(isv);
|
||||||
|
|
||||||
if (iswrite) {
|
if (iswrite) {
|
||||||
|
@ -70,6 +70,9 @@ static inline void store_cpu_offset(TCGv_i32 var, int offset)
|
|||||||
#define store_cpu_field(var, name) \
|
#define store_cpu_field(var, name) \
|
||||||
store_cpu_offset(var, offsetof(CPUARMState, name))
|
store_cpu_offset(var, offsetof(CPUARMState, name))
|
||||||
|
|
||||||
|
#define store_cpu_field_constant(val, name) \
|
||||||
|
tcg_gen_st_i32(tcg_constant_i32(val), cpu_env, offsetof(CPUARMState, name))
|
||||||
|
|
||||||
/* Create a new temporary and set it to the value of a CPU register. */
|
/* Create a new temporary and set it to the value of a CPU register. */
|
||||||
static inline TCGv_i32 load_reg(DisasContext *s, int reg)
|
static inline TCGv_i32 load_reg(DisasContext *s, int reg)
|
||||||
{
|
{
|
||||||
|
@ -1943,20 +1943,20 @@ static void do_sat_addsub_32(TCGv_i64 reg, TCGv_i64 val, bool u, bool d)
|
|||||||
static void do_sat_addsub_64(TCGv_i64 reg, TCGv_i64 val, bool u, bool d)
|
static void do_sat_addsub_64(TCGv_i64 reg, TCGv_i64 val, bool u, bool d)
|
||||||
{
|
{
|
||||||
TCGv_i64 t0 = tcg_temp_new_i64();
|
TCGv_i64 t0 = tcg_temp_new_i64();
|
||||||
TCGv_i64 t1 = tcg_temp_new_i64();
|
|
||||||
TCGv_i64 t2;
|
TCGv_i64 t2;
|
||||||
|
|
||||||
if (u) {
|
if (u) {
|
||||||
if (d) {
|
if (d) {
|
||||||
tcg_gen_sub_i64(t0, reg, val);
|
tcg_gen_sub_i64(t0, reg, val);
|
||||||
tcg_gen_movi_i64(t1, 0);
|
t2 = tcg_constant_i64(0);
|
||||||
tcg_gen_movcond_i64(TCG_COND_LTU, reg, reg, val, t1, t0);
|
tcg_gen_movcond_i64(TCG_COND_LTU, reg, reg, val, t2, t0);
|
||||||
} else {
|
} else {
|
||||||
tcg_gen_add_i64(t0, reg, val);
|
tcg_gen_add_i64(t0, reg, val);
|
||||||
tcg_gen_movi_i64(t1, -1);
|
t2 = tcg_constant_i64(-1);
|
||||||
tcg_gen_movcond_i64(TCG_COND_LTU, reg, t0, reg, t1, t0);
|
tcg_gen_movcond_i64(TCG_COND_LTU, reg, t0, reg, t2, t0);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
TCGv_i64 t1 = tcg_temp_new_i64();
|
||||||
if (d) {
|
if (d) {
|
||||||
/* Detect signed overflow for subtraction. */
|
/* Detect signed overflow for subtraction. */
|
||||||
tcg_gen_xor_i64(t0, reg, val);
|
tcg_gen_xor_i64(t0, reg, val);
|
||||||
@ -1966,7 +1966,7 @@ static void do_sat_addsub_64(TCGv_i64 reg, TCGv_i64 val, bool u, bool d)
|
|||||||
|
|
||||||
/* Bound the result. */
|
/* Bound the result. */
|
||||||
tcg_gen_movi_i64(reg, INT64_MIN);
|
tcg_gen_movi_i64(reg, INT64_MIN);
|
||||||
t2 = tcg_const_i64(0);
|
t2 = tcg_constant_i64(0);
|
||||||
tcg_gen_movcond_i64(TCG_COND_LT, reg, t0, t2, reg, t1);
|
tcg_gen_movcond_i64(TCG_COND_LT, reg, t0, t2, reg, t1);
|
||||||
} else {
|
} else {
|
||||||
/* Detect signed overflow for addition. */
|
/* Detect signed overflow for addition. */
|
||||||
@ -1977,13 +1977,12 @@ static void do_sat_addsub_64(TCGv_i64 reg, TCGv_i64 val, bool u, bool d)
|
|||||||
|
|
||||||
/* Bound the result. */
|
/* Bound the result. */
|
||||||
tcg_gen_movi_i64(t1, INT64_MAX);
|
tcg_gen_movi_i64(t1, INT64_MAX);
|
||||||
t2 = tcg_const_i64(0);
|
t2 = tcg_constant_i64(0);
|
||||||
tcg_gen_movcond_i64(TCG_COND_LT, reg, t0, t2, t1, reg);
|
tcg_gen_movcond_i64(TCG_COND_LT, reg, t0, t2, t1, reg);
|
||||||
}
|
}
|
||||||
tcg_temp_free_i64(t2);
|
tcg_temp_free_i64(t1);
|
||||||
}
|
}
|
||||||
tcg_temp_free_i64(t0);
|
tcg_temp_free_i64(t0);
|
||||||
tcg_temp_free_i64(t1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Similarly with a vector and a scalar operand. */
|
/* Similarly with a vector and a scalar operand. */
|
||||||
|
@ -364,8 +364,7 @@ void clear_eci_state(DisasContext *s)
|
|||||||
* multiple insn executes.
|
* multiple insn executes.
|
||||||
*/
|
*/
|
||||||
if (s->eci) {
|
if (s->eci) {
|
||||||
TCGv_i32 tmp = tcg_const_i32(0);
|
store_cpu_field_constant(0, condexec_bits);
|
||||||
store_cpu_field(tmp, condexec_bits);
|
|
||||||
s->eci = 0;
|
s->eci = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -389,13 +388,12 @@ static void gen_smul_dual(TCGv_i32 a, TCGv_i32 b)
|
|||||||
void gen_rev16(TCGv_i32 dest, TCGv_i32 var)
|
void gen_rev16(TCGv_i32 dest, TCGv_i32 var)
|
||||||
{
|
{
|
||||||
TCGv_i32 tmp = tcg_temp_new_i32();
|
TCGv_i32 tmp = tcg_temp_new_i32();
|
||||||
TCGv_i32 mask = tcg_const_i32(0x00ff00ff);
|
TCGv_i32 mask = tcg_constant_i32(0x00ff00ff);
|
||||||
tcg_gen_shri_i32(tmp, var, 8);
|
tcg_gen_shri_i32(tmp, var, 8);
|
||||||
tcg_gen_and_i32(tmp, tmp, mask);
|
tcg_gen_and_i32(tmp, tmp, mask);
|
||||||
tcg_gen_and_i32(var, var, mask);
|
tcg_gen_and_i32(var, var, mask);
|
||||||
tcg_gen_shli_i32(var, var, 8);
|
tcg_gen_shli_i32(var, var, 8);
|
||||||
tcg_gen_or_i32(dest, var, tmp);
|
tcg_gen_or_i32(dest, var, tmp);
|
||||||
tcg_temp_free_i32(mask);
|
|
||||||
tcg_temp_free_i32(tmp);
|
tcg_temp_free_i32(tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -740,9 +738,8 @@ void gen_set_condexec(DisasContext *s)
|
|||||||
{
|
{
|
||||||
if (s->condexec_mask) {
|
if (s->condexec_mask) {
|
||||||
uint32_t val = (s->condexec_cond << 4) | (s->condexec_mask >> 1);
|
uint32_t val = (s->condexec_cond << 4) | (s->condexec_mask >> 1);
|
||||||
TCGv_i32 tmp = tcg_temp_new_i32();
|
|
||||||
tcg_gen_movi_i32(tmp, val);
|
store_cpu_field_constant(val, condexec_bits);
|
||||||
store_cpu_field(tmp, condexec_bits);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -7849,10 +7846,9 @@ static bool op_smlad(DisasContext *s, arg_rrrr *a, bool m_swap, bool sub)
|
|||||||
t3 = tcg_temp_new_i32();
|
t3 = tcg_temp_new_i32();
|
||||||
tcg_gen_sari_i32(t3, t1, 31);
|
tcg_gen_sari_i32(t3, t1, 31);
|
||||||
qf = load_cpu_field(QF);
|
qf = load_cpu_field(QF);
|
||||||
one = tcg_const_i32(1);
|
one = tcg_constant_i32(1);
|
||||||
tcg_gen_movcond_i32(TCG_COND_NE, qf, t2, t3, one, qf);
|
tcg_gen_movcond_i32(TCG_COND_NE, qf, t2, t3, one, qf);
|
||||||
store_cpu_field(qf, QF);
|
store_cpu_field(qf, QF);
|
||||||
tcg_temp_free_i32(one);
|
|
||||||
tcg_temp_free_i32(t3);
|
tcg_temp_free_i32(t3);
|
||||||
tcg_temp_free_i32(t2);
|
tcg_temp_free_i32(t2);
|
||||||
}
|
}
|
||||||
@ -8363,8 +8359,6 @@ static bool trans_BL(DisasContext *s, arg_i *a)
|
|||||||
|
|
||||||
static bool trans_BLX_i(DisasContext *s, arg_BLX_i *a)
|
static bool trans_BLX_i(DisasContext *s, arg_BLX_i *a)
|
||||||
{
|
{
|
||||||
TCGv_i32 tmp;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* BLX <imm> would be useless on M-profile; the encoding space
|
* BLX <imm> would be useless on M-profile; the encoding space
|
||||||
* is used for other insns from v8.1M onward, and UNDEFs before that.
|
* is used for other insns from v8.1M onward, and UNDEFs before that.
|
||||||
@ -8378,8 +8372,7 @@ static bool trans_BLX_i(DisasContext *s, arg_BLX_i *a)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
tcg_gen_movi_i32(cpu_R[14], s->base.pc_next | s->thumb);
|
tcg_gen_movi_i32(cpu_R[14], s->base.pc_next | s->thumb);
|
||||||
tmp = tcg_const_i32(!s->thumb);
|
store_cpu_field_constant(!s->thumb, thumb);
|
||||||
store_cpu_field(tmp, thumb);
|
|
||||||
gen_jmp(s, (read_pc(s) & ~3) + a->imm);
|
gen_jmp(s, (read_pc(s) & ~3) + a->imm);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -8678,7 +8671,6 @@ static bool trans_LCTP(DisasContext *s, arg_LCTP *a)
|
|||||||
* doesn't cache branch information, all we need to do is reset
|
* doesn't cache branch information, all we need to do is reset
|
||||||
* FPSCR.LTPSIZE to 4.
|
* FPSCR.LTPSIZE to 4.
|
||||||
*/
|
*/
|
||||||
TCGv_i32 ltpsize;
|
|
||||||
|
|
||||||
if (!dc_isar_feature(aa32_lob, s) ||
|
if (!dc_isar_feature(aa32_lob, s) ||
|
||||||
!dc_isar_feature(aa32_mve, s)) {
|
!dc_isar_feature(aa32_mve, s)) {
|
||||||
@ -8689,8 +8681,7 @@ static bool trans_LCTP(DisasContext *s, arg_LCTP *a)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
ltpsize = tcg_const_i32(4);
|
store_cpu_field_constant(4, v7m.ltpsize);
|
||||||
store_cpu_field(ltpsize, v7m.ltpsize);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -9488,9 +9479,7 @@ static void arm_tr_tb_start(DisasContextBase *dcbase, CPUState *cpu)
|
|||||||
/* Reset the conditional execution bits immediately. This avoids
|
/* Reset the conditional execution bits immediately. This avoids
|
||||||
complications trying to do it at the end of the block. */
|
complications trying to do it at the end of the block. */
|
||||||
if (dc->condexec_mask || dc->condexec_cond) {
|
if (dc->condexec_mask || dc->condexec_cond) {
|
||||||
TCGv_i32 tmp = tcg_temp_new_i32();
|
store_cpu_field_constant(0, condexec_bits);
|
||||||
tcg_gen_movi_i32(tmp, 0);
|
|
||||||
store_cpu_field(tmp, condexec_bits);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ libqos_srcs = files('../libqtest.c',
|
|||||||
'fw_cfg.c',
|
'fw_cfg.c',
|
||||||
'malloc.c',
|
'malloc.c',
|
||||||
'libqos.c',
|
'libqos.c',
|
||||||
|
'sdhci-cmd.c',
|
||||||
|
|
||||||
# spapr
|
# spapr
|
||||||
'malloc-spapr.c',
|
'malloc-spapr.c',
|
||||||
|
116
tests/qtest/libqos/sdhci-cmd.c
Normal file
116
tests/qtest/libqos/sdhci-cmd.c
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
/*
|
||||||
|
* MMC Host Controller Commands
|
||||||
|
*
|
||||||
|
* Copyright (c) 2021 Google LLC
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "qemu/osdep.h"
|
||||||
|
#include "sdhci-cmd.h"
|
||||||
|
#include "libqtest.h"
|
||||||
|
|
||||||
|
static ssize_t read_fifo(QTestState *qts, uint64_t reg, char *msg, size_t count)
|
||||||
|
{
|
||||||
|
uint32_t mask = 0xff;
|
||||||
|
size_t index = 0;
|
||||||
|
uint32_t msg_frag;
|
||||||
|
int size;
|
||||||
|
while (index < count) {
|
||||||
|
size = count - index;
|
||||||
|
if (size > 4) {
|
||||||
|
size = 4;
|
||||||
|
}
|
||||||
|
msg_frag = qtest_readl(qts, reg);
|
||||||
|
while (size > 0) {
|
||||||
|
msg[index] = msg_frag & mask;
|
||||||
|
if (msg[index++] == 0) {
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
msg_frag >>= 8;
|
||||||
|
--size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void write_fifo(QTestState *qts, uint64_t reg, const char *msg,
|
||||||
|
size_t count)
|
||||||
|
{
|
||||||
|
size_t index = 0;
|
||||||
|
uint32_t msg_frag;
|
||||||
|
int size;
|
||||||
|
int frag_i;
|
||||||
|
while (index < count) {
|
||||||
|
size = count - index;
|
||||||
|
if (size > 4) {
|
||||||
|
size = 4;
|
||||||
|
}
|
||||||
|
msg_frag = 0;
|
||||||
|
frag_i = 0;
|
||||||
|
while (frag_i < size) {
|
||||||
|
msg_frag |= ((uint32_t)msg[index++]) << (frag_i * 8);
|
||||||
|
++frag_i;
|
||||||
|
}
|
||||||
|
qtest_writel(qts, reg, msg_frag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fill_block(QTestState *qts, uint64_t reg, int count)
|
||||||
|
{
|
||||||
|
while (--count >= 0) {
|
||||||
|
qtest_writel(qts, reg, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void sdhci_cmd_regs(QTestState *qts, uint64_t base_addr, uint16_t blksize,
|
||||||
|
uint16_t blkcnt, uint32_t argument, uint16_t trnmod,
|
||||||
|
uint16_t cmdreg)
|
||||||
|
{
|
||||||
|
qtest_writew(qts, base_addr + SDHC_BLKSIZE, blksize);
|
||||||
|
qtest_writew(qts, base_addr + SDHC_BLKCNT, blkcnt);
|
||||||
|
qtest_writel(qts, base_addr + SDHC_ARGUMENT, argument);
|
||||||
|
qtest_writew(qts, base_addr + SDHC_TRNMOD, trnmod);
|
||||||
|
qtest_writew(qts, base_addr + SDHC_CMDREG, cmdreg);
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t sdhci_read_cmd(QTestState *qts, uint64_t base_addr, char *msg,
|
||||||
|
size_t count)
|
||||||
|
{
|
||||||
|
sdhci_cmd_regs(qts, base_addr, count, 1, 0,
|
||||||
|
SDHC_TRNS_MULTI | SDHC_TRNS_READ | SDHC_TRNS_BLK_CNT_EN,
|
||||||
|
SDHC_READ_MULTIPLE_BLOCK | SDHC_CMD_DATA_PRESENT);
|
||||||
|
|
||||||
|
/* read sd fifo_buffer */
|
||||||
|
ssize_t bytes_read = read_fifo(qts, base_addr + SDHC_BDATA, msg, count);
|
||||||
|
|
||||||
|
sdhci_cmd_regs(qts, base_addr, 0, 0, 0,
|
||||||
|
SDHC_TRNS_MULTI | SDHC_TRNS_READ | SDHC_TRNS_BLK_CNT_EN,
|
||||||
|
SDHC_STOP_TRANSMISSION);
|
||||||
|
|
||||||
|
return bytes_read;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sdhci_write_cmd(QTestState *qts, uint64_t base_addr, const char *msg,
|
||||||
|
size_t count, size_t blksize)
|
||||||
|
{
|
||||||
|
sdhci_cmd_regs(qts, base_addr, blksize, 1, 0,
|
||||||
|
SDHC_TRNS_MULTI | SDHC_TRNS_WRITE | SDHC_TRNS_BLK_CNT_EN,
|
||||||
|
SDHC_WRITE_MULTIPLE_BLOCK | SDHC_CMD_DATA_PRESENT);
|
||||||
|
|
||||||
|
/* write to sd fifo_buffer */
|
||||||
|
write_fifo(qts, base_addr + SDHC_BDATA, msg, count);
|
||||||
|
fill_block(qts, base_addr + SDHC_BDATA, (blksize - count) / 4);
|
||||||
|
|
||||||
|
sdhci_cmd_regs(qts, base_addr, 0, 0, 0,
|
||||||
|
SDHC_TRNS_MULTI | SDHC_TRNS_WRITE | SDHC_TRNS_BLK_CNT_EN,
|
||||||
|
SDHC_STOP_TRANSMISSION);
|
||||||
|
}
|
70
tests/qtest/libqos/sdhci-cmd.h
Normal file
70
tests/qtest/libqos/sdhci-cmd.h
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
/*
|
||||||
|
* MMC Host Controller Commands
|
||||||
|
*
|
||||||
|
* Copyright (c) 2021 Google LLC
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "libqtest.h"
|
||||||
|
|
||||||
|
/* more details at hw/sd/sdhci-internal.h */
|
||||||
|
#define SDHC_BLKSIZE 0x04
|
||||||
|
#define SDHC_BLKCNT 0x06
|
||||||
|
#define SDHC_ARGUMENT 0x08
|
||||||
|
#define SDHC_TRNMOD 0x0C
|
||||||
|
#define SDHC_CMDREG 0x0E
|
||||||
|
#define SDHC_BDATA 0x20
|
||||||
|
#define SDHC_PRNSTS 0x24
|
||||||
|
#define SDHC_BLKGAP 0x2A
|
||||||
|
#define SDHC_CLKCON 0x2C
|
||||||
|
#define SDHC_SWRST 0x2F
|
||||||
|
#define SDHC_CAPAB 0x40
|
||||||
|
#define SDHC_MAXCURR 0x48
|
||||||
|
#define SDHC_HCVER 0xFE
|
||||||
|
|
||||||
|
/* TRNSMOD Reg */
|
||||||
|
#define SDHC_TRNS_BLK_CNT_EN 0x0002
|
||||||
|
#define SDHC_TRNS_READ 0x0010
|
||||||
|
#define SDHC_TRNS_WRITE 0x0000
|
||||||
|
#define SDHC_TRNS_MULTI 0x0020
|
||||||
|
|
||||||
|
/* CMD Reg */
|
||||||
|
#define SDHC_CMD_DATA_PRESENT (1 << 5)
|
||||||
|
#define SDHC_ALL_SEND_CID (2 << 8)
|
||||||
|
#define SDHC_SEND_RELATIVE_ADDR (3 << 8)
|
||||||
|
#define SDHC_SELECT_DESELECT_CARD (7 << 8)
|
||||||
|
#define SDHC_SEND_CSD (9 << 8)
|
||||||
|
#define SDHC_STOP_TRANSMISSION (12 << 8)
|
||||||
|
#define SDHC_READ_MULTIPLE_BLOCK (18 << 8)
|
||||||
|
#define SDHC_WRITE_MULTIPLE_BLOCK (25 << 8)
|
||||||
|
#define SDHC_APP_CMD (55 << 8)
|
||||||
|
|
||||||
|
/* SWRST Reg */
|
||||||
|
#define SDHC_RESET_ALL 0x01
|
||||||
|
|
||||||
|
/* CLKCTRL Reg */
|
||||||
|
#define SDHC_CLOCK_INT_EN 0x0001
|
||||||
|
#define SDHC_CLOCK_INT_STABLE 0x0002
|
||||||
|
#define SDHC_CLOCK_SDCLK_EN (1 << 2)
|
||||||
|
|
||||||
|
/* Set registers needed to send commands to SD */
|
||||||
|
void sdhci_cmd_regs(QTestState *qts, uint64_t base_addr, uint16_t blksize,
|
||||||
|
uint16_t blkcnt, uint32_t argument, uint16_t trnmod,
|
||||||
|
uint16_t cmdreg);
|
||||||
|
|
||||||
|
/* Read at most 1 block of SD using non-DMA */
|
||||||
|
ssize_t sdhci_read_cmd(QTestState *qts, uint64_t base_addr, char *msg,
|
||||||
|
size_t count);
|
||||||
|
|
||||||
|
/* Write at most 1 block of SD using non-DMA */
|
||||||
|
void sdhci_write_cmd(QTestState *qts, uint64_t base_addr, const char *msg,
|
||||||
|
size_t count, size_t blksize);
|
Loading…
Reference in New Issue
Block a user