[PATCH v2 2/2] lib: utils: reset: Add T-HEAD sample platform reset driver

guoren at kernel.org guoren at kernel.org
Sat Apr 17 17:26:17 BST 2021


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.

Change in v2 (by Anup):
 - Clean up includes in fdt_reset_thead.h and keep the minimum.
 - Add macro of fence.i & ebreak in riscv_asm&barrier.h.
 - Fixup system_reset_check() for ebreak and test it on hardware.
 - Add __FDT_RESET_THEAD_H__ in fdt_reset_thead.h.

Signed-off-by: Guo Ren <guoren at linux.alibaba.com>
Link: http://lists.infradead.org/pipermail/opensbi/2021-April/000863.html
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>
---
 include/sbi/riscv_asm.h               |   5 ++
 include/sbi/riscv_barrier.h           |   3 +
 lib/utils/reset/fdt_reset.c           |   2 +
 lib/utils/reset/fdt_reset_thead.c     | 130 ++++++++++++++++++++++++++++++++++
 lib/utils/reset/fdt_reset_thead.h     |  23 ++++++
 lib/utils/reset/fdt_reset_thead_asm.S |  47 ++++++++++++
 lib/utils/reset/objects.mk            |   2 +
 7 files changed, 212 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/include/sbi/riscv_asm.h b/include/sbi/riscv_asm.h
index 9fa0fe5..1ff36de 100644
--- a/include/sbi/riscv_asm.h
+++ b/include/sbi/riscv_asm.h
@@ -157,6 +157,11 @@ void csr_write_num(int csr_num, unsigned long val);
 		__asm__ __volatile__("wfi" ::: "memory"); \
 	} while (0)
 
+#define ebreak()                                             \
+	do {                                              \
+		__asm__ __volatile__("ebreak" ::: "memory"); \
+	} while (0)
+
 /* Get current HART id */
 #define current_hartid()	((unsigned int)csr_read(CSR_MHARTID))
 
diff --git a/include/sbi/riscv_barrier.h b/include/sbi/riscv_barrier.h
index 905ecb4..1fba8b8 100644
--- a/include/sbi/riscv_barrier.h
+++ b/include/sbi/riscv_barrier.h
@@ -18,6 +18,9 @@
 #define RISCV_FENCE(p, s) \
 	__asm__ __volatile__ ("fence " #p "," #s : : : "memory")
 
+#define RISCV_FENCE_I \
+	__asm__ __volatile__ ("fence.i" : : : "memory")
+
 /* Read & Write Memory barrier */
 #define mb()			RISCV_FENCE(iorw,iorw)
 
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..cce0141
--- /dev/null
+++ b/lib/utils/reset/fdt_reset_thead.c
@@ -0,0 +1,130 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#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>
+#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();
+
+		RISCV_FENCE_I;
+
+		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;
+}
+
+int thead_system_reset_check(u32 type, u32 reason)
+{
+	return 1;
+}
+
+void thead_system_reset(u32 type, u32 reason)
+{
+	ebreak();
+}
+
+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_check = thead_system_reset_check,
+	.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..d7a686e
--- /dev/null
+++ b/lib/utils/reset/fdt_reset_thead.h
@@ -0,0 +1,23 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __FDT_RESET_THEAD_H__
+#define __FDT_RESET_THEAD_H__
+
+#define MAX_CUSTOM_CSR	32
+
+#ifndef __ASSEMBLER__
+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 /* __ASSEMBLER__ */
+
+#endif /* __FDT_RESET_THEAD_H__ */
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




More information about the opensbi mailing list