diff mbox series

[v2,3/9] riscv: Add SOC early init support

Message ID 20200312051107.1454880-4-damien.lemoal@wdc.com (mailing list archive)
State New, archived
Headers show
Series Kendryte k210 SoC boards support | expand

Commit Message

Damien Le Moal March 12, 2020, 5:11 a.m. UTC
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

Comments

Sean Anderson March 12, 2020, 6:21 p.m. UTC | #1
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
Atish Patra March 12, 2020, 7:50 p.m. UTC | #2
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>
Atish Patra March 12, 2020, 8:53 p.m. UTC | #3
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
>
>
Damien Le Moal March 13, 2020, 5:52 a.m. UTC | #4
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
Damien Le Moal March 13, 2020, 6:42 a.m. UTC | #5
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
> > 
> > 
> 
>
Atish Patra March 13, 2020, 9:10 p.m. UTC | #6
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
Damien Le Moal March 16, 2020, 12:34 a.m. UTC | #7
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 mbox series

Patch

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 :
 	{