From nobody Thu Jun 11 09:32:31 2026 Received: from mx0b-0031df01.pphosted.com (mx0b-0031df01.pphosted.com [205.220.180.131]) (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 CE7A54E377C for ; Wed, 13 May 2026 18:14:13 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=205.220.180.131 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778696062; cv=none; b=PG8+YJ2rKhHbM5RgKklnO5+QPh0CLwswfk62GcalulIzA2fqCBUVUtQcHLjilrt6fHNtQ1cQenmXaTgiboQuQ/c3/a3IysgW7B2r192bfzcUUZ7moZYc5Ck5nSILH99orEvV0ascX1G3Yx0s9RtFyhV9uxzsdkn7yXygjr35Ob4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778696062; c=relaxed/simple; bh=CrE39D29SgxYb+LBwhVl7rkpg20tWiPQQLQrO4tMNSI=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=UaPZQW/xbjEzR+jCv5/ciBhMw5PT9DXxWcj3kXczS5Ms3yADkxsYOfZSRlp6JL1T2oUz07gfpwRh+Ie7hq++FegWCavezWuyAlVAMcJVcN+il1iO7nA6ushMtlHPbzMhGxdCxn2ii11Qqt6CgtsnwvSG1gyESq+Hu0lWVY704Nc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=oss.qualcomm.com; spf=pass smtp.mailfrom=oss.qualcomm.com; dkim=pass (2048-bit key) header.d=qualcomm.com header.i=@qualcomm.com header.b=daXTFTDj; dkim=pass (2048-bit key) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com header.b=bhuFfoJY; arc=none smtp.client-ip=205.220.180.131 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=oss.qualcomm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=oss.qualcomm.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=qualcomm.com header.i=@qualcomm.com header.b="daXTFTDj"; dkim=pass (2048-bit key) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com header.b="bhuFfoJY" Received: from pps.filterd (m0279872.ppops.net [127.0.0.1]) by mx0a-0031df01.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 64DF2oVI3474770 for ; Wed, 13 May 2026 18:14:13 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=qualcomm.com; h= cc:content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=qcppdkim1; bh= bNtf2rTstDOk2y7YNVSrw29rKbIKXnvD12lsZDmn42M=; b=daXTFTDjR/e4koca I66avF57xwLiwOanJozZ/zsi+SJM4wyItbDX+0PSQvKcjl7aXhTm42rx2k42GIcp VQ95xvbqCiFeigXrk2/Xal4gxhtXiG1oNgXb+o9ry/ndenKaT7zhZwb880yyKpyg FPun6kPoWO+APi0HweCtBXm5HrqUExqAIMZ6c032TZHl/aE7kIbDsAFxQr/+7ZSQ dzGUWJzqEJRiVIhqcJytSMv4lnnmGHeeqeXiBNBISs3lD9Zsn7PwsK/Jn7W/FwYi gusgU6DEmY/8jWhJKOFavswS9SB4VNv8neXy+Mbwy4pcsmPd/oPk7g/YreQ5g63n X2ZbBw== Received: from mail-ua1-f69.google.com (mail-ua1-f69.google.com [209.85.222.69]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 4e4p41a7r2-1 (version=TLSv1.3 cipher=TLS_AES_128_GCM_SHA256 bits=128 verify=NOT) for ; Wed, 13 May 2026 18:14:12 +0000 (GMT) Received: by mail-ua1-f69.google.com with SMTP id a1e0cc1a2514c-9518cf3768aso3151769241.2 for ; Wed, 13 May 2026 11:14:12 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oss.qualcomm.com; s=google; t=1778696052; x=1779300852; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=bNtf2rTstDOk2y7YNVSrw29rKbIKXnvD12lsZDmn42M=; b=bhuFfoJYuh7sbNfA/x/LJrgCaeMAEkyqLIx2Rap+fjMRRLoJTkf5AdnMIDTw9SDdUb Ix4m+71ahgY+R3rAkDWju0d42nsOXi0t4YtFF8sqbzUPdTsnYfH3zSi4lAcFGtS8DvIc 2Vf/g/SOLNIXGJ00CAgKxW3WbKvKYQpUrG/xsD7mU8Srh1Gjbu1eyYqZaV186D8i+8ZQ QotRlnBobr4UXwhLSlDiyRiQqJGI1YvpDkOqfr1aLgyYs+4G8Xp0vjTOcCtjdxa6480T suHv8VhT7/L5VOg0ecs8lK3J3DrVpo4c2jTu4emGXqBNkby7Q15QKuP+n5aldCbcz323 xa5w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1778696052; x=1779300852; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-gg:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to; bh=bNtf2rTstDOk2y7YNVSrw29rKbIKXnvD12lsZDmn42M=; b=sqp9OGEVj+DSOQjTpGuMwf6w5Wr1uBxO4UUtzjNXVquGebjzbA21riR/k2d6Uc/1Ls RlKDC4c/Pz4D1y8192IieLLVnc0rCuj0Bn0Czl3f1kPmeuC8MYXmD+/hK8lDxVjrYs1O /Z9uf6LgJbYz7VPJvsFxAtQAL1Mpj8CJh5v59ouNLpH/dja5OvK8CCyxbWHchXfsJR/J PSm4tfbndoVjY3eEce45wm33T8PuPPfRf4Vu4t3mPyyBW0SEJrlYvLbmeOe28pI0V3sP 7y8xDq42VzoyagS57kRO1vpKk5mHQbShlQ8OhJCH4g+eRe1HxWJCxEzGn6QAT5Bb7qB6 Ik4A== X-Gm-Message-State: AOJu0YykeJsnEasXf1m5tEMBbZmvftql1xe/fer91fVI4H9w7bxNHd6G gwzHijPrGUZSMiD1PUbZkeJhscDlOViHqv2wgMY/zeAphpJtacMXotkhmBN4h6dkKdCGUvUWOIm SSChgMHVjrt33NoD+eVxuJ3GPPAG5C/FuY8Y4FuNj9G1AiL5v8PvZd+mSgz7KQjU48E0= X-Gm-Gg: Acq92OHYGizEhGrBtejxm+TTBraJRe3HgCHbu1a4zTMaRpNB2YTceh/jKNlmDCF50qp uBsnWbL2LfLXocqyf+BewfxkwGOgKwYNhMIJ83UEhYBnCJBaztKN3gKD3/eQ79McMT0yH99wYFo jFNslLke/fji1zAdWBjgOxCfA0c44nySmEaXNwsQOzyJbYdBIL7ap/NSURi9LbdXrAwj5wlH4Fk /fm7aeeuVIaw0Qn5tbDkYrfsZValt4mRDVVS36bzgkjBLuA9IaiUUneewBXRKlOQE9SDs8l3Lwf FfNfARPEkeg2WaMF9NgCfMOEakONsWWIkxKHJEvnfnuTG0uwb5l3veKUwFgRnH8eB0NiuyCJJlr izisXNcPojU7+i8i/J9l8DhzFrrQt76+IVXXTaF9jI5N7WSUFsv6YhcONJKKhQ8w+NA2a1fv8wk APAlEsDOVxt7FdI81Gh85C0gsGxBpTc0Aq2+k= X-Received: by 2002:a05:6102:3e14:b0:62f:34db:9474 with SMTP id ada2fe7eead31-63773d164e2mr2482936137.20.1778696050368; Wed, 13 May 2026 11:14:10 -0700 (PDT) X-Received: by 2002:a05:6102:3e14:b0:62f:34db:9474 with SMTP id ada2fe7eead31-63773d164e2mr2482888137.20.1778696049061; Wed, 13 May 2026 11:14:09 -0700 (PDT) Received: from umbar.lan (2001-14ba-a073-af00-264b-feff-fe8b-be8a.rev.dnainternet.fi. [2001:14ba:a073:af00:264b:feff:fe8b:be8a]) by smtp.gmail.com with ESMTPSA id 2adb3069b0e04-5a8bd7d8974sm3174770e87.64.2026.05.13.11.14.07 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 13 May 2026 11:14:07 -0700 (PDT) From: Dmitry Baryshkov Date: Wed, 13 May 2026 21:14:04 +0300 Subject: [PATCH v9 1/5] drm/msm/hdmi: switch to generic PHY subsystem 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: <20260513-fd-hdmi-phy-v9-1-ca98c72f1f9f@oss.qualcomm.com> References: <20260513-fd-hdmi-phy-v9-0-ca98c72f1f9f@oss.qualcomm.com> In-Reply-To: <20260513-fd-hdmi-phy-v9-0-ca98c72f1f9f@oss.qualcomm.com> To: Rob Clark , Dmitry Baryshkov , Abhinav Kumar , Jessica Zhang , Sean Paul , Marijn Suijten , David Airlie , Simona Vetter , Vinod Koul , Neil Armstrong Cc: linux-kernel@vger.kernel.org, linux-arm-msm@vger.kernel.org, dri-devel@lists.freedesktop.org, freedreno@lists.freedesktop.org, linux-phy@lists.infradead.org, Dmitry Baryshkov , Konrad Dybcio X-Mailer: b4 0.15.1 X-Developer-Signature: v=1; a=openpgp-sha256; l=174129; i=dmitry.baryshkov@oss.qualcomm.com; h=from:subject:message-id; bh=AsA+qQz6EqgkSZ54/ECufIfAIlR+0ePO51BW1lvgN08=; b=owEBbQGS/pANAwAKAYs8ij4CKSjVAcsmYgBqBL9t5J1Ui54laXP06z4JtIV7Abx/qpnfhhMGW FemFn+h7geJATMEAAEKAB0WIQRMcISVXLJjVvC4lX+LPIo+Aiko1QUCagS/bQAKCRCLPIo+Aiko 1atwB/wKmWQwV3Cjmt2iSqmfyOY5jy/T+0W8OmHlWhRuDnuvyxF8LAb28CECiciOLAWsU1AEO5/ ptIoySm3yC0hu/vkGOR9vECCu5JVDptK6xOAfG5GIHYgGEEaKEB9JWC2t0ysmPOZb5tSaWMMQpQ 7bqfNfBgX6hOqsKVkayRJO2fcmlkBWAu60RItuXyRp2G28wC9wYn8Vh7uhkB58etrp5Eaq8lsjQ rOVvpXkzeKMYn1YZ5TQI6WNTwqpn3Er3uYM1FoAohHvMam3oe2TQdgPiWoxm7WllJr8oWwcMeFP XqrXSdh8ibwO4mR3hvsNWmjLgg0SS3BHnjsQz80CVTseIjFX X-Developer-Key: i=dmitry.baryshkov@oss.qualcomm.com; a=openpgp; fpr=8F88381DD5C873E4AE487DA5199BF1243632046A X-Authority-Analysis: v=2.4 cv=df+wG3Xe c=1 sm=1 tr=0 ts=6a04bf74 cx=c_pps a=UbhLPJ621ZpgOD2l3yZY1w==:117 a=xqWC_Br6kY4A:10 a=IkcTkHD0fZMA:10 a=NGcC8JguVDcA:10 a=s4-Qcg_JpJYA:10 a=VkNPw1HP01LnGYTKEx00:22 a=u7WPNUs3qKkmUXheDGA7:22 a=yx91gb_oNiZeI1HMLzn7:22 a=e5mUnYsNAAAA:8 a=KKAkSRfTAAAA:8 a=EUspDBNiAAAA:8 a=pGLkceISAAAA:8 a=Hv-X-kUjGcdez5Ya_TwA:9 a=QEXdDO2ut3YA:10 a=TOPH6uDL9cOC6tEoww4z:22 a=Vxmtnl_E_bksehYqCbjh:22 a=cvBusfyB2V15izCimMoJ:22 X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwNTEzMDE4MiBTYWx0ZWRfX8I5KO+yNyQ5i qmoluZQngcskYtNzTwGV6UeIwvHrYG9GvkMgKlhSPKsK1U70MWtbGq9eh1h1efeeWoPqLfejD1h sMwj0XmA85W2YJBbf/oK2jLqPE5ifMHDGrxUx7LnIt55Qlbr3eillvsB6aMbCxxnqp/qo9g2Wun qUQORYcl3tpD//tDugqh7yHnpBNqOOyi6YF36CH2latpItKoKBq/p352XF2hwVgDcCFMkE8K+Lu cLFRRnVDlTY2tPB5Q3dC+lS5foS5ATk0KDIV43wSDTqPqEUUf09FKSTozvSqaENK9zDzGUWs8jm Ib2T7hQhO4nZ+lkKVWCo9HaDs0PH9myyqEktmgaKTXiylZleGg33Op0sfpIhZm+onoaOACcAWax 6vuv0EDeVF/x25wwfs6SBxJOQ3A8K90mvRJxGfriCbHMNdpazeyop86wicSe6m2DKTY5Xe/+HlP Fq46SEiAH8ssbLkMNaQ== X-Proofpoint-GUID: Zepp6nWPWuoepF4Ol91nFyR0wwl6ubfW X-Proofpoint-ORIG-GUID: Zepp6nWPWuoepF4Ol91nFyR0wwl6ubfW X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1143,Hydra:6.1.51,FMLib:17.12.100.49 definitions=2026-05-13_02,2026-05-13_01,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 adultscore=0 malwarescore=0 priorityscore=1501 suspectscore=0 clxscore=1015 impostorscore=0 phishscore=0 spamscore=0 lowpriorityscore=0 bulkscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.22.0-2605050000 definitions=main-2605130182 From: Dmitry Baryshkov Change the MSM HDMI driver to use generic PHY subsystem. Moving PHY drivers allows better code sharing with the rest of the PHY system. Signed-off-by: Dmitry Baryshkov Acked-by: Konrad Dybcio Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/msm/Makefile | 7 - drivers/gpu/drm/msm/hdmi/hdmi.c | 59 +- drivers/gpu/drm/msm/hdmi/hdmi.h | 83 +-- drivers/gpu/drm/msm/hdmi/hdmi_bridge.c | 88 ++- drivers/gpu/drm/msm/hdmi/hdmi_phy.c | 226 ------ drivers/gpu/drm/msm/hdmi/hdmi_phy_8960.c | 51 -- drivers/gpu/drm/msm/hdmi/hdmi_phy_8996.c | 761 -----------------= --- drivers/gpu/drm/msm/hdmi/hdmi_phy_8998.c | 765 -----------------= ---- drivers/gpu/drm/msm/hdmi/hdmi_phy_8x60.c | 141 ---- drivers/gpu/drm/msm/hdmi/hdmi_phy_8x74.c | 44 -- drivers/gpu/drm/msm/registers/display/hdmi.xml | 537 --------------- drivers/phy/qualcomm/Kconfig | 24 + drivers/phy/qualcomm/Makefile | 14 + drivers/phy/qualcomm/phy-qcom-hdmi-28hpm.c | 71 ++ .../qualcomm/phy-qcom-hdmi-28lpm.c} | 430 ++++++++---- drivers/phy/qualcomm/phy-qcom-hdmi-45nm.c | 186 +++++ drivers/phy/qualcomm/phy-qcom-hdmi-preqmp.c | 211 ++++++ drivers/phy/qualcomm/phy-qcom-hdmi-preqmp.h | 59 ++ drivers/phy/qualcomm/phy-qcom-qmp-hdmi-base.c | 185 +++++ drivers/phy/qualcomm/phy-qcom-qmp-hdmi-msm8996.c | 440 ++++++++++++ drivers/phy/qualcomm/phy-qcom-qmp-hdmi-msm8998.c | 489 +++++++++++++ drivers/phy/qualcomm/phy-qcom-qmp-hdmi.h | 49 ++ 22 files changed, 2063 insertions(+), 2857 deletions(-) diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile index ba45e99be05b..01b6ebb1086f 100644 --- a/drivers/gpu/drm/msm/Makefile +++ b/drivers/gpu/drm/msm/Makefile @@ -37,13 +37,6 @@ msm-display-$(CONFIG_DRM_MSM_HDMI) +=3D \ hdmi/hdmi_bridge.o \ hdmi/hdmi_hpd.o \ hdmi/hdmi_i2c.o \ - hdmi/hdmi_phy.o \ - hdmi/hdmi_phy_8960.o \ - hdmi/hdmi_phy_8996.o \ - hdmi/hdmi_phy_8998.o \ - hdmi/hdmi_phy_8x60.o \ - hdmi/hdmi_phy_8x74.o \ - hdmi/hdmi_pll_8960.o \ =20 msm-display-$(CONFIG_DRM_MSM_MDP4) +=3D \ disp/mdp4/mdp4_crtc.o \ diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdm= i.c index d9491aac1a89..fd71da9a8782 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi.c @@ -10,6 +10,7 @@ #include #include #include +#include =20 #include #include @@ -76,44 +77,6 @@ static void msm_hdmi_destroy(struct hdmi *hdmi) msm_hdmi_i2c_destroy(hdmi->i2c); } =20 -static void msm_hdmi_put_phy(struct hdmi *hdmi) -{ - if (hdmi->phy_dev) { - put_device(hdmi->phy_dev); - hdmi->phy =3D NULL; - hdmi->phy_dev =3D NULL; - } -} - -static int msm_hdmi_get_phy(struct hdmi *hdmi) -{ - struct platform_device *pdev =3D hdmi->pdev; - struct platform_device *phy_pdev; - struct device_node *phy_node; - - phy_node =3D of_parse_phandle(dev_of_node(&pdev->dev), "phys", 0); - if (!phy_node) { - DRM_DEV_ERROR(&pdev->dev, "cannot find phy device\n"); - return -ENXIO; - } - - phy_pdev =3D of_find_device_by_node(phy_node); - of_node_put(phy_node); - - if (!phy_pdev) - return dev_err_probe(&pdev->dev, -EPROBE_DEFER, "phy driver is not ready= \n"); - - hdmi->phy =3D platform_get_drvdata(phy_pdev); - if (!hdmi->phy) { - put_device(&phy_pdev->dev); - return dev_err_probe(&pdev->dev, -EPROBE_DEFER, "phy driver is not ready= \n"); - } - - hdmi->phy_dev =3D &phy_pdev->dev; - - return 0; -} - /* construct hdmi at bind/probe time, grab all the resources. If * we are to EPROBE_DEFER we want to do it here, rather than later * at modeset_init() time @@ -353,34 +316,30 @@ static int msm_hdmi_dev_probe(struct platform_device = *pdev) if (hdmi->hpd_gpiod) gpiod_set_consumer_name(hdmi->hpd_gpiod, "HDMI_HPD"); =20 - ret =3D msm_hdmi_get_phy(hdmi); - if (ret) - return ret; + hdmi->phy =3D devm_phy_get(dev, NULL); + if (IS_ERR(hdmi->phy)) + return dev_err_probe(dev, PTR_ERR(hdmi->phy), + "failed to get phy\n"); =20 ret =3D devm_pm_runtime_enable(dev); if (ret) - goto err_put_phy; + goto err; =20 platform_set_drvdata(pdev, hdmi); =20 ret =3D component_add(dev, &msm_hdmi_ops); if (ret) - goto err_put_phy; + goto err; =20 return 0; =20 -err_put_phy: - msm_hdmi_put_phy(hdmi); +err: return ret; } =20 static void msm_hdmi_dev_remove(struct platform_device *pdev) { - struct hdmi *hdmi =3D dev_get_drvdata(&pdev->dev); - component_del(&pdev->dev, &msm_hdmi_ops); - - msm_hdmi_put_phy(hdmi); } =20 static int msm_hdmi_runtime_suspend(struct device *dev) @@ -449,12 +408,10 @@ static struct platform_driver msm_hdmi_driver =3D { =20 void __init msm_hdmi_register(void) { - msm_hdmi_phy_driver_register(); platform_driver_register(&msm_hdmi_driver); } =20 void __exit msm_hdmi_unregister(void) { platform_driver_unregister(&msm_hdmi_driver); - msm_hdmi_phy_driver_unregister(); } diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.h b/drivers/gpu/drm/msm/hdmi/hdm= i.h index 49433f7727c3..5857b5fa8ece 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi.h +++ b/drivers/gpu/drm/msm/hdmi/hdmi.h @@ -19,7 +19,6 @@ #include "msm_drv.h" #include "hdmi.xml.h" =20 -struct hdmi_phy; struct hdmi_platform_config; =20 struct hdmi_audio { @@ -41,8 +40,9 @@ struct hdmi { =20 /* video state: */ bool power_on; + bool phy_power_on; bool hpd_enabled; - struct mutex state_mutex; /* protects two booleans */ + struct mutex state_mutex; /* protects the booleans */ unsigned long pixclock; =20 void __iomem *mmio; @@ -55,8 +55,7 @@ struct hdmi { =20 struct gpio_desc *hpd_gpiod; =20 - struct hdmi_phy *phy; - struct device *phy_dev; + struct phy *phy; =20 struct i2c_adapter *i2c; struct drm_connector *connector; @@ -117,82 +116,6 @@ static inline u32 hdmi_qfprom_read(struct hdmi *hdmi, = u32 reg) return readl(hdmi->qfprom_mmio + reg); } =20 -/* - * hdmi phy: - */ - -enum hdmi_phy_type { - MSM_HDMI_PHY_8x60, - MSM_HDMI_PHY_8960, - MSM_HDMI_PHY_8x74, - MSM_HDMI_PHY_8996, - MSM_HDMI_PHY_8998, - MSM_HDMI_PHY_MAX, -}; - -struct hdmi_phy_cfg { - enum hdmi_phy_type type; - void (*powerup)(struct hdmi_phy *phy, unsigned long pixclock); - void (*powerdown)(struct hdmi_phy *phy); - const char * const *reg_names; - int num_regs; - const char * const *clk_names; - int num_clks; -}; - -extern const struct hdmi_phy_cfg msm_hdmi_phy_8x60_cfg; -extern const struct hdmi_phy_cfg msm_hdmi_phy_8960_cfg; -extern const struct hdmi_phy_cfg msm_hdmi_phy_8x74_cfg; -extern const struct hdmi_phy_cfg msm_hdmi_phy_8996_cfg; -extern const struct hdmi_phy_cfg msm_hdmi_phy_8998_cfg; - -struct hdmi_phy { - struct platform_device *pdev; - void __iomem *mmio; - struct hdmi_phy_cfg *cfg; - const struct hdmi_phy_funcs *funcs; - struct regulator_bulk_data *regs; - struct clk **clks; -}; - -static inline void hdmi_phy_write(struct hdmi_phy *phy, u32 reg, u32 data) -{ - writel(data, phy->mmio + reg); -} - -static inline u32 hdmi_phy_read(struct hdmi_phy *phy, u32 reg) -{ - return readl(phy->mmio + reg); -} - -int msm_hdmi_phy_resource_enable(struct hdmi_phy *phy); -void msm_hdmi_phy_resource_disable(struct hdmi_phy *phy); -void msm_hdmi_phy_powerup(struct hdmi_phy *phy, unsigned long pixclock); -void msm_hdmi_phy_powerdown(struct hdmi_phy *phy); -void __init msm_hdmi_phy_driver_register(void); -void __exit msm_hdmi_phy_driver_unregister(void); - -#ifdef CONFIG_COMMON_CLK -int msm_hdmi_pll_8960_init(struct platform_device *pdev); -int msm_hdmi_pll_8996_init(struct platform_device *pdev); -int msm_hdmi_pll_8998_init(struct platform_device *pdev); -#else -static inline int msm_hdmi_pll_8960_init(struct platform_device *pdev) -{ - return -ENODEV; -} - -static inline int msm_hdmi_pll_8996_init(struct platform_device *pdev) -{ - return -ENODEV; -} - -static inline int msm_hdmi_pll_8998_init(struct platform_device *pdev) -{ - return -ENODEV; -} -#endif - /* * audio: */ diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c b/drivers/gpu/drm/msm/h= dmi/hdmi_bridge.c index c4d5e0faf3b3..42eafc2bde00 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c @@ -5,6 +5,7 @@ */ =20 #include +#include #include #include #include @@ -13,43 +14,6 @@ #include "msm_kms.h" #include "hdmi.h" =20 -static void msm_hdmi_power_on(struct drm_bridge *bridge) -{ - struct drm_device *dev =3D bridge->dev; - struct hdmi_bridge *hdmi_bridge =3D to_hdmi_bridge(bridge); - struct hdmi *hdmi =3D hdmi_bridge->hdmi; - int ret; - - pm_runtime_resume_and_get(&hdmi->pdev->dev); - - if (hdmi->extp_clk) { - DBG("pixclock: %lu", hdmi->pixclock); - ret =3D clk_set_rate(hdmi->extp_clk, hdmi->pixclock); - if (ret) - DRM_DEV_ERROR(dev->dev, "failed to set extp clk rate: %d\n", ret); - - ret =3D clk_prepare_enable(hdmi->extp_clk); - if (ret) - DRM_DEV_ERROR(dev->dev, "failed to enable extp clk: %d\n", ret); - } -} - -static void power_off(struct drm_bridge *bridge) -{ - struct hdmi_bridge *hdmi_bridge =3D to_hdmi_bridge(bridge); - struct hdmi *hdmi =3D hdmi_bridge->hdmi; - - /* TODO do we need to wait for final vblank somewhere before - * cutting the clocks? - */ - mdelay(16 + 4); - - if (hdmi->extp_clk) - clk_disable_unprepare(hdmi->extp_clk); - - pm_runtime_put(&hdmi->pdev->dev); -} - #define AVI_IFRAME_LINE_NUMBER 1 #define SPD_IFRAME_LINE_NUMBER 1 #define VENSPEC_IFRAME_LINE_NUMBER 3 @@ -287,11 +251,12 @@ static void msm_hdmi_bridge_atomic_pre_enable(struct = drm_bridge *bridge, { struct hdmi_bridge *hdmi_bridge =3D to_hdmi_bridge(bridge); struct hdmi *hdmi =3D hdmi_bridge->hdmi; - struct hdmi_phy *phy =3D hdmi->phy; struct drm_encoder *encoder =3D bridge->encoder; struct drm_connector *connector; struct drm_connector_state *conn_state; struct drm_crtc_state *crtc_state; + union phy_configure_opts phy_opts =3D {}; + int ret; =20 DBG("power up"); =20 @@ -305,18 +270,38 @@ static void msm_hdmi_bridge_atomic_pre_enable(struct = drm_bridge *bridge, =20 mutex_lock(&hdmi->state_mutex); if (!hdmi->power_on) { - msm_hdmi_phy_resource_enable(phy); - msm_hdmi_power_on(bridge); + phy_init(hdmi->phy); + pm_runtime_get_sync(&hdmi->pdev->dev); hdmi->power_on =3D true; } - mutex_unlock(&hdmi->state_mutex); =20 if (connector->display_info.is_hdmi) msm_hdmi_audio_update(hdmi); =20 drm_atomic_helper_connector_hdmi_update_infoframes(connector, state); =20 - msm_hdmi_phy_powerup(phy, hdmi->pixclock); + phy_opts.hdmi.tmds_char_rate =3D conn_state->hdmi.tmds_char_rate; + phy_opts.hdmi.bpc =3D 8; + phy_configure(hdmi->phy, &phy_opts); + + ret =3D phy_power_on(hdmi->phy); + if (WARN_ON(ret)) { + mutex_unlock(&hdmi->state_mutex); + return; + } + + hdmi->phy_power_on =3D true; + mutex_unlock(&hdmi->state_mutex); + + if (hdmi->extp_clk) { + ret =3D clk_set_rate(hdmi->extp_clk, hdmi->pixclock); + if (ret) + DRM_DEV_ERROR(bridge->dev->dev, "failed to set extp clk rate: %d\n", re= t); + + ret =3D clk_prepare_enable(hdmi->extp_clk); + if (ret) + DRM_DEV_ERROR(bridge->dev->dev, "failed to enable extp clk: %d\n", ret); + } =20 msm_hdmi_set_mode(hdmi, true); =20 @@ -329,7 +314,6 @@ static void msm_hdmi_bridge_atomic_post_disable(struct = drm_bridge *bridge, { struct hdmi_bridge *hdmi_bridge =3D to_hdmi_bridge(bridge); struct hdmi *hdmi =3D hdmi_bridge->hdmi; - struct hdmi_phy *phy =3D hdmi->phy; =20 if (hdmi->hdcp_ctrl) msm_hdmi_hdcp_off(hdmi->hdcp_ctrl); @@ -340,14 +324,26 @@ static void msm_hdmi_bridge_atomic_post_disable(struc= t drm_bridge *bridge, mutex_lock(&hdmi->state_mutex); msm_hdmi_set_mode(hdmi, hdmi->hpd_enabled); =20 - msm_hdmi_phy_powerdown(phy); + /* TODO do we need to wait for final vblank somewhere before + * cutting the clocks? + */ + mdelay(16 + 4); + + if (hdmi->extp_clk) + clk_disable_unprepare(hdmi->extp_clk); + + if (hdmi->phy_power_on) + phy_power_off(hdmi->phy); + + hdmi->phy_power_on =3D false; =20 if (hdmi->power_on) { - power_off(bridge); + pm_runtime_put_sync(&hdmi->pdev->dev); + hdmi->power_on =3D false; if (hdmi->connector->display_info.is_hdmi) msm_hdmi_audio_update(hdmi); - msm_hdmi_phy_resource_disable(phy); + phy_exit(hdmi->phy); } mutex_unlock(&hdmi->state_mutex); } diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_phy.c b/drivers/gpu/drm/msm/hdmi= /hdmi_phy.c deleted file mode 100644 index eb1088755cb3..000000000000 --- a/drivers/gpu/drm/msm/hdmi/hdmi_phy.c +++ /dev/null @@ -1,226 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (c) 2016, The Linux Foundation. All rights reserved. - */ - -#include -#include - -#include "hdmi.h" - -static int msm_hdmi_phy_resource_init(struct hdmi_phy *phy) -{ - struct hdmi_phy_cfg *cfg =3D phy->cfg; - struct device *dev =3D &phy->pdev->dev; - int i, ret; - - phy->regs =3D devm_kcalloc(dev, cfg->num_regs, sizeof(phy->regs[0]), - GFP_KERNEL); - if (!phy->regs) - return -ENOMEM; - - phy->clks =3D devm_kcalloc(dev, cfg->num_clks, sizeof(phy->clks[0]), - GFP_KERNEL); - if (!phy->clks) - return -ENOMEM; - - for (i =3D 0; i < cfg->num_regs; i++) - phy->regs[i].supply =3D cfg->reg_names[i]; - - ret =3D devm_regulator_bulk_get(dev, cfg->num_regs, phy->regs); - if (ret) { - if (ret !=3D -EPROBE_DEFER) - DRM_DEV_ERROR(dev, "failed to get phy regulators: %d\n", ret); - - return ret; - } - - for (i =3D 0; i < cfg->num_clks; i++) { - struct clk *clk; - - clk =3D msm_clk_get(phy->pdev, cfg->clk_names[i]); - if (IS_ERR(clk)) { - ret =3D PTR_ERR(clk); - DRM_DEV_ERROR(dev, "failed to get phy clock: %s (%d)\n", - cfg->clk_names[i], ret); - return ret; - } - - phy->clks[i] =3D clk; - } - - return 0; -} - -int msm_hdmi_phy_resource_enable(struct hdmi_phy *phy) -{ - struct hdmi_phy_cfg *cfg =3D phy->cfg; - struct device *dev =3D &phy->pdev->dev; - int i, ret =3D 0; - - ret =3D pm_runtime_resume_and_get(dev); - if (ret) { - DRM_DEV_ERROR(dev, "runtime resume failed: %d\n", ret); - return ret; - } - - ret =3D regulator_bulk_enable(cfg->num_regs, phy->regs); - if (ret) { - DRM_DEV_ERROR(dev, "failed to enable regulators: (%d)\n", ret); - return ret; - } - - for (i =3D 0; i < cfg->num_clks; i++) { - ret =3D clk_prepare_enable(phy->clks[i]); - if (ret) - DRM_DEV_ERROR(dev, "failed to enable clock: %s (%d)\n", - cfg->clk_names[i], ret); - } - - return ret; -} - -void msm_hdmi_phy_resource_disable(struct hdmi_phy *phy) -{ - struct hdmi_phy_cfg *cfg =3D phy->cfg; - struct device *dev =3D &phy->pdev->dev; - int i; - - for (i =3D cfg->num_clks - 1; i >=3D 0; i--) - clk_disable_unprepare(phy->clks[i]); - - regulator_bulk_disable(cfg->num_regs, phy->regs); - - pm_runtime_put_sync(dev); -} - -void msm_hdmi_phy_powerup(struct hdmi_phy *phy, unsigned long pixclock) -{ - if (!phy || !phy->cfg->powerup) - return; - - phy->cfg->powerup(phy, pixclock); -} - -void msm_hdmi_phy_powerdown(struct hdmi_phy *phy) -{ - if (!phy || !phy->cfg->powerdown) - return; - - phy->cfg->powerdown(phy); -} - -static int msm_hdmi_phy_pll_init(struct platform_device *pdev, - enum hdmi_phy_type type) -{ - int ret; - - switch (type) { - case MSM_HDMI_PHY_8960: - ret =3D msm_hdmi_pll_8960_init(pdev); - break; - case MSM_HDMI_PHY_8996: - ret =3D msm_hdmi_pll_8996_init(pdev); - break; - case MSM_HDMI_PHY_8998: - ret =3D msm_hdmi_pll_8998_init(pdev); - break; - /* - * we don't have PLL support for these, don't report an error for now - */ - case MSM_HDMI_PHY_8x60: - case MSM_HDMI_PHY_8x74: - default: - ret =3D 0; - break; - } - - return ret; -} - -static int msm_hdmi_phy_probe(struct platform_device *pdev) -{ - struct device *dev =3D &pdev->dev; - struct hdmi_phy *phy; - int ret; - - phy =3D devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL); - if (!phy) - return -ENODEV; - - phy->cfg =3D (struct hdmi_phy_cfg *)of_device_get_match_data(dev); - if (!phy->cfg) - return -ENODEV; - - phy->mmio =3D msm_ioremap(pdev, "hdmi_phy"); - if (IS_ERR(phy->mmio)) { - DRM_DEV_ERROR(dev, "%s: failed to map phy base\n", __func__); - return -ENOMEM; - } - - phy->pdev =3D pdev; - - ret =3D msm_hdmi_phy_resource_init(phy); - if (ret) - return ret; - - pm_runtime_enable(&pdev->dev); - - ret =3D msm_hdmi_phy_resource_enable(phy); - if (ret) - return ret; - - ret =3D msm_hdmi_phy_pll_init(pdev, phy->cfg->type); - if (ret) { - DRM_DEV_ERROR(dev, "couldn't init PLL\n"); - msm_hdmi_phy_resource_disable(phy); - return ret; - } - - msm_hdmi_phy_resource_disable(phy); - - platform_set_drvdata(pdev, phy); - - return 0; -} - -static void msm_hdmi_phy_remove(struct platform_device *pdev) -{ - pm_runtime_disable(&pdev->dev); -} - -static const struct of_device_id msm_hdmi_phy_dt_match[] =3D { - { .compatible =3D "qcom,hdmi-phy-8660", - .data =3D &msm_hdmi_phy_8x60_cfg }, - { .compatible =3D "qcom,hdmi-phy-8960", - .data =3D &msm_hdmi_phy_8960_cfg }, - { .compatible =3D "qcom,hdmi-phy-8974", - .data =3D &msm_hdmi_phy_8x74_cfg }, - { .compatible =3D "qcom,hdmi-phy-8084", - .data =3D &msm_hdmi_phy_8x74_cfg }, - { .compatible =3D "qcom,hdmi-phy-8996", - .data =3D &msm_hdmi_phy_8996_cfg }, - { .compatible =3D "qcom,hdmi-phy-8998", - .data =3D &msm_hdmi_phy_8998_cfg }, - {} -}; -MODULE_DEVICE_TABLE(of, msm_hdmi_phy_dt_match); - -static struct platform_driver msm_hdmi_phy_platform_driver =3D { - .probe =3D msm_hdmi_phy_probe, - .remove =3D msm_hdmi_phy_remove, - .driver =3D { - .name =3D "msm_hdmi_phy", - .of_match_table =3D msm_hdmi_phy_dt_match, - }, -}; - -void __init msm_hdmi_phy_driver_register(void) -{ - platform_driver_register(&msm_hdmi_phy_platform_driver); -} - -void __exit msm_hdmi_phy_driver_unregister(void) -{ - platform_driver_unregister(&msm_hdmi_phy_platform_driver); -} diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_phy_8960.c b/drivers/gpu/drm/msm= /hdmi/hdmi_phy_8960.c deleted file mode 100644 index cfa8fc494199..000000000000 --- a/drivers/gpu/drm/msm/hdmi/hdmi_phy_8960.c +++ /dev/null @@ -1,51 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) 2013 Red Hat - * Author: Rob Clark - */ - -#include "hdmi.h" - -static void hdmi_phy_8960_powerup(struct hdmi_phy *phy, - unsigned long pixclock) -{ - DBG("pixclock: %lu", pixclock); - - hdmi_phy_write(phy, REG_HDMI_8960_PHY_REG2, 0x00); - hdmi_phy_write(phy, REG_HDMI_8960_PHY_REG0, 0x1b); - hdmi_phy_write(phy, REG_HDMI_8960_PHY_REG1, 0xf2); - hdmi_phy_write(phy, REG_HDMI_8960_PHY_REG4, 0x00); - hdmi_phy_write(phy, REG_HDMI_8960_PHY_REG5, 0x00); - hdmi_phy_write(phy, REG_HDMI_8960_PHY_REG6, 0x00); - hdmi_phy_write(phy, REG_HDMI_8960_PHY_REG7, 0x00); - hdmi_phy_write(phy, REG_HDMI_8960_PHY_REG8, 0x00); - hdmi_phy_write(phy, REG_HDMI_8960_PHY_REG9, 0x00); - hdmi_phy_write(phy, REG_HDMI_8960_PHY_REG10, 0x00); - hdmi_phy_write(phy, REG_HDMI_8960_PHY_REG11, 0x00); - hdmi_phy_write(phy, REG_HDMI_8960_PHY_REG3, 0x20); -} - -static void hdmi_phy_8960_powerdown(struct hdmi_phy *phy) -{ - DBG(""); - - hdmi_phy_write(phy, REG_HDMI_8960_PHY_REG2, 0x7f); -} - -static const char * const hdmi_phy_8960_reg_names[] =3D { - "core-vdda", -}; - -static const char * const hdmi_phy_8960_clk_names[] =3D { - "slave_iface", -}; - -const struct hdmi_phy_cfg msm_hdmi_phy_8960_cfg =3D { - .type =3D MSM_HDMI_PHY_8960, - .powerup =3D hdmi_phy_8960_powerup, - .powerdown =3D hdmi_phy_8960_powerdown, - .reg_names =3D hdmi_phy_8960_reg_names, - .num_regs =3D ARRAY_SIZE(hdmi_phy_8960_reg_names), - .clk_names =3D hdmi_phy_8960_clk_names, - .num_clks =3D ARRAY_SIZE(hdmi_phy_8960_clk_names), -}; diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_phy_8996.c b/drivers/gpu/drm/msm= /hdmi/hdmi_phy_8996.c deleted file mode 100644 index 36e928b0fd5a..000000000000 --- a/drivers/gpu/drm/msm/hdmi/hdmi_phy_8996.c +++ /dev/null @@ -1,761 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (c) 2016, The Linux Foundation. All rights reserved. - */ - -#include -#include - -#include "hdmi.h" - -#define HDMI_VCO_MAX_FREQ 12000000000UL -#define HDMI_VCO_MIN_FREQ 8000000000UL - -#define HDMI_PCLK_MAX_FREQ 600000000 -#define HDMI_PCLK_MIN_FREQ 25000000 - -#define HDMI_HIGH_FREQ_BIT_CLK_THRESHOLD 3400000000UL -#define HDMI_DIG_FREQ_BIT_CLK_THRESHOLD 1500000000UL -#define HDMI_MID_FREQ_BIT_CLK_THRESHOLD 750000000UL -#define HDMI_CORECLK_DIV 5 -#define HDMI_DEFAULT_REF_CLOCK 19200000 -#define HDMI_PLL_CMP_CNT 1024 - -#define HDMI_PLL_POLL_MAX_READS 100 -#define HDMI_PLL_POLL_TIMEOUT_US 150 - -#define HDMI_NUM_TX_CHANNEL 4 - -struct hdmi_pll_8996 { - struct platform_device *pdev; - struct clk_hw clk_hw; - - /* pll mmio base */ - void __iomem *mmio_qserdes_com; - /* tx channel base */ - void __iomem *mmio_qserdes_tx[HDMI_NUM_TX_CHANNEL]; -}; - -#define hw_clk_to_pll(x) container_of(x, struct hdmi_pll_8996, clk_hw) - -struct hdmi_8996_phy_pll_reg_cfg { - u32 tx_lx_lane_mode[HDMI_NUM_TX_CHANNEL]; - u32 tx_lx_tx_band[HDMI_NUM_TX_CHANNEL]; - u32 com_svs_mode_clk_sel; - u32 com_hsclk_sel; - u32 com_pll_cctrl_mode0; - u32 com_pll_rctrl_mode0; - u32 com_cp_ctrl_mode0; - u32 com_dec_start_mode0; - u32 com_div_frac_start1_mode0; - u32 com_div_frac_start2_mode0; - u32 com_div_frac_start3_mode0; - u32 com_integloop_gain0_mode0; - u32 com_integloop_gain1_mode0; - u32 com_lock_cmp_en; - u32 com_lock_cmp1_mode0; - u32 com_lock_cmp2_mode0; - u32 com_lock_cmp3_mode0; - u32 com_core_clk_en; - u32 com_coreclk_div; - u32 com_vco_tune_ctrl; - - u32 tx_lx_tx_drv_lvl[HDMI_NUM_TX_CHANNEL]; - u32 tx_lx_tx_emp_post1_lvl[HDMI_NUM_TX_CHANNEL]; - u32 tx_lx_vmode_ctrl1[HDMI_NUM_TX_CHANNEL]; - u32 tx_lx_vmode_ctrl2[HDMI_NUM_TX_CHANNEL]; - u32 tx_lx_res_code_lane_tx[HDMI_NUM_TX_CHANNEL]; - u32 tx_lx_hp_pd_enables[HDMI_NUM_TX_CHANNEL]; - - u32 phy_mode; -}; - -struct hdmi_8996_post_divider { - u64 vco_freq; - int hsclk_divsel; - int vco_ratio; - int tx_band_sel; - int half_rate_mode; -}; - -static inline struct hdmi_phy *pll_get_phy(struct hdmi_pll_8996 *pll) -{ - return platform_get_drvdata(pll->pdev); -} - -static inline void hdmi_pll_write(struct hdmi_pll_8996 *pll, int offset, - u32 data) -{ - writel(data, pll->mmio_qserdes_com + offset); -} - -static inline u32 hdmi_pll_read(struct hdmi_pll_8996 *pll, int offset) -{ - return readl(pll->mmio_qserdes_com + offset); -} - -static inline void hdmi_tx_chan_write(struct hdmi_pll_8996 *pll, int chann= el, - int offset, int data) -{ - writel(data, pll->mmio_qserdes_tx[channel] + offset); -} - -static inline u32 pll_get_cpctrl(u64 frac_start, unsigned long ref_clk, - bool gen_ssc) -{ - if ((frac_start !=3D 0) || gen_ssc) - return (11000000 / (ref_clk / 20)); - - return 0x23; -} - -static inline u32 pll_get_rctrl(u64 frac_start, bool gen_ssc) -{ - if ((frac_start !=3D 0) || gen_ssc) - return 0x16; - - return 0x10; -} - -static inline u32 pll_get_cctrl(u64 frac_start, bool gen_ssc) -{ - if ((frac_start !=3D 0) || gen_ssc) - return 0x28; - - return 0x1; -} - -static inline u32 pll_get_integloop_gain(u64 frac_start, u64 bclk, u32 ref= _clk, - bool gen_ssc) -{ - int digclk_divsel =3D bclk >=3D HDMI_DIG_FREQ_BIT_CLK_THRESHOLD ? 1 : 2; - u64 base; - - if ((frac_start !=3D 0) || gen_ssc) - base =3D (64 * ref_clk) / HDMI_DEFAULT_REF_CLOCK; - else - base =3D (1022 * ref_clk) / 100; - - base <<=3D digclk_divsel; - - return (base <=3D 2046 ? base : 2046); -} - -static inline u32 pll_get_pll_cmp(u64 fdata, unsigned long ref_clk) -{ - u64 dividend =3D HDMI_PLL_CMP_CNT * fdata; - u32 divisor =3D ref_clk * 10; - u32 rem; - - rem =3D do_div(dividend, divisor); - if (rem > (divisor >> 1)) - dividend++; - - return dividend - 1; -} - -static inline u64 pll_cmp_to_fdata(u32 pll_cmp, unsigned long ref_clk) -{ - u64 fdata =3D ((u64)pll_cmp) * ref_clk * 10; - - do_div(fdata, HDMI_PLL_CMP_CNT); - - return fdata; -} - -static int pll_get_post_div(struct hdmi_8996_post_divider *pd, u64 bclk) -{ - int ratio[] =3D { 2, 3, 4, 5, 6, 9, 10, 12, 14, 15, 20, 21, 25, 28, 35 }; - int hs_divsel[] =3D { 0, 4, 8, 12, 1, 5, 2, 9, 3, 13, 10, 7, 14, 11, 15 }; - int tx_band_sel[] =3D { 0, 1, 2, 3 }; - u64 vco_freq[60]; - u64 vco, vco_optimal; - int half_rate_mode =3D 0; - int vco_optimal_index, vco_freq_index; - int i, j; - -retry: - vco_optimal =3D HDMI_VCO_MAX_FREQ; - vco_optimal_index =3D -1; - vco_freq_index =3D 0; - for (i =3D 0; i < 15; i++) { - for (j =3D 0; j < 4; j++) { - u32 ratio_mult =3D ratio[i] << tx_band_sel[j]; - - vco =3D bclk >> half_rate_mode; - vco *=3D ratio_mult; - vco_freq[vco_freq_index++] =3D vco; - } - } - - for (i =3D 0; i < 60; i++) { - u64 vco_tmp =3D vco_freq[i]; - - if ((vco_tmp >=3D HDMI_VCO_MIN_FREQ) && - (vco_tmp <=3D vco_optimal)) { - vco_optimal =3D vco_tmp; - vco_optimal_index =3D i; - } - } - - if (vco_optimal_index =3D=3D -1) { - if (!half_rate_mode) { - half_rate_mode =3D 1; - goto retry; - } - } else { - pd->vco_freq =3D vco_optimal; - pd->tx_band_sel =3D tx_band_sel[vco_optimal_index % 4]; - pd->vco_ratio =3D ratio[vco_optimal_index / 4]; - pd->hsclk_divsel =3D hs_divsel[vco_optimal_index / 4]; - - return 0; - } - - return -EINVAL; -} - -static int pll_calculate(unsigned long pix_clk, unsigned long ref_clk, - struct hdmi_8996_phy_pll_reg_cfg *cfg) -{ - struct hdmi_8996_post_divider pd; - u64 bclk; - u64 tmds_clk; - u64 dec_start; - u64 frac_start; - u64 fdata; - u32 pll_divisor; - u32 rem; - u32 cpctrl; - u32 rctrl; - u32 cctrl; - u32 integloop_gain; - u32 pll_cmp; - int i, ret; - - /* bit clk =3D 10 * pix_clk */ - bclk =3D ((u64)pix_clk) * 10; - - if (bclk > HDMI_HIGH_FREQ_BIT_CLK_THRESHOLD) - tmds_clk =3D pix_clk >> 2; - else - tmds_clk =3D pix_clk; - - ret =3D pll_get_post_div(&pd, bclk); - if (ret) - return ret; - - dec_start =3D pd.vco_freq; - pll_divisor =3D 4 * ref_clk; - do_div(dec_start, pll_divisor); - - frac_start =3D pd.vco_freq * (1 << 20); - - rem =3D do_div(frac_start, pll_divisor); - frac_start -=3D dec_start * (1 << 20); - if (rem > (pll_divisor >> 1)) - frac_start++; - - cpctrl =3D pll_get_cpctrl(frac_start, ref_clk, false); - rctrl =3D pll_get_rctrl(frac_start, false); - cctrl =3D pll_get_cctrl(frac_start, false); - integloop_gain =3D pll_get_integloop_gain(frac_start, bclk, - ref_clk, false); - - fdata =3D pd.vco_freq; - do_div(fdata, pd.vco_ratio); - - pll_cmp =3D pll_get_pll_cmp(fdata, ref_clk); - - DBG("VCO freq: %llu", pd.vco_freq); - DBG("fdata: %llu", fdata); - DBG("pix_clk: %lu", pix_clk); - DBG("tmds clk: %llu", tmds_clk); - DBG("HSCLK_SEL: %d", pd.hsclk_divsel); - DBG("DEC_START: %llu", dec_start); - DBG("DIV_FRAC_START: %llu", frac_start); - DBG("PLL_CPCTRL: %u", cpctrl); - DBG("PLL_RCTRL: %u", rctrl); - DBG("PLL_CCTRL: %u", cctrl); - DBG("INTEGLOOP_GAIN: %u", integloop_gain); - DBG("TX_BAND: %d", pd.tx_band_sel); - DBG("PLL_CMP: %u", pll_cmp); - - /* Convert these values to register specific values */ - if (bclk > HDMI_DIG_FREQ_BIT_CLK_THRESHOLD) - cfg->com_svs_mode_clk_sel =3D 1; - else - cfg->com_svs_mode_clk_sel =3D 2; - - cfg->com_hsclk_sel =3D (0x20 | pd.hsclk_divsel); - cfg->com_pll_cctrl_mode0 =3D cctrl; - cfg->com_pll_rctrl_mode0 =3D rctrl; - cfg->com_cp_ctrl_mode0 =3D cpctrl; - cfg->com_dec_start_mode0 =3D dec_start; - cfg->com_div_frac_start1_mode0 =3D (frac_start & 0xff); - cfg->com_div_frac_start2_mode0 =3D ((frac_start & 0xff00) >> 8); - cfg->com_div_frac_start3_mode0 =3D ((frac_start & 0xf0000) >> 16); - cfg->com_integloop_gain0_mode0 =3D (integloop_gain & 0xff); - cfg->com_integloop_gain1_mode0 =3D ((integloop_gain & 0xf00) >> 8); - cfg->com_lock_cmp1_mode0 =3D (pll_cmp & 0xff); - cfg->com_lock_cmp2_mode0 =3D ((pll_cmp & 0xff00) >> 8); - cfg->com_lock_cmp3_mode0 =3D ((pll_cmp & 0x30000) >> 16); - cfg->com_lock_cmp_en =3D 0x0; - cfg->com_core_clk_en =3D 0x2c; - cfg->com_coreclk_div =3D HDMI_CORECLK_DIV; - cfg->phy_mode =3D (bclk > HDMI_HIGH_FREQ_BIT_CLK_THRESHOLD) ? 0x10 : 0x0; - cfg->com_vco_tune_ctrl =3D 0x0; - - cfg->tx_lx_lane_mode[0] =3D - cfg->tx_lx_lane_mode[2] =3D 0x43; - - cfg->tx_lx_hp_pd_enables[0] =3D - cfg->tx_lx_hp_pd_enables[1] =3D - cfg->tx_lx_hp_pd_enables[2] =3D 0x0c; - cfg->tx_lx_hp_pd_enables[3] =3D 0x3; - - for (i =3D 0; i < HDMI_NUM_TX_CHANNEL; i++) - cfg->tx_lx_tx_band[i] =3D pd.tx_band_sel + 4; - - if (bclk > HDMI_HIGH_FREQ_BIT_CLK_THRESHOLD) { - cfg->tx_lx_tx_drv_lvl[0] =3D - cfg->tx_lx_tx_drv_lvl[1] =3D - cfg->tx_lx_tx_drv_lvl[2] =3D 0x25; - cfg->tx_lx_tx_drv_lvl[3] =3D 0x22; - - cfg->tx_lx_tx_emp_post1_lvl[0] =3D - cfg->tx_lx_tx_emp_post1_lvl[1] =3D - cfg->tx_lx_tx_emp_post1_lvl[2] =3D 0x23; - cfg->tx_lx_tx_emp_post1_lvl[3] =3D 0x27; - - cfg->tx_lx_vmode_ctrl1[0] =3D - cfg->tx_lx_vmode_ctrl1[1] =3D - cfg->tx_lx_vmode_ctrl1[2] =3D - cfg->tx_lx_vmode_ctrl1[3] =3D 0x00; - - cfg->tx_lx_vmode_ctrl2[0] =3D - cfg->tx_lx_vmode_ctrl2[1] =3D - cfg->tx_lx_vmode_ctrl2[2] =3D 0x0D; - - cfg->tx_lx_vmode_ctrl2[3] =3D 0x00; - } else if (bclk > HDMI_MID_FREQ_BIT_CLK_THRESHOLD) { - for (i =3D 0; i < HDMI_NUM_TX_CHANNEL; i++) { - cfg->tx_lx_tx_drv_lvl[i] =3D 0x25; - cfg->tx_lx_tx_emp_post1_lvl[i] =3D 0x23; - cfg->tx_lx_vmode_ctrl1[i] =3D 0x00; - } - - cfg->tx_lx_vmode_ctrl2[0] =3D - cfg->tx_lx_vmode_ctrl2[1] =3D - cfg->tx_lx_vmode_ctrl2[2] =3D 0x0D; - cfg->tx_lx_vmode_ctrl2[3] =3D 0x00; - } else { - for (i =3D 0; i < HDMI_NUM_TX_CHANNEL; i++) { - cfg->tx_lx_tx_drv_lvl[i] =3D 0x20; - cfg->tx_lx_tx_emp_post1_lvl[i] =3D 0x20; - cfg->tx_lx_vmode_ctrl1[i] =3D 0x00; - cfg->tx_lx_vmode_ctrl2[i] =3D 0x0E; - } - } - - DBG("com_svs_mode_clk_sel =3D 0x%x", cfg->com_svs_mode_clk_sel); - DBG("com_hsclk_sel =3D 0x%x", cfg->com_hsclk_sel); - DBG("com_lock_cmp_en =3D 0x%x", cfg->com_lock_cmp_en); - DBG("com_pll_cctrl_mode0 =3D 0x%x", cfg->com_pll_cctrl_mode0); - DBG("com_pll_rctrl_mode0 =3D 0x%x", cfg->com_pll_rctrl_mode0); - DBG("com_cp_ctrl_mode0 =3D 0x%x", cfg->com_cp_ctrl_mode0); - DBG("com_dec_start_mode0 =3D 0x%x", cfg->com_dec_start_mode0); - DBG("com_div_frac_start1_mode0 =3D 0x%x", cfg->com_div_frac_start1_mode0); - DBG("com_div_frac_start2_mode0 =3D 0x%x", cfg->com_div_frac_start2_mode0); - DBG("com_div_frac_start3_mode0 =3D 0x%x", cfg->com_div_frac_start3_mode0); - DBG("com_integloop_gain0_mode0 =3D 0x%x", cfg->com_integloop_gain0_mode0); - DBG("com_integloop_gain1_mode0 =3D 0x%x", cfg->com_integloop_gain1_mode0); - DBG("com_lock_cmp1_mode0 =3D 0x%x", cfg->com_lock_cmp1_mode0); - DBG("com_lock_cmp2_mode0 =3D 0x%x", cfg->com_lock_cmp2_mode0); - DBG("com_lock_cmp3_mode0 =3D 0x%x", cfg->com_lock_cmp3_mode0); - DBG("com_core_clk_en =3D 0x%x", cfg->com_core_clk_en); - DBG("com_coreclk_div =3D 0x%x", cfg->com_coreclk_div); - DBG("phy_mode =3D 0x%x", cfg->phy_mode); - - DBG("tx_l0_lane_mode =3D 0x%x", cfg->tx_lx_lane_mode[0]); - DBG("tx_l2_lane_mode =3D 0x%x", cfg->tx_lx_lane_mode[2]); - - for (i =3D 0; i < HDMI_NUM_TX_CHANNEL; i++) { - DBG("tx_l%d_tx_band =3D 0x%x", i, cfg->tx_lx_tx_band[i]); - DBG("tx_l%d_tx_drv_lvl =3D 0x%x", i, cfg->tx_lx_tx_drv_lvl[i]); - DBG("tx_l%d_tx_emp_post1_lvl =3D 0x%x", i, - cfg->tx_lx_tx_emp_post1_lvl[i]); - DBG("tx_l%d_vmode_ctrl1 =3D 0x%x", i, cfg->tx_lx_vmode_ctrl1[i]); - DBG("tx_l%d_vmode_ctrl2 =3D 0x%x", i, cfg->tx_lx_vmode_ctrl2[i]); - } - - return 0; -} - -static int hdmi_8996_pll_set_clk_rate(struct clk_hw *hw, unsigned long rat= e, - unsigned long parent_rate) -{ - struct hdmi_pll_8996 *pll =3D hw_clk_to_pll(hw); - struct hdmi_phy *phy =3D pll_get_phy(pll); - struct hdmi_8996_phy_pll_reg_cfg cfg; - int i, ret; - - memset(&cfg, 0x00, sizeof(cfg)); - - ret =3D pll_calculate(rate, parent_rate, &cfg); - if (ret) { - DRM_ERROR("PLL calculation failed\n"); - return ret; - } - - /* Initially shut down PHY */ - DBG("Disabling PHY"); - hdmi_phy_write(phy, REG_HDMI_8996_PHY_PD_CTL, 0x0); - udelay(500); - - /* Power up sequence */ - hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_BG_CTRL, 0x04); - - hdmi_phy_write(phy, REG_HDMI_8996_PHY_PD_CTL, 0x1); - hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_RESETSM_CNTRL, 0x20); - hdmi_phy_write(phy, REG_HDMI_8996_PHY_TX0_TX1_LANE_CTL, 0x0F); - hdmi_phy_write(phy, REG_HDMI_8996_PHY_TX2_TX3_LANE_CTL, 0x0F); - - for (i =3D 0; i < HDMI_NUM_TX_CHANNEL; i++) { - hdmi_tx_chan_write(pll, i, - REG_HDMI_PHY_QSERDES_TX_LX_CLKBUF_ENABLE, - 0x03); - hdmi_tx_chan_write(pll, i, - REG_HDMI_PHY_QSERDES_TX_LX_TX_BAND, - cfg.tx_lx_tx_band[i]); - hdmi_tx_chan_write(pll, i, - REG_HDMI_PHY_QSERDES_TX_LX_RESET_TSYNC_EN, - 0x03); - } - - hdmi_tx_chan_write(pll, 0, REG_HDMI_PHY_QSERDES_TX_LX_LANE_MODE, - cfg.tx_lx_lane_mode[0]); - hdmi_tx_chan_write(pll, 2, REG_HDMI_PHY_QSERDES_TX_LX_LANE_MODE, - cfg.tx_lx_lane_mode[2]); - - hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_SYSCLK_BUF_ENABLE, 0x1E); - hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x07); - hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_SYSCLK_EN_SEL, 0x37); - hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_SYS_CLK_CTRL, 0x02); - hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_CLK_ENABLE1, 0x0E); - - /* Bypass VCO calibration */ - hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_SVS_MODE_CLK_SEL, - cfg.com_svs_mode_clk_sel); - - hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_BG_TRIM, 0x0F); - hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_PLL_IVCO, 0x0F); - hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_VCO_TUNE_CTRL, - cfg.com_vco_tune_ctrl); - - hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_BG_CTRL, 0x06); - - hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_CLK_SELECT, 0x30); - hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_HSCLK_SEL, - cfg.com_hsclk_sel); - hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_LOCK_CMP_EN, - cfg.com_lock_cmp_en); - - hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_PLL_CCTRL_MODE0, - cfg.com_pll_cctrl_mode0); - hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_PLL_RCTRL_MODE0, - cfg.com_pll_rctrl_mode0); - hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_CP_CTRL_MODE0, - cfg.com_cp_ctrl_mode0); - hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_DEC_START_MODE0, - cfg.com_dec_start_mode0); - hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_DIV_FRAC_START1_MODE0, - cfg.com_div_frac_start1_mode0); - hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_DIV_FRAC_START2_MODE0, - cfg.com_div_frac_start2_mode0); - hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_DIV_FRAC_START3_MODE0, - cfg.com_div_frac_start3_mode0); - - hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_INTEGLOOP_GAIN0_MODE0, - cfg.com_integloop_gain0_mode0); - hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_INTEGLOOP_GAIN1_MODE0, - cfg.com_integloop_gain1_mode0); - - hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_LOCK_CMP1_MODE0, - cfg.com_lock_cmp1_mode0); - hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_LOCK_CMP2_MODE0, - cfg.com_lock_cmp2_mode0); - hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_LOCK_CMP3_MODE0, - cfg.com_lock_cmp3_mode0); - - hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_VCO_TUNE_MAP, 0x00); - hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_CORE_CLK_EN, - cfg.com_core_clk_en); - hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_CORECLK_DIV, - cfg.com_coreclk_div); - hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_CMN_CONFIG, 0x02); - - hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_RESCODE_DIV_NUM, 0x15); - - /* TX lanes setup (TX 0/1/2/3) */ - for (i =3D 0; i < HDMI_NUM_TX_CHANNEL; i++) { - hdmi_tx_chan_write(pll, i, - REG_HDMI_PHY_QSERDES_TX_LX_TX_DRV_LVL, - cfg.tx_lx_tx_drv_lvl[i]); - hdmi_tx_chan_write(pll, i, - REG_HDMI_PHY_QSERDES_TX_LX_TX_EMP_POST1_LVL, - cfg.tx_lx_tx_emp_post1_lvl[i]); - hdmi_tx_chan_write(pll, i, - REG_HDMI_PHY_QSERDES_TX_LX_VMODE_CTRL1, - cfg.tx_lx_vmode_ctrl1[i]); - hdmi_tx_chan_write(pll, i, - REG_HDMI_PHY_QSERDES_TX_LX_VMODE_CTRL2, - cfg.tx_lx_vmode_ctrl2[i]); - hdmi_tx_chan_write(pll, i, - REG_HDMI_PHY_QSERDES_TX_LX_TX_DRV_LVL_OFFSET, - 0x00); - hdmi_tx_chan_write(pll, i, - REG_HDMI_PHY_QSERDES_TX_LX_RES_CODE_LANE_OFFSET, - 0x00); - hdmi_tx_chan_write(pll, i, - REG_HDMI_PHY_QSERDES_TX_LX_TRAN_DRVR_EMP_EN, - 0x03); - hdmi_tx_chan_write(pll, i, - REG_HDMI_PHY_QSERDES_TX_LX_PARRATE_REC_DETECT_IDLE_EN, - 0x40); - hdmi_tx_chan_write(pll, i, - REG_HDMI_PHY_QSERDES_TX_LX_HP_PD_ENABLES, - cfg.tx_lx_hp_pd_enables[i]); - } - - hdmi_phy_write(phy, REG_HDMI_8996_PHY_MODE, cfg.phy_mode); - hdmi_phy_write(phy, REG_HDMI_8996_PHY_PD_CTL, 0x1F); - - /* - * Ensure that vco configuration gets flushed to hardware before - * enabling the PLL - */ - wmb(); - - return 0; -} - -static int hdmi_8996_phy_ready_status(struct hdmi_phy *phy) -{ - u32 nb_tries =3D HDMI_PLL_POLL_MAX_READS; - unsigned long timeout =3D HDMI_PLL_POLL_TIMEOUT_US; - u32 status; - int phy_ready =3D 0; - - DBG("Waiting for PHY ready"); - - while (nb_tries--) { - status =3D hdmi_phy_read(phy, REG_HDMI_8996_PHY_STATUS); - phy_ready =3D status & BIT(0); - - if (phy_ready) - break; - - udelay(timeout); - } - - DBG("PHY is %sready", phy_ready ? "" : "*not* "); - - return phy_ready; -} - -static int hdmi_8996_pll_lock_status(struct hdmi_pll_8996 *pll) -{ - u32 status; - int nb_tries =3D HDMI_PLL_POLL_MAX_READS; - unsigned long timeout =3D HDMI_PLL_POLL_TIMEOUT_US; - int pll_locked =3D 0; - - DBG("Waiting for PLL lock"); - - while (nb_tries--) { - status =3D hdmi_pll_read(pll, - REG_HDMI_PHY_QSERDES_COM_C_READY_STATUS); - pll_locked =3D status & BIT(0); - - if (pll_locked) - break; - - udelay(timeout); - } - - DBG("HDMI PLL is %slocked", pll_locked ? "" : "*not* "); - - return pll_locked; -} - -static int hdmi_8996_pll_prepare(struct clk_hw *hw) -{ - struct hdmi_pll_8996 *pll =3D hw_clk_to_pll(hw); - struct hdmi_phy *phy =3D pll_get_phy(pll); - int i, ret =3D 0; - - hdmi_phy_write(phy, REG_HDMI_8996_PHY_CFG, 0x1); - udelay(100); - - hdmi_phy_write(phy, REG_HDMI_8996_PHY_CFG, 0x19); - udelay(100); - - ret =3D hdmi_8996_pll_lock_status(pll); - if (!ret) - return ret; - - for (i =3D 0; i < HDMI_NUM_TX_CHANNEL; i++) - hdmi_tx_chan_write(pll, i, - REG_HDMI_PHY_QSERDES_TX_LX_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN, - 0x6F); - - /* Disable SSC */ - hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_SSC_PER1, 0x0); - hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_SSC_PER2, 0x0); - hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_SSC_STEP_SIZE1, 0x0); - hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_SSC_STEP_SIZE2, 0x0); - hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_SSC_EN_CENTER, 0x2); - - ret =3D hdmi_8996_phy_ready_status(phy); - if (!ret) - return ret; - - /* Restart the retiming buffer */ - hdmi_phy_write(phy, REG_HDMI_8996_PHY_CFG, 0x18); - udelay(1); - hdmi_phy_write(phy, REG_HDMI_8996_PHY_CFG, 0x19); - - return 0; -} - -static int hdmi_8996_pll_determine_rate(struct clk_hw *hw, - struct clk_rate_request *req) -{ - req->rate =3D clamp_t(unsigned long, req->rate, HDMI_PCLK_MIN_FREQ, HDMI_= PCLK_MAX_FREQ); - - return 0; -} - -static unsigned long hdmi_8996_pll_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) -{ - struct hdmi_pll_8996 *pll =3D hw_clk_to_pll(hw); - u64 fdata; - u32 cmp1, cmp2, cmp3, pll_cmp; - - cmp1 =3D hdmi_pll_read(pll, REG_HDMI_PHY_QSERDES_COM_LOCK_CMP1_MODE0); - cmp2 =3D hdmi_pll_read(pll, REG_HDMI_PHY_QSERDES_COM_LOCK_CMP2_MODE0); - cmp3 =3D hdmi_pll_read(pll, REG_HDMI_PHY_QSERDES_COM_LOCK_CMP3_MODE0); - - pll_cmp =3D cmp1 | (cmp2 << 8) | (cmp3 << 16); - - fdata =3D pll_cmp_to_fdata(pll_cmp + 1, parent_rate); - - do_div(fdata, 10); - - return fdata; -} - -static void hdmi_8996_pll_unprepare(struct clk_hw *hw) -{ - struct hdmi_pll_8996 *pll =3D hw_clk_to_pll(hw); - struct hdmi_phy *phy =3D pll_get_phy(pll); - - hdmi_phy_write(phy, REG_HDMI_8996_PHY_CFG, 0x6); - usleep_range(100, 150); -} - -static int hdmi_8996_pll_is_enabled(struct clk_hw *hw) -{ - struct hdmi_pll_8996 *pll =3D hw_clk_to_pll(hw); - u32 status; - int pll_locked; - - status =3D hdmi_pll_read(pll, REG_HDMI_PHY_QSERDES_COM_C_READY_STATUS); - pll_locked =3D status & BIT(0); - - return pll_locked; -} - -static const struct clk_ops hdmi_8996_pll_ops =3D { - .set_rate =3D hdmi_8996_pll_set_clk_rate, - .determine_rate =3D hdmi_8996_pll_determine_rate, - .recalc_rate =3D hdmi_8996_pll_recalc_rate, - .prepare =3D hdmi_8996_pll_prepare, - .unprepare =3D hdmi_8996_pll_unprepare, - .is_enabled =3D hdmi_8996_pll_is_enabled, -}; - -static const struct clk_init_data pll_init =3D { - .name =3D "hdmipll", - .ops =3D &hdmi_8996_pll_ops, - .parent_data =3D (const struct clk_parent_data[]){ - { .fw_name =3D "xo", .name =3D "xo_board" }, - }, - .num_parents =3D 1, - .flags =3D CLK_IGNORE_UNUSED, -}; - -int msm_hdmi_pll_8996_init(struct platform_device *pdev) -{ - struct device *dev =3D &pdev->dev; - struct hdmi_pll_8996 *pll; - int i, ret; - - pll =3D devm_kzalloc(dev, sizeof(*pll), GFP_KERNEL); - if (!pll) - return -ENOMEM; - - pll->pdev =3D pdev; - - pll->mmio_qserdes_com =3D msm_ioremap(pdev, "hdmi_pll"); - if (IS_ERR(pll->mmio_qserdes_com)) { - DRM_DEV_ERROR(dev, "failed to map pll base\n"); - return -ENOMEM; - } - - for (i =3D 0; i < HDMI_NUM_TX_CHANNEL; i++) { - char name[32]; - - snprintf(name, sizeof(name), "hdmi_tx_l%d", i); - - pll->mmio_qserdes_tx[i] =3D msm_ioremap(pdev, name); - if (IS_ERR(pll->mmio_qserdes_tx[i])) { - DRM_DEV_ERROR(dev, "failed to map pll base\n"); - return -ENOMEM; - } - } - pll->clk_hw.init =3D &pll_init; - - ret =3D devm_clk_hw_register(dev, &pll->clk_hw); - if (ret) { - DRM_DEV_ERROR(dev, "failed to register pll clock\n"); - return ret; - } - - ret =3D devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, &pll->clk_= hw); - if (ret) { - DRM_DEV_ERROR(dev, "%s: failed to register clk provider: %d\n", __func__= , ret); - return ret; - } - - return 0; -} - -static const char * const hdmi_phy_8996_reg_names[] =3D { - "vddio", - "vcca", -}; - -static const char * const hdmi_phy_8996_clk_names[] =3D { - "iface", "ref", -}; - -const struct hdmi_phy_cfg msm_hdmi_phy_8996_cfg =3D { - .type =3D MSM_HDMI_PHY_8996, - .reg_names =3D hdmi_phy_8996_reg_names, - .num_regs =3D ARRAY_SIZE(hdmi_phy_8996_reg_names), - .clk_names =3D hdmi_phy_8996_clk_names, - .num_clks =3D ARRAY_SIZE(hdmi_phy_8996_clk_names), -}; diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_phy_8998.c b/drivers/gpu/drm/msm= /hdmi/hdmi_phy_8998.c deleted file mode 100644 index a86ff3706369..000000000000 --- a/drivers/gpu/drm/msm/hdmi/hdmi_phy_8998.c +++ /dev/null @@ -1,765 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (c) 2016, The Linux Foundation. All rights reserved. - * Copyright (c) 2024 Freebox SAS - */ - -#include -#include - -#include "hdmi.h" - -#define HDMI_VCO_MAX_FREQ 12000000000UL -#define HDMI_VCO_MIN_FREQ 8000000000UL - -#define HDMI_PCLK_MAX_FREQ 600000000 -#define HDMI_PCLK_MIN_FREQ 25000000 - -#define HDMI_HIGH_FREQ_BIT_CLK_THRESHOLD 3400000000UL -#define HDMI_DIG_FREQ_BIT_CLK_THRESHOLD 1500000000UL -#define HDMI_MID_FREQ_BIT_CLK_THRESHOLD 750000000UL -#define HDMI_CORECLK_DIV 5 -#define HDMI_DEFAULT_REF_CLOCK 19200000 -#define HDMI_PLL_CMP_CNT 1024 - -#define HDMI_PLL_POLL_MAX_READS 100 -#define HDMI_PLL_POLL_TIMEOUT_US 150 - -#define HDMI_NUM_TX_CHANNEL 4 - -struct hdmi_pll_8998 { - struct platform_device *pdev; - struct clk_hw clk_hw; - unsigned long rate; - - /* pll mmio base */ - void __iomem *mmio_qserdes_com; - /* tx channel base */ - void __iomem *mmio_qserdes_tx[HDMI_NUM_TX_CHANNEL]; -}; - -#define hw_clk_to_pll(x) container_of(x, struct hdmi_pll_8998, clk_hw) - -struct hdmi_8998_phy_pll_reg_cfg { - u32 com_svs_mode_clk_sel; - u32 com_hsclk_sel; - u32 com_pll_cctrl_mode0; - u32 com_pll_rctrl_mode0; - u32 com_cp_ctrl_mode0; - u32 com_dec_start_mode0; - u32 com_div_frac_start1_mode0; - u32 com_div_frac_start2_mode0; - u32 com_div_frac_start3_mode0; - u32 com_integloop_gain0_mode0; - u32 com_integloop_gain1_mode0; - u32 com_lock_cmp_en; - u32 com_lock_cmp1_mode0; - u32 com_lock_cmp2_mode0; - u32 com_lock_cmp3_mode0; - u32 com_core_clk_en; - u32 com_coreclk_div_mode0; - - u32 tx_lx_tx_band[HDMI_NUM_TX_CHANNEL]; - u32 tx_lx_tx_drv_lvl[HDMI_NUM_TX_CHANNEL]; - u32 tx_lx_tx_emp_post1_lvl[HDMI_NUM_TX_CHANNEL]; - u32 tx_lx_pre_driver_1[HDMI_NUM_TX_CHANNEL]; - u32 tx_lx_pre_driver_2[HDMI_NUM_TX_CHANNEL]; - u32 tx_lx_res_code_offset[HDMI_NUM_TX_CHANNEL]; - - u32 phy_mode; -}; - -struct hdmi_8998_post_divider { - u64 vco_freq; - int hsclk_divsel; - int vco_ratio; - int tx_band_sel; - int half_rate_mode; -}; - -static inline struct hdmi_phy *pll_get_phy(struct hdmi_pll_8998 *pll) -{ - return platform_get_drvdata(pll->pdev); -} - -static inline void hdmi_pll_write(struct hdmi_pll_8998 *pll, int offset, - u32 data) -{ - writel(data, pll->mmio_qserdes_com + offset); -} - -static inline u32 hdmi_pll_read(struct hdmi_pll_8998 *pll, int offset) -{ - return readl(pll->mmio_qserdes_com + offset); -} - -static inline void hdmi_tx_chan_write(struct hdmi_pll_8998 *pll, int chann= el, - int offset, int data) -{ - writel(data, pll->mmio_qserdes_tx[channel] + offset); -} - -static inline u32 pll_get_cpctrl(u64 frac_start, unsigned long ref_clk, - bool gen_ssc) -{ - if ((frac_start !=3D 0) || gen_ssc) - return 0x8; - - return 0x30; -} - -static inline u32 pll_get_rctrl(u64 frac_start, bool gen_ssc) -{ - if ((frac_start !=3D 0) || gen_ssc) - return 0x16; - - return 0x18; -} - -static inline u32 pll_get_cctrl(u64 frac_start, bool gen_ssc) -{ - if ((frac_start !=3D 0) || gen_ssc) - return 0x34; - - return 0x2; -} - -static inline u32 pll_get_integloop_gain(u64 frac_start, u64 bclk, u32 ref= _clk, - bool gen_ssc) -{ - int digclk_divsel =3D bclk > HDMI_DIG_FREQ_BIT_CLK_THRESHOLD ? 1 : 2; - u64 base; - - if ((frac_start !=3D 0) || gen_ssc) - base =3D 0x3F; - else - base =3D 0xC4; - - base <<=3D (digclk_divsel =3D=3D 2 ? 1 : 0); - - return base; -} - -static inline u32 pll_get_pll_cmp(u64 fdata, unsigned long ref_clk) -{ - u64 dividend =3D HDMI_PLL_CMP_CNT * fdata; - u32 divisor =3D ref_clk * 10; - u32 rem; - - rem =3D do_div(dividend, divisor); - if (rem > (divisor >> 1)) - dividend++; - - return dividend - 1; -} - -#define HDMI_REF_CLOCK_HZ ((u64)19200000) -#define HDMI_MHZ_TO_HZ ((u64)1000000) -static int pll_get_post_div(struct hdmi_8998_post_divider *pd, u64 bclk) -{ - static const u32 ratio_list[] =3D {1, 2, 3, 4, 5, 6, 9, 10, 12, 15, 25}; - static const u32 band_list[] =3D {0, 1, 2, 3}; - u32 const sz_ratio =3D ARRAY_SIZE(ratio_list); - u32 const sz_band =3D ARRAY_SIZE(band_list); - u32 const cmp_cnt =3D 1024; - u32 const th_min =3D 500, th_max =3D 1000; - u32 half_rate_mode =3D 0; - u32 list_elements; - int optimal_index; - u32 i, j, k; - u32 found_hsclk_divsel =3D 0, found_vco_ratio; - u32 found_tx_band_sel; - u64 const min_freq =3D HDMI_VCO_MIN_FREQ, max_freq =3D HDMI_VCO_MAX_FREQ; - u64 freq_list[ARRAY_SIZE(ratio_list) * ARRAY_SIZE(band_list)]; - u64 found_vco_freq; - u64 freq_optimal; - -find_optimal_index: - freq_optimal =3D max_freq; - optimal_index =3D -1; - list_elements =3D 0; - - for (i =3D 0; i < sz_ratio; i++) { - for (j =3D 0; j < sz_band; j++) { - u64 freq =3D div_u64(bclk, (1 << half_rate_mode)); - - freq *=3D (ratio_list[i] * (1 << band_list[j])); - freq_list[list_elements++] =3D freq; - } - } - - for (k =3D 0; k < ARRAY_SIZE(freq_list); k++) { - u32 const clks_pll_div =3D 2, core_clk_div =3D 5; - u32 const rng1 =3D 16, rng2 =3D 8; - u32 th1, th2; - u64 core_clk, rvar1, rem; - - core_clk =3D div_u64(freq_list[k], - ratio_list[k / sz_band] * clks_pll_div * - core_clk_div); - - rvar1 =3D HDMI_REF_CLOCK_HZ * rng1 * HDMI_MHZ_TO_HZ; - rvar1 =3D div64_u64_rem(rvar1, (cmp_cnt * core_clk), &rem); - if (rem > ((cmp_cnt * core_clk) >> 1)) - rvar1++; - th1 =3D rvar1; - - rvar1 =3D HDMI_REF_CLOCK_HZ * rng2 * HDMI_MHZ_TO_HZ; - rvar1 =3D div64_u64_rem(rvar1, (cmp_cnt * core_clk), &rem); - if (rem > ((cmp_cnt * core_clk) >> 1)) - rvar1++; - th2 =3D rvar1; - - if (freq_list[k] >=3D min_freq && - freq_list[k] <=3D max_freq) { - if ((th1 >=3D th_min && th1 <=3D th_max) || - (th2 >=3D th_min && th2 <=3D th_max)) { - if (freq_list[k] <=3D freq_optimal) { - freq_optimal =3D freq_list[k]; - optimal_index =3D k; - } - } - } - } - - if (optimal_index =3D=3D -1) { - if (!half_rate_mode) { - half_rate_mode =3D 1; - goto find_optimal_index; - } else { - return -EINVAL; - } - } else { - found_vco_ratio =3D ratio_list[optimal_index / sz_band]; - found_tx_band_sel =3D band_list[optimal_index % sz_band]; - found_vco_freq =3D freq_optimal; - } - - switch (found_vco_ratio) { - case 1: - found_hsclk_divsel =3D 15; - break; - case 2: - found_hsclk_divsel =3D 0; - break; - case 3: - found_hsclk_divsel =3D 4; - break; - case 4: - found_hsclk_divsel =3D 8; - break; - case 5: - found_hsclk_divsel =3D 12; - break; - case 6: - found_hsclk_divsel =3D 1; - break; - case 9: - found_hsclk_divsel =3D 5; - break; - case 10: - found_hsclk_divsel =3D 2; - break; - case 12: - found_hsclk_divsel =3D 9; - break; - case 15: - found_hsclk_divsel =3D 13; - break; - case 25: - found_hsclk_divsel =3D 14; - break; - } - - pd->vco_freq =3D found_vco_freq; - pd->tx_band_sel =3D found_tx_band_sel; - pd->vco_ratio =3D found_vco_ratio; - pd->hsclk_divsel =3D found_hsclk_divsel; - - return 0; -} - -static int pll_calculate(unsigned long pix_clk, unsigned long ref_clk, - struct hdmi_8998_phy_pll_reg_cfg *cfg) -{ - struct hdmi_8998_post_divider pd; - u64 bclk; - u64 dec_start; - u64 frac_start; - u64 fdata; - u32 pll_divisor; - u32 rem; - u32 cpctrl; - u32 rctrl; - u32 cctrl; - u32 integloop_gain; - u32 pll_cmp; - int i, ret; - - /* bit clk =3D 10 * pix_clk */ - bclk =3D ((u64)pix_clk) * 10; - - ret =3D pll_get_post_div(&pd, bclk); - if (ret) - return ret; - - dec_start =3D pd.vco_freq; - pll_divisor =3D 4 * ref_clk; - do_div(dec_start, pll_divisor); - - frac_start =3D pd.vco_freq * (1 << 20); - - rem =3D do_div(frac_start, pll_divisor); - frac_start -=3D dec_start * (1 << 20); - if (rem > (pll_divisor >> 1)) - frac_start++; - - cpctrl =3D pll_get_cpctrl(frac_start, ref_clk, false); - rctrl =3D pll_get_rctrl(frac_start, false); - cctrl =3D pll_get_cctrl(frac_start, false); - integloop_gain =3D pll_get_integloop_gain(frac_start, bclk, - ref_clk, false); - - fdata =3D pd.vco_freq; - do_div(fdata, pd.vco_ratio); - - pll_cmp =3D pll_get_pll_cmp(fdata, ref_clk); - - /* Convert these values to register specific values */ - if (bclk > HDMI_DIG_FREQ_BIT_CLK_THRESHOLD) - cfg->com_svs_mode_clk_sel =3D 1; - else - cfg->com_svs_mode_clk_sel =3D 2; - - cfg->com_hsclk_sel =3D (0x20 | pd.hsclk_divsel); - cfg->com_pll_cctrl_mode0 =3D cctrl; - cfg->com_pll_rctrl_mode0 =3D rctrl; - cfg->com_cp_ctrl_mode0 =3D cpctrl; - cfg->com_dec_start_mode0 =3D dec_start; - cfg->com_div_frac_start1_mode0 =3D (frac_start & 0xff); - cfg->com_div_frac_start2_mode0 =3D ((frac_start & 0xff00) >> 8); - cfg->com_div_frac_start3_mode0 =3D ((frac_start & 0xf0000) >> 16); - cfg->com_integloop_gain0_mode0 =3D (integloop_gain & 0xff); - cfg->com_integloop_gain1_mode0 =3D ((integloop_gain & 0xf00) >> 8); - cfg->com_lock_cmp1_mode0 =3D (pll_cmp & 0xff); - cfg->com_lock_cmp2_mode0 =3D ((pll_cmp & 0xff00) >> 8); - cfg->com_lock_cmp3_mode0 =3D ((pll_cmp & 0x30000) >> 16); - cfg->com_lock_cmp_en =3D 0x0; - cfg->com_core_clk_en =3D 0x2c; - cfg->com_coreclk_div_mode0 =3D HDMI_CORECLK_DIV; - cfg->phy_mode =3D (bclk > HDMI_HIGH_FREQ_BIT_CLK_THRESHOLD) ? 0x5 : 0x4; - - for (i =3D 0; i < HDMI_NUM_TX_CHANNEL; i++) - cfg->tx_lx_tx_band[i] =3D pd.tx_band_sel; - - if (bclk > HDMI_HIGH_FREQ_BIT_CLK_THRESHOLD) { - cfg->tx_lx_tx_drv_lvl[0] =3D 0x0f; - cfg->tx_lx_tx_drv_lvl[1] =3D 0x0f; - cfg->tx_lx_tx_drv_lvl[2] =3D 0x0f; - cfg->tx_lx_tx_drv_lvl[3] =3D 0x0f; - cfg->tx_lx_tx_emp_post1_lvl[0] =3D 0x03; - cfg->tx_lx_tx_emp_post1_lvl[1] =3D 0x02; - cfg->tx_lx_tx_emp_post1_lvl[2] =3D 0x03; - cfg->tx_lx_tx_emp_post1_lvl[3] =3D 0x00; - cfg->tx_lx_pre_driver_1[0] =3D 0x00; - cfg->tx_lx_pre_driver_1[1] =3D 0x00; - cfg->tx_lx_pre_driver_1[2] =3D 0x00; - cfg->tx_lx_pre_driver_1[3] =3D 0x00; - cfg->tx_lx_pre_driver_2[0] =3D 0x1C; - cfg->tx_lx_pre_driver_2[1] =3D 0x1C; - cfg->tx_lx_pre_driver_2[2] =3D 0x1C; - cfg->tx_lx_pre_driver_2[3] =3D 0x00; - cfg->tx_lx_res_code_offset[0] =3D 0x03; - cfg->tx_lx_res_code_offset[1] =3D 0x00; - cfg->tx_lx_res_code_offset[2] =3D 0x00; - cfg->tx_lx_res_code_offset[3] =3D 0x03; - } else if (bclk > HDMI_DIG_FREQ_BIT_CLK_THRESHOLD) { - cfg->tx_lx_tx_drv_lvl[0] =3D 0x0f; - cfg->tx_lx_tx_drv_lvl[1] =3D 0x0f; - cfg->tx_lx_tx_drv_lvl[2] =3D 0x0f; - cfg->tx_lx_tx_drv_lvl[3] =3D 0x0f; - cfg->tx_lx_tx_emp_post1_lvl[0] =3D 0x03; - cfg->tx_lx_tx_emp_post1_lvl[1] =3D 0x03; - cfg->tx_lx_tx_emp_post1_lvl[2] =3D 0x03; - cfg->tx_lx_tx_emp_post1_lvl[3] =3D 0x00; - cfg->tx_lx_pre_driver_1[0] =3D 0x00; - cfg->tx_lx_pre_driver_1[1] =3D 0x00; - cfg->tx_lx_pre_driver_1[2] =3D 0x00; - cfg->tx_lx_pre_driver_1[3] =3D 0x00; - cfg->tx_lx_pre_driver_2[0] =3D 0x16; - cfg->tx_lx_pre_driver_2[1] =3D 0x16; - cfg->tx_lx_pre_driver_2[2] =3D 0x16; - cfg->tx_lx_pre_driver_2[3] =3D 0x18; - cfg->tx_lx_res_code_offset[0] =3D 0x03; - cfg->tx_lx_res_code_offset[1] =3D 0x00; - cfg->tx_lx_res_code_offset[2] =3D 0x00; - cfg->tx_lx_res_code_offset[3] =3D 0x00; - } else if (bclk > HDMI_MID_FREQ_BIT_CLK_THRESHOLD) { - cfg->tx_lx_tx_drv_lvl[0] =3D 0x0f; - cfg->tx_lx_tx_drv_lvl[1] =3D 0x0f; - cfg->tx_lx_tx_drv_lvl[2] =3D 0x0f; - cfg->tx_lx_tx_drv_lvl[3] =3D 0x0f; - cfg->tx_lx_tx_emp_post1_lvl[0] =3D 0x05; - cfg->tx_lx_tx_emp_post1_lvl[1] =3D 0x05; - cfg->tx_lx_tx_emp_post1_lvl[2] =3D 0x05; - cfg->tx_lx_tx_emp_post1_lvl[3] =3D 0x00; - cfg->tx_lx_pre_driver_1[0] =3D 0x00; - cfg->tx_lx_pre_driver_1[1] =3D 0x00; - cfg->tx_lx_pre_driver_1[2] =3D 0x00; - cfg->tx_lx_pre_driver_1[3] =3D 0x00; - cfg->tx_lx_pre_driver_2[0] =3D 0x0E; - cfg->tx_lx_pre_driver_2[1] =3D 0x0E; - cfg->tx_lx_pre_driver_2[2] =3D 0x0E; - cfg->tx_lx_pre_driver_2[3] =3D 0x0E; - cfg->tx_lx_res_code_offset[0] =3D 0x00; - cfg->tx_lx_res_code_offset[1] =3D 0x00; - cfg->tx_lx_res_code_offset[2] =3D 0x00; - cfg->tx_lx_res_code_offset[3] =3D 0x00; - } else { - cfg->tx_lx_tx_drv_lvl[0] =3D 0x01; - cfg->tx_lx_tx_drv_lvl[1] =3D 0x01; - cfg->tx_lx_tx_drv_lvl[2] =3D 0x01; - cfg->tx_lx_tx_drv_lvl[3] =3D 0x00; - cfg->tx_lx_tx_emp_post1_lvl[0] =3D 0x00; - cfg->tx_lx_tx_emp_post1_lvl[1] =3D 0x00; - cfg->tx_lx_tx_emp_post1_lvl[2] =3D 0x00; - cfg->tx_lx_tx_emp_post1_lvl[3] =3D 0x00; - cfg->tx_lx_pre_driver_1[0] =3D 0x00; - cfg->tx_lx_pre_driver_1[1] =3D 0x00; - cfg->tx_lx_pre_driver_1[2] =3D 0x00; - cfg->tx_lx_pre_driver_1[3] =3D 0x00; - cfg->tx_lx_pre_driver_2[0] =3D 0x16; - cfg->tx_lx_pre_driver_2[1] =3D 0x16; - cfg->tx_lx_pre_driver_2[2] =3D 0x16; - cfg->tx_lx_pre_driver_2[3] =3D 0x18; - cfg->tx_lx_res_code_offset[0] =3D 0x00; - cfg->tx_lx_res_code_offset[1] =3D 0x00; - cfg->tx_lx_res_code_offset[2] =3D 0x00; - cfg->tx_lx_res_code_offset[3] =3D 0x00; - } - - return 0; -} - -static int hdmi_8998_pll_set_clk_rate(struct clk_hw *hw, unsigned long rat= e, - unsigned long parent_rate) -{ - struct hdmi_pll_8998 *pll =3D hw_clk_to_pll(hw); - struct hdmi_phy *phy =3D pll_get_phy(pll); - struct hdmi_8998_phy_pll_reg_cfg cfg =3D {}; - int i, ret; - - ret =3D pll_calculate(rate, parent_rate, &cfg); - if (ret) { - DRM_ERROR("PLL calculation failed\n"); - return ret; - } - - /* Initially shut down PHY */ - hdmi_phy_write(phy, REG_HDMI_8998_PHY_PD_CTL, 0x0); - udelay(500); - - /* Power up sequence */ - hdmi_phy_write(phy, REG_HDMI_8998_PHY_PD_CTL, 0x1); - hdmi_pll_write(pll, REG_HDMI_8998_PHY_QSERDES_COM_RESETSM_CNTRL, 0x20); - hdmi_phy_write(phy, REG_HDMI_8998_PHY_CMN_CTRL, 0x6); - - for (i =3D 0; i < HDMI_NUM_TX_CHANNEL; i++) { - hdmi_tx_chan_write(pll, i, - REG_HDMI_8998_PHY_TXn_INTERFACE_SELECT_TX_BAND, - cfg.tx_lx_tx_band[i]); - hdmi_tx_chan_write(pll, i, - REG_HDMI_8998_PHY_TXn_CLKBUF_TERM_ENABLE, - 0x1); - hdmi_tx_chan_write(pll, i, - REG_HDMI_8998_PHY_TXn_LANE_MODE, - 0x20); - } - - hdmi_pll_write(pll, REG_HDMI_8998_PHY_QSERDES_COM_SYSCLK_BUF_ENABLE, 0x02= ); - hdmi_pll_write(pll, REG_HDMI_8998_PHY_QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x= 0B); - hdmi_pll_write(pll, REG_HDMI_8998_PHY_QSERDES_COM_SYSCLK_EN_SEL, 0x37); - hdmi_pll_write(pll, REG_HDMI_8998_PHY_QSERDES_COM_SYS_CLK_CTRL, 0x02); - hdmi_pll_write(pll, REG_HDMI_8998_PHY_QSERDES_COM_CLK_ENABLE1, 0x0E); - - /* Bypass VCO calibration */ - hdmi_pll_write(pll, REG_HDMI_8998_PHY_QSERDES_COM_SVS_MODE_CLK_SEL, - cfg.com_svs_mode_clk_sel); - - hdmi_pll_write(pll, REG_HDMI_8998_PHY_QSERDES_COM_PLL_IVCO, 0x07); - hdmi_pll_write(pll, REG_HDMI_8998_PHY_QSERDES_COM_VCO_TUNE_CTRL, 0x00); - - hdmi_pll_write(pll, REG_HDMI_8998_PHY_QSERDES_COM_CLK_SEL, 0x30); - hdmi_pll_write(pll, REG_HDMI_8998_PHY_QSERDES_COM_HSCLK_SEL, - cfg.com_hsclk_sel); - hdmi_pll_write(pll, REG_HDMI_8998_PHY_QSERDES_COM_LOCK_CMP_EN, - cfg.com_lock_cmp_en); - - hdmi_pll_write(pll, REG_HDMI_8998_PHY_QSERDES_COM_PLL_CCTRL_MODE0, - cfg.com_pll_cctrl_mode0); - hdmi_pll_write(pll, REG_HDMI_8998_PHY_QSERDES_COM_PLL_RCTRL_MODE0, - cfg.com_pll_rctrl_mode0); - hdmi_pll_write(pll, REG_HDMI_8998_PHY_QSERDES_COM_CP_CTRL_MODE0, - cfg.com_cp_ctrl_mode0); - hdmi_pll_write(pll, REG_HDMI_8998_PHY_QSERDES_COM_DEC_START_MODE0, - cfg.com_dec_start_mode0); - hdmi_pll_write(pll, REG_HDMI_8998_PHY_QSERDES_COM_DIV_FRAC_START1_MODE0, - cfg.com_div_frac_start1_mode0); - hdmi_pll_write(pll, REG_HDMI_8998_PHY_QSERDES_COM_DIV_FRAC_START2_MODE0, - cfg.com_div_frac_start2_mode0); - hdmi_pll_write(pll, REG_HDMI_8998_PHY_QSERDES_COM_DIV_FRAC_START3_MODE0, - cfg.com_div_frac_start3_mode0); - - hdmi_pll_write(pll, REG_HDMI_8998_PHY_QSERDES_COM_INTEGLOOP_GAIN0_MODE0, - cfg.com_integloop_gain0_mode0); - hdmi_pll_write(pll, REG_HDMI_8998_PHY_QSERDES_COM_INTEGLOOP_GAIN1_MODE0, - cfg.com_integloop_gain1_mode0); - - hdmi_pll_write(pll, REG_HDMI_8998_PHY_QSERDES_COM_LOCK_CMP1_MODE0, - cfg.com_lock_cmp1_mode0); - hdmi_pll_write(pll, REG_HDMI_8998_PHY_QSERDES_COM_LOCK_CMP2_MODE0, - cfg.com_lock_cmp2_mode0); - hdmi_pll_write(pll, REG_HDMI_8998_PHY_QSERDES_COM_LOCK_CMP3_MODE0, - cfg.com_lock_cmp3_mode0); - - hdmi_pll_write(pll, REG_HDMI_8998_PHY_QSERDES_COM_VCO_TUNE_MAP, 0x00); - hdmi_pll_write(pll, REG_HDMI_8998_PHY_QSERDES_COM_CORE_CLK_EN, - cfg.com_core_clk_en); - hdmi_pll_write(pll, REG_HDMI_8998_PHY_QSERDES_COM_CORECLK_DIV_MODE0, - cfg.com_coreclk_div_mode0); - - /* TX lanes setup (TX 0/1/2/3) */ - for (i =3D 0; i < HDMI_NUM_TX_CHANNEL; i++) { - hdmi_tx_chan_write(pll, i, - REG_HDMI_8998_PHY_TXn_DRV_LVL, - cfg.tx_lx_tx_drv_lvl[i]); - hdmi_tx_chan_write(pll, i, - REG_HDMI_8998_PHY_TXn_EMP_POST1_LVL, - cfg.tx_lx_tx_emp_post1_lvl[i]); - hdmi_tx_chan_write(pll, i, - REG_HDMI_8998_PHY_TXn_PRE_DRIVER_1, - cfg.tx_lx_pre_driver_1[i]); - hdmi_tx_chan_write(pll, i, - REG_HDMI_8998_PHY_TXn_PRE_DRIVER_2, - cfg.tx_lx_pre_driver_2[i]); - hdmi_tx_chan_write(pll, i, - REG_HDMI_8998_PHY_TXn_DRV_LVL_RES_CODE_OFFSET, - cfg.tx_lx_res_code_offset[i]); - } - - hdmi_phy_write(phy, REG_HDMI_8998_PHY_MODE, cfg.phy_mode); - - for (i =3D 0; i < HDMI_NUM_TX_CHANNEL; i++) { - hdmi_tx_chan_write(pll, i, - REG_HDMI_8998_PHY_TXn_LANE_CONFIG, - 0x10); - } - - /* - * Ensure that vco configuration gets flushed to hardware before - * enabling the PLL - */ - wmb(); - - pll->rate =3D rate; - - return 0; -} - -static int hdmi_8998_phy_ready_status(struct hdmi_phy *phy) -{ - u32 nb_tries =3D HDMI_PLL_POLL_MAX_READS; - unsigned long timeout =3D HDMI_PLL_POLL_TIMEOUT_US; - u32 status; - int phy_ready =3D 0; - - while (nb_tries--) { - status =3D hdmi_phy_read(phy, REG_HDMI_8998_PHY_STATUS); - phy_ready =3D status & BIT(0); - - if (phy_ready) - break; - - udelay(timeout); - } - - return phy_ready; -} - -static int hdmi_8998_pll_lock_status(struct hdmi_pll_8998 *pll) -{ - u32 status; - int nb_tries =3D HDMI_PLL_POLL_MAX_READS; - unsigned long timeout =3D HDMI_PLL_POLL_TIMEOUT_US; - int pll_locked =3D 0; - - while (nb_tries--) { - status =3D hdmi_pll_read(pll, - REG_HDMI_8998_PHY_QSERDES_COM_C_READY_STATUS); - pll_locked =3D status & BIT(0); - - if (pll_locked) - break; - - udelay(timeout); - } - - return pll_locked; -} - -static int hdmi_8998_pll_prepare(struct clk_hw *hw) -{ - struct hdmi_pll_8998 *pll =3D hw_clk_to_pll(hw); - struct hdmi_phy *phy =3D pll_get_phy(pll); - int i, ret =3D 0; - - hdmi_phy_write(phy, REG_HDMI_8998_PHY_CFG, 0x1); - udelay(100); - - hdmi_phy_write(phy, REG_HDMI_8998_PHY_CFG, 0x59); - udelay(100); - - ret =3D hdmi_8998_pll_lock_status(pll); - if (!ret) - return ret; - - for (i =3D 0; i < HDMI_NUM_TX_CHANNEL; i++) { - hdmi_tx_chan_write(pll, i, - REG_HDMI_8998_PHY_TXn_LANE_CONFIG, 0x1F); - } - - /* Ensure all registers are flushed to hardware */ - wmb(); - - ret =3D hdmi_8998_phy_ready_status(phy); - if (!ret) - return ret; - - /* Restart the retiming buffer */ - hdmi_phy_write(phy, REG_HDMI_8998_PHY_CFG, 0x58); - udelay(1); - hdmi_phy_write(phy, REG_HDMI_8998_PHY_CFG, 0x59); - - /* Ensure all registers are flushed to hardware */ - wmb(); - - return 0; -} - -static int hdmi_8998_pll_determine_rate(struct clk_hw *hw, - struct clk_rate_request *req) -{ - req->rate =3D clamp_t(unsigned long, req->rate, HDMI_PCLK_MIN_FREQ, HDMI_= PCLK_MAX_FREQ); - - return 0; -} - -static unsigned long hdmi_8998_pll_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) -{ - struct hdmi_pll_8998 *pll =3D hw_clk_to_pll(hw); - return pll->rate; -} - -static void hdmi_8998_pll_unprepare(struct clk_hw *hw) -{ - struct hdmi_pll_8998 *pll =3D hw_clk_to_pll(hw); - struct hdmi_phy *phy =3D pll_get_phy(pll); - - hdmi_phy_write(phy, REG_HDMI_8998_PHY_PD_CTL, 0); - usleep_range(100, 150); -} - -static int hdmi_8998_pll_is_enabled(struct clk_hw *hw) -{ - struct hdmi_pll_8998 *pll =3D hw_clk_to_pll(hw); - u32 status; - int pll_locked; - - status =3D hdmi_pll_read(pll, REG_HDMI_8998_PHY_QSERDES_COM_C_READY_STATU= S); - pll_locked =3D status & BIT(0); - - return pll_locked; -} - -static const struct clk_ops hdmi_8998_pll_ops =3D { - .set_rate =3D hdmi_8998_pll_set_clk_rate, - .determine_rate =3D hdmi_8998_pll_determine_rate, - .recalc_rate =3D hdmi_8998_pll_recalc_rate, - .prepare =3D hdmi_8998_pll_prepare, - .unprepare =3D hdmi_8998_pll_unprepare, - .is_enabled =3D hdmi_8998_pll_is_enabled, -}; - -static const struct clk_init_data pll_init =3D { - .name =3D "hdmipll", - .ops =3D &hdmi_8998_pll_ops, - .parent_data =3D (const struct clk_parent_data[]){ - { .fw_name =3D "xo", .name =3D "xo_board" }, - }, - .num_parents =3D 1, - .flags =3D CLK_IGNORE_UNUSED, -}; - -int msm_hdmi_pll_8998_init(struct platform_device *pdev) -{ - struct device *dev =3D &pdev->dev; - struct hdmi_pll_8998 *pll; - int ret, i; - - pll =3D devm_kzalloc(dev, sizeof(*pll), GFP_KERNEL); - if (!pll) - return -ENOMEM; - - pll->pdev =3D pdev; - - pll->mmio_qserdes_com =3D msm_ioremap(pdev, "hdmi_pll"); - if (IS_ERR(pll->mmio_qserdes_com)) { - DRM_DEV_ERROR(dev, "failed to map pll base\n"); - return -ENOMEM; - } - - for (i =3D 0; i < HDMI_NUM_TX_CHANNEL; i++) { - char name[32]; - - snprintf(name, sizeof(name), "hdmi_tx_l%d", i); - - pll->mmio_qserdes_tx[i] =3D msm_ioremap(pdev, name); - if (IS_ERR(pll->mmio_qserdes_tx[i])) { - DRM_DEV_ERROR(dev, "failed to map pll base\n"); - return -ENOMEM; - } - } - pll->clk_hw.init =3D &pll_init; - - ret =3D devm_clk_hw_register(dev, &pll->clk_hw); - if (ret) { - DRM_DEV_ERROR(dev, "failed to register pll clock\n"); - return ret; - } - - ret =3D devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, &pll->clk_= hw); - if (ret) { - DRM_DEV_ERROR(dev, "failed to register clk provider: %d\n", ret); - return ret; - } - - return 0; -} - -static const char * const hdmi_phy_8998_reg_names[] =3D { - "vddio", - "vcca", -}; - -static const char * const hdmi_phy_8998_clk_names[] =3D { - "iface", "ref", "xo", -}; - -const struct hdmi_phy_cfg msm_hdmi_phy_8998_cfg =3D { - .type =3D MSM_HDMI_PHY_8998, - .reg_names =3D hdmi_phy_8998_reg_names, - .num_regs =3D ARRAY_SIZE(hdmi_phy_8998_reg_names), - .clk_names =3D hdmi_phy_8998_clk_names, - .num_clks =3D ARRAY_SIZE(hdmi_phy_8998_clk_names), -}; diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_phy_8x60.c b/drivers/gpu/drm/msm= /hdmi/hdmi_phy_8x60.c deleted file mode 100644 index 10ee91818364..000000000000 --- a/drivers/gpu/drm/msm/hdmi/hdmi_phy_8x60.c +++ /dev/null @@ -1,141 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) 2013 Red Hat - * Author: Rob Clark - */ - -#include - -#include "hdmi.h" - -static void hdmi_phy_8x60_powerup(struct hdmi_phy *phy, - unsigned long pixclock) -{ - /* De-serializer delay D/C for non-lbk mode: */ - hdmi_phy_write(phy, REG_HDMI_8x60_PHY_REG0, - HDMI_8x60_PHY_REG0_DESER_DEL_CTRL(3)); - - if (pixclock =3D=3D 27000000) { - /* video_format =3D=3D HDMI_VFRMT_720x480p60_16_9 */ - hdmi_phy_write(phy, REG_HDMI_8x60_PHY_REG1, - HDMI_8x60_PHY_REG1_DTEST_MUX_SEL(5) | - HDMI_8x60_PHY_REG1_OUTVOL_SWING_CTRL(3)); - } else { - hdmi_phy_write(phy, REG_HDMI_8x60_PHY_REG1, - HDMI_8x60_PHY_REG1_DTEST_MUX_SEL(5) | - HDMI_8x60_PHY_REG1_OUTVOL_SWING_CTRL(4)); - } - - /* No matter what, start from the power down mode: */ - hdmi_phy_write(phy, REG_HDMI_8x60_PHY_REG2, - HDMI_8x60_PHY_REG2_PD_PWRGEN | - HDMI_8x60_PHY_REG2_PD_PLL | - HDMI_8x60_PHY_REG2_PD_DRIVE_4 | - HDMI_8x60_PHY_REG2_PD_DRIVE_3 | - HDMI_8x60_PHY_REG2_PD_DRIVE_2 | - HDMI_8x60_PHY_REG2_PD_DRIVE_1 | - HDMI_8x60_PHY_REG2_PD_DESER); - - /* Turn PowerGen on: */ - hdmi_phy_write(phy, REG_HDMI_8x60_PHY_REG2, - HDMI_8x60_PHY_REG2_PD_PLL | - HDMI_8x60_PHY_REG2_PD_DRIVE_4 | - HDMI_8x60_PHY_REG2_PD_DRIVE_3 | - HDMI_8x60_PHY_REG2_PD_DRIVE_2 | - HDMI_8x60_PHY_REG2_PD_DRIVE_1 | - HDMI_8x60_PHY_REG2_PD_DESER); - - /* Turn PLL power on: */ - hdmi_phy_write(phy, REG_HDMI_8x60_PHY_REG2, - HDMI_8x60_PHY_REG2_PD_DRIVE_4 | - HDMI_8x60_PHY_REG2_PD_DRIVE_3 | - HDMI_8x60_PHY_REG2_PD_DRIVE_2 | - HDMI_8x60_PHY_REG2_PD_DRIVE_1 | - HDMI_8x60_PHY_REG2_PD_DESER); - - /* Write to HIGH after PLL power down de-assert: */ - hdmi_phy_write(phy, REG_HDMI_8x60_PHY_REG3, - HDMI_8x60_PHY_REG3_PLL_ENABLE); - - /* ASIC power on; PHY REG9 =3D 0 */ - hdmi_phy_write(phy, REG_HDMI_8x60_PHY_REG9, 0); - - /* Enable PLL lock detect, PLL lock det will go high after lock - * Enable the re-time logic - */ - hdmi_phy_write(phy, REG_HDMI_8x60_PHY_REG12, - HDMI_8x60_PHY_REG12_RETIMING_EN | - HDMI_8x60_PHY_REG12_PLL_LOCK_DETECT_EN); - - /* Drivers are on: */ - hdmi_phy_write(phy, REG_HDMI_8x60_PHY_REG2, - HDMI_8x60_PHY_REG2_PD_DESER); - - /* If the RX detector is needed: */ - hdmi_phy_write(phy, REG_HDMI_8x60_PHY_REG2, - HDMI_8x60_PHY_REG2_RCV_SENSE_EN | - HDMI_8x60_PHY_REG2_PD_DESER); - - hdmi_phy_write(phy, REG_HDMI_8x60_PHY_REG4, 0); - hdmi_phy_write(phy, REG_HDMI_8x60_PHY_REG5, 0); - hdmi_phy_write(phy, REG_HDMI_8x60_PHY_REG6, 0); - hdmi_phy_write(phy, REG_HDMI_8x60_PHY_REG7, 0); - hdmi_phy_write(phy, REG_HDMI_8x60_PHY_REG8, 0); - hdmi_phy_write(phy, REG_HDMI_8x60_PHY_REG9, 0); - hdmi_phy_write(phy, REG_HDMI_8x60_PHY_REG10, 0); - hdmi_phy_write(phy, REG_HDMI_8x60_PHY_REG11, 0); - - /* If we want to use lock enable based on counting: */ - hdmi_phy_write(phy, REG_HDMI_8x60_PHY_REG12, - HDMI_8x60_PHY_REG12_RETIMING_EN | - HDMI_8x60_PHY_REG12_PLL_LOCK_DETECT_EN | - HDMI_8x60_PHY_REG12_FORCE_LOCK); -} - -static void hdmi_phy_8x60_powerdown(struct hdmi_phy *phy) -{ - /* Assert RESET PHY from controller */ - hdmi_phy_write(phy, REG_HDMI_PHY_CTRL, - HDMI_PHY_CTRL_SW_RESET); - udelay(10); - /* De-assert RESET PHY from controller */ - hdmi_phy_write(phy, REG_HDMI_PHY_CTRL, 0); - /* Turn off Driver */ - hdmi_phy_write(phy, REG_HDMI_8x60_PHY_REG2, - HDMI_8x60_PHY_REG2_PD_DRIVE_4 | - HDMI_8x60_PHY_REG2_PD_DRIVE_3 | - HDMI_8x60_PHY_REG2_PD_DRIVE_2 | - HDMI_8x60_PHY_REG2_PD_DRIVE_1 | - HDMI_8x60_PHY_REG2_PD_DESER); - udelay(10); - /* Disable PLL */ - hdmi_phy_write(phy, REG_HDMI_8x60_PHY_REG3, 0); - /* Power down PHY, but keep RX-sense: */ - hdmi_phy_write(phy, REG_HDMI_8x60_PHY_REG2, - HDMI_8x60_PHY_REG2_RCV_SENSE_EN | - HDMI_8x60_PHY_REG2_PD_PWRGEN | - HDMI_8x60_PHY_REG2_PD_PLL | - HDMI_8x60_PHY_REG2_PD_DRIVE_4 | - HDMI_8x60_PHY_REG2_PD_DRIVE_3 | - HDMI_8x60_PHY_REG2_PD_DRIVE_2 | - HDMI_8x60_PHY_REG2_PD_DRIVE_1 | - HDMI_8x60_PHY_REG2_PD_DESER); -} - -static const char * const hdmi_phy_8x60_reg_names[] =3D { - "core-vdda", -}; - -static const char * const hdmi_phy_8x60_clk_names[] =3D { - "slave_iface", -}; - -const struct hdmi_phy_cfg msm_hdmi_phy_8x60_cfg =3D { - .type =3D MSM_HDMI_PHY_8x60, - .powerup =3D hdmi_phy_8x60_powerup, - .powerdown =3D hdmi_phy_8x60_powerdown, - .reg_names =3D hdmi_phy_8x60_reg_names, - .num_regs =3D ARRAY_SIZE(hdmi_phy_8x60_reg_names), - .clk_names =3D hdmi_phy_8x60_clk_names, - .num_clks =3D ARRAY_SIZE(hdmi_phy_8x60_clk_names), -}; diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_phy_8x74.c b/drivers/gpu/drm/msm= /hdmi/hdmi_phy_8x74.c deleted file mode 100644 index 6f40820d9071..000000000000 --- a/drivers/gpu/drm/msm/hdmi/hdmi_phy_8x74.c +++ /dev/null @@ -1,44 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) 2013 Red Hat - * Author: Rob Clark - */ - -#include "hdmi.h" - -static void hdmi_phy_8x74_powerup(struct hdmi_phy *phy, - unsigned long pixclock) -{ - hdmi_phy_write(phy, REG_HDMI_8x74_ANA_CFG0, 0x1b); - hdmi_phy_write(phy, REG_HDMI_8x74_ANA_CFG1, 0xf2); - hdmi_phy_write(phy, REG_HDMI_8x74_BIST_CFG0, 0x0); - hdmi_phy_write(phy, REG_HDMI_8x74_BIST_PATN0, 0x0); - hdmi_phy_write(phy, REG_HDMI_8x74_BIST_PATN1, 0x0); - hdmi_phy_write(phy, REG_HDMI_8x74_BIST_PATN2, 0x0); - hdmi_phy_write(phy, REG_HDMI_8x74_BIST_PATN3, 0x0); - hdmi_phy_write(phy, REG_HDMI_8x74_PD_CTRL1, 0x20); -} - -static void hdmi_phy_8x74_powerdown(struct hdmi_phy *phy) -{ - hdmi_phy_write(phy, REG_HDMI_8x74_PD_CTRL0, 0x7f); -} - -static const char * const hdmi_phy_8x74_reg_names[] =3D { - "core-vdda", - "vddio", -}; - -static const char * const hdmi_phy_8x74_clk_names[] =3D { - "iface", "alt_iface" -}; - -const struct hdmi_phy_cfg msm_hdmi_phy_8x74_cfg =3D { - .type =3D MSM_HDMI_PHY_8x74, - .powerup =3D hdmi_phy_8x74_powerup, - .powerdown =3D hdmi_phy_8x74_powerdown, - .reg_names =3D hdmi_phy_8x74_reg_names, - .num_regs =3D ARRAY_SIZE(hdmi_phy_8x74_reg_names), - .clk_names =3D hdmi_phy_8x74_clk_names, - .num_clks =3D ARRAY_SIZE(hdmi_phy_8x74_clk_names), -}; diff --git a/drivers/gpu/drm/msm/registers/display/hdmi.xml b/drivers/gpu/d= rm/msm/registers/display/hdmi.xml index 0ebb96297dae..1d44aa26c833 100644 --- a/drivers/gpu/drm/msm/registers/display/hdmi.xml +++ b/drivers/gpu/drm/msm/registers/display/hdmi.xml @@ -564,541 +564,4 @@ xsi:schemaLocation=3D"https://gitlab.freedesktop.org/= freedreno/ rules-fd.xsd"> =20 =20 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/drivers/phy/qualcomm/Kconfig b/drivers/phy/qualcomm/Kconfig index 60a0ead127fa..2c0f5547c5de 100644 --- a/drivers/phy/qualcomm/Kconfig +++ b/drivers/phy/qualcomm/Kconfig @@ -42,6 +42,20 @@ config PHY_QCOM_IPQ806X_SATA depends on OF select GENERIC_PHY =20 +config PHY_QCOM_HDMI + tristate "Qualcomm MSM8x60/MSM8960/MSM8974 HDMI PHY driver" + depends on ARCH_QCOM || COMPILE_TEST + depends on OF + depends on COMMON_CLK + default DRM_MSM_HDMI && ARCH_QCOM && ARM + select GENERIC_PHY + help + Enable this to support the Qualcomm HDMI PHY presend on 32-bit platform= s: + MSM8260, MSM8660, MSM8960, MSM8974, APQ8060, APQ8064, APQ8074 and APQ80= 84. + + Note, this driver is not used on MSM899x platforms, which use + PHY_QCOM_QMP_HDMI instead. + config PHY_QCOM_PCIE2 tristate "Qualcomm PCIe Gen2 PHY Driver" depends on OF && COMMON_CLK && (ARCH_QCOM || COMPILE_TEST) @@ -68,6 +82,16 @@ config PHY_QCOM_QMP_COMBO Enable this to support the QMP Combo PHY transceiver that is used with USB3 and DisplayPort controllers on Qualcomm chips. =20 +config PHY_QCOM_QMP_HDMI + tristate "Qualcomm QMP HDMI PHY Driver" + default PHY_QCOM_QMP && DRM_MSM_HDMI + help + Enable this to support the QMP HDMI PHY transceiver that is used + with HDMI output on Qualcomm MSM8996 and MSM8998 chips. + + Note, this driver is not used on Qualcomm 32-bit platforms, which use + PHY_QCOM_HDMI instead. + config PHY_QCOM_QMP_PCIE tristate "Qualcomm QMP PCIe PHY Driver" depends on PCI || COMPILE_TEST diff --git a/drivers/phy/qualcomm/Makefile b/drivers/phy/qualcomm/Makefile index b71a6a0bed3f..60946c14514a 100644 --- a/drivers/phy/qualcomm/Makefile +++ b/drivers/phy/qualcomm/Makefile @@ -4,17 +4,31 @@ obj-$(CONFIG_PHY_QCOM_APQ8064_SATA) +=3D phy-qcom-apq8064= -sata.o obj-$(CONFIG_PHY_QCOM_EDP) +=3D phy-qcom-edp.o obj-$(CONFIG_PHY_QCOM_IPQ4019_USB) +=3D phy-qcom-ipq4019-usb.o obj-$(CONFIG_PHY_QCOM_IPQ806X_SATA) +=3D phy-qcom-ipq806x-sata.o +obj-$(CONFIG_PHY_QCOM_HDMI) +=3D phy-qcom-hdmi.o + +phy-qcom-hdmi-y :=3D \ + phy-qcom-hdmi-preqmp.o \ + phy-qcom-hdmi-28hpm.o \ + phy-qcom-hdmi-28lpm.o \ + phy-qcom-hdmi-45nm.o \ + obj-$(CONFIG_PHY_QCOM_M31_USB) +=3D phy-qcom-m31.o obj-$(CONFIG_PHY_QCOM_M31_EUSB) +=3D phy-qcom-m31-eusb2.o obj-$(CONFIG_PHY_QCOM_PCIE2) +=3D phy-qcom-pcie2.o =20 obj-$(CONFIG_PHY_QCOM_QMP_COMBO) +=3D phy-qcom-qmp-combo.o phy-qcom-qmp-us= bc.o +obj-$(CONFIG_PHY_QCOM_QMP_HDMI) +=3D phy-qcom-qmp-hdmi.o obj-$(CONFIG_PHY_QCOM_QMP_PCIE) +=3D phy-qcom-qmp-pcie.o obj-$(CONFIG_PHY_QCOM_QMP_PCIE_8996) +=3D phy-qcom-qmp-pcie-msm8996.o obj-$(CONFIG_PHY_QCOM_QMP_UFS) +=3D phy-qcom-qmp-ufs.o obj-$(CONFIG_PHY_QCOM_QMP_USB) +=3D phy-qcom-qmp-usb.o obj-$(CONFIG_PHY_QCOM_QMP_USB_LEGACY) +=3D phy-qcom-qmp-usb-legacy.o =20 +phy-qcom-qmp-hdmi-y :=3D \ + phy-qcom-qmp-hdmi-base.o \ + phy-qcom-qmp-hdmi-msm8996.o \ + phy-qcom-qmp-hdmi-msm8998.o \ + obj-$(CONFIG_PHY_QCOM_QUSB2) +=3D phy-qcom-qusb2.o obj-$(CONFIG_PHY_QCOM_EUSB2_REPEATER) +=3D phy-qcom-eusb2-repeater.o obj-$(CONFIG_PHY_QCOM_UNIPHY_PCIE_28LP) +=3D phy-qcom-uniphy-pcie-28lp.o diff --git a/drivers/phy/qualcomm/phy-qcom-hdmi-28hpm.c b/drivers/phy/qualc= omm/phy-qcom-hdmi-28hpm.c new file mode 100644 index 000000000000..720757f8f393 --- /dev/null +++ b/drivers/phy/qualcomm/phy-qcom-hdmi-28hpm.c @@ -0,0 +1,71 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2013 Red Hat + * Copyright (c) 2023, Linaro Ltd. + * Copyright (c) 2025, Qualcomm Incorporated + * Author: Rob Clark + */ + +#include +#include + +#include "phy-qcom-hdmi-preqmp.h" + +#define REG_HDMI_8x74_ANA_CFG0 0x00000000 +#define REG_HDMI_8x74_ANA_CFG1 0x00000004 +#define REG_HDMI_8x74_ANA_CFG2 0x00000008 +#define REG_HDMI_8x74_ANA_CFG3 0x0000000c +#define REG_HDMI_8x74_PD_CTRL0 0x00000010 +#define REG_HDMI_8x74_PD_CTRL1 0x00000014 +#define REG_HDMI_8x74_GLB_CFG 0x00000018 +#define REG_HDMI_8x74_DCC_CFG0 0x0000001c +#define REG_HDMI_8x74_DCC_CFG1 0x00000020 +#define REG_HDMI_8x74_TXCAL_CFG0 0x00000024 +#define REG_HDMI_8x74_TXCAL_CFG1 0x00000028 +#define REG_HDMI_8x74_TXCAL_CFG2 0x0000002c +#define REG_HDMI_8x74_TXCAL_CFG3 0x00000030 +#define REG_HDMI_8x74_BIST_CFG0 0x00000034 +#define REG_HDMI_8x74_BIST_PATN0 0x0000003c +#define REG_HDMI_8x74_BIST_PATN1 0x00000040 +#define REG_HDMI_8x74_BIST_PATN2 0x00000044 +#define REG_HDMI_8x74_BIST_PATN3 0x00000048 +#define REG_HDMI_8x74_STATUS 0x0000005c + +static int qcom_hdmi_msm8974_phy_power_on(struct qcom_hdmi_preqmp_phy *hdm= i_phy) +{ + writel(0x1b, hdmi_phy->phy_reg + REG_HDMI_8x74_ANA_CFG0); + writel(0xf2, hdmi_phy->phy_reg + REG_HDMI_8x74_ANA_CFG1); + writel(0x00, hdmi_phy->phy_reg + REG_HDMI_8x74_BIST_CFG0); + writel(0x00, hdmi_phy->phy_reg + REG_HDMI_8x74_BIST_PATN0); + writel(0x00, hdmi_phy->phy_reg + REG_HDMI_8x74_BIST_PATN1); + writel(0x00, hdmi_phy->phy_reg + REG_HDMI_8x74_BIST_PATN2); + writel(0x00, hdmi_phy->phy_reg + REG_HDMI_8x74_BIST_PATN3); + writel(0x20, hdmi_phy->phy_reg + REG_HDMI_8x74_PD_CTRL1); + + return 0; +} + +static int qcom_hdmi_msm8974_phy_power_off(struct qcom_hdmi_preqmp_phy *hd= mi_phy) +{ + writel(0x7f, hdmi_phy->phy_reg + REG_HDMI_8x74_PD_CTRL0); + + return 0; +} + +const struct clk_parent_data msm8974_hdmi_pll_parent =3D { + .fw_name =3D "xo", .name =3D "xo_board", +}; + +const struct qcom_hdmi_preqmp_cfg msm8974_hdmi_phy_cfg =3D { + .clk_names =3D { "iface", "alt_iface" }, + .num_clks =3D 2, + + .reg_names =3D { "vddio", "core-vdda" }, + .reg_init_load =3D { 100000, 10000 }, + .num_regs =3D 2, + + .power_on =3D qcom_hdmi_msm8974_phy_power_on, + .power_off =3D qcom_hdmi_msm8974_phy_power_off, + + .pll_parent =3D &msm8974_hdmi_pll_parent, +}; diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_pll_8960.c b/drivers/phy/qualcom= m/phy-qcom-hdmi-28lpm.c similarity index 52% rename from drivers/gpu/drm/msm/hdmi/hdmi_pll_8960.c rename to drivers/phy/qualcomm/phy-qcom-hdmi-28lpm.c index 6ba6bbdb7e05..f1e7113e10bd 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi_pll_8960.c +++ b/drivers/phy/qualcomm/phy-qcom-hdmi-28lpm.c @@ -1,31 +1,152 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2016, The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat + * Copyright (c) 2023, Linaro Ltd. + * Copyright (c) 2025, Qualcomm Incorporated * Author: Rob Clark */ =20 -#include #include +#include +#include =20 -#include "hdmi.h" +#include "phy-qcom-hdmi-preqmp.h" =20 -struct hdmi_pll_8960 { - struct platform_device *pdev; - struct clk_hw clk_hw; - void __iomem *mmio; +#define REG_HDMI_8960_PHY_REG0 0x00000000 =20 - unsigned long pixclk; -}; +#define REG_HDMI_8960_PHY_REG1 0x00000004 =20 -#define hw_clk_to_pll(x) container_of(x, struct hdmi_pll_8960, clk_hw) +#define REG_HDMI_8960_PHY_REG2 0x00000008 =20 -/* - * HDMI PLL: - * - * To get the parent clock setup properly, we need to plug in hdmi pll - * configuration into common-clock-framework. - */ +#define REG_HDMI_8960_PHY_REG3 0x0000000c + +#define REG_HDMI_8960_PHY_REG4 0x00000010 + +#define REG_HDMI_8960_PHY_REG5 0x00000014 + +#define REG_HDMI_8960_PHY_REG6 0x00000018 + +#define REG_HDMI_8960_PHY_REG7 0x0000001c + +#define REG_HDMI_8960_PHY_REG8 0x00000020 + +#define REG_HDMI_8960_PHY_REG9 0x00000024 + +#define REG_HDMI_8960_PHY_REG10 0x00000028 + +#define REG_HDMI_8960_PHY_REG11 0x0000002c + +#define REG_HDMI_8960_PHY_REG12 0x00000030 +#define HDMI_8960_PHY_REG12_SW_RESET BIT(5) +#define HDMI_8960_PHY_REG12_PWRDN_B BIT(7) + +#define REG_HDMI_8960_PHY_REG_BIST_CFG 0x00000034 + +#define REG_HDMI_8960_PHY_DEBUG_BUS_SEL 0x00000038 + +#define REG_HDMI_8960_PHY_REG_MISC0 0x0000003c + +#define REG_HDMI_8960_PHY_REG13 0x00000040 + +#define REG_HDMI_8960_PHY_REG14 0x00000044 + +#define REG_HDMI_8960_PHY_REG15 0x00000048 + +#define REG_HDMI_8960_PHY_PLL_REFCLK_CFG 0x00000000 +#define HDMI_8960_PHY_PLL_VCO_DIV GENMASK(5, 4) +#define HDMI_8960_PHY_DBLR_EN BIT(3) +#define HDMI_8960_PHY_CLK0_DIV GENMASK(2, 1) + +#define REG_HDMI_8960_PHY_PLL_CHRG_PUMP_CFG 0x00000004 + +#define REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 0x00000008 + +#define REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1 0x0000000c + +#define REG_HDMI_8960_PHY_PLL_IDAC_ADJ_CFG 0x00000010 + +#define REG_HDMI_8960_PHY_PLL_I_VI_KVCO_CFG 0x00000014 + +#define REG_HDMI_8960_PHY_PLL_PWRDN_B 0x00000018 +#define HDMI_8960_PHY_PLL_PWRDN_B_PD_PLL 0x00000002 +#define HDMI_8960_PHY_PLL_PWRDN_B_PLL_PWRDN_B 0x00000008 + +#define REG_HDMI_8960_PHY_PLL_SDM_CFG0 0x0000001c +#define HDMI_8960_PHY_SDM_BYP BIT(6) +#define HDMI_8960_PHY_BYP_DIV GENMASK(5, 0) + +#define REG_HDMI_8960_PHY_PLL_SDM_CFG1 0x00000020 +#define HDMI_8960_PHY_DITHER BIT(6) +#define HDMI_8960_PHY_DC_OFFSET GENMASK(5, 0) + +#define REG_HDMI_8960_PHY_PLL_SDM_CFG2 0x00000024 + +#define REG_HDMI_8960_PHY_PLL_SDM_CFG3 0x00000028 + +#define REG_HDMI_8960_PHY_PLL_SDM_CFG4 0x0000002c + +#define REG_HDMI_8960_PHY_PLL_SSC_CFG0 0x00000030 + +#define REG_HDMI_8960_PHY_PLL_SSC_CFG1 0x00000034 + +#define REG_HDMI_8960_PHY_PLL_SSC_CFG2 0x00000038 + +#define REG_HDMI_8960_PHY_PLL_SSC_CFG3 0x0000003c + +#define REG_HDMI_8960_PHY_PLL_LOCKDET_CFG0 0x00000040 + +#define REG_HDMI_8960_PHY_PLL_LOCKDET_CFG1 0x00000044 + +#define REG_HDMI_8960_PHY_PLL_LOCKDET_CFG2 0x00000048 + +#define REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0 0x0000004c + +#define REG_HDMI_8960_PHY_PLL_VCOCAL_CFG1 0x00000050 + +#define REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2 0x00000054 + +#define REG_HDMI_8960_PHY_PLL_VCOCAL_CFG3 0x00000058 + +#define REG_HDMI_8960_PHY_PLL_VCOCAL_CFG4 0x0000005c + +#define REG_HDMI_8960_PHY_PLL_VCOCAL_CFG5 0x00000060 + +#define REG_HDMI_8960_PHY_PLL_VCOCAL_CFG6 0x00000064 + +#define REG_HDMI_8960_PHY_PLL_VCOCAL_CFG7 0x00000068 + +#define REG_HDMI_8960_PHY_PLL_DEBUG_SEL 0x0000006c + +#define REG_HDMI_8960_PHY_PLL_MISC0 0x00000070 + +#define REG_HDMI_8960_PHY_PLL_MISC1 0x00000074 + +#define REG_HDMI_8960_PHY_PLL_MISC2 0x00000078 + +#define REG_HDMI_8960_PHY_PLL_MISC3 0x0000007c + +#define REG_HDMI_8960_PHY_PLL_MISC4 0x00000080 + +#define REG_HDMI_8960_PHY_PLL_MISC5 0x00000084 + +#define REG_HDMI_8960_PHY_PLL_MISC6 0x00000088 + +#define REG_HDMI_8960_PHY_PLL_DEBUG_BUS0 0x0000008c + +#define REG_HDMI_8960_PHY_PLL_DEBUG_BUS1 0x00000090 + +#define REG_HDMI_8960_PHY_PLL_DEBUG_BUS2 0x00000094 + +#define REG_HDMI_8960_PHY_PLL_STATUS0 0x00000098 +#define HDMI_8960_PHY_PLL_STATUS0_PLL_LOCK 0x00000001 + +#define REG_HDMI_8960_PHY_PLL_STATUS1 0x0000009c + +/* FIXME: verify boundaries */ +#define HDMI_8960_VCO_MAX_FREQ 1125000000UL +#define HDMI_8960_VCO_MIN_FREQ 540000000UL + +#define HDMI_8960_COMMON_DIV 5 =20 struct pll_rate { unsigned long rate; @@ -234,34 +355,96 @@ static const struct pll_rate freqtbl[] =3D { }, }; =20 -static inline void pll_write(struct hdmi_pll_8960 *pll, u32 reg, u32 data) +static const struct pll_rate *qcom_hdmi_8960_pll_find_rate(unsigned long r= ate) +{ + int i; + + for (i =3D 1; i < ARRAY_SIZE(freqtbl); i++) + if (rate > freqtbl[i].rate) + return &freqtbl[i - 1]; + + return &freqtbl[i - 1]; +} + +static inline u32 read24(void __iomem *reg) { - writel(data, pll->mmio + reg); + u32 val =3D readl(reg); + + val |=3D readl(reg + 4) << 8; + val |=3D readl(reg + 8) << 16; + + return val; } =20 -static inline u32 pll_read(struct hdmi_pll_8960 *pll, u32 reg) +/* This function is close to UNIPHY, but it has slighly different fields */ +static unsigned long qcom_28lpm_recalc(struct qcom_hdmi_preqmp_phy *hdmi_p= hy, + unsigned long parent_rate) { - return readl(pll->mmio + reg); + unsigned long rate; + u32 refclk_cfg; + u32 dc_offset; + u64 fraq_n; + u32 val; + + refclk_cfg =3D readl(hdmi_phy->pll_reg + REG_HDMI_8960_PHY_PLL_REFCLK_CFG= ); + parent_rate /=3D FIELD_GET(HDMI_8960_PHY_CLK0_DIV, refclk_cfg) + 1; + if (refclk_cfg & HDMI_8960_PHY_DBLR_EN) + parent_rate *=3D 2; + + val =3D readl(hdmi_phy->pll_reg + REG_HDMI_8960_PHY_PLL_SDM_CFG0); + if (val & HDMI_8960_PHY_SDM_BYP) { + dc_offset =3D FIELD_GET(HDMI_8960_PHY_BYP_DIV, val); + fraq_n =3D 0; + } else { + val =3D readl(hdmi_phy->pll_reg + REG_HDMI_8960_PHY_PLL_SDM_CFG1); + dc_offset =3D FIELD_GET(HDMI_8960_PHY_DC_OFFSET, val); + fraq_n =3D read24(hdmi_phy->pll_reg + REG_HDMI_8960_PHY_PLL_SDM_CFG2); + } + + rate =3D (dc_offset + 1) * parent_rate; + rate +=3D div_u64(fraq_n * parent_rate, 0x10000); + + return rate; } =20 -static inline struct hdmi_phy *pll_get_phy(struct hdmi_pll_8960 *pll) +static const unsigned int qcom_hdmi_8960_divs[] =3D {1, 2, 4, 6}; + +static unsigned long qcom_hdmi_8960_pll_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) { - return platform_get_drvdata(pll->pdev); + struct qcom_hdmi_preqmp_phy *hdmi_phy =3D hw_clk_to_phy(hw); + u32 refclk_cfg =3D readl(hdmi_phy->pll_reg + REG_HDMI_8960_PHY_PLL_REFCLK= _CFG); + u32 div_idx =3D FIELD_GET(HDMI_8960_PHY_PLL_VCO_DIV, refclk_cfg); + unsigned long rate =3D qcom_28lpm_recalc(hdmi_phy, parent_rate); + + return rate / HDMI_8960_COMMON_DIV / qcom_hdmi_8960_divs[div_idx]; } =20 -static int hdmi_pll_enable(struct clk_hw *hw) +static int qcom_hdmi_8960_pll_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { - struct hdmi_pll_8960 *pll =3D hw_clk_to_pll(hw); - struct hdmi_phy *phy =3D pll_get_phy(pll); - int timeout_count, pll_lock_retry =3D 10; - unsigned int val; + const struct pll_rate *pll_rate =3D qcom_hdmi_8960_pll_find_rate(req->rat= e); =20 - DBG(""); + req->rate =3D pll_rate->rate; + + return 0; +} + +static const struct clk_ops qcom_hdmi_8960_pll_ops =3D { + .recalc_rate =3D qcom_hdmi_8960_pll_recalc_rate, + .determine_rate =3D qcom_hdmi_8960_pll_determine_rate, +}; + +static int qcom_hdmi_msm8960_phy_pll_enable(struct qcom_hdmi_preqmp_phy *h= dmi_phy) +{ + int pll_lock_retry =3D 10; + unsigned int val; + int ret; =20 /* Assert PLL S/W reset */ - pll_write(pll, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG2, 0x8d); - pll_write(pll, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG0, 0x10); - pll_write(pll, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG1, 0x1a); + writel(0x8d, hdmi_phy->pll_reg + REG_HDMI_8960_PHY_PLL_LOCKDET_CFG2); + writel(0x10, hdmi_phy->pll_reg + REG_HDMI_8960_PHY_PLL_LOCKDET_CFG0); + writel(0x1a, hdmi_phy->pll_reg + REG_HDMI_8960_PHY_PLL_LOCKDET_CFG1); =20 /* Wait for a short time before de-asserting * to allow the hardware to complete its job. @@ -271,12 +454,12 @@ static int hdmi_pll_enable(struct clk_hw *hw) udelay(10); =20 /* De-assert PLL S/W reset */ - pll_write(pll, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG2, 0x0d); + writel(0x0d, hdmi_phy->pll_reg + REG_HDMI_8960_PHY_PLL_LOCKDET_CFG2); =20 - val =3D hdmi_phy_read(phy, REG_HDMI_8960_PHY_REG12); + val =3D readl(hdmi_phy->phy_reg + REG_HDMI_8960_PHY_REG12); val |=3D HDMI_8960_PHY_REG12_SW_RESET; /* Assert PHY S/W reset */ - hdmi_phy_write(phy, REG_HDMI_8960_PHY_REG12, val); + writel(val, hdmi_phy->phy_reg + REG_HDMI_8960_PHY_REG12); val &=3D ~HDMI_8960_PHY_REG12_SW_RESET; /* * Wait for a short time before de-asserting to allow the hardware to @@ -285,176 +468,127 @@ static int hdmi_pll_enable(struct clk_hw *hw) */ udelay(10); /* De-assert PHY S/W reset */ - hdmi_phy_write(phy, REG_HDMI_8960_PHY_REG12, val); - hdmi_phy_write(phy, REG_HDMI_8960_PHY_REG2, 0x3f); + writel(val, hdmi_phy->phy_reg + REG_HDMI_8960_PHY_REG12); + writel(0x3f, hdmi_phy->phy_reg + REG_HDMI_8960_PHY_REG2); =20 - val =3D hdmi_phy_read(phy, REG_HDMI_8960_PHY_REG12); + val =3D readl(hdmi_phy->phy_reg + REG_HDMI_8960_PHY_REG12); val |=3D HDMI_8960_PHY_REG12_PWRDN_B; - hdmi_phy_write(phy, REG_HDMI_8960_PHY_REG12, val); + writel(val, hdmi_phy->phy_reg + REG_HDMI_8960_PHY_REG12); /* Wait 10 us for enabling global power for PHY */ mb(); udelay(10); =20 - val =3D pll_read(pll, REG_HDMI_8960_PHY_PLL_PWRDN_B); + val =3D readl(hdmi_phy->pll_reg + REG_HDMI_8960_PHY_PLL_PWRDN_B); val |=3D HDMI_8960_PHY_PLL_PWRDN_B_PLL_PWRDN_B; val &=3D ~HDMI_8960_PHY_PLL_PWRDN_B_PD_PLL; - pll_write(pll, REG_HDMI_8960_PHY_PLL_PWRDN_B, val); - hdmi_phy_write(phy, REG_HDMI_8960_PHY_REG2, 0x80); + writel(val, hdmi_phy->pll_reg + REG_HDMI_8960_PHY_PLL_PWRDN_B); + writel(0x80, hdmi_phy->phy_reg + REG_HDMI_8960_PHY_REG2); =20 - timeout_count =3D 1000; while (--pll_lock_retry > 0) { - /* are we there yet? */ - val =3D pll_read(pll, REG_HDMI_8960_PHY_PLL_STATUS0); - if (val & HDMI_8960_PHY_PLL_STATUS0_PLL_LOCK) + ret =3D readl_poll_timeout(hdmi_phy->pll_reg + REG_HDMI_8960_PHY_PLL_STA= TUS0, + val, val & HDMI_8960_PHY_PLL_STATUS0_PLL_LOCK, + 1, 1000); + if (!ret) break; =20 - udelay(1); - - if (--timeout_count > 0) - continue; - /* * PLL has still not locked. * Do a software reset and try again * Assert PLL S/W reset first */ - pll_write(pll, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG2, 0x8d); + writel(0x8d, hdmi_phy->pll_reg + REG_HDMI_8960_PHY_PLL_LOCKDET_CFG2); udelay(10); - pll_write(pll, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG2, 0x0d); + writel(0x0d, hdmi_phy->pll_reg + REG_HDMI_8960_PHY_PLL_LOCKDET_CFG2); =20 /* * Wait for a short duration for the PLL calibration * before checking if the PLL gets locked */ udelay(350); - - timeout_count =3D 1000; } =20 + return ret; +} + +static int qcom_hdmi_msm8960_phy_set_rate(struct qcom_hdmi_preqmp_phy *hdm= i_phy) +{ + unsigned long long pixclk =3D hdmi_phy->hdmi_opts.tmds_char_rate; + const struct pll_rate *pll_rate =3D qcom_hdmi_8960_pll_find_rate(pixclk); + int i; + + for (i =3D 0; i < pll_rate->num_reg; i++) + writel(pll_rate->conf[i].val, hdmi_phy->pll_reg + pll_rate->conf[i].reg); + return 0; } =20 -static void hdmi_pll_disable(struct clk_hw *hw) +static void qcom_hdmi_msm8960_phy_pll_disable(struct qcom_hdmi_preqmp_phy = *hdmi_phy) { - struct hdmi_pll_8960 *pll =3D hw_clk_to_pll(hw); - struct hdmi_phy *phy =3D pll_get_phy(pll); unsigned int val; =20 - DBG(""); - - val =3D hdmi_phy_read(phy, REG_HDMI_8960_PHY_REG12); + val =3D readl(hdmi_phy->phy_reg + REG_HDMI_8960_PHY_REG12); val &=3D ~HDMI_8960_PHY_REG12_PWRDN_B; - hdmi_phy_write(phy, REG_HDMI_8960_PHY_REG12, val); + writel(val, hdmi_phy->phy_reg + REG_HDMI_8960_PHY_REG12); =20 - val =3D pll_read(pll, REG_HDMI_8960_PHY_PLL_PWRDN_B); + val =3D readl(hdmi_phy->pll_reg + REG_HDMI_8960_PHY_PLL_PWRDN_B); val |=3D HDMI_8960_PHY_REG12_SW_RESET; val &=3D ~HDMI_8960_PHY_REG12_PWRDN_B; - pll_write(pll, REG_HDMI_8960_PHY_PLL_PWRDN_B, val); + writel(val, hdmi_phy->pll_reg + REG_HDMI_8960_PHY_PLL_PWRDN_B); /* Make sure HDMI PHY/PLL are powered down */ mb(); } =20 -static const struct pll_rate *find_rate(unsigned long rate) +static int qcom_hdmi_msm8960_phy_power_on(struct qcom_hdmi_preqmp_phy *hdm= i_phy) { - int i; - - for (i =3D 1; i < ARRAY_SIZE(freqtbl); i++) - if (rate > freqtbl[i].rate) - return &freqtbl[i - 1]; + int ret; =20 - return &freqtbl[i - 1]; -} - -static unsigned long hdmi_pll_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) -{ - struct hdmi_pll_8960 *pll =3D hw_clk_to_pll(hw); - - return pll->pixclk; -} + ret =3D qcom_hdmi_msm8960_phy_set_rate(hdmi_phy); + if (ret) + return ret; =20 -static int hdmi_pll_determine_rate(struct clk_hw *hw, - struct clk_rate_request *req) -{ - const struct pll_rate *pll_rate =3D find_rate(req->rate); + ret =3D qcom_hdmi_msm8960_phy_pll_enable(hdmi_phy); + if (ret) + return ret; =20 - req->rate =3D pll_rate->rate; + writel(0x00, hdmi_phy->phy_reg + REG_HDMI_8960_PHY_REG2); + writel(0x1b, hdmi_phy->phy_reg + REG_HDMI_8960_PHY_REG0); + writel(0xf2, hdmi_phy->phy_reg + REG_HDMI_8960_PHY_REG1); + writel(0x00, hdmi_phy->phy_reg + REG_HDMI_8960_PHY_REG4); + writel(0x00, hdmi_phy->phy_reg + REG_HDMI_8960_PHY_REG5); + writel(0x00, hdmi_phy->phy_reg + REG_HDMI_8960_PHY_REG6); + writel(0x00, hdmi_phy->phy_reg + REG_HDMI_8960_PHY_REG7); + writel(0x00, hdmi_phy->phy_reg + REG_HDMI_8960_PHY_REG8); + writel(0x00, hdmi_phy->phy_reg + REG_HDMI_8960_PHY_REG9); + writel(0x00, hdmi_phy->phy_reg + REG_HDMI_8960_PHY_REG10); + writel(0x00, hdmi_phy->phy_reg + REG_HDMI_8960_PHY_REG11); + writel(0x20, hdmi_phy->phy_reg + REG_HDMI_8960_PHY_REG3); =20 return 0; } =20 -static int hdmi_pll_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate) +static int qcom_hdmi_msm8960_phy_power_off(struct qcom_hdmi_preqmp_phy *hd= mi_phy) { - struct hdmi_pll_8960 *pll =3D hw_clk_to_pll(hw); - const struct pll_rate *pll_rate =3D find_rate(rate); - int i; + writel(0x7f, hdmi_phy->phy_reg + REG_HDMI_8960_PHY_REG2); =20 - DBG("rate=3D%lu", rate); - - for (i =3D 0; i < pll_rate->num_reg; i++) - pll_write(pll, pll_rate->conf[i].reg, pll_rate->conf[i].val); - - pll->pixclk =3D rate; + qcom_hdmi_msm8960_phy_pll_disable(hdmi_phy); =20 return 0; } =20 -static const struct clk_ops hdmi_pll_ops =3D { - .enable =3D hdmi_pll_enable, - .disable =3D hdmi_pll_disable, - .recalc_rate =3D hdmi_pll_recalc_rate, - .determine_rate =3D hdmi_pll_determine_rate, - .set_rate =3D hdmi_pll_set_rate, -}; - -static const struct clk_parent_data hdmi_pll_parents[] =3D { - { .fw_name =3D "pxo", .name =3D "pxo_board" }, +const struct clk_parent_data msm8960_hdmi_pll_parent =3D { + .fw_name =3D "pxo", .name =3D "pxo_board", }; =20 -static struct clk_init_data pll_init =3D { - .name =3D "hdmi_pll", - .ops =3D &hdmi_pll_ops, - .parent_data =3D hdmi_pll_parents, - .num_parents =3D ARRAY_SIZE(hdmi_pll_parents), - .flags =3D CLK_IGNORE_UNUSED, -}; - -int msm_hdmi_pll_8960_init(struct platform_device *pdev) -{ - struct device *dev =3D &pdev->dev; - struct hdmi_pll_8960 *pll; - int i, ret; - - /* sanity check: */ - for (i =3D 0; i < (ARRAY_SIZE(freqtbl) - 1); i++) - if (WARN_ON(freqtbl[i].rate < freqtbl[i + 1].rate)) - return -EINVAL; - - pll =3D devm_kzalloc(dev, sizeof(*pll), GFP_KERNEL); - if (!pll) - return -ENOMEM; - - pll->mmio =3D msm_ioremap(pdev, "hdmi_pll"); - if (IS_ERR(pll->mmio)) { - DRM_DEV_ERROR(dev, "failed to map pll base\n"); - return -ENOMEM; - } - - pll->pdev =3D pdev; - pll->clk_hw.init =3D &pll_init; +const struct qcom_hdmi_preqmp_cfg msm8960_hdmi_phy_cfg =3D { + .clk_names =3D { "slave_iface" }, + .num_clks =3D 1, =20 - ret =3D devm_clk_hw_register(dev, &pll->clk_hw); - if (ret < 0) { - DRM_DEV_ERROR(dev, "failed to register pll clock\n"); - return ret; - } + .reg_names =3D { "core-vdda" }, + .num_regs =3D 1, =20 - ret =3D devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, &pll->clk_= hw); - if (ret) { - DRM_DEV_ERROR(dev, "%s: failed to register clk provider: %d\n", __func__= , ret); - return ret; - } + .power_on =3D qcom_hdmi_msm8960_phy_power_on, + .power_off =3D qcom_hdmi_msm8960_phy_power_off, =20 - return 0; -} + .pll_ops =3D &qcom_hdmi_8960_pll_ops, + .pll_parent =3D &msm8960_hdmi_pll_parent, +}; diff --git a/drivers/phy/qualcomm/phy-qcom-hdmi-45nm.c b/drivers/phy/qualco= mm/phy-qcom-hdmi-45nm.c new file mode 100644 index 000000000000..bb7834d1d421 --- /dev/null +++ b/drivers/phy/qualcomm/phy-qcom-hdmi-45nm.c @@ -0,0 +1,186 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2013 Red Hat + * Copyright (c) 2023, Linaro Ltd. + * Copyright (c) 2025, Qualcomm Incorporated + * Author: Rob Clark + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "phy-qcom-hdmi-preqmp.h" + +#define REG_HDMI_8x60_PHY_REG0 0x00000000 +#define HDMI_8x60_PHY_REG0_DESER_DEL_CTRL__MASK 0x0000001c + +#define REG_HDMI_8x60_PHY_REG1 0x00000004 +#define HDMI_8x60_PHY_REG1_DTEST_MUX_SEL__MASK 0x000000f0 +#define HDMI_8x60_PHY_REG1_OUTVOL_SWING_CTRL__MASK 0x0000000f + +#define REG_HDMI_8x60_PHY_REG2 0x00000008 +#define HDMI_8x60_PHY_REG2_PD_DESER 0x00000001 +#define HDMI_8x60_PHY_REG2_PD_DRIVE_1 0x00000002 +#define HDMI_8x60_PHY_REG2_PD_DRIVE_2 0x00000004 +#define HDMI_8x60_PHY_REG2_PD_DRIVE_3 0x00000008 +#define HDMI_8x60_PHY_REG2_PD_DRIVE_4 0x00000010 +#define HDMI_8x60_PHY_REG2_PD_PLL 0x00000020 +#define HDMI_8x60_PHY_REG2_PD_PWRGEN 0x00000040 +#define HDMI_8x60_PHY_REG2_RCV_SENSE_EN 0x00000080 + +#define REG_HDMI_8x60_PHY_REG3 0x0000000c +#define HDMI_8x60_PHY_REG3_PLL_ENABLE 0x00000001 + +#define REG_HDMI_8x60_PHY_REG4 0x00000010 + +#define REG_HDMI_8x60_PHY_REG5 0x00000014 + +#define REG_HDMI_8x60_PHY_REG6 0x00000018 + +#define REG_HDMI_8x60_PHY_REG7 0x0000001c + +#define REG_HDMI_8x60_PHY_REG8 0x00000020 + +#define REG_HDMI_8x60_PHY_REG9 0x00000024 + +#define REG_HDMI_8x60_PHY_REG10 0x00000028 + +#define REG_HDMI_8x60_PHY_REG11 0x0000002c + +#define REG_HDMI_8x60_PHY_REG12 0x00000030 +#define HDMI_8x60_PHY_REG12_RETIMING_EN 0x00000001 +#define HDMI_8x60_PHY_REG12_PLL_LOCK_DETECT_EN 0x00000002 +#define HDMI_8x60_PHY_REG12_FORCE_LOCK 0x00000010 + +static int qcom_hdmi_msm8x60_phy_power_on(struct qcom_hdmi_preqmp_phy *hdm= i_phy) +{ + unsigned long pixclock =3D hdmi_phy->hdmi_opts.tmds_char_rate; + + /* De-serializer delay D/C for non-lbk mode: */ + writel(FIELD_PREP(HDMI_8x60_PHY_REG0_DESER_DEL_CTRL__MASK, 3), + hdmi_phy->phy_reg + REG_HDMI_8x60_PHY_REG0); + + if (pixclock =3D=3D 27 * HZ_PER_MHZ) { + /* video_format =3D=3D HDMI_VFRMT_720x480p60_16_9 */ + writel(FIELD_PREP(HDMI_8x60_PHY_REG1_DTEST_MUX_SEL__MASK, 5) | + FIELD_PREP(HDMI_8x60_PHY_REG1_OUTVOL_SWING_CTRL__MASK, 3), + hdmi_phy->phy_reg + REG_HDMI_8x60_PHY_REG1); + } else { + writel(FIELD_PREP(HDMI_8x60_PHY_REG1_DTEST_MUX_SEL__MASK, 5) | + FIELD_PREP(HDMI_8x60_PHY_REG1_OUTVOL_SWING_CTRL__MASK, 4), + hdmi_phy->phy_reg + REG_HDMI_8x60_PHY_REG1); + } + + /* No matter what, start from the power down mode: */ + writel(HDMI_8x60_PHY_REG2_PD_PWRGEN | + HDMI_8x60_PHY_REG2_PD_PLL | + HDMI_8x60_PHY_REG2_PD_DRIVE_4 | + HDMI_8x60_PHY_REG2_PD_DRIVE_3 | + HDMI_8x60_PHY_REG2_PD_DRIVE_2 | + HDMI_8x60_PHY_REG2_PD_DRIVE_1 | + HDMI_8x60_PHY_REG2_PD_DESER, + hdmi_phy->phy_reg + REG_HDMI_8x60_PHY_REG2); + + /* Turn PowerGen on: */ + writel(HDMI_8x60_PHY_REG2_PD_PLL | + HDMI_8x60_PHY_REG2_PD_DRIVE_4 | + HDMI_8x60_PHY_REG2_PD_DRIVE_3 | + HDMI_8x60_PHY_REG2_PD_DRIVE_2 | + HDMI_8x60_PHY_REG2_PD_DRIVE_1 | + HDMI_8x60_PHY_REG2_PD_DESER, + hdmi_phy->phy_reg + REG_HDMI_8x60_PHY_REG2); + + /* Turn PLL power on: */ + writel(HDMI_8x60_PHY_REG2_PD_DRIVE_4 | + HDMI_8x60_PHY_REG2_PD_DRIVE_3 | + HDMI_8x60_PHY_REG2_PD_DRIVE_2 | + HDMI_8x60_PHY_REG2_PD_DRIVE_1 | + HDMI_8x60_PHY_REG2_PD_DESER, + hdmi_phy->phy_reg + REG_HDMI_8x60_PHY_REG2); + + /* Write to HIGH after PLL power down de-assert: */ + writel(HDMI_8x60_PHY_REG3_PLL_ENABLE, + hdmi_phy->phy_reg + REG_HDMI_8x60_PHY_REG3); + + /* ASIC power on; PHY REG9 =3D 0 */ + writel(0, hdmi_phy->phy_reg + REG_HDMI_8x60_PHY_REG9); + + /* Enable PLL lock detect, PLL lock det will go high after lock + * Enable the re-time logic + */ + writel(HDMI_8x60_PHY_REG12_RETIMING_EN | + HDMI_8x60_PHY_REG12_PLL_LOCK_DETECT_EN, + hdmi_phy->phy_reg + REG_HDMI_8x60_PHY_REG12); + + /* Drivers are on: */ + writel(HDMI_8x60_PHY_REG2_PD_DESER, + hdmi_phy->phy_reg + REG_HDMI_8x60_PHY_REG2); + + /* If the RX detector is needed: */ + writel(HDMI_8x60_PHY_REG2_RCV_SENSE_EN | + HDMI_8x60_PHY_REG2_PD_DESER, + hdmi_phy->phy_reg + REG_HDMI_8x60_PHY_REG2); + + writel(0, hdmi_phy->phy_reg + REG_HDMI_8x60_PHY_REG4); + writel(0, hdmi_phy->phy_reg + REG_HDMI_8x60_PHY_REG5); + writel(0, hdmi_phy->phy_reg + REG_HDMI_8x60_PHY_REG6); + writel(0, hdmi_phy->phy_reg + REG_HDMI_8x60_PHY_REG7); + writel(0, hdmi_phy->phy_reg + REG_HDMI_8x60_PHY_REG8); + writel(0, hdmi_phy->phy_reg + REG_HDMI_8x60_PHY_REG9); + writel(0, hdmi_phy->phy_reg + REG_HDMI_8x60_PHY_REG10); + writel(0, hdmi_phy->phy_reg + REG_HDMI_8x60_PHY_REG11); + + /* If we want to use lock enable based on counting: */ + writel(HDMI_8x60_PHY_REG12_RETIMING_EN | + HDMI_8x60_PHY_REG12_PLL_LOCK_DETECT_EN | + HDMI_8x60_PHY_REG12_FORCE_LOCK, + hdmi_phy->phy_reg + REG_HDMI_8x60_PHY_REG12); + + return 0; +} + +static int qcom_hdmi_msm8x60_phy_power_off(struct qcom_hdmi_preqmp_phy *hd= mi_phy) +{ + /* Turn off Driver */ + writel(HDMI_8x60_PHY_REG2_PD_DRIVE_4 | + HDMI_8x60_PHY_REG2_PD_DRIVE_3 | + HDMI_8x60_PHY_REG2_PD_DRIVE_2 | + HDMI_8x60_PHY_REG2_PD_DRIVE_1 | + HDMI_8x60_PHY_REG2_PD_DESER, + hdmi_phy->phy_reg + REG_HDMI_8x60_PHY_REG2); + udelay(10); + /* Disable PLL */ + writel(0, hdmi_phy->phy_reg + REG_HDMI_8x60_PHY_REG3); + /* Power down PHY, but keep RX-sense: */ + writel(HDMI_8x60_PHY_REG2_RCV_SENSE_EN | + HDMI_8x60_PHY_REG2_PD_PWRGEN | + HDMI_8x60_PHY_REG2_PD_PLL | + HDMI_8x60_PHY_REG2_PD_DRIVE_4 | + HDMI_8x60_PHY_REG2_PD_DRIVE_3 | + HDMI_8x60_PHY_REG2_PD_DRIVE_2 | + HDMI_8x60_PHY_REG2_PD_DRIVE_1 | + HDMI_8x60_PHY_REG2_PD_DESER, + hdmi_phy->phy_reg + REG_HDMI_8x60_PHY_REG2); + + return 0; +} + +const struct qcom_hdmi_preqmp_cfg msm8x60_hdmi_phy_cfg =3D { + .clk_names =3D { "slave_iface" }, + .num_clks =3D 1, + + .reg_names =3D { "core-vdda" }, + .num_regs =3D 1, + + .power_on =3D qcom_hdmi_msm8x60_phy_power_on, + .power_off =3D qcom_hdmi_msm8x60_phy_power_off, + + /* FIXME: no PLL support */ +}; diff --git a/drivers/phy/qualcomm/phy-qcom-hdmi-preqmp.c b/drivers/phy/qual= comm/phy-qcom-hdmi-preqmp.c new file mode 100644 index 000000000000..7715e5c9b1e4 --- /dev/null +++ b/drivers/phy/qualcomm/phy-qcom-hdmi-preqmp.c @@ -0,0 +1,211 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2013 Red Hat + * Copyright (c) 2023, Linaro Ltd. + * Copyright (c) 2025, Qualcomm Incorporated + */ + +#include +#include + +#include "phy-qcom-hdmi-preqmp.h" + +static int qcom_hdmi_preqmp_phy_init(struct phy *phy) +{ + struct qcom_hdmi_preqmp_phy *hdmi_phy =3D phy_get_drvdata(phy); + + return pm_runtime_resume_and_get(hdmi_phy->dev); +} + +static int qcom_hdmi_preqmp_phy_exit(struct phy *phy) +{ + struct qcom_hdmi_preqmp_phy *hdmi_phy =3D phy_get_drvdata(phy); + + return pm_runtime_put_sync(hdmi_phy->dev); +} + +static int qcom_hdmi_preqmp_phy_power_on(struct phy *phy) +{ + struct qcom_hdmi_preqmp_phy *hdmi_phy =3D phy_get_drvdata(phy); + + return hdmi_phy->power_on(hdmi_phy); +}; + +static int qcom_hdmi_preqmp_phy_power_off(struct phy *phy) +{ + struct qcom_hdmi_preqmp_phy *hdmi_phy =3D phy_get_drvdata(phy); + + return hdmi_phy->power_off(hdmi_phy); +}; + +static int qcom_hdmi_preqmp_phy_configure(struct phy *phy, union phy_confi= gure_opts *opts) +{ + const struct phy_configure_opts_hdmi *hdmi_opts =3D &opts->hdmi; + struct qcom_hdmi_preqmp_phy *hdmi_phy =3D phy_get_drvdata(phy); + int ret =3D 0; + + memcpy(&hdmi_phy->hdmi_opts, hdmi_opts, sizeof(*hdmi_opts)); + + return ret; +} + +static int __maybe_unused qcom_hdmi_preqmp_runtime_resume(struct device *d= ev) +{ + struct qcom_hdmi_preqmp_phy *hdmi_phy =3D dev_get_drvdata(dev); + int ret; + + ret =3D regulator_bulk_enable(hdmi_phy->num_regs, hdmi_phy->regs); + if (ret) + return ret; + + ret =3D clk_bulk_prepare_enable(hdmi_phy->num_clks, hdmi_phy->clks); + if (ret) + goto out_disable_supplies; + + return 0; + +out_disable_supplies: + regulator_bulk_disable(hdmi_phy->num_regs, hdmi_phy->regs); + + return ret; +} + +static int __maybe_unused qcom_hdmi_preqmp_runtime_suspend(struct device *= dev) +{ + struct qcom_hdmi_preqmp_phy *hdmi_phy =3D dev_get_drvdata(dev); + + clk_bulk_disable_unprepare(hdmi_phy->num_clks, hdmi_phy->clks); + regulator_bulk_disable(hdmi_phy->num_regs, hdmi_phy->regs); + + return 0; +} + +static const struct phy_ops qcom_hdmi_preqmp_phy_ops =3D { + .init =3D qcom_hdmi_preqmp_phy_init, + .configure =3D qcom_hdmi_preqmp_phy_configure, + .power_on =3D qcom_hdmi_preqmp_phy_power_on, + .power_off =3D qcom_hdmi_preqmp_phy_power_off, + .exit =3D qcom_hdmi_preqmp_phy_exit, + .owner =3D THIS_MODULE, +}; + +static int qcom_hdmi_preqmp_probe(struct platform_device *pdev) +{ + struct clk_init_data init; + struct phy_provider *phy_provider; + struct device *dev =3D &pdev->dev; + struct qcom_hdmi_preqmp_phy *hdmi_phy; + const struct qcom_hdmi_preqmp_cfg *cfg; + int i, ret; + + cfg =3D of_device_get_match_data(dev); + if (!cfg) + return -EINVAL; + + hdmi_phy =3D devm_kzalloc(dev, sizeof(*hdmi_phy), GFP_KERNEL); + if (!hdmi_phy) + return -ENOMEM; + + hdmi_phy->dev =3D dev; + + hdmi_phy->phy_reg =3D devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(hdmi_phy->phy_reg)) + return PTR_ERR(hdmi_phy->phy_reg); + + hdmi_phy->pll_reg =3D devm_platform_ioremap_resource(pdev, 1); + if (IS_ERR(hdmi_phy->pll_reg)) + return PTR_ERR(hdmi_phy->pll_reg); + + hdmi_phy->num_clks =3D cfg->num_clks; + for (i =3D 0; i < cfg->num_clks; i++) + hdmi_phy->clks[i].id =3D cfg->clk_names[i]; + ret =3D devm_clk_bulk_get(dev, hdmi_phy->num_clks, hdmi_phy->clks); + if (ret) + return ret; + + hdmi_phy->num_regs =3D cfg->num_regs; + for (i =3D 0; i < cfg->num_regs; i++) { + hdmi_phy->regs[i].supply =3D cfg->reg_names[i]; + hdmi_phy->regs[i].init_load_uA =3D cfg->reg_init_load[i]; + } + ret =3D devm_regulator_bulk_get(dev, hdmi_phy->num_regs, hdmi_phy->regs); + if (ret) + return ret; + + hdmi_phy->power_on =3D cfg->power_on; + hdmi_phy->power_off =3D cfg->power_off; + + platform_set_drvdata(pdev, hdmi_phy); + + ret =3D devm_pm_runtime_enable(&pdev->dev); + if (ret) + return ret; + + ret =3D pm_runtime_resume_and_get(&pdev->dev); + if (ret) + return ret; + + /* FIXME: msm8x60 doesn't yet have PLL ops */ + if (cfg->pll_ops) { + init.name =3D "hdmipll"; + init.ops =3D cfg->pll_ops; + init.flags =3D CLK_GET_RATE_NOCACHE; + init.parent_data =3D cfg->pll_parent; + init.num_parents =3D 1; + + hdmi_phy->pll_hw.init =3D &init; + ret =3D devm_clk_hw_register(hdmi_phy->dev, &hdmi_phy->pll_hw); + if (ret) + goto err; + + ret =3D devm_of_clk_add_hw_provider(hdmi_phy->dev, of_clk_hw_simple_get, + &hdmi_phy->pll_hw); + if (ret) + goto err; + } + + hdmi_phy->phy =3D devm_phy_create(dev, pdev->dev.of_node, &qcom_hdmi_preq= mp_phy_ops); + if (IS_ERR(hdmi_phy->phy)) { + ret =3D PTR_ERR(hdmi_phy->phy); + goto err; + } + + phy_set_drvdata(hdmi_phy->phy, hdmi_phy); + + phy_provider =3D devm_of_phy_provider_register(dev, of_phy_simple_xlate); + pm_runtime_put_sync(&pdev->dev); + return PTR_ERR_OR_ZERO(phy_provider); + +err: + pm_runtime_put_sync(&pdev->dev); + return ret; +} + +static const struct of_device_id qcom_hdmi_preqmp_of_match_table[] =3D { + { .compatible =3D "qcom,hdmi-phy-8084", .data =3D &msm8974_hdmi_phy_cfg, = }, + { .compatible =3D "qcom,hdmi-phy-8660", .data =3D &msm8x60_hdmi_phy_cfg, = }, + { .compatible =3D "qcom,hdmi-phy-8960", .data =3D &msm8960_hdmi_phy_cfg, = }, + { .compatible =3D "qcom,hdmi-phy-8974", .data =3D &msm8974_hdmi_phy_cfg, = }, + { }, +}; +MODULE_DEVICE_TABLE(of, qcom_hdmi_preqmp_of_match_table); + +DEFINE_RUNTIME_DEV_PM_OPS(qcom_hdmi_preqmp_pm_ops, + qcom_hdmi_preqmp_runtime_suspend, + qcom_hdmi_preqmp_runtime_resume, + NULL); + +static struct platform_driver qcom_hdmi_preqmp_driver =3D { + .probe =3D qcom_hdmi_preqmp_probe, + .driver =3D { + .name =3D "qcom-preqmp-hdmi-phy", + .of_match_table =3D qcom_hdmi_preqmp_of_match_table, + .pm =3D &qcom_hdmi_preqmp_pm_ops, + }, +}; + +module_platform_driver(qcom_hdmi_preqmp_driver); + +MODULE_AUTHOR("Dmitry Baryshkov "); +MODULE_DESCRIPTION("Qualcomm MSMpreqmp HDMI PHY driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/phy/qualcomm/phy-qcom-hdmi-preqmp.h b/drivers/phy/qual= comm/phy-qcom-hdmi-preqmp.h new file mode 100644 index 000000000000..dda230616d76 --- /dev/null +++ b/drivers/phy/qualcomm/phy-qcom-hdmi-preqmp.h @@ -0,0 +1,59 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2013 Red Hat + * Copyright (c) 2023, Linaro Ltd. + * Copyright (c) 2025, Qualcomm Incorporated + */ + +#ifndef PHY_QCOM_HDMI_PREQMP_H +#define PHY_QCOM_HDMI_PREQMP_H + +#include +#include +#include +#include + +#define MAX_CLKS 2 +#define MAX_SUPPLIES 2 + +struct qcom_hdmi_preqmp_phy { + struct device *dev; + struct phy *phy; + void __iomem *pll_reg; + void __iomem *phy_reg; + + struct phy_configure_opts_hdmi hdmi_opts; + + struct clk_hw pll_hw; + struct clk_bulk_data clks[MAX_CLKS]; + int num_clks; + + struct regulator_bulk_data regs[MAX_SUPPLIES]; + int num_regs; + + int (*power_on)(struct qcom_hdmi_preqmp_phy *phy); + int (*power_off)(struct qcom_hdmi_preqmp_phy *phy); +}; + +#define hw_clk_to_phy(x) container_of(x, struct qcom_hdmi_preqmp_phy, pll_= hw) + +struct qcom_hdmi_preqmp_cfg { + const char * const clk_names[MAX_CLKS]; + int num_clks; + + const char * const reg_names[MAX_SUPPLIES]; + int reg_init_load[MAX_SUPPLIES]; + int num_regs; + + int (*power_on)(struct qcom_hdmi_preqmp_phy *phy); + int (*power_off)(struct qcom_hdmi_preqmp_phy *phy); + + const struct clk_ops *pll_ops; + const struct clk_parent_data *pll_parent; +}; + +extern const struct qcom_hdmi_preqmp_cfg msm8x60_hdmi_phy_cfg; +extern const struct qcom_hdmi_preqmp_cfg msm8960_hdmi_phy_cfg; +extern const struct qcom_hdmi_preqmp_cfg msm8974_hdmi_phy_cfg; + +#endif diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-hdmi-base.c b/drivers/phy/qu= alcomm/phy-qcom-qmp-hdmi-base.c new file mode 100644 index 000000000000..7ea8295f7f40 --- /dev/null +++ b/drivers/phy/qualcomm/phy-qcom-qmp-hdmi-base.c @@ -0,0 +1,185 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2023, Linaro Ltd. + * Copyright (c) 2025, Qualcomm Incorporated + */ + +#include +#include +#include + +#include "phy-qcom-qmp-hdmi.h" + +int qmp_hdmi_phy_init(struct phy *phy) +{ + struct qmp_hdmi_phy *hdmi_phy =3D phy_get_drvdata(phy); + + return pm_runtime_resume_and_get(hdmi_phy->dev); +} + +int qmp_hdmi_phy_configure(struct phy *phy, union phy_configure_opts *opts) +{ + const struct phy_configure_opts_hdmi *hdmi_opts =3D &opts->hdmi; + struct qmp_hdmi_phy *hdmi_phy =3D phy_get_drvdata(phy); + int ret =3D 0; + + memcpy(&hdmi_phy->hdmi_opts, hdmi_opts, sizeof(*hdmi_opts)); + + return ret; +} + +int qmp_hdmi_phy_exit(struct phy *phy) +{ + struct qmp_hdmi_phy *hdmi_phy =3D phy_get_drvdata(phy); + + return pm_runtime_put_sync(hdmi_phy->dev); +} + +static int __maybe_unused qmp_hdmi_runtime_resume(struct device *dev) +{ + struct qmp_hdmi_phy *hdmi_phy =3D dev_get_drvdata(dev); + int ret; + + ret =3D regulator_bulk_enable(ARRAY_SIZE(hdmi_phy->supplies), hdmi_phy->s= upplies); + if (ret) + return ret; + + ret =3D clk_bulk_prepare_enable(ARRAY_SIZE(hdmi_phy->clks), hdmi_phy->clk= s); + if (ret) + goto out_disable_supplies; + + return 0; + +out_disable_supplies: + regulator_bulk_disable(ARRAY_SIZE(hdmi_phy->supplies), hdmi_phy->supplies= ); + + return ret; +} + +static int __maybe_unused qmp_hdmi_runtime_suspend(struct device *dev) +{ + struct qmp_hdmi_phy *hdmi_phy =3D dev_get_drvdata(dev); + + clk_bulk_disable_unprepare(ARRAY_SIZE(hdmi_phy->clks), hdmi_phy->clks); + regulator_bulk_disable(ARRAY_SIZE(hdmi_phy->supplies), hdmi_phy->supplies= ); + + return 0; +} + +static int qmp_hdmi_probe(struct platform_device *pdev) +{ + struct clk_init_data init =3D { + .name =3D "hdmipll", + .parent_data =3D (const struct clk_parent_data[]) { + { .fw_name =3D "xo", .name =3D "xo_board" }, + }, + .flags =3D CLK_GET_RATE_NOCACHE, + .num_parents =3D 1, + }; + const struct qmp_hdmi_cfg *cfg =3D of_device_get_match_data(&pdev->dev); + struct phy_provider *phy_provider; + struct device *dev =3D &pdev->dev; + struct qmp_hdmi_phy *hdmi_phy; + int ret, i; + + hdmi_phy =3D devm_kzalloc(dev, sizeof(*hdmi_phy), GFP_KERNEL); + if (!hdmi_phy) + return -ENOMEM; + + hdmi_phy->dev =3D dev; + + hdmi_phy->serdes =3D devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(hdmi_phy->serdes)) + return PTR_ERR(hdmi_phy->serdes); + + for (i =3D 0; i < HDMI_NUM_TX_CHANNEL; i++) { + hdmi_phy->tx[i] =3D devm_platform_ioremap_resource(pdev, 1 + i); + if (IS_ERR(hdmi_phy->tx[i])) + return PTR_ERR(hdmi_phy->tx[i]); + } + + hdmi_phy->phy_reg =3D devm_platform_ioremap_resource(pdev, 5); + if (IS_ERR(hdmi_phy->phy_reg)) + return PTR_ERR(hdmi_phy->phy_reg); + + hdmi_phy->clks[0].id =3D "iface"; + hdmi_phy->clks[1].id =3D "ref"; + ret =3D devm_clk_bulk_get(dev, ARRAY_SIZE(hdmi_phy->clks), hdmi_phy->clks= ); + if (ret) + return ret; + + hdmi_phy->supplies[0].supply =3D "vddio"; + hdmi_phy->supplies[0].init_load_uA =3D 100000; + hdmi_phy->supplies[1].supply =3D "vcca"; + hdmi_phy->supplies[1].init_load_uA =3D 10000; + ret =3D devm_regulator_bulk_get(dev, ARRAY_SIZE(hdmi_phy->supplies), hdmi= _phy->supplies); + if (ret) + return ret; + + platform_set_drvdata(pdev, hdmi_phy); + + ret =3D devm_pm_runtime_enable(&pdev->dev); + if (ret) + return ret; + + ret =3D pm_runtime_resume_and_get(&pdev->dev); + if (ret) + return ret; + + init.ops =3D cfg->pll_ops; + hdmi_phy->pll_hw.init =3D &init; + ret =3D devm_clk_hw_register(hdmi_phy->dev, &hdmi_phy->pll_hw); + if (ret) + goto err; + + ret =3D devm_of_clk_add_hw_provider(hdmi_phy->dev, of_clk_hw_simple_get, = &hdmi_phy->pll_hw); + if (ret) + goto err; + + hdmi_phy->phy =3D devm_phy_create(dev, pdev->dev.of_node, cfg->phy_ops); + if (IS_ERR(hdmi_phy->phy)) { + ret =3D PTR_ERR(hdmi_phy->phy); + goto err; + } + + phy_set_drvdata(hdmi_phy->phy, hdmi_phy); + + phy_provider =3D devm_of_phy_provider_register(dev, of_phy_simple_xlate); + pm_runtime_put_sync(&pdev->dev); + return PTR_ERR_OR_ZERO(phy_provider); + +err: + pm_runtime_put_sync(&pdev->dev); + return ret; +} + +static const struct of_device_id qmp_hdmi_of_match_table[] =3D { + { + .compatible =3D "qcom,hdmi-phy-8996", .data =3D &qmp_hdmi_8996_cfg, + }, { + .compatible =3D "qcom,hdmi-phy-8998", .data =3D &qmp_hdmi_8998_cfg, + }, + { }, +}; +MODULE_DEVICE_TABLE(of, qmp_hdmi_of_match_table); + +DEFINE_RUNTIME_DEV_PM_OPS(qmp_hdmi_pm_ops, + qmp_hdmi_runtime_suspend, + qmp_hdmi_runtime_resume, + NULL); + +static struct platform_driver qmp_hdmi_driver =3D { + .probe =3D qmp_hdmi_probe, + .driver =3D { + .name =3D "qcom-qmp-hdmi-phy", + .of_match_table =3D qmp_hdmi_of_match_table, + .pm =3D &qmp_hdmi_pm_ops, + }, +}; + +module_platform_driver(qmp_hdmi_driver); + +MODULE_AUTHOR("Dmitry Baryshkov "); +MODULE_DESCRIPTION("Qualcomm QMP HDMI PHY driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-hdmi-msm8996.c b/drivers/phy= /qualcomm/phy-qcom-qmp-hdmi-msm8996.c new file mode 100644 index 000000000000..67be7aba6feb --- /dev/null +++ b/drivers/phy/qualcomm/phy-qcom-qmp-hdmi-msm8996.c @@ -0,0 +1,440 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2023, Linaro Ltd. + * Copyright (c) 2025, Qualcomm Incorporated + */ + +#include +#include +#include + +#include "phy-qcom-qmp-hdmi.h" +#include "phy-qcom-qmp-qserdes-com.h" +#include "phy-qcom-qmp-qserdes-txrx.h" + +#define HDMI_VCO_MAX_FREQ 12000000000UL +#define HDMI_VCO_MIN_FREQ 8000000000UL + +#define HDMI_PCLK_MAX_FREQ 600000000UL +#define HDMI_PCLK_MIN_FREQ 25000000UL + +#define HDMI_HIGH_FREQ_BIT_CLK_THRESHOLD 3400000000UL +#define HDMI_DIG_FREQ_BIT_CLK_THRESHOLD 1500000000UL +#define HDMI_MID_FREQ_BIT_CLK_THRESHOLD 750000000UL +#define HDMI_DEFAULT_REF_CLOCK 19200000 +#define HDMI_PLL_CMP_CNT 1024 + +#define HDMI_PLL_POLL_MAX_READS 100 +#define HDMI_PLL_POLL_TIMEOUT_US 150 + +#define HDMI_8996_PHY_CFG 0x00000000 +#define HDMI_8996_PHY_PD_CTL 0x00000004 +#define HDMI_8996_PHY_MODE 0x00000008 +#define HDMI_8996_PHY_MISR_CLEAR 0x0000000c +#define HDMI_8996_PHY_TX0_TX1_BIST_CFG0 0x00000010 +#define HDMI_8996_PHY_TX0_TX1_BIST_CFG1 0x00000014 +#define HDMI_8996_PHY_TX0_TX1_PRBS_SEED_BYTE0 0x00000018 +#define HDMI_8996_PHY_TX0_TX1_PRBS_SEED_BYTE1 0x0000001c +#define HDMI_8996_PHY_TX0_TX1_BIST_PATTERN0 0x00000020 +#define HDMI_8996_PHY_TX0_TX1_BIST_PATTERN1 0x00000024 +#define HDMI_8996_PHY_TX2_TX3_BIST_CFG0 0x00000028 +#define HDMI_8996_PHY_TX2_TX3_BIST_CFG1 0x0000002c +#define HDMI_8996_PHY_TX2_TX3_PRBS_SEED_BYTE0 0x00000030 +#define HDMI_8996_PHY_TX2_TX3_PRBS_SEED_BYTE1 0x00000034 +#define HDMI_8996_PHY_TX2_TX3_BIST_PATTERN0 0x00000038 +#define HDMI_8996_PHY_TX2_TX3_BIST_PATTERN1 0x0000003c +#define HDMI_8996_PHY_DEBUG_BUS_SEL 0x00000040 +#define HDMI_8996_PHY_TXCAL_CFG0 0x00000044 +#define HDMI_8996_PHY_TXCAL_CFG1 0x00000048 +#define HDMI_8996_PHY_TX0_TX1_LANE_CTL 0x0000004c +#define HDMI_8996_PHY_TX2_TX3_LANE_CTL 0x00000050 +#define HDMI_8996_PHY_LANE_BIST_CONFIG 0x00000054 +#define HDMI_8996_PHY_CLOCK 0x00000058 +#define HDMI_8996_PHY_MISC1 0x0000005c +#define HDMI_8996_PHY_MISC2 0x00000060 +#define HDMI_8996_PHY_TX0_TX1_BIST_STATUS0 0x00000064 +#define HDMI_8996_PHY_TX0_TX1_BIST_STATUS1 0x00000068 +#define HDMI_8996_PHY_TX0_TX1_BIST_STATUS2 0x0000006c +#define HDMI_8996_PHY_TX2_TX3_BIST_STATUS0 0x00000070 +#define HDMI_8996_PHY_TX2_TX3_BIST_STATUS1 0x00000074 +#define HDMI_8996_PHY_TX2_TX3_BIST_STATUS2 0x00000078 +#define HDMI_8996_PHY_PRE_MISR_STATUS0 0x0000007c +#define HDMI_8996_PHY_PRE_MISR_STATUS1 0x00000080 +#define HDMI_8996_PHY_PRE_MISR_STATUS2 0x00000084 +#define HDMI_8996_PHY_PRE_MISR_STATUS3 0x00000088 +#define HDMI_8996_PHY_POST_MISR_STATUS0 0x0000008c +#define HDMI_8996_PHY_POST_MISR_STATUS1 0x00000090 +#define HDMI_8996_PHY_POST_MISR_STATUS2 0x00000094 +#define HDMI_8996_PHY_POST_MISR_STATUS3 0x00000098 +#define HDMI_8996_PHY_STATUS 0x0000009c +#define HDMI_8996_PHY_MISC3_STATUS 0x000000a0 +#define HDMI_8996_PHY_MISC4_STATUS 0x000000a4 +#define HDMI_8996_PHY_DEBUG_BUS0 0x000000a8 +#define HDMI_8996_PHY_DEBUG_BUS1 0x000000ac +#define HDMI_8996_PHY_DEBUG_BUS2 0x000000b0 +#define HDMI_8996_PHY_DEBUG_BUS3 0x000000b4 +#define HDMI_8996_PHY_PHY_REVISION_ID0 0x000000b8 +#define HDMI_8996_PHY_PHY_REVISION_ID1 0x000000bc +#define HDMI_8996_PHY_PHY_REVISION_ID2 0x000000c0 +#define HDMI_8996_PHY_PHY_REVISION_ID3 0x000000c4 + +struct qmp_hdmi_8996_post_divider { + u64 vco_freq; + int hsclk_divsel; + int vco_ratio; + int tx_band_sel; +}; + +static inline void write16(u16 val, void __iomem *reg) +{ + writel(val & 0xff, reg); + writel(val >> 8, reg + 4); +} + +static inline void write24(u32 val, void __iomem *reg) +{ + writel(val & 0xff, reg); + writel((val >> 8) & 0xff, reg + 4); + writel(val >> 16, reg + 8); +} + +static inline u32 read24(void __iomem *reg) +{ + u32 val =3D readl(reg); + + val |=3D readl(reg + 4) << 8; + val |=3D readl(reg + 8) << 16; + + return val; +} + +static inline u32 qmp_hdmi_8996_pll_get_pll_cmp(u64 fdata, unsigned long r= ef_clk) +{ + u64 dividend =3D HDMI_PLL_CMP_CNT * fdata; + u32 divisor =3D ref_clk * 10; + u32 rem; + + rem =3D do_div(dividend, divisor); + if (rem > (divisor >> 1)) + dividend++; + + return dividend - 1; +} + +static int qmp_hdmi_8996_pll_get_post_div(struct qmp_hdmi_8996_post_divide= r *pd, u64 bclk) +{ + int ratio[] =3D { 2, 3, 4, 5, 6, 9, 10, 12, 14, 15, 20, 21, 25, 28, 35 }; + int hs_divsel[] =3D { 0, 4, 8, 12, 1, 5, 2, 9, 3, 13, 10, 7, 14, 11, 15 }; + int tx_band_sel[] =3D { 0, 1, 2, 3 }; + u64 vco_freq[60]; + u64 vco, vco_optimal; + int half_rate_mode =3D 0; + int vco_optimal_index, vco_freq_index; + int i, j; + +retry: + vco_optimal =3D HDMI_VCO_MAX_FREQ; + vco_optimal_index =3D -1; + vco_freq_index =3D 0; + for (i =3D 0; i < 15; i++) { + for (j =3D 0; j < 4; j++) { + u32 ratio_mult =3D ratio[i] << tx_band_sel[j]; + + vco =3D bclk >> half_rate_mode; + vco *=3D ratio_mult; + vco_freq[vco_freq_index++] =3D vco; + } + } + + for (i =3D 0; i < 60; i++) { + u64 vco_tmp =3D vco_freq[i]; + + if ((vco_tmp >=3D HDMI_VCO_MIN_FREQ) && + (vco_tmp <=3D vco_optimal)) { + vco_optimal =3D vco_tmp; + vco_optimal_index =3D i; + } + } + + if (vco_optimal_index =3D=3D -1) { + if (!half_rate_mode) { + half_rate_mode =3D 1; + goto retry; + } + + return -EINVAL; + } + + pd->vco_freq =3D vco_optimal; + pd->tx_band_sel =3D tx_band_sel[vco_optimal_index % 4]; + pd->vco_ratio =3D ratio[vco_optimal_index / 4]; + pd->hsclk_divsel =3D hs_divsel[vco_optimal_index / 4]; + + return 0; +} + +static int qmp_hdmi_8996_phy_set_rate(struct qmp_hdmi_phy *hdmi_phy) +{ + unsigned long parent_rate =3D HDMI_DEFAULT_REF_CLOCK; + unsigned long rate =3D hdmi_phy->hdmi_opts.tmds_char_rate; + struct qmp_hdmi_8996_post_divider pd; + bool gen_ssc =3D false; + u64 bclk; + u64 dec_start; + u64 frac_start; + u64 fdata; + u32 pll_divisor; + u32 rem; + u32 integloop_gain; + u32 pll_cmp; + int i, ret; + + bclk =3D ((u64)rate) * 10; + ret =3D qmp_hdmi_8996_pll_get_post_div(&pd, bclk); + if (ret) { + dev_err(hdmi_phy->dev, "PLL calculation failed\n"); + return ret; + } + + dec_start =3D pd.vco_freq; + pll_divisor =3D 4 * parent_rate; + do_div(dec_start, pll_divisor); + + frac_start =3D pd.vco_freq * (1 << 20); + + rem =3D do_div(frac_start, pll_divisor); + frac_start -=3D dec_start * (1 << 20); + if (rem > (pll_divisor >> 1)) + frac_start++; + + fdata =3D pd.vco_freq; + do_div(fdata, pd.vco_ratio); + + pll_cmp =3D qmp_hdmi_8996_pll_get_pll_cmp(fdata, parent_rate); + + /* Initially shut down PHY */ + dev_dbg(hdmi_phy->dev, "Disabling PHY"); + writel(0x0, hdmi_phy->phy_reg + HDMI_8996_PHY_PD_CTL); + udelay(500); + + /* Power up sequence */ + writel(0x04, hdmi_phy->serdes + QSERDES_COM_BG_CTRL); + + writel(0x1, hdmi_phy->phy_reg + HDMI_8996_PHY_PD_CTL); + writel(0x20, hdmi_phy->serdes + QSERDES_COM_RESETSM_CNTRL); + writel(0x0f, hdmi_phy->phy_reg + HDMI_8996_PHY_TX0_TX1_LANE_CTL); + writel(0x0f, hdmi_phy->phy_reg + HDMI_8996_PHY_TX2_TX3_LANE_CTL); + + writel(0x43, hdmi_phy->tx[0] + QSERDES_TX_LANE_MODE); + writel(0x43, hdmi_phy->tx[2] + QSERDES_TX_LANE_MODE); + + writel(0x1e, hdmi_phy->serdes + QSERDES_COM_SYSCLK_BUF_ENABLE); + writel(0x07, hdmi_phy->serdes + QSERDES_COM_BIAS_EN_CLKBUFLR_EN); + writel(0x37, hdmi_phy->serdes + QSERDES_COM_SYSCLK_EN_SEL); + writel(0x02, hdmi_phy->serdes + QSERDES_COM_SYS_CLK_CTRL); + writel(0x0e, hdmi_phy->serdes + QSERDES_COM_CLK_ENABLE1); + + if (frac_start !=3D 0 || gen_ssc) { + writel(0x28, hdmi_phy->serdes + QSERDES_COM_PLL_CCTRL_MODE0); + writel(0x16, hdmi_phy->serdes + QSERDES_COM_PLL_RCTRL_MODE0); + writel(11000000 / (parent_rate / 20), + hdmi_phy->serdes + QSERDES_COM_CP_CTRL_MODE0); + integloop_gain =3D (64 * parent_rate) / HDMI_DEFAULT_REF_CLOCK; + } else { + writel(0x01, hdmi_phy->serdes + QSERDES_COM_PLL_CCTRL_MODE0); + writel(0x10, hdmi_phy->serdes + QSERDES_COM_PLL_RCTRL_MODE0); + writel(0x23, hdmi_phy->serdes + QSERDES_COM_CP_CTRL_MODE0); + integloop_gain =3D (1022 * parent_rate) / (100 * 1000 * 1000); + } + + /* Bypass VCO calibration */ + if (bclk > HDMI_DIG_FREQ_BIT_CLK_THRESHOLD) { + writel(1, hdmi_phy->serdes + QSERDES_COM_SVS_MODE_CLK_SEL); + integloop_gain <<=3D 1; + } else { + writel(2, hdmi_phy->serdes + QSERDES_COM_SVS_MODE_CLK_SEL); + integloop_gain <<=3D 2; + } + + integloop_gain =3D min_t(u32, integloop_gain, 2046); + + writel(0x0f, hdmi_phy->serdes + QSERDES_COM_BG_TRIM); + writel(0x0f, hdmi_phy->serdes + QSERDES_COM_PLL_IVCO); + writel(0, hdmi_phy->serdes + QSERDES_COM_VCO_TUNE_CTRL); + + writel(0x06, hdmi_phy->serdes + QSERDES_COM_BG_CTRL); + + writel(0x30, hdmi_phy->serdes + QSERDES_COM_CLK_SELECT); + writel(0x20 | pd.hsclk_divsel, hdmi_phy->serdes + QSERDES_COM_HSCLK_SEL); + writel(0x0, hdmi_phy->serdes + QSERDES_COM_LOCK_CMP_EN); + + writel(dec_start, hdmi_phy->serdes + QSERDES_COM_DEC_START_MODE0); + write24(frac_start, hdmi_phy->serdes + QSERDES_COM_DIV_FRAC_START1_MODE0); + + write16(integloop_gain, hdmi_phy->serdes + QSERDES_COM_INTEGLOOP_GAIN0_MO= DE0); + + write24(pll_cmp, hdmi_phy->serdes + QSERDES_COM_LOCK_CMP1_MODE0); + + writel(0x00, hdmi_phy->serdes + QSERDES_COM_VCO_TUNE_MAP); + writel(0x2c, hdmi_phy->serdes + QSERDES_COM_CORE_CLK_EN); + writel(5, hdmi_phy->serdes + QSERDES_COM_CORECLK_DIV); + writel(0x02, hdmi_phy->serdes + QSERDES_COM_CMN_CONFIG); + + writel(0x15, hdmi_phy->serdes + QSERDES_COM_RESCODE_DIV_NUM); + + /* TX lanes setup (TX 0/1/2/3) */ + for (i =3D 0; i < HDMI_NUM_TX_CHANNEL; i++) { + writel(0x03, hdmi_phy->tx[i] + QSERDES_TX_CLKBUF_ENABLE); + writel(pd.tx_band_sel + 4, hdmi_phy->tx[i] + QSERDES_TX_TX_BAND); + writel(0x03, hdmi_phy->tx[i] + QSERDES_TX_RESET_TSYNC_EN); + writel(0x00, hdmi_phy->tx[i] + QSERDES_TX_VMODE_CTRL1); + writel(0x00, hdmi_phy->tx[i] + QSERDES_TX_TX_DRV_LVL_OFFSET); + writel(0x00, hdmi_phy->tx[i] + QSERDES_TX_RES_CODE_LANE_OFFSET); + writel(0x03, hdmi_phy->tx[i] + QSERDES_TX_TRAN_DRVR_EMP_EN); + writel(0x40, hdmi_phy->tx[i] + QSERDES_TX_PARRATE_REC_DETECT_IDLE_EN); + writel(i !=3D 3 ? 0xc : 0x3, hdmi_phy->tx[i] + QSERDES_TX_HP_PD_ENABLES); + } + + if (bclk > HDMI_HIGH_FREQ_BIT_CLK_THRESHOLD) { + for (i =3D 0; i < HDMI_NUM_TX_CHANNEL; i++) { + writel(i !=3D 3 ? 0x25 : 0x22, hdmi_phy->tx[i] + QSERDES_TX_TX_DRV_LVL); + writel(i !=3D 3 ? 0x23 : 0x27, hdmi_phy->tx[i] + QSERDES_TX_TX_EMP_POST= 1_LVL); + writel(i !=3D 3 ? 0x0d : 0x00, hdmi_phy->tx[i] + QSERDES_TX_VMODE_CTRL2= ); + } + } else if (bclk > HDMI_MID_FREQ_BIT_CLK_THRESHOLD) { + for (i =3D 0; i < HDMI_NUM_TX_CHANNEL; i++) { + writel(0x25, hdmi_phy->tx[i] + QSERDES_TX_TX_DRV_LVL); + writel(0x23, hdmi_phy->tx[i] + QSERDES_TX_TX_EMP_POST1_LVL); + writel(i !=3D 3 ? 0x0d : 0x00, hdmi_phy->tx[i] + QSERDES_TX_VMODE_CTRL2= ); + } + } else { + for (i =3D 0; i < HDMI_NUM_TX_CHANNEL; i++) { + writel(0x20, hdmi_phy->tx[i] + QSERDES_TX_TX_DRV_LVL); + writel(0x20, hdmi_phy->tx[i] + QSERDES_TX_TX_EMP_POST1_LVL); + writel(0x0e, hdmi_phy->tx[i] + QSERDES_TX_VMODE_CTRL2); + } + } + + if (bclk > HDMI_HIGH_FREQ_BIT_CLK_THRESHOLD) + writel(0x10, hdmi_phy->phy_reg + HDMI_8996_PHY_MODE); + else + writel(0x00, hdmi_phy->phy_reg + HDMI_8996_PHY_MODE); + writel(0x1f, hdmi_phy->phy_reg + HDMI_8996_PHY_PD_CTL); + + return 0; +} + +static int qmp_hdmi_8996_phy_power_on(struct phy *phy) +{ + struct qmp_hdmi_phy *hdmi_phy =3D phy_get_drvdata(phy); + u32 status; + int i, ret =3D 0; + + ret =3D qmp_hdmi_8996_phy_set_rate(hdmi_phy); + if (ret) { + dev_err(hdmi_phy->dev, "Setting pixel clock rate failed\n"); + return ret; + } + + writel(0x1, hdmi_phy->phy_reg + HDMI_8996_PHY_CFG); + udelay(100); + + writel(0x19, hdmi_phy->phy_reg + HDMI_8996_PHY_CFG); + udelay(100); + + ret =3D readl_poll_timeout(hdmi_phy->serdes + QSERDES_COM_C_READY_STATUS, + status, status & BIT(0), + HDMI_PLL_POLL_TIMEOUT_US, + HDMI_PLL_POLL_MAX_READS * HDMI_PLL_POLL_TIMEOUT_US); + + if (ret) { + dev_warn(hdmi_phy->dev, "HDMI PLL is not locked\n"); + return ret; + } + + for (i =3D 0; i < HDMI_NUM_TX_CHANNEL; i++) + writel(0x6f, hdmi_phy->tx[i] + QSERDES_TX_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_= EN); + + /* Disable SSC */ + writel(0x0, hdmi_phy->serdes + QSERDES_COM_SSC_PER1); + writel(0x0, hdmi_phy->serdes + QSERDES_COM_SSC_PER2); + writel(0x0, hdmi_phy->serdes + QSERDES_COM_SSC_STEP_SIZE1); + writel(0x0, hdmi_phy->serdes + QSERDES_COM_SSC_STEP_SIZE2); + writel(0x2, hdmi_phy->serdes + QSERDES_COM_SSC_EN_CENTER); + + ret =3D readl_poll_timeout(hdmi_phy->phy_reg + HDMI_8996_PHY_STATUS, + status, status & BIT(0), + HDMI_PLL_POLL_TIMEOUT_US, + HDMI_PLL_POLL_MAX_READS * HDMI_PLL_POLL_TIMEOUT_US); + if (ret) { + dev_warn(hdmi_phy->dev, "HDMI PLL is not locked\n"); + return ret; + } + + /* Restart the retiming buffer */ + writel(0x18, hdmi_phy->phy_reg + HDMI_8996_PHY_CFG); + udelay(1); + writel(0x19, hdmi_phy->phy_reg + HDMI_8996_PHY_CFG); + + return 0; +} + +static int qmp_hdmi_8996_phy_power_off(struct phy *phy) +{ + struct qmp_hdmi_phy *hdmi_phy =3D phy_get_drvdata(phy); + + writel(0x6, hdmi_phy->phy_reg + HDMI_8996_PHY_CFG); + usleep_range(100, 150); + + return 0; +} + +static int qmp_hdmi_8996_pll_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + req->rate =3D clamp(req->rate, HDMI_PCLK_MIN_FREQ, HDMI_PCLK_MAX_FREQ); + + return 0; +} + +static unsigned long qmp_hdmi_8996_pll_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct qmp_hdmi_phy *phy =3D hw_clk_to_pll(hw); + u32 pll_cmp =3D read24(phy->serdes + QSERDES_COM_LOCK_CMP1_MODE0); + + return mult_frac(pll_cmp + 1, parent_rate, HDMI_PLL_CMP_CNT); +} + +static int qmp_hdmi_8996_pll_is_enabled(struct clk_hw *hw) +{ + struct qmp_hdmi_phy *phy =3D hw_clk_to_pll(hw); + u32 status; + int pll_locked; + + status =3D readl(phy->serdes + QSERDES_COM_C_READY_STATUS); + pll_locked =3D status & BIT(0); + + return pll_locked; +} + +static const struct clk_ops qmp_hdmi_8996_pll_ops =3D { + .recalc_rate =3D qmp_hdmi_8996_pll_recalc_rate, + .determine_rate =3D qmp_hdmi_8996_pll_determine_rate, + .is_enabled =3D qmp_hdmi_8996_pll_is_enabled, +}; + +static const struct phy_ops qmp_hdmi_8996_phy_ops =3D { + .init =3D qmp_hdmi_phy_init, + .configure =3D qmp_hdmi_phy_configure, + .power_on =3D qmp_hdmi_8996_phy_power_on, + .power_off =3D qmp_hdmi_8996_phy_power_off, + .exit =3D qmp_hdmi_phy_exit, + .owner =3D THIS_MODULE, +}; + +const struct qmp_hdmi_cfg qmp_hdmi_8996_cfg =3D { + .pll_ops =3D &qmp_hdmi_8996_pll_ops, + .phy_ops =3D &qmp_hdmi_8996_phy_ops, +}; diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-hdmi-msm8998.c b/drivers/phy= /qualcomm/phy-qcom-qmp-hdmi-msm8998.c new file mode 100644 index 000000000000..495c5ee053d6 --- /dev/null +++ b/drivers/phy/qualcomm/phy-qcom-qmp-hdmi-msm8998.c @@ -0,0 +1,489 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2024 Freebox SAS + * Copyright (c) 2025, Qualcomm Incorporated + */ + +#include +#include +#include +#include + +#include "phy-qcom-qmp-hdmi.h" +#include "phy-qcom-qmp-qserdes-com-v3.h" +#include "phy-qcom-qmp-qserdes-txrx.h" + +#define HDMI_VCO_MAX_FREQ 12000000000UL +#define HDMI_VCO_MIN_FREQ 8000000000UL + +#define HDMI_PCLK_MAX_FREQ 600000000UL +#define HDMI_PCLK_MIN_FREQ 25000000UL + +#define HDMI_HIGH_FREQ_BIT_CLK_THRESHOLD 3400000000UL +#define HDMI_DIG_FREQ_BIT_CLK_THRESHOLD 1500000000UL +#define HDMI_MID_FREQ_BIT_CLK_THRESHOLD 750000000UL +#define HDMI_DEFAULT_REF_CLOCK 19200000 +#define HDMI_PLL_CMP_CNT 1024 + +#define HDMI_PLL_POLL_MAX_READS 100 +#define HDMI_PLL_POLL_TIMEOUT_US 150 + +#define HDMI_8998_PHY_CFG 0x00000000 +#define HDMI_8998_PHY_PD_CTL 0x00000004 +#define HDMI_8998_PHY_MODE 0x00000010 +#define HDMI_8998_PHY_CLOCK 0x0000005c +#define HDMI_8998_PHY_CMN_CTRL 0x00000068 +#define HDMI_8998_PHY_STATUS 0x000000b4 + +#define HDMI_8998_PHY_TXn_EMP_POST1_LVL 0x00000000 +#define HDMI_8998_PHY_TXn_INTERFACE_SELECT_TX_BAND 0x00000008 +#define HDMI_8998_PHY_TXn_CLKBUF_TERM_ENABLE 0x0000000c +#define HDMI_8998_PHY_TXn_DRV_LVL_RES_CODE_OFFSET 0x00000014 +#define HDMI_8998_PHY_TXn_DRV_LVL 0x00000018 +#define HDMI_8998_PHY_TXn_LANE_CONFIG 0x0000001c +#define HDMI_8998_PHY_TXn_PRE_DRIVER_1 0x00000024 +#define HDMI_8998_PHY_TXn_PRE_DRIVER_2 0x00000028 +#define HDMI_8998_PHY_TXn_LANE_MODE 0x0000002c + +struct qmp_hdmi_8998_post_divider { + u64 vco_freq; + int hsclk_divsel; + int vco_ratio; + int tx_band_sel; + int half_rate_mode; +}; + +static inline void write16(u16 val, void __iomem *reg) +{ + writel(val & 0xff, reg); + writel(val >> 8, reg + 4); +} + +static inline void write24(u32 val, void __iomem *reg) +{ + writel(val & 0xff, reg); + writel((val >> 8) & 0xff, reg + 4); + writel(val >> 16, reg + 8); +} + +static inline u32 read24(void __iomem *reg) +{ + u32 val =3D readl(reg); + + val |=3D readl(reg + 4) << 8; + val |=3D readl(reg + 8) << 16; + + return val; +} + +static inline u32 qmp_hdmi_8998_pll_get_pll_cmp(u64 fdata, unsigned long r= ef_clk) +{ + u64 dividend =3D HDMI_PLL_CMP_CNT * fdata; + u32 divisor =3D ref_clk * 10; + u32 rem; + + rem =3D do_div(dividend, divisor); + if (rem > (divisor >> 1)) + dividend++; + + return dividend - 1; +} + +static int qmp_hdmi_8998_pll_get_post_div(struct qmp_hdmi_8998_post_divide= r *pd, u64 bclk) +{ + u32 const ratio_list[] =3D {1, 2, 3, 4, 5, 6, 9, 10, 12, 15, 25}; + u32 const band_list[] =3D {0, 1, 2, 3}; + u32 const sz_ratio =3D ARRAY_SIZE(ratio_list); + u32 const sz_band =3D ARRAY_SIZE(band_list); + u32 const cmp_cnt =3D 1024; + u32 const th_min =3D 500, th_max =3D 1000; + u32 half_rate_mode =3D 0; + u32 list_elements; + int optimal_index; + u32 i, j, k; + u32 found_hsclk_divsel =3D 0, found_vco_ratio; + u32 found_tx_band_sel; + u64 const min_freq =3D HDMI_VCO_MIN_FREQ, max_freq =3D HDMI_VCO_MAX_FREQ; + u64 freq_list[ARRAY_SIZE(ratio_list) * ARRAY_SIZE(band_list)]; + u64 found_vco_freq; + u64 freq_optimal; + +find_optimal_index: + freq_optimal =3D max_freq; + optimal_index =3D -1; + list_elements =3D 0; + + for (i =3D 0; i < sz_ratio; i++) { + for (j =3D 0; j < sz_band; j++) { + u64 freq =3D div_u64(bclk, (1 << half_rate_mode)); + + freq *=3D (ratio_list[i] * (1 << band_list[j])); + freq_list[list_elements++] =3D freq; + } + } + + for (k =3D 0; k < ARRAY_SIZE(freq_list); k++) { + u32 const clks_pll_div =3D 2, core_clk_div =3D 5; + u32 const rng1 =3D 16, rng2 =3D 8; + u32 th1, th2; + u64 core_clk, rvar1, rem; + + core_clk =3D div_u64(freq_list[k], + ratio_list[k / sz_band] * clks_pll_div * + core_clk_div); + + rvar1 =3D HDMI_DEFAULT_REF_CLOCK * rng1 * HZ_PER_MHZ; + rvar1 =3D div64_u64_rem(rvar1, (cmp_cnt * core_clk), &rem); + if (rem > ((cmp_cnt * core_clk) >> 1)) + rvar1++; + th1 =3D rvar1; + + rvar1 =3D HDMI_DEFAULT_REF_CLOCK * rng2 * HZ_PER_MHZ; + rvar1 =3D div64_u64_rem(rvar1, (cmp_cnt * core_clk), &rem); + if (rem > ((cmp_cnt * core_clk) >> 1)) + rvar1++; + th2 =3D rvar1; + + if (freq_list[k] >=3D min_freq && + freq_list[k] <=3D max_freq) { + if ((th1 >=3D th_min && th1 <=3D th_max) || + (th2 >=3D th_min && th2 <=3D th_max)) { + if (freq_list[k] <=3D freq_optimal) { + freq_optimal =3D freq_list[k]; + optimal_index =3D k; + } + } + } + } + + if (optimal_index =3D=3D -1) { + if (!half_rate_mode) { + half_rate_mode =3D 1; + goto find_optimal_index; + } else { + return -EINVAL; + } + } else { + found_vco_ratio =3D ratio_list[optimal_index / sz_band]; + found_tx_band_sel =3D band_list[optimal_index % sz_band]; + found_vco_freq =3D freq_optimal; + } + + switch (found_vco_ratio) { + case 1: + found_hsclk_divsel =3D 15; + break; + case 2: + found_hsclk_divsel =3D 0; + break; + case 3: + found_hsclk_divsel =3D 4; + break; + case 4: + found_hsclk_divsel =3D 8; + break; + case 5: + found_hsclk_divsel =3D 12; + break; + case 6: + found_hsclk_divsel =3D 1; + break; + case 9: + found_hsclk_divsel =3D 5; + break; + case 10: + found_hsclk_divsel =3D 2; + break; + case 12: + found_hsclk_divsel =3D 9; + break; + case 15: + found_hsclk_divsel =3D 13; + break; + case 25: + found_hsclk_divsel =3D 14; + break; + } + + pd->vco_freq =3D found_vco_freq; + pd->tx_band_sel =3D found_tx_band_sel; + pd->vco_ratio =3D found_vco_ratio; + pd->hsclk_divsel =3D found_hsclk_divsel; + + return 0; +} + +static int qmp_hdmi_8998_phy_set_rate(struct qmp_hdmi_phy *hdmi_phy) +{ + unsigned long parent_rate =3D HDMI_DEFAULT_REF_CLOCK; + unsigned long rate =3D hdmi_phy->hdmi_opts.tmds_char_rate; + struct qmp_hdmi_8998_post_divider pd; + bool gen_ssc =3D false; + u64 bclk; + u64 dec_start; + u64 frac_start; + u64 fdata; + u32 pll_divisor; + u32 rem; + u32 integloop_gain; + u32 pll_cmp; + int i, ret; + + bclk =3D ((u64)rate) * 10; + ret =3D qmp_hdmi_8998_pll_get_post_div(&pd, bclk); + if (ret) { + dev_err(hdmi_phy->dev, "PLL calculation failed\n"); + return ret; + } + + dec_start =3D pd.vco_freq; + pll_divisor =3D 4 * parent_rate; + do_div(dec_start, pll_divisor); + + frac_start =3D pd.vco_freq * (1 << 20); + + rem =3D do_div(frac_start, pll_divisor); + frac_start -=3D dec_start * (1 << 20); + if (rem > (pll_divisor >> 1)) + frac_start++; + + fdata =3D pd.vco_freq; + do_div(fdata, pd.vco_ratio); + + pll_cmp =3D qmp_hdmi_8998_pll_get_pll_cmp(fdata, parent_rate); + + /* Initially shut down PHY */ + dev_dbg(hdmi_phy->dev, "Disabling PHY"); + writel(0x0, hdmi_phy->phy_reg + HDMI_8998_PHY_PD_CTL); + udelay(500); + + /* Power up sequence */ + writel(0x1, hdmi_phy->phy_reg + HDMI_8998_PHY_PD_CTL); + writel(0x20, hdmi_phy->serdes + QSERDES_V3_COM_RESETSM_CNTRL); + writel(0x6, hdmi_phy->phy_reg + HDMI_8998_PHY_CMN_CTRL); + + for (i =3D 0; i < HDMI_NUM_TX_CHANNEL; i++) { + writel(pd.tx_band_sel, + hdmi_phy->tx[i] + HDMI_8998_PHY_TXn_INTERFACE_SELECT_TX_BAND); + writel(0x1, hdmi_phy->tx[i] + HDMI_8998_PHY_TXn_CLKBUF_TERM_ENABLE); + writel(0x20, hdmi_phy->tx[i] + HDMI_8998_PHY_TXn_LANE_MODE); + } + + writel(0x02, hdmi_phy->serdes + QSERDES_V3_COM_SYSCLK_BUF_ENABLE); + writel(0x0B, hdmi_phy->serdes + QSERDES_V3_COM_BIAS_EN_CLKBUFLR_EN); + writel(0x37, hdmi_phy->serdes + QSERDES_V3_COM_SYSCLK_EN_SEL); + writel(0x02, hdmi_phy->serdes + QSERDES_V3_COM_SYS_CLK_CTRL); + writel(0x0E, hdmi_phy->serdes + QSERDES_V3_COM_CLK_ENABLE1); + + if (frac_start !=3D 0 || gen_ssc) { + writel(0x34, hdmi_phy->serdes + QSERDES_V3_COM_PLL_CCTRL_MODE0); + writel(0x16, hdmi_phy->serdes + QSERDES_V3_COM_PLL_RCTRL_MODE0); + writel(0x08, hdmi_phy->serdes + QSERDES_V3_COM_CP_CTRL_MODE0); + integloop_gain =3D 0x3f; + } else { + writel(0x02, hdmi_phy->serdes + QSERDES_V3_COM_PLL_CCTRL_MODE0); + writel(0x18, hdmi_phy->serdes + QSERDES_V3_COM_PLL_RCTRL_MODE0); + writel(0x30, hdmi_phy->serdes + QSERDES_V3_COM_CP_CTRL_MODE0); + integloop_gain =3D 0xc4; + } + + /* Bypass VCO calibration */ + if (bclk > HDMI_DIG_FREQ_BIT_CLK_THRESHOLD) { + writel(1, hdmi_phy->serdes + QSERDES_V3_COM_SVS_MODE_CLK_SEL); + integloop_gain <<=3D 1; + } else { + writel(2, hdmi_phy->serdes + QSERDES_V3_COM_SVS_MODE_CLK_SEL); + integloop_gain <<=3D 2; + } + + writel(0x07, hdmi_phy->serdes + QSERDES_V3_COM_PLL_IVCO); + writel(0x00, hdmi_phy->serdes + QSERDES_V3_COM_VCO_TUNE_CTRL); + + writel(0x30, hdmi_phy->serdes + QSERDES_V3_COM_CLK_SELECT); + writel(0x20 | pd.hsclk_divsel, hdmi_phy->serdes + QSERDES_V3_COM_HSCLK_SE= L); + writel(0x0, hdmi_phy->serdes + QSERDES_V3_COM_LOCK_CMP_EN); + + writel(dec_start, hdmi_phy->serdes + QSERDES_V3_COM_DEC_START_MODE0); + write24(frac_start, hdmi_phy->serdes + QSERDES_V3_COM_DIV_FRAC_START1_MOD= E0); + + write16(integloop_gain, hdmi_phy->serdes + QSERDES_V3_COM_INTEGLOOP_GAIN0= _MODE0); + + write24(pll_cmp, hdmi_phy->serdes + QSERDES_V3_COM_LOCK_CMP1_MODE0); + + writel(0x00, hdmi_phy->serdes + QSERDES_V3_COM_VCO_TUNE_MAP); + writel(0x2c, hdmi_phy->serdes + QSERDES_V3_COM_CORE_CLK_EN); + writel(5, hdmi_phy->serdes + QSERDES_V3_COM_CORECLK_DIV_MODE0); + + /* TX lanes setup (TX 0/1/2/3) */ + if (bclk > HDMI_HIGH_FREQ_BIT_CLK_THRESHOLD) { + for (i =3D 0; i < HDMI_NUM_TX_CHANNEL; i++) { + writel(0xf, + hdmi_phy->tx[i] + HDMI_8998_PHY_TXn_DRV_LVL); + writel(i =3D=3D 3 ? 0x00 : i =3D=3D 1 ? 0x02 : 0x03, + hdmi_phy->tx[i] + HDMI_8998_PHY_TXn_EMP_POST1_LVL); + writel(0x00, + hdmi_phy->tx[i] + HDMI_8998_PHY_TXn_PRE_DRIVER_1); + writel(i =3D=3D 3 ? 0x00 : 0x1c, + hdmi_phy->tx[i] + HDMI_8998_PHY_TXn_PRE_DRIVER_2); + writel((i =3D=3D 0 || i =3D=3D 3) ? 0x03 : 0x00, + hdmi_phy->tx[i] + HDMI_8998_PHY_TXn_DRV_LVL_RES_CODE_OFFSET); + } + } else if (bclk > HDMI_DIG_FREQ_BIT_CLK_THRESHOLD) { + for (i =3D 0; i < HDMI_NUM_TX_CHANNEL; i++) { + writel(0x0f, + hdmi_phy->tx[i] + HDMI_8998_PHY_TXn_DRV_LVL); + writel(i =3D=3D 3 ? 0x00 : 0x03, + hdmi_phy->tx[i] + HDMI_8998_PHY_TXn_EMP_POST1_LVL); + writel(0x00, + hdmi_phy->tx[i] + HDMI_8998_PHY_TXn_PRE_DRIVER_1); + writel(i =3D=3D 3 ? 0x18 : 0x16, + hdmi_phy->tx[i] + HDMI_8998_PHY_TXn_PRE_DRIVER_2); + writel(i =3D=3D 0 ? 0x03 : 0x00, + hdmi_phy->tx[i] + HDMI_8998_PHY_TXn_DRV_LVL_RES_CODE_OFFSET); + } + } else if (bclk > HDMI_MID_FREQ_BIT_CLK_THRESHOLD) { + for (i =3D 0; i < HDMI_NUM_TX_CHANNEL; i++) { + writel(0x0f, + hdmi_phy->tx[i] + HDMI_8998_PHY_TXn_DRV_LVL); + writel(i =3D=3D 3 ? 0x00 : 0x05, + hdmi_phy->tx[i] + HDMI_8998_PHY_TXn_EMP_POST1_LVL); + writel(0x00, + hdmi_phy->tx[i] + HDMI_8998_PHY_TXn_PRE_DRIVER_1); + writel(0x0e, + hdmi_phy->tx[i] + HDMI_8998_PHY_TXn_PRE_DRIVER_2); + writel(0x00, + hdmi_phy->tx[i] + HDMI_8998_PHY_TXn_DRV_LVL_RES_CODE_OFFSET); + } + } else { + for (i =3D 0; i < HDMI_NUM_TX_CHANNEL; i++) { + writel(i =3D=3D 3 ? 0x00 : 0x01, + hdmi_phy->tx[i] + HDMI_8998_PHY_TXn_DRV_LVL); + writel(0x00, + hdmi_phy->tx[i] + HDMI_8998_PHY_TXn_EMP_POST1_LVL); + writel(0x00, + hdmi_phy->tx[i] + HDMI_8998_PHY_TXn_PRE_DRIVER_1); + writel(i =3D=3D 3 ? 0x18 : 0x16, + hdmi_phy->tx[i] + HDMI_8998_PHY_TXn_PRE_DRIVER_2); + writel(0x00, + hdmi_phy->tx[i] + HDMI_8998_PHY_TXn_DRV_LVL_RES_CODE_OFFSET); + } + } + + if (bclk > HDMI_HIGH_FREQ_BIT_CLK_THRESHOLD) + writel(0x5, hdmi_phy->phy_reg + HDMI_8998_PHY_MODE); + else + writel(0x4, hdmi_phy->phy_reg + HDMI_8998_PHY_MODE); + + for (i =3D 0; i < HDMI_NUM_TX_CHANNEL; i++) + writel(0x10, hdmi_phy->tx[i] + HDMI_8998_PHY_TXn_LANE_CONFIG); + + return 0; +} + +static int qmp_hdmi_8998_phy_power_on(struct phy *phy) +{ + struct qmp_hdmi_phy *hdmi_phy =3D phy_get_drvdata(phy); + u32 status; + int i, ret =3D 0; + + ret =3D qmp_hdmi_8998_phy_set_rate(hdmi_phy); + if (ret) { + dev_err(hdmi_phy->dev, "Setting pixel clock rate failed\n"); + return ret; + } + + writel(0x1, hdmi_phy->phy_reg + HDMI_8998_PHY_CFG); + udelay(100); + + writel(0x59, hdmi_phy->phy_reg + HDMI_8998_PHY_CFG); + udelay(100); + + ret =3D readl_poll_timeout(hdmi_phy->serdes + QSERDES_V3_COM_C_READY_STAT= US, + status, status & BIT(0), + HDMI_PLL_POLL_TIMEOUT_US, + HDMI_PLL_POLL_MAX_READS * HDMI_PLL_POLL_TIMEOUT_US); + + if (ret) { + dev_warn(hdmi_phy->dev, "HDMI PLL is not locked\n"); + return ret; + } + + for (i =3D 0; i < HDMI_NUM_TX_CHANNEL; i++) + writel(0x1f, hdmi_phy->tx[i] + HDMI_8998_PHY_TXn_LANE_CONFIG); + + ret =3D readl_poll_timeout(hdmi_phy->phy_reg + HDMI_8998_PHY_STATUS, + status, status & BIT(0), + HDMI_PLL_POLL_TIMEOUT_US, + HDMI_PLL_POLL_MAX_READS * HDMI_PLL_POLL_TIMEOUT_US); + if (ret) { + dev_warn(hdmi_phy->dev, "HDMI PLL is not locked\n"); + return ret; + } + + /* Restart the retiming buffer */ + writel(0x58, hdmi_phy->phy_reg + HDMI_8998_PHY_CFG); + udelay(1); + writel(0x59, hdmi_phy->phy_reg + HDMI_8998_PHY_CFG); + + return 0; +} + +static int qmp_hdmi_8998_phy_power_off(struct phy *phy) +{ + struct qmp_hdmi_phy *hdmi_phy =3D phy_get_drvdata(phy); + + writel(0, hdmi_phy->phy_reg + HDMI_8998_PHY_PD_CTL); + usleep_range(100, 150); + + return 0; +} + +static int qmp_hdmi_8998_pll_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + req->rate =3D clamp(req->rate, HDMI_PCLK_MIN_FREQ, HDMI_PCLK_MAX_FREQ); + + return 0; +} + +static unsigned long qmp_hdmi_8998_pll_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct qmp_hdmi_phy *phy =3D hw_clk_to_pll(hw); + u32 pll_cmp =3D read24(phy->serdes + QSERDES_V3_COM_LOCK_CMP1_MODE0); + + return mult_frac(pll_cmp + 1, parent_rate, HDMI_PLL_CMP_CNT); +} + +static int qmp_hdmi_8998_pll_is_enabled(struct clk_hw *hw) +{ + struct qmp_hdmi_phy *phy =3D hw_clk_to_pll(hw); + u32 status; + int pll_locked; + + status =3D readl(phy->serdes + QSERDES_V3_COM_C_READY_STATUS); + pll_locked =3D status & BIT(0); + + return pll_locked; +} + +static const struct clk_ops qmp_hdmi_8998_pll_ops =3D { + .recalc_rate =3D qmp_hdmi_8998_pll_recalc_rate, + .determine_rate =3D qmp_hdmi_8998_pll_determine_rate, + .is_enabled =3D qmp_hdmi_8998_pll_is_enabled, +}; + +static const struct phy_ops qmp_hdmi_8998_phy_ops =3D { + .init =3D qmp_hdmi_phy_init, + .configure =3D qmp_hdmi_phy_configure, + .power_on =3D qmp_hdmi_8998_phy_power_on, + .power_off =3D qmp_hdmi_8998_phy_power_off, + .exit =3D qmp_hdmi_phy_exit, + .owner =3D THIS_MODULE, +}; + +const struct qmp_hdmi_cfg qmp_hdmi_8998_cfg =3D { + .pll_ops =3D &qmp_hdmi_8998_pll_ops, + .phy_ops =3D &qmp_hdmi_8998_phy_ops, +}; diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-hdmi.h b/drivers/phy/qualcom= m/phy-qcom-qmp-hdmi.h new file mode 100644 index 000000000000..7a92ac02cab5 --- /dev/null +++ b/drivers/phy/qualcomm/phy-qcom-qmp-hdmi.h @@ -0,0 +1,49 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2023, Linaro Ltd. + * Copyright (c) 2025, Qualcomm Incorporated + */ + +#ifndef PHY_QCOM_QMP_HDMI_H +#define PHY_QCOM_QMP_HDMI_H + +#include +#include +#include +#include + +#define MAX_CLKS 2 +#define MAX_SUPPLIES 2 + +#define HDMI_NUM_TX_CHANNEL 4 + +struct qmp_hdmi_phy { + struct device *dev; + struct phy *phy; + void __iomem *serdes; + void __iomem *tx[HDMI_NUM_TX_CHANNEL]; + void __iomem *phy_reg; + + struct phy_configure_opts_hdmi hdmi_opts; + + struct clk_hw pll_hw; + struct clk_bulk_data clks[MAX_CLKS]; + struct regulator_bulk_data supplies[MAX_SUPPLIES]; +}; + +struct qmp_hdmi_cfg { + const struct clk_ops *pll_ops; + const struct phy_ops *phy_ops; +}; + +#define hw_clk_to_pll(x) container_of(x, struct qmp_hdmi_phy, pll_hw) + +int qmp_hdmi_phy_init(struct phy *phy); +int qmp_hdmi_phy_configure(struct phy *phy, union phy_configure_opts *opts= ); +int qmp_hdmi_phy_exit(struct phy *phy); + +extern const struct qmp_hdmi_cfg qmp_hdmi_8996_cfg; +extern const struct qmp_hdmi_cfg qmp_hdmi_8998_cfg; + +#endif --=20 2.47.3 From nobody Thu Jun 11 09:32:31 2026 Received: from mx0a-0031df01.pphosted.com (mx0a-0031df01.pphosted.com [205.220.168.131]) (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 5CAD54E3777 for ; Wed, 13 May 2026 18:14:13 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=205.220.168.131 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778696055; cv=none; b=OnzkbNpIOO+gRPKd7ifhH1iAdQoqaLwGI41mXH00hWbHJ1F9oNNoFl4YhrurhBsp7hOuGrDXmSfQqFk636Zc2u7ClzJ1HFj1rhs2XjbmdVIsXOUvBpXeIsMpuk+3Bacw+dveGChUi5+DdcCMrT8fVlPBjALdsSuacr9nZHr+1Ac= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778696055; c=relaxed/simple; bh=Gb9iaHhErPAWN0IRSVbJi0WfaWGvRDkDjNcbmOqzreM=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=UnjwA5pJO62IuHrEvZFXe88YOzNQUfhiWn/dOZAiAk/5apBzDoqXeXNyFdLRB23e/TnsrXqhZq7y2aaDf01wUkW81Z9wb+zicSqSd40f2uEgDZLZbvkK2GN9H2+ezv2/22PAMYkznzFOofUuzRcUrNIR98F59SU7gdaEJWb02Wg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=oss.qualcomm.com; spf=pass smtp.mailfrom=oss.qualcomm.com; dkim=pass (2048-bit key) header.d=qualcomm.com header.i=@qualcomm.com header.b=C/HOeRdm; dkim=pass (2048-bit key) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com header.b=arc2QBCI; arc=none smtp.client-ip=205.220.168.131 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=oss.qualcomm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=oss.qualcomm.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=qualcomm.com header.i=@qualcomm.com header.b="C/HOeRdm"; dkim=pass (2048-bit key) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com header.b="arc2QBCI" Received: from pps.filterd (m0279867.ppops.net [127.0.0.1]) by mx0a-0031df01.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 64DEbaAx2887912 for ; Wed, 13 May 2026 18:14:12 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=qualcomm.com; h= cc:content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=qcppdkim1; bh= bbJqSkiMGG/gTLlM9QQTChdoblkSPekP2NE+zK4RSQA=; b=C/HOeRdmjsX7LIMc N8C3ZLYyTNEjpFHRMQhpgHsFzgwvV/v4ccfSWjvy8Wh4t21P8spUVCvPr2FEkTre khJC7r0nTwM4pKUni19l1G+JmlY6qv/+P8wol+WJwcjIvFUwbSp8IsQ3lNUoraMt z3Z8PypH7jOgNwy1DNRzH4ZqSQsCs2DgL+JYsfQaTN3ZWEXKT0eqb3+Llgs8re2A PqUkvVZxdE8SPtVUo0XGC0QVFw+vcNfBvMkQaPMVEs/v7hWwOSNQkPr1o8bhUZMH kUaUK7V0+oZxOfRcLw3f5OthJ1k0i/MBpvqLxBhn2n9gnvnHmJqMS+bL5VdSDSqL 6L55BQ== Received: from mail-vs1-f69.google.com (mail-vs1-f69.google.com [209.85.217.69]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 4e4p4gj8jh-1 (version=TLSv1.3 cipher=TLS_AES_128_GCM_SHA256 bits=128 verify=NOT) for ; Wed, 13 May 2026 18:14:12 +0000 (GMT) Received: by mail-vs1-f69.google.com with SMTP id ada2fe7eead31-6312af106fcso10392432137.3 for ; Wed, 13 May 2026 11:14:12 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oss.qualcomm.com; s=google; t=1778696051; x=1779300851; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=bbJqSkiMGG/gTLlM9QQTChdoblkSPekP2NE+zK4RSQA=; b=arc2QBCIaArXtIBhoskHMcz38jSrGz6sGjCTgoiDigsQAdgKhuRbqgu/MPkubh9DBh 2fQT5A8wjRcF6TQVNvx599t/mIsqIDZENjzdeCMTEh62VVjcIJrH63AFnzjO8TCiTVEW /n7ICnvvbbEwxKbYc2jsaHNMZ76Gi+CwQq2Xb3wwLT6Ni/uFH9oFW9jP2ryym1PRCxv+ ia7QDKfewIWLXxzZsl9asOCvRGnyf75sAbp40L6yPia29i66PFaNk0EA6RoPinx34wEY UQzM5IlMh4dQEMpI6JvCMqhHaTX57cJdncMaGrZcIZwEYDtsRuqFI0NlWOwDTVzFe+Jt vCDg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1778696051; x=1779300851; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-gg:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to; bh=bbJqSkiMGG/gTLlM9QQTChdoblkSPekP2NE+zK4RSQA=; b=Srexh9i8vfdGvIS0EPjk65+jojYwRPC5PdZFgZY8mDwtwEHhKfnBZ1NtAlMS9xc9Kk eX5X5e0zVFL9BC2moe/V8cXZ9qnFj3EdhZUtbIVsj4Y4uHXfauDDHBuFwBWACpPjP3O2 UX4eamNUKm8+U3Fx7rts9hzTAMXqAb+MDL2IC9PbOznXJmwXW/fhA+MmIHCZxurU3PuJ jLASaEgSvAaOtUqp+fFprTJGM4to2GSHMw4eWnv9vXyIeu84SB8K4zlSN8VHqcSlsNhG pe8Alyvv8HxSlCzaBZXs0Mu6pnlNXd8/c5P9UKHEYJMQK0PwJvgHRroaoQWnHQv8XLzr 7MZw== X-Gm-Message-State: AOJu0YzPP4oE3tNWiPmkwdMjRe1O1XX0goaOCeeslL47i+RAP1AHLEYC xQ/+z5WNpvE4np1ZGNX8dyw8b6mVCOZ95yKWxCxYc9ZOCxchv19nCVTrSQOBfMsDFnFWOhuxVY8 +8y5rqh4MSNgACnB0I/GaR+XLykf0lD391/9u2cb1t2inTpWZ1sI0ZES2sERRfmX+Eds= X-Gm-Gg: Acq92OFzRsL0vdMeX3mYTZOVarzVZPJ+5hRU5Yy4t0ngS5meu2ucN47BmkD6mriZTLl nJ4FjYvhSMrjgyhLdq/mvQfCv2i4MscO0qnOFRv8038Iy0qxVF/Vl8Zt/ZGhJmAI3gtk2D5TPZt F+5geoVD6WWysq/DxacXFbzfQY9R+YDz3e8si0ts392K0MpXrCRDih0ETp69Uw4qd1yGStRQagJ FnYK0EnHFHrafAczJbmN/bIxgN5ALy/ZeYNYmcKjfV0Sy2/ifPBy1eefR3kCHZXY5HdL/QS5stp C/ghs2aaF5wbPlCp031XrV1EeaTyEozH2xaM9tgSsGh3Pgb8/ROx1YMAcrnVcwSzKdjOs9JpNsf DzQCTcFm0EcyENJ/ohpfRlUt45OXmGKFXdxEjNdPqrzm95scXoHoTvriQCLQzGCNoCdq55s+0kC r1R2HSclPLv5lXAnQuQiogRlak7vnNXhZRpYM= X-Received: by 2002:a05:6102:3a12:b0:631:8665:350c with SMTP id ada2fe7eead31-637a96e9cc3mr2136988137.25.1778696051408; Wed, 13 May 2026 11:14:11 -0700 (PDT) X-Received: by 2002:a05:6102:3a12:b0:631:8665:350c with SMTP id ada2fe7eead31-637a96e9cc3mr2136961137.25.1778696050842; Wed, 13 May 2026 11:14:10 -0700 (PDT) Received: from umbar.lan (2001-14ba-a073-af00-264b-feff-fe8b-be8a.rev.dnainternet.fi. [2001:14ba:a073:af00:264b:feff:fe8b:be8a]) by smtp.gmail.com with ESMTPSA id 2adb3069b0e04-5a8bd7d8974sm3174770e87.64.2026.05.13.11.14.09 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 13 May 2026 11:14:09 -0700 (PDT) From: Dmitry Baryshkov Date: Wed, 13 May 2026 21:14:05 +0300 Subject: [PATCH v9 2/5] phy: qualcomm: hdmi-28lpm: provide dynamic configuration 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: <20260513-fd-hdmi-phy-v9-2-ca98c72f1f9f@oss.qualcomm.com> References: <20260513-fd-hdmi-phy-v9-0-ca98c72f1f9f@oss.qualcomm.com> In-Reply-To: <20260513-fd-hdmi-phy-v9-0-ca98c72f1f9f@oss.qualcomm.com> To: Rob Clark , Dmitry Baryshkov , Abhinav Kumar , Jessica Zhang , Sean Paul , Marijn Suijten , David Airlie , Simona Vetter , Vinod Koul , Neil Armstrong Cc: linux-kernel@vger.kernel.org, linux-arm-msm@vger.kernel.org, dri-devel@lists.freedesktop.org, freedreno@lists.freedesktop.org, linux-phy@lists.infradead.org X-Mailer: b4 0.15.1 X-Developer-Signature: v=1; a=openpgp-sha256; l=14593; i=dmitry.baryshkov@oss.qualcomm.com; h=from:subject:message-id; bh=Gb9iaHhErPAWN0IRSVbJi0WfaWGvRDkDjNcbmOqzreM=; b=owEBbQGS/pANAwAKAYs8ij4CKSjVAcsmYgBqBL9tcVl2yBY5Sp5zqauRiqNPnJ4JPfcFm0gu5 XiGZue78ZOJATMEAAEKAB0WIQRMcISVXLJjVvC4lX+LPIo+Aiko1QUCagS/bQAKCRCLPIo+Aiko 1cdIB/9HEGnTFQD+U8aYt1inxPazDFqyM5/xUjplEupLOdC6+t1ACNc6YNHX0Ed4McwNFZpbwpj kG1lRdYC7qcn7Uk+CaRw+4n4YcKToJTbfXIkfY1jgKkBl/rAChj12VoN30+ppoxm6ni+pfdak3g 6O02fAyq1h9xq4VGQ1yuOogTIIelMuTzKKBngS+mcHkPKng4S5CuL1n+xmILyQlh/Wm+YmmuINP Yp4dZlymfIjjhRH7Txdz0VvcvSIgQBamnz24Dqo+PVIns91V3nxl2/nbVbX3LF+u07v9Y1iXZhi byUA+mQG29Hi6vOIzmuZ7e+/kPw25HFGMdzTFEXnxfEmpzB7 X-Developer-Key: i=dmitry.baryshkov@oss.qualcomm.com; a=openpgp; fpr=8F88381DD5C873E4AE487DA5199BF1243632046A X-Proofpoint-GUID: NKdACbWJrNFQnuN0o9ST-vC3GfXyYWw0 X-Authority-Analysis: v=2.4 cv=DOS/JSNb c=1 sm=1 tr=0 ts=6a04bf74 cx=c_pps a=5HAIKLe1ejAbszaTRHs9Ug==:117 a=xqWC_Br6kY4A:10 a=IkcTkHD0fZMA:10 a=NGcC8JguVDcA:10 a=s4-Qcg_JpJYA:10 a=VkNPw1HP01LnGYTKEx00:22 a=u7WPNUs3qKkmUXheDGA7:22 a=eoimf2acIAo5FJnRuUoq:22 a=EUspDBNiAAAA:8 a=rFVNmrDKDD7H5MqYjYMA:9 a=QEXdDO2ut3YA:10 a=gYDTvv6II1OnSo0itH1n:22 X-Proofpoint-ORIG-GUID: NKdACbWJrNFQnuN0o9ST-vC3GfXyYWw0 X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwNTEzMDE4MiBTYWx0ZWRfX6dS7h3HQGft6 9ytaZkKjNvtoxbNMEFr4aNqr1QSbOZnortcCMIEiuzerXUXWa07A0cJ8jSHh2EAFlwKhx7wrg3M zr55+wKSD5+RbeMfPb2spf/Hp7YSrBOyObXhePChKUVA5IrdyVTAMxhFk8Rwl2rSIfH4CWiQZya opHSKMJPRiRuNqseGaUQAnj++U4e5gEqo+aUSlpXq9PqQtqlm4NZ/ptsJAFRsNJGOsF9FQvQZMw MEM8fYg5Vsp0rwe+oU09FdF8vSmmGllm0PNJIXgCw7I/nSrMNutYxfzksiQ1JR6tmwXmc1njOCy mMJ3u8xDmy5uEXX60eGgHilHDeg+qwQg2bdG5DRXxmNu82u7xy5ie4Ji3e/ywWyrIZLOaAKaDAH xFzrAEpjLYtPGvaPevl2X4vrCgp0wpMcbt4ELS+4PIZmbGGvSHJhiG7+OQjgaYXu3NbT3NhQ7UJ 9zxPxwW2FQEcr4Ris7w== X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1143,Hydra:6.1.51,FMLib:17.12.100.49 definitions=2026-05-13_02,2026-05-13_01,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 malwarescore=0 adultscore=0 impostorscore=0 bulkscore=0 clxscore=1015 priorityscore=1501 phishscore=0 suspectscore=0 lowpriorityscore=0 spamscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.22.0-2605050000 definitions=main-2605130182 Replace fixed value configuration tables with the values calculated at the runtime. In some cases the values might differ from the original values. Those were validated on the IFC6410 board. Signed-off-by: Dmitry Baryshkov --- drivers/phy/qualcomm/phy-qcom-hdmi-28lpm.c | 325 +++++++++----------------= ---- 1 file changed, 104 insertions(+), 221 deletions(-) diff --git a/drivers/phy/qualcomm/phy-qcom-hdmi-28lpm.c b/drivers/phy/qualc= omm/phy-qcom-hdmi-28lpm.c index f1e7113e10bd..90d3331313c0 100644 --- a/drivers/phy/qualcomm/phy-qcom-hdmi-28lpm.c +++ b/drivers/phy/qualcomm/phy-qcom-hdmi-28lpm.c @@ -148,222 +148,17 @@ =20 #define HDMI_8960_COMMON_DIV 5 =20 -struct pll_rate { - unsigned long rate; - int num_reg; - struct { - u32 val; - u32 reg; - } conf[32]; -}; - -/* NOTE: keep sorted highest freq to lowest: */ -static const struct pll_rate freqtbl[] =3D { - { 154000000, 14, { - { 0x08, REG_HDMI_8960_PHY_PLL_REFCLK_CFG }, - { 0x20, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 }, - { 0xf9, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1 }, - { 0x02, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0 }, - { 0x03, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG1 }, - { 0x3b, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2 }, - { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG3 }, - { 0x86, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG4 }, - { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG5 }, - { 0x0d, REG_HDMI_8960_PHY_PLL_SDM_CFG0 }, - { 0x4d, REG_HDMI_8960_PHY_PLL_SDM_CFG1 }, - { 0x5e, REG_HDMI_8960_PHY_PLL_SDM_CFG2 }, - { 0x42, REG_HDMI_8960_PHY_PLL_SDM_CFG3 }, - { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG4 }, - } - }, - /* 1080p60/1080p50 case */ - { 148500000, 27, { - { 0x02, REG_HDMI_8960_PHY_PLL_REFCLK_CFG }, - { 0x02, REG_HDMI_8960_PHY_PLL_CHRG_PUMP_CFG }, - { 0x01, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 }, - { 0x33, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1 }, - { 0x2c, REG_HDMI_8960_PHY_PLL_IDAC_ADJ_CFG }, - { 0x06, REG_HDMI_8960_PHY_PLL_I_VI_KVCO_CFG }, - { 0x0a, REG_HDMI_8960_PHY_PLL_PWRDN_B }, - { 0x76, REG_HDMI_8960_PHY_PLL_SDM_CFG0 }, - { 0x01, REG_HDMI_8960_PHY_PLL_SDM_CFG1 }, - { 0x4c, REG_HDMI_8960_PHY_PLL_SDM_CFG2 }, - { 0xc0, REG_HDMI_8960_PHY_PLL_SDM_CFG3 }, - { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG4 }, - { 0x9a, REG_HDMI_8960_PHY_PLL_SSC_CFG0 }, - { 0x00, REG_HDMI_8960_PHY_PLL_SSC_CFG1 }, - { 0x00, REG_HDMI_8960_PHY_PLL_SSC_CFG2 }, - { 0x00, REG_HDMI_8960_PHY_PLL_SSC_CFG3 }, - { 0x10, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG0 }, - { 0x1a, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG1 }, - { 0x0d, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG2 }, - { 0xe6, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0 }, - { 0x02, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG1 }, - { 0x3b, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2 }, - { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG3 }, - { 0x86, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG4 }, - { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG5 }, - { 0x33, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG6 }, - { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG7 }, - } - }, - { 108000000, 13, { - { 0x08, REG_HDMI_8960_PHY_PLL_REFCLK_CFG }, - { 0x21, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 }, - { 0xf9, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1 }, - { 0x1c, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0 }, - { 0x02, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG1 }, - { 0x3b, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2 }, - { 0x86, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG4 }, - { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG5 }, - { 0x49, REG_HDMI_8960_PHY_PLL_SDM_CFG0 }, - { 0x49, REG_HDMI_8960_PHY_PLL_SDM_CFG1 }, - { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG2 }, - { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG3 }, - { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG4 }, - } - }, - /* 720p60/720p50/1080i60/1080i50/1080p24/1080p30/1080p25 */ - { 74250000, 8, { - { 0x0a, REG_HDMI_8960_PHY_PLL_PWRDN_B }, - { 0x12, REG_HDMI_8960_PHY_PLL_REFCLK_CFG }, - { 0x01, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 }, - { 0x33, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1 }, - { 0x76, REG_HDMI_8960_PHY_PLL_SDM_CFG0 }, - { 0xe6, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0 }, - { 0x02, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG1 }, - { 0x3b, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2 }, - } - }, - { 74176000, 14, { - { 0x18, REG_HDMI_8960_PHY_PLL_REFCLK_CFG }, - { 0x20, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 }, - { 0xf9, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1 }, - { 0xe5, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0 }, - { 0x02, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG1 }, - { 0x3b, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2 }, - { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG3 }, - { 0x86, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG4 }, - { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG5 }, - { 0x0c, REG_HDMI_8960_PHY_PLL_SDM_CFG0 }, - { 0x4c, REG_HDMI_8960_PHY_PLL_SDM_CFG1 }, - { 0x7d, REG_HDMI_8960_PHY_PLL_SDM_CFG2 }, - { 0xbc, REG_HDMI_8960_PHY_PLL_SDM_CFG3 }, - { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG4 }, - } - }, - { 65000000, 14, { - { 0x18, REG_HDMI_8960_PHY_PLL_REFCLK_CFG }, - { 0x20, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 }, - { 0xf9, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1 }, - { 0x8a, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0 }, - { 0x02, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG1 }, - { 0x3b, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2 }, - { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG3 }, - { 0x86, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG4 }, - { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG5 }, - { 0x0b, REG_HDMI_8960_PHY_PLL_SDM_CFG0 }, - { 0x4b, REG_HDMI_8960_PHY_PLL_SDM_CFG1 }, - { 0x7b, REG_HDMI_8960_PHY_PLL_SDM_CFG2 }, - { 0x09, REG_HDMI_8960_PHY_PLL_SDM_CFG3 }, - { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG4 }, - } - }, - /* 480p60/480i60 */ - { 27030000, 18, { - { 0x0a, REG_HDMI_8960_PHY_PLL_PWRDN_B }, - { 0x38, REG_HDMI_8960_PHY_PLL_REFCLK_CFG }, - { 0x02, REG_HDMI_8960_PHY_PLL_CHRG_PUMP_CFG }, - { 0x20, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 }, - { 0xff, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1 }, - { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG0 }, - { 0x4e, REG_HDMI_8960_PHY_PLL_SDM_CFG1 }, - { 0xd7, REG_HDMI_8960_PHY_PLL_SDM_CFG2 }, - { 0x03, REG_HDMI_8960_PHY_PLL_SDM_CFG3 }, - { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG4 }, - { 0x2a, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0 }, - { 0x03, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG1 }, - { 0x3b, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2 }, - { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG3 }, - { 0x86, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG4 }, - { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG5 }, - { 0x33, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG6 }, - { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG7 }, - } - }, - /* 576p50/576i50 */ - { 27000000, 27, { - { 0x32, REG_HDMI_8960_PHY_PLL_REFCLK_CFG }, - { 0x02, REG_HDMI_8960_PHY_PLL_CHRG_PUMP_CFG }, - { 0x01, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 }, - { 0x33, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1 }, - { 0x2c, REG_HDMI_8960_PHY_PLL_IDAC_ADJ_CFG }, - { 0x06, REG_HDMI_8960_PHY_PLL_I_VI_KVCO_CFG }, - { 0x0a, REG_HDMI_8960_PHY_PLL_PWRDN_B }, - { 0x7b, REG_HDMI_8960_PHY_PLL_SDM_CFG0 }, - { 0x01, REG_HDMI_8960_PHY_PLL_SDM_CFG1 }, - { 0x4c, REG_HDMI_8960_PHY_PLL_SDM_CFG2 }, - { 0xc0, REG_HDMI_8960_PHY_PLL_SDM_CFG3 }, - { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG4 }, - { 0x9a, REG_HDMI_8960_PHY_PLL_SSC_CFG0 }, - { 0x00, REG_HDMI_8960_PHY_PLL_SSC_CFG1 }, - { 0x00, REG_HDMI_8960_PHY_PLL_SSC_CFG2 }, - { 0x00, REG_HDMI_8960_PHY_PLL_SSC_CFG3 }, - { 0x10, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG0 }, - { 0x1a, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG1 }, - { 0x0d, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG2 }, - { 0x2a, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0 }, - { 0x03, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG1 }, - { 0x3b, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2 }, - { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG3 }, - { 0x86, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG4 }, - { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG5 }, - { 0x33, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG6 }, - { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG7 }, - } - }, - /* 640x480p60 */ - { 25200000, 27, { - { 0x32, REG_HDMI_8960_PHY_PLL_REFCLK_CFG }, - { 0x02, REG_HDMI_8960_PHY_PLL_CHRG_PUMP_CFG }, - { 0x01, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 }, - { 0x33, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1 }, - { 0x2c, REG_HDMI_8960_PHY_PLL_IDAC_ADJ_CFG }, - { 0x06, REG_HDMI_8960_PHY_PLL_I_VI_KVCO_CFG }, - { 0x0a, REG_HDMI_8960_PHY_PLL_PWRDN_B }, - { 0x77, REG_HDMI_8960_PHY_PLL_SDM_CFG0 }, - { 0x4c, REG_HDMI_8960_PHY_PLL_SDM_CFG1 }, - { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG2 }, - { 0xc0, REG_HDMI_8960_PHY_PLL_SDM_CFG3 }, - { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG4 }, - { 0x9a, REG_HDMI_8960_PHY_PLL_SSC_CFG0 }, - { 0x00, REG_HDMI_8960_PHY_PLL_SSC_CFG1 }, - { 0x00, REG_HDMI_8960_PHY_PLL_SSC_CFG2 }, - { 0x20, REG_HDMI_8960_PHY_PLL_SSC_CFG3 }, - { 0x10, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG0 }, - { 0x1a, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG1 }, - { 0x0d, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG2 }, - { 0xf4, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0 }, - { 0x02, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG1 }, - { 0x3b, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2 }, - { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG3 }, - { 0x86, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG4 }, - { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG5 }, - { 0x33, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG6 }, - { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG7 }, - } - }, -}; - -static const struct pll_rate *qcom_hdmi_8960_pll_find_rate(unsigned long r= ate) +static inline void write16(u16 val, void __iomem *reg) { - int i; - - for (i =3D 1; i < ARRAY_SIZE(freqtbl); i++) - if (rate > freqtbl[i].rate) - return &freqtbl[i - 1]; + writel(val & 0xff, reg); + writel(val >> 8, reg + 4); +} =20 - return &freqtbl[i - 1]; +static inline void write24(u32 val, void __iomem *reg) +{ + writel(val & 0xff, reg); + writel((val >> 8) & 0xff, reg + 4); + writel(val >> 16, reg + 8); } =20 static inline u32 read24(void __iomem *reg) @@ -407,6 +202,70 @@ static unsigned long qcom_28lpm_recalc(struct qcom_hdm= i_preqmp_phy *hdmi_phy, return rate; } =20 +/* This function is close to UNIPHY, but it has slighly different fields */ +static int qcom_28lpm_set_rate(struct qcom_hdmi_preqmp_phy *hdmi_phy, unsi= gned long parent_rate, + unsigned long vco_freq, u32 div_idx) +{ + unsigned int pixclk =3D hdmi_phy->hdmi_opts.tmds_char_rate; + unsigned int int_ref_freq; + unsigned int dc_offset; + unsigned int sdm_freq_seed; + unsigned int val; + bool sdm_mode =3D false; + u32 refclk_cfg; + u32 lf_cfg0; + u32 lf_cfg1; + u64 tmp; + + dev_dbg(hdmi_phy->dev, "rate=3D%u, div =3D %d, vco =3D %lu", pixclk, div_= idx, vco_freq); + + if (vco_freq % (parent_rate / 2) =3D=3D 0) { + refclk_cfg =3D FIELD_PREP(HDMI_8960_PHY_CLK0_DIV, 1); + int_ref_freq =3D parent_rate / 2; + } else { + refclk_cfg =3D HDMI_8960_PHY_DBLR_EN; + int_ref_freq =3D parent_rate * 2; + sdm_mode =3D true; + } + + dc_offset =3D vco_freq / int_ref_freq - 1; + tmp =3D vco_freq % int_ref_freq; + tmp *=3D 0x10000; + sdm_freq_seed =3D div_u64(tmp, int_ref_freq); + + val =3D FIELD_PREP(HDMI_8960_PHY_PLL_VCO_DIV, div_idx) | refclk_cfg; + writel(val, hdmi_phy->pll_reg + REG_HDMI_8960_PHY_PLL_REFCLK_CFG); + + lf_cfg0 =3D dc_offset >=3D 30 ? 0 : (dc_offset >=3D 16 ? 0x10 : 0x20); + lf_cfg0 +=3D sdm_mode ? 0 : 1; + + /* XXX: 0xc3 instead of 0x33 for qcs404 */ + lf_cfg1 =3D dc_offset >=3D 30 ? 0x33 : (dc_offset >=3D 16 ? 0xbb : 0xf9); + + writel(lf_cfg0, + hdmi_phy->pll_reg + REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0); + writel(lf_cfg1, + hdmi_phy->pll_reg + REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1); + + if (sdm_mode) + writel(dc_offset, + hdmi_phy->pll_reg + REG_HDMI_8960_PHY_PLL_SDM_CFG0); + else + writel(HDMI_8960_PHY_SDM_BYP | dc_offset, + hdmi_phy->pll_reg + REG_HDMI_8960_PHY_PLL_SDM_CFG0); + + writel(HDMI_8960_PHY_DITHER | dc_offset, + hdmi_phy->pll_reg + REG_HDMI_8960_PHY_PLL_SDM_CFG1); + + write24(sdm_freq_seed, hdmi_phy->pll_reg + REG_HDMI_8960_PHY_PLL_SDM_CFG2= ); + + write16(vco_freq / 1000, hdmi_phy->pll_reg + REG_HDMI_8960_PHY_PLL_VCOCAL= _CFG0); + + writel(0x3b, hdmi_phy->pll_reg + REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2); + + return 0; +} + static const unsigned int qcom_hdmi_8960_divs[] =3D {1, 2, 4, 6}; =20 static unsigned long qcom_hdmi_8960_pll_recalc_rate(struct clk_hw *hw, @@ -423,9 +282,10 @@ static unsigned long qcom_hdmi_8960_pll_recalc_rate(st= ruct clk_hw *hw, static int qcom_hdmi_8960_pll_determine_rate(struct clk_hw *hw, struct clk_rate_request *req) { - const struct pll_rate *pll_rate =3D qcom_hdmi_8960_pll_find_rate(req->rat= e); + unsigned long long min_freq =3D HDMI_8960_VCO_MIN_FREQ / HDMI_8960_COMMON= _DIV; + unsigned long long max_freq =3D HDMI_8960_VCO_MAX_FREQ / HDMI_8960_COMMON= _DIV; =20 - req->rate =3D pll_rate->rate; + req->rate =3D clamp(req->rate, min_freq / 6, max_freq); =20 return 0; } @@ -510,16 +370,39 @@ static int qcom_hdmi_msm8960_phy_pll_enable(struct qc= om_hdmi_preqmp_phy *hdmi_ph return ret; } =20 +static int qcom_hdmi_msm8960_phy_find_div(unsigned long long pixclk) +{ + unsigned long long min_freq =3D HDMI_8960_VCO_MIN_FREQ / HDMI_8960_COMMON= _DIV; + int i; + + if (pixclk > HDMI_8960_VCO_MAX_FREQ / HDMI_8960_COMMON_DIV) + return -E2BIG; + + for (i =3D 0; i < ARRAY_SIZE(qcom_hdmi_8960_divs); i++) { + if (pixclk >=3D min_freq / qcom_hdmi_8960_divs[i]) + return i; + } + + return -EINVAL; +} + static int qcom_hdmi_msm8960_phy_set_rate(struct qcom_hdmi_preqmp_phy *hdm= i_phy) { unsigned long long pixclk =3D hdmi_phy->hdmi_opts.tmds_char_rate; - const struct pll_rate *pll_rate =3D qcom_hdmi_8960_pll_find_rate(pixclk); - int i; + /* XXX: 19.2 for qcs404 */ + unsigned long parent_rate =3D 27000000; + unsigned long vco_freq; + int div_idx; + u32 div; =20 - for (i =3D 0; i < pll_rate->num_reg; i++) - writel(pll_rate->conf[i].val, hdmi_phy->pll_reg + pll_rate->conf[i].reg); + div_idx =3D qcom_hdmi_msm8960_phy_find_div(pixclk); + if (WARN_ON(div_idx < 0)) + return div_idx; =20 - return 0; + div =3D qcom_hdmi_8960_divs[div_idx]; + vco_freq =3D pixclk * HDMI_8960_COMMON_DIV * div; + + return qcom_28lpm_set_rate(hdmi_phy, parent_rate, vco_freq, div_idx); } =20 static void qcom_hdmi_msm8960_phy_pll_disable(struct qcom_hdmi_preqmp_phy = *hdmi_phy) --=20 2.47.3 From nobody Thu Jun 11 09:32:31 2026 Received: from mx0a-0031df01.pphosted.com (mx0a-0031df01.pphosted.com [205.220.168.131]) (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 A1A1C4E3765 for ; Wed, 13 May 2026 18:14:14 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=205.220.168.131 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778696056; cv=none; b=OdLKIx+GheX56Po3boTF4yVxxBINW4X7LuyW9xIZutlYyLoBXVfICHCseb0/V4BWDuAV66SLClWSvazvJ8R3qvNSdJlreujXdD8ho0FeBC76bWAlMqK3SON4rVXXyy6JC22kENyXHAci5j10Iwujm2cjzBVvA1FSJijNDfoBpfg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778696056; c=relaxed/simple; bh=IoIExoNsCI7F0rJKyOfjFp9IzVsJ0t/UC6Pro/GQZyc=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=AfAOeugFtAHGP5d8wG1u6TK46SiQFR0CKnRLM8tKNGb0OqvOfugDsJGDAVD5XncL7dfwQXmNcSj4L0x4Ru25ZfgNwgpMo1BAsYI8Xwu108d8kH7Ko+saHj5jhUsdGMIp8/wgAFcfLLO9t2wOZScmNsqP5dnLQGbYqgaU5kAXByw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=oss.qualcomm.com; spf=pass smtp.mailfrom=oss.qualcomm.com; dkim=pass (2048-bit key) header.d=qualcomm.com header.i=@qualcomm.com header.b=OGuYv31N; dkim=pass (2048-bit key) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com header.b=YgdVtD0c; arc=none smtp.client-ip=205.220.168.131 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=oss.qualcomm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=oss.qualcomm.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=qualcomm.com header.i=@qualcomm.com header.b="OGuYv31N"; dkim=pass (2048-bit key) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com header.b="YgdVtD0c" Received: from pps.filterd (m0279867.ppops.net [127.0.0.1]) by mx0a-0031df01.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 64DEgDkt2888326 for ; Wed, 13 May 2026 18:14:14 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=qualcomm.com; h= cc:content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=qcppdkim1; bh= /zVPSIIUWKZIXl9Pgp6/Eie1lp8Tnk+2GrtmbNvXeno=; b=OGuYv31NAgMi70jX sb07jsqMpvjddqFhCaI9Lsi1KVHPbuyo0+LDz1E1EHLTOnAHNjd5I4c5lRv2rmCT SmspIkjRIcAmqDZlHVl13K8sF63vRDPXnAao2YmtSrvz57BR1FkWjo6tMLcewSfr v/5DP46+gKZhb26zBSNP/SHAzo/DZM/vGr3OzA52gm1OBUHWVCfuRpjfVYZDqCMS LeRuHfRdDVcyMlFksMhlWB0G/hVX/9BEBxaxlYVSYtzsbmPeuMB5XKiP27UT/M57 mB6xoHXYYWchvzNn3w5/zwyEFZ6vFvhBIlFrUUhUrpzCgdf41pqlsz+a7kFGZJu3 V2Af6g== Received: from mail-vs1-f69.google.com (mail-vs1-f69.google.com [209.85.217.69]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 4e4p4gj8jp-1 (version=TLSv1.3 cipher=TLS_AES_128_GCM_SHA256 bits=128 verify=NOT) for ; Wed, 13 May 2026 18:14:13 +0000 (GMT) Received: by mail-vs1-f69.google.com with SMTP id ada2fe7eead31-6374098885eso2187723137.3 for ; Wed, 13 May 2026 11:14:13 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oss.qualcomm.com; s=google; t=1778696053; x=1779300853; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=/zVPSIIUWKZIXl9Pgp6/Eie1lp8Tnk+2GrtmbNvXeno=; b=YgdVtD0corv04eW7SxtS0R2KLwpYXbxSp5jYqJSHNBlsSpQtX0oBRGY720Y5/2IY6P HVZ7mU7g5SwniVs8pagPFKTeO01xsMaMQI3Z/tEkKJTjsVBPms1/GgPsGkKJab/qVYqA ewFKfVl2SKX6kglMiiSuIf++I2eQjYQ5kQrpDtXWOg34Y/De+BY8nhACqn4OTk7N9U6h WWgOHAI8FkbVefAyyeNtSZXhGGm4VDexUK96wnAQyGwxF+itEzypsmbRctc0k+uMLvUI +PDCBId62/lA7zFDv2PNoDQEPLUP2yDVjTP3TEIxUmf19tJQ+pk8CoWy0EgcA7FtULIw soOw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1778696053; x=1779300853; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-gg:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to; bh=/zVPSIIUWKZIXl9Pgp6/Eie1lp8Tnk+2GrtmbNvXeno=; b=iII9ipsGYyE9vtFUzf39V8Ul6SFn67BV/TVQ2Ksr/f304QlHDW3uZ+wyLjvsViIaCc 6ZbEqYjNh3PY4sQHS+L+KrfBm1dKxqSdT5bWgTp8AJ+/YZFOmUdV3k7yn1/zowI0CNAq PH3mGQNH4meqgvCeHMJfwT1CDiTiR3sdPMPMaT4K+VnniAgBQ7NQg7iO4OdeDpidyOrh lrSfziVEB4/HayBYQ+dBR9oK4Oii9kG+rZD8iktCyNVPvtsiiy7bB0JigHAlA1Pw0aSc MgxrKLHbtGelkZp9glCru782B73E76655U6oIpeYgaN1mkn+DCXwsHQZqLW14GR/yWHx K8aw== X-Gm-Message-State: AOJu0YyIH3kbEsMU1D5AJweeRua1y1A8OyFroYeUDdR9k8xy3jQK9cqV wWSp2lS8SSjuDitnzQ6WmJ/wOIQRctjBUdVkZT5VJcalfs0nIWeJA7fQIZC6GYYRdhmSdlS1XBV phGTBa1tMP49DvSGUHeOVRfLxlDj0fVPsR1iy5eGpwuV91AbjC6T2FfW2+J72F8LbE3Y= X-Gm-Gg: Acq92OGwv22XkEvCDHjHgu8vkoGX6OaYWpAQDH9URRbqHATHYuu1RhrE4Hs2TKWDDup Ba2Kqzt6LcWs4olThw8z4cnAt5+OJEPhWoSSEt0hZ0+qyYRxbAji10HGtWzeFLd+J/X7Pq91eyb 1B5K2iss1rO6DGdWbcPOpIcafzgyon9aN3e5J4WEz3Lm1AhE1Tcq/Pn8t+U5EXR/R9QYcPNy3We uAtEqKEV1gSR8Nb04e5oULU9nLlyuPf5xEgEM+T/opgJi9MGF/+ItEVg/DDvfKFivdWby4AeiSB AFdJaU/iBMYlRjSTCFU+fLpzMEzVuGXtGoCrl4dUkikVOPG1BIaDdOljNHmbKTuaoYV91XJo2sw LTTGGvGBuciAeebTdaftFjShDJY71ZVUly5uWw9RdKIgbgKb0xLSTUMtcwcV9uy0ewLG1aDTLnG ZsDmQUASmvIj7H+Jb8VfnHV6dg3xp5Dwza0xA= X-Received: by 2002:a05:6102:3581:b0:631:4e9a:ba3 with SMTP id ada2fe7eead31-63775d35309mr2383198137.21.1778696052980; Wed, 13 May 2026 11:14:12 -0700 (PDT) X-Received: by 2002:a05:6102:3581:b0:631:4e9a:ba3 with SMTP id ada2fe7eead31-63775d35309mr2383166137.21.1778696052465; Wed, 13 May 2026 11:14:12 -0700 (PDT) Received: from umbar.lan (2001-14ba-a073-af00-264b-feff-fe8b-be8a.rev.dnainternet.fi. [2001:14ba:a073:af00:264b:feff:fe8b:be8a]) by smtp.gmail.com with ESMTPSA id 2adb3069b0e04-5a8bd7d8974sm3174770e87.64.2026.05.13.11.14.11 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 13 May 2026 11:14:11 -0700 (PDT) From: Dmitry Baryshkov Date: Wed, 13 May 2026 21:14:06 +0300 Subject: [PATCH v9 3/5] phy: qcom: apq8064-sata: extract UNI PLL register defines 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: <20260513-fd-hdmi-phy-v9-3-ca98c72f1f9f@oss.qualcomm.com> References: <20260513-fd-hdmi-phy-v9-0-ca98c72f1f9f@oss.qualcomm.com> In-Reply-To: <20260513-fd-hdmi-phy-v9-0-ca98c72f1f9f@oss.qualcomm.com> To: Rob Clark , Dmitry Baryshkov , Abhinav Kumar , Jessica Zhang , Sean Paul , Marijn Suijten , David Airlie , Simona Vetter , Vinod Koul , Neil Armstrong Cc: linux-kernel@vger.kernel.org, linux-arm-msm@vger.kernel.org, dri-devel@lists.freedesktop.org, freedreno@lists.freedesktop.org, linux-phy@lists.infradead.org, Dmitry Baryshkov X-Mailer: b4 0.15.1 X-Developer-Signature: v=1; a=openpgp-sha256; l=3408; i=dmitry.baryshkov@oss.qualcomm.com; h=from:subject:message-id; bh=HsnaYsV5sY0OkAw5eu/o4daj/nHtfAshF8JWidON18Q=; b=owEBbQGS/pANAwAKAYs8ij4CKSjVAcsmYgBqBL9tjLrY83UXLmEunVYGYLAM+Hg0YNzJYpfrq 96k9e4FlDeJATMEAAEKAB0WIQRMcISVXLJjVvC4lX+LPIo+Aiko1QUCagS/bQAKCRCLPIo+Aiko 1VZzB/9B2E/N1NfXzdEpQOpWpJYaqJ4JY4cFaruTvIQuvIIOydYHm/rnl4TPJ+Dzk0xu/XU3C4h kgKr8ffT+PaJ2nzpHU8ccDCD+GVLpY1N6+UhPNRcLQ0DLgSG/9kMZXe1G80EGO4+gAOjaMEhP3I Zo1w635FY2rocR/XSEOL26z9fv68ZtKLRKQQ2QBfwqnQbGO7y/mtKRsECKPdiSF7kJLXBfQi1lU yCz5JUFTY+s6XL/VHZUk5S+4CZ9VD6kqhjXKFwWNBXmjORys4v87YpGQxsPceXilHESDLF9BdMP ob7h0vrDH5CXPlsNO5fzEnWbqwbpnUn8u90DPvj5SzPxgdxQ X-Developer-Key: i=dmitry.baryshkov@oss.qualcomm.com; a=openpgp; fpr=8F88381DD5C873E4AE487DA5199BF1243632046A X-Proofpoint-GUID: C_VN3k9z9Ip46YEY52nsAgtSHNjPEwBg X-Authority-Analysis: v=2.4 cv=DOS/JSNb c=1 sm=1 tr=0 ts=6a04bf75 cx=c_pps a=5HAIKLe1ejAbszaTRHs9Ug==:117 a=xqWC_Br6kY4A:10 a=IkcTkHD0fZMA:10 a=NGcC8JguVDcA:10 a=s4-Qcg_JpJYA:10 a=VkNPw1HP01LnGYTKEx00:22 a=u7WPNUs3qKkmUXheDGA7:22 a=eoimf2acIAo5FJnRuUoq:22 a=KKAkSRfTAAAA:8 a=EUspDBNiAAAA:8 a=_xNQ4P_HJxdd5osA_owA:9 a=QEXdDO2ut3YA:10 a=gYDTvv6II1OnSo0itH1n:22 a=cvBusfyB2V15izCimMoJ:22 X-Proofpoint-ORIG-GUID: C_VN3k9z9Ip46YEY52nsAgtSHNjPEwBg X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwNTEzMDE4MiBTYWx0ZWRfX1zCJUsA8kEK4 /TMyXihEryds2G/1oiSUV9pK4l6MjBcuO8NJAJ0tMIRINt90Gmav4EMTAt6DpDs4Ty3Q9OTL8bS 9xHMgGnGdEStHrI5t8VLKXueD5FKXvykioGvEd1JDrZtJYA2+8+POFyOxcM6ukgHpArRIG2nLlc FeVy/9rJBJ8hnY5bZGlA6J9aH9avpSoaSHqY/zbqlsDoMus+EueXSJu09B0M1tnZR6zmSRL9WzR RqGHtAsaywHl9+qi1W9u51YxrI6qk+X5b4uNubjm9Ph3EQ7Jf2FvCy6I0jb75pYUruQ2nuSERcc KEgUy5R82vSIr3GdMbu1FmJjA31jklwpQm+d7kjmkSANko/xSnrwZqNm2CYZ0xQKm8zkFLiUbBc 2MEtr1e83pZt1D843ZP5F6QzVAsqMDlVDBlz5SRu0HqC/K4WcIcj3+J6IWUp1ivlfMVZktQAKl/ sECX3qFIeJ7TgRk9F1A== X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1143,Hydra:6.1.51,FMLib:17.12.100.49 definitions=2026-05-13_02,2026-05-13_01,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 malwarescore=0 adultscore=0 impostorscore=0 bulkscore=0 clxscore=1015 priorityscore=1501 phishscore=0 suspectscore=0 lowpriorityscore=0 spamscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.22.0-2605050000 definitions=main-2605130182 From: Dmitry Baryshkov The "uni" PLL is shared between several PHYS: APQ8064's SATA, MSM8974/APQ8084 HDMI, MSM8916 DSI, MSM8974/APQ8084 DSI. Extract the common register names to a separate header with the hope of later having the common code to handle PLL in those PHYs. Signed-off-by: Dmitry Baryshkov Reviewed-by: Neil Armstrong Signed-off-by: Dmitry Baryshkov --- drivers/phy/qualcomm/phy-qcom-apq8064-sata.c | 24 +------------------- drivers/phy/qualcomm/phy-qcom-uniphy.h | 33 ++++++++++++++++++++++++= ++++ 2 files changed, 34 insertions(+), 23 deletions(-) diff --git a/drivers/phy/qualcomm/phy-qcom-apq8064-sata.c b/drivers/phy/qua= lcomm/phy-qcom-apq8064-sata.c index cae290a6e19f..52f180e0cfb4 100644 --- a/drivers/phy/qualcomm/phy-qcom-apq8064-sata.c +++ b/drivers/phy/qualcomm/phy-qcom-apq8064-sata.c @@ -15,28 +15,7 @@ #include #include =20 -/* PHY registers */ -#define UNIPHY_PLL_REFCLK_CFG 0x000 -#define UNIPHY_PLL_PWRGEN_CFG 0x014 -#define UNIPHY_PLL_GLB_CFG 0x020 -#define UNIPHY_PLL_SDM_CFG0 0x038 -#define UNIPHY_PLL_SDM_CFG1 0x03C -#define UNIPHY_PLL_SDM_CFG2 0x040 -#define UNIPHY_PLL_SDM_CFG3 0x044 -#define UNIPHY_PLL_SDM_CFG4 0x048 -#define UNIPHY_PLL_SSC_CFG0 0x04C -#define UNIPHY_PLL_SSC_CFG1 0x050 -#define UNIPHY_PLL_SSC_CFG2 0x054 -#define UNIPHY_PLL_SSC_CFG3 0x058 -#define UNIPHY_PLL_LKDET_CFG0 0x05C -#define UNIPHY_PLL_LKDET_CFG1 0x060 -#define UNIPHY_PLL_LKDET_CFG2 0x064 -#define UNIPHY_PLL_CAL_CFG0 0x06C -#define UNIPHY_PLL_CAL_CFG8 0x08C -#define UNIPHY_PLL_CAL_CFG9 0x090 -#define UNIPHY_PLL_CAL_CFG10 0x094 -#define UNIPHY_PLL_CAL_CFG11 0x098 -#define UNIPHY_PLL_STATUS 0x0C0 +#include "phy-qcom-uniphy.h" =20 #define SATA_PHY_SER_CTRL 0x100 #define SATA_PHY_TX_DRIV_CTRL0 0x104 @@ -58,7 +37,6 @@ #define SATA_PHY_TX_IMCAL_STAT 0x1E4 #define SATA_PHY_RX_IMCAL_STAT 0x1E8 =20 -#define UNIPHY_PLL_LOCK BIT(0) #define SATA_PHY_TX_CAL BIT(0) #define SATA_PHY_RX_CAL BIT(0) =20 diff --git a/drivers/phy/qualcomm/phy-qcom-uniphy.h b/drivers/phy/qualcomm/= phy-qcom-uniphy.h new file mode 100644 index 000000000000..5f18f9593cda --- /dev/null +++ b/drivers/phy/qualcomm/phy-qcom-uniphy.h @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2014, The Linux Foundation. All rights reserved. + */ + +#ifndef PHY_QCOM_UNIPHY_H +#define PHY_QCOM_UNIPHY_H + +/* PHY registers */ +#define UNIPHY_PLL_REFCLK_CFG 0x000 +#define UNIPHY_PLL_PWRGEN_CFG 0x014 +#define UNIPHY_PLL_GLB_CFG 0x020 +#define UNIPHY_PLL_SDM_CFG0 0x038 +#define UNIPHY_PLL_SDM_CFG1 0x03c +#define UNIPHY_PLL_SDM_CFG2 0x040 +#define UNIPHY_PLL_SDM_CFG3 0x044 +#define UNIPHY_PLL_SDM_CFG4 0x048 +#define UNIPHY_PLL_SSC_CFG0 0x04c +#define UNIPHY_PLL_SSC_CFG1 0x050 +#define UNIPHY_PLL_SSC_CFG2 0x054 +#define UNIPHY_PLL_SSC_CFG3 0x058 +#define UNIPHY_PLL_LKDET_CFG0 0x05c +#define UNIPHY_PLL_LKDET_CFG1 0x060 +#define UNIPHY_PLL_LKDET_CFG2 0x064 +#define UNIPHY_PLL_CAL_CFG0 0x06c +#define UNIPHY_PLL_CAL_CFG8 0x08c +#define UNIPHY_PLL_CAL_CFG9 0x090 +#define UNIPHY_PLL_CAL_CFG10 0x094 +#define UNIPHY_PLL_CAL_CFG11 0x098 +#define UNIPHY_PLL_STATUS 0x0c0 +#define UNIPHY_PLL_LOCK BIT(0) + +#endif --=20 2.47.3 From nobody Thu Jun 11 09:32:31 2026 Received: from mx0b-0031df01.pphosted.com (mx0b-0031df01.pphosted.com [205.220.180.131]) (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 995054C6EF0 for ; Wed, 13 May 2026 18:14:16 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=205.220.180.131 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778696058; cv=none; b=dQoiMoBSPmkl3s44H88VdMQ9K8SGN7Qt3QRupUrOFlQAkEYBR7l+iv+Tr2/w9aCZYyBDeh+lhT2kk8Qs8vGDdNScSnv3eh61KFFWhiicK+2O7bPcWGAbeTNQXBbx9RdwKnEOO6ZEF4salAQVz5QPetpxHk5VWpXw+d8QOb92m5Q= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778696058; c=relaxed/simple; bh=utaWKPqMFCAQ6A3D9lUtcp1dz1XaesiuCD80PEH5ikM=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=COl1AaE6HEbGPhZDG1Icm5FecCj0w8MTU8BxcvQ10eUjNvgfErvV2UQm2vkthFW/GasKkHeKsfexBMmjnDdqou/cBPmmwrUTw9dfAipBvFs3GGIHiqFrIl5RqPKlDTPshbEBxdkxpvw/sQcLX8vEyWUD4l8bL/WyRiy1Uh16vSA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=oss.qualcomm.com; spf=pass smtp.mailfrom=oss.qualcomm.com; dkim=pass (2048-bit key) header.d=qualcomm.com header.i=@qualcomm.com header.b=HdpOtto+; dkim=pass (2048-bit key) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com header.b=OUyY7Sfn; arc=none smtp.client-ip=205.220.180.131 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=oss.qualcomm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=oss.qualcomm.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=qualcomm.com header.i=@qualcomm.com header.b="HdpOtto+"; dkim=pass (2048-bit key) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com header.b="OUyY7Sfn" Received: from pps.filterd (m0279870.ppops.net [127.0.0.1]) by mx0a-0031df01.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 64DGvEFV3997611 for ; Wed, 13 May 2026 18:14:15 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=qualcomm.com; h= cc:content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=qcppdkim1; bh= /rxOjF0YX/LqRk0erNH1VM1reWsG38dZ2KsYX/zC7SQ=; b=HdpOtto+23WHnld5 m9XsZSf8vjqIqTFx8IKn6RUtD7/lsk+4EKewrWV6rnrS7L1hI2vSiygETvsvEngB MlR9inW+DbF7P+L5pldV147XYKVHXEJQPLscb60CDKVozMPwk/72DZ4rMNipITRD gqJubpp85cAnD1FnvAWVm018jiVRJDNdwq/701YVPr3B6ezbb+VlMdhw1B7GV20K 32N1kSE47y25NB0KPnmOORDanknYymTFonQ0VMCk7l/aal5lbLw545PxL+WNYFKk wzIbgR/ILhzLPQAl6Glv38U3cs5eBNATc+y/Vu9lvc4i0U6gl7x9AuKkMlIVDxUY nr3J9g== Received: from mail-ua1-f70.google.com (mail-ua1-f70.google.com [209.85.222.70]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 4e4w8ur9y7-1 (version=TLSv1.3 cipher=TLS_AES_128_GCM_SHA256 bits=128 verify=NOT) for ; Wed, 13 May 2026 18:14:15 +0000 (GMT) Received: by mail-ua1-f70.google.com with SMTP id a1e0cc1a2514c-95f5daf2d5bso4773685241.1 for ; Wed, 13 May 2026 11:14:15 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oss.qualcomm.com; s=google; t=1778696055; x=1779300855; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=/rxOjF0YX/LqRk0erNH1VM1reWsG38dZ2KsYX/zC7SQ=; b=OUyY7Sfnq53MD+agSnijVGHXPtxyXLJc/8sV3uhV84hmvarUi7+HsYfk81iTJ3AuxK 9+VWlzjqX9Eic+1Jr7mrMMF0aduFxGzNmh4KTf79CPEU5qOr6gGsI2HtvMzjoYqpHLsu RmcpAfj1HqdOa9WmwQbrOybhb5ZC/v88p29VsPdo6/glaWoq9l+MqU+0fm1m08TMDoR3 EDNu8wsQWPhcPLYRWpQSSZFWjNMoNK072s2eNe5y5BC/ydXLWSpSCyV2w7+wDW06U9eQ hswgVQqsZoZcl7VBgcIcCSndCwREMfO24k0doyH1VmhE9ppWszY4+7uvKFFnmihJUKtP 4LVQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1778696055; x=1779300855; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-gg:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to; bh=/rxOjF0YX/LqRk0erNH1VM1reWsG38dZ2KsYX/zC7SQ=; b=iZdVYXNe2xwg381lesut8NKHiw2Zn9zxDpkKePH9I50gqSr3hl0Ll8AloMHcfF4aVx XC+Z8fziFf5OjbRMt1Xab5jc+XQJfzoP3e2prdap0tHEvhhK/kwgY/KnXCdQRBwk+iAK d/nEb7LgbFK7g9Ol4gZoZ764FHNuqjJLR3+OfjugNJj673bq0DC1Uv2vInn0uW75bHm8 gzFuKWFD41N2bDK5gSOXGnfvfQZmr396SNAZZGcdUogpxulFHugbAbnaT7rFWWT42V0P tA0lrpatlPc4djgLAja58P8wOAVHuZoaDBECzciU3mJ9Htq6axNJWAggbGO4pEb216J5 aD+Q== X-Gm-Message-State: AOJu0YyudIJheigA/4o0nCcYJIJWYhtAke/kyDxvBUa29bKcC+65h8yb 5feQob55FN3Rk5wxF1YJYiqyziOEYGLYE+617fwaqbjR8ypJxw+MbLqOn19pAPkVktjTi0ReGFw TmWRDRuqRwgwUgQDEBa8RbuDHY8s8G1ez28/WnPC3YT1hxzf2Zub4fPnc1pW+c7Tr2Yc= X-Gm-Gg: Acq92OEIfnXEgit7u1RVZQi9gcPdnwABktBdzVhWRp9iPvy2muIZEhGi9O2KDrUSJLh 0YsUI+PwqSekQB0I6HUO5dE2iP52xEMFEP4mNfxGVA23cQbIt7/Zvf67S//4r796KcPUL14iUKy P42gO7c9Jmh2YYAAVpowHok4CEE1omZqHQuwZn41iiLdzgxjNMwyVupc4hxap2ygnLMf8M8I/On ou0nly++qHEvs4MSZmuPNopiuvf0OSMFF3bBJLI2B5ytGcAwVcac/zWEqHnr++SFY9Ox7iyMqHu ptHbDb+KTr0O7u/S4KYvyDkqMa/8eJB5e1SnZd43+MDFDWeVrnnpnSJLkJzyp/yGcviimqQ5Qx2 uVfPbMFNfCu8BPckvqIXR3SXDLUMNmWXdQySQMILLAh1ZRySCrqm/ptIuuaxz42GHJC0QmpX5Lw H5aAO6/8WZOi8BKpGLIh+Wnv+tksIGCGNDsBA= X-Received: by 2002:a05:6102:3e0b:b0:637:ad7:f57 with SMTP id ada2fe7eead31-637aaa5a6f5mr2136048137.25.1778696054980; Wed, 13 May 2026 11:14:14 -0700 (PDT) X-Received: by 2002:a05:6102:3e0b:b0:637:ad7:f57 with SMTP id ada2fe7eead31-637aaa5a6f5mr2136024137.25.1778696054522; Wed, 13 May 2026 11:14:14 -0700 (PDT) Received: from umbar.lan (2001-14ba-a073-af00-264b-feff-fe8b-be8a.rev.dnainternet.fi. [2001:14ba:a073:af00:264b:feff:fe8b:be8a]) by smtp.gmail.com with ESMTPSA id 2adb3069b0e04-5a8bd7d8974sm3174770e87.64.2026.05.13.11.14.12 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 13 May 2026 11:14:12 -0700 (PDT) From: Dmitry Baryshkov Date: Wed, 13 May 2026 21:14:07 +0300 Subject: [PATCH v9 4/5] phy: qcom-uniphy: add more registers from display PHYs 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: <20260513-fd-hdmi-phy-v9-4-ca98c72f1f9f@oss.qualcomm.com> References: <20260513-fd-hdmi-phy-v9-0-ca98c72f1f9f@oss.qualcomm.com> In-Reply-To: <20260513-fd-hdmi-phy-v9-0-ca98c72f1f9f@oss.qualcomm.com> To: Rob Clark , Dmitry Baryshkov , Abhinav Kumar , Jessica Zhang , Sean Paul , Marijn Suijten , David Airlie , Simona Vetter , Vinod Koul , Neil Armstrong Cc: linux-kernel@vger.kernel.org, linux-arm-msm@vger.kernel.org, dri-devel@lists.freedesktop.org, freedreno@lists.freedesktop.org, linux-phy@lists.infradead.org, Dmitry Baryshkov X-Mailer: b4 0.15.1 X-Developer-Signature: v=1; a=openpgp-sha256; l=2924; i=dmitry.baryshkov@oss.qualcomm.com; h=from:subject:message-id; bh=zXUnJKheGLXFIh2NeGjJnci3b8qeGjvnWTuieLLb4mc=; b=owEBbQGS/pANAwAKAYs8ij4CKSjVAcsmYgBqBL9t68jSUNFaly1KX3iQ5b/7/WNJg90DoXXSF URoUFQz3aeJATMEAAEKAB0WIQRMcISVXLJjVvC4lX+LPIo+Aiko1QUCagS/bQAKCRCLPIo+Aiko 1XUfB/wIlFw2c2IYwvDoS2FUSiaPjh3z/fuDn6ICL4Z65bKcyRXkqDKfFscu81X085BbcVczwkG kqiPpIT6gYmKtUbpCWMcpxMDhYNoE1WJEsoHg0S1piUbeqJBMSPMFfUZ6Irt9QaaG7i202FYTBU pcncuJXwDLEajYKKk7GNdK59AJM3sxwWaGzfpV76nZtBxz+BTyrSmhKr7rQ+FBe00+cRsPyu8mh mUkZOSBrAIjAUDzsjIr0S5mYaSBBrmTv+T/cjOiGqTbi+mJeXwY6LTQxxtT92n4xrVdU+HX6A9p leqYJo7jpCehRzYwoyxal9cQ8KwoBxEoWKpiIeR90o6AqMX4 X-Developer-Key: i=dmitry.baryshkov@oss.qualcomm.com; a=openpgp; fpr=8F88381DD5C873E4AE487DA5199BF1243632046A X-Authority-Analysis: v=2.4 cv=WP1PmHsR c=1 sm=1 tr=0 ts=6a04bf77 cx=c_pps a=R6oCqFB+Yf/t2GF8e0/dFg==:117 a=xqWC_Br6kY4A:10 a=IkcTkHD0fZMA:10 a=NGcC8JguVDcA:10 a=s4-Qcg_JpJYA:10 a=VkNPw1HP01LnGYTKEx00:22 a=u7WPNUs3qKkmUXheDGA7:22 a=gowsoOTTUOVcmtlkKump:22 a=KKAkSRfTAAAA:8 a=EUspDBNiAAAA:8 a=NWzoLV28igjY6Ppe7YgA:9 a=QEXdDO2ut3YA:10 a=TD8TdBvy0hsOASGTdmB-:22 a=cvBusfyB2V15izCimMoJ:22 X-Proofpoint-GUID: Q4HEfcK7MEUZ2U9KxDL_tVDdg8cE1YpC X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwNTEzMDE4MiBTYWx0ZWRfX1Nzm8ZO9l8+s ihkBQ2P/oe9wU8gX6rsKY2UnbRiJZZ+wjyt4KQCXQqWGv9hm9l/j1TN06jm9O/CArT1hv3gctLz g6iw75v4U2PtCiq/Njq09TOzDSsYnab6hzO82CiutxeBEoX2rM25IZ+tAv6PfNa1WhAnHdXFabi 5nZzk2Mo1yFC8lV2pgGIRnfMEmvyaEK/xNNawE5y6PPYTTH/tH/I23MuvWNzKrEC4O+FsRuGZeR 5s1s1ECk2JKINq8IlLr2XIwrb1RLc6YCabUfcL2N/9I5qwAvpQh9+gBvx26DzwhCd/UUErg+fMo mqTjAD/Iz/qc1mhAE5Bo0mPReMxghNtNrhqv31oV+dcKK1FKWWy+vpXMOkbMycD7FlbAf9vY747 p3QgBXaBvU58BHcEkgZoVhcYPd9A5r6D2XesaFG0KRzxF2+P9Iv9M/ylX/VFDa26r21mOv2ozCo JfPaiqH4gFkS7V91B1Q== X-Proofpoint-ORIG-GUID: Q4HEfcK7MEUZ2U9KxDL_tVDdg8cE1YpC X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1143,Hydra:6.1.51,FMLib:17.12.100.49 definitions=2026-05-13_02,2026-05-13_01,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 lowpriorityscore=0 priorityscore=1501 clxscore=1015 malwarescore=0 bulkscore=0 spamscore=0 impostorscore=0 suspectscore=0 adultscore=0 phishscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.22.0-2605050000 definitions=main-2605130182 From: Dmitry Baryshkov Import register definitions from 28nm DSI and HDMI PHYs, adding more UNI PHY registers. Signed-off-by: Dmitry Baryshkov Reviewed-by: Neil Armstrong Signed-off-by: Dmitry Baryshkov --- drivers/phy/qualcomm/phy-qcom-uniphy.h | 43 ++++++++++++++++++++++++++++++= ++++ 1 file changed, 43 insertions(+) diff --git a/drivers/phy/qualcomm/phy-qcom-uniphy.h b/drivers/phy/qualcomm/= phy-qcom-uniphy.h index 5f18f9593cda..e02bcc5e8150 100644 --- a/drivers/phy/qualcomm/phy-qcom-uniphy.h +++ b/drivers/phy/qualcomm/phy-qcom-uniphy.h @@ -8,10 +8,30 @@ =20 /* PHY registers */ #define UNIPHY_PLL_REFCLK_CFG 0x000 +#define UNIPHY_PLL_REFCLK_DBLR BIT(0) +#define UNIPHY_PLL_REFCLK_DIV GENMASK(3, 2) + +#define UNIPHY_PLL_POSTDIV1_CFG 0x004 +#define UNIPHY_PLL_CHGPUMP_CFG 0x008 +#define UNIPHY_PLL_VCOLPF_CFG 0x00c +#define UNIPHY_PLL_VREG_CFG 0x010 #define UNIPHY_PLL_PWRGEN_CFG 0x014 +#define UNIPHY_PLL_DMUX_CFG 0x018 +#define UNIPHY_PLL_AMUX_CFG 0x01c #define UNIPHY_PLL_GLB_CFG 0x020 +#define UNIPHY_PLL_POSTDIV2_CFG 0x024 +#define UNIPHY_PLL_POSTDIV3_CFG 0x028 +#define UNIPHY_PLL_LPFR_CFG 0x02c +#define UNIPHY_PLL_LPFC1_CFG 0x030 +#define UNIPHY_PLL_LPFC2_CFG 0x034 #define UNIPHY_PLL_SDM_CFG0 0x038 +#define UNIPHY_PLL_SDM_BYP BIT(6) +#define UNIPHY_PLL_SDM_BYP_DIV GENMASK(5, 0) + #define UNIPHY_PLL_SDM_CFG1 0x03c +#define UNIPHY_PLL_SDM_DITHER_EN BIT(6) +#define UNIPHY_PLL_SDM_DC_OFFSET GENMASK(5, 0) + #define UNIPHY_PLL_SDM_CFG2 0x040 #define UNIPHY_PLL_SDM_CFG3 0x044 #define UNIPHY_PLL_SDM_CFG4 0x048 @@ -22,12 +42,35 @@ #define UNIPHY_PLL_LKDET_CFG0 0x05c #define UNIPHY_PLL_LKDET_CFG1 0x060 #define UNIPHY_PLL_LKDET_CFG2 0x064 +#define UNIPHY_PLL_TEST_CFG 0x068 #define UNIPHY_PLL_CAL_CFG0 0x06c +#define UNIPHY_PLL_CAL_CFG1 0x070 +#define UNIPHY_PLL_CAL_CFG2 0x074 +#define UNIPHY_PLL_CAL_CFG3 0x078 +#define UNIPHY_PLL_CAL_CFG4 0x07c +#define UNIPHY_PLL_CAL_CFG5 0x080 +#define UNIPHY_PLL_CAL_CFG6 0x084 +#define UNIPHY_PLL_CAL_CFG7 0x088 #define UNIPHY_PLL_CAL_CFG8 0x08c #define UNIPHY_PLL_CAL_CFG9 0x090 #define UNIPHY_PLL_CAL_CFG10 0x094 #define UNIPHY_PLL_CAL_CFG11 0x098 +#define UNIPHY_PLL_EFUSE_CFG 0x09c +#define UNIPHY_PLL_DEBUG_BUS_SEL 0x0a0 +#define UNIPHY_PLL_CTRL_42 0x0a4 +#define UNIPHY_PLL_CTRL_43 0x0a8 +#define UNIPHY_PLL_CTRL_44 0x0ac +#define UNIPHY_PLL_CTRL_45 0x0b0 +#define UNIPHY_PLL_CTRL_46 0x0b4 +#define UNIPHY_PLL_CTRL_47 0x0b8 +#define UNIPHY_PLL_CTRL_48 0x0bc #define UNIPHY_PLL_STATUS 0x0c0 #define UNIPHY_PLL_LOCK BIT(0) =20 +#define UNIPHY_PLL_DEBUG_BUS0 0x0c4 +#define UNIPHY_PLL_DEBUG_BUS1 0x0c8 +#define UNIPHY_PLL_DEBUG_BUS2 0x0cc +#define UNIPHY_PLL_DEBUG_BUS3 0x0d0 +#define UNIPHY_PLL_CTRL_54 0x0d4 + #endif --=20 2.47.3 From nobody Thu Jun 11 09:32:31 2026 Received: from mx0a-0031df01.pphosted.com (mx0a-0031df01.pphosted.com [205.220.168.131]) (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 7292C4E3799 for ; Wed, 13 May 2026 18:14:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=205.220.168.131 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778696060; cv=none; b=K+afkmukK2byfST9p+h4BN5Qn53Iw36uCap/E6FJ9Z/XeRt4K22Qb2kM64zGkyvdWhHS/Wcgr2Q91Ip4PGhRsL9y/tDkfYS1wKzBtMd76GY9x6tkeP5x4K+uulpFHULOdO2GNqACmB2ssl4nr8zexx1nfZW/nvM4MU++CV6jRHw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778696060; c=relaxed/simple; bh=fiAxSKr0MiXtgdMoguQGBGHvUIsEFSFdo1fVWLdz2eA=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=NSV/EAUNvQNadpaZSx7YYMg2zwAy+/HOKUjh99OG2LdqQmYzs1NUM4SZfHPBdlrGo0wccYQcvWIQ/YyYoDSSU3+UnInedtciqaf+mrq7ZjYoA035g9hIccCIEY/Q5Xjw+S5VRv4pH4Zu+5H7oHZBFfonnJW0vtqGRyoaAwYYj5I= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=oss.qualcomm.com; spf=pass smtp.mailfrom=oss.qualcomm.com; dkim=pass (2048-bit key) header.d=qualcomm.com header.i=@qualcomm.com header.b=PXb1bli7; dkim=pass (2048-bit key) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com header.b=GZYafzmV; arc=none smtp.client-ip=205.220.168.131 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=oss.qualcomm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=oss.qualcomm.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=qualcomm.com header.i=@qualcomm.com header.b="PXb1bli7"; dkim=pass (2048-bit key) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com header.b="GZYafzmV" Received: from pps.filterd (m0279866.ppops.net [127.0.0.1]) by mx0a-0031df01.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 64DHe7Lc1393359 for ; Wed, 13 May 2026 18:14:18 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=qualcomm.com; h= cc:content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=qcppdkim1; bh= 3o2dYgGq0E5lPn5vU0FBECkmJVwMp6ZZWkBRjZuUung=; b=PXb1bli76W6OLUK6 B/EctDeA7IUNRWW5kS6MN+a8KUVkTnbJIZdRloTzaMnRYwmi935yjV0Op4h8XowJ xRBtPeOIM/IvXV4pvdh2woarzpZtQHmWIw0Lot1ek1FDwlItibqffxrCEqLjrsWV i/dEi6FXTCO/YYgYa6gVnz7rlh7NvEyoNTV9Yb063DxFak8Rs7kcrffse/Jl3cVz RakNe11se/Y+SjLQIkO3DBTVc3K9of2ZHivAI3WCPJE28mZvFabO7ypY5ZB10Q32 tc0bZ4m3eh2qzO/aT90FTjDLQkxRnB+At2R5ES7j3bvlT7+8k5yRPrW50R3rQktG SV28LA== Received: from mail-vs1-f69.google.com (mail-vs1-f69.google.com [209.85.217.69]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 4e4k26312j-1 (version=TLSv1.3 cipher=TLS_AES_128_GCM_SHA256 bits=128 verify=NOT) for ; Wed, 13 May 2026 18:14:17 +0000 (GMT) Received: by mail-vs1-f69.google.com with SMTP id ada2fe7eead31-6322654bb6eso5672604137.3 for ; Wed, 13 May 2026 11:14:17 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oss.qualcomm.com; s=google; t=1778696057; x=1779300857; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=3o2dYgGq0E5lPn5vU0FBECkmJVwMp6ZZWkBRjZuUung=; b=GZYafzmV/LJNwu6Lh0mkTEA12TI7m9eDlMPwQoKIavgAl1Baeh7qRUvbGdG0J4QkwF YqtiqOG0nKbO3H1v1EEZPmHsb2ymNXVjREvTagNg/fapIa/QsTf0NyUdm3AwF7EmXWow gwhLQphnkBz2hK2vQ2vCFJxc7uow8VF8ABx8ekl6+5mJn8KudKWyv0UR4dSrES2/GaCH xNWsrU7weO+Mty29GwWNphieZJ87HK6XKPfHlsHGD0PMg79Lf+lFaUClQoNa0pzNkE7o VGIZizejIKXURqDr/a5qFrzgQ+jHoinSg3j08CCIZOo19bxKmlP5s7b3xThplC5m9dxm uWRw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1778696057; x=1779300857; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-gg:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to; bh=3o2dYgGq0E5lPn5vU0FBECkmJVwMp6ZZWkBRjZuUung=; b=oEQ9yHq0byA1dNBywPfgh7XFj4/vtCYKvkil89m2FvT5a83eKvjkMxQ9gHivF/jEDc kiw3khfrm3otPaigneAcvHE7JvOE83u8zEpZ6a+909WFfg1qEFC7gr1ERksB8yOtNo5S 0U8vMkElGGHVo1GVICtgdNRcRrVNfGSZMqOCNFur3zIfJ6stb4/n0q5Wjd6zgP3Z8biv v4KdyBl/OngJ+KDcpxgYANWmghgTH+ygK40WpDOTuCQ4eP75EVJQwnxc6XMRsletLhII bmeyeBQuxhCNtL5znij14jDPtpkCDcV7Zn+91onCBM87izANqsdu4GzLjO1wxu2vTRyN rWBw== X-Gm-Message-State: AOJu0Yxukhc3DpXOA23eNOetBrEfMbAR7APuLXxPhRbfm9AAfYMd/N96 +TBRAFkvzpHASsiumUZ0rgIjQ8F4vAVzmY67oy2HxTyLYbuiphYVIyJy+P3SZh0V47KjaOOrFBn gAIvUUab4QxLvDFLAKeJf5DCpleLIh2DhmdHk3UHANQ5eJs8KXXPpHvcoMQQHnA7wMlI= X-Gm-Gg: Acq92OF4T4lo9rqqiCgE95ZC4xLoAxbmXpQCLZXYzuUr4CqDapyhC6Pty3MClKsJaV8 CqX3iixJuawusO0VoXTr5qBxWpl8vjajqEPquBlKnKgWG+MwAPRU8TceS1oRVcjHVRt0YEhOTny HCBsVwU5oXPSgynTzv/Ycrze242zT43cs38SCbLhmWjTCXTTt+E5khLjuihXN0Z08dOjySeEeOe LWNt10V26MOOMxfcn0bToUSEf2+0g/fTzkAWlzgIuZdPFTdYO1Lc4/aeUOaVLUmvyd7MU8AzVcY lnT6mWTuT0Bx0XzZ8gggiCq80SK994Mn7SWOQYG8XYMRYiC8rTVrN1kUOZgqxsvcImEOUoAo1be MfT26KWM3VEAiFtV2yf8g4rEYQ/394XpzEfVK6V88Bv5+7iqbbn/e+S8YtjMtuj8oVEVXNPljKN YVNDs1Tr3RJtyHGOhy3FEagvzQGV+R8Dd/4bCnl8ozxEpiuQ== X-Received: by 2002:a67:e703:0:b0:632:78bc:2bdf with SMTP id ada2fe7eead31-637ab388366mr2362458137.31.1778696056660; Wed, 13 May 2026 11:14:16 -0700 (PDT) X-Received: by 2002:a67:e703:0:b0:632:78bc:2bdf with SMTP id ada2fe7eead31-637ab388366mr2362417137.31.1778696056073; Wed, 13 May 2026 11:14:16 -0700 (PDT) Received: from umbar.lan (2001-14ba-a073-af00-264b-feff-fe8b-be8a.rev.dnainternet.fi. [2001:14ba:a073:af00:264b:feff:fe8b:be8a]) by smtp.gmail.com with ESMTPSA id 2adb3069b0e04-5a8bd7d8974sm3174770e87.64.2026.05.13.11.14.14 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 13 May 2026 11:14:15 -0700 (PDT) From: Dmitry Baryshkov Date: Wed, 13 May 2026 21:14:08 +0300 Subject: [PATCH v9 5/5] phy: qualcomm: add MSM8974 HDMI PHY support 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: <20260513-fd-hdmi-phy-v9-5-ca98c72f1f9f@oss.qualcomm.com> References: <20260513-fd-hdmi-phy-v9-0-ca98c72f1f9f@oss.qualcomm.com> In-Reply-To: <20260513-fd-hdmi-phy-v9-0-ca98c72f1f9f@oss.qualcomm.com> To: Rob Clark , Dmitry Baryshkov , Abhinav Kumar , Jessica Zhang , Sean Paul , Marijn Suijten , David Airlie , Simona Vetter , Vinod Koul , Neil Armstrong Cc: linux-kernel@vger.kernel.org, linux-arm-msm@vger.kernel.org, dri-devel@lists.freedesktop.org, freedreno@lists.freedesktop.org, linux-phy@lists.infradead.org, Dmitry Baryshkov , Konrad Dybcio X-Mailer: b4 0.15.1 X-Developer-Signature: v=1; a=openpgp-sha256; l=10299; i=dmitry.baryshkov@oss.qualcomm.com; h=from:subject:message-id; bh=fiAxSKr0MiXtgdMoguQGBGHvUIsEFSFdo1fVWLdz2eA=; b=owEBbQGS/pANAwAKAYs8ij4CKSjVAcsmYgBqBL9t2xJILDiTUglQXAPwOJoAblLE9eTWuCWxM UG7ow3AGp6JATMEAAEKAB0WIQRMcISVXLJjVvC4lX+LPIo+Aiko1QUCagS/bQAKCRCLPIo+Aiko 1YR1B/44Qhu2PZRI2XldEMpcilSgnWABIFpUPMlVRyggw/TwqvHsEJkI/Y2Delv9Zpv5/wooIeH ksgXuJeIrM8I+/5MWjCXRpcczv0rAxiHZby9NojAzo2kIWbxJoi/3GrhTylYoDFeXXLK0HDEIEO ZlyVyonGAx4O8WW7psKY7yUXxMOQ1843A8Inth3mNIkC10m274Jhoakc9jCWGt7i0sTLrcn5Uz0 sVYvDSW/vpnKQQsoSOdDm8KAizpItql6lGSIkm6JOOyTGcQC8vdEu9Vo3mGeAZj2nT+aqZWi6n/ TEXqqRd0CaTU675gqmbeDi7rVNZBeVdeatN1kzNEjUj+/E/3 X-Developer-Key: i=dmitry.baryshkov@oss.qualcomm.com; a=openpgp; fpr=8F88381DD5C873E4AE487DA5199BF1243632046A X-Authority-Analysis: v=2.4 cv=M/l97Sws c=1 sm=1 tr=0 ts=6a04bf79 cx=c_pps a=5HAIKLe1ejAbszaTRHs9Ug==:117 a=xqWC_Br6kY4A:10 a=IkcTkHD0fZMA:10 a=NGcC8JguVDcA:10 a=s4-Qcg_JpJYA:10 a=VkNPw1HP01LnGYTKEx00:22 a=u7WPNUs3qKkmUXheDGA7:22 a=YMgV9FUhrdKAYTUUvYB2:22 a=KKAkSRfTAAAA:8 a=EUspDBNiAAAA:8 a=pGLkceISAAAA:8 a=U0NZ41NzsMKYcVuMMSoA:9 a=QEXdDO2ut3YA:10 a=gYDTvv6II1OnSo0itH1n:22 a=cvBusfyB2V15izCimMoJ:22 X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwNTEzMDE4MiBTYWx0ZWRfX3w9z/p/fIAKi 7z72nFyv3ydwovpY6c/SCBt9znn+cgKc5a4JlewQ6MO5n45aynbYQho4G87PmMgqY6DQQzbY1Uy p4wMn1T5ltSTOhJlwGqWai/0kI40NmTCOIqVgNLxsZwixhEyBN6UzpPOqxYO7aie3k/SNb+7dTI NhKWZT1IYWLpoY3Q4ef32jVUhuwgId8Qfm9aiOhDcfJb2UB4k6vSIX1MYWxW5tOD3gCCMgKmjXu cnYIgQhq9aJ5yI7SAUa5hJ3tF7UUnciJlECWSfjOqd0W1rJcynLBcs1tY98yYbzicvuI99QL91C nzz6tAcZ/fmwzgkX+/QCBxYoLThH7LMCaRvdKdNJqUBAN2m1XmsVP8nG1XhSceyWXf/Dn8sjkvP rYLrR889dwEE59J000cd3bUeyED+bYY76ULQGm+gkoN3emOZyndrInRNPkXUxnkCNdQpijN9F0f GBdMGZqwmrpy142alOQ== X-Proofpoint-ORIG-GUID: 5twVySwl_i29s3u-LbS3DzcqbMuLNdEU X-Proofpoint-GUID: 5twVySwl_i29s3u-LbS3DzcqbMuLNdEU X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1143,Hydra:6.1.51,FMLib:17.12.100.49 definitions=2026-05-13_02,2026-05-13_01,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 bulkscore=0 clxscore=1015 impostorscore=0 malwarescore=0 suspectscore=0 spamscore=0 phishscore=0 lowpriorityscore=0 priorityscore=1501 adultscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.22.0-2605050000 definitions=main-2605130182 Add support for HDMI PHY on Qualcomm MSM8974 / APQ8074 platforms. Signed-off-by: Dmitry Baryshkov Acked-by: Konrad Dybcio Signed-off-by: Dmitry Baryshkov --- drivers/phy/qualcomm/phy-qcom-hdmi-28hpm.c | 282 +++++++++++++++++++++++++= ++++ 1 file changed, 282 insertions(+) diff --git a/drivers/phy/qualcomm/phy-qcom-hdmi-28hpm.c b/drivers/phy/qualc= omm/phy-qcom-hdmi-28hpm.c index 720757f8f393..7d398060b3a3 100644 --- a/drivers/phy/qualcomm/phy-qcom-hdmi-28hpm.c +++ b/drivers/phy/qualcomm/phy-qcom-hdmi-28hpm.c @@ -6,10 +6,13 @@ * Author: Rob Clark */ =20 +#include #include #include +#include =20 #include "phy-qcom-hdmi-preqmp.h" +#include "phy-qcom-uniphy.h" =20 #define REG_HDMI_8x74_ANA_CFG0 0x00000000 #define REG_HDMI_8x74_ANA_CFG1 0x00000004 @@ -31,8 +34,282 @@ #define REG_HDMI_8x74_BIST_PATN3 0x00000048 #define REG_HDMI_8x74_STATUS 0x0000005c =20 +#define HDMI_8974_VCO_MAX_FREQ 1800000000UL +#define HDMI_8974_VCO_MIN_FREQ 600000000UL + +#define HDMI_8974_COMMON_DIV 5 + +static inline void write16(u16 val, void __iomem *reg) +{ + writel(val & 0xff, reg); + writel(val >> 8, reg + 4); +} + +static inline void write24(u32 val, void __iomem *reg) +{ + writel(val & 0xff, reg); + writel((val >> 8) & 0xff, reg + 4); + writel(val >> 16, reg + 8); +} + +static inline u32 read24(void __iomem *reg) +{ + u32 val =3D readl(reg); + + val |=3D readl(reg + 4) << 8; + val |=3D readl(reg + 8) << 16; + + return val; +} + +static void qcom_uniphy_setup(void __iomem *base, unsigned int ref_freq, + bool sdm_mode, + bool ref_freq_mult_2, + bool dither, + unsigned int refclk_div, + unsigned int vco_freq) +{ + unsigned int int_ref_freq =3D ref_freq * (ref_freq_mult_2 ? 2 : 1); + unsigned int div_in_freq =3D vco_freq / refclk_div; + unsigned int dc_offset =3D div_in_freq / int_ref_freq - 1; + unsigned int sdm_freq_seed; + unsigned int val; + u64 tmp =3D div_in_freq % int_ref_freq; + + tmp *=3D 0x10000; + sdm_freq_seed =3D div_u64(tmp, int_ref_freq); + + val =3D FIELD_PREP(UNIPHY_PLL_REFCLK_DBLR, ref_freq_mult_2) | + FIELD_PREP(UNIPHY_PLL_REFCLK_DIV, refclk_div - 1); + writel(val, base + UNIPHY_PLL_REFCLK_CFG); + + if (sdm_mode) { + writel(0, base + UNIPHY_PLL_SDM_CFG0); + writel(FIELD_PREP(UNIPHY_PLL_SDM_DITHER_EN, dither) | dc_offset, + base + UNIPHY_PLL_SDM_CFG1); + write24(sdm_freq_seed, base + UNIPHY_PLL_SDM_CFG2); + } else { + writel(UNIPHY_PLL_SDM_BYP | dc_offset, base + UNIPHY_PLL_SDM_CFG0); + writel(0, base + UNIPHY_PLL_SDM_CFG1); + write24(0, base + UNIPHY_PLL_SDM_CFG2); + } + + write16(mult_frac(ref_freq, 5, 1000000), base + UNIPHY_PLL_CAL_CFG8); + write16(vco_freq / 16, base + UNIPHY_PLL_CAL_CFG10); +} + +static unsigned long qcom_uniphy_recalc(void __iomem *base, unsigned long = parent_rate) +{ + unsigned long rate; + u32 refclk_cfg; + u32 dc_offset; + u64 fraq_n; + u32 val; + + refclk_cfg =3D readl(base + UNIPHY_PLL_REFCLK_CFG); + if (refclk_cfg & UNIPHY_PLL_REFCLK_DBLR) + parent_rate *=3D 2; + + val =3D readl(base + UNIPHY_PLL_SDM_CFG0); + if (FIELD_GET(UNIPHY_PLL_SDM_BYP, val)) { + dc_offset =3D FIELD_GET(UNIPHY_PLL_SDM_BYP_DIV, val); + fraq_n =3D 0; + } else { + dc_offset =3D FIELD_GET(UNIPHY_PLL_SDM_DC_OFFSET, + readl(base + UNIPHY_PLL_SDM_CFG1)); + fraq_n =3D read24(base + UNIPHY_PLL_SDM_CFG2); + } + + rate =3D (dc_offset + 1) * parent_rate; + rate +=3D div_u64(fraq_n * parent_rate, 0x10000); + + rate *=3D FIELD_GET(UNIPHY_PLL_REFCLK_DIV, refclk_cfg) + 1; + + return rate; +} + +static const unsigned int qcom_hdmi_8974_divs[] =3D {1, 2, 4, 6}; + +static unsigned long qcom_hdmi_8974_pll_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct qcom_hdmi_preqmp_phy *hdmi_phy =3D hw_clk_to_phy(hw); + u32 div_idx =3D readl(hdmi_phy->pll_reg + UNIPHY_PLL_POSTDIV1_CFG); + unsigned long rate =3D qcom_uniphy_recalc(hdmi_phy->pll_reg, parent_rate); + + return rate / HDMI_8974_COMMON_DIV / qcom_hdmi_8974_divs[div_idx & 0x3]; +} + +static int qcom_hdmi_8974_pll_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + unsigned long min_freq =3D HDMI_8974_VCO_MIN_FREQ / HDMI_8974_COMMON_DIV; + unsigned long max_freq =3D HDMI_8974_VCO_MAX_FREQ / HDMI_8974_COMMON_DIV; + + req->rate =3D clamp(req->rate, min_freq / 6, max_freq); + + return 0; +} + +static const struct clk_ops qcom_hdmi_8974_pll_ops =3D { + .recalc_rate =3D qcom_hdmi_8974_pll_recalc_rate, + .determine_rate =3D qcom_hdmi_8974_pll_determine_rate, +}; + +static int qcom_hdmi_msm8974_phy_find_div(unsigned long long pixclk) +{ + unsigned long long min_freq =3D HDMI_8974_VCO_MIN_FREQ / HDMI_8974_COMMON= _DIV; + int i; + + if (pixclk > HDMI_8974_VCO_MAX_FREQ / HDMI_8974_COMMON_DIV) + return -EINVAL; + + for (i =3D 0; i < ARRAY_SIZE(qcom_hdmi_8974_divs); i++) { + if (pixclk >=3D min_freq / qcom_hdmi_8974_divs[i]) + return i; + } + + return -EINVAL; +} + +static int qcom_hdmi_msm8974_phy_pll_set_rate(struct qcom_hdmi_preqmp_phy = *hdmi_phy) +{ + unsigned long long pixclk =3D hdmi_phy->hdmi_opts.tmds_char_rate; + unsigned long vco_rate; + unsigned int div; + int div_idx =3D 0; + + div_idx =3D qcom_hdmi_msm8974_phy_find_div(pixclk); + if (WARN_ON(div_idx < 0)) + return div_idx; + + div =3D qcom_hdmi_8974_divs[div_idx]; + vco_rate =3D pixclk * HDMI_8974_COMMON_DIV * div; + + writel(0x81, hdmi_phy->phy_reg + REG_HDMI_8x74_GLB_CFG); + + writel(0x01, hdmi_phy->pll_reg + UNIPHY_PLL_GLB_CFG); + writel(0x19, hdmi_phy->pll_reg + UNIPHY_PLL_VCOLPF_CFG); + writel(0x0e, hdmi_phy->pll_reg + UNIPHY_PLL_LPFR_CFG); + writel(0x20, hdmi_phy->pll_reg + UNIPHY_PLL_LPFC1_CFG); + writel(0x0d, hdmi_phy->pll_reg + UNIPHY_PLL_LPFC2_CFG); + + qcom_uniphy_setup(hdmi_phy->pll_reg, 19200000, true, true, true, 1, vco_r= ate); + + writel(0x10, hdmi_phy->pll_reg + UNIPHY_PLL_LKDET_CFG0); + writel(0x1a, hdmi_phy->pll_reg + UNIPHY_PLL_LKDET_CFG1); + writel(0x05, hdmi_phy->pll_reg + UNIPHY_PLL_LKDET_CFG2); + + writel(div_idx, hdmi_phy->pll_reg + UNIPHY_PLL_POSTDIV1_CFG); + + writel(0x00, hdmi_phy->pll_reg + UNIPHY_PLL_POSTDIV2_CFG); + writel(0x00, hdmi_phy->pll_reg + UNIPHY_PLL_POSTDIV3_CFG); + writel(0x01, hdmi_phy->pll_reg + UNIPHY_PLL_CAL_CFG2); + + writel(0x1f, hdmi_phy->phy_reg + REG_HDMI_8x74_PD_CTRL0); + udelay(50); + + writel(0x0f, hdmi_phy->pll_reg + UNIPHY_PLL_GLB_CFG); + + writel(0x00, hdmi_phy->phy_reg + REG_HDMI_8x74_PD_CTRL1); + writel(0x10, hdmi_phy->phy_reg + REG_HDMI_8x74_ANA_CFG2); + writel(0xdb, hdmi_phy->phy_reg + REG_HDMI_8x74_ANA_CFG0); + writel(0x43, hdmi_phy->phy_reg + REG_HDMI_8x74_ANA_CFG1); + if (pixclk =3D=3D 297000000) { + writel(0x06, hdmi_phy->phy_reg + REG_HDMI_8x74_ANA_CFG2); + writel(0x03, hdmi_phy->phy_reg + REG_HDMI_8x74_ANA_CFG3); + } else if (pixclk =3D=3D 268500000) { + writel(0x05, hdmi_phy->phy_reg + REG_HDMI_8x74_ANA_CFG2); + writel(0x00, hdmi_phy->phy_reg + REG_HDMI_8x74_ANA_CFG3); + } else { + writel(0x02, hdmi_phy->phy_reg + REG_HDMI_8x74_ANA_CFG2); + writel(0x00, hdmi_phy->phy_reg + REG_HDMI_8x74_ANA_CFG3); + } + + writel(0x04, hdmi_phy->pll_reg + UNIPHY_PLL_VREG_CFG); + + writel(0xd0, hdmi_phy->phy_reg + REG_HDMI_8x74_DCC_CFG0); + writel(0x1a, hdmi_phy->phy_reg + REG_HDMI_8x74_DCC_CFG1); + writel(0x00, hdmi_phy->phy_reg + REG_HDMI_8x74_TXCAL_CFG0); + writel(0x00, hdmi_phy->phy_reg + REG_HDMI_8x74_TXCAL_CFG1); + + if (pixclk =3D=3D 268500000) + writel(0x11, hdmi_phy->phy_reg + REG_HDMI_8x74_TXCAL_CFG2); + else + writel(0x02, hdmi_phy->phy_reg + REG_HDMI_8x74_TXCAL_CFG2); + + writel(0x05, hdmi_phy->phy_reg + REG_HDMI_8x74_TXCAL_CFG3); + udelay(200); + + return 0; +} + +static int qcom_hdmi_msm8974_phy_pll_enable(struct qcom_hdmi_preqmp_phy *h= dmi_phy) +{ + int ret; + unsigned long status; + + /* Global enable */ + writel(0x81, hdmi_phy->phy_reg + REG_HDMI_8x74_GLB_CFG); + + /* Power up power gen */ + writel(0x00, hdmi_phy->phy_reg + REG_HDMI_8x74_PD_CTRL0); + udelay(350); + + /* PLL power up */ + writel(0x01, hdmi_phy->pll_reg + UNIPHY_PLL_GLB_CFG); + udelay(5); + + /* Power up PLL LDO */ + writel(0x03, hdmi_phy->pll_reg + UNIPHY_PLL_GLB_CFG); + udelay(350); + + /* PLL power up */ + writel(0x0f, hdmi_phy->pll_reg + UNIPHY_PLL_GLB_CFG); + udelay(350); + + /* Poll for PLL ready status */ + ret =3D readl_poll_timeout(hdmi_phy->pll_reg + UNIPHY_PLL_STATUS, + status, status & UNIPHY_PLL_LOCK, + 100, 2000); + if (ret) { + dev_warn(hdmi_phy->dev, "HDMI PLL not ready\n"); + goto err; + } + + udelay(350); + + /* Poll for PHY ready status */ + ret =3D readl_poll_timeout(hdmi_phy->phy_reg + REG_HDMI_8x74_STATUS, + status, status & BIT(0), + 100, 2000); + if (ret) { + dev_warn(hdmi_phy->dev, "HDMI PHY not ready\n"); + goto err; + } + + return 0; + +err: + writel(0, hdmi_phy->pll_reg + UNIPHY_PLL_GLB_CFG); + udelay(5); + writel(0, hdmi_phy->phy_reg + REG_HDMI_8x74_GLB_CFG); + + return ret; +} + static int qcom_hdmi_msm8974_phy_power_on(struct qcom_hdmi_preqmp_phy *hdm= i_phy) { + int ret; + + ret =3D qcom_hdmi_msm8974_phy_pll_set_rate(hdmi_phy); + if (ret) + return ret; + + ret =3D qcom_hdmi_msm8974_phy_pll_enable(hdmi_phy); + if (ret) + return ret; + writel(0x1b, hdmi_phy->phy_reg + REG_HDMI_8x74_ANA_CFG0); writel(0xf2, hdmi_phy->phy_reg + REG_HDMI_8x74_ANA_CFG1); writel(0x00, hdmi_phy->phy_reg + REG_HDMI_8x74_BIST_CFG0); @@ -49,6 +326,10 @@ static int qcom_hdmi_msm8974_phy_power_off(struct qcom_= hdmi_preqmp_phy *hdmi_phy { writel(0x7f, hdmi_phy->phy_reg + REG_HDMI_8x74_PD_CTRL0); =20 + writel(0, hdmi_phy->pll_reg + UNIPHY_PLL_GLB_CFG); + udelay(5); + writel(0, hdmi_phy->phy_reg + REG_HDMI_8x74_GLB_CFG); + return 0; } =20 @@ -67,5 +348,6 @@ const struct qcom_hdmi_preqmp_cfg msm8974_hdmi_phy_cfg = =3D { .power_on =3D qcom_hdmi_msm8974_phy_power_on, .power_off =3D qcom_hdmi_msm8974_phy_power_off, =20 + .pll_ops =3D &qcom_hdmi_8974_pll_ops, .pll_parent =3D &msm8974_hdmi_pll_parent, }; --=20 2.47.3