Message ID | 20200312051107.1454880-4-damien.lemoal@wdc.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | Kendryte k210 SoC boards support | expand |
On 3/12/20 1:11 AM, Damien Le Moal wrote: > Add a mechanism for early SoC initialization for platforms that need > additional hardware initialization not possible through the regular > device tree and drivers mechanism. With this, a SoC specific > initialization function can be called very early, before DTB parsing > is done by parse_dtb() in Linux RISC-V kernel setup code. Why does it need to be called that early (e.g. before parsing dtb)? > > This can be very useful for early hardware initialization for No-MMU > kernels booted directly in M-mode because it is quite likely that no > other booting stage exist prior to the No-MMU kernel. > > Example use of a SoC early initialization is as follows: > > static void vendor_abc_early_init(const void *fdt) > { > /* > * some early init code here that can use simple matches > * against the flat device tree file. > */ > } > SOC_EARLY_INIT_DECLARE("vendor,abc", abc_early_init); > > This early initialization function is executed only if the flat device > tree for the board has a 'compatible = "vendor,abc"' entry; > > Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com> > Signed-off-by: Anup Patel <anup.patel@wdc.com> > Reviewed-by: Palmer Dabbelt <palmerdabbelt@google.com> --Sean
On Wed, Mar 11, 2020 at 10:11 PM Damien Le Moal <damien.lemoal@wdc.com> wrote: > > Add a mechanism for early SoC initialization for platforms that need > additional hardware initialization not possible through the regular > device tree and drivers mechanism. With this, a SoC specific > initialization function can be called very early, before DTB parsing > is done by parse_dtb() in Linux RISC-V kernel setup code. > > This can be very useful for early hardware initialization for No-MMU > kernels booted directly in M-mode because it is quite likely that no > other booting stage exist prior to the No-MMU kernel. > > Example use of a SoC early initialization is as follows: > > static void vendor_abc_early_init(const void *fdt) > { > /* > * some early init code here that can use simple matches > * against the flat device tree file. > */ > } > SOC_EARLY_INIT_DECLARE("vendor,abc", abc_early_init); > > This early initialization function is executed only if the flat device > tree for the board has a 'compatible = "vendor,abc"' entry; > > Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com> > Signed-off-by: Anup Patel <anup.patel@wdc.com> > Reviewed-by: Palmer Dabbelt <palmerdabbelt@google.com> > --- > arch/riscv/include/asm/soc.h | 23 +++++++++++++++++++++++ > arch/riscv/kernel/Makefile | 1 + > arch/riscv/kernel/head.S | 1 + > arch/riscv/kernel/soc.c | 28 ++++++++++++++++++++++++++++ > arch/riscv/kernel/vmlinux.lds.S | 6 ++++++ > 5 files changed, 59 insertions(+) > create mode 100644 arch/riscv/include/asm/soc.h > create mode 100644 arch/riscv/kernel/soc.c > > diff --git a/arch/riscv/include/asm/soc.h b/arch/riscv/include/asm/soc.h > new file mode 100644 > index 000000000000..9b8c332cbe76 > --- /dev/null > +++ b/arch/riscv/include/asm/soc.h > @@ -0,0 +1,23 @@ > +/* SPDX-License-Identifier: GPL-2.0-or-later */ > +/* > + * Copyright (C) 2020 Western Digital Corporation or its affiliates. > + */ > + > +#ifndef _ASM_RISCV_SOC_H > +#define _ASM_RISCV_SOC_H > + > +#include <linux/of.h> > +#include <linux/linkage.h> > +#include <linux/types.h> > + > +#define SOC_EARLY_INIT_DECLARE(compat, fn) \ > + static const struct of_device_id __soc_early_init \ > + __used __section(__soc_early_init_table) \ > + = { .compatible = compat, .data = fn } > + > +void soc_early_init(void); > + > +extern unsigned long __soc_early_init_table_start; > +extern unsigned long __soc_early_init_table_end; > + > +#endif > diff --git a/arch/riscv/kernel/Makefile b/arch/riscv/kernel/Makefile > index 97d0c35f8b37..e4a22999dbc6 100644 > --- a/arch/riscv/kernel/Makefile > +++ b/arch/riscv/kernel/Makefile > @@ -10,6 +10,7 @@ endif > extra-y += head.o > extra-y += vmlinux.lds > > +obj-y += soc.o > obj-y += cpu.o > obj-y += cpufeature.o > obj-y += entry.o > diff --git a/arch/riscv/kernel/head.S b/arch/riscv/kernel/head.S > index 85f2073e7fe4..52ed11b4fda6 100644 > --- a/arch/riscv/kernel/head.S > +++ b/arch/riscv/kernel/head.S > @@ -131,6 +131,7 @@ clear_bss_done: > call kasan_early_init > #endif > /* Start the kernel */ > + call soc_early_init > call parse_dtb > tail start_kernel > > diff --git a/arch/riscv/kernel/soc.c b/arch/riscv/kernel/soc.c > new file mode 100644 > index 000000000000..0b3b3dc9ad0f > --- /dev/null > +++ b/arch/riscv/kernel/soc.c > @@ -0,0 +1,28 @@ > +// SPDX-License-Identifier: GPL-2.0-or-later > +/* > + * Copyright (C) 2020 Western Digital Corporation or its affiliates. > + */ > +#include <linux/init.h> > +#include <linux/libfdt.h> > +#include <asm/pgtable.h> > +#include <asm/soc.h> > + > +/* > + * This is called extremly early, before parse_dtb(), to allow initializing > + * SoC hardware before memory or any device driver initialization. > + */ > +void __init soc_early_init(void) > +{ > + void (*early_fn)(const void *fdt); > + const struct of_device_id *s; > + const void *fdt = dtb_early_va; > + > + for (s = (void *)&__soc_early_init_table_start; > + (void *)s < (void *)&__soc_early_init_table_end; s++) { > + if (!fdt_node_check_compatible(fdt, 0, s->compatible)) { > + early_fn = s->data; > + early_fn(fdt); > + return; > + } > + } > +} > diff --git a/arch/riscv/kernel/vmlinux.lds.S b/arch/riscv/kernel/vmlinux.lds.S > index 1e0193ded420..32b160942f40 100644 > --- a/arch/riscv/kernel/vmlinux.lds.S > +++ b/arch/riscv/kernel/vmlinux.lds.S > @@ -24,6 +24,12 @@ SECTIONS > HEAD_TEXT_SECTION > INIT_TEXT_SECTION(PAGE_SIZE) > INIT_DATA_SECTION(16) > + . = ALIGN(8); > + __soc_early_init_table : { > + __soc_early_init_table_start = .; > + KEEP(*(__soc_early_init_table)) > + __soc_early_init_table_end = .; > + } > /* we have to discard exit text and such at runtime, not link time */ > .exit.text : > { > -- > 2.24.1 > > Reviewed-by: Atish Patra <atish.patra@wdc.com>
On Wed, Mar 11, 2020 at 10:11 PM Damien Le Moal <damien.lemoal@wdc.com> wrote: > > Add a mechanism for early SoC initialization for platforms that need > additional hardware initialization not possible through the regular > device tree and drivers mechanism. With this, a SoC specific > initialization function can be called very early, before DTB parsing > is done by parse_dtb() in Linux RISC-V kernel setup code. > > This can be very useful for early hardware initialization for No-MMU > kernels booted directly in M-mode because it is quite likely that no > other booting stage exist prior to the No-MMU kernel. > > Example use of a SoC early initialization is as follows: > > static void vendor_abc_early_init(const void *fdt) > { > /* > * some early init code here that can use simple matches > * against the flat device tree file. > */ > } > SOC_EARLY_INIT_DECLARE("vendor,abc", abc_early_init); > > This early initialization function is executed only if the flat device > tree for the board has a 'compatible = "vendor,abc"' entry; > > Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com> > Signed-off-by: Anup Patel <anup.patel@wdc.com> > Reviewed-by: Palmer Dabbelt <palmerdabbelt@google.com> > --- > arch/riscv/include/asm/soc.h | 23 +++++++++++++++++++++++ > arch/riscv/kernel/Makefile | 1 + > arch/riscv/kernel/head.S | 1 + > arch/riscv/kernel/soc.c | 28 ++++++++++++++++++++++++++++ > arch/riscv/kernel/vmlinux.lds.S | 6 ++++++ > 5 files changed, 59 insertions(+) > create mode 100644 arch/riscv/include/asm/soc.h > create mode 100644 arch/riscv/kernel/soc.c > > diff --git a/arch/riscv/include/asm/soc.h b/arch/riscv/include/asm/soc.h > new file mode 100644 > index 000000000000..9b8c332cbe76 > --- /dev/null > +++ b/arch/riscv/include/asm/soc.h > @@ -0,0 +1,23 @@ > +/* SPDX-License-Identifier: GPL-2.0-or-later */ > +/* > + * Copyright (C) 2020 Western Digital Corporation or its affiliates. > + */ > + > +#ifndef _ASM_RISCV_SOC_H > +#define _ASM_RISCV_SOC_H > + > +#include <linux/of.h> > +#include <linux/linkage.h> > +#include <linux/types.h> > + > +#define SOC_EARLY_INIT_DECLARE(compat, fn) \ > + static const struct of_device_id __soc_early_init \ > + __used __section(__soc_early_init_table) \ > + = { .compatible = compat, .data = fn } > + There may be some future kendryte board or some other RISC-V board which want to use SOC_EARLY_INIT_DECLARE. There should be a name parameter as well which allows multiple usage of SOC_EARLY_INIT_DECLARE. > +void soc_early_init(void); > + > +extern unsigned long __soc_early_init_table_start; > +extern unsigned long __soc_early_init_table_end; > + > +#endif > diff --git a/arch/riscv/kernel/Makefile b/arch/riscv/kernel/Makefile > index 97d0c35f8b37..e4a22999dbc6 100644 > --- a/arch/riscv/kernel/Makefile > +++ b/arch/riscv/kernel/Makefile > @@ -10,6 +10,7 @@ endif > extra-y += head.o > extra-y += vmlinux.lds > > +obj-y += soc.o > obj-y += cpu.o > obj-y += cpufeature.o > obj-y += entry.o > diff --git a/arch/riscv/kernel/head.S b/arch/riscv/kernel/head.S > index 85f2073e7fe4..52ed11b4fda6 100644 > --- a/arch/riscv/kernel/head.S > +++ b/arch/riscv/kernel/head.S > @@ -131,6 +131,7 @@ clear_bss_done: > call kasan_early_init > #endif > /* Start the kernel */ > + call soc_early_init > call parse_dtb > tail start_kernel > > diff --git a/arch/riscv/kernel/soc.c b/arch/riscv/kernel/soc.c > new file mode 100644 > index 000000000000..0b3b3dc9ad0f > --- /dev/null > +++ b/arch/riscv/kernel/soc.c > @@ -0,0 +1,28 @@ > +// SPDX-License-Identifier: GPL-2.0-or-later > +/* > + * Copyright (C) 2020 Western Digital Corporation or its affiliates. > + */ > +#include <linux/init.h> > +#include <linux/libfdt.h> > +#include <asm/pgtable.h> > +#include <asm/soc.h> > + > +/* > + * This is called extremly early, before parse_dtb(), to allow initializing > + * SoC hardware before memory or any device driver initialization. > + */ > +void __init soc_early_init(void) > +{ > + void (*early_fn)(const void *fdt); > + const struct of_device_id *s; > + const void *fdt = dtb_early_va; > + > + for (s = (void *)&__soc_early_init_table_start; > + (void *)s < (void *)&__soc_early_init_table_end; s++) { > + if (!fdt_node_check_compatible(fdt, 0, s->compatible)) { > + early_fn = s->data; > + early_fn(fdt); > + return; > + } > + } > +} > diff --git a/arch/riscv/kernel/vmlinux.lds.S b/arch/riscv/kernel/vmlinux.lds.S > index 1e0193ded420..32b160942f40 100644 > --- a/arch/riscv/kernel/vmlinux.lds.S > +++ b/arch/riscv/kernel/vmlinux.lds.S > @@ -24,6 +24,12 @@ SECTIONS > HEAD_TEXT_SECTION > INIT_TEXT_SECTION(PAGE_SIZE) > INIT_DATA_SECTION(16) > + . = ALIGN(8); > + __soc_early_init_table : { > + __soc_early_init_table_start = .; > + KEEP(*(__soc_early_init_table)) > + __soc_early_init_table_end = .; > + } > /* we have to discard exit text and such at runtime, not link time */ > .exit.text : > { > -- > 2.24.1 > >
On Thu, 2020-03-12 at 14:21 -0400, Sean Anderson wrote: > On 3/12/20 1:11 AM, Damien Le Moal wrote: > > Add a mechanism for early SoC initialization for platforms that need > > additional hardware initialization not possible through the regular > > device tree and drivers mechanism. With this, a SoC specific > > initialization function can be called very early, before DTB parsing > > is done by parse_dtb() in Linux RISC-V kernel setup code. > > Why does it need to be called that early (e.g. before parsing dtb)? Because dtb parsing will trigger the initialization of the memory segments listed for use with memory allocation. That leads to the dtb parsing itself allocating memory that ends up on the kpu sram before a device driver specified in the dt can be initialized to turn the memory on. That is at least what I observed: I never go past the parse_dtb() point without the memory turned on if there is an entry in the device tree for it. > > > This can be very useful for early hardware initialization for No-MMU > > kernels booted directly in M-mode because it is quite likely that no > > other booting stage exist prior to the No-MMU kernel. > > > > Example use of a SoC early initialization is as follows: > > > > static void vendor_abc_early_init(const void *fdt) > > { > > /* > > * some early init code here that can use simple matches > > * against the flat device tree file. > > */ > > } > > SOC_EARLY_INIT_DECLARE("vendor,abc", abc_early_init); > > > > This early initialization function is executed only if the flat device > > tree for the board has a 'compatible = "vendor,abc"' entry; > > > > Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com> > > Signed-off-by: Anup Patel <anup.patel@wdc.com> > > Reviewed-by: Palmer Dabbelt <palmerdabbelt@google.com> > > --Sean
On Thu, 2020-03-12 at 13:53 -0700, Atish Patra wrote: > On Wed, Mar 11, 2020 at 10:11 PM Damien Le Moal <damien.lemoal@wdc.com> wrote: > > Add a mechanism for early SoC initialization for platforms that need > > additional hardware initialization not possible through the regular > > device tree and drivers mechanism. With this, a SoC specific > > initialization function can be called very early, before DTB parsing > > is done by parse_dtb() in Linux RISC-V kernel setup code. > > > > This can be very useful for early hardware initialization for No-MMU > > kernels booted directly in M-mode because it is quite likely that no > > other booting stage exist prior to the No-MMU kernel. > > > > Example use of a SoC early initialization is as follows: > > > > static void vendor_abc_early_init(const void *fdt) > > { > > /* > > * some early init code here that can use simple matches > > * against the flat device tree file. > > */ > > } > > SOC_EARLY_INIT_DECLARE("vendor,abc", abc_early_init); > > > > This early initialization function is executed only if the flat device > > tree for the board has a 'compatible = "vendor,abc"' entry; > > > > Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com> > > Signed-off-by: Anup Patel <anup.patel@wdc.com> > > Reviewed-by: Palmer Dabbelt <palmerdabbelt@google.com> > > --- > > arch/riscv/include/asm/soc.h | 23 +++++++++++++++++++++++ > > arch/riscv/kernel/Makefile | 1 + > > arch/riscv/kernel/head.S | 1 + > > arch/riscv/kernel/soc.c | 28 ++++++++++++++++++++++++++++ > > arch/riscv/kernel/vmlinux.lds.S | 6 ++++++ > > 5 files changed, 59 insertions(+) > > create mode 100644 arch/riscv/include/asm/soc.h > > create mode 100644 arch/riscv/kernel/soc.c > > > > diff --git a/arch/riscv/include/asm/soc.h b/arch/riscv/include/asm/soc.h > > new file mode 100644 > > index 000000000000..9b8c332cbe76 > > --- /dev/null > > +++ b/arch/riscv/include/asm/soc.h > > @@ -0,0 +1,23 @@ > > +/* SPDX-License-Identifier: GPL-2.0-or-later */ > > +/* > > + * Copyright (C) 2020 Western Digital Corporation or its affiliates. > > + */ > > + > > +#ifndef _ASM_RISCV_SOC_H > > +#define _ASM_RISCV_SOC_H > > + > > +#include <linux/of.h> > > +#include <linux/linkage.h> > > +#include <linux/types.h> > > + > > +#define SOC_EARLY_INIT_DECLARE(compat, fn) \ > > + static const struct of_device_id __soc_early_init \ > > + __used __section(__soc_early_init_table) \ > > + = { .compatible = compat, .data = fn } > > + > > There may be some future kendryte board or some other RISC-V board > which want to use SOC_EARLY_INIT_DECLARE. > There should be a name parameter as well which allows multiple usage > of SOC_EARLY_INIT_DECLARE. I am not sure I understand your point here. Currently, the call to an early init functions is driven by the value (name) specified in the DT compatible entry. If what needs to be done in the early init function for one SoC is common with another, the same function can be used for different SOC_EARLY_INIT_DECLARE() with different compatible strings, or the same compatible string used in the different boards DT. No ? Am I missing something ? > > > +void soc_early_init(void); > > + > > +extern unsigned long __soc_early_init_table_start; > > +extern unsigned long __soc_early_init_table_end; > > + > > +#endif > > diff --git a/arch/riscv/kernel/Makefile b/arch/riscv/kernel/Makefile > > index 97d0c35f8b37..e4a22999dbc6 100644 > > --- a/arch/riscv/kernel/Makefile > > +++ b/arch/riscv/kernel/Makefile > > @@ -10,6 +10,7 @@ endif > > extra-y += head.o > > extra-y += vmlinux.lds > > > > +obj-y += soc.o > > obj-y += cpu.o > > obj-y += cpufeature.o > > obj-y += entry.o > > diff --git a/arch/riscv/kernel/head.S b/arch/riscv/kernel/head.S > > index 85f2073e7fe4..52ed11b4fda6 100644 > > --- a/arch/riscv/kernel/head.S > > +++ b/arch/riscv/kernel/head.S > > @@ -131,6 +131,7 @@ clear_bss_done: > > call kasan_early_init > > #endif > > /* Start the kernel */ > > + call soc_early_init > > call parse_dtb > > tail start_kernel > > > > diff --git a/arch/riscv/kernel/soc.c b/arch/riscv/kernel/soc.c > > new file mode 100644 > > index 000000000000..0b3b3dc9ad0f > > --- /dev/null > > +++ b/arch/riscv/kernel/soc.c > > @@ -0,0 +1,28 @@ > > +// SPDX-License-Identifier: GPL-2.0-or-later > > +/* > > + * Copyright (C) 2020 Western Digital Corporation or its affiliates. > > + */ > > +#include <linux/init.h> > > +#include <linux/libfdt.h> > > +#include <asm/pgtable.h> > > +#include <asm/soc.h> > > + > > +/* > > + * This is called extremly early, before parse_dtb(), to allow initializing > > + * SoC hardware before memory or any device driver initialization. > > + */ > > +void __init soc_early_init(void) > > +{ > > + void (*early_fn)(const void *fdt); > > + const struct of_device_id *s; > > + const void *fdt = dtb_early_va; > > + > > + for (s = (void *)&__soc_early_init_table_start; > > + (void *)s < (void *)&__soc_early_init_table_end; s++) { > > + if (!fdt_node_check_compatible(fdt, 0, s->compatible)) { > > + early_fn = s->data; > > + early_fn(fdt); > > + return; > > + } > > + } > > +} > > diff --git a/arch/riscv/kernel/vmlinux.lds.S b/arch/riscv/kernel/vmlinux.lds.S > > index 1e0193ded420..32b160942f40 100644 > > --- a/arch/riscv/kernel/vmlinux.lds.S > > +++ b/arch/riscv/kernel/vmlinux.lds.S > > @@ -24,6 +24,12 @@ SECTIONS > > HEAD_TEXT_SECTION > > INIT_TEXT_SECTION(PAGE_SIZE) > > INIT_DATA_SECTION(16) > > + . = ALIGN(8); > > + __soc_early_init_table : { > > + __soc_early_init_table_start = .; > > + KEEP(*(__soc_early_init_table)) > > + __soc_early_init_table_end = .; > > + } > > /* we have to discard exit text and such at runtime, not link time */ > > .exit.text : > > { > > -- > > 2.24.1 > > > > > >
On Thu, Mar 12, 2020 at 11:42 PM Damien Le Moal <Damien.LeMoal@wdc.com> wrote: > > On Thu, 2020-03-12 at 13:53 -0700, Atish Patra wrote: > > On Wed, Mar 11, 2020 at 10:11 PM Damien Le Moal <damien.lemoal@wdc.com> wrote: > > > Add a mechanism for early SoC initialization for platforms that need > > > additional hardware initialization not possible through the regular > > > device tree and drivers mechanism. With this, a SoC specific > > > initialization function can be called very early, before DTB parsing > > > is done by parse_dtb() in Linux RISC-V kernel setup code. > > > > > > This can be very useful for early hardware initialization for No-MMU > > > kernels booted directly in M-mode because it is quite likely that no > > > other booting stage exist prior to the No-MMU kernel. > > > > > > Example use of a SoC early initialization is as follows: > > > > > > static void vendor_abc_early_init(const void *fdt) > > > { > > > /* > > > * some early init code here that can use simple matches > > > * against the flat device tree file. > > > */ > > > } > > > SOC_EARLY_INIT_DECLARE("vendor,abc", abc_early_init); > > > > > > This early initialization function is executed only if the flat device > > > tree for the board has a 'compatible = "vendor,abc"' entry; > > > > > > Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com> > > > Signed-off-by: Anup Patel <anup.patel@wdc.com> > > > Reviewed-by: Palmer Dabbelt <palmerdabbelt@google.com> > > > --- > > > arch/riscv/include/asm/soc.h | 23 +++++++++++++++++++++++ > > > arch/riscv/kernel/Makefile | 1 + > > > arch/riscv/kernel/head.S | 1 + > > > arch/riscv/kernel/soc.c | 28 ++++++++++++++++++++++++++++ > > > arch/riscv/kernel/vmlinux.lds.S | 6 ++++++ > > > 5 files changed, 59 insertions(+) > > > create mode 100644 arch/riscv/include/asm/soc.h > > > create mode 100644 arch/riscv/kernel/soc.c > > > > > > diff --git a/arch/riscv/include/asm/soc.h b/arch/riscv/include/asm/soc.h > > > new file mode 100644 > > > index 000000000000..9b8c332cbe76 > > > --- /dev/null > > > +++ b/arch/riscv/include/asm/soc.h > > > @@ -0,0 +1,23 @@ > > > +/* SPDX-License-Identifier: GPL-2.0-or-later */ > > > +/* > > > + * Copyright (C) 2020 Western Digital Corporation or its affiliates. > > > + */ > > > + > > > +#ifndef _ASM_RISCV_SOC_H > > > +#define _ASM_RISCV_SOC_H > > > + > > > +#include <linux/of.h> > > > +#include <linux/linkage.h> > > > +#include <linux/types.h> > > > + > > > +#define SOC_EARLY_INIT_DECLARE(compat, fn) \ > > > + static const struct of_device_id __soc_early_init \ > > > + __used __section(__soc_early_init_table) \ > > > + = { .compatible = compat, .data = fn } > > > + > > > > There may be some future kendryte board or some other RISC-V board > > which want to use SOC_EARLY_INIT_DECLARE. > > There should be a name parameter as well which allows multiple usage > > of SOC_EARLY_INIT_DECLARE. > > I am not sure I understand your point here. Currently, the call to an > early init functions is driven by the value (name) specified in the DT > compatible entry. If what needs to be done in the early init function > for one SoC is common with another, the same function can be used for > different SOC_EARLY_INIT_DECLARE() with different compatible strings, > or the same compatible string used in the different boards DT. No ? Am > I missing something ? > To use different compatible strings, SOC_EARLY_INIT_DECLARE has to be declared twice. As SOC_EARLY_INIT_DECLARE is just a macro that declares __soc_early_init, redefinition compile error will happen. That's why __soc_early_init has to be suffixed with name to avoid the redefinition error. Here is the diff I am talking about -#define SOC_EARLY_INIT_DECLARE(compat, fn) \ - static const struct of_device_id __soc_early_init \ +#define SOC_EARLY_INIT_DECLARE(name, compat, fn) \ + static const struct of_device_id __soc_early_init__##name \ __used __section(__soc_early_init_table) \ = { .compatible = compat, .data = fn } > > > > > +void soc_early_init(void); > > > + > > > +extern unsigned long __soc_early_init_table_start; > > > +extern unsigned long __soc_early_init_table_end; > > > + > > > +#endif > > > diff --git a/arch/riscv/kernel/Makefile b/arch/riscv/kernel/Makefile > > > index 97d0c35f8b37..e4a22999dbc6 100644 > > > --- a/arch/riscv/kernel/Makefile > > > +++ b/arch/riscv/kernel/Makefile > > > @@ -10,6 +10,7 @@ endif > > > extra-y += head.o > > > extra-y += vmlinux.lds > > > > > > +obj-y += soc.o > > > obj-y += cpu.o > > > obj-y += cpufeature.o > > > obj-y += entry.o > > > diff --git a/arch/riscv/kernel/head.S b/arch/riscv/kernel/head.S > > > index 85f2073e7fe4..52ed11b4fda6 100644 > > > --- a/arch/riscv/kernel/head.S > > > +++ b/arch/riscv/kernel/head.S > > > @@ -131,6 +131,7 @@ clear_bss_done: > > > call kasan_early_init > > > #endif > > > /* Start the kernel */ > > > + call soc_early_init > > > call parse_dtb > > > tail start_kernel > > > > > > diff --git a/arch/riscv/kernel/soc.c b/arch/riscv/kernel/soc.c > > > new file mode 100644 > > > index 000000000000..0b3b3dc9ad0f > > > --- /dev/null > > > +++ b/arch/riscv/kernel/soc.c > > > @@ -0,0 +1,28 @@ > > > +// SPDX-License-Identifier: GPL-2.0-or-later > > > +/* > > > + * Copyright (C) 2020 Western Digital Corporation or its affiliates. > > > + */ > > > +#include <linux/init.h> > > > +#include <linux/libfdt.h> > > > +#include <asm/pgtable.h> > > > +#include <asm/soc.h> > > > + > > > +/* > > > + * This is called extremly early, before parse_dtb(), to allow initializing > > > + * SoC hardware before memory or any device driver initialization. > > > + */ > > > +void __init soc_early_init(void) > > > +{ > > > + void (*early_fn)(const void *fdt); > > > + const struct of_device_id *s; > > > + const void *fdt = dtb_early_va; > > > + > > > + for (s = (void *)&__soc_early_init_table_start; > > > + (void *)s < (void *)&__soc_early_init_table_end; s++) { > > > + if (!fdt_node_check_compatible(fdt, 0, s->compatible)) { > > > + early_fn = s->data; > > > + early_fn(fdt); > > > + return; > > > + } > > > + } > > > +} > > > diff --git a/arch/riscv/kernel/vmlinux.lds.S b/arch/riscv/kernel/vmlinux.lds.S > > > index 1e0193ded420..32b160942f40 100644 > > > --- a/arch/riscv/kernel/vmlinux.lds.S > > > +++ b/arch/riscv/kernel/vmlinux.lds.S > > > @@ -24,6 +24,12 @@ SECTIONS > > > HEAD_TEXT_SECTION > > > INIT_TEXT_SECTION(PAGE_SIZE) > > > INIT_DATA_SECTION(16) > > > + . = ALIGN(8); > > > + __soc_early_init_table : { > > > + __soc_early_init_table_start = .; > > > + KEEP(*(__soc_early_init_table)) > > > + __soc_early_init_table_end = .; > > > + } > > > /* we have to discard exit text and such at runtime, not link time */ > > > .exit.text : > > > { > > > -- > > > 2.24.1 > > > > > > > > > > > > -- > Damien Le Moal > Western Digital Research -- Regards, Atish
On 2020/03/14 6:10, Atish Patra wrote: > On Thu, Mar 12, 2020 at 11:42 PM Damien Le Moal <Damien.LeMoal@wdc.com> wrote: >> >> On Thu, 2020-03-12 at 13:53 -0700, Atish Patra wrote: >>> On Wed, Mar 11, 2020 at 10:11 PM Damien Le Moal <damien.lemoal@wdc.com> wrote: >>>> Add a mechanism for early SoC initialization for platforms that need >>>> additional hardware initialization not possible through the regular >>>> device tree and drivers mechanism. With this, a SoC specific >>>> initialization function can be called very early, before DTB parsing >>>> is done by parse_dtb() in Linux RISC-V kernel setup code. >>>> >>>> This can be very useful for early hardware initialization for No-MMU >>>> kernels booted directly in M-mode because it is quite likely that no >>>> other booting stage exist prior to the No-MMU kernel. >>>> >>>> Example use of a SoC early initialization is as follows: >>>> >>>> static void vendor_abc_early_init(const void *fdt) >>>> { >>>> /* >>>> * some early init code here that can use simple matches >>>> * against the flat device tree file. >>>> */ >>>> } >>>> SOC_EARLY_INIT_DECLARE("vendor,abc", abc_early_init); >>>> >>>> This early initialization function is executed only if the flat device >>>> tree for the board has a 'compatible = "vendor,abc"' entry; >>>> >>>> Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com> >>>> Signed-off-by: Anup Patel <anup.patel@wdc.com> >>>> Reviewed-by: Palmer Dabbelt <palmerdabbelt@google.com> >>>> --- >>>> arch/riscv/include/asm/soc.h | 23 +++++++++++++++++++++++ >>>> arch/riscv/kernel/Makefile | 1 + >>>> arch/riscv/kernel/head.S | 1 + >>>> arch/riscv/kernel/soc.c | 28 ++++++++++++++++++++++++++++ >>>> arch/riscv/kernel/vmlinux.lds.S | 6 ++++++ >>>> 5 files changed, 59 insertions(+) >>>> create mode 100644 arch/riscv/include/asm/soc.h >>>> create mode 100644 arch/riscv/kernel/soc.c >>>> >>>> diff --git a/arch/riscv/include/asm/soc.h b/arch/riscv/include/asm/soc.h >>>> new file mode 100644 >>>> index 000000000000..9b8c332cbe76 >>>> --- /dev/null >>>> +++ b/arch/riscv/include/asm/soc.h >>>> @@ -0,0 +1,23 @@ >>>> +/* SPDX-License-Identifier: GPL-2.0-or-later */ >>>> +/* >>>> + * Copyright (C) 2020 Western Digital Corporation or its affiliates. >>>> + */ >>>> + >>>> +#ifndef _ASM_RISCV_SOC_H >>>> +#define _ASM_RISCV_SOC_H >>>> + >>>> +#include <linux/of.h> >>>> +#include <linux/linkage.h> >>>> +#include <linux/types.h> >>>> + >>>> +#define SOC_EARLY_INIT_DECLARE(compat, fn) \ >>>> + static const struct of_device_id __soc_early_init \ >>>> + __used __section(__soc_early_init_table) \ >>>> + = { .compatible = compat, .data = fn } >>>> + >>> >>> There may be some future kendryte board or some other RISC-V board >>> which want to use SOC_EARLY_INIT_DECLARE. >>> There should be a name parameter as well which allows multiple usage >>> of SOC_EARLY_INIT_DECLARE. >> >> I am not sure I understand your point here. Currently, the call to an >> early init functions is driven by the value (name) specified in the DT >> compatible entry. If what needs to be done in the early init function >> for one SoC is common with another, the same function can be used for >> different SOC_EARLY_INIT_DECLARE() with different compatible strings, >> or the same compatible string used in the different boards DT. No ? Am >> I missing something ? >> > > To use different compatible strings, SOC_EARLY_INIT_DECLARE has to be > declared twice. > As SOC_EARLY_INIT_DECLARE is just a macro that declares > __soc_early_init, redefinition compile error > will happen. That's why __soc_early_init has to be suffixed with name > to avoid the redefinition error. > Here is the diff I am talking about > > -#define SOC_EARLY_INIT_DECLARE(compat, fn) \ > - static const struct of_device_id __soc_early_init \ > +#define SOC_EARLY_INIT_DECLARE(name, compat, fn) > \ > + static const struct of_device_id __soc_early_init__##name > \ > __used __section(__soc_early_init_table) \ > = { .compatible = compat, .data = fn } > OK. Got it. I will make this simple change and send a v4 of the series. > >>> >>>> +void soc_early_init(void); >>>> + >>>> +extern unsigned long __soc_early_init_table_start; >>>> +extern unsigned long __soc_early_init_table_end; >>>> + >>>> +#endif >>>> diff --git a/arch/riscv/kernel/Makefile b/arch/riscv/kernel/Makefile >>>> index 97d0c35f8b37..e4a22999dbc6 100644 >>>> --- a/arch/riscv/kernel/Makefile >>>> +++ b/arch/riscv/kernel/Makefile >>>> @@ -10,6 +10,7 @@ endif >>>> extra-y += head.o >>>> extra-y += vmlinux.lds >>>> >>>> +obj-y += soc.o >>>> obj-y += cpu.o >>>> obj-y += cpufeature.o >>>> obj-y += entry.o >>>> diff --git a/arch/riscv/kernel/head.S b/arch/riscv/kernel/head.S >>>> index 85f2073e7fe4..52ed11b4fda6 100644 >>>> --- a/arch/riscv/kernel/head.S >>>> +++ b/arch/riscv/kernel/head.S >>>> @@ -131,6 +131,7 @@ clear_bss_done: >>>> call kasan_early_init >>>> #endif >>>> /* Start the kernel */ >>>> + call soc_early_init >>>> call parse_dtb >>>> tail start_kernel >>>> >>>> diff --git a/arch/riscv/kernel/soc.c b/arch/riscv/kernel/soc.c >>>> new file mode 100644 >>>> index 000000000000..0b3b3dc9ad0f >>>> --- /dev/null >>>> +++ b/arch/riscv/kernel/soc.c >>>> @@ -0,0 +1,28 @@ >>>> +// SPDX-License-Identifier: GPL-2.0-or-later >>>> +/* >>>> + * Copyright (C) 2020 Western Digital Corporation or its affiliates. >>>> + */ >>>> +#include <linux/init.h> >>>> +#include <linux/libfdt.h> >>>> +#include <asm/pgtable.h> >>>> +#include <asm/soc.h> >>>> + >>>> +/* >>>> + * This is called extremly early, before parse_dtb(), to allow initializing >>>> + * SoC hardware before memory or any device driver initialization. >>>> + */ >>>> +void __init soc_early_init(void) >>>> +{ >>>> + void (*early_fn)(const void *fdt); >>>> + const struct of_device_id *s; >>>> + const void *fdt = dtb_early_va; >>>> + >>>> + for (s = (void *)&__soc_early_init_table_start; >>>> + (void *)s < (void *)&__soc_early_init_table_end; s++) { >>>> + if (!fdt_node_check_compatible(fdt, 0, s->compatible)) { >>>> + early_fn = s->data; >>>> + early_fn(fdt); >>>> + return; >>>> + } >>>> + } >>>> +} >>>> diff --git a/arch/riscv/kernel/vmlinux.lds.S b/arch/riscv/kernel/vmlinux.lds.S >>>> index 1e0193ded420..32b160942f40 100644 >>>> --- a/arch/riscv/kernel/vmlinux.lds.S >>>> +++ b/arch/riscv/kernel/vmlinux.lds.S >>>> @@ -24,6 +24,12 @@ SECTIONS >>>> HEAD_TEXT_SECTION >>>> INIT_TEXT_SECTION(PAGE_SIZE) >>>> INIT_DATA_SECTION(16) >>>> + . = ALIGN(8); >>>> + __soc_early_init_table : { >>>> + __soc_early_init_table_start = .; >>>> + KEEP(*(__soc_early_init_table)) >>>> + __soc_early_init_table_end = .; >>>> + } >>>> /* we have to discard exit text and such at runtime, not link time */ >>>> .exit.text : >>>> { >>>> -- >>>> 2.24.1 >>>> >>>> >>> >>> >> >> -- >> Damien Le Moal >> Western Digital Research > > > > -- > Regards, > Atish >
diff --git a/arch/riscv/include/asm/soc.h b/arch/riscv/include/asm/soc.h new file mode 100644 index 000000000000..9b8c332cbe76 --- /dev/null +++ b/arch/riscv/include/asm/soc.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2020 Western Digital Corporation or its affiliates. + */ + +#ifndef _ASM_RISCV_SOC_H +#define _ASM_RISCV_SOC_H + +#include <linux/of.h> +#include <linux/linkage.h> +#include <linux/types.h> + +#define SOC_EARLY_INIT_DECLARE(compat, fn) \ + static const struct of_device_id __soc_early_init \ + __used __section(__soc_early_init_table) \ + = { .compatible = compat, .data = fn } + +void soc_early_init(void); + +extern unsigned long __soc_early_init_table_start; +extern unsigned long __soc_early_init_table_end; + +#endif diff --git a/arch/riscv/kernel/Makefile b/arch/riscv/kernel/Makefile index 97d0c35f8b37..e4a22999dbc6 100644 --- a/arch/riscv/kernel/Makefile +++ b/arch/riscv/kernel/Makefile @@ -10,6 +10,7 @@ endif extra-y += head.o extra-y += vmlinux.lds +obj-y += soc.o obj-y += cpu.o obj-y += cpufeature.o obj-y += entry.o diff --git a/arch/riscv/kernel/head.S b/arch/riscv/kernel/head.S index 85f2073e7fe4..52ed11b4fda6 100644 --- a/arch/riscv/kernel/head.S +++ b/arch/riscv/kernel/head.S @@ -131,6 +131,7 @@ clear_bss_done: call kasan_early_init #endif /* Start the kernel */ + call soc_early_init call parse_dtb tail start_kernel diff --git a/arch/riscv/kernel/soc.c b/arch/riscv/kernel/soc.c new file mode 100644 index 000000000000..0b3b3dc9ad0f --- /dev/null +++ b/arch/riscv/kernel/soc.c @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2020 Western Digital Corporation or its affiliates. + */ +#include <linux/init.h> +#include <linux/libfdt.h> +#include <asm/pgtable.h> +#include <asm/soc.h> + +/* + * This is called extremly early, before parse_dtb(), to allow initializing + * SoC hardware before memory or any device driver initialization. + */ +void __init soc_early_init(void) +{ + void (*early_fn)(const void *fdt); + const struct of_device_id *s; + const void *fdt = dtb_early_va; + + for (s = (void *)&__soc_early_init_table_start; + (void *)s < (void *)&__soc_early_init_table_end; s++) { + if (!fdt_node_check_compatible(fdt, 0, s->compatible)) { + early_fn = s->data; + early_fn(fdt); + return; + } + } +} diff --git a/arch/riscv/kernel/vmlinux.lds.S b/arch/riscv/kernel/vmlinux.lds.S index 1e0193ded420..32b160942f40 100644 --- a/arch/riscv/kernel/vmlinux.lds.S +++ b/arch/riscv/kernel/vmlinux.lds.S @@ -24,6 +24,12 @@ SECTIONS HEAD_TEXT_SECTION INIT_TEXT_SECTION(PAGE_SIZE) INIT_DATA_SECTION(16) + . = ALIGN(8); + __soc_early_init_table : { + __soc_early_init_table_start = .; + KEEP(*(__soc_early_init_table)) + __soc_early_init_table_end = .; + } /* we have to discard exit text and such at runtime, not link time */ .exit.text : {