From nobody Thu Oct 9 01:13:12 2025 Received: from mailout2.w1.samsung.com (mailout2.w1.samsung.com [210.118.77.12]) (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 3EAB6246BB2 for ; Mon, 23 Jun 2025 11:44:37 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=210.118.77.12 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1750679079; cv=none; b=e5NBCVoHwThaavocy3pKamQKgXKawZd2NxM+PLXd/GWDXjvDbxJcV1AyLm7P+zpRRvViBpj3O/GwuO6EHIZfxUjZKzGOP1DrM53SKixq4yK/fNFonAqilhnxgM0VkqeQ9nczSs0LRRlY56tm4ybbtBuavq8ErIbUfDe97RTAvyE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1750679079; c=relaxed/simple; bh=t2xuGN8nfSuPAS/bBmyt96jfSjrysM5nZ74woAU9oDk=; h=From:Date:Subject:MIME-Version:Message-Id:In-Reply-To:To:Cc: Content-Type:References; b=mob7znjHtgsmhZpBzg83Jw1oUEaw2WbRe7NA3QIgmcJ1DfAL1KCsHhfdl2aotWHxQd1xcTbII8YwVHgbo4QMk9et1fg9AFWRb7z4aEsx3BAcnXDoTLGF/DqH1J8c0ECWruLzLFIqGtQej2z2p6zLrYplqneP9lszg8k3963hx98= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=samsung.com; spf=pass smtp.mailfrom=samsung.com; dkim=pass (1024-bit key) header.d=samsung.com header.i=@samsung.com header.b=c9GEN4LL; arc=none smtp.client-ip=210.118.77.12 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=samsung.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=samsung.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=samsung.com header.i=@samsung.com header.b="c9GEN4LL" Received: from eucas1p2.samsung.com (unknown [182.198.249.207]) by mailout2.w1.samsung.com (KnoxPortal) with ESMTP id 20250623114434euoutp02e1d3bdc339f792f536228daae559f0f4~LqVfKe59G1762917629euoutp02I for ; Mon, 23 Jun 2025 11:44:34 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 mailout2.w1.samsung.com 20250623114434euoutp02e1d3bdc339f792f536228daae559f0f4~LqVfKe59G1762917629euoutp02I DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=samsung.com; s=mail20170921; t=1750679074; bh=Rj7R0jtm/OqxhKqDgLBDqK/E3xCykvkcK3rjLxTG3bg=; h=From:Date:Subject:In-Reply-To:To:Cc:References:From; b=c9GEN4LLOI1gwSXtuvBQ9lK8myj8fdTl8CnlvLgSbZ8BZTXvhvs+VdAtXIf4/sYzW oRG1Yy6SxGkqA+azfkJpv+zOErHYU5JgfFZMl7/PuFNYKJ1e6vnnCTUpXc0zEmsB8U pHGZoxZiG8hkpdNQkxHqRdfLyFl1vrPkSyCqzbJE= Received: from eusmtip1.samsung.com (unknown [203.254.199.221]) by eucas1p1.samsung.com (KnoxPortal) with ESMTPA id 20250623114433eucas1p1659c22d6696f3eb51d4169eee80b7cb2~LqVefSZLM1347313473eucas1p1h; Mon, 23 Jun 2025 11:44:33 +0000 (GMT) Received: from AMDC4942.eu.corp.samsungelectronics.net (unknown [106.210.136.40]) by eusmtip1.samsung.com (KnoxPortal) with ESMTPA id 20250623114432eusmtip17cc43a0ff0d845139e39aa6b61cfe777~LqVdbwSyx1396413964eusmtip1I; Mon, 23 Jun 2025 11:44:32 +0000 (GMT) From: Michal Wilczynski Date: Mon, 23 Jun 2025 13:42:42 +0200 Subject: [PATCH v6 4/8] drm/imagination: Use pwrseq for TH1520 GPU power management Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Message-Id: <20250623-apr_14_for_sending-v6-4-6583ce0f6c25@samsung.com> In-Reply-To: <20250623-apr_14_for_sending-v6-0-6583ce0f6c25@samsung.com> To: Drew Fustini , Guo Ren , Fu Wei , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Michal Wilczynski , Bartosz Golaszewski , Philipp Zabel , Frank Binns , Matt Coster , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Simona Vetter , Paul Walmsley , Palmer Dabbelt , Albert Ou , Alexandre Ghiti , Ulf Hansson , Marek Szyprowski Cc: linux-riscv@lists.infradead.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-pm@vger.kernel.org, dri-devel@lists.freedesktop.org, Bartosz Golaszewski X-Mailer: b4 0.15-dev X-CMS-MailID: 20250623114433eucas1p1659c22d6696f3eb51d4169eee80b7cb2 X-Msg-Generator: CA Content-Type: text/plain; charset="utf-8" X-RootMTR: 20250623114433eucas1p1659c22d6696f3eb51d4169eee80b7cb2 X-EPHeader: CA X-CMS-RootMailID: 20250623114433eucas1p1659c22d6696f3eb51d4169eee80b7cb2 References: <20250623-apr_14_for_sending-v6-0-6583ce0f6c25@samsung.com> Update the Imagination PVR DRM driver to leverage the pwrseq framework for managing the power sequence of the GPU on the T-HEAD TH1520 SoC. To cleanly handle the TH1520's specific power requirements in the generic driver, this patch implements the "driver match data" pattern. The pvr_soc_data struct, associated with a compatible string in the of_device_id table, now holds pointers to platform-specific power_on and power_off functions. At probe time, the driver inspects the assigned power_on function pointer. If it points to the pwrseq variant, the driver calls devm_pwrseq_get("gpu-power"), requiring a valid sequencer and deferring probe on failure. Otherwise, it falls back to its standard manual reset initialization. The runtime PM callbacks, pvr_power_device_resume() and pvr_power_device_suspend(), call the power_on and power_off function pointers. Helper functions for both manual and pwrseq-based sequences are introduced to support this. Reviewed-by: Ulf Hansson Reviewed-by: Bartosz Golaszewski Signed-off-by: Michal Wilczynski --- drivers/gpu/drm/imagination/Kconfig | 1 + drivers/gpu/drm/imagination/pvr_device.c | 31 +++++++-- drivers/gpu/drm/imagination/pvr_device.h | 19 ++++++ drivers/gpu/drm/imagination/pvr_drv.c | 30 ++++++++- drivers/gpu/drm/imagination/pvr_power.c | 112 ++++++++++++++++++++-------= ---- drivers/gpu/drm/imagination/pvr_power.h | 6 ++ 6 files changed, 152 insertions(+), 47 deletions(-) diff --git a/drivers/gpu/drm/imagination/Kconfig b/drivers/gpu/drm/imaginat= ion/Kconfig index 3bfa2ac212dccb73c53bdc2bc259bcba636e7cfc..5f9fff43d6baadc42ebf48d9172= 9bfbf27e06caa 100644 --- a/drivers/gpu/drm/imagination/Kconfig +++ b/drivers/gpu/drm/imagination/Kconfig @@ -11,6 +11,7 @@ config DRM_POWERVR select DRM_SCHED select DRM_GPUVM select FW_LOADER + select POWER_SEQUENCING help Choose this option if you have a system that has an Imagination Technologies PowerVR (Series 6 or later) or IMG GPU. diff --git a/drivers/gpu/drm/imagination/pvr_device.c b/drivers/gpu/drm/ima= gination/pvr_device.c index 8b9ba4983c4cb5bc40342fcafc4259078bc70547..c1c24c441c821ccce59f7cd3f14= 544a91ef54ea9 100644 --- a/drivers/gpu/drm/imagination/pvr_device.c +++ b/drivers/gpu/drm/imagination/pvr_device.c @@ -23,8 +23,10 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -618,6 +620,9 @@ pvr_device_init(struct pvr_device *pvr_dev) struct device *dev =3D drm_dev->dev; int err; =20 + /* Get the platform-specific data based on the compatible string. */ + pvr_dev->soc_data =3D of_device_get_match_data(dev); + /* * Setup device parameters. We do this first in case other steps * depend on them. @@ -631,10 +636,28 @@ pvr_device_init(struct pvr_device *pvr_dev) if (err) return err; =20 - /* Get the reset line for the GPU */ - err =3D pvr_device_reset_init(pvr_dev); - if (err) - return err; + /* + * For platforms that require it, get the power sequencer. + * For all others, perform manual reset initialization. + */ + if (pvr_dev->soc_data->power_on =3D=3D pvr_power_on_sequence_pwrseq) { + pvr_dev->pwrseq =3D devm_pwrseq_get(dev, "gpu-power"); + if (IS_ERR(pvr_dev->pwrseq)) { + /* + * This platform requires a sequencer. If we can't get + * it, we must return the error (including -EPROBE_DEFER + * to wait for the provider to appear) + */ + return dev_err_probe( + dev, PTR_ERR(pvr_dev->pwrseq), + "Failed to get required power sequencer\n"); + } + } else { + /* This platform does not use a sequencer, init reset manually. */ + err =3D pvr_device_reset_init(pvr_dev); + if (err) + return err; + } =20 /* Explicitly power the GPU so we can access control registers before the= FW is booted. */ err =3D pm_runtime_resume_and_get(dev); diff --git a/drivers/gpu/drm/imagination/pvr_device.h b/drivers/gpu/drm/ima= gination/pvr_device.h index 7cb01c38d2a9c3fc71effe789d4dfe54eddd93ee..3f35025e84efac031d3261c849e= f9fe105466423 100644 --- a/drivers/gpu/drm/imagination/pvr_device.h +++ b/drivers/gpu/drm/imagination/pvr_device.h @@ -37,6 +37,9 @@ struct clk; /* Forward declaration from . */ struct firmware; =20 +/* Forward declaration from #include #include +#include #include #include #include @@ -234,6 +235,71 @@ pvr_watchdog_init(struct pvr_device *pvr_dev) return 0; } =20 +int pvr_power_on_sequence_pwrseq(struct pvr_device *pvr_dev) +{ + return pwrseq_power_on(pvr_dev->pwrseq); +} + +int pvr_power_off_sequence_pwrseq(struct pvr_device *pvr_dev) +{ + return pwrseq_power_off(pvr_dev->pwrseq); +} + +int pvr_power_on_sequence_manual(struct pvr_device *pvr_dev) +{ + int err; + + err =3D clk_prepare_enable(pvr_dev->core_clk); + if (err) + return err; + + err =3D clk_prepare_enable(pvr_dev->sys_clk); + if (err) + goto err_core_clk_disable; + + err =3D clk_prepare_enable(pvr_dev->mem_clk); + if (err) + goto err_sys_clk_disable; + + /* + * According to the hardware manual, a delay of at least 32 clock + * cycles is required between de-asserting the clkgen reset and + * de-asserting the GPU reset. Assuming a worst-case scenario with + * a very high GPU clock frequency, a delay of 1 microsecond is + * sufficient to ensure this requirement is met across all + * feasible GPU clock speeds. + */ + udelay(1); + + err =3D reset_control_deassert(pvr_dev->reset); + if (err) + goto err_mem_clk_disable; + + return 0; + +err_mem_clk_disable: + clk_disable_unprepare(pvr_dev->mem_clk); +err_sys_clk_disable: + clk_disable_unprepare(pvr_dev->sys_clk); +err_core_clk_disable: + clk_disable_unprepare(pvr_dev->core_clk); + + return err; +} + +int pvr_power_off_sequence_manual(struct pvr_device *pvr_dev) +{ + int err; + + err =3D reset_control_assert(pvr_dev->reset); + + clk_disable_unprepare(pvr_dev->mem_clk); + clk_disable_unprepare(pvr_dev->sys_clk); + clk_disable_unprepare(pvr_dev->core_clk); + + return err; +} + int pvr_power_device_suspend(struct device *dev) { @@ -252,11 +318,7 @@ pvr_power_device_suspend(struct device *dev) goto err_drm_dev_exit; } =20 - clk_disable_unprepare(pvr_dev->mem_clk); - clk_disable_unprepare(pvr_dev->sys_clk); - clk_disable_unprepare(pvr_dev->core_clk); - - err =3D reset_control_assert(pvr_dev->reset); + err =3D pvr_dev->soc_data->power_off(pvr_dev); =20 err_drm_dev_exit: drm_dev_exit(idx); @@ -276,54 +338,22 @@ pvr_power_device_resume(struct device *dev) if (!drm_dev_enter(drm_dev, &idx)) return -EIO; =20 - err =3D clk_prepare_enable(pvr_dev->core_clk); + err =3D pvr_dev->soc_data->power_on(pvr_dev); if (err) goto err_drm_dev_exit; =20 - err =3D clk_prepare_enable(pvr_dev->sys_clk); - if (err) - goto err_core_clk_disable; - - err =3D clk_prepare_enable(pvr_dev->mem_clk); - if (err) - goto err_sys_clk_disable; - - /* - * According to the hardware manual, a delay of at least 32 clock - * cycles is required between de-asserting the clkgen reset and - * de-asserting the GPU reset. Assuming a worst-case scenario with - * a very high GPU clock frequency, a delay of 1 microsecond is - * sufficient to ensure this requirement is met across all - * feasible GPU clock speeds. - */ - udelay(1); - - err =3D reset_control_deassert(pvr_dev->reset); - if (err) - goto err_mem_clk_disable; - if (pvr_dev->fw_dev.booted) { err =3D pvr_power_fw_enable(pvr_dev); if (err) - goto err_reset_assert; + goto err_power_off; } =20 drm_dev_exit(idx); =20 return 0; =20 -err_reset_assert: - reset_control_assert(pvr_dev->reset); - -err_mem_clk_disable: - clk_disable_unprepare(pvr_dev->mem_clk); - -err_sys_clk_disable: - clk_disable_unprepare(pvr_dev->sys_clk); - -err_core_clk_disable: - clk_disable_unprepare(pvr_dev->core_clk); - +err_power_off: + pvr_dev->soc_data->power_off(pvr_dev); err_drm_dev_exit: drm_dev_exit(idx); =20 diff --git a/drivers/gpu/drm/imagination/pvr_power.h b/drivers/gpu/drm/imag= ination/pvr_power.h index ada85674a7ca762dcf92df40424230e1c3910342..d91d5f3f39b61f81121357f4187= b1a6e09b3dec0 100644 --- a/drivers/gpu/drm/imagination/pvr_power.h +++ b/drivers/gpu/drm/imagination/pvr_power.h @@ -41,4 +41,10 @@ pvr_power_put(struct pvr_device *pvr_dev) int pvr_power_domains_init(struct pvr_device *pvr_dev); void pvr_power_domains_fini(struct pvr_device *pvr_dev); =20 +/* Power sequence functions */ +int pvr_power_on_sequence_manual(struct pvr_device *pvr_dev); +int pvr_power_off_sequence_manual(struct pvr_device *pvr_dev); +int pvr_power_on_sequence_pwrseq(struct pvr_device *pvr_dev); +int pvr_power_off_sequence_pwrseq(struct pvr_device *pvr_dev); + #endif /* PVR_POWER_H */ --=20 2.34.1