Files
opensbi/platform/generic/sifive_fu740.c
Jessica Clarke 14faee6916 lib: sbi: Improve fatal error handling
BUG and BUG_ON are not informative and are rather lazy interfaces, only
telling the user that something went wrong in a given function, but not
what, requiring the user to find the sources corresponding to their
firmware (which may not be available) and figure out how that BUG(_ON)
was hit. Even SBI_ASSERT in its current form, which does include the
condition that triggered it in the output, isn't necessarily very
informative. In some cases, the error may be fixable by the user, but
they need to know the problem in order to have any hope of fixing it.
It's also a nuisance for developers, whose development trees may have
changed significantly since the release in question being used, and so
line numbers can make it harder for them to understand which error case
a user has hit.

This patch introduces a new sbi_panic function which is printf-like,
allowing detailed error messages to be printed to the console. BUG and
BUG_ON are removed, since the former is just a worse form of sbi_panic
and the latter is a worse version of SBI_ASSERT. Finally, SBI_ASSERT is
augmented to take a set of arguments to pass to sbi_panic on failure,
used like so (sbi_boot_print_hart's current error case, which currently
manually calls sbi_printf and sbi_hart_hang):

  SBI_ASSERT(xlen >= 1, ("Error %d getting MISA XLEN\n", xlen));

The existing users of BUG are replaced with calls to sbi_panic along
with informative error messages. BUG_ON and SBI_ASSERT were unused (and,
in the case of SBI_ASSERT, remain unused).

Many existing users of sbi_hart_hang should be converted to use either
sbi_panic or SBI_ASSERT after this commit.

Signed-off-by: Jessica Clarke <jrtc27@jrtc27.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2021-12-02 08:50:36 +05:30

232 lines
5.0 KiB
C

/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2021 SiFive
* Copyright (c) 2021 YADRO
*
* Authors:
* David Abdurachmanov <david.abdurachmanov@sifive.com>
* Nikita Shubin <n.shubin@yadro.com>
*/
#include <platform_override.h>
#include <libfdt.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_hart.h>
#include <sbi/sbi_system.h>
#include <sbi/sbi_console.h>
#include <sbi_utils/fdt/fdt_helper.h>
#include <sbi_utils/fdt/fdt_fixup.h>
#include <sbi_utils/reset/fdt_reset.h>
#include <sbi_utils/i2c/fdt_i2c.h>
#define DA9063_REG_PAGE_CON 0x00
#define DA9063_REG_CONTROL_A 0x0e
#define DA9063_REG_CONTROL_F 0x13
#define DA9063_REG_DEVICE_ID 0x81
#define DA9063_CONTROL_A_M_POWER1_EN (1 << 6)
#define DA9063_CONTROL_A_M_POWER_EN (1 << 5)
#define DA9063_CONTROL_A_STANDBY (1 << 3)
#define DA9063_CONTROL_F_WAKEUP (1 << 2)
#define DA9063_CONTROL_F_SHUTDOWN (1 << 1)
#define PMIC_CHIP_ID_DA9063 0x61
static struct {
struct i2c_adapter *adapter;
uint32_t reg;
} da9063;
static int da9063_system_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 inline int da9063_sanity_check(struct i2c_adapter *adap, uint32_t reg)
{
uint8_t val;
int rc = i2c_adapter_reg_write(adap, reg, DA9063_REG_PAGE_CON, 0x02);
if (rc)
return rc;
/* check set page*/
rc = i2c_adapter_reg_read(adap, reg, 0x0, &val);
if (rc)
return rc;
if (val != 0x02)
return SBI_ENODEV;
/* read and check device id */
rc = i2c_adapter_reg_read(adap, reg, DA9063_REG_DEVICE_ID, &val);
if (rc)
return rc;
if (val != PMIC_CHIP_ID_DA9063)
return SBI_ENODEV;
return 0;
}
static inline int da9063_shutdown(struct i2c_adapter *adap, uint32_t reg)
{
int rc = i2c_adapter_reg_write(adap, da9063.reg,
DA9063_REG_PAGE_CON, 0x00);
if (rc)
return rc;
return i2c_adapter_reg_write(adap, da9063.reg,
DA9063_REG_CONTROL_F,
DA9063_CONTROL_F_SHUTDOWN);
}
static inline int da9063_reset(struct i2c_adapter *adap, uint32_t reg)
{
int rc = i2c_adapter_reg_write(adap, da9063.reg,
DA9063_REG_PAGE_CON, 0x00);
if (rc)
return rc;
rc = i2c_adapter_reg_write(adap, da9063.reg,
DA9063_REG_CONTROL_F,
DA9063_CONTROL_F_WAKEUP);
if (rc)
return rc;
return i2c_adapter_reg_write(adap, da9063.reg,
DA9063_REG_CONTROL_A,
DA9063_CONTROL_A_M_POWER1_EN |
DA9063_CONTROL_A_M_POWER_EN |
DA9063_CONTROL_A_STANDBY);
}
static void da9063_system_reset(u32 type, u32 reason)
{
struct i2c_adapter *adap = da9063.adapter;
uint32_t reg = da9063.reg;
int rc;
if (adap) {
/* sanity check */
rc = da9063_sanity_check(adap, reg);
if (rc) {
sbi_printf("%s: chip is not da9063 PMIC\n", __func__);
goto skip_reset;
}
switch (type) {
case SBI_SRST_RESET_TYPE_SHUTDOWN:
da9063_shutdown(adap, reg);
break;
case SBI_SRST_RESET_TYPE_COLD_REBOOT:
case SBI_SRST_RESET_TYPE_WARM_REBOOT:
da9063_reset(adap, reg);
break;
}
}
skip_reset:
sbi_hart_hang();
}
static struct sbi_system_reset_device da9063_reset_i2c = {
.name = "da9063-reset",
.system_reset_check = da9063_system_reset_check,
.system_reset = da9063_system_reset
};
static int da9063_reset_init(void *fdt, int nodeoff,
const struct fdt_match *match)
{
int rc, i2c_bus;
struct i2c_adapter *adapter;
uint64_t addr;
/* we are dlg,da9063 node */
rc = fdt_get_node_addr_size(fdt, nodeoff, 0, &addr, NULL);
if (rc)
return rc;
da9063.reg = addr;
/* find i2c bus parent node */
i2c_bus = fdt_parent_offset(fdt, nodeoff);
if (i2c_bus < 0)
return i2c_bus;
/* i2c adapter get */
rc = fdt_i2c_adapter_get(fdt, i2c_bus, &adapter);
if (rc)
return rc;
da9063.adapter = adapter;
sbi_system_reset_add_device(&da9063_reset_i2c);
return 0;
}
static const struct fdt_match da9063_reset_match[] = {
{ .compatible = "dlg,da9063", .data = (void *)TRUE },
{ },
};
struct fdt_reset fdt_reset_da9063 = {
.match_table = da9063_reset_match,
.init = da9063_reset_init,
};
static u64 sifive_fu740_tlbr_flush_limit(const struct fdt_match *match)
{
/*
* Needed to address CIP-1200 errata on SiFive FU740
* Title: Instruction TLB can fail to respect a non-global SFENCE
* Workaround: Flush the TLB using SFENCE.VMA x0, x0
* See Errata_FU740-C000_20210205 from
* https://www.sifive.com/boards/hifive-unmatched
*/
return 0;
}
static int sifive_fu740_final_init(bool cold_boot,
const struct fdt_match *match)
{
int rc;
void *fdt = fdt_get_address();
if (cold_boot) {
rc = fdt_reset_driver_init(fdt, &fdt_reset_da9063);
if (rc)
sbi_printf("%s: failed to find da9063 for reset\n",
__func__);
}
return 0;
}
static const struct fdt_match sifive_fu740_match[] = {
{ .compatible = "sifive,fu740" },
{ .compatible = "sifive,fu740-c000" },
{ .compatible = "sifive,hifive-unmatched-a00" },
{ },
};
const struct platform_override sifive_fu740 = {
.match_table = sifive_fu740_match,
.tlbr_flush_limit = sifive_fu740_tlbr_flush_limit,
.final_init = sifive_fu740_final_init,
};