summary refs log tree commit diff
path: root/arch/riscv/kernel
diff options
context:
space:
mode:
authorPalmer Dabbelt <palmerdabbelt@google.com>2020-04-14 13:43:24 +0900
committerPalmer Dabbelt <palmerdabbelt@google.com>2020-05-18 11:38:05 -0700
commit2d2682512f0faf4d09a696184bf3c0bb6838baca (patch)
tree31d238d63d671ff6b8ade87e521186d30afec7e7 /arch/riscv/kernel
parentb9bbe6ed63b2b9f2c9ee5cbd0f2c946a2723f4ce (diff)
downloadlinux-2d2682512f0faf4d09a696184bf3c0bb6838baca.tar.gz
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.c4
-rw-r--r--arch/riscv/kernel/soc.c27
-rw-r--r--arch/riscv/kernel/vmlinux.lds.S5
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 :
 	{