Skip to content

Commit 2d26825

Browse files
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 <[email protected]>
1 parent b9bbe6e commit 2d26825

File tree

7 files changed

+90
-0
lines changed

7 files changed

+90
-0
lines changed

arch/riscv/Kbuild

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
# SPDX-License-Identifier: GPL-2.0-only
22

33
obj-y += kernel/ mm/ net/
4+
obj-$(CONFIG_BUILTIN_DTB) += boot/dts/

arch/riscv/Kconfig

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,11 @@ endchoice
381381

382382
endmenu
383383

384+
config BUILTIN_DTB
385+
def_bool n
386+
depends on RISCV_M_MODE
387+
depends on OF
388+
384389
menu "Power management options"
385390

386391
source "kernel/power/Kconfig"

arch/riscv/include/asm/soc.h

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/* SPDX-License-Identifier: GPL-2.0-or-later */
22
/*
33
* Copyright (C) 2020 Western Digital Corporation or its affiliates.
4+
* Copyright (C) 2020 Google, Inc
45
*/
56

67
#ifndef _ASM_RISCV_SOC_H
@@ -20,4 +21,42 @@ void soc_early_init(void);
2021
extern unsigned long __soc_early_init_table_start;
2122
extern unsigned long __soc_early_init_table_end;
2223

24+
/*
25+
* Allows Linux to provide a device tree, which is necessary for SOCs that
26+
* don't provide a useful one on their own.
27+
*/
28+
struct soc_builtin_dtb {
29+
unsigned long vendor_id;
30+
unsigned long arch_id;
31+
unsigned long imp_id;
32+
void *(*dtb_func)(void);
33+
};
34+
35+
/*
36+
* The argument name must specify a valid DTS file name without the dts
37+
* extension.
38+
*/
39+
#define SOC_BUILTIN_DTB_DECLARE(name, vendor, arch, impl) \
40+
extern void *__dtb_##name##_begin; \
41+
\
42+
static __init __used \
43+
void *__soc_builtin_dtb_f__##name(void) \
44+
{ \
45+
return (void *)&__dtb_##name##_begin; \
46+
} \
47+
\
48+
static const struct soc_builtin_dtb __soc_builtin_dtb__##name \
49+
__used __section(__soc_builtin_dtb_table) = \
50+
{ \
51+
.vendor_id = vendor, \
52+
.arch_id = arch, \
53+
.imp_id = impl, \
54+
.dtb_func = __soc_builtin_dtb_f__##name, \
55+
}
56+
57+
extern unsigned long __soc_builtin_dtb_table_start;
58+
extern unsigned long __soc_builtin_dtb_table_end;
59+
60+
void *soc_lookup_builtin_dtb(void);
61+
2362
#endif

arch/riscv/kernel/setup.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,11 @@ void __init setup_arch(char **cmdline_p)
7575

7676
setup_bootmem();
7777
paging_init();
78+
#if IS_ENABLED(CONFIG_BUILTIN_DTB)
79+
unflatten_and_copy_device_tree();
80+
#else
7881
unflatten_device_tree();
82+
#endif
7983
clint_init_boot_cpu();
8084

8185
#ifdef CONFIG_SWIOTLB

arch/riscv/kernel/soc.c

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,30 @@ void __init soc_early_init(void)
2626
}
2727
}
2828
}
29+
30+
static bool soc_builtin_dtb_match(unsigned long vendor_id,
31+
unsigned long arch_id, unsigned long imp_id,
32+
const struct soc_builtin_dtb *entry)
33+
{
34+
return entry->vendor_id == vendor_id &&
35+
entry->arch_id == arch_id &&
36+
entry->imp_id == imp_id;
37+
}
38+
39+
void * __init soc_lookup_builtin_dtb(void)
40+
{
41+
unsigned long vendor_id, arch_id, imp_id;
42+
const struct soc_builtin_dtb *s;
43+
44+
__asm__ ("csrr %0, mvendorid" : "=r"(vendor_id));
45+
__asm__ ("csrr %0, marchid" : "=r"(arch_id));
46+
__asm__ ("csrr %0, mimpid" : "=r"(imp_id));
47+
48+
for (s = (void *)&__soc_builtin_dtb_table_start;
49+
(void *)s < (void *)&__soc_builtin_dtb_table_end; s++) {
50+
if (soc_builtin_dtb_match(vendor_id, arch_id, imp_id, s))
51+
return s->dtb_func();
52+
}
53+
54+
return NULL;
55+
}

arch/riscv/kernel/vmlinux.lds.S

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,11 @@ SECTIONS
3434
KEEP(*(__soc_early_init_table))
3535
__soc_early_init_table_end = .;
3636
}
37+
__soc_builtin_dtb_table : {
38+
__soc_builtin_dtb_table_start = .;
39+
KEEP(*(__soc_builtin_dtb_table))
40+
__soc_builtin_dtb_table_end = .;
41+
}
3742
/* we have to discard exit text and such at runtime, not link time */
3843
.exit.text :
3944
{

arch/riscv/mm/init.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include <asm/fixmap.h>
1818
#include <asm/tlbflush.h>
1919
#include <asm/sections.h>
20+
#include <asm/soc.h>
2021
#include <asm/pgtable.h>
2122
#include <asm/io.h>
2223

@@ -493,7 +494,15 @@ void free_initmem(void)
493494
#else
494495
asmlinkage void __init setup_vm(uintptr_t dtb_pa)
495496
{
497+
#ifdef CONFIG_BUILTIN_DTB
498+
dtb_early_va = soc_lookup_builtin_dtb();
499+
if (!dtb_early_va) {
500+
/* Fallback to first available DTS */
501+
dtb_early_va = (void *) __dtb_start;
502+
}
503+
#else
496504
dtb_early_va = (void *)dtb_pa;
505+
#endif
497506
}
498507

499508
static inline void setup_vm_final(void)

0 commit comments

Comments
 (0)