Skip to content

Commit ac7d55b

Browse files
tmon-nordicfabiobaltieri
authored andcommitted
drivers: usb: udc_dwc2: Support Remote Wakeup
According to USB 2.0 Specification the remote wakeup device must hold the resume signaling for at least 1 ms but for no more than 15 ms. The DWC2 otg controller requires the software to drive the remote wakeup signalling for appropriate duration (when LPM is disabled, which is currently always the case in udc_dwc2). Arbitrarily choose to drive the resume signalling for 2 ms to have sufficient margin in both directions. Signed-off-by: Tomasz Moń <[email protected]>
1 parent 68b8818 commit ac7d55b

File tree

1 file changed

+93
-17
lines changed

1 file changed

+93
-17
lines changed

drivers/usb/udc/udc_dwc2.c

Lines changed: 93 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ enum dwc2_drv_event_type {
3131
DWC2_DRV_EVT_SETUP,
3232
/* Transaction on endpoint is finished */
3333
DWC2_DRV_EVT_EP_FINISHED,
34+
/* Remote Wakeup should be initiated */
35+
DWC2_DRV_EVT_REMOTE_WAKEUP,
3436
/* Core should enter hibernation */
3537
DWC2_DRV_EVT_ENTER_HIBERNATION,
3638
/* Core should exit hibernation due to bus reset */
@@ -115,6 +117,7 @@ struct udc_dwc2_data {
115117
/* Configuration flags */
116118
unsigned int dynfifosizing : 1;
117119
unsigned int bufferdma : 1;
120+
unsigned int syncrst : 1;
118121
/* Runtime state flags */
119122
unsigned int hibernated : 1;
120123
unsigned int enumdone : 1;
@@ -900,7 +903,8 @@ static void dwc2_backup_registers(const struct device *dev)
900903
backup->pcgcctl = sys_read32((mem_addr_t)&base->pcgcctl);
901904
}
902905

903-
static void dwc2_restore_essential_registers(const struct device *dev)
906+
static void dwc2_restore_essential_registers(const struct device *dev,
907+
bool rwup)
904908
{
905909
const struct udc_dwc2_config *const config = dev->config;
906910
struct usb_dwc2_reg *const base = config->base;
@@ -921,15 +925,17 @@ static void dwc2_restore_essential_registers(const struct device *dev)
921925
sys_write32(backup->gusbcfg, (mem_addr_t)&base->gusbcfg);
922926
sys_write32(backup->dcfg, (mem_addr_t)&base->dcfg);
923927

924-
pcgcctl |= USB_DWC2_PCGCCTL_RESTOREMODE | USB_DWC2_PCGCCTL_RSTPDWNMODULE;
928+
if (!rwup) {
929+
pcgcctl |= USB_DWC2_PCGCCTL_RESTOREMODE | USB_DWC2_PCGCCTL_RSTPDWNMODULE;
930+
}
925931
sys_write32(pcgcctl, (mem_addr_t)&base->pcgcctl);
926932
k_busy_wait(1);
927933

928934
pcgcctl |= USB_DWC2_PCGCCTL_ESSREGRESTORED;
929935
sys_write32(pcgcctl, (mem_addr_t)&base->pcgcctl);
930936
}
931937

932-
static void dwc2_restore_device_registers(const struct device *dev)
938+
static void dwc2_restore_device_registers(const struct device *dev, bool rwup)
933939
{
934940
const struct udc_dwc2_config *const config = dev->config;
935941
struct usb_dwc2_reg *const base = config->base;
@@ -948,7 +954,10 @@ static void dwc2_restore_device_registers(const struct device *dev)
948954
sys_write32(backup->dieptxf[i - 1], (mem_addr_t)&base->dieptxf[i - 1]);
949955
}
950956

951-
sys_write32(backup->dctl, (mem_addr_t)&base->dctl);
957+
if (!rwup) {
958+
sys_write32(backup->dctl, (mem_addr_t)&base->dctl);
959+
}
960+
952961
sys_write32(backup->diepmsk, (mem_addr_t)&base->diepmsk);
953962
sys_write32(backup->doepmsk, (mem_addr_t)&base->doepmsk);
954963
sys_write32(backup->daintmsk, (mem_addr_t)&base->daintmsk);
@@ -1015,7 +1024,7 @@ static void dwc2_enter_hibernation(const struct device *dev)
10151024
LOG_DBG("Hibernated");
10161025
}
10171026

1018-
static void dwc2_exit_hibernation(const struct device *dev)
1027+
static void dwc2_exit_hibernation(const struct device *dev, bool rwup)
10191028
{
10201029
const struct udc_dwc2_config *const config = dev->config;
10211030
struct usb_dwc2_reg *const base = config->base;
@@ -1038,14 +1047,24 @@ static void dwc2_exit_hibernation(const struct device *dev)
10381047
/* Disable power clamps */
10391048
sys_clear_bits(gpwrdn_reg, USB_DWC2_GPWRDN_PWRDNCLMP);
10401049

1050+
if (rwup) {
1051+
if (priv->syncrst) {
1052+
k_busy_wait(1);
1053+
} else {
1054+
k_busy_wait(50);
1055+
}
1056+
}
1057+
10411058
/* Remove reset to the controller */
10421059
sys_set_bits(gpwrdn_reg, USB_DWC2_GPWRDN_PWRDNRST_N);
10431060
k_busy_wait(1);
10441061

10451062
/* Disable PMU interrupt */
10461063
sys_clear_bits(gpwrdn_reg, USB_DWC2_GPWRDN_PMUINTSEL);
10471064

1048-
dwc2_restore_essential_registers(dev);
1065+
dwc2_restore_essential_registers(dev, rwup);
1066+
1067+
/* Note: in Remote Wakeup case 15 ms max signaling time starts now */
10491068

10501069
/* Wait for Restore Done Interrupt */
10511070
dwc2_wait_for_bit(dev, (mem_addr_t)&base->gintsts, USB_DWC2_GINTSTS_RSTRDONEINT);
@@ -1055,8 +1074,10 @@ static void dwc2_exit_hibernation(const struct device *dev)
10551074
sys_clear_bits(gpwrdn_reg, USB_DWC2_GPWRDN_RESTORE);
10561075
k_busy_wait(1);
10571076

1058-
/* Clear reset to power down module */
1059-
sys_clear_bits(pcgcctl_reg, USB_DWC2_PCGCCTL_RSTPDWNMODULE);
1077+
if (!rwup) {
1078+
/* Clear reset to power down module */
1079+
sys_clear_bits(pcgcctl_reg, USB_DWC2_PCGCCTL_RSTPDWNMODULE);
1080+
}
10601081

10611082
/* Restore GUSBCFG, DCFG and DCTL */
10621083
sys_write32(priv->backup.gusbcfg, (mem_addr_t)&base->gusbcfg);
@@ -1065,9 +1086,15 @@ static void dwc2_exit_hibernation(const struct device *dev)
10651086

10661087
/* Disable PMU */
10671088
sys_clear_bits(gpwrdn_reg, USB_DWC2_GPWRDN_PMUACTV);
1068-
k_busy_wait(5);
1089+
if (!rwup) {
1090+
k_busy_wait(5);
1091+
sys_set_bits((mem_addr_t)&base->dctl, USB_DWC2_DCTL_PWRONPRGDONE);
1092+
} else {
1093+
k_busy_wait(1);
1094+
sys_write32(USB_DWC2_DCTL_RMTWKUPSIG | priv->backup.dctl,
1095+
(mem_addr_t)&base->dctl);
1096+
}
10691097

1070-
sys_set_bits((mem_addr_t)&base->dctl, USB_DWC2_DCTL_PWRONPRGDONE);
10711098
k_msleep(1);
10721099
sys_write32(0xFFFFFFFFUL, (mem_addr_t)&base->gintsts);
10731100
}
@@ -1621,9 +1648,13 @@ static int udc_dwc2_test_mode(const struct device *dev,
16211648

16221649
static int udc_dwc2_host_wakeup(const struct device *dev)
16231650
{
1651+
struct udc_dwc2_data *const priv = udc_get_private(dev);
1652+
16241653
LOG_DBG("Remote wakeup from %p", dev);
16251654

1626-
return -ENOTSUP;
1655+
k_event_post(&priv->drv_evt, BIT(DWC2_DRV_EVT_REMOTE_WAKEUP));
1656+
1657+
return 0;
16271658
}
16281659

16291660
/* Return actual USB device speed */
@@ -1785,6 +1816,10 @@ static int udc_dwc2_init_controller(const struct device *dev)
17851816
LOG_DBG("LPM mode is %s",
17861817
(ghwcfg3 & USB_DWC2_GHWCFG3_LPMMODE) ? "enabled" : "disabled");
17871818

1819+
if (ghwcfg3 & USB_DWC2_GHWCFG3_RSTTYPE) {
1820+
priv->syncrst = 1;
1821+
}
1822+
17881823
/* Configure AHB, select Completer or DMA mode */
17891824
gahbcfg = sys_read32(gahbcfg_reg);
17901825

@@ -1988,7 +2023,7 @@ static int udc_dwc2_disable(const struct device *dev)
19882023
config->irq_disable_func(dev);
19892024

19902025
if (priv->hibernated) {
1991-
dwc2_exit_hibernation(dev);
2026+
dwc2_exit_hibernation(dev, false);
19922027
priv->hibernated = 0;
19932028
}
19942029

@@ -2045,6 +2080,7 @@ static int dwc2_driver_preinit(const struct device *dev)
20452080
k_event_init(&priv->xfer_new);
20462081
k_event_init(&priv->xfer_finished);
20472082

2083+
data->caps.rwup = true;
20482084
data->caps.addr_before_status = true;
20492085
data->caps.mps0 = UDC_MPS0_64;
20502086

@@ -2704,20 +2740,36 @@ static void udc_dwc2_isr_handler(const struct device *dev)
27042740
}
27052741

27062742
static void dwc2_handle_hibernation_exit(const struct device *dev,
2707-
bool bus_reset)
2743+
bool rwup, bool bus_reset)
27082744
{
2745+
struct usb_dwc2_reg *const base = dwc2_get_base(dev);
27092746
struct udc_dwc2_data *const priv = udc_get_private(dev);
27102747

2711-
dwc2_exit_hibernation(dev);
2712-
dwc2_restore_device_registers(dev);
2748+
dwc2_exit_hibernation(dev, rwup);
2749+
dwc2_restore_device_registers(dev, rwup);
27132750

27142751
priv->hibernated = 0;
2715-
LOG_DBG("Hibernation exit complete");
2752+
if (!rwup) {
2753+
LOG_DBG("Hibernation exit complete");
2754+
}
27162755

27172756
/* Let stack know we are no longer suspended */
27182757
udc_set_suspended(dev, false);
27192758
udc_submit_event(dev, UDC_EVT_RESUME, 0);
27202759

2760+
if (rwup) {
2761+
/* Resume has been driven for at least 1 ms now, do 1 ms more to
2762+
* have sufficient margin.
2763+
*/
2764+
k_msleep(1);
2765+
2766+
sys_clear_bits((mem_addr_t)&base->dctl, USB_DWC2_DCTL_RMTWKUPSIG);
2767+
}
2768+
2769+
if (rwup) {
2770+
LOG_DBG("Hibernation exit on Remote Wakeup complete");
2771+
}
2772+
27212773
if (bus_reset) {
27222774
/* Clear all pending transfers */
27232775
k_event_clear(&priv->xfer_new, UINT32_MAX);
@@ -2754,6 +2806,7 @@ static uint8_t pull_next_ep_from_bitmap(uint32_t *bitmap)
27542806
static ALWAYS_INLINE void dwc2_thread_handler(void *const arg)
27552807
{
27562808
const struct device *dev = (const struct device *)arg;
2809+
struct usb_dwc2_reg *const base = dwc2_get_base(dev);
27572810
struct udc_dwc2_data *const priv = udc_get_private(dev);
27582811
const struct udc_dwc2_config *const config = dev->config;
27592812
struct udc_ep_config *ep_cfg;
@@ -2833,6 +2886,29 @@ static ALWAYS_INLINE void dwc2_thread_handler(void *const arg)
28332886
dwc2_handle_evt_setup(dev);
28342887
}
28352888

2889+
if (evt & BIT(DWC2_DRV_EVT_REMOTE_WAKEUP)) {
2890+
k_event_clear(&priv->drv_evt, BIT(DWC2_DRV_EVT_REMOTE_WAKEUP) |
2891+
BIT(DWC2_DRV_EVT_ENTER_HIBERNATION));
2892+
2893+
if (priv->hibernated) {
2894+
config->irq_disable_func(dev);
2895+
2896+
dwc2_handle_hibernation_exit(dev, true, false);
2897+
2898+
config->irq_enable_func(dev);
2899+
} else {
2900+
sys_set_bits((mem_addr_t)&base->dctl, USB_DWC2_DCTL_RMTWKUPSIG);
2901+
2902+
udc_set_suspended(dev, false);
2903+
udc_submit_event(dev, UDC_EVT_RESUME, 0);
2904+
2905+
/* Drive resume for 2 ms to have sufficient margin */
2906+
k_msleep(2);
2907+
2908+
sys_clear_bits((mem_addr_t)&base->dctl, USB_DWC2_DCTL_RMTWKUPSIG);
2909+
}
2910+
}
2911+
28362912
if (evt & BIT(DWC2_DRV_EVT_ENTER_HIBERNATION)) {
28372913
config->irq_disable_func(dev);
28382914

@@ -2856,7 +2932,7 @@ static ALWAYS_INLINE void dwc2_thread_handler(void *const arg)
28562932
bus_reset = prev & BIT(DWC2_DRV_EVT_HIBERNATION_EXIT_BUS_RESET);
28572933

28582934
if (priv->hibernated) {
2859-
dwc2_handle_hibernation_exit(dev, bus_reset);
2935+
dwc2_handle_hibernation_exit(dev, false, bus_reset);
28602936
}
28612937

28622938
config->irq_enable_func(dev);

0 commit comments

Comments
 (0)