[PATCH 2/2] lib: utils: reset: Add T-HEAD sample platform reset driver
Guo Ren
guoren at kernel.org
Sat Apr 17 15:08:17 BST 2021
On Sat, Apr 17, 2021 at 7:50 PM Jessica Clarke <jrtc27 at jrtc27.com> wrote:
>
> On 13 Apr 2021, at 04:44, guoren at kernel.org wrote:
> >
> > From: Guo Ren <guoren at linux.alibaba.com>
> >
> > This driver is for T-HEAD test chip, fpga. It could work with
> > all T-HEAD riscv processors: C9xx series.
> >
> > example1: (Using io-regs for reset)
> > reset: reset-sample {
> > compatible = "thead,reset-sample";
> > plic-delegate = <0xff 0xd81ffffc>;
> > entry-reg = <0xff 0xff019050>;
> > entry-cnt = <4>;
> > control-reg = <0xff 0xff015004>;
> > control-val = <0x1c>;
> > csr-copy = <0x7f3 0x7c0 0x7c1 0x7c2 0x7c3 0x7c5 0x7cc>;
> > };
> >
> > example2: (Using csr-regs for reset)
> > reset: reset-sample {
> > compatible = "thead,reset-sample";
> > plic-delegate = <0xff 0xd81ffffc>;
> > using-csr-reset;
> > csr-copy = <0x7c0 0x7c1 0x7c2 0x7c3 0x7c5 0x7cc
> > 0x3b0 0x3b1 0x3b2 0x3b3
> > 0x3b4 0x3b5 0x3b6 0x3b7
> > 0x3a0>;
> > };
> >
> > example3: (Only delegate plic enable to S-mode)
> > reset: reset-sample {
> > compatible = "thead,reset-sample";
> > plic-delegate = <0xff 0xd81ffffc>;
> > };
> >
> > After this patch, all T-HEAD c9xx would use platform/generic with fw_dynamic
> > as default:
> >
> > CROSS_COMPILE=riscv64-linux-gnu- PLATFORM=generic FW_PIC=y /usr/bin/make
> >
> > dts full example:
> > cpus {
> > #address-cells = <1>;
> > #size-cells = <0>;
> > timebase-frequency = <0x2dc6c0>;
> > cpu at 0 {
> > device_type = "cpu";
> > reg = <0>;
> > status = "okay";
> > compatible = "riscv";
> > riscv,isa = "rv64imafdcsu";
> > mmu-type = "riscv,sv39";
> > cpu0_intc: interrupt-controller {
> > #interrupt-cells = <1>;
> > compatible = "riscv,cpu-intc";
> > interrupt-controller;
> > };
> > };
> > cpu at 1 {
> > device_type = "cpu";
> > reg = <1>;
> > status = "fail";
> > compatible = "riscv";
> > riscv,isa = "rv64imafdcsu";
> > mmu-type = "riscv,sv39";
> > cpu1_intc: interrupt-controller {
> > #interrupt-cells = <1>;
> > compatible = "riscv,cpu-intc";
> > interrupt-controller;
> > };
> > };
> > cpu at 2 {
> > device_type = "cpu";
> > reg = <2>;
> > status = "fail";
> > compatible = "riscv";
> > riscv,isa = "rv64imafdcsu";
> > mmu-type = "riscv,sv39";
> > cpu2_intc: interrupt-controller {
> > #interrupt-cells = <1>;
> > compatible = "riscv,cpu-intc";
> > interrupt-controller;
> > };
> > };
> > cpu at 3 {
> > device_type = "cpu";
> > reg = <3>;
> > status = "fail";
> > compatible = "riscv";
> > riscv,isa = "rv64imafdcsu";
> > mmu-type = "riscv,sv39";
> > cpu3_intc: interrupt-controller {
> > #interrupt-cells = <1>;
> > compatible = "riscv,cpu-intc";
> > interrupt-controller;
> > };
> > };
> > };
> >
> > soc {
> > #address-cells = <2>;
> > #size-cells = <2>;
> > compatible = "simple-bus";
> > ranges;
> >
> > reset: reset-sample {
> > compatible = "thead,reset-sample";
> > plic-delegate = <0xff 0xd81ffffc>;
> > using-csr-reset;
> > csr-copy = <
> > 0x7c0 0x7c1 0x7c2 0x7c3 0x7c5 0x7cc
> > 0x3b0 0x3b1 0x3b2 0x3b3
> > 0x3b4 0x3b5 0x3b6 0x3b7
> > 0x3a0
> > >;
> > };
> >
> > clint0: clint at ffdc000000 {
> > compatible = "riscv,clint0";
> > interrupts-extended = <
> > &cpu0_intc 3 &cpu0_intc 7
> > &cpu1_intc 3 &cpu1_intc 7
> > &cpu2_intc 3 &cpu2_intc 7
> > &cpu3_intc 3 &cpu3_intc 7
> > &cpu4_intc 3 &cpu4_intc 7
> > >;
> > reg = <0xff 0xdc000000 0x0 0x04000000>;
> > clint,has-no-64bit-mmio;
> > };
> >
> > intc: interrupt-controller at ffd8000000 {
> > #interrupt-cells = <1>;
> > compatible = "riscv,plic0";
> > interrupt-controller;
> > interrupts-extended = <
> > &cpu0_intc 0xffffffff &cpu0_intc 9
> > &cpu1_intc 0xffffffff &cpu1_intc 9
> > &cpu2_intc 0xffffffff &cpu2_intc 9
> > &cpu3_intc 0xffffffff &cpu3_intc 9
> > >;
> > reg = <0xff 0xd8000000 0x0 0x04000000>;
> > reg-names = "control";
> > riscv,max-priority = <7>;
> > riscv,ndev = <80>;
> > };
> > }
> >
> > The platform/thead will be deprecated.
>
> This seems extremely complicated for just doing a reset, yet the reset itself
> is just an ebreak?
The ebreak is used to break down the gdb test, Jtag downloads the
vmlinux, gdb continues..., when the test finished, we'll call poweroff
-> sbi_reset -> ebreak in Linux shell.
Test script would come out :)
> Is there any documentation for how this is meant to work
> rather than just the above device tree spew, because right now it doesn’t make
> any sense to me?
We are a CPU vendor, not a soc vendor. So this is a sample for our
customers to help them bring up basic system in a short time.
Firstly, we give them a simple reset address, reset control address in
SOC integration. So they needn't care about multi-harts boot code at
first and all are controlled by the driver. For this we also design a
fdt_reset_thead_asm.S for warm-init.
If customers want to bring up basic Linux with our CPU in FPGA, zebu,
Veloce, any emulators ... even any tapouted chips ... They just need
devicetree + gdbinit.script + fw_dynamic.bin + Image without writing
any bootloader codes.
And fw_dynamic.bin + Image also could compatible with qemu + platform
generic boards (sifive board). A union opensbi & Linux is good idea
for riscv Linux eco-systrem developement.
That's the reason why we change into platform/generic.
>
> Jess
>
> > Signed-off-by: Guo Ren <guoren at linux.alibaba.com>
> > Cc: Anup Patel <anup.patel at wdc.com>
> > Cc: Atish Patra <atish.patra at wdc.com>
> > Cc: Xiang W <wxjstz at 126.com>
> > Cc: Bin Meng <bmeng.cn at gmail.com>
> > ---
> > lib/utils/reset/fdt_reset.c | 2 +
> > lib/utils/reset/fdt_reset_thead.c | 117 ++++++++++++++++++++++++++++++++++
> > lib/utils/reset/fdt_reset_thead.h | 25 ++++++++
> > lib/utils/reset/fdt_reset_thead_asm.S | 47 ++++++++++++++
> > lib/utils/reset/objects.mk | 2 +
> > 5 files changed, 193 insertions(+)
> > create mode 100644 lib/utils/reset/fdt_reset_thead.c
> > create mode 100644 lib/utils/reset/fdt_reset_thead.h
> > create mode 100644 lib/utils/reset/fdt_reset_thead_asm.S
> >
> > diff --git a/lib/utils/reset/fdt_reset.c b/lib/utils/reset/fdt_reset.c
> > index dead8a3..82532c2 100644
> > --- a/lib/utils/reset/fdt_reset.c
> > +++ b/lib/utils/reset/fdt_reset.c
> > @@ -13,10 +13,12 @@
> >
> > extern struct fdt_reset fdt_reset_sifive;
> > extern struct fdt_reset fdt_reset_htif;
> > +extern struct fdt_reset fdt_reset_thead;
> >
> > static struct fdt_reset *reset_drivers[] = {
> > &fdt_reset_sifive,
> > &fdt_reset_htif,
> > + &fdt_reset_thead,
> > };
> >
> > static struct fdt_reset *current_driver = NULL;
> > diff --git a/lib/utils/reset/fdt_reset_thead.c b/lib/utils/reset/fdt_reset_thead.c
> > new file mode 100644
> > index 0000000..12eb1fc
> > --- /dev/null
> > +++ b/lib/utils/reset/fdt_reset_thead.c
> > @@ -0,0 +1,117 @@
> > +/*
> > + * SPDX-License-Identifier: BSD-2-Clause
> > + */
> > +
> > +#include "fdt_reset_thead.h"
> > +
> > +struct custom_csr custom_csr[MAX_CUSTOM_CSR];
> > +
> > +#define CSR_OPCODE 0x39073
> > +static void clone_csrs(int cnt)
> > +{
> > + unsigned long i;
> > +
> > + for (i = 0; i < cnt; i++) {
> > + /* Write csr BIT[31 - 20] to stub */
> > + __reset_thead_csr_stub[3*i + 1] =
> > + CSR_OPCODE | (custom_csr[i].index << 20);
> > +
> > + /* Mask csr BIT[31 - 20] */
> > + *(u32 *)&__fdt_reset_thead_csrr &= BIT(20) - 1;
> > + smp_mb();
> > +
> > + /* Write csr BIT[31 - 20] to __fdt_reset_thead_csrr */
> > + *(u32 *)&__fdt_reset_thead_csrr |= custom_csr[i].index << 20;
> > + smp_mb();
> > +
> > + __asm__ __volatile__("fence.i\n":::"memory");
> > +
> > + custom_csr[i].value = __fdt_reset_thead_csrr();
> > + }
> > +}
> > +
> > +extern void __thead_pre_start_warm(void);
> > +static int thead_reset_init(void *fdt, int nodeoff,
> > + const struct fdt_match *match)
> > +{
> > + void *p;
> > + const fdt64_t *val;
> > + const fdt32_t *val_w;
> > + int len, i, cnt;
> > + u32 tmp = 0;
> > +
> > + /* Prepare clone csrs */
> > + val_w = fdt_getprop(fdt, nodeoff, "csr-copy", &len);
> > + if (len > 0 && val_w) {
> > + cnt = len / sizeof(fdt32_t);
> > +
> > + if (cnt > MAX_CUSTOM_CSR)
> > + sbi_hart_hang();
> > +
> > + for (i = 0; i < cnt; i++) {
> > + custom_csr[i].index = fdt32_to_cpu(val_w[i]);
> > + }
> > + }
> > +
> > + if (cnt)
> > + clone_csrs(cnt);
> > +
> > + /* Delegate plic enable regs for S-mode */
> > + val = fdt_getprop(fdt, nodeoff, "plic-delegate", &len);
> > + if (len > 0 && val) {
> > + p = (void *)fdt64_to_cpu(*val);
> > + writel(BIT(0), p);
> > + }
> > +
> > + /* Old reset method for secondary harts */
> > + if (fdt_getprop(fdt, nodeoff, "using-csr-reset", &len)) {
> > + csr_write(0x7c7, (u64)&__thead_pre_start_warm);
> > + csr_write(0x7c6, -1);
> > + }
> > +
> > + /* Custom reset method for secondary harts */
> > + val = fdt_getprop(fdt, nodeoff, "entry-reg", &len);
> > + if (len > 0 && val) {
> > + p = (void *)fdt64_to_cpu(*val);
> > +
> > + val_w = fdt_getprop(fdt, nodeoff, "entry-cnt", &len);
> > + if (len > 0 && val_w) {
> > + tmp = fdt32_to_cpu(*val_w);
> > +
> > + for (i = 0; i < tmp; i++) {
> > + writel((u64)(&__thead_pre_start_warm), p + 8*i);
> > + writel((u64)(&__thead_pre_start_warm) >> 32, p + 8*i + 4);
> > + }
> > + }
> > +
> > + val = fdt_getprop(fdt, nodeoff, "control-reg", &len);
> > + if (len > 0 && val) {
> > + p = (void *)fdt64_to_cpu(*val);
> > +
> > + val_w = fdt_getprop(fdt, nodeoff, "control-val", &len);
> > + if (len > 0 && val_w) {
> > + tmp = fdt32_to_cpu(*val_w);
> > + tmp |= readl(p);
> > + writel(tmp, p);
> > + }
> > + }
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +void thead_system_reset(u32 type, u32 reason)
> > +{
> > + __asm__ __volatile__("ebreak\n");
> > +}
> > +
> > +static const struct fdt_match thead_reset_match[] = {
> > + { .compatible = "thead,reset-sample" },
> > + { },
> > +};
> > +
> > +struct fdt_reset fdt_reset_thead = {
> > + .match_table = thead_reset_match,
> > + .init = thead_reset_init,
> > + .system_reset = thead_system_reset
> > +};
> > diff --git a/lib/utils/reset/fdt_reset_thead.h b/lib/utils/reset/fdt_reset_thead.h
> > new file mode 100644
> > index 0000000..dbd76ad
> > --- /dev/null
> > +++ b/lib/utils/reset/fdt_reset_thead.h
> > @@ -0,0 +1,25 @@
> > +/*
> > + * SPDX-License-Identifier: BSD-2-Clause
> > + */
> > +
> > +#define MAX_CUSTOM_CSR 32
> > +
> > +#ifndef __ASSEMBLER__
> > +#include <libfdt.h>
> > +#include <sbi/riscv_io.h>
> > +#include <sbi/sbi_bitops.h>
> > +#include <sbi/sbi_hart.h>
> > +#include <sbi/sbi_scratch.h>
> > +#include <sbi_utils/fdt/fdt_helper.h>
> > +#include <sbi_utils/reset/fdt_reset.h>
> > +
> > +struct custom_csr {
> > + unsigned long index;
> > + unsigned long value;
> > +};
> > +
> > +u64 __fdt_reset_thead_csrr(void);
> > +
> > +extern struct custom_csr custom_csr[MAX_CUSTOM_CSR];
> > +extern u32 __reset_thead_csr_stub[];
> > +#endif
> > diff --git a/lib/utils/reset/fdt_reset_thead_asm.S b/lib/utils/reset/fdt_reset_thead_asm.S
> > new file mode 100644
> > index 0000000..8237951
> > --- /dev/null
> > +++ b/lib/utils/reset/fdt_reset_thead_asm.S
> > @@ -0,0 +1,47 @@
> > +/*
> > + * SPDX-License-Identifier: BSD-2-Clause
> > + */
> > +
> > +#include <sbi/riscv_asm.h>
> > +#include "fdt_reset_thead.h"
> > +
> > +/*
> > + * csrrs rd, csr, rs1
> > + * |31 20|19 15|14 12|11 7|6 0|
> > + * csr rs1 010 rd 1110011
> > + */
> > +#define CSR_STUB addi x0, x0, 0
> > +
> > + .option norvc
> > + .align 3
> > + .global __fdt_reset_thead_csrr
> > +__fdt_reset_thead_csrr:
> > + csrrs a0, 0, x0
> > + ret
> > +
> > + .align 3
> > + .global __thead_pre_start_warm
> > +__thead_pre_start_warm:
> > + /*
> > + * Clear L1 cache & BTB & BHT ...
> > + */
> > + li t1, 0x70013
> > + csrw 0x7c2, t1
> > + fence rw,rw
> > +
> > + lla t1, custom_csr
> > +
> > + .global __reset_thead_csr_stub
> > +__reset_thead_csr_stub:
> > +.rept MAX_CUSTOM_CSR
> > + REG_L t2, 8(t1)
> > + CSR_STUB
> > + addi t1, t1, 16
> > +.endr
> > + /*
> > + * Clear L1 cache & BTB & BHT ...
> > + */
> > + li t1, 0x70013
> > + csrw 0x7c2, t1
> > + fence rw,rw
> > + j _start_warm
> > diff --git a/lib/utils/reset/objects.mk b/lib/utils/reset/objects.mk
> > index b447261..b6619f4 100644
> > --- a/lib/utils/reset/objects.mk
> > +++ b/lib/utils/reset/objects.mk
> > @@ -10,3 +10,5 @@
> > libsbiutils-objs-y += reset/fdt_reset.o
> > libsbiutils-objs-y += reset/fdt_reset_htif.o
> > libsbiutils-objs-y += reset/fdt_reset_sifive.o
> > +libsbiutils-objs-y += reset/fdt_reset_thead.o
> > +libsbiutils-objs-y += reset/fdt_reset_thead_asm.o
> > --
> > 2.7.4
> >
> >
> > --
> > opensbi mailing list
> > opensbi at lists.infradead.org
> > http://lists.infradead.org/mailman/listinfo/opensbi
>
--
Best Regards
Guo Ren
ML: https://lore.kernel.org/linux-csky/
More information about the opensbi
mailing list