Skip to content

Commit 4d7b324

Browse files
committed
bus: ti-sysc: Fix am335x resume hang for usb otg module
On am335x, suspend and resume only works once, and the system hangs if suspend is attempted again. However, turns out suspend and resume works fine multiple times if the USB OTG driver for musb controller is loaded. The issue is caused my the interconnect target module losing context during suspend, and it needs a restore on resume to be reconfigure again as debugged earlier by Dave Gerlach <[email protected]>. There are also other modules that need a restore on resume, like gpmc as noted by Dave. So let's add a common way to restore an interconnect target module based on a quirk flag. For now, let's enable the quirk for am335x otg only to fix the suspend and resume issue. As gpmc is not causing hangs based on tests with BeagleBone, let's patch gpmc separately. For gpmc, we also need a hardware reset done before restore according to Dave. To reinit the modules, we decouple system suspend from PM runtime. We replace calls to pm_runtime_force_suspend() and pm_runtime_force_resume() with direct calls to internal functions and rely on the driver internal state. There no point trying to handle complex system suspend and resume quirks via PM runtime. This is issue should have already been noticed with commit 1819ef2 ("bus: ti-sysc: Use swsup quirks also for am335x musb") when quirk handling was added for am335x otg for swsup. But the issue went unnoticed as having musb driver loaded hides the issue, and suspend and resume works once without the driver loaded. Fixes: 1819ef2 ("bus: ti-sysc: Use swsup quirks also for am335x musb") Suggested-by: Dave Gerlach <[email protected]> Signed-off-by: Tony Lindgren <[email protected]>
1 parent 85ebe5a commit 4d7b324

File tree

2 files changed

+51
-3
lines changed

2 files changed

+51
-3
lines changed

drivers/bus/ti-sysc.c

Lines changed: 50 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1334,6 +1334,34 @@ static int __maybe_unused sysc_runtime_resume(struct device *dev)
13341334
return error;
13351335
}
13361336

1337+
static int sysc_reinit_module(struct sysc *ddata, bool leave_enabled)
1338+
{
1339+
struct device *dev = ddata->dev;
1340+
int error;
1341+
1342+
/* Disable target module if it is enabled */
1343+
if (ddata->enabled) {
1344+
error = sysc_runtime_suspend(dev);
1345+
if (error)
1346+
dev_warn(dev, "reinit suspend failed: %i\n", error);
1347+
}
1348+
1349+
/* Enable target module */
1350+
error = sysc_runtime_resume(dev);
1351+
if (error)
1352+
dev_warn(dev, "reinit resume failed: %i\n", error);
1353+
1354+
if (leave_enabled)
1355+
return error;
1356+
1357+
/* Disable target module if no leave_enabled was set */
1358+
error = sysc_runtime_suspend(dev);
1359+
if (error)
1360+
dev_warn(dev, "reinit suspend failed: %i\n", error);
1361+
1362+
return error;
1363+
}
1364+
13371365
static int __maybe_unused sysc_noirq_suspend(struct device *dev)
13381366
{
13391367
struct sysc *ddata;
@@ -1344,20 +1372,38 @@ static int __maybe_unused sysc_noirq_suspend(struct device *dev)
13441372
(SYSC_QUIRK_LEGACY_IDLE | SYSC_QUIRK_NO_IDLE))
13451373
return 0;
13461374

1347-
return pm_runtime_force_suspend(dev);
1375+
if (!ddata->enabled)
1376+
return 0;
1377+
1378+
ddata->needs_resume = 1;
1379+
1380+
return sysc_runtime_suspend(dev);
13481381
}
13491382

13501383
static int __maybe_unused sysc_noirq_resume(struct device *dev)
13511384
{
13521385
struct sysc *ddata;
1386+
int error = 0;
13531387

13541388
ddata = dev_get_drvdata(dev);
13551389

13561390
if (ddata->cfg.quirks &
13571391
(SYSC_QUIRK_LEGACY_IDLE | SYSC_QUIRK_NO_IDLE))
13581392
return 0;
13591393

1360-
return pm_runtime_force_resume(dev);
1394+
if (ddata->cfg.quirks & SYSC_QUIRK_REINIT_ON_RESUME) {
1395+
error = sysc_reinit_module(ddata, ddata->needs_resume);
1396+
if (error)
1397+
dev_warn(dev, "noirq_resume failed: %i\n", error);
1398+
} else if (ddata->needs_resume) {
1399+
error = sysc_runtime_resume(dev);
1400+
if (error)
1401+
dev_warn(dev, "noirq_resume failed: %i\n", error);
1402+
}
1403+
1404+
ddata->needs_resume = 0;
1405+
1406+
return error;
13611407
}
13621408

13631409
static const struct dev_pm_ops sysc_pm_ops = {
@@ -1468,7 +1514,8 @@ static const struct sysc_revision_quirk sysc_revision_quirks[] = {
14681514
SYSC_QUIRK("usb_otg_hs", 0, 0x400, 0x404, 0x408, 0x00000050,
14691515
0xffffffff, SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_SWSUP_MSTANDBY),
14701516
SYSC_QUIRK("usb_otg_hs", 0, 0, 0x10, -ENODEV, 0x4ea2080d, 0xffffffff,
1471-
SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_SWSUP_MSTANDBY),
1517+
SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_SWSUP_MSTANDBY |
1518+
SYSC_QUIRK_REINIT_ON_RESUME),
14721519
SYSC_QUIRK("wdt", 0, 0, 0x10, 0x14, 0x502a0500, 0xfffff0f0,
14731520
SYSC_MODULE_QUIRK_WDT),
14741521
/* PRUSS on am3, am4 and am5 */

include/linux/platform_data/ti-sysc.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ struct sysc_regbits {
5050
s8 emufree_shift;
5151
};
5252

53+
#define SYSC_QUIRK_REINIT_ON_RESUME BIT(27)
5354
#define SYSC_QUIRK_GPMC_DEBUG BIT(26)
5455
#define SYSC_MODULE_QUIRK_ENA_RESETDONE BIT(25)
5556
#define SYSC_MODULE_QUIRK_PRUSS BIT(24)

0 commit comments

Comments
 (0)