P9 CFAM register override procedure

This new procedure will allow users to
provide P9 CFAM register overrides
before the P9 SBE is started.

Change-Id: If3658f9a6ede9a3682c4ed7888e9acb328c67709
Signed-off-by: Michael Tritz <mtritz@us.ibm.com>
diff --git a/procedures/p9/cfam_overrides.cpp b/procedures/p9/cfam_overrides.cpp
new file mode 100644
index 0000000..90891b9
--- /dev/null
+++ b/procedures/p9/cfam_overrides.cpp
@@ -0,0 +1,69 @@
+#include <fstream>
+#include <sstream>
+#include <iostream>
+#include "cfam_access.hpp"
+#include "p9_cfam.hpp"
+#include "registration.hpp"
+#include "targeting.hpp"
+
+/* File /var/lib/obmc/cfam_overrides requires whitespace-separated parameters
+Pos Address Data Mask with one register write per line. For example:
+0 0x283F 0x12345678 0xF0F0F0F0
+0 0x283F 0x87654321 0x0F0F0F0F
+Blank lines and comment lines beginning with # will be ignored. */
+
+namespace openpower
+{
+namespace p9
+{
+
+using namespace openpower::cfam::access;
+using namespace openpower::targeting;
+using namespace openpower::util;
+
+void CFAMOverride() {
+    int pos = 0;
+    cfam_address_t address = 0;
+    cfam_data_t data = 0;
+    cfam_mask_t mask = 0;
+
+    Targeting targets;
+
+    std::string line;
+
+    std::ifstream overrides("/var/lib/obmc/cfam_overrides");
+
+    if (overrides.is_open())
+    {
+        while (std::getline(overrides,line))
+        {
+            if (!line.empty())
+            {
+                line.erase(0, line.find_first_not_of(" \t\r\n"));
+                if (!line.empty() && line.at(0) != '#')
+                {
+                    mask = 0xFFFFFFFF;
+                    if (sscanf(line.c_str(), "%x %hx %x %x", &pos, &address,
+                        &data, &mask) >= 3)
+                    {
+                        const auto& target = targets.getTarget(pos);
+                        writeRegWithMask(target, address, data, mask);
+                    }
+                    else
+                    {
+                        throw std::runtime_error("Cannot write to register - "
+                                "not enough parameters given.");
+                    }
+                }
+            }
+        }
+        overrides.close();
+    }
+
+    return;
+}
+
+REGISTER_PROCEDURE("CFAMOverride", CFAMOverride);
+
+}
+}
diff --git a/procedures/p9/start_host.cpp b/procedures/p9/start_host.cpp
index a31503b..6494086 100644
--- a/procedures/p9/start_host.cpp
+++ b/procedures/p9/start_host.cpp
@@ -66,7 +66,7 @@
     //Kick off the SBE to start the boot
 
     //First ensure ISTEP stepping isn't enabled
-    writeReg(master, P9_SCRATCH_REGISTER_8, 0x20000000);
+    writeRegWithMask(master, P9_SCRATCH_REGISTER_8, 0x20000000, 0x20000000);
 
     //Start the SBE
     writeRegWithMask(master, P9_CBS_CS, 0x80000000, 0x80000000);
@@ -76,4 +76,3 @@
 
 }
 }
-
diff --git a/targeting.cpp b/targeting.cpp
index 635c8bb..c5118c1 100644
--- a/targeting.cpp
+++ b/targeting.cpp
@@ -37,6 +37,24 @@
     return cfamFD->get();
 }
 
+std::unique_ptr<Target>& Targeting::getTarget(size_t pos)
+{
+    auto search = [pos](const auto& t)
+    {
+        return t->getPos() == pos;
+    };
+
+    auto target = find_if(targets.begin(), targets.end(), search);
+    if (target == targets.end())
+    {
+        throw std::runtime_error("Target not found: " + std::to_string(pos));
+    }
+    else
+    {
+        return *target;
+    }
+}
+
 
 Targeting::Targeting(const std::string& fsiMasterDev,
                      const std::string& fsiSlaveDir) :
diff --git a/targeting.hpp b/targeting.hpp
index 9719a65..8ab8eda 100644
--- a/targeting.hpp
+++ b/targeting.hpp
@@ -127,6 +127,11 @@
             return targets.size();
         }
 
+        /**
+         * Returns a target by position.
+         */
+        std::unique_ptr<Target>& getTarget(size_t pos);
+
     private:
 
         /**