diff options
-rw-r--r-- | docs/platform/generic.md | 42 | ||||
-rw-r--r-- | docs/platform/platform.md | 6 | ||||
-rw-r--r-- | platform/generic/config.mk | 40 | ||||
-rw-r--r-- | platform/generic/include/platform_override.h | 26 | ||||
-rw-r--r-- | platform/generic/objects.mk | 10 | ||||
-rw-r--r-- | platform/generic/platform.c | 209 |
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 +}; |