From 1a9d1bd73aa2cd0c36203b247976ad0d00a360e4 Mon Sep 17 00:00:00 2001 From: Jimmy Zhang Date: Fri, 24 Jan 2014 18:04:36 -0800 Subject: [PATCH] tegra124: support tri-state Board Id Since Nyan Big board id pins may layout in tri-state, we need code to support this change. We use every two-bit to encode a gpio state as below: b00: LOW b01: HIGH b10: TRI-STATE BUG=none TEST=emerge-nyan chromeos-coreboot-nyan coreboot log shows "Board TRISTATE ID: 0x41" for gpios 1001 Change-Id: I05d63f0bdafd533ef9d9e0da668837ecd2f4c8c0 Signed-off-by: Jimmy Zhang Reviewed-on: https://chromium-review.googlesource.com/183855 Reviewed-by: Gabe Black Commit-Queue: Doug Anderson --- src/mainboard/google/nyan_big/boardid.c | 17 +++++--- src/soc/nvidia/tegra/gpio.c | 53 +++++++++++++++++++++++++ src/soc/nvidia/tegra/gpio.h | 1 + 3 files changed, 66 insertions(+), 5 deletions(-) diff --git a/src/mainboard/google/nyan_big/boardid.c b/src/mainboard/google/nyan_big/boardid.c index f43e532c0a..23b1c6adff 100644 --- a/src/mainboard/google/nyan_big/boardid.c +++ b/src/mainboard/google/nyan_big/boardid.c @@ -19,6 +19,7 @@ #include #include +#include #include "boardid.h" @@ -27,11 +28,17 @@ uint8_t board_id(void) static int id = -1; if (id < 0) { - id = gpio_get_in_value(GPIO(Q3)) << 0 | - gpio_get_in_value(GPIO(T1)) << 1 | - gpio_get_in_value(GPIO(X1)) << 2 | - gpio_get_in_value(GPIO(X4)) << 3; - printk(BIOS_SPEW, "Board ID: %#x.\n", id); + gpio_t gpio[] = {GPIO(Q3), GPIO(T1), GPIO(X1), GPIO(X4)}; + int value[ARRAY_SIZE(gpio)]; + + gpio_get_in_tristate_values(gpio, ARRAY_SIZE(gpio), value); + + /* A gpio state is encoded in every two-bit */ + id = value[0] << 0 | + value[1] << 2 | + value[2] << 4 | + value[3] << 6; + printk(BIOS_SPEW, "Board TRISTATE ID: %#x.\n", id); } return id; diff --git a/src/soc/nvidia/tegra/gpio.c b/src/soc/nvidia/tegra/gpio.c index 4cf6d5f43a..ac0fc3f986 100644 --- a/src/soc/nvidia/tegra/gpio.c +++ b/src/soc/nvidia/tegra/gpio.c @@ -22,6 +22,7 @@ #include #include #include +#include #include "gpio.h" #include "pinmux.h" @@ -174,6 +175,58 @@ int gpio_get_in_value(gpio_t gpio) return (port & (1 << bit)) != 0; } +int gpio_get_in_tristate_values(gpio_t gpio[], int num_gpio, int value[]) +{ + /* + * GPIOs which are tied to stronger external pull up or pull down + * will stay there regardless of the internal pull up or pull + * down setting. + * + * GPIOs which are floating will go to whatever level they're + * internally pulled to. + */ + + int temp; + int index; + + /* Enable internal pull up */ + for (index = 0; index < num_gpio; ++index) + gpio_input_pullup(gpio[index]); + + /* Wait until signals become stable */ + udelay(10); + + /* Get gpio values at internal pull up */ + for (index = 0; index < num_gpio; ++index) + value[index] = gpio_get_in_value(gpio[index]); + + /* Enable internal pull down */ + for (index = 0; index < num_gpio; ++index) + gpio_input_pulldown(gpio[index]); + + /* Wait until signals become stable */ + udelay(10); + + /* + * Get gpio values at internal pull down. + * Compare with gpio pull up value and then + * determine a gpio final value/state: + * 0: pull down + * 1: pull up + * 2: floating + */ + for (index = 0; index < num_gpio; ++index) { + temp = gpio_get_in_value(gpio[index]); + value[index] = ((value[index] ^ temp) << 1) | temp; + } + + /* Disable pull up / pull down to conserve power */ + for (index = 0; index < num_gpio; ++index) + gpio_input(gpio[index]); + + return 0; +} + int gpio_get_int_status(gpio_t gpio) { int bit = gpio % GPIO_GPIOS_PER_PORT; diff --git a/src/soc/nvidia/tegra/gpio.h b/src/soc/nvidia/tegra/gpio.h index 70c1026f44..5f6833af79 100644 --- a/src/soc/nvidia/tegra/gpio.h +++ b/src/soc/nvidia/tegra/gpio.h @@ -81,6 +81,7 @@ void gpio_set_out_value(gpio_t gpio, int value); int gpio_get_out_value(gpio_t gpio); int gpio_get_in_value(gpio_t gpio); +int gpio_get_in_tristate_values(gpio_t gpio[], int num_gpio, int value[]); int gpio_get_int_status(gpio_t gpio);