From nobody Thu Dec 18 23:41:05 2025 Received: from mx08-00376f01.pphosted.com (mx08-00376f01.pphosted.com [91.207.212.86]) (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 8C48926FA4D; Thu, 10 Apr 2025 10:06:12 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=91.207.212.86 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744279576; cv=none; b=haLXtSngHd9yJpeZJzsruQhUXz/b7DL0QWPziadQTeWmqGfqd++/o2guvljwVMbURQGvPw45WIgcjOXenwPMWXxgoAgthI9Op1AON9Cm49CLghA9rDnHg6km+HnbkCbiagLizuOCzzaf1uD29vP/ZkAxuYXklAY+NmY2zuGnqEM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744279576; c=relaxed/simple; bh=zQRq630D+cdbXxy/xhQQqYzzty8W27NaB8MrgAU75F0=; h=From:Date:Subject:MIME-Version:Content-Type:Message-ID:References: In-Reply-To:To:CC; b=aeRMEOI7f44F4J8SXGeSKt6kws6SpcfxcNbZWr0l38GqtcGcIYJoGMy5omOMF5wDuZCfGW4W2sioT++BnY3TNY+6KaVPOALeiYSHQqZU09gYg1vlA55Y7j6mfjwKl+ZoFyDDunmPyMtfl++4P21ky2tEDDg0sjQv/Ns1bM91TtM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=imgtec.com; spf=pass smtp.mailfrom=imgtec.com; dkim=pass (2048-bit key) header.d=imgtec.com header.i=@imgtec.com header.b=NbseA5xx; arc=none smtp.client-ip=91.207.212.86 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=imgtec.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=imgtec.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=imgtec.com header.i=@imgtec.com header.b="NbseA5xx" Received: from pps.filterd (m0168888.ppops.net [127.0.0.1]) by mx08-00376f01.pphosted.com (8.18.1.2/8.18.1.2) with ESMTP id 53A62MMH009620; Thu, 10 Apr 2025 10:55:21 +0100 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=imgtec.com; h=cc :content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=dk201812; bh=w 10ku9+QGCxyS3AMeDqcOwgnGjg9TRecUeu2KHERN88=; b=NbseA5xxLP3xHOAYK 7f6Tp5wgNvMfDV+SPKHg5XLfxD6OXDNGpdBUmv660He0Iilf51+ZRgzficAIDQCN lDk9LSd/tUamscP/e/6BoTxrz1lAq2HAF65qaMCxxibVRoIZNolxMKAT90PKZ+Z6 MYxlIfzNoU553MKDUzoYLGxDcaF9cqiL/4geMwsKn32GrlYHbvurjrdk/oCrqhRq zmbVKspV7IU+D0u4ulYEaDITkgwZy80S3hsgGAHkfuhn0BwZz9nD/6kjx7IozGb2 UAMizKFsYTVQ33d+Ls+vlc4RgLv8LCrBYKIzPsTZP20h55TGda7GXzjHIQS9/GMz 2Hrdw== Received: from hhmail05.hh.imgtec.org (83-244-153-141.cust-83.exponential-e.net [83.244.153.141]) by mx08-00376f01.pphosted.com (PPS) with ESMTPS id 45ttssbgdy-6 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128 verify=NOT); Thu, 10 Apr 2025 10:55:21 +0100 (BST) Received: from 1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa (172.25.6.134) by HHMAIL05.hh.imgtec.org (10.100.10.120) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.44; Thu, 10 Apr 2025 10:55:19 +0100 From: Matt Coster Date: Thu, 10 Apr 2025 10:55:04 +0100 Subject: [PATCH v6 05/18] drm/imagination: Add power domain control Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-ID: <20250410-sets-bxs-4-64-patch-v1-v6-5-eda620c5865f@imgtec.com> References: <20250410-sets-bxs-4-64-patch-v1-v6-0-eda620c5865f@imgtec.com> In-Reply-To: <20250410-sets-bxs-4-64-patch-v1-v6-0-eda620c5865f@imgtec.com> To: Frank Binns , Matt Coster , David Airlie , Simona Vetter , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Nishanth Menon , "Vignesh Raghavendra" , Tero Kristo CC: , , , , Randolph Sapp , Darren Etheridge , "Michal Wilczynski" , Alessio Belle , Alexandru Dadu X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=7444; i=matt.coster@imgtec.com; h=from:subject:message-id; bh=zQRq630D+cdbXxy/xhQQqYzzty8W27NaB8MrgAU75F0=; b=owGbwMvMwCFWuUfy8817WRsYT6slMaR/n9q4UOrQ8bX7qi2lFSxZ9b9J/5p2/qv0rOTyA1OfW Ynvu8Sl0VHKwiDGwSArpsiyY4XlCrU/aloSN34Vw8xhZQIZwsDFKQATyV3MyDDnYZtwSUmb2Qam hQIbJthOkmBqDPp9Oybx1GJ/H6fCmosM/+sqPrdPcPKfm/fl/cOp0wxnRi4yDbE7ofZxr+x7nQp HL3YA X-Developer-Key: i=matt.coster@imgtec.com; a=openpgp; fpr=05A40CFCE7269D61D97100A1747F0A9036F90DFA X-EXCLAIMER-MD-CONFIG: 15a78312-3e47-46eb-9010-2e54d84a9631 X-Proofpoint-ORIG-GUID: iKNpcMPqa6hFVtqQPSDUAAprQtbbpccu X-Authority-Analysis: v=2.4 cv=I7hlRMgg c=1 sm=1 tr=0 ts=67f79589 cx=c_pps a=AKOq//PuzOIrVTIF9yBwbA==:117 a=AKOq//PuzOIrVTIF9yBwbA==:17 a=UtEzwyU9vMAA:10 a=IkcTkHD0fZMA:10 a=XR8D0OoHHMoA:10 a=VwQbUJbxAAAA:8 a=r_1tXGB3AAAA:8 a=SbYmRvZrNKriMxqfaWcA:9 a=QEXdDO2ut3YA:10 a=t8nPyN_e6usw4ciXM-Pk:22 X-Proofpoint-GUID: iKNpcMPqa6hFVtqQPSDUAAprQtbbpccu The first supported GPU only used a single power domain so this was automatically handled by the device runtime. In order to support multiple power domains, they must be enumerated from devicetree and linked to both the GPU device and each other to ensure correct power sequencing at start time. For all Imagination Rogue GPUs, power domains are named "a", "b", etc. and the sequence A->B->... is always valid for startup with the reverse true for shutdown. Note this is not always the *only* valid sequence, but it's simple and does not require special-casing for different GPU power topologies. Signed-off-by: Matt Coster Reviewed-by: Frank Binns --- Changes in v6: - Add Frank's Rb - Link to v5: https://lore.kernel.org/r/20250326-sets-bxs-4-64-patch-v1-v5-= 5-e4c46e8280a9@imgtec.com Changes in v5: - None - Link to v4: https://lore.kernel.org/r/20250320-sets-bxs-4-64-patch-v1-v4-= 5-d987cf4ca439@imgtec.com Changes in v4: - None - Link to v3: https://lore.kernel.org/r/20250310-sets-bxs-4-64-patch-v1-v3-= 5-143b3dbef02f@imgtec.com Changes in v3: - None - Link to v2: https://lore.kernel.org/r/20241118-sets-bxs-4-64-patch-v1-v2-= 6-3fd45d9fb0cf@imgtec.com Changes in v2: - None - Link to v1: https://lore.kernel.org/r/20241105-sets-bxs-4-64-patch-v1-v1-= 6-4ed30e865892@imgtec.com --- drivers/gpu/drm/imagination/pvr_device.h | 8 +++ drivers/gpu/drm/imagination/pvr_drv.c | 7 ++ drivers/gpu/drm/imagination/pvr_power.c | 114 +++++++++++++++++++++++++++= ++++ drivers/gpu/drm/imagination/pvr_power.h | 3 + 4 files changed, 132 insertions(+) diff --git a/drivers/gpu/drm/imagination/pvr_device.h b/drivers/gpu/drm/ima= gination/pvr_device.h index 6d0dfacb677b46a880f37f419dfa7b67c68fe63d..2dd8a8885fe07078896d669d822= 525fb2b7bab51 100644 --- a/drivers/gpu/drm/imagination/pvr_device.h +++ b/drivers/gpu/drm/imagination/pvr_device.h @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -131,6 +132,13 @@ struct pvr_device { */ struct clk *mem_clk; =20 + struct pvr_device_power { + struct device **domain_devs; + struct device_link **domain_links; + + u32 domain_count; + } power; + /** @irq: IRQ number. */ int irq; =20 diff --git a/drivers/gpu/drm/imagination/pvr_drv.c b/drivers/gpu/drm/imagin= ation/pvr_drv.c index 3130193f8fffc185e630a293be53374bdc4b7ce0..ac4f5855c5692f0956862cebdbf= 76b16d8da9a81 100644 --- a/drivers/gpu/drm/imagination/pvr_drv.c +++ b/drivers/gpu/drm/imagination/pvr_drv.c @@ -1411,6 +1411,10 @@ pvr_probe(struct platform_device *plat_dev) =20 platform_set_drvdata(plat_dev, drm_dev); =20 + err =3D pvr_power_domains_init(pvr_dev); + if (err) + return err; + init_rwsem(&pvr_dev->reset_sem); =20 pvr_context_device_init(pvr_dev); @@ -1450,6 +1454,8 @@ pvr_probe(struct platform_device *plat_dev) err_context_fini: pvr_context_device_fini(pvr_dev); =20 + pvr_power_domains_fini(pvr_dev); + return err; } =20 @@ -1470,6 +1476,7 @@ static void pvr_remove(struct platform_device *plat_d= ev) pvr_watchdog_fini(pvr_dev); pvr_queue_device_fini(pvr_dev); pvr_context_device_fini(pvr_dev); + pvr_power_domains_fini(pvr_dev); } =20 static const struct of_device_id dt_match[] =3D { diff --git a/drivers/gpu/drm/imagination/pvr_power.c b/drivers/gpu/drm/imag= ination/pvr_power.c index ba7816fd28ec77e6ca5ce408302a413ce1afeb6e..19b079b357df78e8bcdecfa377f= c9c05b6e8e4b0 100644 --- a/drivers/gpu/drm/imagination/pvr_power.c +++ b/drivers/gpu/drm/imagination/pvr_power.c @@ -10,10 +10,13 @@ =20 #include #include +#include #include #include #include +#include #include +#include #include #include #include @@ -431,3 +434,114 @@ pvr_watchdog_fini(struct pvr_device *pvr_dev) { cancel_delayed_work_sync(&pvr_dev->watchdog.work); } + +int pvr_power_domains_init(struct pvr_device *pvr_dev) +{ + struct device *dev =3D from_pvr_device(pvr_dev)->dev; + + struct device_link **domain_links __free(kfree) =3D NULL; + struct device **domain_devs __free(kfree) =3D NULL; + int domain_count; + int link_count; + + char dev_name[2] =3D "a"; + int err; + int i; + + domain_count =3D of_count_phandle_with_args(dev->of_node, "power-domains", + "#power-domain-cells"); + if (domain_count < 0) + return domain_count; + + if (domain_count <=3D 1) + return 0; + + link_count =3D domain_count + (domain_count - 1); + + domain_devs =3D kcalloc(domain_count, sizeof(*domain_devs), GFP_KERNEL); + if (!domain_devs) + return -ENOMEM; + + domain_links =3D kcalloc(link_count, sizeof(*domain_links), GFP_KERNEL); + if (!domain_links) + return -ENOMEM; + + for (i =3D 0; i < domain_count; i++) { + struct device *domain_dev; + + dev_name[0] =3D 'a' + i; + domain_dev =3D dev_pm_domain_attach_by_name(dev, dev_name); + if (IS_ERR_OR_NULL(domain_dev)) { + err =3D domain_dev ? PTR_ERR(domain_dev) : -ENODEV; + goto err_detach; + } + + domain_devs[i] =3D domain_dev; + } + + for (i =3D 0; i < domain_count; i++) { + struct device_link *link; + + link =3D device_link_add(dev, domain_devs[i], DL_FLAG_STATELESS | DL_FLA= G_PM_RUNTIME); + if (!link) { + err =3D -ENODEV; + goto err_unlink; + } + + domain_links[i] =3D link; + } + + for (i =3D domain_count; i < link_count; i++) { + struct device_link *link; + + link =3D device_link_add(domain_devs[i - domain_count + 1], + domain_devs[i - domain_count], + DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME); + if (!link) { + err =3D -ENODEV; + goto err_unlink; + } + + domain_links[i] =3D link; + } + + pvr_dev->power =3D (struct pvr_device_power){ + .domain_devs =3D no_free_ptr(domain_devs), + .domain_links =3D no_free_ptr(domain_links), + .domain_count =3D domain_count, + }; + + return 0; + +err_unlink: + while (--i >=3D 0) + device_link_del(domain_links[i]); + + i =3D domain_count; + +err_detach: + while (--i >=3D 0) + dev_pm_domain_detach(domain_devs[i], true); + + return err; +} + +void pvr_power_domains_fini(struct pvr_device *pvr_dev) +{ + const int domain_count =3D pvr_dev->power.domain_count; + + int i =3D domain_count + (domain_count - 1); + + while (--i >=3D 0) + device_link_del(pvr_dev->power.domain_links[i]); + + i =3D domain_count; + + while (--i >=3D 0) + dev_pm_domain_detach(pvr_dev->power.domain_devs[i], true); + + kfree(pvr_dev->power.domain_links); + kfree(pvr_dev->power.domain_devs); + + pvr_dev->power =3D (struct pvr_device_power){ 0 }; +} diff --git a/drivers/gpu/drm/imagination/pvr_power.h b/drivers/gpu/drm/imag= ination/pvr_power.h index 9a9312dcb2dab7d36ee8ff7f69e69d126c5469a9..ada85674a7ca762dcf92df40424= 230e1c3910342 100644 --- a/drivers/gpu/drm/imagination/pvr_power.h +++ b/drivers/gpu/drm/imagination/pvr_power.h @@ -38,4 +38,7 @@ pvr_power_put(struct pvr_device *pvr_dev) return pm_runtime_put(drm_dev->dev); } =20 +int pvr_power_domains_init(struct pvr_device *pvr_dev); +void pvr_power_domains_fini(struct pvr_device *pvr_dev); + #endif /* PVR_POWER_H */ --=20 2.49.0