diff options
author | Palmer Dabbelt <palmerdabbelt@google.com> | 2020-04-14 13:43:24 +0900 |
---|---|---|
committer | Palmer Dabbelt <palmerdabbelt@google.com> | 2020-05-18 11:38:05 -0700 |
commit | 2d2682512f0faf4d09a696184bf3c0bb6838baca (patch) | |
tree | 31d238d63d671ff6b8ade87e521186d30afec7e7 /arch/riscv/kernel | |
parent | b9bbe6ed63b2b9f2c9ee5cbd0f2c946a2723f4ce (diff) |
riscv: Allow device trees to be built into the kernel
Some systems don't provide a useful device tree to the kernel on boot.
Chasing around bootloaders for these systems is a headache, so instead
le't's just keep a device tree table in the kernel, keyed by the SOC's
unique identifier, that contains the relevant DTB.
This is only implemented for M mode right now. While we could implement
this via the SBI calls that allow access to these identifiers, we don't
have any systems that need this right now.
Signed-off-by: Palmer Dabbelt <palmerdabbelt@google.com>
Diffstat (limited to 'arch/riscv/kernel')
-rw-r--r-- | arch/riscv/kernel/setup.c | 4 | ||||
-rw-r--r-- | arch/riscv/kernel/soc.c | 27 | ||||
-rw-r--r-- | arch/riscv/kernel/vmlinux.lds.S | 5 |
3 files changed, 36 insertions, 0 deletions
diff --git a/arch/riscv/kernel/setup.c b/arch/riscv/kernel/setup.c index 145128a7e560..3e528312f615 100644 --- a/arch/riscv/kernel/setup.c +++ b/arch/riscv/kernel/setup.c @@ -75,7 +75,11 @@ void __init setup_arch(char **cmdline_p) setup_bootmem(); paging_init(); +#if IS_ENABLED(CONFIG_BUILTIN_DTB) + unflatten_and_copy_device_tree(); +#else unflatten_device_tree(); +#endif clint_init_boot_cpu(); #ifdef CONFIG_SWIOTLB diff --git a/arch/riscv/kernel/soc.c b/arch/riscv/kernel/soc.c index 0b3b3dc9ad0f..1fc87621c728 100644 --- a/arch/riscv/kernel/soc.c +++ b/arch/riscv/kernel/soc.c @@ -26,3 +26,30 @@ void __init soc_early_init(void) } } } + +static bool soc_builtin_dtb_match(unsigned long vendor_id, + unsigned long arch_id, unsigned long imp_id, + const struct soc_builtin_dtb *entry) +{ + return entry->vendor_id == vendor_id && + entry->arch_id == arch_id && + entry->imp_id == imp_id; +} + +void * __init soc_lookup_builtin_dtb(void) +{ + unsigned long vendor_id, arch_id, imp_id; + const struct soc_builtin_dtb *s; + + __asm__ ("csrr %0, mvendorid" : "=r"(vendor_id)); + __asm__ ("csrr %0, marchid" : "=r"(arch_id)); + __asm__ ("csrr %0, mimpid" : "=r"(imp_id)); + + for (s = (void *)&__soc_builtin_dtb_table_start; + (void *)s < (void *)&__soc_builtin_dtb_table_end; s++) { + if (soc_builtin_dtb_match(vendor_id, arch_id, imp_id, s)) + return s->dtb_func(); + } + + return NULL; +} diff --git a/arch/riscv/kernel/vmlinux.lds.S b/arch/riscv/kernel/vmlinux.lds.S index 0339b6bbe11a..e6f8016b366a 100644 --- a/arch/riscv/kernel/vmlinux.lds.S +++ b/arch/riscv/kernel/vmlinux.lds.S @@ -34,6 +34,11 @@ SECTIONS KEEP(*(__soc_early_init_table)) __soc_early_init_table_end = .; } + __soc_builtin_dtb_table : { + __soc_builtin_dtb_table_start = .; + KEEP(*(__soc_builtin_dtb_table)) + __soc_builtin_dtb_table_end = .; + } /* we have to discard exit text and such at runtime, not link time */ .exit.text : { |