mirror of
https://github.com/riscv-software-src/opensbi.git
synced 2025-12-22 06:12:02 +00:00
platform: generic: eswin: Add shutdown/reboot support for Hifive Premier P550
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/cold 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> Reviewed-by: Anup Patel <anup@brainfault.org> Link: https://lore.kernel.org/r/20251218104243.562667-8-ganboing@gmail.com Signed-off-by: Anup Patel <anup@brainfault.org>
This commit is contained in:
@@ -13,6 +13,7 @@
|
|||||||
#include <sbi/sbi_hart_pmp.h>
|
#include <sbi/sbi_hart_pmp.h>
|
||||||
#include <sbi/sbi_hart_protection.h>
|
#include <sbi/sbi_hart_protection.h>
|
||||||
#include <eswin/eic770x.h>
|
#include <eswin/eic770x.h>
|
||||||
|
#include <eswin/hfp.h>
|
||||||
|
|
||||||
static struct sbi_hart_protection eswin_eic7700_pmp_protection;
|
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[] = {
|
static const struct fdt_match eswin_eic7700_match[] = {
|
||||||
|
{ .compatible = "sifive,hifive-premier-p550", .data = &hfp_override },
|
||||||
{ .compatible = "eswin,eic7700" },
|
{ .compatible = "eswin,eic7700" },
|
||||||
{ },
|
{ },
|
||||||
};
|
};
|
||||||
|
|||||||
118
platform/generic/eswin/hfp.c
Normal file
118
platform/generic/eswin/hfp.c
Normal file
@@ -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,
|
||||||
|
};
|
||||||
@@ -7,4 +7,5 @@
|
|||||||
ifeq ($(PLATFORM_RISCV_XLEN), 64)
|
ifeq ($(PLATFORM_RISCV_XLEN), 64)
|
||||||
carray-platform_override_modules-$(CONFIG_PLATFORM_ESWIN_EIC770X) += eswin_eic7700
|
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/eic770x.o
|
||||||
|
platform-objs-$(CONFIG_PLATFORM_ESWIN_EIC770X) += eswin/hfp.o
|
||||||
endif
|
endif
|
||||||
|
|||||||
@@ -48,7 +48,16 @@ struct eic770x_board_override {
|
|||||||
#define EIC770X_SYSPORT_SIZE 0x20000000UL
|
#define EIC770X_SYSPORT_SIZE 0x20000000UL
|
||||||
#define EIC770X_SYSPORT_BASE(d) (0x40000000UL + EIC770X_SYSPORT_SIZE * (d))
|
#define EIC770X_SYSPORT_BASE(d) (0x40000000UL + EIC770X_SYSPORT_SIZE * (d))
|
||||||
#define EIC770X_SYSPORT_LOCAL EIC770X_SYSPORT_BASE(current_hart_die())
|
#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 (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 (EIC770X_SYSCRG + 0x300UL)
|
||||||
#define EIC770X_SYSCRG_RST_VAL 0x1AC0FFE6UL
|
#define EIC770X_SYSCRG_RST_VAL 0x1AC0FFE6UL
|
||||||
|
|
||||||
@@ -76,4 +85,17 @@ struct eic770x_board_override {
|
|||||||
#define EIC770X_TO_UNCACHED(x) ((x) - EIC770X_CACHED_BASE + \
|
#define EIC770X_TO_UNCACHED(x) ((x) - EIC770X_CACHED_BASE + \
|
||||||
EIC770X_UNCACHED_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
|
#endif
|
||||||
|
|||||||
64
platform/generic/include/eswin/hfp.h
Normal file
64
platform/generic/include/eswin/hfp.h
Normal file
@@ -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
|
||||||
Reference in New Issue
Block a user