diff options
-rw-r--r-- | board/puff/board.c | 36 | ||||
-rw-r--r-- | board/puff/gpio.inc | 2 | ||||
-rw-r--r-- | power/cometlake-discrete.c | 28 | ||||
-rw-r--r-- | power/cometlake-discrete.h | 13 |
4 files changed, 66 insertions, 13 deletions
diff --git a/board/puff/board.c b/board/puff/board.c index 93cdc0f374..b3215f7855 100644 --- a/board/puff/board.c +++ b/board/puff/board.c @@ -395,23 +395,37 @@ const struct ina3221_t ina3221[] = { }; const unsigned int ina3221_count = ARRAY_SIZE(ina3221); +static void override_interrupt_priority(int irq, int priority) +{ + const uint32_t prio_shift = irq % 4 * 8 + 5; + + CPU_NVIC_PRI(irq / 4) = + (CPU_NVIC_PRI(irq / 4) & + ~(0x7 << prio_shift)) | + (priority << prio_shift); +} + static void board_init(void) { uint8_t *memmap_batt_flags; - /* Increase priority of C10 gate interrupts to minimize latency. + /* Override some GPIO interrupt priorities. * - * We assume that GPIO_CPU_C10_GATE_L is on GPIO6.7, which is on - * the WKINTH_1 IRQ. + * These interrupts are timing-critical for AP power sequencing, so we + * increase their NVIC priority from the default of 3. This affects + * whole MIWU groups of 8 GPIOs since they share an IRQ. + * + * Latency at the default priority level can be hundreds of + * microseconds while other equal-priority IRQs are serviced, so GPIOs + * requiring faster response must be higher priority. */ - const int c10_gpio_irq = NPCX_IRQ_WKINTH_1; - const int c10_gpio_prio = 2; - const uint32_t prio_shift = c10_gpio_irq % 4 * 8 + 5; - - CPU_NVIC_PRI(c10_gpio_irq / 4) = - (CPU_NVIC_PRI(c10_gpio_irq / 4) & - ~(0x7 << prio_shift)) | - (c10_gpio_prio << prio_shift); + /* CPU_C10_GATE_L on GPIO6.7: must be ~instant for ~60us response. */ + override_interrupt_priority(NPCX_IRQ_WKINTH_1, 1); + /* + * slp_s3_interrupt (GPIOA.5 on WKINTC_0) must respond within 200us + * (tPLT18); less critical than the C10 gate. + */ + override_interrupt_priority(NPCX_IRQ_WKINTC_0, 2); update_port_limits(); gpio_enable_interrupt(GPIO_BJ_ADP_PRESENT_L); diff --git a/board/puff/gpio.inc b/board/puff/gpio.inc index a0d3f044e8..9296805be5 100644 --- a/board/puff/gpio.inc +++ b/board/puff/gpio.inc @@ -31,7 +31,7 @@ GPIO_INT(SLP_S4_L, PIN(D, 4), GPIO_INT_BOTH, power_signal_interrupt) GPIO_INT(PG_PP2500_DRAM_U_OD, PIN(2, 0), GPIO_INT_BOTH, power_signal_interrupt) GPIO_INT(PG_PP1200_U_OD, PIN(2, 1), GPIO_INT_BOTH, power_signal_interrupt) #ifndef CONFIG_HOSTCMD_ESPI_VW_SLP_S3 -GPIO_INT(SLP_S3_L, PIN(A, 5), GPIO_INT_BOTH, power_signal_interrupt) +GPIO_INT(SLP_S3_L, PIN(A, 5), GPIO_INT_BOTH, slp_s3_interrupt) #endif GPIO_INT(PG_PP950_VCCIO_OD, PIN(1, 7), GPIO_INT_BOTH, power_signal_interrupt) GPIO_INT(SLP_S0_L, PIN(D, 5), GPIO_INT_BOTH, power_signal_interrupt) diff --git a/power/cometlake-discrete.c b/power/cometlake-discrete.c index 5465920334..56465ef61f 100644 --- a/power/cometlake-discrete.c +++ b/power/cometlake-discrete.c @@ -159,6 +159,9 @@ BUILD_ASSERT(ARRAY_SIZE(power_signal_list) == POWER_SIGNAL_COUNT); * * This is a separate function so it can be reused when forcing shutdown due to * power failure or other reasons. + * + * This function may be called from an ISR (slp_s3_interrupt) so must not + * assume that it's running in a regular task. */ static void shutdown_s0_rails(void) { @@ -172,7 +175,15 @@ static void shutdown_s0_rails(void) gpio_set_level(GPIO_EC_PCH_SYS_PWROK, 0); gpio_set_level(GPIO_EN_IMVP8_VR, 0); gpio_set_level(GPIO_EN_S0_RAILS, 0); - usleep(1); /* tPCH10: PCH_PWROK to VCCIO off >400 ns */ + /* + * * tPCH10: PCH_PWROK to VCCIO off >400ns (but only on unexpected + * power-down) + * * tPLT18: SLP_S3_L to VCCIO disable <200us + * + * tPCH10 is only 7 CPU cycles at 16 MHz so we should satisfy that + * minimum time with no extra code, and sleeping is likely to cause + * a delay that exceeds tPLT18. + */ gpio_set_level(GPIO_EN_PP950_VCCIO, 0); } @@ -331,6 +342,10 @@ enum power_state power_handle_state(enum power_state state) break; case POWER_S0S3: + /* + * Handled in the slp_s3_interrupt fast path, but also run + * here in case we miss the interrupt somehow. + */ shutdown_s0_rails(); break; @@ -388,3 +403,14 @@ void c10_gate_interrupt(enum gpio_signal signal) return power_signal_interrupt(signal); } + +void slp_s3_interrupt(enum gpio_signal signal) +{ + if (!gpio_get_level(GPIO_SLP_S3_L) + && chipset_in_state(CHIPSET_STATE_ON)) { + /* Falling edge on SLP_S3_L means dropping to S3 from S0 */ + shutdown_s0_rails(); + } + + return power_signal_interrupt(signal); +} diff --git a/power/cometlake-discrete.h b/power/cometlake-discrete.h index e69deb195c..6f5370beee 100644 --- a/power/cometlake-discrete.h +++ b/power/cometlake-discrete.h @@ -101,6 +101,9 @@ enum power_signal { * Board-specific enable for any additional rails in S0. * * Input 0 to turn off, 1 to turn on. + * + * This function may be called from interrupts so must not assume it's running + * in a task. */ void board_enable_s0_rails(int enable); @@ -134,4 +137,14 @@ int board_is_c10_gate_enabled(void); */ void c10_gate_interrupt(enum gpio_signal signal); +/* + * Special interrupt for SLP_S3_L handling. + * + * The time window in which to turn off some rails when dropping to S3 is + * ~200us, and using the regular power state machine path tends to have latency + * >1ms. This ISR short-circuits the relevant signals in a fast path before + * scheduling a state machine update to ensure sufficiently low latency. + */ +void slp_s3_interrupt(enum gpio_signal signal); + #endif /* __CROS_EC_COMETLAKE_DISCRETE_H */ |