diff options
author | Nicolas Boichat <drinkcat@google.com> | 2017-02-22 16:47:27 +0800 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2017-03-01 07:25:03 -0800 |
commit | b8c255484c59161217becdc29e353424d1f7a364 (patch) | |
tree | 9599cc58c41139ddfcae5f8e39dd36ac797cfedb | |
parent | c425cbae0be48cf9a9a5b30610c282ced1328d70 (diff) | |
download | chrome-ec-b8c255484c59161217becdc29e353424d1f7a364.tar.gz |
stm32/usb: Add support for USB suspend
This follows the basics of what is decribed in
RM0091 Reference Manual 30.5.5 Suspend/Resume events .
We call enable/disable_sleep at suspend/resume, to make
sure the EC stays awake when USB is connected and active.
We also call clock_enable/disable_module, which is stubbed on
stm32f0, but can be used on other devices in the family.
This also fixes interrupt handling in usb_interrupt, by only
clearing interrupt bits that were handled instead of resetting
them all, which is racy, and can potentially lead to issues
if reset comes soon after a resume event.
BRANCH=none
BUG=chrome-os-partner:62325
TEST=build and flash hammer, connect to chell, suspend/resume,
and see that hammer prints USB suspend and USB resume lines.
Change-Id: Ie9d02fd4a114add3ebc98dc9393680bc9a64a522
Reviewed-on: https://chromium-review.googlesource.com/446239
Commit-Ready: Nicolas Boichat <drinkcat@chromium.org>
Tested-by: Nicolas Boichat <drinkcat@chromium.org>
Reviewed-by: Vincent Palatin <vpalatin@chromium.org>
-rw-r--r-- | chip/stm32/registers.h | 4 | ||||
-rw-r--r-- | chip/stm32/usb-stm32f0.c | 7 | ||||
-rw-r--r-- | chip/stm32/usb-stm32f3.c | 7 | ||||
-rw-r--r-- | chip/stm32/usb-stm32l.c | 7 | ||||
-rw-r--r-- | chip/stm32/usb.c | 58 | ||||
-rw-r--r-- | include/config.h | 3 |
6 files changed, 84 insertions, 2 deletions
diff --git a/chip/stm32/registers.h b/chip/stm32/registers.h index 57193b08af..4f79beb769 100644 --- a/chip/stm32/registers.h +++ b/chip/stm32/registers.h @@ -2157,6 +2157,10 @@ typedef volatile struct stm32_dma_regs stm32_dma_regs_t; #define STM32_USB_ISTR_CTR (1 << 15) #define STM32_USB_FNR REG16(STM32_USB_FS_BASE + 0x48) + +#define STM32_USB_FNR_RXDP_RXDM_SHIFT (14) +#define STM32_USB_FNR_RXDP_RXDM_MASK (3 << STM32_USB_FNR_RXDP_RXDM_SHIFT) + #define STM32_USB_DADDR REG16(STM32_USB_FS_BASE + 0x4C) #define STM32_USB_BTABLE REG16(STM32_USB_FS_BASE + 0x50) #define STM32_USB_LPMCSR REG16(STM32_USB_FS_BASE + 0x54) diff --git a/chip/stm32/usb-stm32f0.c b/chip/stm32/usb-stm32f0.c index 1805c74e5e..97bb93cafd 100644 --- a/chip/stm32/usb-stm32f0.c +++ b/chip/stm32/usb-stm32f0.c @@ -6,10 +6,14 @@ */ #include "registers.h" +#include "system.h" #include "usb_api.h" void usb_connect(void) { + /* USB is in use */ + disable_sleep(SLEEP_MASK_USB_DEVICE); + STM32_USB_BCDR |= (1 << 15) /* DPPU */; } @@ -17,4 +21,7 @@ void usb_disconnect(void) { /* disable pull-up on DP to disconnect */ STM32_USB_BCDR &= ~(1 << 15) /* DPPU */; + + /* USB is off, so sleep whenever */ + enable_sleep(SLEEP_MASK_USB_DEVICE); } diff --git a/chip/stm32/usb-stm32f3.c b/chip/stm32/usb-stm32f3.c index 8c16bd6b4a..d81548729b 100644 --- a/chip/stm32/usb-stm32f3.c +++ b/chip/stm32/usb-stm32f3.c @@ -7,14 +7,21 @@ #include "usb-stm32f3.h" +#include "system.h" #include "usb_api.h" void usb_connect(void) { + /* USB is in use */ + disable_sleep(SLEEP_MASK_USB_DEVICE); + usb_board_connect(); } void usb_disconnect(void) { usb_board_disconnect(); + + /* USB is off, so sleep whenever */ + enable_sleep(SLEEP_MASK_USB_DEVICE); } diff --git a/chip/stm32/usb-stm32l.c b/chip/stm32/usb-stm32l.c index c5d58257cb..0fa3cd0b9d 100644 --- a/chip/stm32/usb-stm32l.c +++ b/chip/stm32/usb-stm32l.c @@ -6,10 +6,14 @@ */ #include "registers.h" +#include "system.h" #include "usb_api.h" void usb_connect(void) { + /* USB is in use */ + disable_sleep(SLEEP_MASK_USB_DEVICE); + STM32_SYSCFG_PMC |= 1; } @@ -17,4 +21,7 @@ void usb_disconnect(void) { /* disable pull-up on DP to disconnect */ STM32_SYSCFG_PMC &= ~1; + + /* USB is off, so sleep whenever */ + enable_sleep(SLEEP_MASK_USB_DEVICE); } diff --git a/chip/stm32/usb.c b/chip/stm32/usb.c index ea34877c6d..4cdfe0828c 100644 --- a/chip/stm32/usb.c +++ b/chip/stm32/usb.c @@ -12,6 +12,7 @@ #include "hooks.h" #include "link_defs.h" #include "registers.h" +#include "system.h" #include "task.h" #include "timer.h" #include "util.h" @@ -292,6 +293,47 @@ static void usb_reset(void) CPRINTF("RST EP0 %04x\n", STM32_USB_EP(0)); } +#ifdef CONFIG_USB_SUSPEND +/* See RM0091 Reference Manual 30.5.5 Suspend/Resume events */ +static void usb_suspend(void) +{ + CPRINTF("USB suspend!\n"); + + /* Set FSUSP bit to activate suspend mode */ + STM32_USB_CNTR |= STM32_USB_CNTR_FSUSP; + + /* Set USB low power mode */ + STM32_USB_CNTR |= STM32_USB_CNTR_LP_MODE; + + clock_enable_module(MODULE_USB, 0); + + /* USB is not in use anymore, we can (hopefully) sleep now. */ + enable_sleep(SLEEP_MASK_USB_DEVICE); +} + +static void usb_resume(void) +{ + int state = (STM32_USB_FNR & STM32_USB_FNR_RXDP_RXDM_MASK) + >> STM32_USB_FNR_RXDP_RXDM_SHIFT; + + CPRINTF("USB resume %x\n", state); + + /* + * TODO(crosbug.com/p/63273): Reference manual suggests going back to + * sleep if state is 10 or 11, but this seems to cause other problems + * (see bug). Ignore them for now. + */ + + clock_enable_module(MODULE_USB, 1); + + /* Clear FSUSP bit to exit suspend mode */ + STM32_USB_CNTR &= ~STM32_USB_CNTR_FSUSP; + + /* USB is in use again */ + disable_sleep(SLEEP_MASK_USB_DEVICE); +} +#endif /* CONFIG_USB_SUSPEND */ + void usb_interrupt(void) { uint16_t status = STM32_USB_ISTR; @@ -299,6 +341,14 @@ void usb_interrupt(void) if (status & STM32_USB_ISTR_RESET) usb_reset(); +#ifdef CONFIG_USB_SUSPEND + if (status & STM32_USB_ISTR_SUSP) + usb_suspend(); + + if (status & STM32_USB_ISTR_WKUP) + usb_resume(); +#endif + if (status & STM32_USB_ISTR_CTR) { int ep = status & STM32_USB_ISTR_EP_ID_MASK; if (ep < USB_EP_COUNT) { @@ -311,8 +361,8 @@ void usb_interrupt(void) /* task_set_event(, 1 << ep_task); */ } - /* ack interrupts */ - STM32_USB_ISTR = 0; + /* ack only interrupts that we handled */ + STM32_USB_ISTR = ~status; } DECLARE_IRQ(STM32_IRQ_USB_LP, usb_interrupt, 1); @@ -350,6 +400,10 @@ void usb_init(void) STM32_USB_CNTR = STM32_USB_CNTR_CTRM | STM32_USB_CNTR_PMAOVRM | STM32_USB_CNTR_ERRM | +#ifdef CONFIG_USB_SUSPEND + STM32_USB_CNTR_WKUPM | + STM32_USB_CNTR_SUSPM | +#endif STM32_USB_CNTR_RESETM; #ifdef CONFIG_USB_SERIALNO diff --git a/include/config.h b/include/config.h index d9597d01cd..5811e0f2b5 100644 --- a/include/config.h +++ b/include/config.h @@ -2442,6 +2442,9 @@ /* Support reporting as self powered in USB configuration. */ #undef CONFIG_USB_SELF_POWERED +/* Support correct handling of USB suspend (host-initiated). */ +#undef CONFIG_USB_SUSPEND + /* Default pull-up value on the USB-C ports when they are used as source. */ #define CONFIG_USB_PD_PULLUP TYPEC_RP_1A5 /* |