Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

remoteproc: mediatek: Unprepare SCP clock during system suspend

Prior to commit d935187cfb27 ("remoteproc: mediatek: Break lock
dependency to prepare_lock"), `scp->clk` was prepared and enabled only
when it needs to communicate with the SCP. The commit d935187cfb27
moved the prepare operation to remoteproc's prepare(), keeping the clock
prepared as long as the SCP is running.

The power consumption due to the prolonged clock preparation can be
negligible when the system is running, as SCP is designed to be a very
power efficient processor.

However, the clock remains prepared even when the system enters system
suspend. This prevents the underlying clock controller (and potentially
the parent PLLs) from shutting down, which increases power consumption
and may block the system from entering deep sleep states.

Add suspend and resume callbacks. Unprepare the clock in suspend() if
it was active and re-prepare it in resume() to ensure the clock is
properly disabled during system suspend, while maintaining the "always
prepared" semantics while the system is active. The driver doesn't
implement .attach() callback, hence it only checks for RPROC_RUNNING.

Fixes: d935187cfb27 ("remoteproc: mediatek: Break lock dependency to prepare_lock")
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Signed-off-by: Tzung-Bi Shih <tzungbi@kernel.org>
Link: https://lore.kernel.org/r/20260206033034.3031781-1-tzungbi@kernel.org
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>

authored by

Tzung-Bi Shih and committed by
Mathieu Poirier
35c3f72a da994db9

+39
+39
drivers/remoteproc/mtk_scp.c
··· 1592 1592 }; 1593 1593 MODULE_DEVICE_TABLE(of, mtk_scp_of_match); 1594 1594 1595 + static int __maybe_unused scp_suspend(struct device *dev) 1596 + { 1597 + struct mtk_scp *scp = dev_get_drvdata(dev); 1598 + struct rproc *rproc = scp->rproc; 1599 + 1600 + /* 1601 + * Only unprepare if the SCP is running and holding the clock. 1602 + * 1603 + * Note: `scp_ops` doesn't implement .attach() callback, hence 1604 + * `rproc->state` can never be RPROC_ATTACHED. Otherwise, it 1605 + * should also be checked here. 1606 + */ 1607 + if (rproc->state == RPROC_RUNNING) 1608 + clk_unprepare(scp->clk); 1609 + return 0; 1610 + } 1611 + 1612 + static int __maybe_unused scp_resume(struct device *dev) 1613 + { 1614 + struct mtk_scp *scp = dev_get_drvdata(dev); 1615 + struct rproc *rproc = scp->rproc; 1616 + 1617 + /* 1618 + * Only prepare if the SCP was running and holding the clock. 1619 + * 1620 + * Note: `scp_ops` doesn't implement .attach() callback, hence 1621 + * `rproc->state` can never be RPROC_ATTACHED. Otherwise, it 1622 + * should also be checked here. 1623 + */ 1624 + if (rproc->state == RPROC_RUNNING) 1625 + return clk_prepare(scp->clk); 1626 + return 0; 1627 + } 1628 + 1629 + static const struct dev_pm_ops scp_pm_ops = { 1630 + SET_SYSTEM_SLEEP_PM_OPS(scp_suspend, scp_resume) 1631 + }; 1632 + 1595 1633 static struct platform_driver mtk_scp_driver = { 1596 1634 .probe = scp_probe, 1597 1635 .remove = scp_remove, 1598 1636 .driver = { 1599 1637 .name = "mtk-scp", 1600 1638 .of_match_table = mtk_scp_of_match, 1639 + .pm = &scp_pm_ops, 1601 1640 }, 1602 1641 }; 1603 1642