target-arm queue:
* support virtualization in GICv3 * enable EL2 in AArch64 CPU models * allow EL2 to be enabled on 'virt' board via -machine virtualization=on * aspeed: SMC improvements * m25p80: support die erase command * m25p80: Add Quad Page Program 4byte * m25p80: Improve 1GiB Micron flash definition * arm: Uniquely name imx25 I2C buses -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABCAAGBQJYgfUpAAoJEDwlJe0UNgzedVIQAIr4GhCIhReTTtTNeAMPcFNR dt+rltEAOjZwSsfL1aSsVxHMAyjtNHl69DZyIDknuBCjjU6LjewGDq5NocgGXG8e 243h+br7OzHiwfnYZlbzolxmDQYArCde/QQmt2K6dqiYeezkHJX6FfrGEMnxgGKc bUAy6HNzQYhm3idESiSN+Oc0DNIZbX73Ct9FmAQo9t2ce+gGKrqZgp7ky2U992bv e8ZsgB9v96xaV20LvuIB0WpPakfD2KvaddE5TMsLBVdF9aw5J2F/nBVl7yXFRips /+4d9xj4yodfZBUHFs9CmGIFIuDNtTDrmqn8pkRgUqOQONW76STpJx+dyFYX83bx NyoR2v+rZ26VE0KwcerhM1mScJVxlYf+W6HIsck+rIc3D3m5RKeuNPubLWYRyWpI OKK+gDsjQLiYPs2sNeDv9tTZLQUkxoOhCGU1bWtUJ+i/uFNMC5KKIj7dxpyaeZoZ 0hC/JnORVQudsvpWXzCZVr8hWI1VT9gmYfOfwwn5c2Z9+yuHwmyLvdZnuIvaoBBb DM4vLXAjUp5HGXGlBx2qHgQnHH2HrY0EVGTGodS4QyhQGKyIvRdiaBm56Bg34qDy hke4Hd7HdH08bIDeTLkp3w0rVNCKx/px8ZanvM7U2/QJYE45LjssF/y2xg4mD7JQ uUfG7IKh1DgwVfPwsXy4 =OSbX -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20170120' into staging target-arm queue: * support virtualization in GICv3 * enable EL2 in AArch64 CPU models * allow EL2 to be enabled on 'virt' board via -machine virtualization=on * aspeed: SMC improvements * m25p80: support die erase command * m25p80: Add Quad Page Program 4byte * m25p80: Improve 1GiB Micron flash definition * arm: Uniquely name imx25 I2C buses # gpg: Signature made Fri 20 Jan 2017 11:31:53 GMT # gpg: using RSA key 0x3C2525ED14360CDE # gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" # gpg: aka "Peter Maydell <pmaydell@gmail.com>" # gpg: aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>" # Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83 15CF 3C25 25ED 1436 0CDE * remotes/pmaydell/tags/pull-target-arm-20170120: (36 commits) hw/arm/virt: Add board property to enable EL2 target-arm: Enable EL2 feature bit on A53 and A57 target/arm/psci.c: If EL2 implemented, start CPUs in EL2 hw/arm/virt-acpi-build: use SMC if booting in EL2 hw/arm/virt: Support using SMC for PSCI hw/intc/arm_gicv3: Implement EL2 traps for CPU i/f regs hw/intc/arm_gicv3: Implement gicv3_cpuif_virt_update() hw/intc/arm_gicv3: Implement ICV_ registers EOIR and IAR hw/intc/arm_gicv3: Implement ICV_ HPPIR, DIR and RPR registers hw/intc/arm_gicv3: Implement ICV_ registers which are just accessors hw/intc/arm_gicv3: Add accessors for ICH_ system registers hw/intc/gicv3: Add data fields for virtualization support hw/intc/gicv3: Add defines for ICH system register fields target-arm: Add ARMCPU fields for GIC CPU i/f config hw/arm/virt: Wire VIRQ, VFIQ, maintenance irq lines from GIC to CPU target-arm: Expose output GPIO line for VCPU maintenance interrupt hw/intc/arm_gic: Add external IRQ lines for VIRQ and VFIQ hw/intc/arm_gicv3: Add external IRQ lines for VIRQ and VFIQ hw/arm/virt-acpi - reserve ECAM space as PNP0C02 device arm: virt: Fix segmentation fault when specifying an unsupported CPU ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
28f5e970a6
@ -20,6 +20,8 @@
|
|||||||
#include "qemu/log.h"
|
#include "qemu/log.h"
|
||||||
#include "sysemu/block-backend.h"
|
#include "sysemu/block-backend.h"
|
||||||
#include "sysemu/blockdev.h"
|
#include "sysemu/blockdev.h"
|
||||||
|
#include "hw/loader.h"
|
||||||
|
#include "qemu/error-report.h"
|
||||||
|
|
||||||
static struct arm_boot_info aspeed_board_binfo = {
|
static struct arm_boot_info aspeed_board_binfo = {
|
||||||
.board_id = -1, /* device-tree-only board */
|
.board_id = -1, /* device-tree-only board */
|
||||||
@ -104,6 +106,28 @@ static const AspeedBoardConfig aspeed_boards[] = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define FIRMWARE_ADDR 0x0
|
||||||
|
|
||||||
|
static void write_boot_rom(DriveInfo *dinfo, hwaddr addr, size_t rom_size,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
BlockBackend *blk = blk_by_legacy_dinfo(dinfo);
|
||||||
|
uint8_t *storage;
|
||||||
|
|
||||||
|
if (rom_size > blk_getlength(blk)) {
|
||||||
|
rom_size = blk_getlength(blk);
|
||||||
|
}
|
||||||
|
|
||||||
|
storage = g_new0(uint8_t, rom_size);
|
||||||
|
if (blk_pread(blk, 0, storage, rom_size) < 0) {
|
||||||
|
error_setg(errp, "failed to read the initial flash content");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
rom_add_blob_fixed("aspeed.boot_rom", storage, rom_size, addr);
|
||||||
|
g_free(storage);
|
||||||
|
}
|
||||||
|
|
||||||
static void aspeed_board_init_flashes(AspeedSMCState *s, const char *flashtype,
|
static void aspeed_board_init_flashes(AspeedSMCState *s, const char *flashtype,
|
||||||
Error **errp)
|
Error **errp)
|
||||||
{
|
{
|
||||||
@ -135,6 +159,7 @@ static void aspeed_board_init(MachineState *machine,
|
|||||||
{
|
{
|
||||||
AspeedBoardState *bmc;
|
AspeedBoardState *bmc;
|
||||||
AspeedSoCClass *sc;
|
AspeedSoCClass *sc;
|
||||||
|
DriveInfo *drive0 = drive_get(IF_MTD, 0, 0);
|
||||||
|
|
||||||
bmc = g_new0(AspeedBoardState, 1);
|
bmc = g_new0(AspeedBoardState, 1);
|
||||||
object_initialize(&bmc->soc, (sizeof(bmc->soc)), cfg->soc_name);
|
object_initialize(&bmc->soc, (sizeof(bmc->soc)), cfg->soc_name);
|
||||||
@ -168,6 +193,22 @@ static void aspeed_board_init(MachineState *machine,
|
|||||||
aspeed_board_init_flashes(&bmc->soc.fmc, cfg->fmc_model, &error_abort);
|
aspeed_board_init_flashes(&bmc->soc.fmc, cfg->fmc_model, &error_abort);
|
||||||
aspeed_board_init_flashes(&bmc->soc.spi[0], cfg->spi_model, &error_abort);
|
aspeed_board_init_flashes(&bmc->soc.spi[0], cfg->spi_model, &error_abort);
|
||||||
|
|
||||||
|
/* Install first FMC flash content as a boot rom. */
|
||||||
|
if (drive0) {
|
||||||
|
AspeedSMCFlash *fl = &bmc->soc.fmc.flashes[0];
|
||||||
|
MemoryRegion *boot_rom = g_new(MemoryRegion, 1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* create a ROM region using the default mapping window size of
|
||||||
|
* the flash module.
|
||||||
|
*/
|
||||||
|
memory_region_init_rom(boot_rom, OBJECT(bmc), "aspeed.boot_rom",
|
||||||
|
fl->size, &error_abort);
|
||||||
|
memory_region_add_subregion(get_system_memory(), FIRMWARE_ADDR,
|
||||||
|
boot_rom);
|
||||||
|
write_boot_rom(drive0, FIRMWARE_ADDR, fl->size, &error_abort);
|
||||||
|
}
|
||||||
|
|
||||||
aspeed_board_binfo.kernel_filename = machine->kernel_filename;
|
aspeed_board_binfo.kernel_filename = machine->kernel_filename;
|
||||||
aspeed_board_binfo.initrd_filename = machine->initrd_filename;
|
aspeed_board_binfo.initrd_filename = machine->initrd_filename;
|
||||||
aspeed_board_binfo.kernel_cmdline = machine->kernel_cmdline;
|
aspeed_board_binfo.kernel_cmdline = machine->kernel_cmdline;
|
||||||
|
@ -139,7 +139,7 @@ static void imx25_pdk_init(MachineState *machine)
|
|||||||
* of simple qtest. See "make check" for details.
|
* of simple qtest. See "make check" for details.
|
||||||
*/
|
*/
|
||||||
i2c_create_slave((I2CBus *)qdev_get_child_bus(DEVICE(&s->soc.i2c[0]),
|
i2c_create_slave((I2CBus *)qdev_get_child_bus(DEVICE(&s->soc.i2c[0]),
|
||||||
"i2c"),
|
"i2c-bus.0"),
|
||||||
"ds1338", 0x68);
|
"ds1338", 0x68);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -310,6 +310,13 @@ static void acpi_dsdt_add_pci(Aml *scope, const MemMapEntry *memmap,
|
|||||||
Aml *dev_rp0 = aml_device("%s", "RP0");
|
Aml *dev_rp0 = aml_device("%s", "RP0");
|
||||||
aml_append(dev_rp0, aml_name_decl("_ADR", aml_int(0)));
|
aml_append(dev_rp0, aml_name_decl("_ADR", aml_int(0)));
|
||||||
aml_append(dev, dev_rp0);
|
aml_append(dev, dev_rp0);
|
||||||
|
|
||||||
|
Aml *dev_res0 = aml_device("%s", "RES0");
|
||||||
|
aml_append(dev_res0, aml_name_decl("_HID", aml_string("PNP0C02")));
|
||||||
|
crs = aml_resource_template();
|
||||||
|
aml_append(crs, aml_memory32_fixed(base_ecam, size_ecam, AML_READ_WRITE));
|
||||||
|
aml_append(dev_res0, aml_name_decl("_CRS", crs));
|
||||||
|
aml_append(dev, dev_res0);
|
||||||
aml_append(scope, dev);
|
aml_append(scope, dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -607,6 +614,9 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
|
|||||||
if (arm_feature(&armcpu->env, ARM_FEATURE_PMU)) {
|
if (arm_feature(&armcpu->env, ARM_FEATURE_PMU)) {
|
||||||
gicc->performance_interrupt = cpu_to_le32(PPI(VIRTUAL_PMU_IRQ));
|
gicc->performance_interrupt = cpu_to_le32(PPI(VIRTUAL_PMU_IRQ));
|
||||||
}
|
}
|
||||||
|
if (vms->virt && vms->gic_version == 3) {
|
||||||
|
gicc->vgic_interrupt = cpu_to_le32(PPI(ARCH_GICV3_MAINT_IRQ));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vms->gic_version == 3) {
|
if (vms->gic_version == 3) {
|
||||||
@ -643,16 +653,30 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* FADT */
|
/* FADT */
|
||||||
static void
|
static void build_fadt(GArray *table_data, BIOSLinker *linker,
|
||||||
build_fadt(GArray *table_data, BIOSLinker *linker, unsigned dsdt_tbl_offset)
|
VirtMachineState *vms, unsigned dsdt_tbl_offset)
|
||||||
{
|
{
|
||||||
AcpiFadtDescriptorRev5_1 *fadt = acpi_data_push(table_data, sizeof(*fadt));
|
AcpiFadtDescriptorRev5_1 *fadt = acpi_data_push(table_data, sizeof(*fadt));
|
||||||
unsigned dsdt_entry_offset = (char *)&fadt->dsdt - table_data->data;
|
unsigned dsdt_entry_offset = (char *)&fadt->dsdt - table_data->data;
|
||||||
|
uint16_t bootflags;
|
||||||
|
|
||||||
/* Hardware Reduced = 1 and use PSCI 0.2+ and with HVC */
|
switch (vms->psci_conduit) {
|
||||||
|
case QEMU_PSCI_CONDUIT_DISABLED:
|
||||||
|
bootflags = 0;
|
||||||
|
break;
|
||||||
|
case QEMU_PSCI_CONDUIT_HVC:
|
||||||
|
bootflags = ACPI_FADT_ARM_PSCI_COMPLIANT | ACPI_FADT_ARM_PSCI_USE_HVC;
|
||||||
|
break;
|
||||||
|
case QEMU_PSCI_CONDUIT_SMC:
|
||||||
|
bootflags = ACPI_FADT_ARM_PSCI_COMPLIANT;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
g_assert_not_reached();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hardware Reduced = 1 and use PSCI 0.2+ */
|
||||||
fadt->flags = cpu_to_le32(1 << ACPI_FADT_F_HW_REDUCED_ACPI);
|
fadt->flags = cpu_to_le32(1 << ACPI_FADT_F_HW_REDUCED_ACPI);
|
||||||
fadt->arm_boot_flags = cpu_to_le16(ACPI_FADT_ARM_PSCI_COMPLIANT |
|
fadt->arm_boot_flags = cpu_to_le16(bootflags);
|
||||||
ACPI_FADT_ARM_PSCI_USE_HVC);
|
|
||||||
|
|
||||||
/* ACPI v5.1 (fadt->revision.fadt->minor_revision) */
|
/* ACPI v5.1 (fadt->revision.fadt->minor_revision) */
|
||||||
fadt->minor_revision = 0x1;
|
fadt->minor_revision = 0x1;
|
||||||
@ -738,7 +762,7 @@ void virt_acpi_build(VirtMachineState *vms, AcpiBuildTables *tables)
|
|||||||
|
|
||||||
/* FADT MADT GTDT MCFG SPCR pointed to by RSDT */
|
/* FADT MADT GTDT MCFG SPCR pointed to by RSDT */
|
||||||
acpi_add_table(table_offsets, tables_blob);
|
acpi_add_table(table_offsets, tables_blob);
|
||||||
build_fadt(tables_blob, tables->linker, dsdt);
|
build_fadt(tables_blob, tables->linker, vms, dsdt);
|
||||||
|
|
||||||
acpi_add_table(table_offsets, tables_blob);
|
acpi_add_table(table_offsets, tables_blob);
|
||||||
build_madt(tables_blob, tables->linker, vms);
|
build_madt(tables_blob, tables->linker, vms);
|
||||||
|
@ -167,7 +167,6 @@ static const char *valid_cpus[] = {
|
|||||||
"cortex-a53",
|
"cortex-a53",
|
||||||
"cortex-a57",
|
"cortex-a57",
|
||||||
"host",
|
"host",
|
||||||
NULL
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool cpuname_valid(const char *cpu)
|
static bool cpuname_valid(const char *cpu)
|
||||||
@ -230,9 +229,19 @@ static void fdt_add_psci_node(const VirtMachineState *vms)
|
|||||||
uint32_t migrate_fn;
|
uint32_t migrate_fn;
|
||||||
void *fdt = vms->fdt;
|
void *fdt = vms->fdt;
|
||||||
ARMCPU *armcpu = ARM_CPU(qemu_get_cpu(0));
|
ARMCPU *armcpu = ARM_CPU(qemu_get_cpu(0));
|
||||||
|
const char *psci_method;
|
||||||
|
|
||||||
if (!vms->using_psci) {
|
switch (vms->psci_conduit) {
|
||||||
|
case QEMU_PSCI_CONDUIT_DISABLED:
|
||||||
return;
|
return;
|
||||||
|
case QEMU_PSCI_CONDUIT_HVC:
|
||||||
|
psci_method = "hvc";
|
||||||
|
break;
|
||||||
|
case QEMU_PSCI_CONDUIT_SMC:
|
||||||
|
psci_method = "smc";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
g_assert_not_reached();
|
||||||
}
|
}
|
||||||
|
|
||||||
qemu_fdt_add_subnode(fdt, "/psci");
|
qemu_fdt_add_subnode(fdt, "/psci");
|
||||||
@ -264,7 +273,7 @@ static void fdt_add_psci_node(const VirtMachineState *vms)
|
|||||||
* However, the device tree binding uses 'method' instead, so that is
|
* However, the device tree binding uses 'method' instead, so that is
|
||||||
* what we should use here.
|
* what we should use here.
|
||||||
*/
|
*/
|
||||||
qemu_fdt_setprop_string(fdt, "/psci", "method", "hvc");
|
qemu_fdt_setprop_string(fdt, "/psci", "method", psci_method);
|
||||||
|
|
||||||
qemu_fdt_setprop_cell(fdt, "/psci", "cpu_suspend", cpu_suspend_fn);
|
qemu_fdt_setprop_cell(fdt, "/psci", "cpu_suspend", cpu_suspend_fn);
|
||||||
qemu_fdt_setprop_cell(fdt, "/psci", "cpu_off", cpu_off_fn);
|
qemu_fdt_setprop_cell(fdt, "/psci", "cpu_off", cpu_off_fn);
|
||||||
@ -366,7 +375,8 @@ static void fdt_add_cpu_nodes(const VirtMachineState *vms)
|
|||||||
qemu_fdt_setprop_string(vms->fdt, nodename, "compatible",
|
qemu_fdt_setprop_string(vms->fdt, nodename, "compatible",
|
||||||
armcpu->dtb_compatible);
|
armcpu->dtb_compatible);
|
||||||
|
|
||||||
if (vms->using_psci && vms->smp_cpus > 1) {
|
if (vms->psci_conduit != QEMU_PSCI_CONDUIT_DISABLED
|
||||||
|
&& vms->smp_cpus > 1) {
|
||||||
qemu_fdt_setprop_string(vms->fdt, nodename,
|
qemu_fdt_setprop_string(vms->fdt, nodename,
|
||||||
"enable-method", "psci");
|
"enable-method", "psci");
|
||||||
}
|
}
|
||||||
@ -433,6 +443,11 @@ static void fdt_add_gic_node(VirtMachineState *vms)
|
|||||||
2, vms->memmap[VIRT_GIC_DIST].size,
|
2, vms->memmap[VIRT_GIC_DIST].size,
|
||||||
2, vms->memmap[VIRT_GIC_REDIST].base,
|
2, vms->memmap[VIRT_GIC_REDIST].base,
|
||||||
2, vms->memmap[VIRT_GIC_REDIST].size);
|
2, vms->memmap[VIRT_GIC_REDIST].size);
|
||||||
|
if (vms->virt) {
|
||||||
|
qemu_fdt_setprop_cells(vms->fdt, "/intc", "interrupts",
|
||||||
|
GIC_FDT_IRQ_TYPE_PPI, ARCH_GICV3_MAINT_IRQ,
|
||||||
|
GIC_FDT_IRQ_FLAGS_LEVEL_HI);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
/* 'cortex-a15-gic' means 'GIC v2' */
|
/* 'cortex-a15-gic' means 'GIC v2' */
|
||||||
qemu_fdt_setprop_string(vms->fdt, "/intc", "compatible",
|
qemu_fdt_setprop_string(vms->fdt, "/intc", "compatible",
|
||||||
@ -547,9 +562,9 @@ static void create_gic(VirtMachineState *vms, qemu_irq *pic)
|
|||||||
sysbus_mmio_map(gicbusdev, 1, vms->memmap[VIRT_GIC_CPU].base);
|
sysbus_mmio_map(gicbusdev, 1, vms->memmap[VIRT_GIC_CPU].base);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Wire the outputs from each CPU's generic timer to the
|
/* Wire the outputs from each CPU's generic timer and the GICv3
|
||||||
* appropriate GIC PPI inputs, and the GIC's IRQ output to
|
* maintenance interrupt signal to the appropriate GIC PPI inputs,
|
||||||
* the CPU's IRQ input.
|
* and the GIC's IRQ/FIQ/VIRQ/VFIQ interrupt outputs to the CPU's inputs.
|
||||||
*/
|
*/
|
||||||
for (i = 0; i < smp_cpus; i++) {
|
for (i = 0; i < smp_cpus; i++) {
|
||||||
DeviceState *cpudev = DEVICE(qemu_get_cpu(i));
|
DeviceState *cpudev = DEVICE(qemu_get_cpu(i));
|
||||||
@ -571,9 +586,17 @@ static void create_gic(VirtMachineState *vms, qemu_irq *pic)
|
|||||||
ppibase + timer_irq[irq]));
|
ppibase + timer_irq[irq]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
qdev_connect_gpio_out_named(cpudev, "gicv3-maintenance-interrupt", 0,
|
||||||
|
qdev_get_gpio_in(gicdev, ppibase
|
||||||
|
+ ARCH_GICV3_MAINT_IRQ));
|
||||||
|
|
||||||
sysbus_connect_irq(gicbusdev, i, qdev_get_gpio_in(cpudev, ARM_CPU_IRQ));
|
sysbus_connect_irq(gicbusdev, i, qdev_get_gpio_in(cpudev, ARM_CPU_IRQ));
|
||||||
sysbus_connect_irq(gicbusdev, i + smp_cpus,
|
sysbus_connect_irq(gicbusdev, i + smp_cpus,
|
||||||
qdev_get_gpio_in(cpudev, ARM_CPU_FIQ));
|
qdev_get_gpio_in(cpudev, ARM_CPU_FIQ));
|
||||||
|
sysbus_connect_irq(gicbusdev, i + 2 * smp_cpus,
|
||||||
|
qdev_get_gpio_in(cpudev, ARM_CPU_VIRQ));
|
||||||
|
sysbus_connect_irq(gicbusdev, i + 3 * smp_cpus,
|
||||||
|
qdev_get_gpio_in(cpudev, ARM_CPU_VFIQ));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < NUM_IRQS; i++) {
|
for (i = 0; i < NUM_IRQS; i++) {
|
||||||
@ -1221,9 +1244,18 @@ static void machvirt_init(MachineState *machine)
|
|||||||
* so it doesn't get in the way. Instead of starting secondary
|
* so it doesn't get in the way. Instead of starting secondary
|
||||||
* CPUs in PSCI powerdown state we will start them all running and
|
* CPUs in PSCI powerdown state we will start them all running and
|
||||||
* let the boot ROM sort them out.
|
* let the boot ROM sort them out.
|
||||||
* The usual case is that we do use QEMU's PSCI implementation.
|
* The usual case is that we do use QEMU's PSCI implementation;
|
||||||
|
* if the guest has EL2 then we will use SMC as the conduit,
|
||||||
|
* and otherwise we will use HVC (for backwards compatibility and
|
||||||
|
* because if we're using KVM then we must use HVC).
|
||||||
*/
|
*/
|
||||||
vms->using_psci = !(vms->secure && firmware_loaded);
|
if (vms->secure && firmware_loaded) {
|
||||||
|
vms->psci_conduit = QEMU_PSCI_CONDUIT_DISABLED;
|
||||||
|
} else if (vms->virt) {
|
||||||
|
vms->psci_conduit = QEMU_PSCI_CONDUIT_SMC;
|
||||||
|
} else {
|
||||||
|
vms->psci_conduit = QEMU_PSCI_CONDUIT_HVC;
|
||||||
|
}
|
||||||
|
|
||||||
/* The maximum number of CPUs depends on the GIC version, or on how
|
/* The maximum number of CPUs depends on the GIC version, or on how
|
||||||
* many redistributors we can fit into the memory map.
|
* many redistributors we can fit into the memory map.
|
||||||
@ -1250,6 +1282,12 @@ static void machvirt_init(MachineState *machine)
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (vms->virt && kvm_enabled()) {
|
||||||
|
error_report("mach-virt: KVM does not support providing "
|
||||||
|
"Virtualization extensions to the guest CPU");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
if (vms->secure) {
|
if (vms->secure) {
|
||||||
if (kvm_enabled()) {
|
if (kvm_enabled()) {
|
||||||
error_report("mach-virt: KVM does not support Security extensions");
|
error_report("mach-virt: KVM does not support Security extensions");
|
||||||
@ -1306,8 +1344,12 @@ static void machvirt_init(MachineState *machine)
|
|||||||
object_property_set_bool(cpuobj, false, "has_el3", NULL);
|
object_property_set_bool(cpuobj, false, "has_el3", NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vms->using_psci) {
|
if (!vms->virt && object_property_find(cpuobj, "has_el2", NULL)) {
|
||||||
object_property_set_int(cpuobj, QEMU_PSCI_CONDUIT_HVC,
|
object_property_set_bool(cpuobj, false, "has_el2", NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vms->psci_conduit != QEMU_PSCI_CONDUIT_DISABLED) {
|
||||||
|
object_property_set_int(cpuobj, vms->psci_conduit,
|
||||||
"psci-conduit", NULL);
|
"psci-conduit", NULL);
|
||||||
|
|
||||||
/* Secondary CPUs start in PSCI powered-down state */
|
/* Secondary CPUs start in PSCI powered-down state */
|
||||||
@ -1408,6 +1450,20 @@ static void virt_set_secure(Object *obj, bool value, Error **errp)
|
|||||||
vms->secure = value;
|
vms->secure = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool virt_get_virt(Object *obj, Error **errp)
|
||||||
|
{
|
||||||
|
VirtMachineState *vms = VIRT_MACHINE(obj);
|
||||||
|
|
||||||
|
return vms->virt;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void virt_set_virt(Object *obj, bool value, Error **errp)
|
||||||
|
{
|
||||||
|
VirtMachineState *vms = VIRT_MACHINE(obj);
|
||||||
|
|
||||||
|
vms->virt = value;
|
||||||
|
}
|
||||||
|
|
||||||
static bool virt_get_highmem(Object *obj, Error **errp)
|
static bool virt_get_highmem(Object *obj, Error **errp)
|
||||||
{
|
{
|
||||||
VirtMachineState *vms = VIRT_MACHINE(obj);
|
VirtMachineState *vms = VIRT_MACHINE(obj);
|
||||||
@ -1495,6 +1551,16 @@ static void virt_2_9_instance_init(Object *obj)
|
|||||||
"Security Extensions (TrustZone)",
|
"Security Extensions (TrustZone)",
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
|
/* EL2 is also disabled by default, for similar reasons */
|
||||||
|
vms->virt = false;
|
||||||
|
object_property_add_bool(obj, "virtualization", virt_get_virt,
|
||||||
|
virt_set_virt, NULL);
|
||||||
|
object_property_set_description(obj, "virtualization",
|
||||||
|
"Set on/off to enable/disable emulating a "
|
||||||
|
"guest CPU which implements the ARM "
|
||||||
|
"Virtualization Extensions",
|
||||||
|
NULL);
|
||||||
|
|
||||||
/* High memory is enabled by default */
|
/* High memory is enabled by default */
|
||||||
vms->highmem = true;
|
vms->highmem = true;
|
||||||
object_property_add_bool(obj, "highmem", virt_get_highmem,
|
object_property_add_bool(obj, "highmem", virt_get_highmem,
|
||||||
|
@ -258,6 +258,8 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
|
|||||||
|
|
||||||
object_property_set_bool(OBJECT(&s->apu_cpu[i]),
|
object_property_set_bool(OBJECT(&s->apu_cpu[i]),
|
||||||
s->secure, "has_el3", NULL);
|
s->secure, "has_el3", NULL);
|
||||||
|
object_property_set_bool(OBJECT(&s->apu_cpu[i]),
|
||||||
|
false, "has_el2", NULL);
|
||||||
object_property_set_int(OBJECT(&s->apu_cpu[i]), GIC_BASE_ADDR,
|
object_property_set_int(OBJECT(&s->apu_cpu[i]), GIC_BASE_ADDR,
|
||||||
"reset-cbar", &error_abort);
|
"reset-cbar", &error_abort);
|
||||||
object_property_set_bool(OBJECT(&s->apu_cpu[i]), true, "realized",
|
object_property_set_bool(OBJECT(&s->apu_cpu[i]), true, "realized",
|
||||||
|
@ -74,6 +74,12 @@ typedef struct FlashPartInfo {
|
|||||||
uint32_t n_sectors;
|
uint32_t n_sectors;
|
||||||
uint32_t page_size;
|
uint32_t page_size;
|
||||||
uint16_t flags;
|
uint16_t flags;
|
||||||
|
/*
|
||||||
|
* Big sized spi nor are often stacked devices, thus sometime
|
||||||
|
* replace chip erase with die erase.
|
||||||
|
* This field inform how many die is in the chip.
|
||||||
|
*/
|
||||||
|
uint8_t die_cnt;
|
||||||
} FlashPartInfo;
|
} FlashPartInfo;
|
||||||
|
|
||||||
/* adapted from linux */
|
/* adapted from linux */
|
||||||
@ -91,7 +97,8 @@ typedef struct FlashPartInfo {
|
|||||||
.sector_size = (_sector_size),\
|
.sector_size = (_sector_size),\
|
||||||
.n_sectors = (_n_sectors),\
|
.n_sectors = (_n_sectors),\
|
||||||
.page_size = 256,\
|
.page_size = 256,\
|
||||||
.flags = (_flags),
|
.flags = (_flags),\
|
||||||
|
.die_cnt = 0
|
||||||
|
|
||||||
#define INFO6(_part_name, _jedec_id, _ext_id, _sector_size, _n_sectors, _flags)\
|
#define INFO6(_part_name, _jedec_id, _ext_id, _sector_size, _n_sectors, _flags)\
|
||||||
.part_name = _part_name,\
|
.part_name = _part_name,\
|
||||||
@ -108,6 +115,24 @@ typedef struct FlashPartInfo {
|
|||||||
.n_sectors = (_n_sectors),\
|
.n_sectors = (_n_sectors),\
|
||||||
.page_size = 256,\
|
.page_size = 256,\
|
||||||
.flags = (_flags),\
|
.flags = (_flags),\
|
||||||
|
.die_cnt = 0
|
||||||
|
|
||||||
|
#define INFO_STACKED(_part_name, _jedec_id, _ext_id, _sector_size, _n_sectors,\
|
||||||
|
_flags, _die_cnt)\
|
||||||
|
.part_name = _part_name,\
|
||||||
|
.id = {\
|
||||||
|
((_jedec_id) >> 16) & 0xff,\
|
||||||
|
((_jedec_id) >> 8) & 0xff,\
|
||||||
|
(_jedec_id) & 0xff,\
|
||||||
|
((_ext_id) >> 8) & 0xff,\
|
||||||
|
(_ext_id) & 0xff,\
|
||||||
|
},\
|
||||||
|
.id_len = (!(_jedec_id) ? 0 : (3 + ((_ext_id) ? 2 : 0))),\
|
||||||
|
.sector_size = (_sector_size),\
|
||||||
|
.n_sectors = (_n_sectors),\
|
||||||
|
.page_size = 256,\
|
||||||
|
.flags = (_flags),\
|
||||||
|
.die_cnt = _die_cnt
|
||||||
|
|
||||||
#define JEDEC_NUMONYX 0x20
|
#define JEDEC_NUMONYX 0x20
|
||||||
#define JEDEC_WINBOND 0xEF
|
#define JEDEC_WINBOND 0xEF
|
||||||
@ -218,8 +243,10 @@ static const FlashPartInfo known_devices[] = {
|
|||||||
{ INFO("n25q128", 0x20ba18, 0, 64 << 10, 256, 0) },
|
{ INFO("n25q128", 0x20ba18, 0, 64 << 10, 256, 0) },
|
||||||
{ INFO("n25q256a", 0x20ba19, 0, 64 << 10, 512, ER_4K) },
|
{ INFO("n25q256a", 0x20ba19, 0, 64 << 10, 512, ER_4K) },
|
||||||
{ INFO("n25q512a", 0x20ba20, 0, 64 << 10, 1024, ER_4K) },
|
{ INFO("n25q512a", 0x20ba20, 0, 64 << 10, 1024, ER_4K) },
|
||||||
{ INFO("mt25ql01g", 0x20ba21, 0, 64 << 10, 2048, ER_4K) },
|
{ INFO_STACKED("n25q00", 0x20ba21, 0x1000, 64 << 10, 2048, ER_4K, 4) },
|
||||||
{ INFO("mt25qu01g", 0x20bb21, 0, 64 << 10, 2048, ER_4K) },
|
{ INFO_STACKED("n25q00a", 0x20bb21, 0x1000, 64 << 10, 2048, ER_4K, 4) },
|
||||||
|
{ INFO_STACKED("mt25ql01g", 0x20ba21, 0x1040, 64 << 10, 2048, ER_4K, 2) },
|
||||||
|
{ INFO_STACKED("mt25qu01g", 0x20bb21, 0x1040, 64 << 10, 2048, ER_4K, 2) },
|
||||||
|
|
||||||
/* Spansion -- single (large) sector size only, at least
|
/* Spansion -- single (large) sector size only, at least
|
||||||
* for the chips listed here (without boot sectors).
|
* for the chips listed here (without boot sectors).
|
||||||
@ -327,6 +354,7 @@ typedef enum {
|
|||||||
PP4_4 = 0x3e,
|
PP4_4 = 0x3e,
|
||||||
DPP = 0xa2,
|
DPP = 0xa2,
|
||||||
QPP = 0x32,
|
QPP = 0x32,
|
||||||
|
QPP_4 = 0x34,
|
||||||
|
|
||||||
ERASE_4K = 0x20,
|
ERASE_4K = 0x20,
|
||||||
ERASE4_4K = 0x21,
|
ERASE4_4K = 0x21,
|
||||||
@ -359,6 +387,8 @@ typedef enum {
|
|||||||
|
|
||||||
REVCR = 0x65,
|
REVCR = 0x65,
|
||||||
WEVCR = 0x61,
|
WEVCR = 0x61,
|
||||||
|
|
||||||
|
DIE_ERASE = 0xC4,
|
||||||
} FlashCMD;
|
} FlashCMD;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
@ -516,6 +546,16 @@ static void flash_erase(Flash *s, int offset, FlashCMD cmd)
|
|||||||
case BULK_ERASE:
|
case BULK_ERASE:
|
||||||
len = s->size;
|
len = s->size;
|
||||||
break;
|
break;
|
||||||
|
case DIE_ERASE:
|
||||||
|
if (s->pi->die_cnt) {
|
||||||
|
len = s->size / s->pi->die_cnt;
|
||||||
|
offset = offset & (~(len - 1));
|
||||||
|
} else {
|
||||||
|
qemu_log_mask(LOG_GUEST_ERROR, "M25P80: die erase is not supported"
|
||||||
|
" by device\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
@ -577,6 +617,7 @@ static inline int get_addr_length(Flash *s)
|
|||||||
switch (s->cmd_in_progress) {
|
switch (s->cmd_in_progress) {
|
||||||
case PP4:
|
case PP4:
|
||||||
case PP4_4:
|
case PP4_4:
|
||||||
|
case QPP_4:
|
||||||
case READ4:
|
case READ4:
|
||||||
case QIOR4:
|
case QIOR4:
|
||||||
case ERASE4_4K:
|
case ERASE4_4K:
|
||||||
@ -610,6 +651,7 @@ static void complete_collecting_data(Flash *s)
|
|||||||
switch (s->cmd_in_progress) {
|
switch (s->cmd_in_progress) {
|
||||||
case DPP:
|
case DPP:
|
||||||
case QPP:
|
case QPP:
|
||||||
|
case QPP_4:
|
||||||
case PP:
|
case PP:
|
||||||
case PP4:
|
case PP4:
|
||||||
case PP4_4:
|
case PP4_4:
|
||||||
@ -635,6 +677,7 @@ static void complete_collecting_data(Flash *s)
|
|||||||
case ERASE4_32K:
|
case ERASE4_32K:
|
||||||
case ERASE_SECTOR:
|
case ERASE_SECTOR:
|
||||||
case ERASE4_SECTOR:
|
case ERASE4_SECTOR:
|
||||||
|
case DIE_ERASE:
|
||||||
flash_erase(s, s->cur_addr, s->cmd_in_progress);
|
flash_erase(s, s->cur_addr, s->cmd_in_progress);
|
||||||
break;
|
break;
|
||||||
case WRSR:
|
case WRSR:
|
||||||
@ -877,9 +920,11 @@ static void decode_new_cmd(Flash *s, uint32_t value)
|
|||||||
case READ4:
|
case READ4:
|
||||||
case DPP:
|
case DPP:
|
||||||
case QPP:
|
case QPP:
|
||||||
|
case QPP_4:
|
||||||
case PP:
|
case PP:
|
||||||
case PP4:
|
case PP4:
|
||||||
case PP4_4:
|
case PP4_4:
|
||||||
|
case DIE_ERASE:
|
||||||
s->needed_bytes = get_addr_length(s);
|
s->needed_bytes = get_addr_length(s);
|
||||||
s->pos = 0;
|
s->pos = 0;
|
||||||
s->len = 0;
|
s->len = 0;
|
||||||
|
@ -310,7 +310,7 @@ static void imx_i2c_realize(DeviceState *dev, Error **errp)
|
|||||||
IMX_I2C_MEM_SIZE);
|
IMX_I2C_MEM_SIZE);
|
||||||
sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
|
sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
|
||||||
sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq);
|
sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq);
|
||||||
s->bus = i2c_init_bus(DEVICE(dev), "i2c");
|
s->bus = i2c_init_bus(DEVICE(dev), NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void imx_i2c_class_init(ObjectClass *klass, void *data)
|
static void imx_i2c_class_init(ObjectClass *klass, void *data)
|
||||||
|
@ -110,6 +110,12 @@ void gic_init_irqs_and_mmio(GICState *s, qemu_irq_handler handler,
|
|||||||
for (i = 0; i < s->num_cpu; i++) {
|
for (i = 0; i < s->num_cpu; i++) {
|
||||||
sysbus_init_irq(sbd, &s->parent_fiq[i]);
|
sysbus_init_irq(sbd, &s->parent_fiq[i]);
|
||||||
}
|
}
|
||||||
|
for (i = 0; i < s->num_cpu; i++) {
|
||||||
|
sysbus_init_irq(sbd, &s->parent_virq[i]);
|
||||||
|
}
|
||||||
|
for (i = 0; i < s->num_cpu; i++) {
|
||||||
|
sysbus_init_irq(sbd, &s->parent_vfiq[i]);
|
||||||
|
}
|
||||||
|
|
||||||
/* Distributor */
|
/* Distributor */
|
||||||
memory_region_init_io(&s->iomem, OBJECT(s), ops, s, "gic_dist", 0x1000);
|
memory_region_init_io(&s->iomem, OBJECT(s), ops, s, "gic_dist", 0x1000);
|
||||||
|
@ -49,6 +49,27 @@ static int gicv3_post_load(void *opaque, int version_id)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool virt_state_needed(void *opaque)
|
||||||
|
{
|
||||||
|
GICv3CPUState *cs = opaque;
|
||||||
|
|
||||||
|
return cs->num_list_regs != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const VMStateDescription vmstate_gicv3_cpu_virt = {
|
||||||
|
.name = "arm_gicv3_cpu/virt",
|
||||||
|
.version_id = 1,
|
||||||
|
.minimum_version_id = 1,
|
||||||
|
.needed = virt_state_needed,
|
||||||
|
.fields = (VMStateField[]) {
|
||||||
|
VMSTATE_UINT64_2DARRAY(ich_apr, GICv3CPUState, 3, 4),
|
||||||
|
VMSTATE_UINT64(ich_hcr_el2, GICv3CPUState),
|
||||||
|
VMSTATE_UINT64_ARRAY(ich_lr_el2, GICv3CPUState, GICV3_LR_MAX),
|
||||||
|
VMSTATE_UINT64(ich_vmcr_el2, GICv3CPUState),
|
||||||
|
VMSTATE_END_OF_LIST()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
static const VMStateDescription vmstate_gicv3_cpu = {
|
static const VMStateDescription vmstate_gicv3_cpu = {
|
||||||
.name = "arm_gicv3_cpu",
|
.name = "arm_gicv3_cpu",
|
||||||
.version_id = 1,
|
.version_id = 1,
|
||||||
@ -75,6 +96,10 @@ static const VMStateDescription vmstate_gicv3_cpu = {
|
|||||||
VMSTATE_UINT64_ARRAY(icc_igrpen, GICv3CPUState, 3),
|
VMSTATE_UINT64_ARRAY(icc_igrpen, GICv3CPUState, 3),
|
||||||
VMSTATE_UINT64(icc_ctlr_el3, GICv3CPUState),
|
VMSTATE_UINT64(icc_ctlr_el3, GICv3CPUState),
|
||||||
VMSTATE_END_OF_LIST()
|
VMSTATE_END_OF_LIST()
|
||||||
|
},
|
||||||
|
.subsections = (const VMStateDescription * []) {
|
||||||
|
&vmstate_gicv3_cpu_virt,
|
||||||
|
NULL
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -126,6 +151,12 @@ void gicv3_init_irqs_and_mmio(GICv3State *s, qemu_irq_handler handler,
|
|||||||
for (i = 0; i < s->num_cpu; i++) {
|
for (i = 0; i < s->num_cpu; i++) {
|
||||||
sysbus_init_irq(sbd, &s->cpu[i].parent_fiq);
|
sysbus_init_irq(sbd, &s->cpu[i].parent_fiq);
|
||||||
}
|
}
|
||||||
|
for (i = 0; i < s->num_cpu; i++) {
|
||||||
|
sysbus_init_irq(sbd, &s->cpu[i].parent_virq);
|
||||||
|
}
|
||||||
|
for (i = 0; i < s->num_cpu; i++) {
|
||||||
|
sysbus_init_irq(sbd, &s->cpu[i].parent_vfiq);
|
||||||
|
}
|
||||||
|
|
||||||
memory_region_init_io(&s->iomem_dist, OBJECT(s), ops, s,
|
memory_region_init_io(&s->iomem_dist, OBJECT(s), ops, s,
|
||||||
"gicv3_dist", 0x10000);
|
"gicv3_dist", 0x10000);
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -159,6 +159,85 @@
|
|||||||
#define ICC_CTLR_EL3_A3V (1U << 15)
|
#define ICC_CTLR_EL3_A3V (1U << 15)
|
||||||
#define ICC_CTLR_EL3_NDS (1U << 17)
|
#define ICC_CTLR_EL3_NDS (1U << 17)
|
||||||
|
|
||||||
|
#define ICH_VMCR_EL2_VENG0_SHIFT 0
|
||||||
|
#define ICH_VMCR_EL2_VENG0 (1U << ICH_VMCR_EL2_VENG0_SHIFT)
|
||||||
|
#define ICH_VMCR_EL2_VENG1_SHIFT 1
|
||||||
|
#define ICH_VMCR_EL2_VENG1 (1U << ICH_VMCR_EL2_VENG1_SHIFT)
|
||||||
|
#define ICH_VMCR_EL2_VACKCTL (1U << 2)
|
||||||
|
#define ICH_VMCR_EL2_VFIQEN (1U << 3)
|
||||||
|
#define ICH_VMCR_EL2_VCBPR_SHIFT 4
|
||||||
|
#define ICH_VMCR_EL2_VCBPR (1U << ICH_VMCR_EL2_VCBPR_SHIFT)
|
||||||
|
#define ICH_VMCR_EL2_VEOIM_SHIFT 9
|
||||||
|
#define ICH_VMCR_EL2_VEOIM (1U << ICH_VMCR_EL2_VEOIM_SHIFT)
|
||||||
|
#define ICH_VMCR_EL2_VBPR1_SHIFT 18
|
||||||
|
#define ICH_VMCR_EL2_VBPR1_LENGTH 3
|
||||||
|
#define ICH_VMCR_EL2_VBPR1_MASK (0x7U << ICH_VMCR_EL2_VBPR1_SHIFT)
|
||||||
|
#define ICH_VMCR_EL2_VBPR0_SHIFT 21
|
||||||
|
#define ICH_VMCR_EL2_VBPR0_LENGTH 3
|
||||||
|
#define ICH_VMCR_EL2_VBPR0_MASK (0x7U << ICH_VMCR_EL2_VBPR0_SHIFT)
|
||||||
|
#define ICH_VMCR_EL2_VPMR_SHIFT 24
|
||||||
|
#define ICH_VMCR_EL2_VPMR_LENGTH 8
|
||||||
|
#define ICH_VMCR_EL2_VPMR_MASK (0xffU << ICH_VMCR_EL2_VPMR_SHIFT)
|
||||||
|
|
||||||
|
#define ICH_HCR_EL2_EN (1U << 0)
|
||||||
|
#define ICH_HCR_EL2_UIE (1U << 1)
|
||||||
|
#define ICH_HCR_EL2_LRENPIE (1U << 2)
|
||||||
|
#define ICH_HCR_EL2_NPIE (1U << 3)
|
||||||
|
#define ICH_HCR_EL2_VGRP0EIE (1U << 4)
|
||||||
|
#define ICH_HCR_EL2_VGRP0DIE (1U << 5)
|
||||||
|
#define ICH_HCR_EL2_VGRP1EIE (1U << 6)
|
||||||
|
#define ICH_HCR_EL2_VGRP1DIE (1U << 7)
|
||||||
|
#define ICH_HCR_EL2_TC (1U << 10)
|
||||||
|
#define ICH_HCR_EL2_TALL0 (1U << 11)
|
||||||
|
#define ICH_HCR_EL2_TALL1 (1U << 12)
|
||||||
|
#define ICH_HCR_EL2_TSEI (1U << 13)
|
||||||
|
#define ICH_HCR_EL2_TDIR (1U << 14)
|
||||||
|
#define ICH_HCR_EL2_EOICOUNT_SHIFT 27
|
||||||
|
#define ICH_HCR_EL2_EOICOUNT_LENGTH 5
|
||||||
|
#define ICH_HCR_EL2_EOICOUNT_MASK (0x1fU << ICH_HCR_EL2_EOICOUNT_SHIFT)
|
||||||
|
|
||||||
|
#define ICH_LR_EL2_VINTID_SHIFT 0
|
||||||
|
#define ICH_LR_EL2_VINTID_LENGTH 32
|
||||||
|
#define ICH_LR_EL2_VINTID_MASK (0xffffffffULL << ICH_LR_EL2_VINTID_SHIFT)
|
||||||
|
#define ICH_LR_EL2_PINTID_SHIFT 32
|
||||||
|
#define ICH_LR_EL2_PINTID_LENGTH 10
|
||||||
|
#define ICH_LR_EL2_PINTID_MASK (0x3ffULL << ICH_LR_EL2_PINTID_SHIFT)
|
||||||
|
/* Note that EOI shares with the top bit of the pINTID field */
|
||||||
|
#define ICH_LR_EL2_EOI (1ULL << 41)
|
||||||
|
#define ICH_LR_EL2_PRIORITY_SHIFT 48
|
||||||
|
#define ICH_LR_EL2_PRIORITY_LENGTH 8
|
||||||
|
#define ICH_LR_EL2_PRIORITY_MASK (0xffULL << ICH_LR_EL2_PRIORITY_SHIFT)
|
||||||
|
#define ICH_LR_EL2_GROUP (1ULL << 60)
|
||||||
|
#define ICH_LR_EL2_HW (1ULL << 61)
|
||||||
|
#define ICH_LR_EL2_STATE_SHIFT 62
|
||||||
|
#define ICH_LR_EL2_STATE_LENGTH 2
|
||||||
|
#define ICH_LR_EL2_STATE_MASK (3ULL << ICH_LR_EL2_STATE_SHIFT)
|
||||||
|
/* values for the state field: */
|
||||||
|
#define ICH_LR_EL2_STATE_INVALID 0
|
||||||
|
#define ICH_LR_EL2_STATE_PENDING 1
|
||||||
|
#define ICH_LR_EL2_STATE_ACTIVE 2
|
||||||
|
#define ICH_LR_EL2_STATE_ACTIVE_PENDING 3
|
||||||
|
#define ICH_LR_EL2_STATE_PENDING_BIT (1ULL << ICH_LR_EL2_STATE_SHIFT)
|
||||||
|
#define ICH_LR_EL2_STATE_ACTIVE_BIT (2ULL << ICH_LR_EL2_STATE_SHIFT)
|
||||||
|
|
||||||
|
#define ICH_MISR_EL2_EOI (1U << 0)
|
||||||
|
#define ICH_MISR_EL2_U (1U << 1)
|
||||||
|
#define ICH_MISR_EL2_LRENP (1U << 2)
|
||||||
|
#define ICH_MISR_EL2_NP (1U << 3)
|
||||||
|
#define ICH_MISR_EL2_VGRP0E (1U << 4)
|
||||||
|
#define ICH_MISR_EL2_VGRP0D (1U << 5)
|
||||||
|
#define ICH_MISR_EL2_VGRP1E (1U << 6)
|
||||||
|
#define ICH_MISR_EL2_VGRP1D (1U << 7)
|
||||||
|
|
||||||
|
#define ICH_VTR_EL2_LISTREGS_SHIFT 0
|
||||||
|
#define ICH_VTR_EL2_TDS (1U << 19)
|
||||||
|
#define ICH_VTR_EL2_NV4 (1U << 20)
|
||||||
|
#define ICH_VTR_EL2_A3V (1U << 21)
|
||||||
|
#define ICH_VTR_EL2_SEIS (1U << 22)
|
||||||
|
#define ICH_VTR_EL2_IDBITS_SHIFT 23
|
||||||
|
#define ICH_VTR_EL2_PREBITS_SHIFT 26
|
||||||
|
#define ICH_VTR_EL2_PRIBITS_SHIFT 29
|
||||||
|
|
||||||
/* Special interrupt IDs */
|
/* Special interrupt IDs */
|
||||||
#define INTID_SECURE 1020
|
#define INTID_SECURE 1020
|
||||||
#define INTID_NONSECURE 1021
|
#define INTID_NONSECURE 1021
|
||||||
|
@ -107,6 +107,39 @@ gicv3_icc_hppir0_read(uint32_t cpu, uint64_t val) "GICv3 ICC_HPPIR0 read cpu %x
|
|||||||
gicv3_icc_hppir1_read(uint32_t cpu, uint64_t val) "GICv3 ICC_HPPIR1 read cpu %x value 0x%" PRIx64
|
gicv3_icc_hppir1_read(uint32_t cpu, uint64_t val) "GICv3 ICC_HPPIR1 read cpu %x value 0x%" PRIx64
|
||||||
gicv3_icc_dir_write(uint32_t cpu, uint64_t val) "GICv3 ICC_DIR write cpu %x value 0x%" PRIx64
|
gicv3_icc_dir_write(uint32_t cpu, uint64_t val) "GICv3 ICC_DIR write cpu %x value 0x%" PRIx64
|
||||||
gicv3_icc_rpr_read(uint32_t cpu, uint64_t val) "GICv3 ICC_RPR read cpu %x value 0x%" PRIx64
|
gicv3_icc_rpr_read(uint32_t cpu, uint64_t val) "GICv3 ICC_RPR read cpu %x value 0x%" PRIx64
|
||||||
|
gicv3_ich_ap_read(int grp, int regno, uint32_t cpu, uint64_t val) "GICv3 ICH_AP%dR%d read cpu %x value 0x%" PRIx64
|
||||||
|
gicv3_ich_ap_write(int grp, int regno, uint32_t cpu, uint64_t val) "GICv3 ICH_AP%dR%d write cpu %x value 0x%" PRIx64
|
||||||
|
gicv3_ich_hcr_read(uint32_t cpu, uint64_t val) "GICv3 ICH_HCR_EL2 read cpu %x value 0x%" PRIx64
|
||||||
|
gicv3_ich_hcr_write(uint32_t cpu, uint64_t val) "GICv3 ICH_HCR_EL2 write cpu %x value 0x%" PRIx64
|
||||||
|
gicv3_ich_vmcr_read(uint32_t cpu, uint64_t val) "GICv3 ICH_VMCR_EL2 read cpu %x value 0x%" PRIx64
|
||||||
|
gicv3_ich_vmcr_write(uint32_t cpu, uint64_t val) "GICv3 ICH_VMCR_EL2 write cpu %x value 0x%" PRIx64
|
||||||
|
gicv3_ich_lr_read(int regno, uint32_t cpu, uint64_t val) "GICv3 ICH_LR%d_EL2 read cpu %x value 0x%" PRIx64
|
||||||
|
gicv3_ich_lr32_read(int regno, uint32_t cpu, uint32_t val) "GICv3 ICH_LR%d read cpu %x value 0x%" PRIx32
|
||||||
|
gicv3_ich_lrc_read(int regno, uint32_t cpu, uint32_t val) "GICv3 ICH_LRC%d read cpu %x value 0x%" PRIx32
|
||||||
|
gicv3_ich_lr_write(int regno, uint32_t cpu, uint64_t val) "GICv3 ICH_LR%d_EL2 write cpu %x value 0x%" PRIx64
|
||||||
|
gicv3_ich_lr32_write(int regno, uint32_t cpu, uint32_t val) "GICv3 ICH_LR%d write cpu %x value 0x%" PRIx32
|
||||||
|
gicv3_ich_lrc_write(int regno, uint32_t cpu, uint32_t val) "GICv3 ICH_LRC%d write cpu %x value 0x%" PRIx32
|
||||||
|
gicv3_ich_vtr_read(uint32_t cpu, uint64_t val) "GICv3 ICH_VTR read cpu %x value 0x%" PRIx64
|
||||||
|
gicv3_ich_misr_read(uint32_t cpu, uint64_t val) "GICv3 ICH_MISR read cpu %x value 0x%" PRIx64
|
||||||
|
gicv3_ich_eisr_read(uint32_t cpu, uint64_t val) "GICv3 ICH_EISR read cpu %x value 0x%" PRIx64
|
||||||
|
gicv3_ich_elrsr_read(uint32_t cpu, uint64_t val) "GICv3 ICH_ELRSR read cpu %x value 0x%" PRIx64
|
||||||
|
gicv3_icv_ap_read(int grp, int regno, uint32_t cpu, uint64_t val) "GICv3 ICV_AP%dR%d read cpu %x value 0x%" PRIx64
|
||||||
|
gicv3_icv_ap_write(int grp, int regno, uint32_t cpu, uint64_t val) "GICv3 ICV_AP%dR%d write cpu %x value 0x%" PRIx64
|
||||||
|
gicv3_icv_bpr_read(int grp, uint32_t cpu, uint64_t val) "GICv3 ICV_BPR%d read cpu %x value 0x%" PRIx64
|
||||||
|
gicv3_icv_bpr_write(int grp, uint32_t cpu, uint64_t val) "GICv3 ICV_BPR%d write cpu %x value 0x%" PRIx64
|
||||||
|
gicv3_icv_pmr_read(uint32_t cpu, uint64_t val) "GICv3 ICV_PMR read cpu %x value 0x%" PRIx64
|
||||||
|
gicv3_icv_pmr_write(uint32_t cpu, uint64_t val) "GICv3 ICV_PMR write cpu %x value 0x%" PRIx64
|
||||||
|
gicv3_icv_igrpen_read(int grp, uint32_t cpu, uint64_t val) "GICv3 ICV_IGRPEN%d read cpu %x value 0x%" PRIx64
|
||||||
|
gicv3_icv_igrpen_write(int grp, uint32_t cpu, uint64_t val) "GICv3 ICV_IGRPEN%d write cpu %x value 0x%" PRIx64
|
||||||
|
gicv3_icv_ctlr_read(uint32_t cpu, uint64_t val) "GICv3 ICV_CTLR read cpu %x value 0x%" PRIx64
|
||||||
|
gicv3_icv_ctlr_write(uint32_t cpu, uint64_t val) "GICv3 ICV_CTLR write cpu %x value 0x%" PRIx64
|
||||||
|
gicv3_icv_rpr_read(uint32_t cpu, uint64_t val) "GICv3 ICV_RPR read cpu %x value 0x%" PRIx64
|
||||||
|
gicv3_icv_hppir_read(int grp, uint32_t cpu, uint64_t val) "GICv3 ICV_HPPIR%d read cpu %x value 0x%" PRIx64
|
||||||
|
gicv3_icv_dir_write(uint32_t cpu, uint64_t val) "GICv3 ICV_DIR write cpu %x value 0x%" PRIx64
|
||||||
|
gicv3_icv_iar_read(int grp, uint32_t cpu, uint64_t val) "GICv3 ICV_IAR%d read cpu %x value 0x%" PRIx64
|
||||||
|
gicv3_icv_eoir_write(int grp, uint32_t cpu, uint64_t val) "GICv3 ICV_EOIR%d write cpu %x value 0x%" PRIx64
|
||||||
|
gicv3_cpuif_virt_update(uint32_t cpuid, int idx) "GICv3 CPU i/f %x virt HPPI update LR index %d"
|
||||||
|
gicv3_cpuif_virt_set_irqs(uint32_t cpuid, int fiqlevel, int irqlevel, int maintlevel) "GICv3 CPU i/f %x virt HPPI update: setting FIQ %d IRQ %d maintenance-irq %d"
|
||||||
|
|
||||||
# hw/intc/arm_gicv3_dist.c
|
# hw/intc/arm_gicv3_dist.c
|
||||||
gicv3_dist_read(uint64_t offset, uint64_t data, unsigned size, bool secure) "GICv3 distributor read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u secure %d"
|
gicv3_dist_read(uint64_t offset, uint64_t data, unsigned size, bool secure) "GICv3 distributor read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u secure %d"
|
||||||
|
@ -39,11 +39,14 @@
|
|||||||
#define CONF_ENABLE_W2 18
|
#define CONF_ENABLE_W2 18
|
||||||
#define CONF_ENABLE_W1 17
|
#define CONF_ENABLE_W1 17
|
||||||
#define CONF_ENABLE_W0 16
|
#define CONF_ENABLE_W0 16
|
||||||
#define CONF_FLASH_TYPE4 9
|
#define CONF_FLASH_TYPE4 8
|
||||||
#define CONF_FLASH_TYPE3 7
|
#define CONF_FLASH_TYPE3 6
|
||||||
#define CONF_FLASH_TYPE2 5
|
#define CONF_FLASH_TYPE2 4
|
||||||
#define CONF_FLASH_TYPE1 3
|
#define CONF_FLASH_TYPE1 2
|
||||||
#define CONF_FLASH_TYPE0 1
|
#define CONF_FLASH_TYPE0 0
|
||||||
|
#define CONF_FLASH_TYPE_NOR 0x0
|
||||||
|
#define CONF_FLASH_TYPE_NAND 0x1
|
||||||
|
#define CONF_FLASH_TYPE_SPI 0x2
|
||||||
|
|
||||||
/* CE Control Register */
|
/* CE Control Register */
|
||||||
#define R_CE_CTRL (0x04 / 4)
|
#define R_CE_CTRL (0x04 / 4)
|
||||||
@ -66,6 +69,7 @@
|
|||||||
#define R_CTRL0 (0x10 / 4)
|
#define R_CTRL0 (0x10 / 4)
|
||||||
#define CTRL_CMD_SHIFT 16
|
#define CTRL_CMD_SHIFT 16
|
||||||
#define CTRL_CMD_MASK 0xff
|
#define CTRL_CMD_MASK 0xff
|
||||||
|
#define CTRL_AST2400_SPI_4BYTE (1 << 13)
|
||||||
#define CTRL_CE_STOP_ACTIVE (1 << 2)
|
#define CTRL_CE_STOP_ACTIVE (1 << 2)
|
||||||
#define CTRL_CMD_MODE_MASK 0x3
|
#define CTRL_CMD_MODE_MASK 0x3
|
||||||
#define CTRL_READMODE 0x0
|
#define CTRL_READMODE 0x0
|
||||||
@ -127,11 +131,17 @@
|
|||||||
#define R_SPI_MISC_CTRL (0x10 / 4)
|
#define R_SPI_MISC_CTRL (0x10 / 4)
|
||||||
#define R_SPI_TIMINGS (0x14 / 4)
|
#define R_SPI_TIMINGS (0x14 / 4)
|
||||||
|
|
||||||
|
#define ASPEED_SMC_R_SPI_MAX (0x20 / 4)
|
||||||
|
#define ASPEED_SMC_R_SMC_MAX (0x20 / 4)
|
||||||
|
|
||||||
#define ASPEED_SOC_SMC_FLASH_BASE 0x10000000
|
#define ASPEED_SOC_SMC_FLASH_BASE 0x10000000
|
||||||
#define ASPEED_SOC_FMC_FLASH_BASE 0x20000000
|
#define ASPEED_SOC_FMC_FLASH_BASE 0x20000000
|
||||||
#define ASPEED_SOC_SPI_FLASH_BASE 0x30000000
|
#define ASPEED_SOC_SPI_FLASH_BASE 0x30000000
|
||||||
#define ASPEED_SOC_SPI2_FLASH_BASE 0x38000000
|
#define ASPEED_SOC_SPI2_FLASH_BASE 0x38000000
|
||||||
|
|
||||||
|
/* Flash opcodes. */
|
||||||
|
#define SPI_OP_READ 0x03 /* Read data bytes (low frequency) */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Default segments mapping addresses and size for each slave per
|
* Default segments mapping addresses and size for each slave per
|
||||||
* controller. These can be changed when board is initialized with the
|
* controller. These can be changed when board is initialized with the
|
||||||
@ -170,24 +180,85 @@ static const AspeedSegments aspeed_segments_ast2500_spi2[] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static const AspeedSMCController controllers[] = {
|
static const AspeedSMCController controllers[] = {
|
||||||
{ "aspeed.smc.smc", R_CONF, R_CE_CTRL, R_CTRL0, R_TIMINGS,
|
{
|
||||||
CONF_ENABLE_W0, 5, aspeed_segments_legacy,
|
.name = "aspeed.smc.smc",
|
||||||
ASPEED_SOC_SMC_FLASH_BASE, 0x6000000 },
|
.r_conf = R_CONF,
|
||||||
{ "aspeed.smc.fmc", R_CONF, R_CE_CTRL, R_CTRL0, R_TIMINGS,
|
.r_ce_ctrl = R_CE_CTRL,
|
||||||
CONF_ENABLE_W0, 5, aspeed_segments_fmc,
|
.r_ctrl0 = R_CTRL0,
|
||||||
ASPEED_SOC_FMC_FLASH_BASE, 0x10000000 },
|
.r_timings = R_TIMINGS,
|
||||||
{ "aspeed.smc.spi", R_SPI_CONF, 0xff, R_SPI_CTRL0, R_SPI_TIMINGS,
|
.conf_enable_w0 = CONF_ENABLE_W0,
|
||||||
SPI_CONF_ENABLE_W0, 1, aspeed_segments_spi,
|
.max_slaves = 5,
|
||||||
ASPEED_SOC_SPI_FLASH_BASE, 0x10000000 },
|
.segments = aspeed_segments_legacy,
|
||||||
{ "aspeed.smc.ast2500-fmc", R_CONF, R_CE_CTRL, R_CTRL0, R_TIMINGS,
|
.flash_window_base = ASPEED_SOC_SMC_FLASH_BASE,
|
||||||
CONF_ENABLE_W0, 3, aspeed_segments_ast2500_fmc,
|
.flash_window_size = 0x6000000,
|
||||||
ASPEED_SOC_FMC_FLASH_BASE, 0x10000000 },
|
.has_dma = false,
|
||||||
{ "aspeed.smc.ast2500-spi1", R_CONF, R_CE_CTRL, R_CTRL0, R_TIMINGS,
|
.nregs = ASPEED_SMC_R_SMC_MAX,
|
||||||
CONF_ENABLE_W0, 2, aspeed_segments_ast2500_spi1,
|
}, {
|
||||||
ASPEED_SOC_SPI_FLASH_BASE, 0x8000000 },
|
.name = "aspeed.smc.fmc",
|
||||||
{ "aspeed.smc.ast2500-spi2", R_CONF, R_CE_CTRL, R_CTRL0, R_TIMINGS,
|
.r_conf = R_CONF,
|
||||||
CONF_ENABLE_W0, 2, aspeed_segments_ast2500_spi2,
|
.r_ce_ctrl = R_CE_CTRL,
|
||||||
ASPEED_SOC_SPI2_FLASH_BASE, 0x8000000 },
|
.r_ctrl0 = R_CTRL0,
|
||||||
|
.r_timings = R_TIMINGS,
|
||||||
|
.conf_enable_w0 = CONF_ENABLE_W0,
|
||||||
|
.max_slaves = 5,
|
||||||
|
.segments = aspeed_segments_fmc,
|
||||||
|
.flash_window_base = ASPEED_SOC_FMC_FLASH_BASE,
|
||||||
|
.flash_window_size = 0x10000000,
|
||||||
|
.has_dma = true,
|
||||||
|
.nregs = ASPEED_SMC_R_MAX,
|
||||||
|
}, {
|
||||||
|
.name = "aspeed.smc.spi",
|
||||||
|
.r_conf = R_SPI_CONF,
|
||||||
|
.r_ce_ctrl = 0xff,
|
||||||
|
.r_ctrl0 = R_SPI_CTRL0,
|
||||||
|
.r_timings = R_SPI_TIMINGS,
|
||||||
|
.conf_enable_w0 = SPI_CONF_ENABLE_W0,
|
||||||
|
.max_slaves = 1,
|
||||||
|
.segments = aspeed_segments_spi,
|
||||||
|
.flash_window_base = ASPEED_SOC_SPI_FLASH_BASE,
|
||||||
|
.flash_window_size = 0x10000000,
|
||||||
|
.has_dma = false,
|
||||||
|
.nregs = ASPEED_SMC_R_SPI_MAX,
|
||||||
|
}, {
|
||||||
|
.name = "aspeed.smc.ast2500-fmc",
|
||||||
|
.r_conf = R_CONF,
|
||||||
|
.r_ce_ctrl = R_CE_CTRL,
|
||||||
|
.r_ctrl0 = R_CTRL0,
|
||||||
|
.r_timings = R_TIMINGS,
|
||||||
|
.conf_enable_w0 = CONF_ENABLE_W0,
|
||||||
|
.max_slaves = 3,
|
||||||
|
.segments = aspeed_segments_ast2500_fmc,
|
||||||
|
.flash_window_base = ASPEED_SOC_FMC_FLASH_BASE,
|
||||||
|
.flash_window_size = 0x10000000,
|
||||||
|
.has_dma = true,
|
||||||
|
.nregs = ASPEED_SMC_R_MAX,
|
||||||
|
}, {
|
||||||
|
.name = "aspeed.smc.ast2500-spi1",
|
||||||
|
.r_conf = R_CONF,
|
||||||
|
.r_ce_ctrl = R_CE_CTRL,
|
||||||
|
.r_ctrl0 = R_CTRL0,
|
||||||
|
.r_timings = R_TIMINGS,
|
||||||
|
.conf_enable_w0 = CONF_ENABLE_W0,
|
||||||
|
.max_slaves = 2,
|
||||||
|
.segments = aspeed_segments_ast2500_spi1,
|
||||||
|
.flash_window_base = ASPEED_SOC_SPI_FLASH_BASE,
|
||||||
|
.flash_window_size = 0x8000000,
|
||||||
|
.has_dma = false,
|
||||||
|
.nregs = ASPEED_SMC_R_MAX,
|
||||||
|
}, {
|
||||||
|
.name = "aspeed.smc.ast2500-spi2",
|
||||||
|
.r_conf = R_CONF,
|
||||||
|
.r_ce_ctrl = R_CE_CTRL,
|
||||||
|
.r_ctrl0 = R_CTRL0,
|
||||||
|
.r_timings = R_TIMINGS,
|
||||||
|
.conf_enable_w0 = CONF_ENABLE_W0,
|
||||||
|
.max_slaves = 2,
|
||||||
|
.segments = aspeed_segments_ast2500_spi2,
|
||||||
|
.flash_window_base = ASPEED_SOC_SPI2_FLASH_BASE,
|
||||||
|
.flash_window_size = 0x8000000,
|
||||||
|
.has_dma = false,
|
||||||
|
.nregs = ASPEED_SMC_R_MAX,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -328,36 +399,137 @@ static const MemoryRegionOps aspeed_smc_flash_default_ops = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline int aspeed_smc_flash_mode(const AspeedSMCState *s, int cs)
|
static inline int aspeed_smc_flash_mode(const AspeedSMCFlash *fl)
|
||||||
{
|
{
|
||||||
return s->regs[s->r_ctrl0 + cs] & CTRL_CMD_MODE_MASK;
|
const AspeedSMCState *s = fl->controller;
|
||||||
|
|
||||||
|
return s->regs[s->r_ctrl0 + fl->id] & CTRL_CMD_MODE_MASK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool aspeed_smc_is_usermode(const AspeedSMCState *s, int cs)
|
static inline bool aspeed_smc_is_writable(const AspeedSMCFlash *fl)
|
||||||
{
|
{
|
||||||
return aspeed_smc_flash_mode(s, cs) == CTRL_USERMODE;
|
const AspeedSMCState *s = fl->controller;
|
||||||
|
|
||||||
|
return s->regs[s->r_conf] & (1 << (s->conf_enable_w0 + fl->id));
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool aspeed_smc_is_writable(const AspeedSMCState *s, int cs)
|
static inline int aspeed_smc_flash_cmd(const AspeedSMCFlash *fl)
|
||||||
{
|
{
|
||||||
return s->regs[s->r_conf] & (1 << (s->conf_enable_w0 + cs));
|
const AspeedSMCState *s = fl->controller;
|
||||||
|
int cmd = (s->regs[s->r_ctrl0 + fl->id] >> CTRL_CMD_SHIFT) & CTRL_CMD_MASK;
|
||||||
|
|
||||||
|
/* In read mode, the default SPI command is READ (0x3). In other
|
||||||
|
* modes, the command should necessarily be defined */
|
||||||
|
if (aspeed_smc_flash_mode(fl) == CTRL_READMODE) {
|
||||||
|
cmd = SPI_OP_READ;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!cmd) {
|
||||||
|
qemu_log_mask(LOG_GUEST_ERROR, "%s: no command defined for mode %d\n",
|
||||||
|
__func__, aspeed_smc_flash_mode(fl));
|
||||||
|
}
|
||||||
|
|
||||||
|
return cmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int aspeed_smc_flash_is_4byte(const AspeedSMCFlash *fl)
|
||||||
|
{
|
||||||
|
const AspeedSMCState *s = fl->controller;
|
||||||
|
|
||||||
|
if (s->ctrl->segments == aspeed_segments_spi) {
|
||||||
|
return s->regs[s->r_ctrl0] & CTRL_AST2400_SPI_4BYTE;
|
||||||
|
} else {
|
||||||
|
return s->regs[s->r_ce_ctrl] & (1 << (CTRL_EXTENDED0 + fl->id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool aspeed_smc_is_ce_stop_active(const AspeedSMCFlash *fl)
|
||||||
|
{
|
||||||
|
const AspeedSMCState *s = fl->controller;
|
||||||
|
|
||||||
|
return s->regs[s->r_ctrl0 + fl->id] & CTRL_CE_STOP_ACTIVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void aspeed_smc_flash_select(AspeedSMCFlash *fl)
|
||||||
|
{
|
||||||
|
AspeedSMCState *s = fl->controller;
|
||||||
|
|
||||||
|
s->regs[s->r_ctrl0 + fl->id] &= ~CTRL_CE_STOP_ACTIVE;
|
||||||
|
qemu_set_irq(s->cs_lines[fl->id], aspeed_smc_is_ce_stop_active(fl));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void aspeed_smc_flash_unselect(AspeedSMCFlash *fl)
|
||||||
|
{
|
||||||
|
AspeedSMCState *s = fl->controller;
|
||||||
|
|
||||||
|
s->regs[s->r_ctrl0 + fl->id] |= CTRL_CE_STOP_ACTIVE;
|
||||||
|
qemu_set_irq(s->cs_lines[fl->id], aspeed_smc_is_ce_stop_active(fl));
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t aspeed_smc_check_segment_addr(const AspeedSMCFlash *fl,
|
||||||
|
uint32_t addr)
|
||||||
|
{
|
||||||
|
const AspeedSMCState *s = fl->controller;
|
||||||
|
AspeedSegments seg;
|
||||||
|
|
||||||
|
aspeed_smc_reg_to_segment(s->regs[R_SEG_ADDR0 + fl->id], &seg);
|
||||||
|
if ((addr & (seg.size - 1)) != addr) {
|
||||||
|
qemu_log_mask(LOG_GUEST_ERROR,
|
||||||
|
"%s: invalid address 0x%08x for CS%d segment : "
|
||||||
|
"[ 0x%"HWADDR_PRIx" - 0x%"HWADDR_PRIx" ]\n",
|
||||||
|
s->ctrl->name, addr, fl->id, seg.addr,
|
||||||
|
seg.addr + seg.size);
|
||||||
|
}
|
||||||
|
|
||||||
|
addr &= seg.size - 1;
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void aspeed_smc_flash_send_addr(AspeedSMCFlash *fl, uint32_t addr)
|
||||||
|
{
|
||||||
|
const AspeedSMCState *s = fl->controller;
|
||||||
|
uint8_t cmd = aspeed_smc_flash_cmd(fl);
|
||||||
|
|
||||||
|
/* Flash access can not exceed CS segment */
|
||||||
|
addr = aspeed_smc_check_segment_addr(fl, addr);
|
||||||
|
|
||||||
|
ssi_transfer(s->spi, cmd);
|
||||||
|
|
||||||
|
if (aspeed_smc_flash_is_4byte(fl)) {
|
||||||
|
ssi_transfer(s->spi, (addr >> 24) & 0xff);
|
||||||
|
}
|
||||||
|
ssi_transfer(s->spi, (addr >> 16) & 0xff);
|
||||||
|
ssi_transfer(s->spi, (addr >> 8) & 0xff);
|
||||||
|
ssi_transfer(s->spi, (addr & 0xff));
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint64_t aspeed_smc_flash_read(void *opaque, hwaddr addr, unsigned size)
|
static uint64_t aspeed_smc_flash_read(void *opaque, hwaddr addr, unsigned size)
|
||||||
{
|
{
|
||||||
AspeedSMCFlash *fl = opaque;
|
AspeedSMCFlash *fl = opaque;
|
||||||
const AspeedSMCState *s = fl->controller;
|
AspeedSMCState *s = fl->controller;
|
||||||
uint64_t ret = 0;
|
uint64_t ret = 0;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (aspeed_smc_is_usermode(s, fl->id)) {
|
switch (aspeed_smc_flash_mode(fl)) {
|
||||||
|
case CTRL_USERMODE:
|
||||||
for (i = 0; i < size; i++) {
|
for (i = 0; i < size; i++) {
|
||||||
ret |= ssi_transfer(s->spi, 0x0) << (8 * i);
|
ret |= ssi_transfer(s->spi, 0x0) << (8 * i);
|
||||||
}
|
}
|
||||||
} else {
|
break;
|
||||||
qemu_log_mask(LOG_UNIMP, "%s: usermode not implemented\n",
|
case CTRL_READMODE:
|
||||||
__func__);
|
case CTRL_FREADMODE:
|
||||||
ret = -1;
|
aspeed_smc_flash_select(fl);
|
||||||
|
aspeed_smc_flash_send_addr(fl, addr);
|
||||||
|
|
||||||
|
for (i = 0; i < size; i++) {
|
||||||
|
ret |= ssi_transfer(s->spi, 0x0) << (8 * i);
|
||||||
|
}
|
||||||
|
|
||||||
|
aspeed_smc_flash_unselect(fl);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid flash mode %d\n",
|
||||||
|
__func__, aspeed_smc_flash_mode(fl));
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
@ -367,23 +539,34 @@ static void aspeed_smc_flash_write(void *opaque, hwaddr addr, uint64_t data,
|
|||||||
unsigned size)
|
unsigned size)
|
||||||
{
|
{
|
||||||
AspeedSMCFlash *fl = opaque;
|
AspeedSMCFlash *fl = opaque;
|
||||||
const AspeedSMCState *s = fl->controller;
|
AspeedSMCState *s = fl->controller;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (!aspeed_smc_is_writable(s, fl->id)) {
|
if (!aspeed_smc_is_writable(fl)) {
|
||||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: flash is not writable at 0x%"
|
qemu_log_mask(LOG_GUEST_ERROR, "%s: flash is not writable at 0x%"
|
||||||
HWADDR_PRIx "\n", __func__, addr);
|
HWADDR_PRIx "\n", __func__, addr);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!aspeed_smc_is_usermode(s, fl->id)) {
|
switch (aspeed_smc_flash_mode(fl)) {
|
||||||
qemu_log_mask(LOG_UNIMP, "%s: usermode not implemented\n",
|
case CTRL_USERMODE:
|
||||||
__func__);
|
for (i = 0; i < size; i++) {
|
||||||
return;
|
ssi_transfer(s->spi, (data >> (8 * i)) & 0xff);
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
case CTRL_WRITEMODE:
|
||||||
|
aspeed_smc_flash_select(fl);
|
||||||
|
aspeed_smc_flash_send_addr(fl, addr);
|
||||||
|
|
||||||
for (i = 0; i < size; i++) {
|
for (i = 0; i < size; i++) {
|
||||||
ssi_transfer(s->spi, (data >> (8 * i)) & 0xff);
|
ssi_transfer(s->spi, (data >> (8 * i)) & 0xff);
|
||||||
|
}
|
||||||
|
|
||||||
|
aspeed_smc_flash_unselect(fl);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid flash mode %d\n",
|
||||||
|
__func__, aspeed_smc_flash_mode(fl));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -397,18 +580,11 @@ static const MemoryRegionOps aspeed_smc_flash_ops = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool aspeed_smc_is_ce_stop_active(const AspeedSMCState *s, int cs)
|
static void aspeed_smc_flash_update_cs(AspeedSMCFlash *fl)
|
||||||
{
|
{
|
||||||
return s->regs[s->r_ctrl0 + cs] & CTRL_CE_STOP_ACTIVE;
|
const AspeedSMCState *s = fl->controller;
|
||||||
}
|
|
||||||
|
|
||||||
static void aspeed_smc_update_cs(const AspeedSMCState *s)
|
qemu_set_irq(s->cs_lines[fl->id], aspeed_smc_is_ce_stop_active(fl));
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < s->num_cs; ++i) {
|
|
||||||
qemu_set_irq(s->cs_lines[i], aspeed_smc_is_ce_stop_active(s, i));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void aspeed_smc_reset(DeviceState *d)
|
static void aspeed_smc_reset(DeviceState *d)
|
||||||
@ -424,6 +600,7 @@ static void aspeed_smc_reset(DeviceState *d)
|
|||||||
/* Unselect all slaves */
|
/* Unselect all slaves */
|
||||||
for (i = 0; i < s->num_cs; ++i) {
|
for (i = 0; i < s->num_cs; ++i) {
|
||||||
s->regs[s->r_ctrl0 + i] |= CTRL_CE_STOP_ACTIVE;
|
s->regs[s->r_ctrl0 + i] |= CTRL_CE_STOP_ACTIVE;
|
||||||
|
qemu_set_irq(s->cs_lines[i], true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* setup default segment register values for all */
|
/* setup default segment register values for all */
|
||||||
@ -432,7 +609,24 @@ static void aspeed_smc_reset(DeviceState *d)
|
|||||||
aspeed_smc_segment_to_reg(&s->ctrl->segments[i]);
|
aspeed_smc_segment_to_reg(&s->ctrl->segments[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
aspeed_smc_update_cs(s);
|
/* HW strapping for AST2500 FMC controllers */
|
||||||
|
if (s->ctrl->segments == aspeed_segments_ast2500_fmc) {
|
||||||
|
/* flash type is fixed to SPI for CE0 and CE1 */
|
||||||
|
s->regs[s->r_conf] |= (CONF_FLASH_TYPE_SPI << CONF_FLASH_TYPE0);
|
||||||
|
s->regs[s->r_conf] |= (CONF_FLASH_TYPE_SPI << CONF_FLASH_TYPE1);
|
||||||
|
|
||||||
|
/* 4BYTE mode is autodetected for CE0. Let's force it to 1 for
|
||||||
|
* now */
|
||||||
|
s->regs[s->r_ce_ctrl] |= (1 << (CTRL_EXTENDED0));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* HW strapping for AST2400 FMC controllers (SCU70). Let's use the
|
||||||
|
* configuration of the palmetto-bmc machine */
|
||||||
|
if (s->ctrl->segments == aspeed_segments_fmc) {
|
||||||
|
s->regs[s->r_conf] |= (CONF_FLASH_TYPE_SPI << CONF_FLASH_TYPE0);
|
||||||
|
|
||||||
|
s->regs[s->r_ce_ctrl] |= (1 << (CTRL_EXTENDED0));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint64_t aspeed_smc_read(void *opaque, hwaddr addr, unsigned int size)
|
static uint64_t aspeed_smc_read(void *opaque, hwaddr addr, unsigned int size)
|
||||||
@ -441,13 +635,6 @@ static uint64_t aspeed_smc_read(void *opaque, hwaddr addr, unsigned int size)
|
|||||||
|
|
||||||
addr >>= 2;
|
addr >>= 2;
|
||||||
|
|
||||||
if (addr >= ARRAY_SIZE(s->regs)) {
|
|
||||||
qemu_log_mask(LOG_GUEST_ERROR,
|
|
||||||
"%s: Out-of-bounds read at 0x%" HWADDR_PRIx "\n",
|
|
||||||
__func__, addr);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (addr == s->r_conf ||
|
if (addr == s->r_conf ||
|
||||||
addr == s->r_timings ||
|
addr == s->r_timings ||
|
||||||
addr == s->r_ce_ctrl ||
|
addr == s->r_ce_ctrl ||
|
||||||
@ -470,20 +657,14 @@ static void aspeed_smc_write(void *opaque, hwaddr addr, uint64_t data,
|
|||||||
|
|
||||||
addr >>= 2;
|
addr >>= 2;
|
||||||
|
|
||||||
if (addr >= ARRAY_SIZE(s->regs)) {
|
|
||||||
qemu_log_mask(LOG_GUEST_ERROR,
|
|
||||||
"%s: Out-of-bounds write at 0x%" HWADDR_PRIx "\n",
|
|
||||||
__func__, addr);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (addr == s->r_conf ||
|
if (addr == s->r_conf ||
|
||||||
addr == s->r_timings ||
|
addr == s->r_timings ||
|
||||||
addr == s->r_ce_ctrl) {
|
addr == s->r_ce_ctrl) {
|
||||||
s->regs[addr] = value;
|
s->regs[addr] = value;
|
||||||
} else if (addr >= s->r_ctrl0 && addr < s->r_ctrl0 + s->num_cs) {
|
} else if (addr >= s->r_ctrl0 && addr < s->r_ctrl0 + s->num_cs) {
|
||||||
|
int cs = addr - s->r_ctrl0;
|
||||||
s->regs[addr] = value;
|
s->regs[addr] = value;
|
||||||
aspeed_smc_update_cs(s);
|
aspeed_smc_flash_update_cs(&s->flashes[cs]);
|
||||||
} else if (addr >= R_SEG_ADDR0 &&
|
} else if (addr >= R_SEG_ADDR0 &&
|
||||||
addr < R_SEG_ADDR0 + s->ctrl->max_slaves) {
|
addr < R_SEG_ADDR0 + s->ctrl->max_slaves) {
|
||||||
int cs = addr - R_SEG_ADDR0;
|
int cs = addr - R_SEG_ADDR0;
|
||||||
@ -541,11 +722,9 @@ static void aspeed_smc_realize(DeviceState *dev, Error **errp)
|
|||||||
sysbus_init_irq(sbd, &s->cs_lines[i]);
|
sysbus_init_irq(sbd, &s->cs_lines[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
aspeed_smc_reset(dev);
|
|
||||||
|
|
||||||
/* The memory region for the controller registers */
|
/* The memory region for the controller registers */
|
||||||
memory_region_init_io(&s->mmio, OBJECT(s), &aspeed_smc_ops, s,
|
memory_region_init_io(&s->mmio, OBJECT(s), &aspeed_smc_ops, s,
|
||||||
s->ctrl->name, ASPEED_SMC_R_MAX * 4);
|
s->ctrl->name, s->ctrl->nregs * 4);
|
||||||
sysbus_init_mmio(sbd, &s->mmio);
|
sysbus_init_mmio(sbd, &s->mmio);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -39,6 +39,8 @@
|
|||||||
#define NUM_GICV2M_SPIS 64
|
#define NUM_GICV2M_SPIS 64
|
||||||
#define NUM_VIRTIO_TRANSPORTS 32
|
#define NUM_VIRTIO_TRANSPORTS 32
|
||||||
|
|
||||||
|
#define ARCH_GICV3_MAINT_IRQ 9
|
||||||
|
|
||||||
#define ARCH_TIMER_VIRT_IRQ 11
|
#define ARCH_TIMER_VIRT_IRQ 11
|
||||||
#define ARCH_TIMER_S_EL1_IRQ 13
|
#define ARCH_TIMER_S_EL1_IRQ 13
|
||||||
#define ARCH_TIMER_NS_EL1_IRQ 14
|
#define ARCH_TIMER_NS_EL1_IRQ 14
|
||||||
@ -91,6 +93,7 @@ typedef struct {
|
|||||||
FWCfgState *fw_cfg;
|
FWCfgState *fw_cfg;
|
||||||
bool secure;
|
bool secure;
|
||||||
bool highmem;
|
bool highmem;
|
||||||
|
bool virt;
|
||||||
int32_t gic_version;
|
int32_t gic_version;
|
||||||
struct arm_boot_info bootinfo;
|
struct arm_boot_info bootinfo;
|
||||||
const MemMapEntry *memmap;
|
const MemMapEntry *memmap;
|
||||||
@ -101,7 +104,7 @@ typedef struct {
|
|||||||
uint32_t clock_phandle;
|
uint32_t clock_phandle;
|
||||||
uint32_t gic_phandle;
|
uint32_t gic_phandle;
|
||||||
uint32_t msi_phandle;
|
uint32_t msi_phandle;
|
||||||
bool using_psci;
|
int psci_conduit;
|
||||||
} VirtMachineState;
|
} VirtMachineState;
|
||||||
|
|
||||||
#define TYPE_VIRT_MACHINE MACHINE_TYPE_NAME("virt")
|
#define TYPE_VIRT_MACHINE MACHINE_TYPE_NAME("virt")
|
||||||
|
@ -55,6 +55,8 @@ typedef struct GICState {
|
|||||||
|
|
||||||
qemu_irq parent_irq[GIC_NCPU];
|
qemu_irq parent_irq[GIC_NCPU];
|
||||||
qemu_irq parent_fiq[GIC_NCPU];
|
qemu_irq parent_fiq[GIC_NCPU];
|
||||||
|
qemu_irq parent_virq[GIC_NCPU];
|
||||||
|
qemu_irq parent_vfiq[GIC_NCPU];
|
||||||
/* GICD_CTLR; for a GIC with the security extensions the NS banked version
|
/* GICD_CTLR; for a GIC with the security extensions the NS banked version
|
||||||
* of this register is just an alias of bit 1 of the S banked version.
|
* of this register is just an alias of bit 1 of the S banked version.
|
||||||
*/
|
*/
|
||||||
|
@ -38,6 +38,9 @@
|
|||||||
/* Number of SGI target-list bits */
|
/* Number of SGI target-list bits */
|
||||||
#define GICV3_TARGETLIST_BITS 16
|
#define GICV3_TARGETLIST_BITS 16
|
||||||
|
|
||||||
|
/* Maximum number of list registers (architectural limit) */
|
||||||
|
#define GICV3_LR_MAX 16
|
||||||
|
|
||||||
/* Minimum BPR for Secure, or when security not enabled */
|
/* Minimum BPR for Secure, or when security not enabled */
|
||||||
#define GIC_MIN_BPR 0
|
#define GIC_MIN_BPR 0
|
||||||
/* Minimum BPR for Nonsecure when security is enabled */
|
/* Minimum BPR for Nonsecure when security is enabled */
|
||||||
@ -145,6 +148,9 @@ struct GICv3CPUState {
|
|||||||
CPUState *cpu;
|
CPUState *cpu;
|
||||||
qemu_irq parent_irq;
|
qemu_irq parent_irq;
|
||||||
qemu_irq parent_fiq;
|
qemu_irq parent_fiq;
|
||||||
|
qemu_irq parent_virq;
|
||||||
|
qemu_irq parent_vfiq;
|
||||||
|
qemu_irq maintenance_irq;
|
||||||
|
|
||||||
/* Redistributor */
|
/* Redistributor */
|
||||||
uint32_t level; /* Current IRQ level */
|
uint32_t level; /* Current IRQ level */
|
||||||
@ -173,6 +179,21 @@ struct GICv3CPUState {
|
|||||||
uint64_t icc_igrpen[3];
|
uint64_t icc_igrpen[3];
|
||||||
uint64_t icc_ctlr_el3;
|
uint64_t icc_ctlr_el3;
|
||||||
|
|
||||||
|
/* Virtualization control interface */
|
||||||
|
uint64_t ich_apr[3][4]; /* ich_apr[GICV3_G1][x] never used */
|
||||||
|
uint64_t ich_hcr_el2;
|
||||||
|
uint64_t ich_lr_el2[GICV3_LR_MAX];
|
||||||
|
uint64_t ich_vmcr_el2;
|
||||||
|
|
||||||
|
/* Properties of the CPU interface. These are initialized from
|
||||||
|
* the settings in the CPU proper.
|
||||||
|
* If the number of implemented list registers is 0 then the
|
||||||
|
* virtualization support is not implemented.
|
||||||
|
*/
|
||||||
|
int num_list_regs;
|
||||||
|
int vpribits; /* number of virtual priority bits */
|
||||||
|
int vprebits; /* number of virtual preemption bits */
|
||||||
|
|
||||||
/* Current highest priority pending interrupt for this CPU.
|
/* Current highest priority pending interrupt for this CPU.
|
||||||
* This is cached information that can be recalculated from the
|
* This is cached information that can be recalculated from the
|
||||||
* real state above; it doesn't need to be migrated.
|
* real state above; it doesn't need to be migrated.
|
||||||
|
@ -44,10 +44,12 @@ typedef struct AspeedSMCController {
|
|||||||
const AspeedSegments *segments;
|
const AspeedSegments *segments;
|
||||||
hwaddr flash_window_base;
|
hwaddr flash_window_base;
|
||||||
uint32_t flash_window_size;
|
uint32_t flash_window_size;
|
||||||
|
bool has_dma;
|
||||||
|
uint32_t nregs;
|
||||||
} AspeedSMCController;
|
} AspeedSMCController;
|
||||||
|
|
||||||
typedef struct AspeedSMCFlash {
|
typedef struct AspeedSMCFlash {
|
||||||
const struct AspeedSMCState *controller;
|
struct AspeedSMCState *controller;
|
||||||
|
|
||||||
uint8_t id;
|
uint8_t id;
|
||||||
uint32_t size;
|
uint32_t size;
|
||||||
|
@ -465,6 +465,9 @@ static void arm_cpu_initfn(Object *obj)
|
|||||||
arm_gt_stimer_cb, cpu);
|
arm_gt_stimer_cb, cpu);
|
||||||
qdev_init_gpio_out(DEVICE(cpu), cpu->gt_timer_outputs,
|
qdev_init_gpio_out(DEVICE(cpu), cpu->gt_timer_outputs,
|
||||||
ARRAY_SIZE(cpu->gt_timer_outputs));
|
ARRAY_SIZE(cpu->gt_timer_outputs));
|
||||||
|
|
||||||
|
qdev_init_gpio_out_named(DEVICE(cpu), &cpu->gicv3_maintenance_interrupt,
|
||||||
|
"gicv3-maintenance-interrupt", 1);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* DTB consumers generally don't in fact care what the 'compatible'
|
/* DTB consumers generally don't in fact care what the 'compatible'
|
||||||
@ -493,6 +496,9 @@ static Property arm_cpu_reset_hivecs_property =
|
|||||||
static Property arm_cpu_rvbar_property =
|
static Property arm_cpu_rvbar_property =
|
||||||
DEFINE_PROP_UINT64("rvbar", ARMCPU, rvbar, 0);
|
DEFINE_PROP_UINT64("rvbar", ARMCPU, rvbar, 0);
|
||||||
|
|
||||||
|
static Property arm_cpu_has_el2_property =
|
||||||
|
DEFINE_PROP_BOOL("has_el2", ARMCPU, has_el2, true);
|
||||||
|
|
||||||
static Property arm_cpu_has_el3_property =
|
static Property arm_cpu_has_el3_property =
|
||||||
DEFINE_PROP_BOOL("has_el3", ARMCPU, has_el3, true);
|
DEFINE_PROP_BOOL("has_el3", ARMCPU, has_el3, true);
|
||||||
|
|
||||||
@ -543,6 +549,11 @@ static void arm_cpu_post_init(Object *obj)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (arm_feature(&cpu->env, ARM_FEATURE_EL2)) {
|
||||||
|
qdev_property_add_static(DEVICE(obj), &arm_cpu_has_el2_property,
|
||||||
|
&error_abort);
|
||||||
|
}
|
||||||
|
|
||||||
if (arm_feature(&cpu->env, ARM_FEATURE_PMU)) {
|
if (arm_feature(&cpu->env, ARM_FEATURE_PMU)) {
|
||||||
qdev_property_add_static(DEVICE(obj), &arm_cpu_has_pmu_property,
|
qdev_property_add_static(DEVICE(obj), &arm_cpu_has_pmu_property,
|
||||||
&error_abort);
|
&error_abort);
|
||||||
@ -691,6 +702,10 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
|
|||||||
cpu->id_aa64pfr0 &= ~0xf000;
|
cpu->id_aa64pfr0 &= ~0xf000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!cpu->has_el2) {
|
||||||
|
unset_feature(env, ARM_FEATURE_EL2);
|
||||||
|
}
|
||||||
|
|
||||||
if (!cpu->has_pmu || !kvm_enabled()) {
|
if (!cpu->has_pmu || !kvm_enabled()) {
|
||||||
cpu->has_pmu = false;
|
cpu->has_pmu = false;
|
||||||
unset_feature(env, ARM_FEATURE_PMU);
|
unset_feature(env, ARM_FEATURE_PMU);
|
||||||
|
@ -558,6 +558,8 @@ struct ARMCPU {
|
|||||||
QEMUTimer *gt_timer[NUM_GTIMERS];
|
QEMUTimer *gt_timer[NUM_GTIMERS];
|
||||||
/* GPIO outputs for generic timer */
|
/* GPIO outputs for generic timer */
|
||||||
qemu_irq gt_timer_outputs[NUM_GTIMERS];
|
qemu_irq gt_timer_outputs[NUM_GTIMERS];
|
||||||
|
/* GPIO output for GICv3 maintenance interrupt signal */
|
||||||
|
qemu_irq gicv3_maintenance_interrupt;
|
||||||
|
|
||||||
/* MemoryRegion to use for secure physical accesses */
|
/* MemoryRegion to use for secure physical accesses */
|
||||||
MemoryRegion *secure_memory;
|
MemoryRegion *secure_memory;
|
||||||
@ -575,6 +577,8 @@ struct ARMCPU {
|
|||||||
bool start_powered_off;
|
bool start_powered_off;
|
||||||
/* CPU currently in PSCI powered-off state */
|
/* CPU currently in PSCI powered-off state */
|
||||||
bool powered_off;
|
bool powered_off;
|
||||||
|
/* CPU has virtualization extension */
|
||||||
|
bool has_el2;
|
||||||
/* CPU has security extension */
|
/* CPU has security extension */
|
||||||
bool has_el3;
|
bool has_el3;
|
||||||
/* CPU has PMU (Performance Monitor Unit) */
|
/* CPU has PMU (Performance Monitor Unit) */
|
||||||
@ -660,6 +664,11 @@ struct ARMCPU {
|
|||||||
uint32_t dcz_blocksize;
|
uint32_t dcz_blocksize;
|
||||||
uint64_t rvbar;
|
uint64_t rvbar;
|
||||||
|
|
||||||
|
/* Configurable aspects of GIC cpu interface (which is part of the CPU) */
|
||||||
|
int gic_num_lrs; /* number of list registers */
|
||||||
|
int gic_vpribits; /* number of virtual priority bits */
|
||||||
|
int gic_vprebits; /* number of virtual preemption bits */
|
||||||
|
|
||||||
ARMELChangeHook *el_change_hook;
|
ARMELChangeHook *el_change_hook;
|
||||||
void *el_change_hook_opaque;
|
void *el_change_hook_opaque;
|
||||||
};
|
};
|
||||||
|
@ -110,6 +110,7 @@ static void aarch64_a57_initfn(Object *obj)
|
|||||||
set_feature(&cpu->env, ARM_FEATURE_V8_SHA256);
|
set_feature(&cpu->env, ARM_FEATURE_V8_SHA256);
|
||||||
set_feature(&cpu->env, ARM_FEATURE_V8_PMULL);
|
set_feature(&cpu->env, ARM_FEATURE_V8_PMULL);
|
||||||
set_feature(&cpu->env, ARM_FEATURE_CRC);
|
set_feature(&cpu->env, ARM_FEATURE_CRC);
|
||||||
|
set_feature(&cpu->env, ARM_FEATURE_EL2);
|
||||||
set_feature(&cpu->env, ARM_FEATURE_EL3);
|
set_feature(&cpu->env, ARM_FEATURE_EL3);
|
||||||
set_feature(&cpu->env, ARM_FEATURE_PMU);
|
set_feature(&cpu->env, ARM_FEATURE_PMU);
|
||||||
cpu->kvm_target = QEMU_KVM_ARM_TARGET_CORTEX_A57;
|
cpu->kvm_target = QEMU_KVM_ARM_TARGET_CORTEX_A57;
|
||||||
@ -147,6 +148,9 @@ static void aarch64_a57_initfn(Object *obj)
|
|||||||
cpu->ccsidr[1] = 0x201fe012; /* 48KB L1 icache */
|
cpu->ccsidr[1] = 0x201fe012; /* 48KB L1 icache */
|
||||||
cpu->ccsidr[2] = 0x70ffe07a; /* 2048KB L2 cache */
|
cpu->ccsidr[2] = 0x70ffe07a; /* 2048KB L2 cache */
|
||||||
cpu->dcz_blocksize = 4; /* 64 bytes */
|
cpu->dcz_blocksize = 4; /* 64 bytes */
|
||||||
|
cpu->gic_num_lrs = 4;
|
||||||
|
cpu->gic_vpribits = 5;
|
||||||
|
cpu->gic_vprebits = 5;
|
||||||
define_arm_cp_regs(cpu, cortex_a57_a53_cp_reginfo);
|
define_arm_cp_regs(cpu, cortex_a57_a53_cp_reginfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -166,6 +170,7 @@ static void aarch64_a53_initfn(Object *obj)
|
|||||||
set_feature(&cpu->env, ARM_FEATURE_V8_SHA256);
|
set_feature(&cpu->env, ARM_FEATURE_V8_SHA256);
|
||||||
set_feature(&cpu->env, ARM_FEATURE_V8_PMULL);
|
set_feature(&cpu->env, ARM_FEATURE_V8_PMULL);
|
||||||
set_feature(&cpu->env, ARM_FEATURE_CRC);
|
set_feature(&cpu->env, ARM_FEATURE_CRC);
|
||||||
|
set_feature(&cpu->env, ARM_FEATURE_EL2);
|
||||||
set_feature(&cpu->env, ARM_FEATURE_EL3);
|
set_feature(&cpu->env, ARM_FEATURE_EL3);
|
||||||
set_feature(&cpu->env, ARM_FEATURE_PMU);
|
set_feature(&cpu->env, ARM_FEATURE_PMU);
|
||||||
cpu->kvm_target = QEMU_KVM_ARM_TARGET_CORTEX_A53;
|
cpu->kvm_target = QEMU_KVM_ARM_TARGET_CORTEX_A53;
|
||||||
@ -201,6 +206,9 @@ static void aarch64_a53_initfn(Object *obj)
|
|||||||
cpu->ccsidr[1] = 0x201fe00a; /* 32KB L1 icache */
|
cpu->ccsidr[1] = 0x201fe00a; /* 32KB L1 icache */
|
||||||
cpu->ccsidr[2] = 0x707fe07a; /* 1024KB L2 cache */
|
cpu->ccsidr[2] = 0x707fe07a; /* 1024KB L2 cache */
|
||||||
cpu->dcz_blocksize = 4; /* 64 bytes */
|
cpu->dcz_blocksize = 4; /* 64 bytes */
|
||||||
|
cpu->gic_num_lrs = 4;
|
||||||
|
cpu->gic_vpribits = 5;
|
||||||
|
cpu->gic_vprebits = 5;
|
||||||
define_arm_cp_regs(cpu, cortex_a57_a53_cp_reginfo);
|
define_arm_cp_regs(cpu, cortex_a57_a53_cp_reginfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4066,6 +4066,13 @@ static const ARMCPRegInfo debug_cp_reginfo[] = {
|
|||||||
.cp = 14, .opc1 = 0, .crn = 0, .crm = 7, .opc2 = 0,
|
.cp = 14, .opc1 = 0, .crn = 0, .crm = 7, .opc2 = 0,
|
||||||
.access = PL1_RW, .accessfn = access_tda,
|
.access = PL1_RW, .accessfn = access_tda,
|
||||||
.type = ARM_CP_NOP },
|
.type = ARM_CP_NOP },
|
||||||
|
/* Dummy DBGVCR32_EL2 (which is only for a 64-bit hypervisor
|
||||||
|
* to save and restore a 32-bit guest's DBGVCR)
|
||||||
|
*/
|
||||||
|
{ .name = "DBGVCR32_EL2", .state = ARM_CP_STATE_AA64,
|
||||||
|
.opc0 = 2, .opc1 = 4, .crn = 0, .crm = 7, .opc2 = 0,
|
||||||
|
.access = PL2_RW, .accessfn = access_tda,
|
||||||
|
.type = ARM_CP_NOP },
|
||||||
/* Dummy MDCCINT_EL1, since we don't implement the Debug Communications
|
/* Dummy MDCCINT_EL1, since we don't implement the Debug Communications
|
||||||
* Channel but Linux may try to access this register. The 32-bit
|
* Channel but Linux may try to access this register. The 32-bit
|
||||||
* alias is DBGDCCINT.
|
* alias is DBGDCCINT.
|
||||||
@ -6399,6 +6406,20 @@ static void arm_cpu_do_interrupt_aarch32(CPUState *cs)
|
|||||||
}
|
}
|
||||||
offset = 4;
|
offset = 4;
|
||||||
break;
|
break;
|
||||||
|
case EXCP_VIRQ:
|
||||||
|
new_mode = ARM_CPU_MODE_IRQ;
|
||||||
|
addr = 0x18;
|
||||||
|
/* Disable IRQ and imprecise data aborts. */
|
||||||
|
mask = CPSR_A | CPSR_I;
|
||||||
|
offset = 4;
|
||||||
|
break;
|
||||||
|
case EXCP_VFIQ:
|
||||||
|
new_mode = ARM_CPU_MODE_FIQ;
|
||||||
|
addr = 0x1c;
|
||||||
|
/* Disable FIQ, IRQ and imprecise data aborts. */
|
||||||
|
mask = CPSR_A | CPSR_I | CPSR_F;
|
||||||
|
offset = 4;
|
||||||
|
break;
|
||||||
case EXCP_SMC:
|
case EXCP_SMC:
|
||||||
new_mode = ARM_CPU_MODE_MON;
|
new_mode = ARM_CPU_MODE_MON;
|
||||||
addr = 0x08;
|
addr = 0x08;
|
||||||
|
@ -148,17 +148,28 @@ void arm_handle_psci_call(ARMCPU *cpu)
|
|||||||
case QEMU_PSCI_0_1_FN_CPU_ON:
|
case QEMU_PSCI_0_1_FN_CPU_ON:
|
||||||
case QEMU_PSCI_0_2_FN_CPU_ON:
|
case QEMU_PSCI_0_2_FN_CPU_ON:
|
||||||
case QEMU_PSCI_0_2_FN64_CPU_ON:
|
case QEMU_PSCI_0_2_FN64_CPU_ON:
|
||||||
|
{
|
||||||
|
/* The PSCI spec mandates that newly brought up CPUs start
|
||||||
|
* in the highest exception level which exists and is enabled
|
||||||
|
* on the calling CPU. Since the QEMU PSCI implementation is
|
||||||
|
* acting as a "fake EL3" or "fake EL2" firmware, this for us
|
||||||
|
* means that we want to start at the highest NS exception level
|
||||||
|
* that we are providing to the guest.
|
||||||
|
* The execution mode should be that which is currently in use
|
||||||
|
* by the same exception level on the calling CPU.
|
||||||
|
* The CPU should be started with the context_id value
|
||||||
|
* in x0 (if AArch64) or r0 (if AArch32).
|
||||||
|
*/
|
||||||
|
int target_el = arm_feature(env, ARM_FEATURE_EL2) ? 2 : 1;
|
||||||
|
bool target_aarch64 = arm_el_is_aa64(env, target_el);
|
||||||
|
|
||||||
mpidr = param[1];
|
mpidr = param[1];
|
||||||
entry = param[2];
|
entry = param[2];
|
||||||
context_id = param[3];
|
context_id = param[3];
|
||||||
/*
|
ret = arm_set_cpu_on(mpidr, entry, context_id,
|
||||||
* The PSCI spec mandates that newly brought up CPUs enter the
|
target_el, target_aarch64);
|
||||||
* exception level of the caller in the same execution mode as
|
|
||||||
* the caller, with context_id in x0/r0, respectively.
|
|
||||||
*/
|
|
||||||
ret = arm_set_cpu_on(mpidr, entry, context_id, arm_current_el(env),
|
|
||||||
is_a64(env));
|
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case QEMU_PSCI_0_1_FN_CPU_OFF:
|
case QEMU_PSCI_0_1_FN_CPU_OFF:
|
||||||
case QEMU_PSCI_0_2_FN_CPU_OFF:
|
case QEMU_PSCI_0_2_FN_CPU_OFF:
|
||||||
goto cpu_off;
|
goto cpu_off;
|
||||||
|
@ -36,6 +36,9 @@
|
|||||||
#define CRTL_EXTENDED0 0 /* 32 bit addressing for SPI */
|
#define CRTL_EXTENDED0 0 /* 32 bit addressing for SPI */
|
||||||
#define R_CTRL0 0x10
|
#define R_CTRL0 0x10
|
||||||
#define CTRL_CE_STOP_ACTIVE (1 << 2)
|
#define CTRL_CE_STOP_ACTIVE (1 << 2)
|
||||||
|
#define CTRL_READMODE 0x0
|
||||||
|
#define CTRL_FREADMODE 0x1
|
||||||
|
#define CTRL_WRITEMODE 0x2
|
||||||
#define CTRL_USERMODE 0x3
|
#define CTRL_USERMODE 0x3
|
||||||
|
|
||||||
#define ASPEED_FMC_BASE 0x1E620000
|
#define ASPEED_FMC_BASE 0x1E620000
|
||||||
@ -50,6 +53,8 @@ enum {
|
|||||||
READ = 0x03,
|
READ = 0x03,
|
||||||
PP = 0x02,
|
PP = 0x02,
|
||||||
WREN = 0x6,
|
WREN = 0x6,
|
||||||
|
RESET_ENABLE = 0x66,
|
||||||
|
RESET_MEMORY = 0x99,
|
||||||
EN_4BYTE_ADDR = 0xB7,
|
EN_4BYTE_ADDR = 0xB7,
|
||||||
ERASE_SECTOR = 0xd8,
|
ERASE_SECTOR = 0xd8,
|
||||||
};
|
};
|
||||||
@ -76,6 +81,30 @@ static void spi_conf(uint32_t value)
|
|||||||
writel(ASPEED_FMC_BASE + R_CONF, conf);
|
writel(ASPEED_FMC_BASE + R_CONF, conf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void spi_conf_remove(uint32_t value)
|
||||||
|
{
|
||||||
|
uint32_t conf = readl(ASPEED_FMC_BASE + R_CONF);
|
||||||
|
|
||||||
|
conf &= ~value;
|
||||||
|
writel(ASPEED_FMC_BASE + R_CONF, conf);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void spi_ce_ctrl(uint32_t value)
|
||||||
|
{
|
||||||
|
uint32_t conf = readl(ASPEED_FMC_BASE + R_CE_CTRL);
|
||||||
|
|
||||||
|
conf |= value;
|
||||||
|
writel(ASPEED_FMC_BASE + R_CE_CTRL, conf);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void spi_ctrl_setmode(uint8_t mode, uint8_t cmd)
|
||||||
|
{
|
||||||
|
uint32_t ctrl = readl(ASPEED_FMC_BASE + R_CTRL0);
|
||||||
|
ctrl &= ~(CTRL_USERMODE | 0xff << 16);
|
||||||
|
ctrl |= mode | (cmd << 16);
|
||||||
|
writel(ASPEED_FMC_BASE + R_CTRL0, ctrl);
|
||||||
|
}
|
||||||
|
|
||||||
static void spi_ctrl_start_user(void)
|
static void spi_ctrl_start_user(void)
|
||||||
{
|
{
|
||||||
uint32_t ctrl = readl(ASPEED_FMC_BASE + R_CTRL0);
|
uint32_t ctrl = readl(ASPEED_FMC_BASE + R_CTRL0);
|
||||||
@ -95,6 +124,18 @@ static void spi_ctrl_stop_user(void)
|
|||||||
writel(ASPEED_FMC_BASE + R_CTRL0, ctrl);
|
writel(ASPEED_FMC_BASE + R_CTRL0, ctrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void flash_reset(void)
|
||||||
|
{
|
||||||
|
spi_conf(CONF_ENABLE_W0);
|
||||||
|
|
||||||
|
spi_ctrl_start_user();
|
||||||
|
writeb(ASPEED_FLASH_BASE, RESET_ENABLE);
|
||||||
|
writeb(ASPEED_FLASH_BASE, RESET_MEMORY);
|
||||||
|
spi_ctrl_stop_user();
|
||||||
|
|
||||||
|
spi_conf_remove(CONF_ENABLE_W0);
|
||||||
|
}
|
||||||
|
|
||||||
static void test_read_jedec(void)
|
static void test_read_jedec(void)
|
||||||
{
|
{
|
||||||
uint32_t jedec = 0x0;
|
uint32_t jedec = 0x0;
|
||||||
@ -108,6 +149,8 @@ static void test_read_jedec(void)
|
|||||||
jedec |= readb(ASPEED_FLASH_BASE);
|
jedec |= readb(ASPEED_FLASH_BASE);
|
||||||
spi_ctrl_stop_user();
|
spi_ctrl_stop_user();
|
||||||
|
|
||||||
|
flash_reset();
|
||||||
|
|
||||||
g_assert_cmphex(jedec, ==, FLASH_JEDEC);
|
g_assert_cmphex(jedec, ==, FLASH_JEDEC);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -128,6 +171,18 @@ static void read_page(uint32_t addr, uint32_t *page)
|
|||||||
spi_ctrl_stop_user();
|
spi_ctrl_stop_user();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void read_page_mem(uint32_t addr, uint32_t *page)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* move out USER mode to use direct reads from the AHB bus */
|
||||||
|
spi_ctrl_setmode(CTRL_READMODE, READ);
|
||||||
|
|
||||||
|
for (i = 0; i < PAGE_SIZE / 4; i++) {
|
||||||
|
page[i] = make_be32(readl(ASPEED_FLASH_BASE + addr + i * 4));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void test_erase_sector(void)
|
static void test_erase_sector(void)
|
||||||
{
|
{
|
||||||
uint32_t some_page_addr = 0x600 * PAGE_SIZE;
|
uint32_t some_page_addr = 0x600 * PAGE_SIZE;
|
||||||
@ -155,6 +210,8 @@ static void test_erase_sector(void)
|
|||||||
for (i = 0; i < PAGE_SIZE / 4; i++) {
|
for (i = 0; i < PAGE_SIZE / 4; i++) {
|
||||||
g_assert_cmphex(page[i], ==, 0xffffffff);
|
g_assert_cmphex(page[i], ==, 0xffffffff);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
flash_reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_erase_all(void)
|
static void test_erase_all(void)
|
||||||
@ -182,6 +239,8 @@ static void test_erase_all(void)
|
|||||||
for (i = 0; i < PAGE_SIZE / 4; i++) {
|
for (i = 0; i < PAGE_SIZE / 4; i++) {
|
||||||
g_assert_cmphex(page[i], ==, 0xffffffff);
|
g_assert_cmphex(page[i], ==, 0xffffffff);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
flash_reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_write_page(void)
|
static void test_write_page(void)
|
||||||
@ -195,6 +254,7 @@ static void test_write_page(void)
|
|||||||
|
|
||||||
spi_ctrl_start_user();
|
spi_ctrl_start_user();
|
||||||
writeb(ASPEED_FLASH_BASE, EN_4BYTE_ADDR);
|
writeb(ASPEED_FLASH_BASE, EN_4BYTE_ADDR);
|
||||||
|
writeb(ASPEED_FLASH_BASE, WREN);
|
||||||
writeb(ASPEED_FLASH_BASE, PP);
|
writeb(ASPEED_FLASH_BASE, PP);
|
||||||
writel(ASPEED_FLASH_BASE, make_be32(my_page_addr));
|
writel(ASPEED_FLASH_BASE, make_be32(my_page_addr));
|
||||||
|
|
||||||
@ -215,6 +275,77 @@ static void test_write_page(void)
|
|||||||
for (i = 0; i < PAGE_SIZE / 4; i++) {
|
for (i = 0; i < PAGE_SIZE / 4; i++) {
|
||||||
g_assert_cmphex(page[i], ==, 0xffffffff);
|
g_assert_cmphex(page[i], ==, 0xffffffff);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
flash_reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_read_page_mem(void)
|
||||||
|
{
|
||||||
|
uint32_t my_page_addr = 0x14000 * PAGE_SIZE; /* beyond 16MB */
|
||||||
|
uint32_t some_page_addr = 0x15000 * PAGE_SIZE;
|
||||||
|
uint32_t page[PAGE_SIZE / 4];
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* Enable 4BYTE mode for controller. This is should be strapped by
|
||||||
|
* HW for CE0 anyhow.
|
||||||
|
*/
|
||||||
|
spi_ce_ctrl(1 << CRTL_EXTENDED0);
|
||||||
|
|
||||||
|
/* Enable 4BYTE mode for flash. */
|
||||||
|
spi_conf(CONF_ENABLE_W0);
|
||||||
|
spi_ctrl_start_user();
|
||||||
|
writeb(ASPEED_FLASH_BASE, EN_4BYTE_ADDR);
|
||||||
|
spi_ctrl_stop_user();
|
||||||
|
spi_conf_remove(CONF_ENABLE_W0);
|
||||||
|
|
||||||
|
/* Check what was written */
|
||||||
|
read_page_mem(my_page_addr, page);
|
||||||
|
for (i = 0; i < PAGE_SIZE / 4; i++) {
|
||||||
|
g_assert_cmphex(page[i], ==, my_page_addr + i * 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check some other page. It should be full of 0xff */
|
||||||
|
read_page_mem(some_page_addr, page);
|
||||||
|
for (i = 0; i < PAGE_SIZE / 4; i++) {
|
||||||
|
g_assert_cmphex(page[i], ==, 0xffffffff);
|
||||||
|
}
|
||||||
|
|
||||||
|
flash_reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_write_page_mem(void)
|
||||||
|
{
|
||||||
|
uint32_t my_page_addr = 0x15000 * PAGE_SIZE;
|
||||||
|
uint32_t page[PAGE_SIZE / 4];
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* Enable 4BYTE mode for controller. This is should be strapped by
|
||||||
|
* HW for CE0 anyhow.
|
||||||
|
*/
|
||||||
|
spi_ce_ctrl(1 << CRTL_EXTENDED0);
|
||||||
|
|
||||||
|
/* Enable 4BYTE mode for flash. */
|
||||||
|
spi_conf(CONF_ENABLE_W0);
|
||||||
|
spi_ctrl_start_user();
|
||||||
|
writeb(ASPEED_FLASH_BASE, EN_4BYTE_ADDR);
|
||||||
|
writeb(ASPEED_FLASH_BASE, WREN);
|
||||||
|
spi_ctrl_stop_user();
|
||||||
|
|
||||||
|
/* move out USER mode to use direct writes to the AHB bus */
|
||||||
|
spi_ctrl_setmode(CTRL_WRITEMODE, PP);
|
||||||
|
|
||||||
|
for (i = 0; i < PAGE_SIZE / 4; i++) {
|
||||||
|
writel(ASPEED_FLASH_BASE + my_page_addr + i * 4,
|
||||||
|
make_be32(my_page_addr + i * 4));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check what was written */
|
||||||
|
read_page_mem(my_page_addr, page);
|
||||||
|
for (i = 0; i < PAGE_SIZE / 4; i++) {
|
||||||
|
g_assert_cmphex(page[i], ==, my_page_addr + i * 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
flash_reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
static char tmp_path[] = "/tmp/qtest.m25p80.XXXXXX";
|
static char tmp_path[] = "/tmp/qtest.m25p80.XXXXXX";
|
||||||
@ -242,6 +373,8 @@ int main(int argc, char **argv)
|
|||||||
qtest_add_func("/m25p80/erase_sector", test_erase_sector);
|
qtest_add_func("/m25p80/erase_sector", test_erase_sector);
|
||||||
qtest_add_func("/m25p80/erase_all", test_erase_all);
|
qtest_add_func("/m25p80/erase_all", test_erase_all);
|
||||||
qtest_add_func("/m25p80/write_page", test_write_page);
|
qtest_add_func("/m25p80/write_page", test_write_page);
|
||||||
|
qtest_add_func("/m25p80/read_page_mem", test_read_page_mem);
|
||||||
|
qtest_add_func("/m25p80/write_page_mem", test_write_page_mem);
|
||||||
|
|
||||||
ret = g_test_run();
|
ret = g_test_run();
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user