blob: 015a1dbef87a65f05c31fceb36fc3f81306958fe [file] [log] [blame]
Ed Tanous2b314e42025-08-19 15:46:18 -07001// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: 2025 NVIDIA
3
Marc Olberding1e17db52025-08-27 12:25:28 -07004#include "gpio.hpp"
5#include "i2c.hpp"
6#include "utilities.hpp"
7
Ed Tanous2b314e42025-08-19 15:46:18 -07008#include <fcntl.h>
9#include <systemd/sd-daemon.h>
10
11#include <CLI/CLI.hpp>
12#include <gpiod.hpp>
13
14#include <chrono>
15#include <cstdint>
16#include <cstdlib>
17#include <cstring>
18#include <filesystem>
19#include <format>
20#include <fstream>
21#include <iostream>
Ed Tanous2b314e42025-08-19 15:46:18 -070022
23using namespace std::chrono_literals;
24
Ed Tanous2b314e42025-08-19 15:46:18 -070025void init_p2020_gpu_card()
26{
27 std::cerr << "Initializing GPU card...\n";
28
29 // Init the P2020 gpio expander
Marc Olberding1e17db52025-08-27 12:25:28 -070030 i2c::new_device(14, 0x20, "pca6408");
Ed Tanous2b314e42025-08-19 15:46:18 -070031
32 // Wait for device to be created
33 const auto* device_path = "/sys/bus/i2c/devices/14-0020";
34 wait_for_path_to_exist(device_path, 1000ms);
35
36 // Find the GPIO chip number
Marc Olberding1e17db52025-08-27 12:25:28 -070037 int gpiochipint = gpio::find_chip_idx_from_dir(device_path);
38 if (gpiochipint < 0)
Ed Tanous2b314e42025-08-19 15:46:18 -070039 {
Ed Tanous2b314e42025-08-19 15:46:18 -070040 return;
41 }
Ed Tanous2b314e42025-08-19 15:46:18 -070042 // Set MCU in recovery
Marc Olberding1e17db52025-08-27 12:25:28 -070043 gpio::set_raw(gpiochipint, 3, 1);
Ed Tanous2b314e42025-08-19 15:46:18 -070044
45 // Reset MCU
Marc Olberding1e17db52025-08-27 12:25:28 -070046 gpio::set_raw(gpiochipint, 4, 0);
47 gpio::set_raw(gpiochipint, 4, 1);
Ed Tanous2b314e42025-08-19 15:46:18 -070048
49 // Switch MUX to MCU
Marc Olberding1e17db52025-08-27 12:25:28 -070050 gpio::set_raw(gpiochipint, 5, 1);
Ed Tanous2b314e42025-08-19 15:46:18 -070051}
52
53bool hmc_is_present()
54{
55 std::error_code ec;
56 bool exists = std::filesystem::exists("/sys/bus/i2c/devices/9-0074", ec);
57 if (ec)
58 {
59 exists = false;
60 }
61 if (exists)
62 {
63 std::cerr << "HMC present in platform";
64 }
65 else
66 {
67 std::cerr << "HMC not present in platform";
68 }
69 return exists;
70}
71
72int init_nvidia_gb200(bool has_p2020)
73{
74 // Reset USB hubs
Marc Olberding1e17db52025-08-27 12:25:28 -070075 gpio::set("USB_HUB_RESET_L-O", 0, 10000ms);
Ed Tanous2b314e42025-08-19 15:46:18 -070076 bool hmc_present = hmc_is_present();
77 if (!hmc_present)
78 {
Marc Olberding1e17db52025-08-27 12:25:28 -070079 gpio::set("SEC_USB2_HUB_RST_L-O", 0, 10000ms);
Ed Tanous2b314e42025-08-19 15:46:18 -070080 }
81
82 sleep_milliseconds(100ms);
83 if (!hmc_present)
84 {
Marc Olberding1e17db52025-08-27 12:25:28 -070085 gpio::set("SEC_USB2_HUB_RST_L-O", 1);
Ed Tanous2b314e42025-08-19 15:46:18 -070086 }
87 // Write SGPIO_BMC_EN-O=1 to correctly set mux to send SGPIO signals to
88 // FPGA
Marc Olberding1e17db52025-08-27 12:25:28 -070089 gpio::set("SGPIO_BMC_EN-O", 1);
Ed Tanous2b314e42025-08-19 15:46:18 -070090
91 // Write the bit for BMC without HMC
Marc Olberding1e17db52025-08-27 12:25:28 -070092 gpio::set("HMC_BMC_DETECT-O", static_cast<int>(!hmc_present), 30000ms);
Ed Tanous2b314e42025-08-19 15:46:18 -070093
94 // Set BMC_EROT_FPGA_SPI_MUX_SEL-O = 1 to enable FPGA to access its EROT
Marc Olberding1e17db52025-08-27 12:25:28 -070095 gpio::set("BMC_EROT_FPGA_SPI_MUX_SEL-O", 1);
Ed Tanous2b314e42025-08-19 15:46:18 -070096
97 // Enable 12V
Marc Olberding1e17db52025-08-27 12:25:28 -070098 gpio::set("BMC_12V_CTRL-O", 1, 10000ms);
Ed Tanous2b314e42025-08-19 15:46:18 -070099
Marc Olberding1e17db52025-08-27 12:25:28 -0700100 gpio::set("PWR_BRAKE_L-O", 1);
101 gpio::set("SHDN_REQ_L-O", 1);
102 gpio::set("SHDN_FORCE_L-O", 1);
Ed Tanous2b314e42025-08-19 15:46:18 -0700103 // Hold in reset (asserted) after standby power enabled
Marc Olberding1e17db52025-08-27 12:25:28 -0700104 gpio::set("SYS_RST_IN_L-O", 0);
Ed Tanous2b314e42025-08-19 15:46:18 -0700105
Marc Olberding1e17db52025-08-27 12:25:28 -0700106 gpio::Event fpga_ready_wait = gpio::Event("FPGA_READY_BMC-I", 1);
107 gpio::Event sec_erot_fpga_rst = gpio::Event("SEC_FPGA_READY_BMC-I", 1);
Ed Tanous2b314e42025-08-19 15:46:18 -0700108
109 // Release FPGA EROT from reset
Marc Olberding1e17db52025-08-27 12:25:28 -0700110 gpio::set("EROT_FPGA_RST_L-O", 1);
111 gpio::set("SEC_EROT_FPGA_RST_L-O", 1);
Ed Tanous2b314e42025-08-19 15:46:18 -0700112
113 sleep_milliseconds(100ms);
114
Marc Olberding1e17db52025-08-27 12:25:28 -0700115 gpio::set("FPGA_RST_L-O", 1);
Ed Tanous2b314e42025-08-19 15:46:18 -0700116
Marc Olberding1e17db52025-08-27 12:25:28 -0700117 if (fpga_ready_wait.wait() != gpio::EventResult::Asserted)
Ed Tanous2b314e42025-08-19 15:46:18 -0700118 {
119 std::cerr << "FPGA_READY_BMC-I failed to assert\n";
120 // return EXIT_FAILURE;
121 }
122
Marc Olberding1e17db52025-08-27 12:25:28 -0700123 if (sec_erot_fpga_rst.wait() != gpio::EventResult::Asserted)
Ed Tanous2b314e42025-08-19 15:46:18 -0700124 {
125 std::cerr << "SEC_FPGA_READY_BMC-I failed to assert\n";
126 // return EXIT_FAILURE;
127 }
128
129 // ReInitialize the FPGA connected I2C buses to unstick them and let
130 // FruDevice know it can scan for FRUs I2c bus 1
Marc Olberding1e17db52025-08-27 12:25:28 -0700131 i2c::rebind_controller("1e78a100");
Ed Tanous2b314e42025-08-19 15:46:18 -0700132 // I2c bus 2
Marc Olberding1e17db52025-08-27 12:25:28 -0700133 i2c::rebind_controller("1e78a180");
Ed Tanous2b314e42025-08-19 15:46:18 -0700134
135 // Set sgpio signals
Marc Olberding1e17db52025-08-27 12:25:28 -0700136 gpio::set("RUN_POWER_EN-O", 1);
137 gpio::set("SYS_RST_IN_L-O", 1);
138 gpio::set("GLOBAL_WP_BMC-O", 0);
Ed Tanous2b314e42025-08-19 15:46:18 -0700139
Marc Olberding1e17db52025-08-27 12:25:28 -0700140 gpio::set("BMC_READY-O", 1);
Ed Tanous2b314e42025-08-19 15:46:18 -0700141
142 if (has_p2020)
143 {
144 init_p2020_gpu_card();
145 }
146
Marc Olberding1e17db52025-08-27 12:25:28 -0700147 gpio::set("USB_HUB_RESET_L-O", 1);
Ed Tanous2b314e42025-08-19 15:46:18 -0700148 if (!hmc_present)
149 {
Marc Olberding1e17db52025-08-27 12:25:28 -0700150 gpio::set("SEC_USB2_HUB_RST_L-O", 1);
Ed Tanous2b314e42025-08-19 15:46:18 -0700151 }
152
153 sd_notify(0, "READY=1");
154 std::cerr << "Platform init complete\n";
155 pause();
156 std::cerr << "Releasing platform\n";
157
158 return EXIT_SUCCESS;
159}
160
161int init_nvidia_gb200_base()
162{
163 return init_nvidia_gb200(false);
164}
165
166int init_nvidia_gb200_with_p2020()
167{
168 return init_nvidia_gb200(true);
169}
170
171constexpr std::array<std::pair<std::string_view, int (*)()>, 2> init_functions{
172 {{"nvidia-gb200", init_nvidia_gb200_base},
173 {"nvidia-gb200-with-p2020", init_nvidia_gb200_with_p2020}}};
174
175int main(int argc, char** argv)
176{
177 CLI::App app("Platform init CLI");
178
179 app.require_subcommand();
180
181 CLI::App* init_sub =
182 app.add_subcommand("init", "Initialize the platform and daemonize");
183 std::string platform_name;
184 init_sub
185 ->add_option("platform_name", platform_name,
186 "Name of the platform to init")
187 ->required();
188 app.require_subcommand();
189
190 CLI11_PARSE(app, argc, argv)
191
192 const auto* it = std::ranges::find_if(
193 init_functions,
194 [&platform_name](const std::pair<std::string_view, int (*)()> val) {
195 return val.first == platform_name;
196 });
197 if (it == init_functions.end())
198 {
199 std::cerr << init_sub->help() << "\n";
200 return EXIT_FAILURE;
201 }
202
203 return it->second();
204}