From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from bali.collaboradmins.com (bali.collaboradmins.com [148.251.105.195]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2CA9D3DB32E for ; Thu, 11 Jun 2026 23:45:48 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.251.105.195 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781221553; cv=none; b=XYvpBKktL5Szlaj1MAadhdFqDKKzHS63Q8qJLGjCwm6Se4U6IdTNZ7roBa8q5zIXqLbmVQS4GZvypXhAQ8tK6K/9L/Bg2uHnNMJMM+YXREpkA3q3Csb1yX1IMGFI4576XTbVJu/xZsOlIxYG8vxP41NVemfxNLutQ/nU3AOyWNo= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781221553; c=relaxed/simple; bh=2kQesQNu3MuWE/xRuzdp6xMGi9TTCCje9qYNe5bbNus=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=PhHBb2CFOaf8UGwEKlGBIfvIix9ZMhWuZ3taCEd4CL5gzl0mbX9t5Ca6WSYtRhilUtGQ196HFiOyej4GFQ5rM+GuyeQuBUZ3+Gdo0B1viQ7jPNRivqp3U056qqxC4EXofGvLfGQf+vVQ8Ch6BxXGuHKxv0iZa4pUJ7xFFZLhqOA= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com; spf=pass smtp.mailfrom=collabora.com; dkim=pass (2048-bit key) header.d=collabora.com header.i=@collabora.com header.b=QxAh8GyF; arc=none smtp.client-ip=148.251.105.195 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=collabora.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=collabora.com header.i=@collabora.com header.b="QxAh8GyF" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=collabora.com; s=mail; t=1781221546; bh=2kQesQNu3MuWE/xRuzdp6xMGi9TTCCje9qYNe5bbNus=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=QxAh8GyFxVZuzvUJmwoIS4LohKM+hcHw3atlh62bUY8PSncxzzF1mWR9LB26QHYXl eEyp5nG1D14AGlDabVu2aPDl5NmYkUY63eTmV4+dUUDHvM9+ABKbPsLs8eA6WYkRbl IjhtjSa6CtCxBUUDRVhtFDMV8dgMQ2ByaBcTwj/MRUZK+FKBb1vfu1ObslpFZpaSLK 0QPF3Qz3ekP+CQBnSCv/ZdZMaUhk04SJBUQhK/j5G5gZpdJIdSEUc4Uf0Q9iSURrRA OuDuOiR5iv6N7/cXyEeryBwMwu+lC4jeAk1W23Pv6h7erWdGC6oBjtJiXrPgRHOcFI smVUFvlW3BFCA== Received: from localhost (unknown [100.64.0.241]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange ECDHE (prime256v1) server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: cristicc) by bali.collaboradmins.com (Postfix) with ESMTPSA id 5E58917E0C21; Fri, 12 Jun 2026 01:45:46 +0200 (CEST) From: Cristian Ciocaltea Date: Fri, 12 Jun 2026 02:45:23 +0300 Subject: [PATCH v4 4/8] phy: rockchip: samsung-hdptx: Handle uncommitted PHY config changes 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: 8bit Message-Id: <20260612-hdptx-clk-fixes-v4-4-ce5e1d456cda@collabora.com> References: <20260612-hdptx-clk-fixes-v4-0-ce5e1d456cda@collabora.com> In-Reply-To: <20260612-hdptx-clk-fixes-v4-0-ce5e1d456cda@collabora.com> To: Vinod Koul , Neil Armstrong , Heiko Stuebner , Algea Cao , Dmitry Baryshkov Cc: kernel@collabora.com, linux-phy@lists.infradead.org, linux-arm-kernel@lists.infradead.org, linux-rockchip@lists.infradead.org, linux-kernel@vger.kernel.org, =?utf-8?q?Thomas_Niederpr=C3=BCm?= , Simon Wright X-Mailer: b4 0.15.2 Any changes to the PHY link rate and/or color depth done via the HDMI PHY configuration API are not immediately programmed into the hardware, but are delayed until the PHY usage count gets incremented from 0 to 1, that is when it is powered on or when the PLL clock exposed through the CCF API is prepared, whichever comes first. Since the clock might remain in prepared state after subsequent PHY config changes, the programming can also be triggered via clk_ops.set_rate(). However, from the clock consumer perspective (i.e. VOP2 display controller), the (pixel) clock rate doesn't vary with bpc, as that is handled internally by the PHY and reflected in the TDMS character rate only. As a consequence, changing the bpc while preserving the modeline may lead to out-of-sync issues between CCF and HDMI PHY config state, because the .set_rate() callback is not invoked when clock rate remains constant. This may also happen when the PHY PLL has been pre-programmed by an external entity, e.g. the bootloader, which is actually a regression introduced by the recent FRL patches. Introduce a pll_config_dirty flag to keep track of uncommitted PHY config changes and use it in clk_ops.determine_rate() to invalidate the current clock rate (as known by CCF) and, consequently, ensure those changes are programmed into hardware via clk_ops.set_rate(). Moreover, proceed with a similar fix in phy_ops.power_on() callback, to handle the scenario where the CCF API is not used due to operating in FRL mode, while the clock is still in a prepared state and thus preventing rk_hdptx_phy_consumer_get() to apply the updated PHY configuration. Fixes: de5dba833118 ("phy: rockchip: samsung-hdptx: Add HDMI 2.1 FRL support") Fixes: 9d0ec51d7c22 ("phy: rockchip: samsung-hdptx: Add high color depth management") Tested-by: Thomas Niederprüm Tested-by: Simon Wright Signed-off-by: Cristian Ciocaltea --- drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c | 84 +++++++++++++---------- 1 file changed, 48 insertions(+), 36 deletions(-) diff --git a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c index b210c1a88b25..25bd821cd039 100644 --- a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c +++ b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c @@ -413,6 +413,7 @@ struct rk_hdptx_phy { /* clk provider */ struct clk_hw hw; + bool pll_config_dirty; bool restrict_rate_change; atomic_t usage_count; @@ -1260,13 +1261,19 @@ static int rk_hdptx_tmds_ropll_cmn_config(struct rk_hdptx_phy *hdptx) static int rk_hdptx_pll_cmn_config(struct rk_hdptx_phy *hdptx) { + int ret; + if (hdptx->hdmi_cfg.rate <= HDMI20_MAX_RATE) - return rk_hdptx_tmds_ropll_cmn_config(hdptx); + ret = rk_hdptx_tmds_ropll_cmn_config(hdptx); + else if (hdptx->hdmi_cfg.rate == FRL_8G4L_RATE) + ret = rk_hdptx_frl_lcpll_ropll_cmn_config(hdptx); + else + ret = rk_hdptx_frl_lcpll_cmn_config(hdptx); - if (hdptx->hdmi_cfg.rate == FRL_8G4L_RATE) - return rk_hdptx_frl_lcpll_ropll_cmn_config(hdptx); + if (!ret) + hdptx->pll_config_dirty = false; - return rk_hdptx_frl_lcpll_cmn_config(hdptx); + return ret; } static int rk_hdptx_frl_lcpll_mode_config(struct rk_hdptx_phy *hdptx) @@ -1347,25 +1354,22 @@ static int rk_hdptx_phy_consumer_get(struct rk_hdptx_phy *hdptx) return 0; ret = regmap_read(hdptx->grf, GRF_HDPTX_STATUS, &status); - if (ret) - goto dec_usage; - - if (status & HDPTX_O_PLL_LOCK_DONE) - dev_warn(hdptx->dev, "PLL locked by unknown consumer!\n"); + if (ret) { + atomic_dec(&hdptx->usage_count); + return ret; + } if (mode == PHY_MODE_DP) { rk_hdptx_dp_reset(hdptx); } else { - ret = rk_hdptx_pll_cmn_config(hdptx); - if (ret) - goto dec_usage; + /* + * Ignore PLL config errors at this point as pll_config_dirty + * was not reset and, therefore, operation will be retried. + */ + rk_hdptx_pll_cmn_config(hdptx); } return 0; - -dec_usage: - atomic_dec(&hdptx->usage_count); - return ret; } static int rk_hdptx_phy_consumer_put(struct rk_hdptx_phy *hdptx, bool force) @@ -1700,13 +1704,18 @@ static int rk_hdptx_phy_power_on(struct phy *phy) if (ret) rk_hdptx_phy_consumer_put(hdptx, true); } else { - regmap_write(hdptx->grf, GRF_HDPTX_CON0, - HDPTX_MODE_SEL << 16 | FIELD_PREP(HDPTX_MODE_SEL, 0x0)); + if (hdptx->pll_config_dirty) + ret = rk_hdptx_pll_cmn_config(hdptx); - if (hdptx->hdmi_cfg.mode == PHY_HDMI_MODE_FRL) - ret = rk_hdptx_frl_lcpll_mode_config(hdptx); - else - ret = rk_hdptx_tmds_ropll_mode_config(hdptx); + if (!ret) { + regmap_write(hdptx->grf, GRF_HDPTX_CON0, + HDPTX_MODE_SEL << 16 | FIELD_PREP(HDPTX_MODE_SEL, 0x0)); + + if (hdptx->hdmi_cfg.mode == PHY_HDMI_MODE_FRL) + ret = rk_hdptx_frl_lcpll_mode_config(hdptx); + else + ret = rk_hdptx_tmds_ropll_mode_config(hdptx); + } if (ret) rk_hdptx_phy_consumer_put(hdptx, true); @@ -2081,7 +2090,10 @@ static int rk_hdptx_phy_configure(struct phy *phy, union phy_configure_opts *opt dev_err(hdptx->dev, "invalid hdmi params for phy configure\n"); } else { hdptx->restrict_rate_change = true; - dev_dbg(hdptx->dev, "%s rate=%llu bpc=%u\n", __func__, + hdptx->pll_config_dirty = true; + + dev_dbg(hdptx->dev, "%s %s rate=%llu bpc=%u\n", __func__, + hdptx->hdmi_cfg.mode ? "FRL" : "TMDS", hdptx->hdmi_cfg.rate, hdptx->hdmi_cfg.bpc); } @@ -2323,8 +2335,19 @@ static int rk_hdptx_phy_clk_determine_rate(struct clk_hw *hw, { struct rk_hdptx_phy *hdptx = to_rk_hdptx_phy(hw); - if (hdptx->hdmi_cfg.mode == PHY_HDMI_MODE_FRL) - return hdptx->hdmi_cfg.rate; + /* + * Invalidate current clock rate to ensure rk_hdptx_phy_clk_set_rate() + * will be invoked to commit PLL configuration. + */ + if (hdptx->pll_config_dirty) { + req->rate = 0; + return 0; + } + + if (hdptx->hdmi_cfg.mode == PHY_HDMI_MODE_FRL) { + req->rate = hdptx->hdmi_cfg.rate; + return 0; + } /* * FIXME: Temporarily allow altering TMDS char rate via CCF. @@ -2356,17 +2379,6 @@ static int rk_hdptx_phy_clk_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) { struct rk_hdptx_phy *hdptx = to_rk_hdptx_phy(hw); - unsigned long long link_rate = rate; - - if (hdptx->hdmi_cfg.mode != PHY_HDMI_MODE_FRL) - link_rate = DIV_ROUND_CLOSEST_ULL(rate * hdptx->hdmi_cfg.bpc, 8); - - /* Revert any unlikely link rate change since determine_rate() */ - if (hdptx->hdmi_cfg.rate != link_rate) { - dev_warn(hdptx->dev, "Reverting unexpected rate change from %llu to %llu\n", - link_rate, hdptx->hdmi_cfg.rate); - hdptx->hdmi_cfg.rate = link_rate; - } /* * The link rate would be normally programmed in HW during -- 2.54.0