gen_devtree: Add fsi-master node support

Generate the device tree node that defines the
GPIOs used by OpenFSI.

Change-Id: Ie47f9961b884c575293b823e3631fa3bce647398
Signed-off-by: Matt Spinler <spinler@us.ibm.com>
diff --git a/gen_devtree.pl b/gen_devtree.pl
index 5614c4c..9ba335d 100755
--- a/gen_devtree.pl
+++ b/gen_devtree.pl
@@ -74,6 +74,8 @@
 
 printNode($f, 1, "leds", getLEDNode());
 
+printNode($f, 1, "fsi-master", getFSINode());
+
 printIncludes($f, ROOT_INCLUDES);
 
 printRootNodeEnd($f, 0);
@@ -682,6 +684,112 @@
 }
 
 
+#Returns a hash that represents the OpenFSI device tree node.
+#This node defines the GPIOs used by FSI.
+#Node will look like:
+#  fsi-master {
+#    status = "okay";
+#    compatible = "ibm,fsi-master-gpio", "ibm,fsi-master";
+#    clock-gpios = <&gpio ASPEED_GPIO(AA, 0) GPIO_ACTIVE_HIGH>;
+#    data-gpios = <&gpio ASPEED_GPIO(E, 0) GPIO_ACTIVE_HIGH>;
+#    enable-gpios = <&gpio ASPEED_GPIO(D, 0) GPIO_ACTIVE_HIGH>;
+#    mux-gpios = <&gpio ASPEED_GPIO(A, 6) GPIO_ACTIVE_HIGH>;
+#    trans-gpios = <&gpio ASPEED_GPIO(R, 2) GPIO_ACTIVE_HIGH>;
+#  };
+sub getFSINode
+{
+    my %node;
+    my $enabled = 0;
+
+    #For now only supports ASPEED because of the GPIO syntax.
+    if (uc($g_bmcMfgr) ne "ASPEED") {
+        die "ERROR:  Unsupported BMC manufacturer $g_bmcMfgr in getFSINode\n";
+    }
+
+    #Check that OpenFSI is enabled in the config file.
+    if (exists $g_configuration{"enable-openfsi"}) {
+        if ($g_configuration{"enable-openfsi"} eq "true") {
+            $enabled = 1;
+        }
+        elsif (($g_configuration{"enable-openfsi"} ne "true") &&
+               ($g_configuration{"enable-openfsi"} ne "false")) {
+            die "Invalid enable-openfsi config file value: " .
+                $g_configuration{"enable-openfsi"} . "\n";
+        }
+    }
+
+    return %node unless ($enabled == 1);
+
+    #In the MRW there is an fsi_bit_bang logical part that connects to the
+    #BMC's 5 FSI related GPIOs.  This part then has an FSI master unit that
+    #would connect to the P9's FSI slave (though we don't check that).
+
+    #Find the specific GPIOs by the fsi_bit_bang slave
+    #unit that they're connected to.  Some are optional.
+    my %fsiGpios = ("fsi_bit_bang.fsi_clk" =>
+                    {
+                        name => "clock-gpios",
+                        gpio => undef,
+                        required => 1
+                    },
+                    "fsi_bit_bang.fsi_dat" =>
+                    {
+                        name => "data-gpios",
+                        gpio => undef,
+                        required => 1
+                    },
+                    "fsi_bit_bang.fsi_mux" =>
+                    {
+                        name => "mux-gpios",
+                        gpio => undef
+                    },
+                    "fsi_bit_bang.fsi_enable" =>
+                    {
+                        name => "enable-gpios",
+                        gpio => undef
+                    },
+                    "fsi_bit_bang.fsi_trans" =>
+                    {
+                        name => "trans-gpios",
+                        gpio => undef
+                    }
+                   );
+
+    my $connections = $g_targetObj->findConnections($g_bmc, "GPIO");
+    if ($connections eq "") {
+        die "No GPIO connections found in getFSINode\n";
+    }
+
+    for my $gpio (@{$connections->{CONN}}) {
+
+        #Check if the destination's slave unit is in our list.
+        my $slaveUnit = $g_targetObj->getInstanceName($gpio->{DEST});
+
+        if (exists $fsiGpios{$slaveUnit}) {
+            my $num = $g_targetObj->getAttribute($gpio->{SOURCE}, "PIN_NUM");
+            $fsiGpios{$slaveUnit}{gpio} = getAspeedGpioMacro($num);
+        }
+    }
+
+    statusOK(\%node);
+
+    push @{$node{compatible}}, "ibm,fsi-master", "ibm,fsi-master-gpio";
+
+    while (my ($key, $hash) = each(%fsiGpios)) {
+        if (not defined $hash->{gpio}) {
+            if (exists $hash->{required}) {
+                die "Missing connection for FSI GPIO $key\n";
+            }
+        }
+        else {
+            $node{$hash->{name}} = "<&gpio $hash->{gpio} GPIO_ACTIVE_HIGH>";
+        }
+    }
+
+    return %node;
+}
+
+
 #Returns a list of hashes that represent the UART nodes on the BMC by
 #finding the UART connections.
 #Nodes will look like:
@@ -1100,7 +1208,7 @@
 #     If the value is:
 #     - a hash - then that hash gets turned into a child node
 #       where the key is the name of the child node
-#     - an array of hashes indicates an array of child nodes
+#     - an array - will print a property list, like: "a", "b"
 sub printNode
 {
     my ($f, $level, $name, %vals) = @_;
@@ -1142,9 +1250,11 @@
         next if ($v eq "DTSI_INCLUDE");
         next if ($v eq "NODE_LABEL");
         next if (ref($vals{$v}) eq "HASH");
-        next if (ref($vals{$v}) eq "ARRAY");
 
-        if ($vals{$v} ne ZERO_LENGTH_PROPERTY) {
+        if (ref($vals{$v}) eq "ARRAY") {
+            printPropertyList($f, $level+1, $v, @{$vals{$v}});
+        }
+        elsif ($vals{$v} ne ZERO_LENGTH_PROPERTY) {
             printProperty($f, $level+1, $v, $vals{$v});
         }
         else {
@@ -1170,11 +1280,6 @@
         if (ref($vals{$v}) eq "HASH") {
             printNode($f, $level+1, $v, %{$vals{$v}});
         }
-        #An array of nested nodes
-        elsif (ref($vals{$v}) eq "ARRAY") {
-            my @array = @{$vals{$v}};
-            &printNodes($f, $level+1, @array);
-        }
     }
 
     print $f indent($level) . "};\n";