From: Bo Gan <ganboing@gmail.com>
To: opensbi@lists.infradead.org
Cc: linmin@eswincomputing.com, pinkesh.vaghela@einfochips.com,
gaohan@iscas.ac.cn, samuel@sholland.org, wangxiang@iscas.ac.cn
Subject: [PATCH v6 7/7] platform: generic: eswin: Add shutdown/reboot support for Hifive Premier P550
Date: Thu, 18 Dec 2025 02:42:43 -0800 [thread overview]
Message-ID: <20251218104243.562667-8-ganboing@gmail.com> (raw)
In-Reply-To: <20251218104243.562667-1-ganboing@gmail.com>
Hifive Premier P550[1] is a Mini-DTX form factor board with EIC7700X.
It has a STM32F407VET6 onboard MCU acting as the BMC, controlling
ATX power on/off while providing remote management features. The
EIC7700X SoC/SoM communicates with the BMC via UART2, using ESWIN's
protocol. The messages transmitted are fixed sizes (267 bytes), and
depending on the type, can be directional or bi-directional. The
shutdown and cold reboot requests are directional messages from SoC
to BMC (NOTIFY type) with CMD_POWER_OFF or CMD_RESTART. The payload
of shutdown/cold reboot requests should be empty and are ignored by
the BMC at the moment. A HFP (Hifive Premier) specific reset device
is registered in addition to the SoC reset device. For shutdown and
cold reboot, the board-level reset takes precedence.
The definitions of the SoC <-> BMC message protocol is taken from
ESWIN's repo [2]. The only file used from that repo is `hf_common.h`
It's disjunctively dual licensed as (GPL-2.0-only OR BSD-2-Clause),
hence, compatible with the license of OpenSBI. It's heavily modified
and renamed as platform/generic/include/eswin/hfp.h. The author and
copyright in the original file are retained.
Validated shutdown/core reboot working on Hifive Premier P550.
[1] https://www.sifive.com/boards/hifive-premier-p550#documentation
[2] https://github.com/eswincomputing/hifive-premier-p550-mcu-patches.git
Signed-off-by: Bo Gan <ganboing@gmail.com>
---
platform/generic/eswin/eic770x.c | 2 +
platform/generic/eswin/hfp.c | 118 +++++++++++++++++++++++
platform/generic/eswin/objects.mk | 1 +
platform/generic/include/eswin/eic770x.h | 22 +++++
platform/generic/include/eswin/hfp.h | 64 ++++++++++++
5 files changed, 207 insertions(+)
create mode 100644 platform/generic/eswin/hfp.c
create mode 100644 platform/generic/include/eswin/hfp.h
diff --git a/platform/generic/eswin/eic770x.c b/platform/generic/eswin/eic770x.c
index bce53a19..7330df9f 100644
--- a/platform/generic/eswin/eic770x.c
+++ b/platform/generic/eswin/eic770x.c
@@ -13,6 +13,7 @@
#include <sbi/sbi_hart_pmp.h>
#include <sbi/sbi_hart_protection.h>
#include <eswin/eic770x.h>
+#include <eswin/hfp.h>
static struct sbi_hart_protection eswin_eic7700_pmp_protection;
@@ -393,6 +394,7 @@ static int eswin_eic7700_platform_init(const void *fdt, int nodeoff,
}
static const struct fdt_match eswin_eic7700_match[] = {
+ { .compatible = "sifive,hifive-premier-p550", .data = &hfp_override },
{ .compatible = "eswin,eic7700" },
{ },
};
diff --git a/platform/generic/eswin/hfp.c b/platform/generic/eswin/hfp.c
new file mode 100644
index 00000000..eabed191
--- /dev/null
+++ b/platform/generic/eswin/hfp.c
@@ -0,0 +1,118 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2025 Bo Gan <ganboing@gmail.com>
+ *
+ */
+
+#include <sbi/riscv_io.h>
+#include <sbi/sbi_string.h>
+#include <sbi/sbi_system.h>
+#include <sbi/sbi_hart.h>
+#include <sbi/sbi_ecall_interface.h>
+#include <sbi_utils/serial/uart8250.h>
+#include <eswin/eic770x.h>
+#include <eswin/hfp.h>
+
+/* HFP -> HiFive Premier P550 */
+
+#define HFP_MCU_UART_PORT 2
+#define HFP_MCU_UART_BAUDRATE 115200
+
+static unsigned long eic770x_sysclk_rate(void)
+{
+ /* syscfg clock is a mux of 24Mhz xtal clock and spll0_fout3/divisor */
+ uint32_t syscfg_clk = readl_relaxed((void*)EIC770X_SYSCRG_SYSCLK);
+
+ if (EIC770X_SYSCLK_SEL(syscfg_clk))
+ return EIC770X_XTAL_CLK_RATE;
+
+ return EIC770X_SPLL0_OUT3_RATE / EIC770X_SYSCLK_DIV(syscfg_clk);
+}
+
+static void eic770x_enable_uart_clk(unsigned port)
+{
+ uint32_t lsp_clk_en = readl_relaxed((void*)EIC770X_SYSCRG_LSPCLK0);
+
+ lsp_clk_en |= EIC770X_UART_CLK_BIT(port);
+ writel(lsp_clk_en, (void*)EIC770X_SYSCRG_LSPCLK0);
+}
+
+static void hfp_send_bmc_msg(uint8_t type, uint8_t cmd,
+ const uint8_t *data, uint8_t len)
+{
+ unsigned long sysclk_rate;
+ struct uart8250_device uart_dev;
+ union {
+ struct hfp_bmc_message msg;
+ char as_char[sizeof(struct hfp_bmc_message)];
+ } xmit = {{
+ .header_magic = MAGIC_HEADER,
+ .type = type,
+ .cmd = cmd,
+ .data_len = len,
+ .tail_magic = MAGIC_TAIL,
+ }};
+
+ /**
+ * Re-initialize UART.
+ * S-mode OS may have changed the clock frequency of syscfg clock
+ * which is the clock of all low speed peripherals, including UARTs.
+ * S-mode OS may also have disabled the UART2 clock via clock gate.
+ * (lsp_clk_en0 bit 17-21 controls UART0-4). Thus, we re-calculate
+ * the clock rate, enable UART clock, and re-initialize UART.
+ */
+
+ sysclk_rate = eic770x_sysclk_rate();
+ eic770x_enable_uart_clk(HFP_MCU_UART_PORT);
+
+ uart8250_device_init(&uart_dev,
+ EIC770X_UART(HFP_MCU_UART_PORT),
+ sysclk_rate,
+ HFP_MCU_UART_BAUDRATE,
+ EIC770X_UART_REG_SHIFT,
+ EIC770X_UART_REG_WIDTH,
+ 0, 0);
+
+ sbi_memcpy(&xmit.msg.data, data, len);
+ hfp_bmc_checksum_msg(&xmit.msg);
+
+ for (unsigned int i = 0; i < sizeof(xmit.as_char); i++)
+ uart8250_device_putc(&uart_dev, xmit.as_char[i]);
+}
+
+static int hfp_system_reset_check(u32 type, u32 reason)
+{
+ switch (type) {
+ case SBI_SRST_RESET_TYPE_COLD_REBOOT:
+ case SBI_SRST_RESET_TYPE_SHUTDOWN:
+ return 255;
+ default:
+ return 0;
+ }
+}
+
+static void hfp_system_reset(u32 type, u32 reason)
+{
+ switch (type) {
+ case SBI_SRST_RESET_TYPE_SHUTDOWN:
+ hfp_send_bmc_msg(HFP_MSG_NOTIFY, HFP_CMD_POWER_OFF,
+ NULL, 0);
+ break;
+ case SBI_SRST_RESET_TYPE_COLD_REBOOT:
+ hfp_send_bmc_msg(HFP_MSG_NOTIFY, HFP_CMD_RESTART,
+ NULL, 0);
+ break;
+ }
+ sbi_hart_hang();
+}
+
+static struct sbi_system_reset_device hfp_reset = {
+ .name = "hfp_reset",
+ .system_reset_check = hfp_system_reset_check,
+ .system_reset = hfp_system_reset,
+};
+
+const struct eic770x_board_override hfp_override = {
+ .reset_dev = &hfp_reset,
+};
diff --git a/platform/generic/eswin/objects.mk b/platform/generic/eswin/objects.mk
index be5420ce..a7165aa3 100644
--- a/platform/generic/eswin/objects.mk
+++ b/platform/generic/eswin/objects.mk
@@ -7,4 +7,5 @@
ifeq ($(PLATFORM_RISCV_XLEN), 64)
carray-platform_override_modules-$(CONFIG_PLATFORM_ESWIN_EIC770X) += eswin_eic7700
platform-objs-$(CONFIG_PLATFORM_ESWIN_EIC770X) += eswin/eic770x.o
+platform-objs-$(CONFIG_PLATFORM_ESWIN_EIC770X) += eswin/hfp.o
endif
diff --git a/platform/generic/include/eswin/eic770x.h b/platform/generic/include/eswin/eic770x.h
index b1994669..67764ec0 100644
--- a/platform/generic/include/eswin/eic770x.h
+++ b/platform/generic/include/eswin/eic770x.h
@@ -48,7 +48,16 @@ struct eic770x_board_override {
#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_UART0 (EIC770X_SYSPORT_LOCAL + 0x10900000UL)
+#define EIC770X_UART_SIZE 0x10000UL
+#define EIC770X_UART(x) (EIC770X_UART0 + EIC770X_UART_SIZE * (x))
+#define EIC770X_UART_REG_SHIFT 2
+#define EIC770X_UART_REG_WIDTH 4
+
#define EIC770X_SYSCRG (EIC770X_SYSPORT_LOCAL + 0x11828000UL)
+#define EIC770X_SYSCRG_LSPCLK0 (EIC770X_SYSCRG + 0x200UL)
+#define EIC770X_SYSCRG_SYSCLK (EIC770X_SYSCRG + 0x20cUL)
#define EIC770X_SYSCRG_RST (EIC770X_SYSCRG + 0x300UL)
#define EIC770X_SYSCRG_RST_VAL 0x1AC0FFE6UL
@@ -76,4 +85,17 @@ struct eic770x_board_override {
#define EIC770X_TO_UNCACHED(x) ((x) - EIC770X_CACHED_BASE + \
EIC770X_UNCACHED_BASE)
+/* Clock definitions */
+#define EIC770X_XTAL_CLK_RATE 24000000UL
+#define EIC770X_SPLL0_OUT1_RATE 1600000000UL
+#define EIC770X_SPLL0_OUT2_RATE 800000000UL
+#define EIC770X_SPLL0_OUT3_RATE 400000000UL
+#define EIC770X_UART_CLK_BIT(x) (1UL << ((x) + 17))
+#define EIC770X_SYSCLK_SEL(x) ((x) & 1)
+#define EIC770X_SYSCLK_DIV(x) \
+ ({ \
+ uint32_t divisor = ((x) >> 4) & 7; \
+ divisor > 2 ? divisor : 2; \
+ })
+
#endif
diff --git a/platform/generic/include/eswin/hfp.h b/platform/generic/include/eswin/hfp.h
new file mode 100644
index 00000000..6ed1b568
--- /dev/null
+++ b/platform/generic/include/eswin/hfp.h
@@ -0,0 +1,64 @@
+// SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+/*
+ * Copyright (c) 2024 Beijing ESWIN Computing Technology Co., Ltd.
+ *
+ * Authors:
+ * Lin Min <linmin@eswincomputing.com>
+ * Bo Gan <ganboing@gmail.com>
+ *
+ * Adapted from Core/Inc/hf_common.h from ESWIN's Hifive Premier P550
+ * onboard BMC (MCU) source repo:
+ * https://github.com/eswincomputing/hifive-premier-p550-mcu-patches.git
+ *
+ */
+
+#ifndef __ESWIN_HFP_H__
+#define __ESWIN_HFP_H__
+
+#include <sbi/sbi_types.h>
+
+enum hfp_bmc_msg {
+ HFP_MSG_REQUEST = 1,
+ HFP_MSG_REPLY,
+ HFP_MSG_NOTIFY,
+};
+
+enum hfp_bmc_cmd {
+ HFP_CMD_POWER_OFF = 1,
+ HFP_CMD_REBOOT,
+ HFP_CMD_READ_BOARD_INFO,
+ HFP_CMD_CONTROL_LED,
+ HFP_CMD_PVT_INFO,
+ HFP_CMD_BOARD_STATUS,
+ HFP_CMD_POWER_INFO,
+ HFP_CMD_RESTART, // cold reboot with power off/on
+};
+
+#define MAGIC_HEADER 0xA55AAA55
+#define MAGIC_TAIL 0xBDBABDBA
+
+struct hfp_bmc_message {
+ uint32_t header_magic;
+ uint32_t task_id;
+ uint8_t type;
+ uint8_t cmd;
+ uint8_t result;
+ uint8_t data_len;
+ uint8_t data[250];
+ uint8_t checksum;
+ uint32_t tail_magic;
+} __packed;
+
+static inline void hfp_bmc_checksum_msg(struct hfp_bmc_message *msg)
+{
+ msg->checksum = 0;
+ msg->checksum ^= msg->type;
+ msg->checksum ^= msg->cmd;
+ msg->checksum ^= msg->data_len;
+ for (uint8_t i = 0; i != msg->data_len; i++)
+ msg->checksum ^= msg->data[i];
+}
+
+extern const struct eic770x_board_override hfp_override;
+
+#endif
--
2.34.1
--
opensbi mailing list
opensbi@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/opensbi
next prev parent reply other threads:[~2025-12-18 10:45 UTC|newest]
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-12-18 10:42 [PATCH v6 0/7] Initial ESWIN/EIC7700 and Hifive P550 support Bo Gan
2025-12-18 10:42 ` [PATCH v6 1/7] lib: sbi_hart_pmp: make sbi_hart_pmp_fence public Bo Gan
2025-12-18 14:35 ` Anup Patel
2025-12-18 10:42 ` [PATCH v6 2/7] lib: sbi_domain: add sbi_domain_get_oldpmp_flags Bo Gan
2025-12-18 14:36 ` Anup Patel
2025-12-18 10:42 ` [PATCH v6 3/7] lib: sbi_domain: make is_region_subset public Bo Gan
2025-12-18 14:38 ` Anup Patel
2025-12-18 10:42 ` [PATCH v6 4/7] lib: sbi: give platform choice of using single memregion to cover OpenSBI Bo Gan
2025-12-21 14:46 ` Anup Patel
2025-12-18 10:42 ` [PATCH v6 5/7] platform: generic: eswin: add EIC7700 Bo Gan
2025-12-21 14:49 ` Anup Patel
2025-12-18 10:42 ` [PATCH v6 6/7] lib: utils/serial: Support multiple UART8250 devices Bo Gan
2025-12-18 10:42 ` Bo Gan [this message]
2025-12-21 6:49 ` [PATCH v6 7/7] platform: generic: eswin: Add shutdown/reboot support for Hifive Premier P550 Bo Gan
2025-12-21 15:38 ` Anup Patel
2025-12-21 15:38 ` [PATCH v6 0/7] Initial ESWIN/EIC7700 and Hifive P550 support Anup Patel
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20251218104243.562667-8-ganboing@gmail.com \
--to=ganboing@gmail.com \
--cc=gaohan@iscas.ac.cn \
--cc=linmin@eswincomputing.com \
--cc=opensbi@lists.infradead.org \
--cc=pinkesh.vaghela@einfochips.com \
--cc=samuel@sholland.org \
--cc=wangxiang@iscas.ac.cn \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.