mirror of
https://github.com/riscv-software-src/opensbi.git
synced 2025-08-24 15:31:22 +01:00

For driver subsystems that are not tightly integrated into the OpenSBI init sequence, it is not important that the drivers are initialized in any particular order. By putting all of these drivers in one array, they can all be initialized with a single pass through the devicetree. This saves about 10 ms of boot time on HiFive Unmatched. Signed-off-by: Samuel Holland <samuel.holland@sifive.com> Reviewed-by: Anup Patel <anup@brainfault.org>
115 lines
2.4 KiB
C
115 lines
2.4 KiB
C
/*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*
|
|
* Copyright (c) 2023 Lin Chunzhi <chunzhi.lin@sophgo.com>
|
|
*/
|
|
|
|
#include <libfdt.h>
|
|
#include <sbi/sbi_hart.h>
|
|
#include <sbi/sbi_types.h>
|
|
#include <sbi/sbi_error.h>
|
|
#include <sbi/sbi_system.h>
|
|
#include <sbi/sbi_console.h>
|
|
#include <sbi_utils/fdt/fdt_driver.h>
|
|
#include <sbi_utils/fdt/fdt_helper.h>
|
|
#include <sbi_utils/i2c/fdt_i2c.h>
|
|
|
|
#define MANGO_BOARD_TYPE_MASK 0x80
|
|
|
|
#define REG_BOARD_TYPE 0x00
|
|
#define REG_CMD 0x03
|
|
|
|
#define CMD_POWEROFF 0x02
|
|
#define CMD_RESET 0x03
|
|
#define CMD_REBOOT 0x07
|
|
|
|
static struct i2c_adapter *mcu_adapter = NULL;
|
|
static uint32_t mcu_reg = 0;
|
|
|
|
static int sg2042_mcu_reset_check(u32 type, u32 reason)
|
|
{
|
|
switch (type) {
|
|
case SBI_SRST_RESET_TYPE_SHUTDOWN:
|
|
return 1;
|
|
case SBI_SRST_RESET_TYPE_COLD_REBOOT:
|
|
case SBI_SRST_RESET_TYPE_WARM_REBOOT:
|
|
return 255;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void sg2042_mcu_reset(u32 type, u32 reason)
|
|
{
|
|
switch (type) {
|
|
case SBI_SRST_RESET_TYPE_SHUTDOWN:
|
|
i2c_adapter_reg_write(mcu_adapter, mcu_reg,
|
|
REG_CMD, CMD_POWEROFF);
|
|
break;
|
|
case SBI_SRST_RESET_TYPE_COLD_REBOOT:
|
|
case SBI_SRST_RESET_TYPE_WARM_REBOOT:
|
|
i2c_adapter_reg_write(mcu_adapter, mcu_reg,
|
|
REG_CMD, CMD_REBOOT);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static struct sbi_system_reset_device sg2042_mcu_reset_device = {
|
|
.name = "sg2042-mcu-reset",
|
|
.system_reset_check = sg2042_mcu_reset_check,
|
|
.system_reset = sg2042_mcu_reset
|
|
};
|
|
|
|
static int sg2042_mcu_reset_check_board(struct i2c_adapter *adap, uint32_t reg)
|
|
{
|
|
static uint8_t val;
|
|
int ret;
|
|
|
|
/* check board type */
|
|
ret = i2c_adapter_reg_read(adap, reg, REG_BOARD_TYPE, &val);
|
|
if (ret)
|
|
return ret;
|
|
|
|
if (!(val & MANGO_BOARD_TYPE_MASK))
|
|
return SBI_ENODEV;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int sg2042_mcu_reset_init(const void *fdt, int nodeoff,
|
|
const struct fdt_match *match)
|
|
{
|
|
int ret, i2c_bus;
|
|
uint64_t addr;
|
|
|
|
ret = fdt_get_node_addr_size(fdt, nodeoff, 0, &addr, NULL);
|
|
if (ret)
|
|
return ret;
|
|
|
|
mcu_reg = addr;
|
|
|
|
i2c_bus = fdt_parent_offset(fdt, nodeoff);
|
|
if (i2c_bus < 0)
|
|
return i2c_bus;
|
|
|
|
ret = fdt_i2c_adapter_get(fdt, i2c_bus, &mcu_adapter);
|
|
if (ret)
|
|
return ret;
|
|
|
|
ret = sg2042_mcu_reset_check_board(mcu_adapter, mcu_reg);
|
|
|
|
sbi_system_reset_add_device(&sg2042_mcu_reset_device);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static const struct fdt_match sg2042_mcu_reset_match[] = {
|
|
{ .compatible = "sophgo,sg2042-hwmon-mcu", .data = (void *)true},
|
|
{ },
|
|
};
|
|
|
|
const struct fdt_driver fdt_reset_sg2042_mcu = {
|
|
.match_table = sg2042_mcu_reset_match,
|
|
.init = sg2042_mcu_reset_init,
|
|
};
|