summaryrefslogtreecommitdiff
path: root/hw/arm/raspi.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/arm/raspi.c')
-rw-r--r--hw/arm/raspi.c77
1 files changed, 62 insertions, 15 deletions
diff --git a/hw/arm/raspi.c b/hw/arm/raspi.c
index a37881433c..06f1e08ca9 100644
--- a/hw/arm/raspi.c
+++ b/hw/arm/raspi.c
@@ -27,12 +27,13 @@
#define BOARDSETUP_ADDR (MVBAR_ADDR + 0x20) /* board setup code */
#define FIRMWARE_ADDR_2 0x8000 /* Pi 2 loads kernel.img here by default */
#define FIRMWARE_ADDR_3 0x80000 /* Pi 3 loads kernel.img here by default */
+#define SPINTABLE_ADDR 0xd8 /* Pi 3 bootloader spintable */
/* Table of Linux board IDs for different Pi versions */
static const int raspi_boardid[] = {[1] = 0xc42, [2] = 0xc43, [3] = 0xc44};
typedef struct RasPiState {
- BCM2836State soc;
+ BCM283XState soc;
MemoryRegion ram;
} RasPiState;
@@ -63,6 +64,40 @@ static void write_smpboot(ARMCPU *cpu, const struct arm_boot_info *info)
info->smp_loader_start);
}
+static void write_smpboot64(ARMCPU *cpu, const struct arm_boot_info *info)
+{
+ /* Unlike the AArch32 version we don't need to call the board setup hook.
+ * The mechanism for doing the spin-table is also entirely different.
+ * We must have four 64-bit fields at absolute addresses
+ * 0xd8, 0xe0, 0xe8, 0xf0 in RAM, which are the flag variables for
+ * our CPUs, and which we must ensure are zero initialized before
+ * the primary CPU goes into the kernel. We put these variables inside
+ * a rom blob, so that the reset for ROM contents zeroes them for us.
+ */
+ static const uint32_t smpboot[] = {
+ 0xd2801b05, /* mov x5, 0xd8 */
+ 0xd53800a6, /* mrs x6, mpidr_el1 */
+ 0x924004c6, /* and x6, x6, #0x3 */
+ 0xd503205f, /* spin: wfe */
+ 0xf86678a4, /* ldr x4, [x5,x6,lsl #3] */
+ 0xb4ffffc4, /* cbz x4, spin */
+ 0xd2800000, /* mov x0, #0x0 */
+ 0xd2800001, /* mov x1, #0x0 */
+ 0xd2800002, /* mov x2, #0x0 */
+ 0xd2800003, /* mov x3, #0x0 */
+ 0xd61f0080, /* br x4 */
+ };
+
+ static const uint64_t spintables[] = {
+ 0, 0, 0, 0
+ };
+
+ rom_add_blob_fixed("raspi_smpboot", smpboot, sizeof(smpboot),
+ info->smp_loader_start);
+ rom_add_blob_fixed("raspi_spintables", spintables, sizeof(spintables),
+ SPINTABLE_ADDR);
+}
+
static void write_board_setup(ARMCPU *cpu, const struct arm_boot_info *info)
{
arm_write_secure_board_setup_dummy_smc(cpu, info, MVBAR_ADDR);
@@ -82,15 +117,28 @@ static void setup_boot(MachineState *machine, int version, size_t ram_size)
binfo.board_id = raspi_boardid[version];
binfo.ram_size = ram_size;
binfo.nb_cpus = smp_cpus;
- binfo.board_setup_addr = BOARDSETUP_ADDR;
- binfo.write_board_setup = write_board_setup;
- binfo.secure_board_setup = true;
- binfo.secure_boot = true;
+
+ if (version <= 2) {
+ /* The rpi1 and 2 require some custom setup code to run in Secure
+ * mode before booting a kernel (to set up the SMC vectors so
+ * that we get a no-op SMC; this is used by Linux to call the
+ * firmware for some cache maintenance operations.
+ * The rpi3 doesn't need this.
+ */
+ binfo.board_setup_addr = BOARDSETUP_ADDR;
+ binfo.write_board_setup = write_board_setup;
+ binfo.secure_board_setup = true;
+ binfo.secure_boot = true;
+ }
/* Pi2 and Pi3 requires SMP setup */
if (version >= 2) {
binfo.smp_loader_start = SMPBOOT_ADDR;
- binfo.write_secondary_boot = write_smpboot;
+ if (version == 2) {
+ binfo.write_secondary_boot = write_smpboot;
+ } else {
+ binfo.write_secondary_boot = write_smpboot64;
+ }
binfo.secondary_cpu_reset_hook = reset_secondary;
}
@@ -127,7 +175,8 @@ static void raspi_init(MachineState *machine, int version)
BusState *bus;
DeviceState *carddev;
- object_initialize(&s->soc, sizeof(s->soc), TYPE_BCM2836);
+ object_initialize(&s->soc, sizeof(s->soc),
+ version == 3 ? TYPE_BCM2837 : TYPE_BCM2836);
object_property_add_child(OBJECT(machine), "soc", OBJECT(&s->soc),
&error_abort);
@@ -140,8 +189,6 @@ static void raspi_init(MachineState *machine, int version)
/* Setup the SOC */
object_property_add_const_link(OBJECT(&s->soc), "ram", OBJECT(&s->ram),
&error_abort);
- object_property_set_str(OBJECT(&s->soc), machine->cpu_type, "cpu-type",
- &error_abort);
object_property_set_int(OBJECT(&s->soc), smp_cpus, "enabled-cpus",
&error_abort);
int board_rev = version == 3 ? 0xa02082 : 0xa21041;
@@ -180,9 +227,9 @@ static void raspi2_machine_init(MachineClass *mc)
mc->no_floppy = 1;
mc->no_cdrom = 1;
mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-a15");
- mc->max_cpus = BCM2836_NCPUS;
- mc->min_cpus = BCM2836_NCPUS;
- mc->default_cpus = BCM2836_NCPUS;
+ mc->max_cpus = BCM283X_NCPUS;
+ mc->min_cpus = BCM283X_NCPUS;
+ mc->default_cpus = BCM283X_NCPUS;
mc->default_ram_size = 1024 * 1024 * 1024;
mc->ignore_memory_transaction_failures = true;
};
@@ -203,9 +250,9 @@ static void raspi3_machine_init(MachineClass *mc)
mc->no_floppy = 1;
mc->no_cdrom = 1;
mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-a53");
- mc->max_cpus = BCM2836_NCPUS;
- mc->min_cpus = BCM2836_NCPUS;
- mc->default_cpus = BCM2836_NCPUS;
+ mc->max_cpus = BCM283X_NCPUS;
+ mc->min_cpus = BCM283X_NCPUS;
+ mc->default_cpus = BCM283X_NCPUS;
mc->default_ram_size = 1024 * 1024 * 1024;
}
DEFINE_MACHINE("raspi3", raspi3_machine_init)