Skip to content

Commit 8b7a1b3

Browse files
lategoodbyegregkh
authored andcommitted
usb: dwc2: Refactor backup/restore of registers
The DWC2 runtime PM code reuses similar patterns to backup and restore the registers. So consolidate them in USB mode specific variants. This also has the advantage it is reusable for further PM improvements. Special care is taken for DCFG register during device mode restore. Signed-off-by: Stefan Wahren <wahrenst@gmx.net> Link: https://lore.kernel.org/r/20250217134132.36786-3-wahrenst@gmx.net Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 3975e68 commit 8b7a1b3

File tree

3 files changed

+121
-101
lines changed

3 files changed

+121
-101
lines changed

drivers/usb/dwc2/core.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1128,6 +1128,7 @@ struct dwc2_hsotg {
11281128
#define DWC2_HS_IOT_ID 0x55320000
11291129

11301130
#define DWC2_RESTORE_DCTL BIT(0)
1131+
#define DWC2_RESTORE_DCFG BIT(1)
11311132

11321133
#if IS_ENABLED(CONFIG_USB_DWC2_HOST) || IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE)
11331134
union dwc2_hcd_internal_flags {
@@ -1437,6 +1438,9 @@ int dwc2_hsotg_tx_fifo_total_depth(struct dwc2_hsotg *hsotg);
14371438
int dwc2_hsotg_tx_fifo_average_depth(struct dwc2_hsotg *hsotg);
14381439
void dwc2_gadget_init_lpm(struct dwc2_hsotg *hsotg);
14391440
void dwc2_gadget_program_ref_clk(struct dwc2_hsotg *hsotg);
1441+
int dwc2_gadget_backup_critical_registers(struct dwc2_hsotg *hsotg);
1442+
int dwc2_gadget_restore_critical_registers(struct dwc2_hsotg *hsotg,
1443+
unsigned int flags);
14401444
static inline void dwc2_clear_fifo_map(struct dwc2_hsotg *hsotg)
14411445
{ hsotg->fifo_map = 0; }
14421446
#else
@@ -1484,6 +1488,11 @@ static inline int dwc2_hsotg_tx_fifo_average_depth(struct dwc2_hsotg *hsotg)
14841488
{ return 0; }
14851489
static inline void dwc2_gadget_init_lpm(struct dwc2_hsotg *hsotg) {}
14861490
static inline void dwc2_gadget_program_ref_clk(struct dwc2_hsotg *hsotg) {}
1491+
static inline int dwc2_gadget_backup_critical_registers(struct dwc2_hsotg *hsotg)
1492+
{ return 0; }
1493+
static inline int dwc2_gadget_restore_critical_registers(struct dwc2_hsotg *hsotg,
1494+
unsigned int flags)
1495+
{ return 0; }
14871496
static inline void dwc2_clear_fifo_map(struct dwc2_hsotg *hsotg) {}
14881497
#endif
14891498

@@ -1507,6 +1516,8 @@ int dwc2_host_exit_partial_power_down(struct dwc2_hsotg *hsotg,
15071516
void dwc2_host_enter_clock_gating(struct dwc2_hsotg *hsotg);
15081517
void dwc2_host_exit_clock_gating(struct dwc2_hsotg *hsotg, int rem_wakeup);
15091518
bool dwc2_host_can_poweroff_phy(struct dwc2_hsotg *dwc2);
1519+
int dwc2_host_backup_critical_registers(struct dwc2_hsotg *hsotg);
1520+
int dwc2_host_restore_critical_registers(struct dwc2_hsotg *hsotg);
15101521
static inline void dwc2_host_schedule_phy_reset(struct dwc2_hsotg *hsotg)
15111522
{ schedule_work(&hsotg->phy_reset_work); }
15121523
#else
@@ -1546,6 +1557,10 @@ static inline void dwc2_host_exit_clock_gating(struct dwc2_hsotg *hsotg,
15461557
int rem_wakeup) {}
15471558
static inline bool dwc2_host_can_poweroff_phy(struct dwc2_hsotg *dwc2)
15481559
{ return false; }
1560+
static inline int dwc2_host_backup_critical_registers(struct dwc2_hsotg *hsotg)
1561+
{ return 0; }
1562+
static inline int dwc2_host_restore_critical_registers(struct dwc2_hsotg *hsotg)
1563+
{ return 0; }
15491564
static inline void dwc2_host_schedule_phy_reset(struct dwc2_hsotg *hsotg) {}
15501565

15511566
#endif

drivers/usb/dwc2/gadget.c

Lines changed: 55 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -5224,6 +5224,9 @@ int dwc2_restore_device_registers(struct dwc2_hsotg *hsotg, unsigned int flags)
52245224
}
52255225
dr->valid = false;
52265226

5227+
if (flags & DWC2_RESTORE_DCFG)
5228+
dwc2_writel(hsotg, dr->dcfg, DCFG);
5229+
52275230
if (flags & DWC2_RESTORE_DCTL)
52285231
dwc2_writel(hsotg, dr->dctl, DCTL);
52295232

@@ -5310,6 +5313,49 @@ void dwc2_gadget_program_ref_clk(struct dwc2_hsotg *hsotg)
53105313
dev_dbg(hsotg->dev, "GREFCLK=0x%08x\n", dwc2_readl(hsotg, GREFCLK));
53115314
}
53125315

5316+
int dwc2_gadget_backup_critical_registers(struct dwc2_hsotg *hsotg)
5317+
{
5318+
int ret;
5319+
5320+
/* Backup all registers */
5321+
ret = dwc2_backup_global_registers(hsotg);
5322+
if (ret) {
5323+
dev_err(hsotg->dev, "%s: failed to backup global registers\n",
5324+
__func__);
5325+
return ret;
5326+
}
5327+
5328+
ret = dwc2_backup_device_registers(hsotg);
5329+
if (ret) {
5330+
dev_err(hsotg->dev, "%s: failed to backup device registers\n",
5331+
__func__);
5332+
return ret;
5333+
}
5334+
5335+
return 0;
5336+
}
5337+
5338+
int dwc2_gadget_restore_critical_registers(struct dwc2_hsotg *hsotg,
5339+
unsigned int flags)
5340+
{
5341+
int ret;
5342+
5343+
ret = dwc2_restore_global_registers(hsotg);
5344+
if (ret) {
5345+
dev_err(hsotg->dev, "%s: failed to restore registers\n",
5346+
__func__);
5347+
return ret;
5348+
}
5349+
ret = dwc2_restore_device_registers(hsotg, flags);
5350+
if (ret) {
5351+
dev_err(hsotg->dev, "%s: failed to restore device registers\n",
5352+
__func__);
5353+
return ret;
5354+
}
5355+
5356+
return 0;
5357+
}
5358+
53135359
/**
53145360
* dwc2_gadget_enter_hibernation() - Put controller in Hibernation.
53155361
*
@@ -5327,18 +5373,9 @@ int dwc2_gadget_enter_hibernation(struct dwc2_hsotg *hsotg)
53275373
/* Change to L2(suspend) state */
53285374
hsotg->lx_state = DWC2_L2;
53295375
dev_dbg(hsotg->dev, "Start of hibernation completed\n");
5330-
ret = dwc2_backup_global_registers(hsotg);
5331-
if (ret) {
5332-
dev_err(hsotg->dev, "%s: failed to backup global registers\n",
5333-
__func__);
5334-
return ret;
5335-
}
5336-
ret = dwc2_backup_device_registers(hsotg);
5337-
if (ret) {
5338-
dev_err(hsotg->dev, "%s: failed to backup device registers\n",
5339-
__func__);
5376+
ret = dwc2_gadget_backup_critical_registers(hsotg);
5377+
if (ret)
53405378
return ret;
5341-
}
53425379

53435380
gpwrdn = GPWRDN_PWRDNRSTN;
53445381
udelay(10);
@@ -5486,20 +5523,9 @@ int dwc2_gadget_exit_hibernation(struct dwc2_hsotg *hsotg,
54865523
dwc2_writel(hsotg, 0xffffffff, GINTSTS);
54875524

54885525
/* Restore global registers */
5489-
ret = dwc2_restore_global_registers(hsotg);
5490-
if (ret) {
5491-
dev_err(hsotg->dev, "%s: failed to restore registers\n",
5492-
__func__);
5493-
return ret;
5494-
}
5495-
5496-
/* Restore device registers */
5497-
ret = dwc2_restore_device_registers(hsotg, flags);
5498-
if (ret) {
5499-
dev_err(hsotg->dev, "%s: failed to restore device registers\n",
5500-
__func__);
5526+
ret = dwc2_gadget_restore_critical_registers(hsotg, flags);
5527+
if (ret)
55015528
return ret;
5502-
}
55035529

55045530
if (rem_wakeup) {
55055531
mdelay(10);
@@ -5533,19 +5559,9 @@ int dwc2_gadget_enter_partial_power_down(struct dwc2_hsotg *hsotg)
55335559
dev_dbg(hsotg->dev, "Entering device partial power down started.\n");
55345560

55355561
/* Backup all registers */
5536-
ret = dwc2_backup_global_registers(hsotg);
5537-
if (ret) {
5538-
dev_err(hsotg->dev, "%s: failed to backup global registers\n",
5539-
__func__);
5540-
return ret;
5541-
}
5542-
5543-
ret = dwc2_backup_device_registers(hsotg);
5544-
if (ret) {
5545-
dev_err(hsotg->dev, "%s: failed to backup device registers\n",
5546-
__func__);
5562+
ret = dwc2_gadget_backup_critical_registers(hsotg);
5563+
if (ret)
55475564
return ret;
5548-
}
55495565

55505566
/*
55515567
* Clear any pending interrupts since dwc2 will not be able to
@@ -5592,11 +5608,8 @@ int dwc2_gadget_exit_partial_power_down(struct dwc2_hsotg *hsotg,
55925608
{
55935609
u32 pcgcctl;
55945610
u32 dctl;
5595-
struct dwc2_dregs_backup *dr;
55965611
int ret = 0;
55975612

5598-
dr = &hsotg->dr_backup;
5599-
56005613
dev_dbg(hsotg->dev, "Exiting device partial Power Down started.\n");
56015614

56025615
pcgcctl = dwc2_readl(hsotg, PCGCTL);
@@ -5613,21 +5626,10 @@ int dwc2_gadget_exit_partial_power_down(struct dwc2_hsotg *hsotg,
56135626

56145627
udelay(100);
56155628
if (restore) {
5616-
ret = dwc2_restore_global_registers(hsotg);
5617-
if (ret) {
5618-
dev_err(hsotg->dev, "%s: failed to restore registers\n",
5619-
__func__);
5620-
return ret;
5621-
}
5622-
/* Restore DCFG */
5623-
dwc2_writel(hsotg, dr->dcfg, DCFG);
5624-
5625-
ret = dwc2_restore_device_registers(hsotg, DWC2_RESTORE_DCTL);
5626-
if (ret) {
5627-
dev_err(hsotg->dev, "%s: failed to restore device registers\n",
5628-
__func__);
5629+
ret = dwc2_gadget_restore_critical_registers(hsotg, DWC2_RESTORE_DCTL |
5630+
DWC2_RESTORE_DCFG);
5631+
if (ret)
56295632
return ret;
5630-
}
56315633
}
56325634

56335635
/* Set the Power-On Programming done bit */

drivers/usb/dwc2/hcd.c

Lines changed: 51 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -5474,6 +5474,49 @@ int dwc2_restore_host_registers(struct dwc2_hsotg *hsotg)
54745474
return 0;
54755475
}
54765476

5477+
int dwc2_host_backup_critical_registers(struct dwc2_hsotg *hsotg)
5478+
{
5479+
int ret;
5480+
5481+
/* Backup all registers */
5482+
ret = dwc2_backup_global_registers(hsotg);
5483+
if (ret) {
5484+
dev_err(hsotg->dev, "%s: failed to backup global registers\n",
5485+
__func__);
5486+
return ret;
5487+
}
5488+
5489+
ret = dwc2_backup_host_registers(hsotg);
5490+
if (ret) {
5491+
dev_err(hsotg->dev, "%s: failed to backup host registers\n",
5492+
__func__);
5493+
return ret;
5494+
}
5495+
5496+
return 0;
5497+
}
5498+
5499+
int dwc2_host_restore_critical_registers(struct dwc2_hsotg *hsotg)
5500+
{
5501+
int ret;
5502+
5503+
ret = dwc2_restore_global_registers(hsotg);
5504+
if (ret) {
5505+
dev_err(hsotg->dev, "%s: failed to restore registers\n",
5506+
__func__);
5507+
return ret;
5508+
}
5509+
5510+
ret = dwc2_restore_host_registers(hsotg);
5511+
if (ret) {
5512+
dev_err(hsotg->dev, "%s: failed to restore host registers\n",
5513+
__func__);
5514+
return ret;
5515+
}
5516+
5517+
return 0;
5518+
}
5519+
54775520
/**
54785521
* dwc2_host_enter_hibernation() - Put controller in Hibernation.
54795522
*
@@ -5489,18 +5532,9 @@ int dwc2_host_enter_hibernation(struct dwc2_hsotg *hsotg)
54895532
u32 gpwrdn;
54905533

54915534
dev_dbg(hsotg->dev, "Preparing host for hibernation\n");
5492-
ret = dwc2_backup_global_registers(hsotg);
5493-
if (ret) {
5494-
dev_err(hsotg->dev, "%s: failed to backup global registers\n",
5495-
__func__);
5496-
return ret;
5497-
}
5498-
ret = dwc2_backup_host_registers(hsotg);
5499-
if (ret) {
5500-
dev_err(hsotg->dev, "%s: failed to backup host registers\n",
5501-
__func__);
5535+
ret = dwc2_host_backup_critical_registers(hsotg);
5536+
if (ret)
55025537
return ret;
5503-
}
55045538

55055539
/* Enter USB Suspend Mode */
55065540
hprt0 = dwc2_readl(hsotg, HPRT0);
@@ -5694,20 +5728,9 @@ int dwc2_host_exit_hibernation(struct dwc2_hsotg *hsotg, int rem_wakeup,
56945728
dwc2_writel(hsotg, 0xffffffff, GINTSTS);
56955729

56965730
/* Restore global registers */
5697-
ret = dwc2_restore_global_registers(hsotg);
5698-
if (ret) {
5699-
dev_err(hsotg->dev, "%s: failed to restore registers\n",
5700-
__func__);
5731+
ret = dwc2_host_restore_critical_registers(hsotg);
5732+
if (ret)
57015733
return ret;
5702-
}
5703-
5704-
/* Restore host registers */
5705-
ret = dwc2_restore_host_registers(hsotg);
5706-
if (ret) {
5707-
dev_err(hsotg->dev, "%s: failed to restore host registers\n",
5708-
__func__);
5709-
return ret;
5710-
}
57115734

57125735
if (rem_wakeup) {
57135736
dwc2_hcd_rem_wakeup(hsotg);
@@ -5774,19 +5797,9 @@ int dwc2_host_enter_partial_power_down(struct dwc2_hsotg *hsotg)
57745797
dev_warn(hsotg->dev, "Suspend wasn't generated\n");
57755798

57765799
/* Backup all registers */
5777-
ret = dwc2_backup_global_registers(hsotg);
5778-
if (ret) {
5779-
dev_err(hsotg->dev, "%s: failed to backup global registers\n",
5780-
__func__);
5781-
return ret;
5782-
}
5783-
5784-
ret = dwc2_backup_host_registers(hsotg);
5785-
if (ret) {
5786-
dev_err(hsotg->dev, "%s: failed to backup host registers\n",
5787-
__func__);
5800+
ret = dwc2_host_backup_critical_registers(hsotg);
5801+
if (ret)
57885802
return ret;
5789-
}
57905803

57915804
/*
57925805
* Clear any pending interrupts since dwc2 will not be able to
@@ -5855,19 +5868,9 @@ int dwc2_host_exit_partial_power_down(struct dwc2_hsotg *hsotg,
58555868

58565869
udelay(100);
58575870
if (restore) {
5858-
ret = dwc2_restore_global_registers(hsotg);
5859-
if (ret) {
5860-
dev_err(hsotg->dev, "%s: failed to restore registers\n",
5861-
__func__);
5862-
return ret;
5863-
}
5864-
5865-
ret = dwc2_restore_host_registers(hsotg);
5866-
if (ret) {
5867-
dev_err(hsotg->dev, "%s: failed to restore host registers\n",
5868-
__func__);
5871+
ret = dwc2_host_restore_critical_registers(hsotg);
5872+
if (ret)
58695873
return ret;
5870-
}
58715874
}
58725875

58735876
/* Drive resume signaling and exit suspend mode on the port. */

0 commit comments

Comments
 (0)