1 #include <unistd.h>
2 
3 #include <gpiod.hpp>
4 #include <phosphor-logging/log.hpp>
5 #include <registration.hpp>
6 
7 #include <chrono>
8 #include <fstream>
9 #include <system_error>
10 #include <thread>
11 
12 namespace openpower
13 {
14 namespace misc
15 {
16 
17 constexpr auto cfamResetPath = "/sys/class/fsi-master/fsi0/device/cfam_reset";
18 
19 using namespace phosphor::logging;
20 
21 /**
22  * @brief Reset the CFAM using the appropriate GPIO
23  * @return void
24  */
25 void cfamReset()
26 {
27     // First look if system supports kernel sysfs based cfam reset
28     // If it does then write a 1 and let the kernel handle the reset
29     std::ofstream file;
30     file.open(cfamResetPath);
31     if (!file)
32     {
33         log<level::DEBUG>("system does not support kernel cfam reset, default "
34                           "to using libgpiod");
35     }
36     else
37     {
38         // Write a 1 to have kernel toggle the reset
39         file << "1";
40         file.close();
41         log<level::DEBUG>("cfam reset via sysfs complete");
42         return;
43     }
44 
45     // No kernel support so toggle gpio from userspace
46     const std::string cfamReset = {"cfam-reset"};
47     auto line = gpiod::find_line(cfamReset);
48     if (!line)
49     {
50         log<level::ERR>("failed to find cfam-reset line");
51         throw std::system_error(ENODEV, std::system_category());
52     }
53 
54     // Configure this app to own the gpio while doing the reset
55     gpiod::line_request conf;
56     conf.consumer = "cfamReset";
57     conf.request_type = gpiod::line_request::DIRECTION_OUTPUT;
58     line.request(conf);
59 
60     // Put chips into reset
61     line.set_value(0);
62 
63     // Sleep one second to ensure reset processed
64     using namespace std::chrono_literals;
65     std::this_thread::sleep_for(1s);
66 
67     // Take chips out of reset
68     line.set_value(1);
69 }
70 
71 REGISTER_PROCEDURE("cfamReset", cfamReset)
72 
73 } // namespace misc
74 } // namespace openpower
75