summaryrefslogtreecommitdiff
path: root/chip/lm4/gpio.c
diff options
context:
space:
mode:
authorRandall Spangler <rspangler@chromium.org>2012-01-12 15:54:35 -0800
committerRandall Spangler <rspangler@chromium.org>2012-01-12 15:54:35 -0800
commit70a9928add62f6fddb0e9dc8e135246446c66eee (patch)
treef85250b8bfb3d7992ce067bb80888245f2ac4ede /chip/lm4/gpio.c
parenta8afa116be94051b78de37e1b2c66a82f82ac4c4 (diff)
downloadchrome-ec-70a9928add62f6fddb0e9dc8e135246446c66eee.tar.gz
Configure all GPIOs
Signed-off-by: Randall Spangler <rspangler@chromium.org> BUG=chrome-os-partner:7528 TEST=none Change-Id: I0a9be4c689fb72507edcf202073b23c58902d7de
Diffstat (limited to 'chip/lm4/gpio.c')
-rw-r--r--chip/lm4/gpio.c230
1 files changed, 165 insertions, 65 deletions
diff --git a/chip/lm4/gpio.c b/chip/lm4/gpio.c
index d4b97b6db0..f2c1b38b34 100644
--- a/chip/lm4/gpio.c
+++ b/chip/lm4/gpio.c
@@ -24,22 +24,109 @@ const uint32_t gpio_bases[] = {
};
+/* Raw flags for GPIO_INFO */
+#define GI_OUTPUT 0x0001 /* Output */
+#define GI_PULL 0x0002 /* Input with on-chip pullup/pulldown */
+#define GI_HIGH 0x0004 /* If GI_OUTPUT, default high; if GI_PULL, pull
+ * up (otherwise default low / pull down) */
+#define GI_INT_RISING 0x0010 /* Interrupt on rising edge */
+#define GI_INT_FALLING 0x0020 /* Interrupt on falling edge */
+#define GI_INT_BOTH 0x0040 /* Interrupt on both edges */
+#define GI_INT_LOW 0x0080 /* Interrupt on low level */
+#define GI_INT_HIGH 0x0100 /* Interrupt on high level */
+/* Common flag combinations */
+#define GI_OUT_LOW GI_OUTPUT
+#define GI_OUT_HIGH (GI_OUTPUT | GI_HIGH)
+#define GI_PULL_DOWN GI_PULL
+#define GI_PULL_UP (GI_PULL | GI_HIGH)
+#define GI_INT_EDGE (GI_INT_RISING | GI_INT_FALLING | GI_INT_BOTH)
+#define GI_INT_LEVEL (GI_INT_LOW | GI_INT_HIGH)
+#define GI_INT_ANY (GI_INT_EDGE | GI_INT_LEVEL)
+/* Note that if no flags are present, the signal is a high-Z input */
+
struct gpio_info {
const char *name;
int port; /* Port (LM4_GPIO_*) */
int mask; /* Bitmask on that port (0x01 - 0x80; 0x00 =
signal not implemented) */
+ uint32_t flags; /* Flags (GI_*) */
void (*irq_handler)(enum gpio_signal signal);
};
/* Macro for signals which don't exist */
-#define SIGNAL_NOT_IMPLEMENTED(name) {name, LM4_GPIO_A, 0x00, NULL}
+#define SIGNAL_NOT_IMPLEMENTED(name) {name, LM4_GPIO_A, 0, 0, NULL}
/* Signal information. Must match order from enum gpio_signal. */
+#ifdef BOARD_link
+const struct gpio_info signal_info[GPIO_COUNT] = {
+ /* Inputs with interrupt handlers are first for efficiency */
+ {"POWER_BUTTONn", LM4_GPIO_K, (1<<7), GI_INT_BOTH,
+ power_button_interrupt},
+ {"LID_SWITCHn", LM4_GPIO_K, (1<<5), GI_INT_BOTH,
+ power_button_interrupt},
+ /* Other inputs */
+ {"POWER_ONEWIRE", LM4_GPIO_H, (1<<2), 0, NULL},
+ {"THERMAL_DATA_READYn", LM4_GPIO_B, (1<<4), 0, NULL},
+ {"AC_PRESENT", LM4_GPIO_H, (1<<3), 0, NULL},
+ {"PCH_BKLTEN", LM4_GPIO_J, (1<<3), 0, NULL},
+ {"PCH_SLP_An", LM4_GPIO_G, (1<<5), 0, NULL},
+ {"PCH_SLP_ME_CSW_DEVn", LM4_GPIO_G, (1<<4), 0, NULL},
+ {"PCH_SLP_S3n", LM4_GPIO_J, (1<<0), 0, NULL},
+ {"PCH_SLP_S4n", LM4_GPIO_J, (1<<1), 0, NULL},
+ {"PCH_SLP_S5n", LM4_GPIO_J, (1<<2), 0, NULL},
+ {"PCH_SLP_SUSn", LM4_GPIO_G, (1<<3), 0, NULL},
+ {"PCH_SUSWARNn", LM4_GPIO_G, (1<<2), 0, NULL},
+ {"PGOOD_1_5V_DDR", LM4_GPIO_K, (1<<0), 0, NULL},
+ {"PGOOD_1_5V_PCH", LM4_GPIO_K, (1<<1), 0, NULL},
+ {"PGOOD_1_8VS", LM4_GPIO_K, (1<<3), 0, NULL},
+ {"PGOOD_5VALW", LM4_GPIO_H, (1<<0), 0, NULL},
+ {"PGOOD_CPU_CORE", LM4_GPIO_M, (1<<3), 0, NULL},
+ {"PGOOD_VCCP", LM4_GPIO_K, (1<<2), 0, NULL},
+ {"PGOOD_VCCSA", LM4_GPIO_H, (1<<1), 0, NULL},
+ {"PGOOD_VGFX_CORE", LM4_GPIO_D, (1<<2), 0, NULL},
+ {"RECOVERYn", LM4_GPIO_H, (1<<7), 0, NULL},
+ {"USB1_STATUSn", LM4_GPIO_E, (1<<7), 0, NULL},
+ {"USB2_STATUSn", LM4_GPIO_E, (1<<1), 0, NULL},
+ {"WRITE_PROTECTn", LM4_GPIO_J, (1<<4), 0, NULL},
+ /* Outputs; all unasserted by default */
+ {"CPU_PROCHOTn", LM4_GPIO_F, (1<<2), GI_OUT_HIGH, NULL},
+ {"ENABLE_1_5V_DDR", LM4_GPIO_H, (1<<5), GI_OUT_LOW, NULL},
+ {"ENABLE_BACKLIGHT", LM4_GPIO_H, (1<<4), GI_OUT_LOW, NULL},
+ {"ENABLE_VCORE", LM4_GPIO_F, (1<<7), GI_OUT_LOW, NULL},
+ {"ENABLE_VS", LM4_GPIO_G, (1<<6), GI_OUT_LOW, NULL},
+ {"ENTERING_RW", LM4_GPIO_J, (1<<5), GI_OUT_LOW, NULL},
+ {"PCH_A20GATE", LM4_GPIO_Q, (1<<6), GI_OUT_LOW, NULL},
+ {"PCH_DPWROK", LM4_GPIO_G, (1<<0), GI_OUT_LOW, NULL},
+ {"PCH_HDA_SDO", LM4_GPIO_G, (1<<1), GI_OUT_LOW, NULL},
+ {"PCH_LID_SWITCHn", LM4_GPIO_F, (1<<0), GI_OUT_HIGH, NULL},
+ {"PCH_NMIn", LM4_GPIO_M, (1<<2), GI_OUT_HIGH, NULL},
+ {"PCH_PWRBTNn", LM4_GPIO_G, (1<<7), GI_OUT_HIGH, NULL},
+ {"PCH_PWROK", LM4_GPIO_F, (1<<5), GI_OUT_LOW, NULL},
+ {"PCH_RCINn", LM4_GPIO_Q, (1<<7), GI_OUT_HIGH, NULL},
+ /* Exception: RSMRST# is asserted at power-on */
+ {"PCH_RSMRSTn", LM4_GPIO_F, (1<<1), GI_OUT_LOW, NULL},
+ {"PCH_SMIn", LM4_GPIO_F, (1<<4), GI_OUT_HIGH, NULL},
+ {"PCH_SUSACKn", LM4_GPIO_F, (1<<3), GI_OUT_HIGH, NULL},
+ {"SHUNT_1_5V_DDR", LM4_GPIO_F, (1<<6), GI_OUT_HIGH, NULL},
+ {"USB1_CTL1", LM4_GPIO_E, (1<<2), GI_OUT_LOW, NULL},
+ {"USB1_CTL2", LM4_GPIO_E, (1<<3), GI_OUT_LOW, NULL},
+ {"USB1_CTL3", LM4_GPIO_E, (1<<4), GI_OUT_LOW, NULL},
+ {"USB1_ENABLE", LM4_GPIO_E, (1<<5), GI_OUT_LOW, NULL},
+ {"USB1_ILIM_SEL", LM4_GPIO_E, (1<<6), GI_OUT_LOW, NULL},
+ {"USB2_CTL1", LM4_GPIO_D, (1<<4), GI_OUT_LOW, NULL},
+ {"USB2_CTL2", LM4_GPIO_D, (1<<5), GI_OUT_LOW, NULL},
+ {"USB2_CTL3", LM4_GPIO_D, (1<<6), GI_OUT_LOW, NULL},
+ {"USB2_ENABLE", LM4_GPIO_D, (1<<7), GI_OUT_LOW, NULL},
+ {"USB2_ILIM_SEL", LM4_GPIO_E, (1<<0), GI_OUT_LOW, NULL},
+};
+
+#else
const struct gpio_info signal_info[GPIO_COUNT] = {
/* Inputs with interrupt handlers are first for efficiency */
- {"POWER_BUTTONn", LM4_GPIO_C, 0x20, power_button_interrupt},
- {"LID_SWITCHn", LM4_GPIO_D, 0x01, power_button_interrupt},
+ {"POWER_BUTTONn", LM4_GPIO_C, (1<<5), GI_PULL_UP | GI_INT_BOTH,
+ power_button_interrupt},
+ {"LID_SWITCHn", LM4_GPIO_D, (1<<0), GI_PULL_UP | GI_INT_BOTH,
+ power_button_interrupt},
SIGNAL_NOT_IMPLEMENTED("POWER_ONEWIRE"),
SIGNAL_NOT_IMPLEMENTED("THERMAL_DATA_READYn"),
/* Other inputs */
@@ -66,7 +153,7 @@ const struct gpio_info signal_info[GPIO_COUNT] = {
SIGNAL_NOT_IMPLEMENTED("WRITE_PROTECTn"),
/* Outputs */
SIGNAL_NOT_IMPLEMENTED("CPU_PROCHOTn"),
- {"DEBUG_LED", LM4_GPIO_A, 0x80, NULL},
+ {"DEBUG_LED", LM4_GPIO_A, (1<<7), GI_OUT_LOW, NULL},
SIGNAL_NOT_IMPLEMENTED("ENABLE_1_5V_DDR"),
SIGNAL_NOT_IMPLEMENTED("ENABLE_BACKLIGHT"),
SIGNAL_NOT_IMPLEMENTED("ENABLE_VCORE"),
@@ -96,6 +183,8 @@ const struct gpio_info signal_info[GPIO_COUNT] = {
SIGNAL_NOT_IMPLEMENTED("USB2_ILIM_SEL"),
};
+#endif
+
#undef SIGNAL_NOT_IMPLEMENTED
@@ -133,66 +222,59 @@ static int find_gpio_port_index(uint32_t port_base)
int gpio_pre_init(void)
{
- /* Enable clocks to the GPIO blocks we use. Bits are encoded this way;
- * blocks we use are in caps: .qpn mlkj hgfe DCbA */
- LM4_SYSTEM_RCGCGPIO |= 0x000d;
+ volatile uint32_t scratch __attribute__((unused));
+ const struct gpio_info *g = signal_info;
+ int i;
- /* Turn off the LED before we make it an output */
- gpio_set_level(GPIO_DEBUG_LED, 0);
+ /* Enable clocks to all the GPIO blocks (since we use all of them as
+ * GPIOs) */
+ LM4_SYSTEM_RCGCGPIO |= 0x7fff;
+ scratch = LM4_SYSTEM_RCGCGPIO; /* Delay a few clocks */
- /* Clear GPIOAFSEL bits for block A pin 7 */
- LM4_GPIO_AFSEL(LM4_GPIO_A) &= ~(0x80);
+ /* Disable GPIO commit control for PD7 and PF0, since we don't use the
+ * NMI pin function. */
+ LM4_GPIO_LOCK(LM4_GPIO_D) = LM4_GPIO_LOCK_UNLOCK;
+ LM4_GPIO_CR(LM4_GPIO_D) |= 0x80;
+ LM4_GPIO_LOCK(LM4_GPIO_D) = 0;
+ LM4_GPIO_LOCK(LM4_GPIO_F) = LM4_GPIO_LOCK_UNLOCK;
+ LM4_GPIO_CR(LM4_GPIO_F) |= 0x01;
+ LM4_GPIO_LOCK(LM4_GPIO_F) = 0;
- /* Set GPIO to digital enable, output */
- LM4_GPIO_DEN(LM4_GPIO_A) |= 0x80;
- LM4_GPIO_DIR(LM4_GPIO_A) |= 0x80;
+ /* Clear SSI0 alternate function on PA2:5 */
+ LM4_GPIO_AFSEL(LM4_GPIO_A) &= ~0x3c;
-#ifdef BOARD_link
- /* Set up LID switch input (block K pin 5) */
- LM4_GPIO_PCTL(LM4_GPIO_K) &= ~(0xf00000);
- LM4_GPIO_DIR(LM4_GPIO_K) &= ~(0x20);
- LM4_GPIO_PUR(LM4_GPIO_K) |= 0x20;
- LM4_GPIO_DEN(LM4_GPIO_K) |= 0x20;
- LM4_GPIO_IM(LM4_GPIO_K) |= 0x20;
- LM4_GPIO_IBE(LM4_GPIO_K) |= 0x20;
-
- /* Block F pin 0 is NMI pin, so we have to unlock GPIO Lock register and
- set the bit in GPIOCR register first. */
- LM4_GPIO_LOCK(LM4_GPIO_F) = 0x4c4f434b;
- LM4_GPIO_CR(LM4_GPIO_F) |= 0x1;
- LM4_GPIO_LOCK(LM4_GPIO_F) = 0x0;
-
- /* Set up LID switch output (block F pin 0) */
- LM4_GPIO_PCTL(LM4_GPIO_F) &= ~(0xf);
- LM4_GPIO_DATA(LM4_GPIO_F, 0x1) =
- (LM4_GPIO_DATA(LM4_GPIO_K, 0x20) ? 1 : 0);
- LM4_GPIO_DIR(LM4_GPIO_F) |= 0x1;
- LM4_GPIO_DEN(LM4_GPIO_F) |= 0x1;
-#endif
+ /* Set all GPIOs to defaults */
+ for (i = 0; i < GPIO_COUNT; i++, g++) {
- /* Setup power button input and output pins */
-#ifdef BOARD_link
- /* input: PK7 */
- LM4_GPIO_PCTL(LM4_GPIO_K) &= ~0xf0000000;
- LM4_GPIO_DIR(LM4_GPIO_K) &= ~0x80;
- LM4_GPIO_PUR(LM4_GPIO_K) |= 0x80;
- LM4_GPIO_DEN(LM4_GPIO_K) |= 0x80;
- LM4_GPIO_IM(LM4_GPIO_K) |= 0x80;
- LM4_GPIO_IBE(LM4_GPIO_K) |= 0x80;
- /* output: PG7 */
- LM4_GPIO_PCTL(LM4_GPIO_G) &= ~0xf0000000;
- LM4_GPIO_DATA(LM4_GPIO_G, 0x80) = 0x80;
- LM4_GPIO_DIR(LM4_GPIO_G) |= 0x80;
- LM4_GPIO_DEN(LM4_GPIO_G) |= 0x80;
-#else
- /* input: PC5 */
- LM4_GPIO_PCTL(LM4_GPIO_C) &= ~0x00f00000;
- LM4_GPIO_DIR(LM4_GPIO_C) &= ~0x20;
- LM4_GPIO_PUR(LM4_GPIO_C) |= 0x20;
- LM4_GPIO_DEN(LM4_GPIO_C) |= 0x20;
- LM4_GPIO_IM(LM4_GPIO_C) |= 0x20;
- LM4_GPIO_IBE(LM4_GPIO_C) |= 0x20;
-#endif
+ /* Handle GPIO direction */
+ if (g->flags & GI_OUTPUT) {
+ /* Output with default level */
+ gpio_set_level(i, g->flags & GI_HIGH);
+ LM4_GPIO_DIR(g->port) |= g->mask;
+ } else {
+ /* Input */
+ if (g->flags & GI_PULL) {
+ /* With pull up/down */
+ if (g->flags & GI_HIGH)
+ LM4_GPIO_PUR(g->port) |= g->mask;
+ else
+ LM4_GPIO_PDR(g->port) |= g->mask;
+ }
+ }
+
+ /* Use as GPIO, not alternate function */
+ gpio_set_alternate_function(g->port, g->mask, 0);
+
+ /* Set up interrupts if necessary */
+ if (g->flags & GI_INT_LEVEL)
+ LM4_GPIO_IS(g->port) |= g->mask;
+ if (g->flags & (GI_INT_RISING | GI_INT_HIGH))
+ LM4_GPIO_IEV(g->port) |= g->mask;
+ if (g->flags & GI_INT_BOTH)
+ LM4_GPIO_IBE(g->port) |= g->mask;
+ if (g->flags & GI_INT_ANY)
+ LM4_GPIO_IM(g->port) |= g->mask;
+ }
return EC_SUCCESS;
}
@@ -286,13 +368,25 @@ static int command_gpio_get(int argc, char **argv)
const struct gpio_info *g = signal_info;
int i;
+ /* If a signal is specified, print only that one */
+ if (argc == 2) {
+ i = find_signal_by_name(argv[1]);
+ if (i == GPIO_COUNT) {
+ uart_puts("Unknown signal name.\n");
+ return EC_ERROR_UNKNOWN;
+ }
+ g = signal_info + i;
+ uart_printf(" %d %s\n", gpio_get_level(i), g->name);
+ return EC_SUCCESS;
+ }
+
+ /* Otherwise print them all */
uart_puts("Current GPIO levels:\n");
for (i = 0; i < GPIO_COUNT; i++, g++) {
if (g->mask)
uart_printf(" %d %s\n", gpio_get_level(i), g->name);
- else
- uart_printf(" - %s\n", g->name);
- /* We'd overflow the output buffer without flushing */
+ /* We have enough GPIOs that we'll overflow the output buffer
+ * without flushing */
uart_flush_output();
}
return EC_SUCCESS;
@@ -301,6 +395,7 @@ static int command_gpio_get(int argc, char **argv)
static int command_gpio_set(int argc, char **argv)
{
+ const struct gpio_info *g;
char *e;
int v, i;
@@ -314,10 +409,15 @@ static int command_gpio_set(int argc, char **argv)
uart_puts("Unknown signal name.\n");
return EC_ERROR_UNKNOWN;
}
+ g = signal_info + i;
- if (!signal_info[i].mask) {
- uart_puts("Signal is not implemented; ignoring request.\n");
- return EC_SUCCESS;
+ if (!g->mask) {
+ uart_puts("Signal is not implemented.\n");
+ return EC_ERROR_UNKNOWN;
+ }
+ if (!(g->flags & GI_OUTPUT)) {
+ uart_puts("Signal is not an output.\n");
+ return EC_ERROR_UNKNOWN;
}
v = strtoi(argv[2], &e, 0);