| // SPDX-License-Identifier: Apache-2.0 |
| // SPDX-FileCopyrightText: Copyright OpenBMC Authors |
| |
| #include "gpio.hpp" |
| #include "i2c.hpp" |
| #include "utilities.hpp" |
| |
| #include <systemd/sd-daemon.h> |
| |
| #include <chrono> |
| #include <filesystem> |
| #include <iostream> |
| |
| using namespace std::chrono_literals; |
| |
| namespace nvidia |
| { |
| |
| void init_p2020_gpu_card() |
| { |
| std::cerr << "Initializing GPU card...\n"; |
| |
| // Init the P2020 gpio expander |
| i2c::new_device(14, 0x20, "pca6408"); |
| |
| // Wait for device to be created |
| const auto* device_path = "/sys/bus/i2c/devices/14-0020"; |
| wait_for_path_to_exist(device_path, 1000ms); |
| |
| // Find the GPIO chip number |
| int gpiochipint = gpio::find_chip_idx_from_dir(device_path); |
| if (gpiochipint < 0) |
| { |
| return; |
| } |
| // Set MCU in recovery |
| gpio::set_raw(gpiochipint, 3, 1); |
| |
| // Reset MCU |
| gpio::set_raw(gpiochipint, 4, 0); |
| gpio::set_raw(gpiochipint, 4, 1); |
| |
| // Switch MUX to MCU |
| gpio::set_raw(gpiochipint, 5, 1); |
| } |
| |
| bool hmc_is_present() |
| { |
| std::error_code ec; |
| bool exists = std::filesystem::exists("/sys/bus/i2c/devices/9-0074", ec); |
| if (ec) |
| { |
| exists = false; |
| } |
| if (exists) |
| { |
| std::cerr << "HMC present in platform"; |
| } |
| else |
| { |
| std::cerr << "HMC not present in platform"; |
| } |
| return exists; |
| } |
| |
| int init_nvidia_gb200(bool has_p2020) |
| { |
| // Reset USB hubs |
| gpio::set("USB_HUB_RESET_L-O", 0, 10000ms); |
| bool hmc_present = hmc_is_present(); |
| if (!hmc_present) |
| { |
| gpio::set("SEC_USB2_HUB_RST_L-O", 0, 10000ms); |
| } |
| |
| sleep_milliseconds(100ms); |
| if (!hmc_present) |
| { |
| gpio::set("SEC_USB2_HUB_RST_L-O", 1); |
| } |
| // Write SGPIO_BMC_EN-O=1 to correctly set mux to send SGPIO signals to |
| // FPGA |
| gpio::set("SGPIO_BMC_EN-O", 1); |
| |
| // Write the bit for BMC without HMC |
| gpio::set("HMC_BMC_DETECT-O", static_cast<int>(!hmc_present), 30000ms); |
| |
| // Set BMC_EROT_FPGA_SPI_MUX_SEL-O = 1 to enable FPGA to access its EROT |
| gpio::set("BMC_EROT_FPGA_SPI_MUX_SEL-O", 1); |
| |
| // Enable 12V |
| gpio::set("BMC_12V_CTRL-O", 1, 10000ms); |
| |
| gpio::set("PWR_BRAKE_L-O", 1); |
| gpio::set("SHDN_REQ_L-O", 1); |
| gpio::set("SHDN_FORCE_L-O", 1); |
| // Hold in reset (asserted) after standby power enabled |
| gpio::set("SYS_RST_IN_L-O", 0); |
| |
| gpio::Event fpga_ready_wait = gpio::Event("FPGA_READY_BMC-I", 1); |
| gpio::Event sec_erot_fpga_rst = gpio::Event("SEC_FPGA_READY_BMC-I", 1); |
| |
| // Release FPGA EROT from reset |
| gpio::set("EROT_FPGA_RST_L-O", 1); |
| gpio::set("SEC_EROT_FPGA_RST_L-O", 1); |
| |
| sleep_milliseconds(100ms); |
| |
| gpio::set("FPGA_RST_L-O", 1); |
| |
| if (fpga_ready_wait.wait() != gpio::EventResult::Asserted) |
| { |
| std::cerr << "FPGA_READY_BMC-I failed to assert\n"; |
| // return EXIT_FAILURE; |
| } |
| |
| if (sec_erot_fpga_rst.wait() != gpio::EventResult::Asserted) |
| { |
| std::cerr << "SEC_FPGA_READY_BMC-I failed to assert\n"; |
| // return EXIT_FAILURE; |
| } |
| |
| // ReInitialize the FPGA connected I2C buses to unstick them and let |
| // FruDevice know it can scan for FRUs I2c bus 1 |
| i2c::rebind_controller("1e78a100"); |
| // I2c bus 2 |
| i2c::rebind_controller("1e78a180"); |
| |
| // Set sgpio signals |
| gpio::set("RUN_POWER_EN-O", 1); |
| gpio::set("SYS_RST_IN_L-O", 1); |
| gpio::set("GLOBAL_WP_BMC-O", 0); |
| |
| gpio::set("BMC_READY-O", 1); |
| |
| if (has_p2020) |
| { |
| init_p2020_gpu_card(); |
| } |
| |
| gpio::set("USB_HUB_RESET_L-O", 1); |
| if (!hmc_present) |
| { |
| gpio::set("SEC_USB2_HUB_RST_L-O", 1); |
| } |
| |
| sd_notify(0, "READY=1"); |
| std::cerr << "Platform init complete\n"; |
| pause(); |
| std::cerr << "Releasing platform\n"; |
| |
| return EXIT_SUCCESS; |
| } |
| |
| int init_gb200_base() |
| { |
| return init_nvidia_gb200(false); |
| } |
| |
| int init_gb200_with_p2020() |
| { |
| return init_nvidia_gb200(true); |
| } |
| } // namespace nvidia |