crossystem: handle BayTrail gpios

BayTrail systems have 3 banks of gpios. Therefore,
the Linux kernel exposes these 3 banks as 3 gpiochip
entries. The kernel driver expects the 3 banks to be
exposed with specific UIDs associated with a specific
banks. ChromeOS firmware maps gpios within a given
bank using the bank's MMIO offset. In summary:

Bank Type | UID | Offset
----------+-----+-------
 SCORE    |  1  | 0x0000
 NCORE    |  2  | 0x1000
 SUS      |  3  | 0x2000

BUG=chrome-os-partner:24408
BUG=chrome-os-partner:24324
BRANCH=None
TEST=Built. 'crossystem wpsw_cur' works correctly.

Change-Id: I251f86285ce9733f7ca90ed1ebef536f4fe5c07c
Signed-off-by: Aaron Durbin <adurbin@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/179513
Reviewed-by: Duncan Laurie <dlaurie@chromium.org>
diff --git a/host/arch/x86/lib/crossystem_arch.c b/host/arch/x86/lib/crossystem_arch.c
index 922dc64..4f2b611 100644
--- a/host/arch/x86/lib/crossystem_arch.c
+++ b/host/arch/x86/lib/crossystem_arch.c
@@ -519,6 +519,59 @@
   return (1 == match);
 }
 
+/* BayTrail has 3 sets of GPIO banks. It is expected the firmware exposes
+ * each bank of gpios using a UID in ACPI. Furthermore the gpio number exposed
+ * is relative to the bank. e.g. gpio 6 in the bank specified by UID 3 would
+ * be encoded as 0x2006.
+ *  UID | Bank Offset
+ *  ----+------------
+ *   1  | 0x0000
+ *   2  | 0x1000
+ *   3  | 0x2000
+ */
+static int BayTrailFindGpioChipOffset(int *gpio_num, int *offset) {
+  DIR *dir;
+  struct dirent *ent;
+  int expected_uid;
+  int match = 0;
+
+  /* Obtain relative GPIO number. */
+  if (*gpio_num >= 0x2000) {
+    *gpio_num -= 0x2000;
+    expected_uid = 3;
+  } else if (*gpio_num >= 0x1000) {
+    *gpio_num -= 0x1000;
+    expected_uid = 2;
+  } else if (*gpio_num >= 0x0000) {
+    *gpio_num -= 0x0000;
+    expected_uid = 1;
+  } else {
+    return 0;
+  }
+
+  dir = opendir(GPIO_BASE_PATH);
+  if (!dir) {
+    return 0;
+  }
+
+  while(0 != (ent = readdir(dir))) {
+    /* For every gpiochip entry determine uid. */
+    if (1 == sscanf(ent->d_name, "gpiochip%d", offset)) {
+      char uid_file[128];
+      snprintf(uid_file, sizeof(uid_file),
+               "%s/gpiochip%d/device/firmware_node/uid", GPIO_BASE_PATH,
+               *offset);
+      if (expected_uid == ReadFileInt(uid_file)) {
+        match++;
+        break;
+      }
+    }
+  }
+
+  closedir(dir);
+  return (1 == match);
+}
+
 
 struct GpioChipset {
   const char *name;
@@ -530,6 +583,7 @@
   { "CougarPoint", FindGpioChipOffset },
   { "PantherPoint", FindGpioChipOffset },
   { "LynxPoint", FindGpioChipOffset },
+  { "BayTrail", BayTrailFindGpioChipOffset },
   { NULL },
 };