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/gpio.cpp b/gpio.cpp
new file mode 100644
index 0000000..d4b2d1b
--- /dev/null
+++ b/gpio.cpp
@@ -0,0 +1,187 @@
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2025 NVIDIA
+
+#include "gpio.hpp"
+
+#include "utilities.hpp"
+
+#include <cstring>
+#include <filesystem>
+#include <format>
+#include <iostream>
+#include <unordered_map>
+
+static std::unordered_map<std::string, gpiod::line> io;
+using namespace std::chrono_literals;
+
+namespace gpio
+{
+
+void set(const char* line_name, int value,
+ std::chrono::milliseconds find_timeout)
+{
+ 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(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;
+}
+
+Event::Event(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);
+ }
+}
+
+EventResult Event::wait()
+{
+ if (!line)
+ {
+ std::cerr << std::format("Line {} wasn't initialized\n", line_name);
+ return EventResult::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 EventResult::Timeout;
+ }
+
+ std::cerr << std::format("{} Asserted\n", line_name);
+
+ return EventResult::Asserted;
+}
+
+void set_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());
+ }
+}
+
+int find_chip_idx_from_dir(std::string_view device_path)
+{
+ std::string gpio_chip;
+ for (const auto& entry : std::filesystem::directory_iterator(device_path))
+ {
+ 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 -ENOENT;
+ }
+
+ 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 -EINVAL;
+ }
+ return gpiochipint;
+}
+} // namespace gpio