summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/platform/generic.md42
-rw-r--r--docs/platform/platform.md6
-rw-r--r--platform/generic/config.mk40
-rw-r--r--platform/generic/include/platform_override.h26
-rw-r--r--platform/generic/objects.mk10
-rw-r--r--platform/generic/platform.c209
6 files changed, 333 insertions, 0 deletions
diff --git a/docs/platform/generic.md b/docs/platform/generic.md
new file mode 100644
index 0000000..73b6fca
--- /dev/null
+++ b/docs/platform/generic.md
@@ -0,0 +1,42 @@
+Generic Platform
+================
+
+The **Generic** platform is a flattened device tree (FDT) based platform
+where all platform specific functionality is provided based on FDT passed
+by previous booting stage. The **Generic** platform allows us to use same
+OpenSBI firmware binaries on various emulators, simulators, FPGAs, and
+boards.
+
+By default, the generic FDT platform makes following assumptions:
+
+1. platform FW_TEXT_START is 0x80000000
+2. platform features are default
+3. platform stack size is default
+4. platform has no quirks or work-arounds
+
+The above assumptions (except 1) can be overridden by adding special platform
+callbacks which will be called based on FDT root node compatible string.
+
+Users of the generic FDT platform will have to ensure that:
+
+1. Various FDT based drivers under lib/utils directory are upto date
+ based on their platform requirements
+2. The FDT passed by previous booting stage has DT compatible strings and
+ DT properties in sync with the FDT based drivers under lib/utils directory
+
+To build the platform-specific library and firmware images, provide the
+*PLATFORM=generic* parameter to the top level `make` command.
+
+For custom FW_TEXT_START, we can build the platform-specific library and
+firmware images by passing *PLATFORM=generic FW_TEXT_START=<custom_text_start>*
+parameter to the top level `make` command.
+
+Platform Options
+----------------
+
+The *Generic* platform does not have any platform-specific options.
+
+RISC-V Platforms Using Generic Platform
+---------------------------------------
+
+To be added later.
diff --git a/docs/platform/platform.md b/docs/platform/platform.md
index 5580283..c8f6ade 100644
--- a/docs/platform/platform.md
+++ b/docs/platform/platform.md
@@ -3,6 +3,11 @@ OpenSBI Supported Platforms
OpenSBI currently supports the following virtual and hardware platforms:
+* **Generic**: Flattened device tree (FDT) based platform where platform
+ specific functionality is provided based on the FDT passed by previous
+ booting stage. More details on this platform can be found in the file
+ *[generic.md]*.
+
* **QEMU RISC-V Virt Machine**: Platform support for the QEMU *virt* virtual
RISC-V machine. This virtual machine is intended for RISC-V software
development and tests. More details on this platform can be found in the
@@ -34,6 +39,7 @@ template files for implementing support for a new platform. The *object.mk*,
*config.mk* and *platform.c* template files provides enough comments to
facilitate the implementation.
+[generic.md]: generic.md
[qemu_virt.md]: qemu_virt.md
[sifive_fu540.md]: sifive_fu540.md
[fpga-ariane.md]: fpga-ariane.md
diff --git a/platform/generic/config.mk b/platform/generic/config.mk
new file mode 100644
index 0000000..8d63ece
--- /dev/null
+++ b/platform/generic/config.mk
@@ -0,0 +1,40 @@
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+# Copyright (c) 2020 Western Digital Corporation or its affiliates.
+#
+# Authors:
+# Anup Patel <anup.patel@wdc.com>
+#
+
+# Compiler flags
+platform-cppflags-y =
+platform-cflags-y =
+platform-asflags-y =
+platform-ldflags-y =
+
+# Command for platform specific "make run"
+platform-runcmd = qemu-system-riscv$(PLATFORM_RISCV_XLEN) -M virt -m 256M \
+ -nographic -kernel $(build_dir)/platform/generic/firmware/fw_payload.elf
+
+# Blobs to build
+FW_TEXT_START=0x80000000
+FW_DYNAMIC=y
+FW_JUMP=y
+ifeq ($(PLATFORM_RISCV_XLEN), 32)
+ # This needs to be 4MB aligned for 32-bit system
+ FW_JUMP_ADDR=$(shell printf "0x%X" $$(($(FW_TEXT_START) + 0x400000)))
+else
+ # This needs to be 2MB aligned for 64-bit system
+ FW_JUMP_ADDR=$(shell printf "0x%X" $$(($(FW_TEXT_START) + 0x200000)))
+endif
+FW_JUMP_FDT_ADDR=$(shell printf "0x%X" $$(($(FW_TEXT_START) + 0x2200000)))
+FW_PAYLOAD=y
+ifeq ($(PLATFORM_RISCV_XLEN), 32)
+ # This needs to be 4MB aligned for 32-bit system
+ FW_PAYLOAD_OFFSET=0x400000
+else
+ # This needs to be 2MB aligned for 64-bit system
+ FW_PAYLOAD_OFFSET=0x200000
+endif
+FW_PAYLOAD_FDT_ADDR=$(FW_JUMP_FDT_ADDR)
diff --git a/platform/generic/include/platform_override.h b/platform/generic/include/platform_override.h
new file mode 100644
index 0000000..1262627
--- /dev/null
+++ b/platform/generic/include/platform_override.h
@@ -0,0 +1,26 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2020 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#ifndef __PLATFORM_OVERRIDE_H__
+#define __PLATFORM_OVERRIDE_H__
+
+#include <sbi/sbi_types.h>
+
+struct platform_override {
+ const struct fdt_match *match_table;
+ u64 (*features)(const struct fdt_match *match);
+ u64 (*tlbr_flush_limit)(const struct fdt_match *match);
+ int (*early_init)(bool cold_boot, const struct fdt_match *match);
+ int (*final_init)(bool cold_boot, const struct fdt_match *match);
+ void (*early_exit)(const struct fdt_match *match);
+ void (*final_exit)(const struct fdt_match *match);
+ int (*system_reset)(u32 reset_type, const struct fdt_match *match);
+};
+
+#endif
diff --git a/platform/generic/objects.mk b/platform/generic/objects.mk
new file mode 100644
index 0000000..5ed4437
--- /dev/null
+++ b/platform/generic/objects.mk
@@ -0,0 +1,10 @@
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+# Copyright (c) 2020 Western Digital Corporation or its affiliates.
+#
+# Authors:
+# Anup Patel <anup.patel@wdc.com>
+#
+
+platform-objs-y += platform.o
diff --git a/platform/generic/platform.c b/platform/generic/platform.c
new file mode 100644
index 0000000..cb16cc4
--- /dev/null
+++ b/platform/generic/platform.c
@@ -0,0 +1,209 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2020 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#include <libfdt.h>
+#include <platform_override.h>
+#include <sbi/riscv_asm.h>
+#include <sbi/sbi_hartmask.h>
+#include <sbi/sbi_platform.h>
+#include <sbi/sbi_string.h>
+#include <sbi_utils/fdt/fdt_fixup.h>
+#include <sbi_utils/fdt/fdt_helper.h>
+#include <sbi_utils/irqchip/fdt_irqchip.h>
+#include <sbi_utils/serial/fdt_serial.h>
+#include <sbi_utils/timer/fdt_timer.h>
+#include <sbi_utils/ipi/fdt_ipi.h>
+#include <sbi_utils/reset/fdt_reset.h>
+
+static const struct platform_override *special_platforms[] = { };
+
+static const struct platform_override *generic_plat = NULL;
+static const struct fdt_match *generic_plat_match = NULL;
+
+static void fw_platform_lookup_special(void *fdt, int root_offset)
+{
+ int pos, noff;
+ const struct platform_override *plat;
+ const struct fdt_match *match;
+
+ for (pos = 0; pos < array_size(special_platforms); pos++) {
+ plat = special_platforms[pos];
+ if (!plat->match_table)
+ continue;
+
+ noff = fdt_find_match(fdt, plat->match_table, &match);
+ if (noff < 0)
+ continue;
+
+ generic_plat = plat;
+ generic_plat_match = match;
+ break;
+ }
+}
+
+extern struct sbi_platform platform;
+static u32 generic_hart_index2id[SBI_HARTMASK_MAX_BITS] = { 0 };
+
+/*
+ * The fw_platform_init() function is called very early on the boot HART
+ * OpenSBI reference firmwares so that platform specific code get chance
+ * to update "platform" instance before it is used.
+ *
+ * The arguments passed to fw_platform_init() function are boot time state
+ * of A0 to A4 register. The "arg0" will be boot HART id and "arg1" will
+ * be address of FDT passed by previous booting stage.
+ */
+void fw_platform_init(unsigned long arg0, unsigned long arg1,
+ unsigned long arg2, unsigned long arg3,
+ unsigned long arg4)
+{
+ const char *model, *mmu_type;
+ void *fdt = (void *)arg1;
+ u32 hartid, hart_count = 0;
+ int rc, root_offset, cpus_offset, cpu_offset, len;
+
+ root_offset = fdt_path_offset(fdt, "/");
+ if (root_offset < 0)
+ goto fail;
+
+ fw_platform_lookup_special(fdt, root_offset);
+
+ model = fdt_getprop(fdt, root_offset, "model", &len);
+ if (model)
+ sbi_strncpy(platform.name, model, sizeof(platform.name));
+
+ if (generic_plat && generic_plat->features)
+ platform.features = generic_plat->features(generic_plat_match);
+
+ cpus_offset = fdt_path_offset(fdt, "/cpus");
+ if (cpus_offset < 0)
+ goto fail;
+
+ fdt_for_each_subnode(cpu_offset, fdt, cpus_offset) {
+ rc = fdt_parse_hart_id(fdt, cpu_offset, &hartid);
+ if (rc)
+ continue;
+
+ if (SBI_HARTMASK_MAX_BITS <= hartid)
+ continue;
+
+ mmu_type = fdt_getprop(fdt, cpu_offset, "mmu-type", &len);
+ if (!mmu_type || !len)
+ hartid = -1U;
+
+ generic_hart_index2id[hart_count++] = hartid;
+ }
+
+ platform.hart_count = hart_count;
+
+ return;
+
+fail:
+ while (1)
+ wfi();
+}
+
+static int generic_early_init(bool cold_boot)
+{
+ int rc;
+
+ if (generic_plat && generic_plat->early_init) {
+ rc = generic_plat->early_init(cold_boot, generic_plat_match);
+ if (rc)
+ return rc;
+ }
+
+ if (!cold_boot)
+ return 0;
+
+ return fdt_reset_init();
+}
+
+static int generic_final_init(bool cold_boot)
+{
+ void *fdt;
+ int rc;
+
+ if (generic_plat && generic_plat->final_init) {
+ rc = generic_plat->final_init(cold_boot, generic_plat_match);
+ if (rc)
+ return rc;
+ }
+
+ if (!cold_boot)
+ return 0;
+
+ fdt = sbi_scratch_thishart_arg1_ptr();
+
+ fdt_cpu_fixup(fdt);
+ fdt_fixups(fdt);
+
+ return 0;
+}
+
+static void generic_early_exit(void)
+{
+ if (generic_plat && generic_plat->early_exit)
+ generic_plat->early_exit(generic_plat_match);
+}
+
+static void generic_final_exit(void)
+{
+ if (generic_plat && generic_plat->final_exit)
+ generic_plat->final_exit(generic_plat_match);
+}
+
+static u64 generic_tlbr_flush_limit(void)
+{
+ if (generic_plat && generic_plat->tlbr_flush_limit)
+ return generic_plat->tlbr_flush_limit(generic_plat_match);
+ return SBI_PLATFORM_TLB_RANGE_FLUSH_LIMIT_DEFAULT;
+}
+
+static int generic_system_reset(u32 reset_type)
+{
+ if (generic_plat && generic_plat->system_reset)
+ return generic_plat->system_reset(reset_type,
+ generic_plat_match);
+ return fdt_system_reset(reset_type);
+}
+
+const struct sbi_platform_operations platform_ops = {
+ .early_init = generic_early_init,
+ .final_init = generic_final_init,
+ .early_exit = generic_early_exit,
+ .final_exit = generic_final_exit,
+ .console_putc = fdt_serial_putc,
+ .console_getc = fdt_serial_getc,
+ .console_init = fdt_serial_init,
+ .irqchip_init = fdt_irqchip_init,
+ .irqchip_exit = fdt_irqchip_exit,
+ .ipi_send = fdt_ipi_send,
+ .ipi_clear = fdt_ipi_clear,
+ .ipi_init = fdt_ipi_init,
+ .ipi_exit = fdt_ipi_exit,
+ .get_tlbr_flush_limit = generic_tlbr_flush_limit,
+ .timer_value = fdt_timer_value,
+ .timer_event_stop = fdt_timer_event_stop,
+ .timer_event_start = fdt_timer_event_start,
+ .timer_init = fdt_timer_init,
+ .timer_exit = fdt_timer_exit,
+ .system_reset = generic_system_reset,
+};
+
+struct sbi_platform platform = {
+ .opensbi_version = OPENSBI_VERSION,
+ .platform_version = SBI_PLATFORM_VERSION(0x0, 0x01),
+ .name = "Generic",
+ .features = SBI_PLATFORM_DEFAULT_FEATURES,
+ .hart_count = SBI_HARTMASK_MAX_BITS,
+ .hart_index2id = generic_hart_index2id,
+ .hart_stack_size = SBI_PLATFORM_DEFAULT_HART_STACK_SIZE,
+ .platform_ops_addr = (unsigned long)&platform_ops
+};