From nobody Tue Dec 16 08:49:50 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 351DD2F260E; Mon, 15 Dec 2025 12:42:26 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1765802546; cv=none; b=YEani0MuZTMub7Wr6j8/xNkiaOrr61ViIh8MwuWLlbwkVg1IXbYzFO1ktSfXY8B1toFf17SIKOJ9DekOT0WNOqsUyw3LNBTeOvc4RZTiPyiNf1oUJms4q3VxXBXsuCcHeykIbwI7vRHvuhSUJcRFziFaqU/qATVk3dIkIhNeojk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1765802546; c=relaxed/simple; bh=B7yPhcKv9wHpjr+TlNGoWcU+7Ga73fL9ccW/SUGGpts=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=o2qFKsY5QSBIcCVZ93fEm5zZlJpFdee20xJaQ/f9yS/f054eV+7XNd2Zjah9KBe0BqXVkHvkvtqu/LyusOIJQF8WAeKBXmlGwC3J4GNtTmd52me+hFg/toq1E9fGzcxNKhohKnZ9LsKsXCJmq9fDNWqLBUKP+vuzsCKdEughi+o= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=VdSXdxaL; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="VdSXdxaL" Received: by smtp.kernel.org (Postfix) with ESMTPS id AFE65C19425; Mon, 15 Dec 2025 12:42:25 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1765802545; bh=B7yPhcKv9wHpjr+TlNGoWcU+7Ga73fL9ccW/SUGGpts=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=VdSXdxaLBRy83VdakbXMccvbz1UMIF7rGHWWHvJzIa/iGzUmYajw/p7X/SplbuFrX X7lL5P0AhCGpZJJRTihmQ5GwHGIyH3FdaTTJbOqwVYfxr6qUNEigQSb0Id/pnqqM22 PrT1opQ79ZAv99F5cBliubax7WofrJJ+nQt4kJ7xcjOTMWPtFpo7ODxmqRuA/fchH2 McirhNopVmgBm+E0uEJ6wnmi+cJk1154FwIpr/RuNzUYzBl3Q0QIB9IeW4nherCkt9 jLkTyUt414gH2ZMhDOUcY1bP8AbM8QTA8eYHyghmFV8uOyXbR1ZWfrIfrmBFFyjnJX Orge03+D8xVBQ== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id A52D5D59D99; Mon, 15 Dec 2025 12:42:25 +0000 (UTC) From: Xiangxu Yin via B4 Relay Date: Mon, 15 Dec 2025 20:42:02 +0800 Subject: [PATCH v8 06/12] phy: qcom: qmp-usbc: add DP link and vco_div clocks for DP PHY 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: <20251215-add-displayport-support-for-qcs615-platform-v8-6-cbc72c88a44e@oss.qualcomm.com> References: <20251215-add-displayport-support-for-qcs615-platform-v8-0-cbc72c88a44e@oss.qualcomm.com> In-Reply-To: <20251215-add-displayport-support-for-qcs615-platform-v8-0-cbc72c88a44e@oss.qualcomm.com> To: Vinod Koul , Neil Armstrong , Rob Herring , Krzysztof Kozlowski , Conor Dooley Cc: linux-arm-msm@vger.kernel.org, linux-phy@lists.infradead.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, fange.zhang@oss.qualcomm.com, yongxing.mou@oss.qualcomm.com, li.liu@oss.qualcomm.com, tingwei.zhang@oss.qualcomm.com, Dmitry Baryshkov , Bjorn Andersson , Konrad Dybcio , Xiangxu Yin X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=ed25519-sha256; t=1765802542; l=8764; i=xiangxu.yin@oss.qualcomm.com; s=20241125; h=from:subject:message-id; bh=EfechlnT8nWeeRbx1u0qd5ExGmvffmrxrvtcu0XQmTw=; b=JQTuvtR1rXlGXec1v46+4sg1AD+KTWT9D8M2jVKanRF11dxH4tZu4I+odlvSrQ9phYnaYkaQZ rYjlbUB46D9DC9qJMjao89edBwEm6pMkYniAtBi/2yNjeC/imE15PtK X-Developer-Key: i=xiangxu.yin@oss.qualcomm.com; a=ed25519; pk=F1TwipJzpywfbt3n/RPi4l/A4AVF+QC89XzCHgZYaOc= X-Endpoint-Received: by B4 Relay for xiangxu.yin@oss.qualcomm.com/20241125 with auth_id=542 X-Original-From: Xiangxu Yin Reply-To: xiangxu.yin@oss.qualcomm.com From: Xiangxu Yin USB3DP PHY requires link and vco_div clocks when operating in DP mode. Extend qmp_usbc_register_clocks and the clock provider logic to register these clocks along with the existing pipe clock, to support both USB and DP configurations. Reviewed-by: Dmitry Baryshkov Signed-off-by: Xiangxu Yin --- drivers/phy/qualcomm/phy-qcom-qmp-usbc.c | 209 +++++++++++++++++++++++++++= +++- 1 file changed, 203 insertions(+), 6 deletions(-) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c b/drivers/phy/qualcom= m/phy-qcom-qmp-usbc.c index cff148dc9f01..a6431e6d5586 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c @@ -22,6 +22,7 @@ #include #include #include +#include =20 #include "phy-qcom-qmp-common.h" =20 @@ -851,9 +852,23 @@ static int qmp_usbc_clk_init(struct qmp_usbc *qmp) return devm_clk_bulk_get_optional(dev, num, qmp->clks); } =20 -static void phy_clk_release_provider(void *res) +static struct clk_hw *qmp_usbc_clks_hw_get(struct of_phandle_args *clkspec= , void *data) { - of_clk_del_provider(res); + struct qmp_usbc *qmp =3D data; + + if (clkspec->args_count =3D=3D 0) + return &qmp->pipe_clk_fixed.hw; + + switch (clkspec->args[0]) { + case QMP_USB43DP_USB3_PIPE_CLK: + return &qmp->pipe_clk_fixed.hw; + case QMP_USB43DP_DP_LINK_CLK: + return &qmp->dp_link_hw; + case QMP_USB43DP_DP_VCO_DIV_CLK: + return &qmp->dp_pixel_hw; + } + + return ERR_PTR(-EINVAL); } =20 /* @@ -878,12 +893,14 @@ static int phy_pipe_clk_register(struct qmp_usbc *qmp= , struct device_node *np) { struct clk_fixed_rate *fixed =3D &qmp->pipe_clk_fixed; struct clk_init_data init =3D { }; + char name[64]; int ret; =20 ret =3D of_property_read_string(np, "clock-output-names", &init.name); if (ret) { - dev_err(qmp->dev, "%pOFn: No clock-output-names\n", np); - return ret; + /* Clock name is not mandatory. */ + snprintf(name, sizeof(name), "%s::pipe_clk", dev_name(qmp->dev)); + init.name =3D name; } =20 init.ops =3D &clk_fixed_rate_ops; @@ -892,10 +909,183 @@ static int phy_pipe_clk_register(struct qmp_usbc *qm= p, struct device_node *np) fixed->fixed_rate =3D 125000000; fixed->hw.init =3D &init; =20 - ret =3D devm_clk_hw_register(qmp->dev, &fixed->hw); + return devm_clk_hw_register(qmp->dev, &fixed->hw); +} + +/* + * Display Port PLL driver block diagram for branch clocks + * + * +------------------------------+ + * | DP_VCO_CLK | + * | | + * | +-------------------+ | + * | | (DP PLL/VCO) | | + * | +---------+---------+ | + * | v | + * | +----------+-----------+ | + * | | hsclk_divsel_clk_src | | + * | +----------+-----------+ | + * +------------------------------+ + * | + * +---------<---------v------------>----------+ + * | | + * +--------v----------------+ | + * | dp_phy_pll_link_clk | | + * | link_clk | | + * +--------+----------------+ | + * | | + * | | + * v v + * Input to DISPCC block | + * for link clk, crypto clk | + * and interface clock | + * | + * | + * +--------<------------+-----------------+---<---+ + * | | | + * +----v---------+ +--------v-----+ +--------v------+ + * | vco_divided | | vco_divided | | vco_divided | + * | _clk_src | | _clk_src | | _clk_src | + * | | | | | | + * |divsel_six | | divsel_two | | divsel_four | + * +-------+------+ +-----+--------+ +--------+------+ + * | | | + * v---->----------v-------------<------v + * | + * +----------+-----------------+ + * | dp_phy_pll_vco_div_clk | + * +---------+------------------+ + * | + * v + * Input to DISPCC block + * for DP pixel clock + * + */ +static int qmp_dp_pixel_clk_determine_rate(struct clk_hw *hw, struct clk_r= ate_request *req) +{ + switch (req->rate) { + case 1620000000UL / 2: + case 2700000000UL / 2: + /* 5.4 is same link rate as 2.7GHz, i.e. div 4 */ + return 0; + default: + return -EINVAL; + } +} + +static unsigned long qmp_dp_pixel_clk_recalc_rate(struct clk_hw *hw, unsig= ned long parent_rate) +{ + const struct qmp_usbc *qmp; + const struct phy_configure_opts_dp *dp_opts; + + qmp =3D container_of(hw, struct qmp_usbc, dp_pixel_hw); + + dp_opts =3D &qmp->dp_opts; + + switch (dp_opts->link_rate) { + case 1620: + return 1620000000UL / 2; + case 2700: + return 2700000000UL / 2; + case 5400: + return 5400000000UL / 4; + default: + return 0; + } +} + +static const struct clk_ops qmp_dp_pixel_clk_ops =3D { + .determine_rate =3D qmp_dp_pixel_clk_determine_rate, + .recalc_rate =3D qmp_dp_pixel_clk_recalc_rate, +}; + +static int qmp_dp_link_clk_determine_rate(struct clk_hw *hw, struct clk_ra= te_request *req) +{ + switch (req->rate) { + case 162000000: + case 270000000: + case 540000000: + return 0; + default: + return -EINVAL; + } +} + +static unsigned long qmp_dp_link_clk_recalc_rate(struct clk_hw *hw, unsign= ed long parent_rate) +{ + const struct qmp_usbc *qmp; + const struct phy_configure_opts_dp *dp_opts; + + qmp =3D container_of(hw, struct qmp_usbc, dp_link_hw); + dp_opts =3D &qmp->dp_opts; + + switch (dp_opts->link_rate) { + case 1620: + case 2700: + case 5400: + return dp_opts->link_rate * 100000; + default: + return 0; + } +} + +static const struct clk_ops qmp_dp_link_clk_ops =3D { + .determine_rate =3D qmp_dp_link_clk_determine_rate, + .recalc_rate =3D qmp_dp_link_clk_recalc_rate, +}; + +static int phy_dp_clks_register(struct qmp_usbc *qmp, struct device_node *= np) +{ + struct clk_init_data init =3D { }; + char name[64]; + int ret; + + snprintf(name, sizeof(name), "%s::link_clk", dev_name(qmp->dev)); + init.ops =3D &qmp_dp_link_clk_ops; + init.name =3D name; + qmp->dp_link_hw.init =3D &init; + ret =3D devm_clk_hw_register(qmp->dev, &qmp->dp_link_hw); + if (ret < 0) { + dev_err(qmp->dev, "link clk reg fail ret=3D%d\n", ret); + return ret; + } + + snprintf(name, sizeof(name), "%s::vco_div_clk", dev_name(qmp->dev)); + init.ops =3D &qmp_dp_pixel_clk_ops; + init.name =3D name; + qmp->dp_pixel_hw.init =3D &init; + ret =3D devm_clk_hw_register(qmp->dev, &qmp->dp_pixel_hw); + if (ret) { + dev_err(qmp->dev, "pxl clk reg fail ret=3D%d\n", ret); + return ret; + } + + return 0; +} + +static void phy_clk_release_provider(void *res) +{ + of_clk_del_provider(res); +} + +static int qmp_usbc_register_clocks(struct qmp_usbc *qmp, struct device_no= de *np) +{ + struct clk_fixed_rate *fixed =3D &qmp->pipe_clk_fixed; + int ret; + + ret =3D phy_pipe_clk_register(qmp, np); if (ret) return ret; =20 + if (qmp->dp_serdes !=3D 0) { + ret =3D phy_dp_clks_register(qmp, np); + if (ret) + return ret; + } + + if (np =3D=3D qmp->dev->of_node) + return devm_of_clk_add_hw_provider(qmp->dev, qmp_usbc_clks_hw_get, qmp); + ret =3D of_clk_add_hw_provider(np, of_clk_hw_simple_get, &fixed->hw); if (ret) return ret; @@ -1040,6 +1230,13 @@ static int qmp_usbc_parse_dt(struct qmp_usbc *qmp) if (IS_ERR(base)) return PTR_ERR(base); =20 + if (offs->dp_serdes !=3D 0) { + qmp->dp_serdes =3D base + offs->dp_serdes; + qmp->dp_tx =3D base + offs->dp_txa; + qmp->dp_tx2 =3D base + offs->dp_txb; + qmp->dp_dp_phy =3D base + offs->dp_dp_phy; + } + qmp->serdes =3D base + offs->serdes; qmp->pcs =3D base + offs->pcs; if (offs->pcs_misc) @@ -1148,7 +1345,7 @@ static int qmp_usbc_probe(struct platform_device *pde= v) */ pm_runtime_forbid(dev); =20 - ret =3D phy_pipe_clk_register(qmp, np); + ret =3D qmp_usbc_register_clocks(qmp, np); if (ret) goto err_node_put; =20 --=20 2.34.1