summaryrefslogtreecommitdiff
path: root/chip/it83xx/lpc.c
diff options
context:
space:
mode:
Diffstat (limited to 'chip/it83xx/lpc.c')
-rw-r--r--chip/it83xx/lpc.c68
1 files changed, 68 insertions, 0 deletions
diff --git a/chip/it83xx/lpc.c b/chip/it83xx/lpc.c
index 519df6731a..1127e93576 100644
--- a/chip/it83xx/lpc.c
+++ b/chip/it83xx/lpc.c
@@ -29,6 +29,8 @@
#define CPUTS(outstr) cputs(CC_LPC, outstr)
#define CPRINTS(format, args...) cprints(CC_LPC, format, ## args)
+#define LPC_SYSJUMP_TAG 0x4c50 /* "LP" */
+
/* LPC PM channels */
enum lpc_pm_ch {
LPC_PM1 = 0,
@@ -107,6 +109,26 @@ static void pm_clear_ibf(enum lpc_pm_ch ch)
IT83XX_PMC_PMIE(ch) |= (1 << 7);
}
+#ifdef CONFIG_KEYBOARD_IRQ_GPIO
+static void keyboard_irq_assert(void)
+{
+ /*
+ * Enforce signal-high for long enough for the signal to be pulled high
+ * by the external pullup resistor. This ensures the host will see the
+ * following falling edge, regardless of the line state before this
+ * function call.
+ */
+ gpio_set_level(CONFIG_KEYBOARD_IRQ_GPIO, 1);
+ udelay(4);
+ /* Generate a falling edge */
+ gpio_set_level(CONFIG_KEYBOARD_IRQ_GPIO, 0);
+ udelay(4);
+
+ /* Set signal high, now that we've generated the edge */
+ gpio_set_level(CONFIG_KEYBOARD_IRQ_GPIO, 1);
+}
+#endif
+
/**
* Generate SMI pulse to the host chipset via GPIO.
*
@@ -273,6 +295,14 @@ void lpc_keyboard_put_char(uint8_t chr, int send_irq)
/* keyboard */
IT83XX_KBC_KBHISR |= 0x10;
+#ifdef CONFIG_KEYBOARD_IRQ_GPIO
+ task_clear_pending_irq(IT83XX_IRQ_KBC_OUT);
+ /* The data output to the KBC Data Output Register. */
+ IT83XX_KBC_KBHIKDOR = chr;
+ task_enable_irq(IT83XX_IRQ_KBC_OUT);
+ if (send_irq)
+ keyboard_irq_assert();
+#else
/*
* bit0 = 0, The IRQ1 is controlled by the IRQ1B bit in KBIRQR.
* bit1 = 0, The IRQ12 is controlled by the IRQ12B bit in KBIRQR.
@@ -292,6 +322,7 @@ void lpc_keyboard_put_char(uint8_t chr, int send_irq)
/* The data output to the KBC Data Output Register. */
IT83XX_KBC_KBHIKDOR = chr;
task_enable_irq(IT83XX_IRQ_KBC_OUT);
+#endif
}
void lpc_keyboard_clear_buffer(void)
@@ -307,6 +338,9 @@ void lpc_keyboard_clear_buffer(void)
void lpc_keyboard_resume_irq(void)
{
if (lpc_keyboard_has_char()) {
+#ifdef CONFIG_KEYBOARD_IRQ_GPIO
+ keyboard_irq_assert();
+#else
/* The IRQ1 is controlled by the IRQ1B bit in KBIRQR. */
IT83XX_KBC_KBHICR &= ~0x01;
@@ -315,6 +349,7 @@ void lpc_keyboard_resume_irq(void)
* (KBHICR) is 0, the bit directly controls the IRQ1 signal.
*/
IT83XX_KBC_KBIRQR |= 0x01;
+#endif
task_clear_pending_irq(IT83XX_IRQ_KBC_OUT);
@@ -409,11 +444,13 @@ void lpc_kbc_obe_interrupt(void)
task_clear_pending_irq(IT83XX_IRQ_KBC_OUT);
+#ifndef CONFIG_KEYBOARD_IRQ_GPIO
if (!(IT83XX_KBC_KBHICR & 0x01)) {
IT83XX_KBC_KBIRQR &= ~0x01;
IT83XX_KBC_KBHICR |= 0x01;
}
+#endif
#ifdef HAS_TASK_KEYPROTO
task_wake(TASK_ID_KEYPROTO);
@@ -562,6 +599,32 @@ void pm5_ibf_interrupt(void)
task_clear_pending_irq(IT83XX_IRQ_PMC5_IN);
}
+/**
+ * Preserve event masks across a sysjump.
+ */
+static void lpc_sysjump(void)
+{
+ system_add_jump_tag(LPC_SYSJUMP_TAG, 1,
+ sizeof(event_mask), event_mask);
+}
+DECLARE_HOOK(HOOK_SYSJUMP, lpc_sysjump, HOOK_PRIO_DEFAULT);
+
+/**
+ * Restore event masks after a sysjump.
+ */
+static void lpc_post_sysjump(void)
+{
+ const uint32_t *prev_mask;
+ int size, version;
+
+ prev_mask = (const uint32_t *)system_get_jump_tag(LPC_SYSJUMP_TAG,
+ &version, &size);
+ if (!prev_mask || version != 1 || size != sizeof(event_mask))
+ return;
+
+ memcpy(event_mask, prev_mask, sizeof(event_mask));
+}
+
static void lpc_init(void)
{
enum ec2i_message ec2i_r;
@@ -687,14 +750,19 @@ static void lpc_init(void)
task_enable_irq(IT83XX_IRQ_KBC_IN);
task_clear_pending_irq(IT83XX_IRQ_PMC_IN);
+ pm_set_status(LPC_ACPI_CMD, EC_LPC_STATUS_PROCESSING, 0);
task_enable_irq(IT83XX_IRQ_PMC_IN);
task_clear_pending_irq(IT83XX_IRQ_PMC2_IN);
+ pm_set_status(LPC_HOST_CMD, EC_LPC_STATUS_PROCESSING, 0);
task_enable_irq(IT83XX_IRQ_PMC2_IN);
task_clear_pending_irq(IT83XX_IRQ_PMC3_IN);
task_enable_irq(IT83XX_IRQ_PMC3_IN);
+ /* Restore event masks if needed */
+ lpc_post_sysjump();
+
/* Sufficiently initialized */
init_done = 1;