summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/include/gpio.h36
-rw-r--r--src/lib/gpio.c49
2 files changed, 82 insertions, 3 deletions
diff --git a/src/include/gpio.h b/src/include/gpio.h
index ea03a23231..4627e4412c 100644
--- a/src/include/gpio.h
+++ b/src/include/gpio.h
@@ -29,6 +29,7 @@ void gpio_input_pulldown(gpio_t gpio);
void gpio_input_pullup(gpio_t gpio);
void gpio_input(gpio_t gpio);
void gpio_output(gpio_t gpio, int value);
+int _gpio_base3_value(gpio_t gpio[], int num_gpio, int binary_first);
/*
* Read the value presented by the set of GPIOs, when each pin is interpreted
@@ -48,6 +49,39 @@ int gpio_base2_value(gpio_t gpio[], int num_gpio);
* gpio[]: pin positions to read. gpio[0] is less significant than gpio[1].
* num_gpio: number of pins to read.
*/
-int gpio_base3_value(gpio_t gpio[], int num_gpio);
+static inline int gpio_base3_value(gpio_t gpio[], int num_gpio)
+{
+ return _gpio_base3_value(gpio, num_gpio, 0);
+}
+
+/*
+ * Read the value presented by the set of GPIOs, when each pin is interpreted
+ * as a base-3 digit (LOW = 0, HIGH = 1, Z/floating = 2) in a non-standard
+ * ternary number system where the first 2^n natural numbers are represented
+ * as they would be in a binary system (without any Z digits), and the following
+ * 3^n-2^n numbers use the remaining ternary representations in the normal
+ * ternary system order (skipping the values that were already used up).
+ * This is useful for boards which initially used a binary board ID and later
+ * decided to switch to tri-state after some revisions have already been built.
+ * Example: For num_gpio = 2 we get the following representation:
+ *
+ * Number X1 X0
+ * 0 0 0
+ * 1 0 1
+ * 2 1 0
+ * 3 1 1 // Start counting ternaries back at 0 after this
+ * 4 0 2 // Skipping 00 and 01 which are already used up
+ * 5 1 2 // Skipping 10 and 11 which are already used up
+ * 6 2 0
+ * 7 2 1
+ * 8 2 2
+ *
+ * gpio[]: pin positions to read. gpio[0] is less significant than gpio[1].
+ * num_gpio: number of pins to read.
+ */
+static inline int gpio_binary_first_base3_value(gpio_t gpio[], int num_gpio)
+{
+ return _gpio_base3_value(gpio, num_gpio, 1);
+}
#endif /* __SRC_INCLUDE_GPIO_H__ */
diff --git a/src/lib/gpio.c b/src/lib/gpio.c
index 5147cfebac..2e345956f8 100644
--- a/src/lib/gpio.c
+++ b/src/lib/gpio.c
@@ -35,7 +35,7 @@ int gpio_base2_value(gpio_t gpio[], int num_gpio)
return result;
}
-int gpio_base3_value(gpio_t gpio[], int num_gpio)
+int _gpio_base3_value(gpio_t gpio[], int num_gpio, int binary_first)
{
/*
* GPIOs which are tied to stronger external pull up or pull down
@@ -50,6 +50,8 @@ int gpio_base3_value(gpio_t gpio[], int num_gpio)
int temp;
int index;
int result = 0;
+ int has_z = 0;
+ int binary_below = 0;
char value[32];
assert(num_gpio <= 32);
@@ -85,8 +87,51 @@ int gpio_base3_value(gpio_t gpio[], int num_gpio)
temp |= ((value[index] ^ temp) << 1);
printk(BIOS_DEBUG, "%c ", tristate_char[temp]);
result = (result * 3) + temp;
+
+ /*
+ * For binary_first we keep track of the normal ternary result
+ * and whether we found any pin that was a Z. We also determine
+ * the amount of numbers that can be represented with only
+ * binary digits (no Z) whose value in the normal ternary system
+ * is lower than the one we are parsing. Counting from the left,
+ * we add 2^i for any '1' digit to account for the binary
+ * numbers whose values would be below it if all following
+ * digits we parsed would be '0'. As soon as we find a '2' digit
+ * we can total the remaining binary numbers below as 2^(i+1)
+ * because we know that all binary representations counting only
+ * this and following digits must have values below our number
+ * (since 1xxx is always smaller than 2xxx).
+ *
+ * Example: 1 0 2 1 (counting from the left / most significant)
+ * '1' at 3^3: Add 2^3 = 8 to account for binaries 0000-0111
+ * '0' at 3^2: Ignore (not all binaries 1000-1100 are below us)
+ * '2' at 3^1: Add 2^(1+1) = 4 to account for binaries 1000-1011
+ * Stop adding for lower digits (3^0), all already accounted
+ * now. We know that there can be no binary numbers 1020-102X.
+ */
+ if (binary_first && !has_z) {
+ switch(temp) {
+ case 0: /* Ignore '0' digits. */
+ break;
+ case 1: /* Account for binaries 0 to 2^index - 1. */
+ binary_below += 1 << index;
+ break;
+ case 2: /* Account for binaries 0 to 2^(index+1) - 1. */
+ binary_below += 1 << (index + 1);
+ has_z = 1;
+ }
+ }
+ }
+
+ if (binary_first) {
+ if (has_z)
+ result = result + (1 << num_gpio) - binary_below;
+ else /* binary_below is normal binary system value if !has_z. */
+ result = binary_below;
}
- printk(BIOS_DEBUG, "= %d\n", result);
+
+ printk(BIOS_DEBUG, "= %d (%s base3 number system)\n", result,
+ binary_first ? "binary_first" : "standard");
/* Disable pull up / pull down to conserve power */
for (index = 0; index < num_gpio; ++index)