From patchwork Wed Dec 11 14:26:51 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sebastian Reichel X-Patchwork-Id: 849618 Received: from bali.collaboradmins.com (bali.collaboradmins.com [148.251.105.195]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8BEFE1AB533; Wed, 11 Dec 2024 14:30:51 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.251.105.195 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1733927455; cv=none; b=mY8jFIYYyQ7bfGQ7hHdgXSyQF4ZZRleR2Md3SuDo2vctieQOvUrcj2Dy+pxkJKEQ70PL+kyV9KGivZrgPfAuRJtbIzJq4EdUjniDTSByWMyIctosdLytgIiJ6uC5u0gi8muV2L3v/Y2+NwP017Xs8QvnhFMqnrEGNn8zLIJfNgQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1733927455; c=relaxed/simple; bh=dS+Z9hSyHNd7E2PNPV3byhFSLmg7UwMv7UmKoykDv6w=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=M4lL2ysofsQWPbcqe9la7j3IKGiB4GsLNjFY7a4oWZ1fDKQYKFTHShx6gEGWK5H0+kqlKLMmcxlVmkl6/ttMG2ekwtytMCqRyM+JnfIxtL5nEXvycAvddiaelaPEs2taJJUXCTx5Gvghu0+fXJtP8KM0aMGzlEAJyqTT9fYmyI0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com; spf=pass smtp.mailfrom=collabora.com; dkim=pass (2048-bit key) header.d=collabora.com header.i=@collabora.com header.b=YczNwWRI; arc=none smtp.client-ip=148.251.105.195 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=collabora.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=collabora.com header.i=@collabora.com header.b="YczNwWRI" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=collabora.com; s=mail; t=1733927446; bh=dS+Z9hSyHNd7E2PNPV3byhFSLmg7UwMv7UmKoykDv6w=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=YczNwWRI45UlU2OziCVY6EoYmbUnvMh07oapxBp0cXxy5I6Ymai+B4FFW4QrKTxRo c5Ljp0ilaqY2j8/FsbRXVNfruH8LODHLF7Pt2po8U9FwHuF5XypH/nwyvzJUi6ooD8 a0v5SUU37tSIvvtwzJ1PkuCiv6RJaHqqJBX9TNNslMdQCPEH9aJinGehC3PdMobHXM mKTiF1FEElnMYdVovhqYHMggavNsAqtPPC9Cg2rQR8XmrgpXoJugpf+S2Y8H2nIVBe bxkr4LGo+ojrreWeDGvIGQfvFjNFMbS1GrwySGsIvV7pD29YFr3KtKzWJ/QQJejPFl bFyDYWuH4Se+g== Received: from jupiter.universe (dyndsl-091-248-215-089.ewe-ip-backbone.de [91.248.215.89]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) (Authenticated sender: sre) by bali.collaboradmins.com (Postfix) with ESMTPSA id 971B817E3780; Wed, 11 Dec 2024 15:30:46 +0100 (CET) Received: by jupiter.universe (Postfix, from userid 1000) id 81D3748CC90; Wed, 11 Dec 2024 15:30:45 +0100 (CET) From: Sebastian Reichel To: Rob Herring , Krzysztof Kozlowski , Conor Dooley , Heiko Stuebner , Ulf Hansson , Mark Brown Cc: Liam Girdwood , Elaine Zhang , =?utf-8?q?Adri=C3=A1n_Mart=C3=ADne?= =?utf-8?q?z_Larumbe?= , Boris Brezillon , Chen-Yu Tsai , devicetree@vger.kernel.org, linux-rockchip@lists.infradead.org, linux-kernel@vger.kernel.org, linux-pm@vger.kernel.org, Sebastian Reichel , kernel@collabora.com Subject: [PATCH v5 6/7] pmdomain: rockchip: add regulator support Date: Wed, 11 Dec 2024 15:26:51 +0100 Message-ID: <20241211143044.9550-7-sebastian.reichel@collabora.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20241211143044.9550-1-sebastian.reichel@collabora.com> References: <20241211143044.9550-1-sebastian.reichel@collabora.com> Precedence: bulk X-Mailing-List: linux-pm@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Some power domains require extra voltages to be applied. For example trying to enable the GPU power domain on RK3588 fails when the SoC does not have VDD GPU enabled. The same is expected to happen for the NPU, which also has a dedicated supply line. We get the regulator using devm_of_regulator_get(), so a missing dependency in the devicetree is handled gracefully by printing a warning and creating a dummy regulator. This is necessary, since existing DTs do not have the regulator described. They might still work if the regulator is marked as always-on. It is also working if the regulator is enabled at boot time and the GPU driver is probed before the kernel disables unused regulators. The regulator itself is not acquired at driver probe time, since that creates an unsolvable circular dependency. The power domain driver must be probed early, since SoC peripherals need it. Regulators on the other hand depend on SoC peripherals like SPI, I2C or GPIO. MediaTek does not run into this, since they have two power domain drivers. Tested-by: Heiko Stuebner Signed-off-by: Sebastian Reichel --- drivers/pmdomain/rockchip/pm-domains.c | 113 +++++++++++++++++-------- 1 file changed, 79 insertions(+), 34 deletions(-) diff --git a/drivers/pmdomain/rockchip/pm-domains.c b/drivers/pmdomain/rockchip/pm-domains.c index f4e555dac20a..31c71b6fddf1 100644 --- a/drivers/pmdomain/rockchip/pm-domains.c +++ b/drivers/pmdomain/rockchip/pm-domains.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -44,6 +45,7 @@ struct rockchip_domain_info { int idle_mask; int ack_mask; bool active_wakeup; + bool need_regulator; int pwr_w_mask; int req_w_mask; int clk_ungate_mask; @@ -92,6 +94,8 @@ struct rockchip_pm_domain { u32 *qos_save_regs[MAX_QOS_REGS_NUM]; int num_clks; struct clk_bulk_data *clks; + struct device_node *node; + struct regulator *supply; }; struct rockchip_pmu { @@ -129,7 +133,7 @@ struct rockchip_pmu { .active_wakeup = wakeup, \ } -#define DOMAIN_M_O_R(_name, p_offset, pwr, status, m_offset, m_status, r_status, r_offset, req, idle, ack, wakeup) \ +#define DOMAIN_M_O_R(_name, p_offset, pwr, status, m_offset, m_status, r_status, r_offset, req, idle, ack, wakeup, regulator) \ { \ .name = _name, \ .pwr_offset = p_offset, \ @@ -145,6 +149,7 @@ struct rockchip_pmu { .idle_mask = (idle), \ .ack_mask = (ack), \ .active_wakeup = wakeup, \ + .need_regulator = regulator, \ } #define DOMAIN_M_O_R_G(_name, p_offset, pwr, status, m_offset, m_status, r_status, r_offset, req, idle, ack, g_mask, wakeup) \ @@ -303,8 +308,8 @@ void rockchip_pmu_unblock(void) } EXPORT_SYMBOL_GPL(rockchip_pmu_unblock); -#define DOMAIN_RK3588(name, p_offset, pwr, status, m_offset, m_status, r_status, r_offset, req, idle, wakeup) \ - DOMAIN_M_O_R(name, p_offset, pwr, status, m_offset, m_status, r_status, r_offset, req, idle, idle, wakeup) +#define DOMAIN_RK3588(name, p_offset, pwr, status, m_offset, m_status, r_status, r_offset, req, idle, wakeup, regulator) \ + DOMAIN_M_O_R(name, p_offset, pwr, status, m_offset, m_status, r_status, r_offset, req, idle, idle, wakeup, regulator) static bool rockchip_pmu_domain_is_idle(struct rockchip_pm_domain *pd) { @@ -619,18 +624,57 @@ static int rockchip_pd_power(struct rockchip_pm_domain *pd, bool power_on) return 0; } +static int rockchip_pd_regulator_disable(struct rockchip_pm_domain *pd) +{ + return IS_ERR_OR_NULL(pd->supply) ? 0 : regulator_disable(pd->supply); +} + +static int rockchip_pd_regulator_enable(struct rockchip_pm_domain *pd) +{ + struct rockchip_pmu *pmu = pd->pmu; + + if (!pd->info->need_regulator) + return 0; + + if (IS_ERR_OR_NULL(pd->supply)) { + pd->supply = devm_of_regulator_get(pmu->dev, pd->node, "domain"); + + if (IS_ERR(pd->supply)) + return PTR_ERR(pd->supply); + } + + return regulator_enable(pd->supply); +} + static int rockchip_pd_power_on(struct generic_pm_domain *domain) { struct rockchip_pm_domain *pd = to_rockchip_pd(domain); + int ret; + + ret = rockchip_pd_regulator_enable(pd); + if (ret) { + dev_err(pd->pmu->dev, "Failed to enable supply: %d\n", ret); + return ret; + } - return rockchip_pd_power(pd, true); + ret = rockchip_pd_power(pd, true); + if (ret) + rockchip_pd_regulator_disable(pd); + + return ret; } static int rockchip_pd_power_off(struct generic_pm_domain *domain) { struct rockchip_pm_domain *pd = to_rockchip_pd(domain); + int ret; - return rockchip_pd_power(pd, false); + ret = rockchip_pd_power(pd, false); + if (ret) + return ret; + + rockchip_pd_regulator_disable(pd); + return ret; } static int rockchip_pd_attach_dev(struct generic_pm_domain *genpd, @@ -711,6 +755,7 @@ static int rockchip_pm_add_one_domain(struct rockchip_pmu *pmu, pd->info = pd_info; pd->pmu = pmu; + pd->node = node; pd->num_clks = of_clk_get_parent_count(node); if (pd->num_clks > 0) { @@ -1174,35 +1219,35 @@ static const struct rockchip_domain_info rk3576_pm_domains[] = { }; static const struct rockchip_domain_info rk3588_pm_domains[] = { - [RK3588_PD_GPU] = DOMAIN_RK3588("gpu", 0x0, BIT(0), 0, 0x0, 0, BIT(1), 0x0, BIT(0), BIT(0), false), - [RK3588_PD_NPU] = DOMAIN_RK3588("npu", 0x0, BIT(1), BIT(1), 0x0, 0, 0, 0x0, 0, 0, false), - [RK3588_PD_VCODEC] = DOMAIN_RK3588("vcodec", 0x0, BIT(2), BIT(2), 0x0, 0, 0, 0x0, 0, 0, false), - [RK3588_PD_NPUTOP] = DOMAIN_RK3588("nputop", 0x0, BIT(3), 0, 0x0, BIT(11), BIT(2), 0x0, BIT(1), BIT(1), false), - [RK3588_PD_NPU1] = DOMAIN_RK3588("npu1", 0x0, BIT(4), 0, 0x0, BIT(12), BIT(3), 0x0, BIT(2), BIT(2), false), - [RK3588_PD_NPU2] = DOMAIN_RK3588("npu2", 0x0, BIT(5), 0, 0x0, BIT(13), BIT(4), 0x0, BIT(3), BIT(3), false), - [RK3588_PD_VENC0] = DOMAIN_RK3588("venc0", 0x0, BIT(6), 0, 0x0, BIT(14), BIT(5), 0x0, BIT(4), BIT(4), false), - [RK3588_PD_VENC1] = DOMAIN_RK3588("venc1", 0x0, BIT(7), 0, 0x0, BIT(15), BIT(6), 0x0, BIT(5), BIT(5), false), - [RK3588_PD_RKVDEC0] = DOMAIN_RK3588("rkvdec0", 0x0, BIT(8), 0, 0x0, BIT(16), BIT(7), 0x0, BIT(6), BIT(6), false), - [RK3588_PD_RKVDEC1] = DOMAIN_RK3588("rkvdec1", 0x0, BIT(9), 0, 0x0, BIT(17), BIT(8), 0x0, BIT(7), BIT(7), false), - [RK3588_PD_VDPU] = DOMAIN_RK3588("vdpu", 0x0, BIT(10), 0, 0x0, BIT(18), BIT(9), 0x0, BIT(8), BIT(8), false), - [RK3588_PD_RGA30] = DOMAIN_RK3588("rga30", 0x0, BIT(11), 0, 0x0, BIT(19), BIT(10), 0x0, 0, 0, false), - [RK3588_PD_AV1] = DOMAIN_RK3588("av1", 0x0, BIT(12), 0, 0x0, BIT(20), BIT(11), 0x0, BIT(9), BIT(9), false), - [RK3588_PD_VI] = DOMAIN_RK3588("vi", 0x0, BIT(13), 0, 0x0, BIT(21), BIT(12), 0x0, BIT(10), BIT(10), false), - [RK3588_PD_FEC] = DOMAIN_RK3588("fec", 0x0, BIT(14), 0, 0x0, BIT(22), BIT(13), 0x0, 0, 0, false), - [RK3588_PD_ISP1] = DOMAIN_RK3588("isp1", 0x0, BIT(15), 0, 0x0, BIT(23), BIT(14), 0x0, BIT(11), BIT(11), false), - [RK3588_PD_RGA31] = DOMAIN_RK3588("rga31", 0x4, BIT(0), 0, 0x0, BIT(24), BIT(15), 0x0, BIT(12), BIT(12), false), - [RK3588_PD_VOP] = DOMAIN_RK3588("vop", 0x4, BIT(1), 0, 0x0, BIT(25), BIT(16), 0x0, BIT(13) | BIT(14), BIT(13) | BIT(14), false), - [RK3588_PD_VO0] = DOMAIN_RK3588("vo0", 0x4, BIT(2), 0, 0x0, BIT(26), BIT(17), 0x0, BIT(15), BIT(15), false), - [RK3588_PD_VO1] = DOMAIN_RK3588("vo1", 0x4, BIT(3), 0, 0x0, BIT(27), BIT(18), 0x4, BIT(0), BIT(16), false), - [RK3588_PD_AUDIO] = DOMAIN_RK3588("audio", 0x4, BIT(4), 0, 0x0, BIT(28), BIT(19), 0x4, BIT(1), BIT(17), false), - [RK3588_PD_PHP] = DOMAIN_RK3588("php", 0x4, BIT(5), 0, 0x0, BIT(29), BIT(20), 0x4, BIT(5), BIT(21), false), - [RK3588_PD_GMAC] = DOMAIN_RK3588("gmac", 0x4, BIT(6), 0, 0x0, BIT(30), BIT(21), 0x0, 0, 0, false), - [RK3588_PD_PCIE] = DOMAIN_RK3588("pcie", 0x4, BIT(7), 0, 0x0, BIT(31), BIT(22), 0x0, 0, 0, true), - [RK3588_PD_NVM] = DOMAIN_RK3588("nvm", 0x4, BIT(8), BIT(24), 0x4, 0, 0, 0x4, BIT(2), BIT(18), false), - [RK3588_PD_NVM0] = DOMAIN_RK3588("nvm0", 0x4, BIT(9), 0, 0x4, BIT(1), BIT(23), 0x0, 0, 0, false), - [RK3588_PD_SDIO] = DOMAIN_RK3588("sdio", 0x4, BIT(10), 0, 0x4, BIT(2), BIT(24), 0x4, BIT(3), BIT(19), false), - [RK3588_PD_USB] = DOMAIN_RK3588("usb", 0x4, BIT(11), 0, 0x4, BIT(3), BIT(25), 0x4, BIT(4), BIT(20), true), - [RK3588_PD_SDMMC] = DOMAIN_RK3588("sdmmc", 0x4, BIT(13), 0, 0x4, BIT(5), BIT(26), 0x0, 0, 0, false), + [RK3588_PD_GPU] = DOMAIN_RK3588("gpu", 0x0, BIT(0), 0, 0x0, 0, BIT(1), 0x0, BIT(0), BIT(0), false, true), + [RK3588_PD_NPU] = DOMAIN_RK3588("npu", 0x0, BIT(1), BIT(1), 0x0, 0, 0, 0x0, 0, 0, false, true), + [RK3588_PD_VCODEC] = DOMAIN_RK3588("vcodec", 0x0, BIT(2), BIT(2), 0x0, 0, 0, 0x0, 0, 0, false, false), + [RK3588_PD_NPUTOP] = DOMAIN_RK3588("nputop", 0x0, BIT(3), 0, 0x0, BIT(11), BIT(2), 0x0, BIT(1), BIT(1), false, false), + [RK3588_PD_NPU1] = DOMAIN_RK3588("npu1", 0x0, BIT(4), 0, 0x0, BIT(12), BIT(3), 0x0, BIT(2), BIT(2), false, false), + [RK3588_PD_NPU2] = DOMAIN_RK3588("npu2", 0x0, BIT(5), 0, 0x0, BIT(13), BIT(4), 0x0, BIT(3), BIT(3), false, false), + [RK3588_PD_VENC0] = DOMAIN_RK3588("venc0", 0x0, BIT(6), 0, 0x0, BIT(14), BIT(5), 0x0, BIT(4), BIT(4), false, false), + [RK3588_PD_VENC1] = DOMAIN_RK3588("venc1", 0x0, BIT(7), 0, 0x0, BIT(15), BIT(6), 0x0, BIT(5), BIT(5), false, false), + [RK3588_PD_RKVDEC0] = DOMAIN_RK3588("rkvdec0", 0x0, BIT(8), 0, 0x0, BIT(16), BIT(7), 0x0, BIT(6), BIT(6), false, false), + [RK3588_PD_RKVDEC1] = DOMAIN_RK3588("rkvdec1", 0x0, BIT(9), 0, 0x0, BIT(17), BIT(8), 0x0, BIT(7), BIT(7), false, false), + [RK3588_PD_VDPU] = DOMAIN_RK3588("vdpu", 0x0, BIT(10), 0, 0x0, BIT(18), BIT(9), 0x0, BIT(8), BIT(8), false, false), + [RK3588_PD_RGA30] = DOMAIN_RK3588("rga30", 0x0, BIT(11), 0, 0x0, BIT(19), BIT(10), 0x0, 0, 0, false, false), + [RK3588_PD_AV1] = DOMAIN_RK3588("av1", 0x0, BIT(12), 0, 0x0, BIT(20), BIT(11), 0x0, BIT(9), BIT(9), false, false), + [RK3588_PD_VI] = DOMAIN_RK3588("vi", 0x0, BIT(13), 0, 0x0, BIT(21), BIT(12), 0x0, BIT(10), BIT(10), false, false), + [RK3588_PD_FEC] = DOMAIN_RK3588("fec", 0x0, BIT(14), 0, 0x0, BIT(22), BIT(13), 0x0, 0, 0, false, false), + [RK3588_PD_ISP1] = DOMAIN_RK3588("isp1", 0x0, BIT(15), 0, 0x0, BIT(23), BIT(14), 0x0, BIT(11), BIT(11), false, false), + [RK3588_PD_RGA31] = DOMAIN_RK3588("rga31", 0x4, BIT(0), 0, 0x0, BIT(24), BIT(15), 0x0, BIT(12), BIT(12), false, false), + [RK3588_PD_VOP] = DOMAIN_RK3588("vop", 0x4, BIT(1), 0, 0x0, BIT(25), BIT(16), 0x0, BIT(13) | BIT(14), BIT(13) | BIT(14), false, false), + [RK3588_PD_VO0] = DOMAIN_RK3588("vo0", 0x4, BIT(2), 0, 0x0, BIT(26), BIT(17), 0x0, BIT(15), BIT(15), false, false), + [RK3588_PD_VO1] = DOMAIN_RK3588("vo1", 0x4, BIT(3), 0, 0x0, BIT(27), BIT(18), 0x4, BIT(0), BIT(16), false, false), + [RK3588_PD_AUDIO] = DOMAIN_RK3588("audio", 0x4, BIT(4), 0, 0x0, BIT(28), BIT(19), 0x4, BIT(1), BIT(17), false, false), + [RK3588_PD_PHP] = DOMAIN_RK3588("php", 0x4, BIT(5), 0, 0x0, BIT(29), BIT(20), 0x4, BIT(5), BIT(21), false, false), + [RK3588_PD_GMAC] = DOMAIN_RK3588("gmac", 0x4, BIT(6), 0, 0x0, BIT(30), BIT(21), 0x0, 0, 0, false, false), + [RK3588_PD_PCIE] = DOMAIN_RK3588("pcie", 0x4, BIT(7), 0, 0x0, BIT(31), BIT(22), 0x0, 0, 0, true, false), + [RK3588_PD_NVM] = DOMAIN_RK3588("nvm", 0x4, BIT(8), BIT(24), 0x4, 0, 0, 0x4, BIT(2), BIT(18), false, false), + [RK3588_PD_NVM0] = DOMAIN_RK3588("nvm0", 0x4, BIT(9), 0, 0x4, BIT(1), BIT(23), 0x0, 0, 0, false, false), + [RK3588_PD_SDIO] = DOMAIN_RK3588("sdio", 0x4, BIT(10), 0, 0x4, BIT(2), BIT(24), 0x4, BIT(3), BIT(19), false, false), + [RK3588_PD_USB] = DOMAIN_RK3588("usb", 0x4, BIT(11), 0, 0x4, BIT(3), BIT(25), 0x4, BIT(4), BIT(20), true, false), + [RK3588_PD_SDMMC] = DOMAIN_RK3588("sdmmc", 0x4, BIT(13), 0, 0x4, BIT(5), BIT(26), 0x0, 0, 0, false, false), }; static const struct rockchip_pmu_info px30_pmu = {