Refactor common functions into files
Refactor common functions into files that can be reused by other
platforms. This is just a start, but make it so we can put different
platform init routines in other files and still access the functions
for gpio i2c and filesystem helpers.
Tested:
flash onto a gb200, log output was clean.
```
USB_HUB_RESET_L-O Request to set to 0
USB_HUB_RESET_L-O Set to 0
HMC present in platformSleeping for 100 milliseconds
SGPIO_BMC_EN-O Request to set to 1
SGPIO_BMC_EN-O Set to 1
HMC_BMC_DETECT-O Request to set to 0
HMC_BMC_DETECT-O Set to 0
BMC_EROT_FPGA_SPI_MUX_SEL-O Request to set to 1
BMC_EROT_FPGA_SPI_MUX_SEL-O Set to 1
BMC_12V_CTRL-O Request to set to 1
BMC_12V_CTRL-O Set to 1
PWR_BRAKE_L-O Request to set to 1
PWR_BRAKE_L-O Set to 1
SHDN_REQ_L-O Request to set to 1
SHDN_REQ_L-O Set to 1
SHDN_FORCE_L-O Request to set to 1
SHDN_FORCE_L-O Set to 1
SYS_RST_IN_L-O Request to set to 0
SYS_RST_IN_L-O Set to 0
FPGA_READY_BMC-I GpioEvent is already 1
SEC_FPGA_READY_BMC-I GpioEvent is already 1
EROT_FPGA_RST_L-O Request to set to 1
EROT_FPGA_RST_L-O Set to 1
SEC_EROT_FPGA_RST_L-O Request to set to 1
SEC_EROT_FPGA_RST_L-O Set to 1
Sleeping for 100 milliseconds
FPGA_RST_L-O Request to set to 1
FPGA_RST_L-O Set to 1
FPGA_READY_BMC-I Waiting to go to assert
FPGA_READY_BMC-I Timeout
FPGA_READY_BMC-I failed to assert
SEC_FPGA_READY_BMC-I Waiting to go to assert
SEC_FPGA_READY_BMC-I Timeout
SEC_FPGA_READY_BMC-I failed to assert
1e78a100 unbound
1e78a100 bound
1e78a180 unbound
1e78a180 bound
RUN_POWER_EN-O Request to set to 1
RUN_POWER_EN-O Set to 1
SYS_RST_IN_L-O Request to set to 1
SYS_RST_IN_L-O Settingto 1
GLOBAL_WP_BMC-O Request to set to 0
GLOBAL_WP_BMC-O Set to 0
BMC_READY-O Request to set to 1
BMC_READY-O Set to 1
USB_HUB_RESET_L-O Request to set to 1
USB_HUB_RESET_L-O Settingto 1
Platform init complete
```
Change-Id: I7f2134470536d48e1face39075c5fa1d40dc0de7
Signed-off-by: Marc Olberding <molberding@nvidia.com>
diff --git a/platform.cpp b/platform.cpp
index 7a947cf..015a1db 100644
--- a/platform.cpp
+++ b/platform.cpp
@@ -1,6 +1,10 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2025 NVIDIA
+#include "gpio.hpp"
+#include "i2c.hpp"
+#include "utilities.hpp"
+
#include <fcntl.h>
#include <systemd/sd-daemon.h>
@@ -15,299 +19,35 @@
#include <format>
#include <fstream>
#include <iostream>
-#include <thread>
-#include <unordered_map>
using namespace std::chrono_literals;
-constexpr static const char* app_name = "platform_init";
-
-// Map of GPIO name to line. Holds lines open for the duration of the program
-static std::unordered_map<std::string, gpiod::line> io;
-
-void sleep_milliseconds(std::chrono::milliseconds milliseconds)
-{
- std::cerr << std::format("Sleeping for {} milliseconds\n",
- milliseconds.count());
- std::this_thread::sleep_for(milliseconds);
-}
-
-void set_gpio(const char* line_name, int value,
- std::chrono::milliseconds find_timeout = 0ms)
-{
- std::cerr << std::format("{} Request to set to {}\n", line_name, value);
- std::chrono::milliseconds polling_time = 10ms;
- gpiod::line& line = io[line_name];
- if (!line)
- {
- do
- {
- line = gpiod::find_line(line_name);
- if (!line)
- {
- std::cerr << std::format(
- "{} not found yet, waiting and retrying\n", line_name);
-
- sleep_milliseconds(polling_time);
- find_timeout -= polling_time;
- }
- } while (!line && find_timeout > 0s);
- if (!line && find_timeout <= 0s)
- {
- std::cerr << std::format("{} Unable to find\n", line_name);
- return;
- }
- try
- {
- line.request({app_name, gpiod::line_request::DIRECTION_OUTPUT, 0},
- value);
- }
- catch (const std::system_error& e)
- {
- std::cerr << std::format(
- "{} unable to set direction and value {}\n", line_name,
- e.what());
- return;
- }
- // No need to set if the init did it for us
- std::cerr << std::format("{} Set to {}\n", line_name, value);
- return;
- }
- std::cerr << std::format("{} Settingto {}\n", line_name, value);
- line.set_value(value);
-}
-
-int get_gpio(const char* line_name)
-{
- std::cerr << std::format("{} Request to get\n", line_name);
-
- gpiod::line line = gpiod::find_line(line_name);
- if (!line)
- {
- std::cerr << std::format("{} Set unable to find\n", line_name);
- return -1;
- }
- try
- {
- line.request({app_name, gpiod::line_request::DIRECTION_INPUT, 0});
- }
- catch (const std::system_error& e)
- {
- std::cerr << std::format("{} unable to set {}\n", line_name, e.what());
- }
-
- int value = line.get_value();
- std::cerr << std::format("{} was {}\n", line_name, value);
- return value;
-}
-
-enum class GpioEventResult
-{
- Error,
- Asserted,
- Timeout
-};
-
-struct GpioEvent
-{
- GpioEvent(const char* line_name_in, int value_in) :
- line_name(line_name_in), value(value_in)
- {
- line = gpiod::find_line(line_name);
- if (!line)
- {
- std::cerr << std::format("{} GpioEvent: Unable to find\n",
- line_name);
- return;
- }
- int edge = (value != 0) ? ::gpiod::line_request::EVENT_RISING_EDGE
- : ::gpiod::line_request::EVENT_FALLING_EDGE;
-
- line.request({app_name, edge, 0});
-
- int val = line.get_value();
- if (val == value)
- {
- std::cerr << std::format("{} GpioEvent is already {}\n", line_name,
- val);
- }
- else
- {
- std::cerr << std::format("GpioEvent created for {}\n", line_name);
- }
- }
- GpioEventResult wait()
- {
- if (!line)
- {
- std::cerr << std::format("Line {} wasn't initialized\n", line_name);
- return GpioEventResult::Error;
- }
- std::cerr << std::format("{} Waiting to go to {}\n", line_name,
- (value != 0) ? "assert" : "deassert");
- auto events = line.event_wait(std::chrono::seconds(120));
- if (!events)
- {
- std::cerr << std::format("{} Timeout\n", line_name);
- return GpioEventResult::Timeout;
- }
-
- std::cerr << std::format("{} Asserted\n", line_name);
-
- return GpioEventResult::Asserted;
- }
-
- gpiod::line line;
- std::string line_name;
- int value;
-};
-
-void rebind_i2c(std::string number)
-{
- std::string bindpath =
- std::format("/sys/bus/platform/drivers/aspeed-i2c-bus/unbind", number);
- std::ofstream bindofs(bindpath);
- if (!bindofs)
- {
- std::cerr << std::format("{} unable to open\n", bindpath);
- return;
- }
- try
- {
- bindofs << std::format("{}.i2c\n", number);
- }
- catch (const std::system_error& e)
- {
- std::cerr << std::format("{} unable to write\n", bindpath);
- return;
- }
- bindofs.close();
- std::cerr << std::format("{} unbound\n", number);
-
- std::string unbindpath =
- std::format("/sys/bus/platform/drivers/aspeed-i2c-bus/bind", number);
- std::ofstream unbindofs(unbindpath);
- if (!unbindofs)
- {
- std::cerr << std::format("{} unable to open\n", unbindpath);
- return;
- }
- try
- {
- unbindofs << std::format("{}.i2c\n", number);
- }
- catch (const std::system_error& e)
- {
- std::cerr << std::format("{} unable to write\n", unbindpath);
- return;
- }
- std::cerr << std::format("{} bound\n", number);
-}
-
-void set_gpio_raw(unsigned int chip_num, unsigned int bit_num, int value)
-{
- std::string syspath = std::format("gpiochip{}", chip_num);
- std::cerr << std::format("Setting gpiochip{} bit {} to {}\n", chip_num,
- bit_num, value);
- try
- {
- gpiod::chip chip(syspath);
- gpiod::line line = chip.get_line(bit_num);
- line.request({app_name, gpiod::line_request::DIRECTION_OUTPUT, 0},
- value);
- std::cerr << std::format("gpiochip{} bit {} set to {}\n", chip_num,
- bit_num, value);
- }
- catch (const std::system_error& e)
- {
- std::cerr << std::format("Error setting gpiochip{} bit {}: {}\n",
- chip_num, bit_num, e.what());
- }
-}
-
-void new_device(unsigned int bus, unsigned int address,
- std::string_view device_type)
-{
- std::string path =
- std::format("/sys/bus/i2c/devices/i2c-{}/new_device", bus);
- std::cerr << std::format("attempting to open {}", path);
- std::ofstream new_device(path);
- if (!new_device)
- {
- std::cerr << "Error: Unable to create I2C device\n";
- return;
- }
- new_device << std::format("{} 0x{:02x}", device_type, address);
- new_device.close();
-
- std::cerr << std::format("{} device created at bus {}", device_type, bus);
-}
-
-void wait_for_path_to_exist(std::string_view path,
- std::chrono::milliseconds timeout)
-{
- while (true)
- {
- std::error_code ec;
- bool exists = std::filesystem::exists(path, ec);
- if (exists)
- {
- return;
- }
- sleep_milliseconds(1ms);
- timeout -= 1ms;
- }
- std::cerr << std::format("Failed to wait for {} to exist", path);
-}
-
void init_p2020_gpu_card()
{
std::cerr << "Initializing GPU card...\n";
// Init the P2020 gpio expander
- new_device(14, 0x20, "pca6408");
+ 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
- std::string gpio_chip;
- for (const auto& entry : std::filesystem::directory_iterator(device_path))
+ int gpiochipint = gpio::find_chip_idx_from_dir(device_path);
+ if (gpiochipint < 0)
{
- std::string path = entry.path().string();
- if (path.find("gpiochip") != std::string::npos)
- {
- gpio_chip =
- path.substr(path.find("gpiochip") + std::strlen("gpiochip"));
- break;
- }
- }
- if (gpio_chip.empty())
- {
- std::cerr << "Error: Could not find GPIO chip number\n";
return;
}
-
- std::cerr << "Found GPIO chip: gpiochip" << gpio_chip << "\n";
- unsigned int gpiochipint = 0;
- std::from_chars_result r =
- std::from_chars(&*gpio_chip.begin(), &*gpio_chip.end(), gpiochipint);
- if (r.ec != std::error_code() || r.ptr != &*gpio_chip.end())
- {
- std::cout << "Failed to convert gpiochip\n";
- return;
- }
-
// Set MCU in recovery
- set_gpio_raw(gpiochipint, 3, 1);
+ gpio::set_raw(gpiochipint, 3, 1);
// Reset MCU
- set_gpio_raw(gpiochipint, 4, 0);
- set_gpio_raw(gpiochipint, 4, 1);
+ gpio::set_raw(gpiochipint, 4, 0);
+ gpio::set_raw(gpiochipint, 4, 1);
// Switch MUX to MCU
- set_gpio_raw(gpiochipint, 5, 1);
+ gpio::set_raw(gpiochipint, 5, 1);
}
bool hmc_is_present()
@@ -332,55 +72,55 @@
int init_nvidia_gb200(bool has_p2020)
{
// Reset USB hubs
- set_gpio("USB_HUB_RESET_L-O", 0, 10000ms);
+ gpio::set("USB_HUB_RESET_L-O", 0, 10000ms);
bool hmc_present = hmc_is_present();
if (!hmc_present)
{
- set_gpio("SEC_USB2_HUB_RST_L-O", 0, 10000ms);
+ gpio::set("SEC_USB2_HUB_RST_L-O", 0, 10000ms);
}
sleep_milliseconds(100ms);
if (!hmc_present)
{
- set_gpio("SEC_USB2_HUB_RST_L-O", 1);
+ 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
- set_gpio("SGPIO_BMC_EN-O", 1);
+ gpio::set("SGPIO_BMC_EN-O", 1);
// Write the bit for BMC without HMC
- set_gpio("HMC_BMC_DETECT-O", static_cast<int>(!hmc_present), 30000ms);
+ 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
- set_gpio("BMC_EROT_FPGA_SPI_MUX_SEL-O", 1);
+ gpio::set("BMC_EROT_FPGA_SPI_MUX_SEL-O", 1);
// Enable 12V
- set_gpio("BMC_12V_CTRL-O", 1, 10000ms);
+ gpio::set("BMC_12V_CTRL-O", 1, 10000ms);
- set_gpio("PWR_BRAKE_L-O", 1);
- set_gpio("SHDN_REQ_L-O", 1);
- set_gpio("SHDN_FORCE_L-O", 1);
+ 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
- set_gpio("SYS_RST_IN_L-O", 0);
+ gpio::set("SYS_RST_IN_L-O", 0);
- GpioEvent fpga_ready_wait = GpioEvent("FPGA_READY_BMC-I", 1);
- GpioEvent sec_erot_fpga_rst = GpioEvent("SEC_FPGA_READY_BMC-I", 1);
+ 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
- set_gpio("EROT_FPGA_RST_L-O", 1);
- set_gpio("SEC_EROT_FPGA_RST_L-O", 1);
+ gpio::set("EROT_FPGA_RST_L-O", 1);
+ gpio::set("SEC_EROT_FPGA_RST_L-O", 1);
sleep_milliseconds(100ms);
- set_gpio("FPGA_RST_L-O", 1);
+ gpio::set("FPGA_RST_L-O", 1);
- if (fpga_ready_wait.wait() != GpioEventResult::Asserted)
+ 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() != GpioEventResult::Asserted)
+ if (sec_erot_fpga_rst.wait() != gpio::EventResult::Asserted)
{
std::cerr << "SEC_FPGA_READY_BMC-I failed to assert\n";
// return EXIT_FAILURE;
@@ -388,26 +128,26 @@
// ReInitialize the FPGA connected I2C buses to unstick them and let
// FruDevice know it can scan for FRUs I2c bus 1
- rebind_i2c("1e78a100");
+ i2c::rebind_controller("1e78a100");
// I2c bus 2
- rebind_i2c("1e78a180");
+ i2c::rebind_controller("1e78a180");
// Set sgpio signals
- set_gpio("RUN_POWER_EN-O", 1);
- set_gpio("SYS_RST_IN_L-O", 1);
- set_gpio("GLOBAL_WP_BMC-O", 0);
+ gpio::set("RUN_POWER_EN-O", 1);
+ gpio::set("SYS_RST_IN_L-O", 1);
+ gpio::set("GLOBAL_WP_BMC-O", 0);
- set_gpio("BMC_READY-O", 1);
+ gpio::set("BMC_READY-O", 1);
if (has_p2020)
{
init_p2020_gpu_card();
}
- set_gpio("USB_HUB_RESET_L-O", 1);
+ gpio::set("USB_HUB_RESET_L-O", 1);
if (!hmc_present)
{
- set_gpio("SEC_USB2_HUB_RST_L-O", 1);
+ gpio::set("SEC_USB2_HUB_RST_L-O", 1);
}
sd_notify(0, "READY=1");