pwrctl: Add latch output to power control

On the Zaius machine, the BMC signals that power up the CPU are gated by
a latch to protect against GPIO blips during BMC reset/power loss.

This adds an optional power GPIO configuration that controls the latch's
enable pin. Its behavior is to assert high when the op-pwrctl runs,
allowing power_up lines to propagate past their latches.

Signed-off-by: Xo Wang <xow@google.com>
Change-Id: Ibf0d1db771033cb9bba82575cca1bd21cfb3ad3d
diff --git a/libopenbmc_intf/power_gpio.c b/libopenbmc_intf/power_gpio.c
index 3f4b5a8..543281f 100644
--- a/libopenbmc_intf/power_gpio.c
+++ b/libopenbmc_intf/power_gpio.c
@@ -28,6 +28,7 @@
 	GError *error;
 	GVariant *value;
 	gchar *power_good_in_name;
+	gchar *latch_out_name;
 	GVariantIter *power_up_outs_iter;
 	GVariantIter *reset_outs_iter;
 	gchar *power_up_out_name;
@@ -66,9 +67,13 @@
 
 	g_assert(value != NULL);
 	memset(power_gpio, 0, sizeof(*power_gpio));
-	g_variant_get(value, "(&sa(sb)a(sb))", &power_good_in_name,
-            &power_up_outs_iter, &reset_outs_iter);
+	g_variant_get(value, "(&s&sa(sb)a(sb))", &power_good_in_name, &latch_out_name,
+			&power_up_outs_iter, &reset_outs_iter);
 
+	g_print("Power GPIO latch output %s\n", latch_out_name);
+	if(*latch_out_name != '\0') {  /* latch is optional */
+		power_gpio->latch_out.name = strdup(latch_out_name);
+	}
 	g_print("Power GPIO power good input %s\n", power_good_in_name);
 	power_gpio->power_good_in.name = g_strdup(power_good_in_name);
 	power_gpio->num_power_up_outs = g_variant_iter_n_children(
@@ -109,6 +114,7 @@
 
 void free_power_gpio(PowerGpio *power_gpio) {
 	int i;
+	g_free(power_gpio->latch_out.name);
 	g_free(power_gpio->power_good_in.name);
 	for(i = 0; i < power_gpio->num_power_up_outs; i++) {
 		g_free(power_gpio->power_up_outs[i].name);
diff --git a/libopenbmc_intf/power_gpio.h b/libopenbmc_intf/power_gpio.h
index f36a722..77e1c9c 100644
--- a/libopenbmc_intf/power_gpio.h
+++ b/libopenbmc_intf/power_gpio.h
@@ -23,6 +23,8 @@
 #include "gpio.h"
 
 typedef struct PowerGpio {
+	/* Optional active high pin enabling writes to latched power_up pins. */
+	GPIO latch_out; /* NULL name if not used. */
 	/* Active high pin that is asserted following successful host power up. */
 	GPIO power_good_in;
 	/* Selectable polarity pins enabling host power rails. */
diff --git a/op-pwrctl/power_control_obj.c b/op-pwrctl/power_control_obj.c
index cd13c68..679493c 100644
--- a/op-pwrctl/power_control_obj.c
+++ b/op-pwrctl/power_control_obj.c
@@ -208,6 +208,12 @@
 	uint8_t pgood_state;
 
 	// get gpio device paths
+	if(power_gpio->latch_out.name != NULL) {  /* latch is optional */
+		rc = gpio_init(connection, &power_gpio->latch_out);
+		if(rc != GPIO_OK) {
+			error = rc;
+		}
+	}
 	rc = gpio_init(connection, &power_gpio->power_good_in);
 	if(rc != GPIO_OK) {
 		error = rc;
@@ -225,6 +231,26 @@
 		}
 	}
 
+	/* If there's a latch, it only needs to be set once. */
+	if(power_gpio->latch_out.name != NULL) {
+		do {
+			rc = gpio_open(&power_gpio->latch_out);
+			if(rc != GPIO_OK) {
+				/* Failures are non-fatal. */
+				break;
+			}
+			rc = gpio_write(&power_gpio->latch_out, 1);
+			gpio_close(&power_gpio->latch_out);
+		} while(0);
+		if (rc != GPIO_OK) {
+			error = rc;
+			g_print("PowerControl ERROR failed to assert latch %s rc=%d\n",
+					power_gpio->latch_out.name, rc);
+		} else {
+			g_print("PowerControl asserted latch %s\n", power_gpio->latch_out.name);
+		}
+	}
+
 	rc = gpio_open(&power_gpio->power_good_in);
 	if(rc != GPIO_OK) {
 		return rc;
diff --git a/pysystemmgr/system_manager.py b/pysystemmgr/system_manager.py
index 5ecc14f..6f4bf81 100644
--- a/pysystemmgr/system_manager.py
+++ b/pysystemmgr/system_manager.py
@@ -180,12 +180,13 @@
         return r
 
     @dbus.service.method(DBUS_NAME, in_signature='',
-            out_signature='sa(sb)a(sb)')
+            out_signature='ssa(sb)a(sb)')
     def getPowerConfiguration(self):
         power_good_in = System.POWER_CONFIG.get('power_good_in', '')
+        latch_out = System.POWER_CONFIG.get('latch_out', '')
         power_up_outs = System.POWER_CONFIG.get('power_up_outs', [])
         reset_outs = System.POWER_CONFIG.get('reset_outs', [])
-        r = [power_good_in, power_up_outs, reset_outs]
+        r = [power_good_in, latch_out, power_up_outs, reset_outs]
         print "Power GPIO config: " + str(r)
         return r