diff options
Diffstat (limited to 'roms/skiboot/core/platform.c')
-rw-r--r-- | roms/skiboot/core/platform.c | 319 |
1 files changed, 319 insertions, 0 deletions
diff --git a/roms/skiboot/core/platform.c b/roms/skiboot/core/platform.c new file mode 100644 index 000000000..320fdea03 --- /dev/null +++ b/roms/skiboot/core/platform.c @@ -0,0 +1,319 @@ +// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later +/* + * OPAL Platform abstraction + * + * Some OPAL calls may/may not call into the struct platform that's + * probed during boot. There's also a bunch of platform specific init + * and configuration that's called. + * + * Copyright 2013-2019 IBM Corp. + */ + +#include <stdlib.h> +#include <skiboot.h> +#include <opal.h> +#include <console.h> +#include <timebase.h> +#include <cpu.h> +#include <chip.h> +#include <xscom.h> +#include <errorlog.h> +#include <bt.h> +#include <nvram.h> +#include <npu2.h> +#include <platforms/astbmc/astbmc.h> + +bool manufacturing_mode = false; +struct platform platform; + +DEFINE_LOG_ENTRY(OPAL_RC_ABNORMAL_REBOOT, OPAL_PLATFORM_ERR_EVT, OPAL_CEC, + OPAL_CEC_HARDWARE, OPAL_ERROR_PANIC, + OPAL_ABNORMAL_POWER_OFF); + +/* + * Various wrappers for platform functions + */ +static int64_t opal_cec_power_down(uint64_t request) +{ + prlog(PR_NOTICE, "OPAL: Shutdown request type 0x%llx...\n", request); + + opal_quiesce(QUIESCE_HOLD, -1); + + console_complete_flush(); + + if (platform.cec_power_down) + return platform.cec_power_down(request); + + return OPAL_SUCCESS; +} +opal_call(OPAL_CEC_POWER_DOWN, opal_cec_power_down, 1); + +static int64_t full_reboot(void) +{ + prlog(PR_NOTICE, "OPAL: Reboot request...\n"); + + console_complete_flush(); + + if (platform.cec_reboot) + return platform.cec_reboot(); + + return OPAL_SUCCESS; +} + +static int64_t opal_cec_reboot(void) +{ + opal_quiesce(QUIESCE_HOLD, -1); + + /* + * Fast-reset was enabled by default for a long time in an attempt to + * make it more stable by exercising it more frequently. This resulted + * in a fair amount of pain due to mis-behaving hardware and confusion + * about what a "reset" is supposed to do exactly. Additionally, + * secure variables require a full reboot to work at all. + * + * Due to all that fast-reset should only be used if it's explicitly + * enabled. It started life as a debug hack and should remain one. + */ + if (nvram_query_eq_safe("fast-reset", "1")) + fast_reboot(); + + return full_reboot(); +} +opal_call(OPAL_CEC_REBOOT, opal_cec_reboot, 0); + +static int64_t opal_cec_reboot2(uint32_t reboot_type, char *diag) +{ + struct errorlog *buf; + + opal_quiesce(QUIESCE_HOLD, -1); + + switch (reboot_type) { + case OPAL_REBOOT_NORMAL: + return opal_cec_reboot(); + case OPAL_REBOOT_PLATFORM_ERROR: + prlog(PR_EMERG, + "OPAL: Reboot requested due to Platform error.\n"); + buf = opal_elog_create(&e_info(OPAL_RC_ABNORMAL_REBOOT), 0); + if (buf) { + log_append_msg(buf, + "OPAL: Reboot requested due to Platform error."); + if (diag) { + /* Add user section "DESC" */ + log_add_section(buf, OPAL_ELOG_SEC_DESC); + log_append_data(buf, diag, strlen(diag)); + } + log_commit(buf); + } else { + prerror("OPAL: failed to log an error\n"); + } + disable_fast_reboot("Reboot due to Platform Error"); + console_complete_flush(); + return xscom_trigger_xstop(); + case OPAL_REBOOT_FULL_IPL: + prlog(PR_NOTICE, "Reboot: Full reboot requested"); + return full_reboot(); + case OPAL_REBOOT_MPIPL: + prlog(PR_NOTICE, "Reboot: OS reported error. Performing MPIPL\n"); + console_complete_flush(); + if (platform.terminate) + platform.terminate("OS reported error. Performing MPIPL\n"); + else + full_reboot(); + for (;;); + break; + case OPAL_REBOOT_FAST: + prlog(PR_NOTICE, "Reboot: Fast reboot requested by OS\n"); + fast_reboot(); + prlog(PR_NOTICE, "Reboot: Fast reboot failed\n"); + return OPAL_UNSUPPORTED; + default: + prlog(PR_NOTICE, "OPAL: Unsupported reboot request %d\n", reboot_type); + return OPAL_UNSUPPORTED; + break; + } + return OPAL_SUCCESS; +} +opal_call(OPAL_CEC_REBOOT2, opal_cec_reboot2, 2); + +static bool generic_platform_probe(void) +{ + if (dt_find_by_path(dt_root, "bmc")) { + /* We appear to have a BMC... so let's cross our fingers + * and see if we can do anything! + */ + prlog(PR_ERR, "GENERIC BMC PLATFORM: **GUESSING** that there's " + "*maybe* a BMC we can talk to.\n"); + prlog(PR_ERR, "THIS IS ****UNSUPPORTED****, BRINGUP USE ONLY.\n"); + astbmc_early_init(); + } else { + uart_init(); + } + + return true; +} + +static void generic_platform_init(void) +{ + if (uart_enabled()) + set_opal_console(&uart_opal_con); + + if (dt_find_by_path(dt_root, "bmc")) { + prlog(PR_ERR, "BMC-GUESSWORK: Here be dragons with a taste for human flesh\n"); + astbmc_init(); + } else { + /* Otherwise we go down the ultra-minimal path */ + + /* Enable a BT interface if we find one too */ + bt_init(); + } + + /* Fake a real time clock */ + fake_rtc_init(); +} + +static int64_t generic_cec_power_down(uint64_t request __unused) +{ + return OPAL_UNSUPPORTED; +} + +static int generic_resource_loaded(enum resource_id id, uint32_t subid) +{ + if (dt_find_by_path(dt_root, "bmc")) + return flash_resource_loaded(id, subid); + + return OPAL_EMPTY; +} + +static int generic_start_preload_resource(enum resource_id id, uint32_t subid, + void *buf, size_t *len) +{ + if (dt_find_by_path(dt_root, "bmc")) + return flash_start_preload_resource(id, subid, buf, len); + + return OPAL_EMPTY; +} + +/* These values will work for a ZZ booted using BML */ +static const struct platform_ocapi generic_ocapi = { + .i2c_engine = 1, + .i2c_port = 4, + .i2c_reset_addr = 0x20, + .i2c_reset_brick2 = (1 << 1), + .i2c_reset_brick3 = (1 << 6), + .i2c_reset_brick4 = 0, /* unused */ + .i2c_reset_brick5 = 0, /* unused */ + .i2c_presence_addr = 0x20, + .i2c_presence_brick2 = (1 << 2), /* bottom connector */ + .i2c_presence_brick3 = (1 << 7), /* top connector */ + .i2c_presence_brick4 = 0, /* unused */ + .i2c_presence_brick5 = 0, /* unused */ + .odl_phy_swap = true, +}; + +static struct bmc_platform generic_bmc = { + .name = "generic", +}; + +static struct platform generic_platform = { + .name = "generic", + .bmc = &generic_bmc, + .probe = generic_platform_probe, + .init = generic_platform_init, + .nvram_info = fake_nvram_info, + .nvram_start_read = fake_nvram_start_read, + .nvram_write = fake_nvram_write, + .cec_power_down = generic_cec_power_down, + .start_preload_resource = generic_start_preload_resource, + .resource_loaded = generic_resource_loaded, + .ocapi = &generic_ocapi, + .npu2_device_detect = npu2_i2c_presence_detect, /* Assumes ZZ */ +}; + +const struct bmc_platform *bmc_platform = &generic_bmc; + +void set_bmc_platform(const struct bmc_platform *bmc) +{ + if (bmc) + prlog(PR_NOTICE, "PLAT: Detected BMC platform %s\n", bmc->name); + else + bmc = &generic_bmc; + + bmc_platform = bmc; +} + +void probe_platform(void) +{ + struct platform *platforms = &__platforms_start; + unsigned int i; + + /* Detect Manufacturing mode */ + if (dt_find_property(dt_root, "ibm,manufacturing-mode")) { + /** + * @fwts-label ManufacturingMode + * @fwts-advice You are running in manufacturing mode. + * This mode should only be enabled in a factory during + * manufacturing. + */ + prlog(PR_NOTICE, "PLAT: Manufacturing mode ON\n"); + manufacturing_mode = true; + } + + for (i = 0; &platforms[i] < &__platforms_end; i++) { + if (platforms[i].probe && platforms[i].probe()) { + platform = platforms[i]; + break; + } + } + if (!platform.name) { + platform = generic_platform; + if (platform.probe) + platform.probe(); + } + + prlog(PR_NOTICE, "PLAT: Detected %s platform\n", platform.name); + + set_bmc_platform(platform.bmc); +} + + +int start_preload_resource(enum resource_id id, uint32_t subid, + void *buf, size_t *len) +{ + if (!platform.start_preload_resource) + return OPAL_UNSUPPORTED; + + return platform.start_preload_resource(id, subid, buf, len); +} + +int resource_loaded(enum resource_id id, uint32_t idx) +{ + if (!platform.resource_loaded) + return OPAL_SUCCESS; + + return platform.resource_loaded(id, idx); +} + +int wait_for_resource_loaded(enum resource_id id, uint32_t idx) +{ + int r = resource_loaded(id, idx); + int waited = 0; + + while(r == OPAL_BUSY) { + opal_run_pollers(); + r = resource_loaded(id, idx); + if (r != OPAL_BUSY) + break; + time_wait_ms_nopoll(5); + waited+=5; + } + + prlog(PR_TRACE, "PLATFORM: wait_for_resource_loaded %x/%x %u ms\n", + id, idx, waited); + return r; +} + +void op_display(enum op_severity sev, enum op_module mod, uint16_t code) +{ + if (platform.op_display) + platform.op_display(sev, mod, code); +} |