mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-18 08:35:08 +08:00
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>
This commit is contained in:
parent
b9bbe6ed63
commit
2d2682512f
@ -1,3 +1,4 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
obj-y += kernel/ mm/ net/
|
||||
obj-$(CONFIG_BUILTIN_DTB) += boot/dts/
|
||||
|
@ -381,6 +381,11 @@ endchoice
|
||||
|
||||
endmenu
|
||||
|
||||
config BUILTIN_DTB
|
||||
def_bool n
|
||||
depends on RISCV_M_MODE
|
||||
depends on OF
|
||||
|
||||
menu "Power management options"
|
||||
|
||||
source "kernel/power/Kconfig"
|
||||
|
@ -1,6 +1,7 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Copyright (C) 2020 Western Digital Corporation or its affiliates.
|
||||
* Copyright (C) 2020 Google, Inc
|
||||
*/
|
||||
|
||||
#ifndef _ASM_RISCV_SOC_H
|
||||
@ -20,4 +21,42 @@ void soc_early_init(void);
|
||||
extern unsigned long __soc_early_init_table_start;
|
||||
extern unsigned long __soc_early_init_table_end;
|
||||
|
||||
/*
|
||||
* Allows Linux to provide a device tree, which is necessary for SOCs that
|
||||
* don't provide a useful one on their own.
|
||||
*/
|
||||
struct soc_builtin_dtb {
|
||||
unsigned long vendor_id;
|
||||
unsigned long arch_id;
|
||||
unsigned long imp_id;
|
||||
void *(*dtb_func)(void);
|
||||
};
|
||||
|
||||
/*
|
||||
* The argument name must specify a valid DTS file name without the dts
|
||||
* extension.
|
||||
*/
|
||||
#define SOC_BUILTIN_DTB_DECLARE(name, vendor, arch, impl) \
|
||||
extern void *__dtb_##name##_begin; \
|
||||
\
|
||||
static __init __used \
|
||||
void *__soc_builtin_dtb_f__##name(void) \
|
||||
{ \
|
||||
return (void *)&__dtb_##name##_begin; \
|
||||
} \
|
||||
\
|
||||
static const struct soc_builtin_dtb __soc_builtin_dtb__##name \
|
||||
__used __section(__soc_builtin_dtb_table) = \
|
||||
{ \
|
||||
.vendor_id = vendor, \
|
||||
.arch_id = arch, \
|
||||
.imp_id = impl, \
|
||||
.dtb_func = __soc_builtin_dtb_f__##name, \
|
||||
}
|
||||
|
||||
extern unsigned long __soc_builtin_dtb_table_start;
|
||||
extern unsigned long __soc_builtin_dtb_table_end;
|
||||
|
||||
void *soc_lookup_builtin_dtb(void);
|
||||
|
||||
#endif
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 :
|
||||
{
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include <asm/fixmap.h>
|
||||
#include <asm/tlbflush.h>
|
||||
#include <asm/sections.h>
|
||||
#include <asm/soc.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
@ -493,7 +494,15 @@ void free_initmem(void)
|
||||
#else
|
||||
asmlinkage void __init setup_vm(uintptr_t dtb_pa)
|
||||
{
|
||||
#ifdef CONFIG_BUILTIN_DTB
|
||||
dtb_early_va = soc_lookup_builtin_dtb();
|
||||
if (!dtb_early_va) {
|
||||
/* Fallback to first available DTS */
|
||||
dtb_early_va = (void *) __dtb_start;
|
||||
}
|
||||
#else
|
||||
dtb_early_va = (void *)dtb_pa;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void setup_vm_final(void)
|
||||
|
Loading…
Reference in New Issue
Block a user