summaryrefslogtreecommitdiff
path: root/drivers/pmdomain
diff options
context:
space:
mode:
authorMing Qian <ming.qian@oss.nxp.com>2026-09-21 19:03:34 +0900
committerUlf Hansson <ulfh@kernel.org>2026-09-23 13:38:52 +0200
commit51c2db3ef0cb89a49ab7f47a40efd5d5b074ce8d (patch)
tree8920928c6f2f28d6f23d9a66dae07cd1268220a3 /drivers/pmdomain
parentdf2908090cda368b01ff43709f51890076c56157 (diff)
downloadlinux-next-51c2db3ef0cb89a49ab7f47a40efd5d5b074ce8d.tar.gz
linux-next-51c2db3ef0cb89a49ab7f47a40efd5d5b074ce8d.zip
pmdomain: imx8m-blk-ctrl: Serialize power on/off across sibling domains
On i.MX8MP the VPU blk-ctrl exposes G1, G2 and VC8000E as three separate genpds, each serialized only by its own genpd lock, so their power_on and power_off callbacks can run concurrently on SMP. The sequences are not independent: they share the VPUMIX bus domain, the VPU_NOC and the ADB400 handshake. On power up the GPC cannot ack-verify the ADB400 handshake - the ack only completes once blk-ctrl sets the bus clk-en bit - so it just waits a fixed delay instead of polling hskack. A sibling transition landing inside another domain's reset window disturbs that shared clock and handshake timing, the victim's reset does not take effect, and its block registers read back all zeros: the decoder times out or the encoder fails its format check. Serialize the blk-ctrl reset sequence with a per-blk-ctrl mutex; the driver deliberately avoids a genpd hierarchy, so the genpd core gives no cross-sibling serialization. Fixes: a1a5f15f7f6c ("soc: imx: imx8m-blk-ctrl: add i.MX8MP VPU blk ctrl") Signed-off-by: Ming Qian <ming.qian@oss.nxp.com> Reviewed-by: Frank Li <Frank.Li@nxp.com> Cc: stable@vger.kernel.org Signed-off-by: Ulf Hansson <ulfh@kernel.org>
Diffstat (limited to 'drivers/pmdomain')
-rw-r--r--drivers/pmdomain/imx/imx8m-blk-ctrl.c15
1 files changed, 15 insertions, 0 deletions
diff --git a/drivers/pmdomain/imx/imx8m-blk-ctrl.c b/drivers/pmdomain/imx/imx8m-blk-ctrl.c
index 479789009c7f..f8105e87ea3c 100644
--- a/drivers/pmdomain/imx/imx8m-blk-ctrl.c
+++ b/drivers/pmdomain/imx/imx8m-blk-ctrl.c
@@ -15,6 +15,7 @@
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <linux/clk.h>
+#include <linux/mutex.h>
#include <dt-bindings/power/imx8mm-power.h>
#include <dt-bindings/power/imx8mn-power.h>
@@ -34,6 +35,12 @@ struct imx8m_blk_ctrl {
struct regmap *regmap;
struct imx8m_blk_ctrl_domain *domains;
struct genpd_onecell_data onecell_data;
+ /*
+ * Serializes the blk-ctrl reset/clock sequence across sibling domains;
+ * their transitions interact through the shared VPUMIX bus domain,
+ * VPU_NOC and the not-ack-verified ADB400 handshake (ERR050531).
+ */
+ struct mutex power_lock;
};
struct imx8m_blk_ctrl_domain_data {
@@ -98,6 +105,8 @@ static int imx8m_blk_ctrl_power_on(struct generic_pm_domain *genpd)
struct imx8m_blk_ctrl *bc = domain->bc;
int ret;
+ guard(mutex)(&bc->power_lock);
+
/* make sure bus domain is awake */
ret = pm_runtime_get_sync(bc->bus_power_dev);
if (ret < 0) {
@@ -164,6 +173,8 @@ static int imx8m_blk_ctrl_power_off(struct generic_pm_domain *genpd)
const struct imx8m_blk_ctrl_domain_data *data = domain->data;
struct imx8m_blk_ctrl *bc = domain->bc;
+ guard(mutex)(&bc->power_lock);
+
/* put devices into reset and disable clocks */
if (data->mipi_phy_rst_mask)
regmap_clear_bits(bc->regmap, BLK_MIPI_RESET_DIV, data->mipi_phy_rst_mask);
@@ -202,6 +213,10 @@ static int imx8m_blk_ctrl_probe(struct platform_device *pdev)
bc->dev = dev;
+ ret = devm_mutex_init(dev, &bc->power_lock);
+ if (ret)
+ return ret;
+
bc_data = of_device_get_match_data(dev);
base = devm_platform_ioremap_resource(pdev, 0);