1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
|
/*
* Raspberry Pi 4B emulation
*
* Copyright (C) 2022 Ovchinnikov Vitalii <vitalii.ovchinnikov@auriga.com>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "qemu/osdep.h"
#include "qemu/units.h"
#include "qemu/cutils.h"
#include "qapi/error.h"
#include "qapi/visitor.h"
#include "hw/arm/raspi_platform.h"
#include "hw/display/bcm2835_fb.h"
#include "hw/registerfields.h"
#include "qemu/error-report.h"
#include "system/device_tree.h"
#include "hw/boards.h"
#include "hw/loader.h"
#include "hw/arm/boot.h"
#include "qom/object.h"
#include "hw/arm/bcm2838.h"
#include <libfdt.h>
#define TYPE_RASPI4B_MACHINE MACHINE_TYPE_NAME("raspi4b")
OBJECT_DECLARE_SIMPLE_TYPE(Raspi4bMachineState, RASPI4B_MACHINE)
struct Raspi4bMachineState {
RaspiBaseMachineState parent_obj;
BCM2838State soc;
};
/*
* Add second memory region if board RAM amount exceeds VC base address
* (see https://datasheets.raspberrypi.com/bcm2711/bcm2711-peripherals.pdf
* 1.2 Address Map)
*/
static int raspi_add_memory_node(void *fdt, hwaddr mem_base, hwaddr mem_len)
{
int ret;
uint32_t acells, scells;
char *nodename = g_strdup_printf("/memory@%" PRIx64, mem_base);
acells = qemu_fdt_getprop_cell(fdt, "/", "#address-cells",
NULL, &error_fatal);
scells = qemu_fdt_getprop_cell(fdt, "/", "#size-cells",
NULL, &error_fatal);
if (acells == 0 || scells == 0) {
fprintf(stderr, "dtb file invalid (#address-cells or #size-cells 0)\n");
ret = -1;
} else {
qemu_fdt_add_subnode(fdt, nodename);
qemu_fdt_setprop_string(fdt, nodename, "device_type", "memory");
ret = qemu_fdt_setprop_sized_cells(fdt, nodename, "reg",
acells, mem_base,
scells, mem_len);
}
g_free(nodename);
return ret;
}
static void raspi4_modify_dtb(const struct arm_boot_info *info, void *fdt)
{
uint64_t ram_size;
/* Temporarily disable following devices until they are implemented */
const char *nodes_to_remove[] = {
"brcm,bcm2711-pcie",
"brcm,bcm2711-rng200",
"brcm,bcm2711-thermal",
"brcm,bcm2711-genet-v5",
};
for (int i = 0; i < ARRAY_SIZE(nodes_to_remove); i++) {
const char *dev_str = nodes_to_remove[i];
int offset = fdt_node_offset_by_compatible(fdt, -1, dev_str);
if (offset >= 0) {
if (!fdt_nop_node(fdt, offset)) {
warn_report("bcm2711 dtc: %s has been disabled!", dev_str);
}
}
}
ram_size = board_ram_size(info->board_id);
if (info->ram_size > UPPER_RAM_BASE) {
raspi_add_memory_node(fdt, UPPER_RAM_BASE, ram_size - UPPER_RAM_BASE);
}
}
static void raspi4b_machine_init(MachineState *machine)
{
Raspi4bMachineState *s = RASPI4B_MACHINE(machine);
RaspiBaseMachineState *s_base = RASPI_BASE_MACHINE(machine);
RaspiBaseMachineClass *mc = RASPI_BASE_MACHINE_GET_CLASS(machine);
BCM2838State *soc = &s->soc;
s_base->binfo.modify_dtb = raspi4_modify_dtb;
s_base->binfo.board_id = mc->board_rev;
object_initialize_child(OBJECT(machine), "soc", soc,
board_soc_type(mc->board_rev));
raspi_base_machine_init(machine, &soc->parent_obj);
}
static void raspi4b_machine_class_init(ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
RaspiBaseMachineClass *rmc = RASPI_BASE_MACHINE_CLASS(oc);
#if HOST_LONG_BITS == 32
rmc->board_rev = 0xa03111; /* Revision 1.1, 1 Gb RAM */
#else
rmc->board_rev = 0xb03115; /* Revision 1.5, 2 Gb RAM */
#endif
raspi_machine_class_common_init(mc, rmc->board_rev);
mc->auto_create_sdcard = true;
mc->init = raspi4b_machine_init;
}
static const TypeInfo raspi4b_machine_type = {
.name = TYPE_RASPI4B_MACHINE,
.parent = TYPE_RASPI_BASE_MACHINE,
.instance_size = sizeof(Raspi4bMachineState),
.class_init = raspi4b_machine_class_init,
};
static void raspi4b_machine_register_type(void)
{
type_register_static(&raspi4b_machine_type);
}
type_init(raspi4b_machine_register_type)
|