Add support for OEM Power Modes

- Allow mode to be set via PassThrough interface
- Allow non-customer OEM power modes to be persisted
- Persist any OEM power mode settings
- moved mode related code from Status to PowerMode object
- merged PowerIPS into PowerMode object

Tested on Everest and Rainier.
Setting mode through PassThrough/ce-login:
  busctl call org.open_power.OCC.Control /org/open_power/control/occ0 org.open_power.OCC.PassThrough SetMode yq 11 3600
Trace (via PassThrough interface)
  openpower-occ-control[4440]: PassThrough::setMode() Setting Power Mode 11 (data: 3600)
  openpower-occ-control[4440]: PowerMode::sendModeChange: SET_MODE(11,3600) command to OCC0 (9 bytes)
Trace (setting mode via GUI/Redfish):
  openpower-occ-control[4440]: Power Mode Change Requested: xyz.openbmc_project.Control.Power.Mode.PowerMode.MaximumPerformance
  openpower-occ-control[4440]: PowerMode::sendModeChange: SET_MODE(12,0) command to OCC0 (9 bytes)
Verified when system in any OEM mode that Redfish also reports OEM
Verified all modes are persisted across PM Complex resets and reboots

Change-Id: Idd0be05cb6fd74dbd0776145f212c49addd1c365
Signed-off-by: Chris Cain <cjcain@us.ibm.com>
diff --git a/occ_pass_through.cpp b/occ_pass_through.cpp
index db133b1..6cf6374 100644
--- a/occ_pass_through.cpp
+++ b/occ_pass_through.cpp
@@ -22,8 +22,21 @@
 namespace occ
 {
 
-PassThrough::PassThrough(const char* path) :
-    Iface(utils::getBus(), path), path(path),
+using namespace phosphor::logging;
+using namespace sdbusplus::org::open_power::OCC::Device::Error;
+
+PassThrough::PassThrough(
+    const char* path
+#ifdef POWER10
+    ,
+    std::unique_ptr<open_power::occ::powermode::PowerMode>& powerModeRef
+#endif
+    ) :
+    Iface(utils::getBus(), path),
+    path(path),
+#ifdef POWER10
+    pmode(powerModeRef),
+#endif
     devicePath(OCC_DEV_PATH + std::to_string((this->path.back() - '0') + 1)),
     occInstance(this->path.back() - '0'),
     activeStatusSignal(
@@ -60,9 +73,6 @@
 
 std::vector<uint8_t> PassThrough::send(std::vector<uint8_t> command)
 {
-    using namespace phosphor::logging;
-    using namespace sdbusplus::org::open_power::OCC::Device::Error;
-
     std::vector<uint8_t> response{};
 
     log<level::DEBUG>(
@@ -100,6 +110,48 @@
     return response;
 }
 
+bool PassThrough::setMode(const uint8_t mode, const uint16_t modeData)
+{
+#ifdef POWER10
+    SysPwrMode newMode = SysPwrMode(mode);
+
+    if ((!VALID_POWER_MODE_SETTING(newMode)) &&
+        (!VALID_OEM_POWER_MODE_SETTING(newMode)))
+    {
+        log<level::ERR>(
+            fmt::format(
+                "PassThrough::setMode() Unsupported mode {} requested (0x{:04X})",
+                newMode, modeData)
+                .c_str());
+        return false;
+    }
+
+    if (((newMode == SysPwrMode::FFO) || (newMode == SysPwrMode::SFP)) &&
+        (modeData == 0))
+    {
+        log<level::ERR>(
+            fmt::format(
+                "PassThrough::setMode() Mode {} requires non-zero frequency point.",
+                newMode)
+                .c_str());
+        return false;
+    }
+
+    log<level::INFO>(
+        fmt::format("PassThrough::setMode() Setting Power Mode {} (data: {})",
+                    newMode, modeData)
+            .c_str());
+    return pmode->setMode(newMode, modeData);
+#else
+    log<level::DEBUG>(
+        fmt::format(
+            "PassThrough::setMode() No support to setting Power Mode {} (data: {})",
+            mode, modeData)
+            .c_str());
+    return false;
+#endif
+}
+
 // Called at OCC Status change signal
 void PassThrough::activeStatusEvent(sdbusplus::message::message& msg)
 {