* [PATCH v4 0/5] Initial ESWIN/EIC7700 support
@ 2025-12-09 10:22 Bo Gan
2025-12-09 10:22 ` [PATCH v4 1/5] lib: sbi_hart_pmp: make sbi_hart_pmp_fence public Bo Gan
` (4 more replies)
0 siblings, 5 replies; 6+ messages in thread
From: Bo Gan @ 2025-12-09 10:22 UTC (permalink / raw)
To: opensbi; +Cc: linmin, pinkesh.vaghela, gaohan, samuel, wangxiang
EIC7700 is the SoC used in HiFive P550 and Milk-V Megrez. This SoC is
currently one of the only off-the-shelf board/chips that support H
extension, although it's v0.6.1. It also supports pre-ratified N-trace.
Add support for it so people can benefit from latest OpenSBI features.
The device-tree of HiFive P550 has been upstreamed to Linux:
https://lore.kernel.org/all/20250825132427.1618089-1-pinkesh.vaghela@einfochips.com/
However U-boot is not, and there are bugs in vendor U-boot device-tree,
and also inconsistencies between the two. Thus, this patch is coded with
the upstreamed device-tree as the reference, but tested with the patched
vendor U-boot device tree as `FW_FDT_PATH`. The patched vendor U-boot is
hosted here: https://github.com/ganboing/u-boot-eic7x/tree/eic7x-dt-fix
Refer to the last PATCH for the instructions on building the firmware
blob and launch it through UART boot.
The major complication of this chip is that it requires certain memory
regions to be blocked with PMP entries to prevent speculative execution
or HW prefetcher from touching the data-cacheable regions within to
avoid bus errors. Due to the fact that this SoC handles cache incoherent
DMA by mapping memory twice, one as cached, and the other as uncached,
we also need an extra PMP to protect the OpenSBI in the uncached portion
in address space. The PMP handling is tricky, so I documented it very
extensively for people to reason about it. I managed to get it done with
only NAPOT PMP entries and still got 1 free PMP for root harts for die 0
(No free PMP for die 1 root harts). This even permits a udomain/tdomain
like partitioning, so we can even try out TEEs. Sample boot log:
OpenSBI v1.7-90-g3544b479
____ _____ ____ _____
/ __ \ / ____| _ \_ _|
| | | |_ __ ___ _ __ | (___ | |_) || |
| | | | '_ \ / _ \ '_ \ \___ \| _ < | |
| |__| | |_) | __/ | | |____) | |_) || |_
\____/| .__/ \___|_| |_|_____/|____/_____|
| |
|_|
Platform Name : SiFive HiFive Premier P550
Platform Features : medeleg
Platform HART Count : 4
Platform HART Protection : eic7700_pmp
Platform IPI Device : aclint-mswi
Platform Timer Device : aclint-mtimer @ 1000000Hz
Platform Console Device : uart8250
Platform HSM Device : ---
Platform PMU Device : ---
Platform Reboot Device : eic770x_reset
Platform Shutdown Device : ---
Platform Suspend Device : ---
Platform CPPC Device : ---
Firmware Base : 0x80000000
Firmware Size : 613 KB
Firmware RW Offset : 0x80000
Firmware RW Size : 101 KB
Firmware Heap Offset : 0x8d000
Firmware Heap Size : 49 KB (total), 1 KB (reserved), 14 KB (used), 33 KB (free)
Firmware Scratch Size : 4096 B (total), 424 B (used), 3672 B (free)
Runtime SBI Version : 3.0
Standard SBI Extensions : time,rfnc,ipi,base,hsm,srst,pmu,dbcn,fwft,legacy,dbtr,sse
Experimental SBI Extensions : none
Domain0 Name : root
Domain0 Boot HART : 0
Domain0 HARTs : 0*,1*,2*,3*
Domain0 Region00 : 0x0000000080000000-0x00000000800fffff M: (F,R,W,X) S/U: ()
Domain0 Region01 : 0x000000c000000000-0x000000c0000fffff M: (I,F,R,W,X) S/U: ()
Domain0 Region02 : 0x0000000002000000-0x000000000200ffff M: (I,R,W) S/U: ()
Domain0 Region03 : 0x0000000000000000-0x000000007fffffff M: (I,R,W) S/U: (R,W)
Domain0 Region04 : 0x0000000000000000-0x0000000fffffffff M: (R,W) S/U: (R,W,X)
Domain0 Region05 : 0x0000000000000000-0x0000007fffffffff M: (I) S/U: ()
Domain0 Region06 : 0x0000000000000000-0xffffffffffffffff M: () S/U: (R,W,X)
Domain0 Next Address : 0x0000000080200000
Domain0 Next Arg1 : 0x00000000f8000000
Domain0 Next Mode : S-mode
Domain0 SysReset : yes
Domain0 SysSuspend : yes
Domain1 Name : trusted-domain
Domain1 Boot HART : -1
Domain1 HARTs :
Domain1 Region00 : 0x0000000080000000-0x00000000800fffff M: (F,R,W,X) S/U: ()
Domain1 Region01 : 0x000000c000000000-0x000000c0000fffff M: (I,F,R,W,X) S/U: ()
Domain1 Region02 : 0x0000000050910000-0x0000000050910fff M: (I,R,W) S/U: (R,W)
Domain1 Region03 : 0x0000000002000000-0x000000000200ffff M: (I,R,W) S/U: ()
Domain1 Region04 : 0x000000047ff00000-0x000000047fffffff M: () S/U: (R,W,X)
Domain1 Region05 : 0x0000000000000000-0x000000007fffffff M: (I,R,W) S/U: ()
Domain1 Region06 : 0x0000000000000000-0x0000007fffffffff M: (I) S/U: ()
Domain1 Next Address : 0x000000047ff00000
Domain1 Next Arg1 : 0x0000000000000000
Domain1 Next Mode : S-mode
Domain1 SysReset : no
Domain1 SysSuspend : no
Domain2 Name : untrusted-domain
Domain2 Boot HART : -1
Domain2 HARTs :
Domain2 Region00 : 0x0000000080000000-0x00000000800fffff M: (F,R,W,X) S/U: ()
Domain2 Region01 : 0x000000c000000000-0x000000c0000fffff M: (I,F,R,W,X) S/U: ()
Domain2 Region02 : 0x0000000002000000-0x000000000200ffff M: (I,R,W) S/U: ()
Domain2 Region03 : 0x000000047ff00000-0x000000047fffffff M: () S/U: ()
Domain2 Region04 : 0x0000000000000000-0x0000000fffffffff M: (R,W) S/U: (R,W,X)
Domain2 Region05 : 0x0000000000000000-0x0000007fffffffff M: (I) S/U: ()
Domain2 Region06 : 0x0000000000000000-0xffffffffffffffff M: () S/U: (R,W,X)
Domain2 Next Address : 0x0000000080000000
Domain2 Next Arg1 : 0x00000000f8000000
Domain2 Next Mode : S-mode
Domain2 SysReset : no
Domain2 SysSuspend : no
Boot HART ID : 0
Boot HART Domain : root
Boot HART Priv Version : v1.11
Boot HART Base ISA : rv64imafdchx
Boot HART ISA Extensions : sscofpmf,zihpm,sdtrig
Boot HART PMP Count : 8
Boot HART PMP Granularity : 12 bits
Boot HART PMP Address Bits : 39
Boot HART MHPM Info : 4 (0x00000078)
Boot HART Debug Triggers : 4 triggers
Boot HART MIDELEG : 0x0000000000002666
Boot HART MEDELEG : 0x0000000000f0b509
Signed-off-by: Bo Gan <ganboing@gmail.com>
---
Changes in v4:
- Adapt to the hart protection abstraction.
Also make use of sbi_hart_pmp_fence for correctness.
- Specify MMIO flag for the uncached mapping of OpenSBI.
It'll avoid adding an extraneous reserved memory region in FDT for S mode.
Changes in v3:
- Figure out the cause behind bus error, and document it properly
- Drop the consolidation logic and let the lib/memregion logic to
optimize out unnecessary regions -- simplifies many things.
- Better and more comprehensive comments in source code.
- Support tdomain/udomain like use cases on die 0.
Changes in v2:
- Major enhancement of PMP consolidation logic. Also fixed a Linux
Panic bug due to the mismatch between PMP settings and reserved
memory regions passed to Linux via FDT.
- Also protects the OpenSBI firmware in uncached memory portion of
address space.
- More detailed documentation on EIC770X/P550
---
Bo Gan (5):
lib: sbi_hart_pmp: make sbi_hart_pmp_fence public
lib: sbi_domain: add sbi_domain_get_oldpmp_flags
lib: sbi_domain: make is_region_subset public
lib: sbi: give platform choice of using single memregion to cover
OpenSBI
platform: generic: eswin: add EIC7700
include/sbi/sbi_domain.h | 29 ++
include/sbi/sbi_hart_pmp.h | 1 +
include/sbi/sbi_platform.h | 21 ++
lib/sbi/sbi_domain.c | 81 +++--
lib/sbi/sbi_hart_pmp.c | 19 +-
platform/generic/Kconfig | 5 +
platform/generic/configs/defconfig | 1 +
platform/generic/eswin/Kconfig | 29 ++
platform/generic/eswin/eic770x.c | 398 +++++++++++++++++++++++
platform/generic/eswin/objects.mk | 11 +
platform/generic/include/eswin/eic770x.h | 73 +++++
11 files changed, 619 insertions(+), 49 deletions(-)
create mode 100644 platform/generic/eswin/Kconfig
create mode 100644 platform/generic/eswin/eic770x.c
create mode 100644 platform/generic/eswin/objects.mk
create mode 100644 platform/generic/include/eswin/eic770x.h
--
2.34.1
--
opensbi mailing list
opensbi@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/opensbi
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v4 1/5] lib: sbi_hart_pmp: make sbi_hart_pmp_fence public
2025-12-09 10:22 [PATCH v4 0/5] Initial ESWIN/EIC7700 support Bo Gan
@ 2025-12-09 10:22 ` Bo Gan
2025-12-09 10:22 ` [PATCH v4 2/5] lib: sbi_domain: add sbi_domain_get_oldpmp_flags Bo Gan
` (3 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Bo Gan @ 2025-12-09 10:22 UTC (permalink / raw)
To: opensbi; +Cc: linmin, pinkesh.vaghela, gaohan, samuel, wangxiang
sbi_hart_pmp_fence can now be utilized by other hart-protection
implementation.
Signed-off-by: Bo Gan <ganboing@gmail.com>
---
include/sbi/sbi_hart_pmp.h | 1 +
lib/sbi/sbi_hart_pmp.c | 2 +-
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/include/sbi/sbi_hart_pmp.h b/include/sbi/sbi_hart_pmp.h
index f54e8b2a..a7765d17 100644
--- a/include/sbi/sbi_hart_pmp.h
+++ b/include/sbi/sbi_hart_pmp.h
@@ -15,6 +15,7 @@ unsigned int sbi_hart_pmp_count(struct sbi_scratch *scratch);
unsigned int sbi_hart_pmp_log2gran(struct sbi_scratch *scratch);
unsigned int sbi_hart_pmp_addrbits(struct sbi_scratch *scratch);
bool sbi_hart_smepmp_is_fw_region(unsigned int pmp_idx);
+void sbi_hart_pmp_fence(void);
int sbi_hart_pmp_init(struct sbi_scratch *scratch);
#endif
diff --git a/lib/sbi/sbi_hart_pmp.c b/lib/sbi/sbi_hart_pmp.c
index ab96e2fa..08bc2cef 100644
--- a/lib/sbi/sbi_hart_pmp.c
+++ b/lib/sbi/sbi_hart_pmp.c
@@ -61,7 +61,7 @@ bool sbi_hart_smepmp_is_fw_region(unsigned int pmp_idx)
return bitmap_test(fw_smepmp_ids, pmp_idx) ? true : false;
}
-static void sbi_hart_pmp_fence(void)
+void sbi_hart_pmp_fence(void)
{
/*
* As per section 3.7.2 of privileged specification v1.12,
--
2.34.1
--
opensbi mailing list
opensbi@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/opensbi
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH v4 2/5] lib: sbi_domain: add sbi_domain_get_oldpmp_flags
2025-12-09 10:22 [PATCH v4 0/5] Initial ESWIN/EIC7700 support Bo Gan
2025-12-09 10:22 ` [PATCH v4 1/5] lib: sbi_hart_pmp: make sbi_hart_pmp_fence public Bo Gan
@ 2025-12-09 10:22 ` Bo Gan
2025-12-09 10:22 ` [PATCH v4 3/5] lib: sbi_domain: make is_region_subset public Bo Gan
` (2 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Bo Gan @ 2025-12-09 10:22 UTC (permalink / raw)
To: opensbi; +Cc: linmin, pinkesh.vaghela, gaohan, samuel, wangxiang
Factor out logic in `sbi_hart_oldpmp_configure` into function
`sbi_domain_get_oldpmp_flags`, analogous to `sbi_domain_get_smepmp_flags`.
Platform specific hart-protection implementation can now leverage it.
Signed-off-by: Bo Gan <ganboing@gmail.com>
---
include/sbi/sbi_domain.h | 7 +++++++
lib/sbi/sbi_domain.c | 22 ++++++++++++++++++++++
lib/sbi/sbi_hart_pmp.c | 17 +----------------
3 files changed, 30 insertions(+), 16 deletions(-)
diff --git a/include/sbi/sbi_domain.h b/include/sbi/sbi_domain.h
index 1196d609..3360e090 100644
--- a/include/sbi/sbi_domain.h
+++ b/include/sbi/sbi_domain.h
@@ -253,6 +253,13 @@ void sbi_domain_memregion_init(unsigned long addr,
unsigned long flags,
struct sbi_domain_memregion *reg);
+/**
+ * Return the oldpmp pmpcfg LRWX encoding for the flags in @reg.
+ *
+ * @param reg pointer to memory region; its flags field encodes permissions.
+ */
+unsigned int sbi_domain_get_oldpmp_flags(struct sbi_domain_memregion *reg);
+
/**
* Return the Smepmp pmpcfg LRWX encoding for the flags in @reg.
*
diff --git a/lib/sbi/sbi_domain.c b/lib/sbi/sbi_domain.c
index 99f453f9..1bc64922 100644
--- a/lib/sbi/sbi_domain.c
+++ b/lib/sbi/sbi_domain.c
@@ -121,6 +121,28 @@ void sbi_domain_memregion_init(unsigned long addr,
}
}
+unsigned int sbi_domain_get_oldpmp_flags(struct sbi_domain_memregion *reg)
+{
+
+ unsigned int pmp_flags = 0;
+
+ /*
+ * If permissions are to be enforced for all modes on
+ * this region, the lock bit should be set.
+ */
+ if (reg->flags & SBI_DOMAIN_MEMREGION_ENF_PERMISSIONS)
+ pmp_flags |= PMP_L;
+
+ if (reg->flags & SBI_DOMAIN_MEMREGION_SU_READABLE)
+ pmp_flags |= PMP_R;
+ if (reg->flags & SBI_DOMAIN_MEMREGION_SU_WRITABLE)
+ pmp_flags |= PMP_W;
+ if (reg->flags & SBI_DOMAIN_MEMREGION_SU_EXECUTABLE)
+ pmp_flags |= PMP_X;
+
+ return pmp_flags;
+}
+
unsigned int sbi_domain_get_smepmp_flags(struct sbi_domain_memregion *reg)
{
unsigned int pmp_flags = 0;
diff --git a/lib/sbi/sbi_hart_pmp.c b/lib/sbi/sbi_hart_pmp.c
index 08bc2cef..c9b6850a 100644
--- a/lib/sbi/sbi_hart_pmp.c
+++ b/lib/sbi/sbi_hart_pmp.c
@@ -271,22 +271,7 @@ static int sbi_hart_oldpmp_configure(struct sbi_scratch *scratch)
if (!is_valid_pmp_idx(pmp_count, pmp_idx))
return SBI_EFAIL;
- pmp_flags = 0;
-
- /*
- * If permissions are to be enforced for all modes on
- * this region, the lock bit should be set.
- */
- if (reg->flags & SBI_DOMAIN_MEMREGION_ENF_PERMISSIONS)
- pmp_flags |= PMP_L;
-
- if (reg->flags & SBI_DOMAIN_MEMREGION_SU_READABLE)
- pmp_flags |= PMP_R;
- if (reg->flags & SBI_DOMAIN_MEMREGION_SU_WRITABLE)
- pmp_flags |= PMP_W;
- if (reg->flags & SBI_DOMAIN_MEMREGION_SU_EXECUTABLE)
- pmp_flags |= PMP_X;
-
+ pmp_flags = sbi_domain_get_oldpmp_flags(reg);
pmp_addr = reg->base >> PMP_SHIFT;
if (pmp_log2gran <= reg->order && pmp_addr < pmp_addr_max) {
sbi_platform_pmp_set(sbi_platform_ptr(scratch),
--
2.34.1
--
opensbi mailing list
opensbi@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/opensbi
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH v4 3/5] lib: sbi_domain: make is_region_subset public
2025-12-09 10:22 [PATCH v4 0/5] Initial ESWIN/EIC7700 support Bo Gan
2025-12-09 10:22 ` [PATCH v4 1/5] lib: sbi_hart_pmp: make sbi_hart_pmp_fence public Bo Gan
2025-12-09 10:22 ` [PATCH v4 2/5] lib: sbi_domain: add sbi_domain_get_oldpmp_flags Bo Gan
@ 2025-12-09 10:22 ` Bo Gan
2025-12-09 10:22 ` [PATCH v4 4/5] lib: sbi: give platform choice of using single memregion to cover OpenSBI Bo Gan
2025-12-09 10:22 ` [PATCH v4 5/5] platform: generic: eswin: add EIC7700 Bo Gan
4 siblings, 0 replies; 6+ messages in thread
From: Bo Gan @ 2025-12-09 10:22 UTC (permalink / raw)
To: opensbi; +Cc: linmin, pinkesh.vaghela, gaohan, samuel, wangxiang
The helper function is renamed as sbi_domain_memregion_is_subset,
and made public in header file.
Also add a convenient helper of sbi_domain_for_each_memregion_idx.
Signed-off-by: Bo Gan <ganboing@gmail.com>
---
include/sbi/sbi_domain.h | 22 ++++++++++++++++++++++
lib/sbi/sbi_domain.c | 23 +++--------------------
2 files changed, 25 insertions(+), 20 deletions(-)
diff --git a/include/sbi/sbi_domain.h b/include/sbi/sbi_domain.h
index 3360e090..c8a6da99 100644
--- a/include/sbi/sbi_domain.h
+++ b/include/sbi/sbi_domain.h
@@ -164,6 +164,25 @@ struct sbi_domain_memregion {
unsigned long flags;
};
+/** Check if regionA is sub-region of regionB */
+static inline bool sbi_domain_memregion_is_subset(
+ const struct sbi_domain_memregion *regA,
+ const struct sbi_domain_memregion *regB)
+{
+ ulong regA_start = regA->base;
+ ulong regA_end = regA->base + (BIT(regA->order) - 1);
+ ulong regB_start = regB->base;
+ ulong regB_end = regB->base + (BIT(regB->order) - 1);
+
+ if ((regB_start <= regA_start) &&
+ (regA_start < regB_end) &&
+ (regB_start < regA_end) &&
+ (regA_end <= regB_end))
+ return true;
+
+ return false;
+}
+
/** Representation of OpenSBI domain */
struct sbi_domain {
/** Node in linked list of domains */
@@ -222,6 +241,9 @@ extern struct sbi_dlist domain_list;
#define sbi_domain_for_each_memregion(__d, __r) \
for ((__r) = (__d)->regions; (__r)->order; (__r)++)
+#define sbi_domain_for_each_memregion_idx(__d, __r, __i) \
+ for ((__r) = (__d)->regions, (__i) = 0; (__r)->order; (__r)++, (__i)++)
+
/**
* Check whether given HART is assigned to specified domain
* @param dom pointer to domain
diff --git a/lib/sbi/sbi_domain.c b/lib/sbi/sbi_domain.c
index 1bc64922..8a0a8fe2 100644
--- a/lib/sbi/sbi_domain.c
+++ b/lib/sbi/sbi_domain.c
@@ -281,29 +281,12 @@ static bool is_region_valid(const struct sbi_domain_memregion *reg)
return true;
}
-/** Check if regionA is sub-region of regionB */
-static bool is_region_subset(const struct sbi_domain_memregion *regA,
- const struct sbi_domain_memregion *regB)
-{
- ulong regA_start = regA->base;
- ulong regA_end = regA->base + (BIT(regA->order) - 1);
- ulong regB_start = regB->base;
- ulong regB_end = regB->base + (BIT(regB->order) - 1);
-
- if ((regB_start <= regA_start) &&
- (regA_start < regB_end) &&
- (regB_start < regA_end) &&
- (regA_end <= regB_end))
- return true;
-
- return false;
-}
-
/** Check if regionA can be replaced by regionB */
static bool is_region_compatible(const struct sbi_domain_memregion *regA,
const struct sbi_domain_memregion *regB)
{
- if (is_region_subset(regA, regB) && regA->flags == regB->flags)
+ if (sbi_domain_memregion_is_subset(regA, regB) &&
+ regA->flags == regB->flags)
return true;
return false;
@@ -363,7 +346,7 @@ static const struct sbi_domain_memregion *find_next_subset_region(
sbi_domain_for_each_memregion(dom, sreg) {
if (sreg == reg || (sreg->base <= addr) ||
- !is_region_subset(sreg, reg))
+ !sbi_domain_memregion_is_subset(sreg, reg))
continue;
if (!ret || (sreg->base < ret->base) ||
--
2.34.1
--
opensbi mailing list
opensbi@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/opensbi
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH v4 4/5] lib: sbi: give platform choice of using single memregion to cover OpenSBI
2025-12-09 10:22 [PATCH v4 0/5] Initial ESWIN/EIC7700 support Bo Gan
` (2 preceding siblings ...)
2025-12-09 10:22 ` [PATCH v4 3/5] lib: sbi_domain: make is_region_subset public Bo Gan
@ 2025-12-09 10:22 ` Bo Gan
2025-12-09 10:22 ` [PATCH v4 5/5] platform: generic: eswin: add EIC7700 Bo Gan
4 siblings, 0 replies; 6+ messages in thread
From: Bo Gan @ 2025-12-09 10:22 UTC (permalink / raw)
To: opensbi; +Cc: linmin, pinkesh.vaghela, gaohan, samuel, wangxiang
By default the OpenSBI itself is covered by 2 memregions for RX/RW
sections. This is required by platforms with Smepmp to enforce
proper permissions in M mode. Note: M-mode only regions can't
have RWX permissions with Smepmp. Platforms with traditional PMPs
won't be able to benefit from it, as both regions are effectively
RWX in M mode, but usually it's harmless to so. Now we provide
these platforms with an option to disable this logic. It saves 1
PMP entry. For platforms really in short of PMPs, it does make a
difference.
Note: Platform requesting single OpenSBI memregion must be using
traditional (old) PMP. We expect the platform code to do
the right thing.
Signed-off-by: Bo Gan <ganboing@gmail.com>
---
include/sbi/sbi_platform.h | 21 +++++++++++++++++++++
lib/sbi/sbi_domain.c | 36 ++++++++++++++++++++++++------------
2 files changed, 45 insertions(+), 12 deletions(-)
diff --git a/include/sbi/sbi_platform.h b/include/sbi/sbi_platform.h
index d75c12de..e65d9877 100644
--- a/include/sbi/sbi_platform.h
+++ b/include/sbi/sbi_platform.h
@@ -76,6 +76,9 @@ struct sbi_platform_operations {
/* Check if specified HART is allowed to do cold boot */
bool (*cold_boot_allowed)(u32 hartid);
+ /* Check if platform requires single firmware region */
+ bool (*single_fw_region)(void);
+
/* Platform nascent initialization */
int (*nascent_init)(void);
@@ -347,6 +350,24 @@ static inline bool sbi_platform_cold_boot_allowed(
return true;
}
+/**
+ * Check whether platform requires single firmware region
+ *
+ * Note: Single firmware region only works with legacy PMP because with
+ * Smepmp M-mode only regions can't have RWX permissions.
+ *
+ * @param plat pointer to struct sbi_platform
+ *
+ * @return true if single firmware region required and false otherwise
+ */
+static inline bool sbi_platform_single_fw_region(
+ const struct sbi_platform *plat)
+{
+ if (plat && sbi_platform_ops(plat)->single_fw_region)
+ return sbi_platform_ops(plat)->single_fw_region();
+ return false;
+}
+
/**
* Nascent (very early) initialization for current HART
*
diff --git a/lib/sbi/sbi_domain.c b/lib/sbi/sbi_domain.c
index 8a0a8fe2..4d3b4ee4 100644
--- a/lib/sbi/sbi_domain.c
+++ b/lib/sbi/sbi_domain.c
@@ -919,18 +919,30 @@ int sbi_domain_init(struct sbi_scratch *scratch, u32 cold_hartid)
root.possible_harts = root_hmask;
/* Root domain firmware memory region */
- sbi_domain_memregion_init(scratch->fw_start, scratch->fw_rw_offset,
- (SBI_DOMAIN_MEMREGION_M_READABLE |
- SBI_DOMAIN_MEMREGION_M_EXECUTABLE |
- SBI_DOMAIN_MEMREGION_FW),
- &root_memregs[root_memregs_count++]);
-
- sbi_domain_memregion_init((scratch->fw_start + scratch->fw_rw_offset),
- (scratch->fw_size - scratch->fw_rw_offset),
- (SBI_DOMAIN_MEMREGION_M_READABLE |
- SBI_DOMAIN_MEMREGION_M_WRITABLE |
- SBI_DOMAIN_MEMREGION_FW),
- &root_memregs[root_memregs_count++]);
+ if (sbi_platform_single_fw_region(sbi_platform_ptr(scratch))) {
+ sbi_domain_memregion_init(scratch->fw_start, scratch->fw_size,
+ (SBI_DOMAIN_MEMREGION_M_READABLE |
+ SBI_DOMAIN_MEMREGION_M_WRITABLE |
+ SBI_DOMAIN_MEMREGION_M_EXECUTABLE |
+ SBI_DOMAIN_MEMREGION_FW),
+ &root_memregs[root_memregs_count++]);
+ } else {
+ sbi_domain_memregion_init(scratch->fw_start,
+ scratch->fw_rw_offset,
+ (SBI_DOMAIN_MEMREGION_M_READABLE |
+ SBI_DOMAIN_MEMREGION_M_EXECUTABLE |
+ SBI_DOMAIN_MEMREGION_FW),
+ &root_memregs[root_memregs_count++]);
+
+ sbi_domain_memregion_init((scratch->fw_start +
+ scratch->fw_rw_offset),
+ (scratch->fw_size -
+ scratch->fw_rw_offset),
+ (SBI_DOMAIN_MEMREGION_M_READABLE |
+ SBI_DOMAIN_MEMREGION_M_WRITABLE |
+ SBI_DOMAIN_MEMREGION_FW),
+ &root_memregs[root_memregs_count++]);
+ }
root.fw_region_inited = true;
--
2.34.1
--
opensbi mailing list
opensbi@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/opensbi
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH v4 5/5] platform: generic: eswin: add EIC7700
2025-12-09 10:22 [PATCH v4 0/5] Initial ESWIN/EIC7700 support Bo Gan
` (3 preceding siblings ...)
2025-12-09 10:22 ` [PATCH v4 4/5] lib: sbi: give platform choice of using single memregion to cover OpenSBI Bo Gan
@ 2025-12-09 10:22 ` Bo Gan
4 siblings, 0 replies; 6+ messages in thread
From: Bo Gan @ 2025-12-09 10:22 UTC (permalink / raw)
To: opensbi; +Cc: linmin, pinkesh.vaghela, gaohan, samuel, wangxiang
Initial platform support for ESWIN Computing EIC7700 based on public SoC
datasheet[1] and tested on HiFive Premier P550. Vendor U-boot/Linux boots
fine, and I've tested Geekbench 6.5.0 Preview and got scores on par with
the vendor OpenSBI. System shutdown is not implemented due to the lack of
public doc regarding the UART communication protocol between the SoC and
the onboard BMC, which controls ATX power on HiFive P550 [2].
The files and functions are intentionally named as eic770x in many places
for future enhancements to support the 2 die version of the same SoC,
namely EIC7702, seen on DC-ROMA AI PC FML13V03 [3]. This patch set only
deals with the single die version, and the assumption is we can be either
die with id=0 or id=1, but there's only a single die in the system, or we
are only using a single die out of 2. However, the way the SoC handles 2-
die greatly affects how we configure it in a 1-die setup. EIC770X address
map has die 0/1 memory regions interleaved (see comments in eic770x.c).
If only 1 die is connected or active, it creates holes in the address map
for those regions corresponding to the remote die. When speculative-
execution or HW prefetcher touches data-cacheable regions that happen to
fall into those holes, it can trigger bus error. Specifically:
- Remote (non-existent) die L3 zero device
- Remote (non-existent) die cached memory region
- Other holes in Memory Port
To make matters worse, EIC770X doesn't have cache coherent DMA, and due
to the fact that the P550 core lacks Svpbmt, the SoC maps main memory
twice as different regions, so it can bypass cache and fetch the data
directly from memory. In address space, we have two memory regions, one
as cached, the other as uncached. Thus, we also need an extra PMP entry
to protect OpenSBI blob from the uncached window. To do this, platform
code requires single_fw_region, otherwise, we'll run out of PMP entries.
EIC770X also have several feature disable/enable CSRs accessible in M
mode. By default many core features such as speculation and HW prefetch
are disabled, and M mode software is responsible of enabling. Hence,
introduce 4 new build time tunable parameters to Kconfig, which reflects
the values get updated to those CSRs:
- ESWIN_EIC770X_FEAT0_CFG
- ESWIN_EIC770X_FEAT1_CFG
- ESWIN_EIC770X_L1_HWPF_CFG
- ESWIN_EIC770X_L2_HWPF_CFG
The default values are somewhat optimal for generic workloads. They are
dumped when running SiFive's vendor OpenSBI, and in addition, with my
own tuning to address the perf regression reported by drmpeg [4]
To build the firmware+u-boot blob, Use the following, and docs [5] for
testing it with UART boot without flashing:
make FW_TEXT_START=0x80000000 \
FW_PAYLOAD_OFFSET=0x200000 \
FW_PAYLOAD_PATH=u-boot-nodtb.bin \
FW_PAYLOAD_FDT_ADDR=0xf8000000 \
FW_FDT_PATH=u-boot.dtb
[1] https://github.com/eswincomputing/EIC7700X-SoC-Technical-Reference-Manual
[2] https://www.sifive.com/boards/hifive-premier-p550#documentation
[3] https://github.com/geerlingguy/sbc-reviews/issues/82
[4] https://forums.sifive.com/t/low-1-core-stream-bandwidth/7274/15
[5] https://github.com/ganboing/EIC770x-Docs/blob/main/p550/bootchain/UART-Boot.md
Signed-off-by: Bo Gan <ganboing@gmail.com>
---
platform/generic/Kconfig | 5 +
platform/generic/configs/defconfig | 1 +
platform/generic/eswin/Kconfig | 29 ++
platform/generic/eswin/eic770x.c | 398 +++++++++++++++++++++++
platform/generic/eswin/objects.mk | 11 +
platform/generic/include/eswin/eic770x.h | 73 +++++
6 files changed, 517 insertions(+)
create mode 100644 platform/generic/eswin/Kconfig
create mode 100644 platform/generic/eswin/eic770x.c
create mode 100644 platform/generic/eswin/objects.mk
create mode 100644 platform/generic/include/eswin/eic770x.h
diff --git a/platform/generic/Kconfig b/platform/generic/Kconfig
index 25b8886b..299817a3 100644
--- a/platform/generic/Kconfig
+++ b/platform/generic/Kconfig
@@ -92,7 +92,12 @@ config PLATFORM_SPACEMIT_K1
select FDT_HSM_SPACEMIT
default n
+config PLATFORM_ESWIN_EIC770X
+ bool "ESWIN EIC770X support"
+ default n
+
source "$(OPENSBI_SRC_DIR)/platform/generic/andes/Kconfig"
+source "$(OPENSBI_SRC_DIR)/platform/generic/eswin/Kconfig"
source "$(OPENSBI_SRC_DIR)/platform/generic/thead/Kconfig"
endif
diff --git a/platform/generic/configs/defconfig b/platform/generic/configs/defconfig
index 3896b0e0..868a4362 100644
--- a/platform/generic/configs/defconfig
+++ b/platform/generic/configs/defconfig
@@ -11,6 +11,7 @@ CONFIG_PLATFORM_STARFIVE_JH7110=y
CONFIG_PLATFORM_THEAD=y
CONFIG_PLATFORM_MIPS_P8700=y
CONFIG_PLATFORM_SPACEMIT_K1=y
+CONFIG_PLATFORM_ESWIN_EIC770X=y
CONFIG_FDT_CACHE=y
CONFIG_FDT_CACHE_SIFIVE_CCACHE=y
CONFIG_FDT_CPPC=y
diff --git a/platform/generic/eswin/Kconfig b/platform/generic/eswin/Kconfig
new file mode 100644
index 00000000..84d0f43a
--- /dev/null
+++ b/platform/generic/eswin/Kconfig
@@ -0,0 +1,29 @@
+# SPDX-License-Identifier: BSD-2-Clause
+
+config ESWIN_EIC770X_FEAT0_CFG
+ int "ESWIN EIC7700X Feature Disable 0 CSR Configuration"
+ default 0x4000
+ help
+ CSR Value to initialize EIC770X_FEAT0 (0x7c1) with.
+ Refer to EIC770X SoC TRM for recommendations.
+
+config ESWIN_EIC770X_FEAT1_CFG
+ int "ESWIN EIC7700X Feature Disable 1 CSR Configuration"
+ default 0x80
+ help
+ CSR Value to initialize EIC770X_FEAT1 (0x7c2) with.
+ Refer to EIC770X SoC TRM for recommendations.
+
+config ESWIN_EIC770X_L1_HWPF_CFG
+ int "ESWIN EIC7700X L1 HW Prefetcher CSR Configuration"
+ default 0x1005c1be649
+ help
+ CSR Value to initialize EIC770X_L1_HWPF (0x7c3) with.
+ Refer to EIC770X SoC TRM for recommendations.
+
+config ESWIN_EIC770X_L2_HWPF_CFG
+ int "ESWIN EIC7700X L2 HW Prefetcher CSR Configuration"
+ default 0x929f
+ help
+ CSR Value to initialize EIC770X_L2_HWPF (0x7c4) with.
+ Refer to EIC770X SoC TRM for recommendations.
diff --git a/platform/generic/eswin/eic770x.c b/platform/generic/eswin/eic770x.c
new file mode 100644
index 00000000..7582341e
--- /dev/null
+++ b/platform/generic/eswin/eic770x.c
@@ -0,0 +1,398 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2025 Bo Gan <ganboing@gmail.com>
+ *
+ */
+
+#include <platform_override.h>
+#include <sbi/riscv_io.h>
+#include <sbi/sbi_console.h>
+#include <sbi/sbi_system.h>
+#include <sbi/sbi_math.h>
+#include <sbi/sbi_hart_pmp.h>
+#include <sbi/sbi_hart_protection.h>
+#include <eswin/eic770x.h>
+
+static struct sbi_hart_protection eswin_eic7700_pmp_protection;
+
+static int eic770x_system_reset_check(u32 type, u32 reason)
+{
+ switch (type) {
+ case SBI_SRST_RESET_TYPE_COLD_REBOOT:
+ case SBI_SRST_RESET_TYPE_WARM_REBOOT:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+static void eic770x_system_reset(u32 type, u32 reason)
+{
+ switch (type) {
+ case SBI_SRST_RESET_TYPE_COLD_REBOOT:
+ case SBI_SRST_RESET_TYPE_WARM_REBOOT:
+ writel(EIC770X_SYSCRG_RST_VAL, (void *)EIC770X_SYSCRG_RST);
+ }
+
+ sbi_printf("%s: Unable to reset system\n", __func__);
+ sbi_hart_hang();
+}
+
+static struct sbi_system_reset_device eic770x_reset = {
+ .name = "eic770x_reset",
+ .system_reset_check = eic770x_system_reset_check,
+ .system_reset = eic770x_system_reset
+};
+
+#define add_root_mem_chk(...) do { \
+ rc = sbi_domain_root_add_memrange(__VA_ARGS__); \
+ if (rc) \
+ return rc; \
+} while (0)
+
+/**
+ * EIC7700 special arrangement of PMP entries:
+ *
+ * We have to use extra PMPs to block data cacheable regions that
+ * that doesn't belong to the current hart's die in order to prevent
+ * speculative accesses or HW prefetcher from generating bus error:
+ *
+ * bus error of cause event: 9, accrued: 0x220,
+ * physical address: 0x24ffffffa0
+ *
+ * The data cacheable regions (per datasheet) include:
+ *
+ * - [0x1a000000, 0x1a400000) -- Die 0 L3 zero device
+ * - [0x3a000000, 0x3a400000) -- Die 1 L3 zero device
+ * - [0x80000000, 0x80_00000000) -- memory port
+ *
+ * To make the blocker effective for M mode too, the extra PMPs need
+ * LOCK bit to be set, and once set, we can't change them later.
+ * We also have to to use 1 extra PMP to protect OpenSBI in uncached
+ * memory. EIC770X maps main memory (DRAM) twice -- one in memory
+ * port (cached), the other in system port (uncached). P550 doesn't
+ * support Svpbmt, so EIC770X use the uncached window to handle DMA
+ * that are cache incoherent -- pretty much all peripherals
+ *
+ * Final PMP configuration:
+ *
+ * From die 0 point of view, block
+ * - [0x3a000000, 0x3a400000) -- Die 1 L3 zero device
+ * - [0x10_00000000, 0x80_00000000) -- Die 1 cached mem + holes
+ *
+ * Root domain Harts:
+ * PMP[0]: [ 0x80000000, 0x80080000) ____ Firmware in cached mem
+ * PMP[1]: [0xc0_00000000, 0xc0_00080000) ____ Firmware in uncached
+ * PMP[2]: [ 0x3a000000, 0x3a400000) L___ Die 1 L3 zero device
+ * PMP[3]: [ 0x2000000 0x2010000) ____ CLINT
+ * PMP[4]: [ 0x0, 0x10_00000000) _RWX P550/System/Die 0 cached mem
+ * PMP[5]: <Free>
+ * PMP[6]: [ 0x0, 0x80_00000000) L___ P550/System/Memory Port
+ * PMP[7]: [ 0x0, 0xffffffffffffffff] _RWX Everything
+ *
+ * From die 1 point of view, block
+ * - [0x1a000000, 0x1a400000) -- Die 0 L3 zero device
+ * - [0x80000000, 0x20_00000000) -- Die 0 cached mem + holes
+ * - [0x30_00000000, 0x80_00000000) -- other holes in Memory port
+ *
+ * Root domain Harts:
+ * PMP[0]: [0x20_00000000, 0x20_00080000) ____ Firmware in cached mem
+ * PMP[1]: [0xe0_00000000, 0xe0_00080000) ____ Firmware in uncached
+ * PMP[2]: [ 0x1a000000, 0x1a400000) L___ Die 0 L3 zero dev
+ * PMP[3]: [ 0x22000000 0x22010000) ____ CLINT
+ * PMP[4]: [ 0x0, 0x80000000) _RWX Die 0/1 P550 internal
+ * PMP[5]: [0x20_00000000, 0x30_00000000) _RWX Die 1 cached memory
+ * PMP[6]: [ 0x0, 0x80_00000000) L___ P550/System/Memory Port
+ * PMP[7]: [ 0x0, 0xffffffffffffffff] _RWX Everything
+ *
+ * EIC770X memory port map:
+ * P550 Internal
+ * ├─ 0x0000_0000 - 0x2000_0000 die 0 internal
+ * └─ 0x2000_0000 - 0x4000_0000 die 1 internal
+ * System Port 0
+ * ├─ 0x4000_0000 - 0x6000_0000 die 0 low MMIO
+ * └─ 0x6000_0000 - 0x8000_0000 die 1 low MMIO
+ * Memory Port
+ * ├─ 0x8000_0000 - 0x10_8000_0000 die 0 memory (cached)
+ * ├─ 0x20_0000_0000 - 0x30_0000_0000 die 1 memory (cached)
+ * └─ 0x40_0000_0000 - 0x60_0000_0000 interleaved memory (cached)
+ * System Port 1
+ * ├─ 0x80_0000_0000 - 0xa0_0000_0000 die 0 high MMIO
+ * ├─ 0xa0_0000_0000 - 0xc0_0000_0000 die 1 high MMIO
+ * ├─ 0xc0_0000_0000 - 0xd0_0000_0000 die 0 memory (uncached)
+ * ├─ 0xe0_0000_0000 - 0xf0_0000_0000 die 1 memory (uncached)
+ * ├─ 0x100_0000_0000 - 0x120_0000_0000 interleaved memory (uncached)
+ * └─ ...
+ *
+ * In early_init, add memory regions such that lib/ code has the knowledge
+ * of blocked ranges. When the driver code inserts new regions, lib/ code
+ * can optimize away unnecessary ones. Next, in final_init, we program the
+ * PMPs to a default state that'll keep ourselves functional (CLINT/...
+ * accessible). Later, in pmp_configure, do the actual configuration of
+ * PMP, using domain memory regions and permissions.
+ */
+
+static int eswin_eic7700_early_init(bool cold_boot)
+{
+ struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
+ int rc;
+
+ if (!cold_boot)
+ return generic_early_init(cold_boot);
+
+ /* Enable bus blocker */
+ writel(1, (void*)EIC770X_TL64D2D_OUT);
+ writel(1, (void*)EIC770X_TL256D2D_OUT);
+ writel(1, (void*)EIC770X_TL256D2D_IN);
+ asm volatile ("fence o, rw");
+
+ /* Block firmware in uncached memory */
+ add_root_mem_chk(EIC770X_TO_UNCACHED(
+ scratch->fw_start),
+ 1UL << log2roundup(scratch->fw_size),
+ 1UL << log2roundup(scratch->fw_size),
+ (SBI_DOMAIN_MEMREGION_M_READABLE |
+ SBI_DOMAIN_MEMREGION_M_WRITABLE |
+ SBI_DOMAIN_MEMREGION_M_EXECUTABLE |
+ SBI_DOMAIN_MEMREGION_MMIO |
+ SBI_DOMAIN_MEMREGION_FW));
+
+ /* Allow SURW of P550 + System Port */
+ add_root_mem_chk(0,
+ EIC770X_MEMPORT_BASE,
+ EIC770X_MEMPORT_BASE,
+ (SBI_DOMAIN_MEMREGION_MMIO |
+ SBI_DOMAIN_MEMREGION_SHARED_SURW_MRW));
+
+ if (current_hart_die()) {
+ /* Allow SURWX of die 1 cached memory */
+ add_root_mem_chk(EIC770X_D1_MEM_BASE,
+ EIC770X_D1_MEM_SIZE,
+ EIC770X_D1_MEM_SIZE,
+ (SBI_DOMAIN_MEMREGION_M_READABLE |
+ SBI_DOMAIN_MEMREGION_M_WRITABLE |
+ SBI_DOMAIN_MEMREGION_SU_RWX));
+ } else {
+ /* Allow SURWX of P550 + System Port + die 0 cached memory */
+ add_root_mem_chk(0,
+ EIC770X_D0_MEM_LIMIT,
+ EIC770X_D0_MEM_LIMIT,
+ (SBI_DOMAIN_MEMREGION_M_READABLE |
+ SBI_DOMAIN_MEMREGION_M_WRITABLE |
+ SBI_DOMAIN_MEMREGION_SU_RWX));
+ }
+
+ /* Block P550 + System Port 0 + Memory Port (enforced) */
+ add_root_mem_chk(0,
+ EIC770X_MEMPORT_LIMIT,
+ EIC770X_MEMPORT_LIMIT,
+ (SBI_DOMAIN_MEMREGION_MMIO |
+ SBI_DOMAIN_MEMREGION_ENF_PERMISSIONS));
+
+ rc = sbi_hart_protection_register(&eswin_eic7700_pmp_protection);
+ if (rc)
+ return rc;
+
+ return generic_early_init(cold_boot);
+}
+
+#define PMP_FW_START 0
+#define PMP_FW_COUNT 2
+#define PMP_RESERVED_A 2
+#define PMP_FREE_A_START 3
+#define PMP_FREE_A_COUNT 3
+#define PMP_RESERVED_B 6
+#define PMP_FREE_B_START 7
+#define PMP_FREE_B_COUNT 1
+
+static int eswin_eic7700_final_init(bool cold_boot)
+{
+ /**
+ * For both dies after final_init:
+ *
+ * PMP[0]: Protect OpenSBI in cached memory
+ * PMP[1]: Protect OpenSBI in uncached memory
+ * PMP[2]: Block remote die P550 L3 Zero Device
+ * PMP[3-5]: <Free ranges A>
+ * PMP[5]: Temporary enable P550 + System Port
+ * PMP[6]: Block all P550 + System + Memory Port
+ * PMP[7-7]: <Free ranges B>
+ */
+ struct sbi_domain_memregion *reg;
+ unsigned int pmp_idx = PMP_FW_START,
+ pmp_max = PMP_FW_START + PMP_FW_COUNT;
+ int rc;
+
+ if (cold_boot)
+ sbi_system_reset_add_device(&eic770x_reset);
+
+ /**
+ * Do generic_final_init stuff first, because it touchs FDT.
+ * After final_init, we'll block entire memory port with the
+ * LOCK bit set, which means we can't access memory outside
+ * of [fw_start, fw_start + fw_size). The FDT could very well
+ * reside outside of firmware region. Later, pmp_configure()
+ * may unblock it with some preceding entries for root domain
+ * harts. It may not unblock it, however, for non-root harts.
+ */
+ rc = generic_final_init(cold_boot);
+ if (rc)
+ return rc;
+
+
+ /* Process firmware regions */
+ sbi_domain_for_each_memregion(&root, reg) {
+ if (!SBI_DOMAIN_MEMREGION_IS_FIRMWARE(reg->flags))
+ continue;
+
+ if (pmp_idx >= pmp_max) {
+ sbi_printf("%s: insufficient FW PMP entries\n",
+ __func__);
+ return SBI_EFAIL;
+ }
+ pmp_set(pmp_idx++, sbi_domain_get_oldpmp_flags(reg),
+ reg->base, reg->order);
+ }
+
+ pmp_set(PMP_RESERVED_A, PMP_L, EIC770X_L3_ZERO_REMOTE,
+ log2roundup(EIC770X_L3_ZERO_SIZE));
+ /**
+ * Enable P550 internal + System Port, so OpenSBI can access
+ * CLINT/PLIC/UART. Might be overwritten in pmp_configure.
+ */
+ pmp_set(PMP_FREE_A_START + PMP_FREE_A_COUNT - 1, 0, 0,
+ log2roundup(EIC770X_MEMPORT_BASE));
+
+ pmp_set(PMP_RESERVED_B, PMP_L, 0,
+ log2roundup(EIC770X_MEMPORT_LIMIT));
+
+ /**
+ * These must come after the setup of PMP, as we are about to
+ * enable speculation and HW prefetcher bits
+ */
+ csr_write(EIC770X_CSR_FEAT0, CONFIG_ESWIN_EIC770X_FEAT0_CFG);
+ csr_write(EIC770X_CSR_FEAT1, CONFIG_ESWIN_EIC770X_FEAT1_CFG);
+ csr_write(EIC770X_CSR_L1_HWPF, CONFIG_ESWIN_EIC770X_L1_HWPF_CFG);
+ csr_write(EIC770X_CSR_L2_HWPF, CONFIG_ESWIN_EIC770X_L2_HWPF_CFG);
+
+ return 0;
+}
+
+static int eswin_eic7700_pmp_configure(struct sbi_scratch *scratch)
+{
+ struct sbi_domain *dom = sbi_domain_thishart_ptr();
+ struct sbi_domain_memregion *reg, *prev = NULL;
+ unsigned int pmp_idx, pmp_max;
+ unsigned int i, j;
+
+ /* Process the first free range A [3-5] */
+ pmp_idx = PMP_FREE_A_START,
+ pmp_max = PMP_FREE_A_START + PMP_FREE_A_COUNT;
+
+ sbi_domain_for_each_memregion_idx(dom, reg, i) {
+ if (SBI_DOMAIN_MEMREGION_IS_FIRMWARE(reg->flags))
+ continue;
+
+ /**
+ * This must be the one blocking P550 + System Port +
+ * Memory Port we setup in early_init, or a superset
+ * of it. If seen, break, and program the rest in
+ * free range B.
+ */
+ if (reg->base == 0 &&
+ reg->order >= log2roundup(EIC770X_MEMPORT_LIMIT))
+ break;
+
+ /**
+ * Relaxation:
+ * Treat a previous region with SURW as SURWX if the
+ * current has SURWX, and current region with MMIO
+ * if previous has MMIO, and see if it can be merged.
+ * This saves 1 PMP entry on die 0/
+ */
+ if (prev && sbi_domain_memregion_is_subset(prev, reg) &&
+ (reg->flags | SBI_DOMAIN_MEMREGION_MMIO) ==
+ (prev->flags | SBI_DOMAIN_MEMREGION_SU_EXECUTABLE))
+ pmp_idx--;
+
+ if (pmp_idx >= pmp_max)
+ goto no_more_pmp;
+
+ pmp_set(pmp_idx++, sbi_domain_get_oldpmp_flags(reg),
+ reg->base, reg->order);
+ prev = reg;
+ }
+ /* Disable the rest */
+ while (pmp_idx < pmp_max)
+ pmp_disable(pmp_idx++);
+
+ /* Process the second free range B [7-7] */
+ pmp_idx = PMP_FREE_B_START,
+ pmp_max = PMP_FREE_B_START + PMP_FREE_B_COUNT;
+
+ sbi_domain_for_each_memregion_idx(dom, reg, j) {
+ if (i >= j)
+ continue;
+
+ if (pmp_idx >= pmp_max)
+ goto no_more_pmp;
+
+ pmp_set(pmp_idx++, sbi_domain_get_oldpmp_flags(reg),
+ reg->base, reg->order);
+ }
+ /* Disable the rest */
+ while (pmp_idx < pmp_max)
+ pmp_disable(pmp_idx++);
+
+ sbi_hart_pmp_fence();
+ return 0;
+no_more_pmp:
+ sbi_printf("%s: insufficient PMP entries\n", __func__);
+ return SBI_EFAIL;
+}
+
+static void eswin_eic7700_pmp_unconfigure(struct sbi_scratch *scratch)
+{
+ /* Enable P550 internal + System Port */
+ pmp_set(PMP_FREE_A_START + PMP_FREE_A_COUNT - 1, 0, 0,
+ log2roundup(EIC770X_MEMPORT_BASE));
+
+ for (unsigned int i = 0; i < PMP_FREE_A_COUNT - 1; i++)
+ pmp_disable(i + PMP_FREE_A_START);
+
+ for (unsigned int i = 0; i < PMP_FREE_B_COUNT; i++)
+ pmp_disable(i + PMP_FREE_B_START);
+}
+
+static struct sbi_hart_protection eswin_eic7700_pmp_protection = {
+ .name = "eic7700_pmp",
+ .rating = -1UL,
+ .configure = eswin_eic7700_pmp_configure,
+ .unconfigure = eswin_eic7700_pmp_unconfigure,
+};
+
+static bool eswin_eic7700_single_fw_region(void)
+{
+ return true;
+}
+
+static int eswin_eic7700_platform_init(const void *fdt, int nodeoff,
+ const struct fdt_match *match)
+{
+ generic_platform_ops.early_init = eswin_eic7700_early_init;
+ generic_platform_ops.final_init = eswin_eic7700_final_init;
+ generic_platform_ops.single_fw_region = eswin_eic7700_single_fw_region;
+
+ return 0;
+}
+
+static const struct fdt_match eswin_eic7700_match[] = {
+ { .compatible = "eswin,eic7700" },
+ { },
+};
+
+const struct fdt_driver eswin_eic7700 = {
+ .match_table = eswin_eic7700_match,
+ .init = eswin_eic7700_platform_init,
+};
diff --git a/platform/generic/eswin/objects.mk b/platform/generic/eswin/objects.mk
new file mode 100644
index 00000000..6942a107
--- /dev/null
+++ b/platform/generic/eswin/objects.mk
@@ -0,0 +1,11 @@
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+# Copyright (C) 2025 Bo Gan <ganboing@gmail.com>
+#
+
+carray-platform_override_modules-$(CONFIG_PLATFORM_ESWIN_EIC770X) += eswin_eic7700
+platform-objs-$(CONFIG_PLATFORM_ESWIN_EIC770X) += eswin/eic770x.o
+
+FW_PAYLOAD=y
+FW_PAYLOAD_OFFSET=0x200000
diff --git a/platform/generic/include/eswin/eic770x.h b/platform/generic/include/eswin/eic770x.h
new file mode 100644
index 00000000..8ce23283
--- /dev/null
+++ b/platform/generic/include/eswin/eic770x.h
@@ -0,0 +1,73 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2025 Bo Gan <ganboing@gmail.com>
+ *
+ */
+
+#ifndef __EIC770X_H__
+#define __EIC770X_H__
+
+/* CSRs */
+#define EIC770X_CSR_BRPREDICT 0x7c0
+#define EIC770X_CSR_FEAT0 0x7c1
+#define EIC770X_CSR_FEAT1 0x7c2
+#define EIC770X_CSR_L1_HWPF 0x7c3
+#define EIC770X_CSR_L2_HWPF 0x7c4
+
+/* Hart ID to core/die conversion */
+#define CPU_CORE_BITS 2
+#define CPU_CORE_MASK ((1 << CPU_CORE_BITS) - 1)
+#define CPU_DIE_SHIFT CPU_CORE_BITS
+#define CPU_DIE_BITS 1
+#define CPU_DIE_MASK ((1 << CPU_DIE_SHIFT) - 1)
+
+#define hart_core(i) ((i) & CPU_CORE_MASK)
+#define hart_die(i) (((i) >> CPU_DIE_SHIFT) & CPU_DIE_MASK)
+#define current_hart_core() hart_core(current_hartid())
+#define current_hart_die() hart_die(current_hartid())
+
+/* P550 Internal and System Port 0 */
+#define EIC770X_P550INT_SIZE 0x20000000UL
+#define EIC770X_P550INT_BASE(d) (0UL + EIC770X_P550INT_SIZE * (d))
+#define EIC770X_P550INT_LOCAL EIC770X_P550INT_BASE(current_hart_die())
+#define EIC770X_TL64D2D_OUT (EIC770X_P550INT_LOCAL + 0x200000)
+#define EIC770X_TL256D2D_OUT (EIC770X_P550INT_LOCAL + 0x202000)
+#define EIC770X_TL256D2D_IN (EIC770X_P550INT_LOCAL + 0x204000)
+#define EIC770X_L3_ZERO_SIZE 0x400000UL
+#define EIC770X_L3_ZERO_BASE(d) (EIC770X_P550INT_BASE(d) + 0x1a000000)
+#define EIC770X_L3_ZERO_LOCAL EIC770X_L3_ZERO_BASE(current_hart_die())
+#define EIC770X_L3_ZERO_REMOTE EIC770X_L3_ZERO_BASE(1 - current_hart_die())
+
+#define EIC770X_SYSPORT_SIZE 0x20000000UL
+#define EIC770X_SYSPORT_BASE(d) (0x40000000UL + EIC770X_SYSPORT_SIZE * (d))
+#define EIC770X_SYSPORT_LOCAL EIC770X_SYSPORT_BASE(current_hart_die())
+#define EIC770X_SYSCRG (EIC770X_SYSPORT_LOCAL + 0x11828000UL)
+#define EIC770X_SYSCRG_RST (EIC770X_SYSCRG + 0x300UL)
+#define EIC770X_SYSCRG_RST_VAL 0x1AC0FFE6UL
+
+/* Memory Ports */
+#define EIC770X_MEMPORT_BASE 0x0080000000UL // 2G
+#define EIC770X_MEMPORT_SIZE 0x7f80000000UL // +510G
+#define EIC770X_MEMPORT_LIMIT (EIC770X_MEMPORT_BASE + EIC770X_MEMPORT_SIZE)
+#define EIC770X_D0_MEM_BASE 0x0080000000UL // 2G
+#define EIC770X_D0_MEM_SIZE 0x0f80000000UL // +62G
+#define EIC770X_D0_MEM_LIMIT (EIC770X_D0_MEM_BASE + EIC770X_D0_MEM_SIZE)
+#define EIC770X_D1_MEM_BASE 0x2000000000UL // 128G
+#define EIC770X_D1_MEM_SIZE 0x1000000000UL // +64G
+#define EIC770X_D1_MEM_LIMIT (EIC770X_D1_MEM_BASE + EIC770X_D1_MEM_SIZE)
+#define EIC770X_CACHED_BASE (current_hart_die() ? \
+ EIC770X_D1_MEM_BASE : \
+ EIC770X_D0_MEM_BASE)
+
+/* Uncached memory mapped in System Port 1 */
+#define EIC770X_D0_UC_BASE 0xc000000000UL
+#define EIC770X_D1_UC_BASE 0xe000000000UL
+#define EIC770X_UNCACHED_BASE (current_hart_die() ? \
+ EIC770X_D1_UC_BASE : \
+ EIC770X_D0_UC_BASE)
+
+#define EIC770X_TO_UNCACHED(x) ((x) - EIC770X_CACHED_BASE + \
+ EIC770X_UNCACHED_BASE)
+
+#endif
--
2.34.1
--
opensbi mailing list
opensbi@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/opensbi
^ permalink raw reply related [flat|nested] 6+ messages in thread
end of thread, other threads:[~2025-12-09 10:25 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-12-09 10:22 [PATCH v4 0/5] Initial ESWIN/EIC7700 support Bo Gan
2025-12-09 10:22 ` [PATCH v4 1/5] lib: sbi_hart_pmp: make sbi_hart_pmp_fence public Bo Gan
2025-12-09 10:22 ` [PATCH v4 2/5] lib: sbi_domain: add sbi_domain_get_oldpmp_flags Bo Gan
2025-12-09 10:22 ` [PATCH v4 3/5] lib: sbi_domain: make is_region_subset public Bo Gan
2025-12-09 10:22 ` [PATCH v4 4/5] lib: sbi: give platform choice of using single memregion to cover OpenSBI Bo Gan
2025-12-09 10:22 ` [PATCH v4 5/5] platform: generic: eswin: add EIC7700 Bo Gan
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox