* Re: [PATCH v3 1/2] phy: rockchip: inno-hdmi: Add configure() and validate() ops
From: Jonas Karlman @ 2026-05-18 11:19 UTC (permalink / raw)
To: Vinod Koul
Cc: Neil Armstrong, Heiko Stuebner, linux-phy, linux-rockchip,
linux-arm-kernel, linux-kernel
In-Reply-To: <agny1ER5j6om9hIT@vaman>
On 5/17/2026 6:54 PM, Vinod Koul wrote:
> On 15-05-26, 23:04, Jonas Karlman wrote:
>> Hi,
>>
>> On 5/15/2026 9:55 PM, Jonas Karlman wrote:
>>> The commit 10ed34d6eaaf ("phy: Add HDMI configuration options")
>>> introduced a way for HDMI PHYs to be configured through the generic
>>> phy_configure() function.
>>>
>>> This driver derives the TMDS character rate from the pixel clock and the
>>> PHY bus width setting. However, no in-tree consumer of this PHY has ever
>>> called phy_set_bus_width() to change the TMDS character rate as only
>>> 8-bit RGB output is supported by the HDMI display driver.
>>>
>>> Add configure() and validate() ops to allow consumers to configure the
>>> TMDS character rate using phy_configure(). Fallback to the deprecated
>>> way of using the PHY bus width to configure the TMDS character rate.
>>>
>>> A typical call chain during DRM modeset on a RK3328 device:
>>>
>>> dw_hdmi_rockchip_encoder_atomic_check():
>>> - inno_hdmi_phy_validate(): pixclock 148500000 tmdsclock 594000000
>>>
>>> dw_hdmi_rockchip_encoder_atomic_mode_set():
>>> - inno_hdmi_phy_configure(): pixclock 148500000
>>> - inno_hdmi_phy_validate(): pixclock 148500000 tmdsclock 594000000
>>>
>>> vop_crtc_atomic_enable():
>>> - inno_hdmi_phy_rk3328_clk_set_rate(): rate 594000000 tmdsclk 594000000
>>> - inno_hdmi_phy_rk3328_clk_set_rate(): pixclock 594000000 tmdsclock 594000000
>>> - inno_hdmi_phy_rk3328_clk_recalc_rate(): pixclock 594000000 vco 594000000
>>>
>>> dw_hdmi_rockchip_encoder_enable():
>>> - inno_hdmi_phy_power_on(): Inno HDMI PHY Power On
>>> - inno_hdmi_phy_rk3328_clk_set_rate(): rate 594000000 tmdsclk 594000000
>>>
>>> Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
>>> ---
>>> Changes in v3:
>>> - Change validate() ops to only validate tmdsclock
>>> - Add comments about expected consumer usage
>>> - Update commit message with a typical call chain
>>> Changes in v2:
>>> - Add validate() ops to validate that the TMDS rate is supported
>>> - Split out parts that remove the old workaround into a separate patch
>>>
>>> Patch "drm/rockchip: dw_hdmi: Configure HDMI PHY in atomic_mode_set()"
>>> at [1] adds phy_validate() and phy_configure() calls for this HDMI PHY.
>>>
>>> [1] https://lore.kernel.org/dri-devel/20260510183114.1248840-10-jonas@kwiboo.se/
>>> ---
>>> drivers/phy/rockchip/phy-rockchip-inno-hdmi.c | 60 ++++++++++++++++++-
>>> 1 file changed, 59 insertions(+), 1 deletion(-)
>>
>> [snip]
>>
>>> +static int inno_hdmi_phy_validate(struct phy *phy, enum phy_mode mode,
>>> + int submode, union phy_configure_opts *opts)
>>> +{
>>> + const struct pre_pll_config *cfg = pre_pll_cfg_table;
>>> + unsigned long tmdsclock;
>>> +
>>> + if (!(mode == PHY_MODE_HDMI && submode == PHY_HDMI_MODE_TMDS))
>>> + return -EINVAL;
>>> +
>>> + if (!opts->hdmi.tmds_char_rate || opts->hdmi.tmds_char_rate > 594000000)
>>> + return -EINVAL;
>>
>> Sashiko reasoning log pointed out that a consumer of phy_validate() or
>> phy_configure() can make a call with opts=NULL, so I may likely send a
>> v4 of this series to fix such possible NULL pointer dereference here.
>
> Yes please
I will send a v4 that includes a NULL check, thanks.
>
>>
>> Or is that something that possible should be checked before phy core
>> calls the .validate()/.configure() ops?
>
> The opts is an optional argument depending upon the mode to be valid. So
> we cant do that in the core...
>
>>
>> Multiple other phy .configure() ops seem to dereference opts members
>> without any type of opts NULL check. (next-20260508)
>
> We should fix these
>
>
> PS: Any reason why you are sending encypted emails?
Hopefully you find a way to read this :-)
My email provider tries to be smart and encrypts any outgoing mail when
there is a PGP key published for a recipient in a Web Key Directory,
something that kernel.org has [2].
I raised an issue with the provider and was hoping that the change they
made [3] would fix the issue, and it looks like your published PGP key
is not sign-only and is in fact encryption-capable.
Will open a new issue and ask them to add some way to fully disable use
of automatic encryption on outgoing mails.
[2] https://www.kernel.org/category/signatures.html
[3] https://github.com/forwardemail/forwardemail.net/commit/88def5438a8da678252c234e876d3cdd469a8202
Regards,
Jonas
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* Re: [PATCH 3/5] phy: qualcomm: qmp-combo: Add preliminary USB4 support
From: sashiko-bot @ 2026-05-18 11:32 UTC (permalink / raw)
To: Konrad Dybcio
Cc: conor+dt, neil.armstrong, olteanv, linux-phy, vkoul, robh,
devicetree
In-Reply-To: <20260518-topic-usb4phy-v1-3-71d827c49dca@oss.qualcomm.com>
Thank you for your contribution! Sashiko AI review found 12 potential issue(s) to consider:
- [Critical] Accessing hardware registers before enabling regulators and clocks causes a system crash.
- [High] Unconditional dereference of the `pcs_aon` pointer in `qmp_combo_com_init()`.
- [High] Register mismatch when checking for an active DP tunnel breaks the DP PLL.
- [High] Incomplete masking of DP reset bits in `qmp_combo_com_init()` actively forces the DP PHY into reset.
- [High] Type-C mux events are permanently dropped before the PHY is initialized, breaking alt modes.
- [High] Double hardware initialization and `pipe_clk` reference leak in `qmp_combo_usb4_init()`.
- [High] Type-C cable orientation state is discarded for USB3 connections following a USB4 disconnect.
- [High] Error paths in `qmp_combo_usb4_init()` leak the `p2rr2p_pipe_clk` reference.
- [High] TOCTOU data race on `qmpphy_mode` and `orientation` in `qmp_combo_typec_switch_set()`.
- [High] Autonomous mode functions access unclocked `pcs_usb` registers, causing a hardware hang.
- [High] Missing lock in `qmp_combo_typec_mux_set()` leads to concurrent PHY reconfiguration races.
- [High] `init_count` underflows on error paths in `qmp_combo_com_init()` when `force` is true.
--
commit f92b7738f7f78a59373363a1b4f2191edf48f3e5
Author: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
phy: qualcomm: qmp-combo: Add preliminary USB4 support
This commit adds preliminary USB4 support for Qualcomm QMP combo PHYs,
introducing a new USB4 submode and handling mutually exclusive USB4 and
USB3/DP operation modes.
> diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c
> index 93f1aa10d4008..898f42de4a086 100644
> --- a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c
> +++ b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c
[ ... ]
> @@ -3691,14 +3691,26 @@ static int qmp_combo_com_init(struct qmp_combo *qmp, bool force)
> {
> const struct qmp_phy_cfg *cfg = qmp->cfg;
> + u32 dp_reset_val = SW_DPPHY_RESET_MUX | SW_DPPHY_RESET;
> void __iomem *com = qmp->com;
> void __iomem *pcs_aon = qmp->pcs_aon;
> + void __iomem *pcs = qmp->pcs;
> int ret;
> u32 val;
>
> if (!force && qmp->init_count++)
> return 0;
If force is true, this bypasses the init_count increment. However, if a
failure occurs later in the function (e.g., regulator_bulk_enable fails),
the error path jumps to err_decrement_count and executes qmp->init_count--.
Could this decrement a count that was never incremented, corrupting the
driver state?
>
> + if (qmp->qmpphy_mode == QMPPHY_MODE_USB4) {
> + pcs = qmp->usb4_pcs;
> +
> + qphy_setbits(pcs_aon, cfg->regs[QPHY_PCS_USB4_CLAMP_ENABLE], CLAMP_EN);
Could pcs_aon be NULL here? Other functions like
qmp_combo_enable_autonomous_mode() check if pcs_aon is valid before using it.
If a platform lacks this memory region in the device tree, will this cause a
kernel panic?
Can accessing these hardware registers before enabling regulators and clocks
cause a system crash? The readl() and qphy_setbits() are called before
regulator_bulk_enable() and clk_bulk_prepare_enable(). Accessing unpowered
or unclocked hardware domains often triggers a synchronous external abort.
> +
> + /* Do not disturb the DP PLL in case there's an active DP tunnel */
> + if (readl(com + QPHY_V3_DP_COM_RESET_OVRD_CTRL) & DP_TUNNELING_CLOCK_GEN_EN)
Does this read the wrong register? DP_TUNNELING_CLOCK_GEN_EN is defined as a
bit in QPHY_V3_DP_COM_PHY_MODE_CTRL, rather than QPHY_V3_DP_COM_RESET_OVRD_CTRL.
This might evaluate SW_USB3PHY_RESET_MUX instead, leading to incorrect DP reset
logic.
> + dp_reset_val &= ~SW_DPPHY_RESET_MUX;
> + }
Does this incomplete mask force the DP PHY into reset? dp_reset_val is
initially SW_DPPHY_RESET_MUX | SW_DPPHY_RESET, so this clears the mux bit
but leaves SW_DPPHY_RESET set to 1.
> +
> ret = regulator_bulk_enable(cfg->num_vregs, qmp->vregs);
[ ... ]
> @@ -3695,8 +3737,9 @@ static int qmp_combo_com_init(struct qmp_combo *qmp, bool force)
>
> /* override hardware control for reset of qmp phy */
> qphy_setbits(com, QPHY_V3_DP_COM_RESET_OVRD_CTRL,
> - SW_DPPHY_RESET_MUX | SW_DPPHY_RESET |
> - SW_USB3PHY_RESET_MUX | SW_USB3PHY_RESET);
> + dp_reset_val |
> + SW_USB3PHY_RESET_MUX | SW_USB3PHY_RESET |
> + SW_USB4PHY_RESET_MUX | SW_USB4PHY_RESET);
When this is applied, since qphy_setbits() performs a bitwise OR, it cannot
clear SW_DPPHY_RESET_MUX in the hardware if it was already 1. Combined with
SW_DPPHY_RESET still being 1 in dp_reset_val, won't this actively put the
DP PHY into reset and destroy the state it was intended to protect?
[ ... ]
> @@ -3991,6 +4098,119 @@ static int qmp_combo_usb_set_mode(struct phy *phy, enum phy_mode mode, int submo
[ ... ]
> +static int qmp_combo_usb4_init(struct phy *phy)
> +{
> + struct qmp_combo *qmp = phy_get_drvdata(phy);
> + int ret;
> +
> + guard(mutex)(&qmp->phy_mutex);
> +
> + if (!qmp->p2rr2p_pipe_clk) {
> + dev_err(qmp->dev, "missing p2rr2p_pipe clock handle. Update your Device Tree.\n");
> + return -EINVAL;
> + }
> +
> + ret = clk_prepare_enable(qmp->p2rr2p_pipe_clk);
> + if (ret) {
> + dev_err(qmp->dev, "p2rr2p_pipe enable failed: %d\n", ret);
> + return ret;
> + }
> +
> + ret = qmp_combo_com_init(qmp, false);
> + if (ret)
> + return ret;
Do the error paths in this function leak the p2rr2p_pipe_clk reference?
If qmp_combo_com_init(), qmp_combo_reconfigure_phy(), or
qmp_combo_usb_power_on() fail, the function returns directly without calling
clk_disable_unprepare() for p2rr2p_pipe_clk.
> +
> + /* USB4 mode takes precedence to USB3(+DP), force reconfigure the PHY */
> + ret = qmp_combo_reconfigure_phy(qmp, QMPPHY_MODE_USB4);
> + if (ret)
> + return ret;
> +
> + ret = qmp_combo_usb_power_on(phy);
Can this cause a double hardware initialization and leak the pipe_clk reference?
If the USB3 PHY is already active, qmp_combo_reconfigure_phy() internally
calls qmp_combo_usb_power_on(qmp->usb_phy). Immediately after, this function
unconditionally calls qmp_combo_usb_power_on(phy) a second time. This would
enable the hardware twice and increment the pipe_clk reference count twice,
but usb4_exit() only calls power_off once.
[ ... ]
> @@ -4037,9 +4264,12 @@ static void qmp_combo_enable_autonomous_mode(struct qmp_combo *qmp)
> * Enable i/o clamp_n for autonomous mode
> * V6 and later versions use pcs aon clamp register
> */
> - if (pcs_aon)
> - qphy_clrbits(pcs_aon, cfg->regs[QPHY_PCS_CLAMP_ENABLE], CLAMP_EN);
> - else if (pcs_misc)
> + if (pcs_aon) {
> + if (qmp->qmpphy_mode == QMPPHY_MODE_USB4)
> + qphy_clrbits(pcs_aon, cfg->regs[QPHY_PCS_USB4_CLAMP_ENABLE], CLAMP_EN);
> + else
> + qphy_clrbits(pcs_aon, cfg->regs[QPHY_PCS_CLAMP_ENABLE], CLAMP_EN);
> + } else if (pcs_misc)
> qphy_clrbits(pcs_misc, cfg->regs[QPHY_PCS_CLAMP_ENABLE], CLAMP_EN);
> }
In USB4 mode, qmp_combo_com_init() does not clear SW_USB3PHY_RESET, leaving
the USB3 PCS block in hardware reset. However,
qmp_combo_enable_autonomous_mode() unconditionally accesses pcs_usb registers
earlier in the function (e.g., QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR). Will
accessing an IP block held in reset cause an external abort?
[ ... ]
> @@ -4427,24 +4660,29 @@ static int qmp_combo_typec_switch_set(struct typec_switch_dev *sw,
> struct qmp_combo *qmp = typec_switch_get_drvdata(sw);
> const struct qmp_phy_cfg *cfg = qmp->cfg;
>
> + if (qmp->qmpphy_mode == QMPPHY_MODE_USB4) {
> + /* QMPPHY has no orientation handling in USB4 mode, don't cache the setting */
> + qmp->orientation = TYPEC_ORIENTATION_NONE;
> + return 0;
> + }
> +
> if (orientation == qmp->orientation || orientation == TYPEC_ORIENTATION_NONE)
> return 0;
>
> - mutex_lock(&qmp->phy_mutex);
> + guard(mutex)(&qmp->phy_mutex);
Is there a data race here? The check for qmp->qmpphy_mode and the
modification of qmp->orientation are performed before acquiring
qmp->phy_mutex. If an orientation switch event races with
qmp_combo_usb4_init() modifying qmpphy_mode, switch_set could read a stale
mode and enter the critical section to execute a full PHY reset while the
USB4 router is actively using it.
Also, if a USB4 device is unplugged, usb4_exit is called but qmpphy_mode
remains QMPPHY_MODE_USB4. If a USB3 device is then plugged in, switch_set()
is typically called before mux_set(). Because it sees the stale USB4 mode,
it drops the valid orientation and forces TYPEC_ORIENTATION_NONE.
When mux_set() is subsequently called, it configures USB3 with no orientation.
Will this cause enumeration to fail if the Type-C cable is flipped?
[ ... ]
> @@ -4495,41 +4755,11 @@ static int qmp_combo_typec_mux_set(struct typec_mux_dev *mux, struct typec_mux_s
[ ... ]
> + /* The mux still receives Type-C events, even if all PHYs are uninitialized */
> + if (!qmp->init_count)
> + return 0;
>
> - return 0;
> + return qmp_combo_reconfigure_phy(qmp, new_mode);
> }
Does this early return break alt modes by dropping Type-C events? It
bypasses saving the requested mode (qmp->qmpphy_mode = new_mode). Since
Type-C events often arrive before the USB controller initializes the PHY,
the requested mode is lost. When phy_init() is later called, it will
initialize with the stale default mode, breaking USB3 or DP routing.
Additionally, qmp_combo_reconfigure_phy() is called here without acquiring
qmp->phy_mutex. Concurrently, qmp_combo_usb4_init() uses the mutex and also
calls qmp_combo_reconfigure_phy(). Doesn't this lack of synchronization
permit concurrent execution of PHY hardware power down/up sequences,
potentially corrupting register states?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260518-topic-usb4phy-v1-0-71d827c49dca@oss.qualcomm.com?part=3
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* Re: [PATCH 4/5] phy: qualcomm: qmp-combo: Add USB4/TBT3 configuration data for Hamoa
From: sashiko-bot @ 2026-05-18 11:49 UTC (permalink / raw)
To: Konrad Dybcio
Cc: olteanv, linux-phy, devicetree, conor+dt, robh, neil.armstrong,
vkoul
In-Reply-To: <20260518-topic-usb4phy-v1-4-71d827c49dca@oss.qualcomm.com>
Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
- [Low] Incorrect `TX_` prefix for RX UCDR fastlock registers.
- [Low] Typo in register macro name: `LPFS` instead of `LFPS`.
- [Low] Redundant `PCS_PCS` prefix in register macro name.
- [Low] Missing `_N4_` infix in the `QSERDES_V6_TX_LDO_TIMER_CTRL` macro.
--
commit 13a3731f3b7c12c298d2f498011a7ef852fd4a42
Author: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
phy: qualcomm: qmp-combo: Add USB4/TBT3 configuration data for Hamoa
This commit adds the offsets and configuration tables to support USB4
and Thunderbolt 3 operation on the USB4-capable PHYs found on Hamoa chips.
> diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c
> index 898f42de4a086..0916d9a4599ed 100644
> --- a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c
> +++ b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c
[ ... ]
> @@ -1873,6 +1952,68 @@ static const struct qmp_phy_init_tbl x1e80100_usb43dp_tx_tbl[] = {
> [ ... ]
> +static const struct qmp_phy_init_tbl x1e80100_usb4_rx_tbl[] = {
> [ ... ]
> + QMP_PHY_INIT_CFG(QSERDES_V6_N4_TX_UCDR_FASTLOCK_COUNTER_LOW_RATE2, 0x30),
> + QMP_PHY_INIT_CFG(QSERDES_V6_N4_TX_UCDR_FASTLOCK_COUNTER_HIGH_RATE2, 0x14),
> + QMP_PHY_INIT_CFG(QSERDES_V6_N4_TX_UCDR_FASTLOCK_COUNTER_LOW_RATE3, 0xff),
> + QMP_PHY_INIT_CFG(QSERDES_V6_N4_TX_UCDR_FASTLOCK_COUNTER_HIGH_RATE3, 0x3f),
This isn't a bug, but should these use the RX_ prefix instead of TX_?
These registers appear to map to the RX block address space and are used
here to configure the RX hardware.
[ ... ]
> diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-usb-v6.h b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-usb-v6.h
> index df670143feb1e..30fdb437146c4 100644
> --- a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-usb-v6.h
> +++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-usb-v6.h
> @@ -14,4 +14,19 @@
> #define QPHY_V6_PCS_USB3_RCVR_DTCT_DLY_U3_L 0x40
> #define QPHY_V6_PCS_USB3_RCVR_DTCT_DLY_U3_H 0x44
>
> +#define QPHY_V6_PCS_USB4_POWER_STATE_CONFIG3 0x98
> [ ... ]
> +#define QPHY_V6_PCS_USB4_PCS_PCS_TX_RX_CONFIG1 0x1a8
This isn't a bug, but is there a duplicate PCS_ prefix in this macro name?
> +#define QPHY_V6_PCS_USB4_EQ_CONFIG1 0x1b8
> [ ... ]
> +#define QPHY_V6_PCS_USB4_LPFS_TX_ECSTART 0x220
This isn't a bug, but is this a typo for LFPS (Low Frequency Periodic
Signaling)?
[ ... ]
> diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v6_n4.h b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v6_n4.h
> index d37cc0d4fd365..e72ae2cb460ac 100644
> --- a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v6_n4.h
> +++ b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v6_n4.h
> @@ -23,27 +23,63 @@
> [ ... ]
> #define QSERDES_V6_N4_TX_VMODE_CTRL1 0xb0
> +#define QSERDES_V6_TX_LDO_TIMER_CTRL 0x120
This isn't a bug, but should this macro include the _N4_ infix for
consistency with the rest of the V6 N4 block definitions?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260518-topic-usb4phy-v1-0-71d827c49dca@oss.qualcomm.com?part=4
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* Re: [PATCH 3/4] arm64: dts: qcom: Add Shikra CQM SoM platform
From: Kamal Wadhwa @ 2026-05-18 11:49 UTC (permalink / raw)
To: Dmitry Baryshkov
Cc: Rakesh Kota, linux-arm-msm, sashiko-reviews, Komal Bajaj, robh,
linux-phy, neil.armstrong, vkoul, olteanv, krzk+dt, conor+dt,
devicetree
In-Reply-To: <obdxony34ckfbtsqj66siszw44sgieskcye5hg66ulkisctpwl@fyqczpze5tnw>
On Sun, May 17, 2026 at 08:18:15PM +0300, Dmitry Baryshkov wrote:
> On Thu, May 14, 2026 at 04:09:18PM +0530, Kamal Wadhwa wrote:
> > On Wed, May 13, 2026 at 06:14:20PM +0300, Dmitry Baryshkov wrote:
> > > On 13/05/2026 17:29, Rakesh Kota wrote:
> > > > On Wed, May 13, 2026 at 03:01:47PM +0300, Dmitry Baryshkov wrote:
> > > > > On Wed, May 13, 2026 at 04:28:35AM +0000, sashiko-bot@kernel.org wrote:
> > > > > > Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
> > > > > > - [High] The PMIC regulator definitions omit their required input supply dependencies (e.g., `vdd_s2-supply`, `vdd_l3-supply`), breaking the power hierarchy.
> > > > > > - [Medium] The device tree inaccurately hardcodes the `compatible` string to a different PMIC model (`qcom,rpm-pm2250-regulators`) instead of explicitly identifying the actual hardware (PM4125).
> > > > > > --
> > > > > >
> > > > > > commit 457abf6e7ac410430c866842e08e602ec3daaa51
> > > > > > Author: Komal Bajaj <komal.bajaj@oss.qualcomm.com>
> > > > > >
> > > > > > arm64: dts: qcom: Add Shikra CQM SoM platform
> > > > > >
> > > > > > Add device tree include for the CQM variant of the Shikra System-on-Module.
> > > > > > This variant integrates the Shikra SoC and PM4125 PMIC. The DTSI includes
> > > > > > the common shikra.dtsi and adds PM4125 PMIC regulator definitions.
> > > > > >
> > > > > > > diff --git a/arch/arm64/boot/dts/qcom/shikra-cqm-som.dtsi b/arch/arm64/boot/dts/qcom/shikra-cqm-som.dtsi
> > > > > > > new file mode 100644
> > > > > > > index 0000000000000..401e71720519d
> > > > > > > --- /dev/null
> > > > > > > +++ b/arch/arm64/boot/dts/qcom/shikra-cqm-som.dtsi
> > > > > > [ ... ]
> > > > > > > +&rpm_requests {
> > > > > > > + regulators {
> > > > > > > + compatible = "qcom,rpm-pm2250-regulators";
> > > > > >
> > > > > > Since the commit message indicates this is a PM4125 PMIC, should the
> > > > > > compatible string include a specific identifier for the actual hardware?
> > > > > >
> > > > > > Using a specific identifier like "qcom,rpm-pm4125-regulators" alongside
> > > > > > the fallback allows the kernel to apply specific quirks if PM4125 errata
> > > > > > are discovered later.
> > > > >
> > > > > This can be ignored. The compat is a leftover from the historically
> > > > > incorrect naming.
> > > > >
> > > > > >
> > > > > > > +
> > > > > > > + pm4125_s2: s2 {
> > > > > > > + regulator-min-microvolt = <1000000>;
> > > > > > > + regulator-max-microvolt = <1200000>;
> > > > > > > + };
> > > > > >
> > > > > > Do these regulators need to explicitly define their input supply dependencies
> > > > > > such as vdd_s2-supply?
> > > > > >
> > > > > > Without these properties, the regulator framework might be unaware that the
> > > > > > PMIC regulators draw power from upstream supplies.
> > > > > >
> > > > > > If the kernel dynamically manages the upstream supply and its reference count
> > > > > > drops to zero, could it be disabled, causing an unexpected power loss for
> > > > > > downstream components?
> > > > >
> > > > > And this is a correct comment. Please provide missing supplies.
> > > > >
> > > > As per the Qualcomm system design, the parent-child supply relationship
> > > > is managed by the RPM firmware, not the Linux regulator framework. The
> > > > RPM ensures the parent supply is never disabled until all subsystem
> > > > votes are cleared.
> > >
> > > How is this different from other, previous platforms?
> >
> > This is not different. In the previous platforms too this is taken care from the
> > RPM/RPMH firmware side, the only case where we may need explicit vote to parent
> > is for non-rpmh/rpm regulator rails (like i2c based regulator pm8008), which
> > may have a RPM/RPMH regulator as a parent.
> >
> > Even on those previous targets the parent rail of all RPM/RPMH regulators are
> > internally voted by RPM/RPMH FW at proper voltage with required headroom
> > calculated based on the active child rails. This was done for all the
> > subsystems (including APPS) regulators.
> >
> > So no explicit handling from the APPS is required for parent supply.
>
> You are explaining the driver behaviour. But the question is about the
> hardware description. If there is no difference, please add necessary
> supplies back.
I understand your concern about descibing the parent-child relation in the
devicetree, and given that we have been almost always followed this for all
the previous targets, it will expected of us to add them.
However, we want to avoid the unnecessary access to the parent from APPS.
At the moment, I do not see a way to avoid that, if we add the parent
regulators.
@Bjorn, @Konrad - can you please also share your suggestion, how we can add
parent-child desciption, but avoid accessing parent supply from APPS, as its
Qualcomm's system design to handle this on RPM/RPMH firmware side (you may
recall we had a verbal/offline discussion about same concern in context of
RPMH regulators earlier).
Regards,
Kamal
>
> --
> With best wishes
> Dmitry
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* Re: [PATCH v1 3/6] dt-bindings: net: Document Infineon/Intel XMM6260 modem
From: Krzysztof Kozlowski @ 2026-05-18 12:04 UTC (permalink / raw)
To: Svyatoslav Ryhel
Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Vinod Koul, Neil Armstrong, Thierry Reding, Jonathan Hunter,
Greg Kroah-Hartman, Peter Chen, netdev, devicetree, linux-kernel,
linux-phy, linux-tegra, linux-usb
In-Reply-To: <CAPVz0n3mvBLracMWGNuJ8kKUvAVZ+JRTJVkZGyq5MkuSobd8NQ@mail.gmail.com>
On Fri, May 15, 2026 at 11:39:49AM +0300, Svyatoslav Ryhel wrote:
> пт, 15 трав. 2026 р. о 11:18 Krzysztof Kozlowski <krzk@kernel.org> пише:
> >
> > On Mon, May 11, 2026 at 04:56:58PM +0300, Svyatoslav Ryhel wrote:
> > > + ap-wake-gpios:
> > > + description: GPIO connected to the EINT3 pin
> > > + maxItems: 1
> > > +
> > > + cp-wake-gpios:
> > > + description: GPIO connected to the EINT2 pin
> > > + maxItems: 1
> > > +
> > > + phys:
> > > + maxItems: 1
> > > +
> > > + vbat-supply:
> > > + description: Supply connected to the VBAT lines.
> >
> > This should be rather name of the pin on this device, not the provider
> > name. VBAT suggests the latter. Please double check.
> >
>
> There is no documentation on this device from Infineon, I have used
> schematics of the P895 where this modem is used. According to it power
> supply is connected to pin with name VBAT (and yes, I am not mixing it
> up since supplies have different names)
ack
Best regards,
Krzysztof
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* Re: [PATCH v1 5/6] dt-bindings: phy: tegra: Document Nvidia Tegra XMM6260 PHY
From: Krzysztof Kozlowski @ 2026-05-18 12:14 UTC (permalink / raw)
To: Svyatoslav Ryhel
Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Vinod Koul, Neil Armstrong, Thierry Reding, Jonathan Hunter,
Greg Kroah-Hartman, Peter Chen, netdev, devicetree, linux-kernel,
linux-phy, linux-tegra, linux-usb
In-Reply-To: <CAPVz0n2wrAdU0JKx7eb7uosCcoGayqNchK591VPph-5_nBAMXg@mail.gmail.com>
On Fri, May 15, 2026 at 11:37:34AM +0300, Svyatoslav Ryhel wrote:
> пт, 15 трав. 2026 р. о 11:20 Krzysztof Kozlowski <krzk@kernel.org> пише:
> >
> > On Mon, May 11, 2026 at 04:57:00PM +0300, Svyatoslav Ryhel wrote:
> > > Document the XMM6260 PHY used by various devices based on the Nvidia Tegra
> > > SoC, describing its usage
> > >
> > > Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> > > ---
> > > .../bindings/phy/nvidia,tegra-xmm6260.yaml | 58 +++++++++++++++++++
> > > 1 file changed, 58 insertions(+)
> > > create mode 100644 Documentation/devicetree/bindings/phy/nvidia,tegra-xmm6260.yaml
> > >
> > > diff --git a/Documentation/devicetree/bindings/phy/nvidia,tegra-xmm6260.yaml b/Documentation/devicetree/bindings/phy/nvidia,tegra-xmm6260.yaml
> > > new file mode 100644
> > > index 000000000000..0346433c9772
> > > --- /dev/null
> > > +++ b/Documentation/devicetree/bindings/phy/nvidia,tegra-xmm6260.yaml
> > > @@ -0,0 +1,58 @@
> > > +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
> > > +%YAML 1.2
> > > +---
> > > +$id: http://devicetree.org/schemas/phy/nvidia,tegra-xmm6260.yaml#
> > > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > > +
> > > +title: Nvidia Tegra PHY for XMM6260 modem
> >
> > XMM6260 is Infineon modem, so any combination with nvidia,tegra is very
> > confusing.
> >
>
> May you please suggest how to adjust the name then? Thank you.
Depending what is that. Start describing hardware, not driver behavior
to help in that.
>
> > > +
> > > +description:
> > > + A hardware configuration used in Tegra SoCs to provide proper interaction
> > > + between the application processor and the modem, as well as control over
> > > + one of the SoC's USB lines for the modem.
> > > +
> > > +maintainers:
> > > + - Svyatoslav Ryhel <clamor95@gmail.com>
> > > +
> > > +properties:
> > > + compatible:
> > > + const: nvidia,tegra-xmm6260
> >
> > Also here.
> >
> > What sort of phy is this? So far looks more like a software construct.
> >
>
> Infineon XMM6260 does not work as an ordinary USB modem, it is a
> standalone CPU which just exposes itself to AP via USB. In order to do
> so, it has to have control over a USB bus of AP which is dedicated to
> it. In case of Tegra - XMM6260 interaction it looks like this: second
> Tegra USB controller is set into HSIC mode and is dedicated solely to
> the modem, modem controls this USB bus. Then the main XMM6260 driver
> performs power and init sequence and once it is ready it calls phy to
> register controller. Phy has its own supply, controls USB controller
> de/register and using enable GPIO sends signal to modem to proceed.
> Additionally, since some XMM626 versions have a few steps to setup
> exposing different USB devices, phy handles controller reinit for each
> step. If treat XMM6260 as an simple USB modem it will never init.
>
> One more benefit of having PHY is that modem driver itself is generic
> and PHY handles SoC specific configurations required by the modem.
> Since this modem was used on a variety of different SoC's (Exynos and
> OMAP for example) they can reuse modem's driver and provide only PHY
> which handles modem interactions with the USB bus.
Without any registers here, this is not a PHY but a power sequencing,
just like we do for other USB or PCI devices.
Optionally, it could be part of existing USB phy, when configuring it in
HSIC mode, but it seems you add here supplies for the modem, not actual
phy as the phy is undefined.
The problem is that in the patch and explanation you mix driver model
and driver behavior, so I really don't know what is this hardware. And
it is not my job to guess, btw. A partial argument/proof why this is not
a PHY, is that you reference the USB in the node, so phy-provider
references the phy-consumer. That's reverse. If this is PHY, it's USB's
HSIC phy, thus this needs to be referenced by USB.
If this is power sequencing, then it can be represented as USB device,
just like we do for all USB devices, but then it is not PHY and
phy-cells are not appropriate.
Best regards,
Krzysztof
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* Re: [PATCH v1 5/6] dt-bindings: phy: tegra: Document Nvidia Tegra XMM6260 PHY
From: Svyatoslav Ryhel @ 2026-05-18 12:23 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Vinod Koul, Neil Armstrong, Thierry Reding, Jonathan Hunter,
Greg Kroah-Hartman, Peter Chen, netdev, devicetree, linux-kernel,
linux-phy, linux-tegra, linux-usb
In-Reply-To: <20260518-mustard-rabbit-of-ecstasy-eed3b6@quoll>
пн, 18 трав. 2026 р. о 15:14 Krzysztof Kozlowski <krzk@kernel.org> пише:
>
> On Fri, May 15, 2026 at 11:37:34AM +0300, Svyatoslav Ryhel wrote:
> > пт, 15 трав. 2026 р. о 11:20 Krzysztof Kozlowski <krzk@kernel.org> пише:
> > >
> > > On Mon, May 11, 2026 at 04:57:00PM +0300, Svyatoslav Ryhel wrote:
> > > > Document the XMM6260 PHY used by various devices based on the Nvidia Tegra
> > > > SoC, describing its usage
> > > >
> > > > Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> > > > ---
> > > > .../bindings/phy/nvidia,tegra-xmm6260.yaml | 58 +++++++++++++++++++
> > > > 1 file changed, 58 insertions(+)
> > > > create mode 100644 Documentation/devicetree/bindings/phy/nvidia,tegra-xmm6260.yaml
> > > >
> > > > diff --git a/Documentation/devicetree/bindings/phy/nvidia,tegra-xmm6260.yaml b/Documentation/devicetree/bindings/phy/nvidia,tegra-xmm6260.yaml
> > > > new file mode 100644
> > > > index 000000000000..0346433c9772
> > > > --- /dev/null
> > > > +++ b/Documentation/devicetree/bindings/phy/nvidia,tegra-xmm6260.yaml
> > > > @@ -0,0 +1,58 @@
> > > > +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
> > > > +%YAML 1.2
> > > > +---
> > > > +$id: http://devicetree.org/schemas/phy/nvidia,tegra-xmm6260.yaml#
> > > > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > > > +
> > > > +title: Nvidia Tegra PHY for XMM6260 modem
> > >
> > > XMM6260 is Infineon modem, so any combination with nvidia,tegra is very
> > > confusing.
> > >
> >
> > May you please suggest how to adjust the name then? Thank you.
>
> Depending what is that. Start describing hardware, not driver behavior
> to help in that.
>
> >
> > > > +
> > > > +description:
> > > > + A hardware configuration used in Tegra SoCs to provide proper interaction
> > > > + between the application processor and the modem, as well as control over
> > > > + one of the SoC's USB lines for the modem.
> > > > +
> > > > +maintainers:
> > > > + - Svyatoslav Ryhel <clamor95@gmail.com>
> > > > +
> > > > +properties:
> > > > + compatible:
> > > > + const: nvidia,tegra-xmm6260
> > >
> > > Also here.
> > >
> > > What sort of phy is this? So far looks more like a software construct.
> > >
> >
> > Infineon XMM6260 does not work as an ordinary USB modem, it is a
> > standalone CPU which just exposes itself to AP via USB. In order to do
> > so, it has to have control over a USB bus of AP which is dedicated to
> > it. In case of Tegra - XMM6260 interaction it looks like this: second
> > Tegra USB controller is set into HSIC mode and is dedicated solely to
> > the modem, modem controls this USB bus. Then the main XMM6260 driver
> > performs power and init sequence and once it is ready it calls phy to
> > register controller. Phy has its own supply, controls USB controller
> > de/register and using enable GPIO sends signal to modem to proceed.
> > Additionally, since some XMM626 versions have a few steps to setup
> > exposing different USB devices, phy handles controller reinit for each
> > step. If treat XMM6260 as an simple USB modem it will never init.
> >
> > One more benefit of having PHY is that modem driver itself is generic
> > and PHY handles SoC specific configurations required by the modem.
> > Since this modem was used on a variety of different SoC's (Exynos and
> > OMAP for example) they can reuse modem's driver and provide only PHY
> > which handles modem interactions with the USB bus.
>
> Without any registers here, this is not a PHY but a power sequencing,
> just like we do for other USB or PCI devices.
>
> Optionally, it could be part of existing USB phy, when configuring it in
> HSIC mode, but it seems you add here supplies for the modem, not actual
> phy as the phy is undefined.
>
> The problem is that in the patch and explanation you mix driver model
> and driver behavior, so I really don't know what is this hardware. And
> it is not my job to guess, btw. A partial argument/proof why this is not
> a PHY, is that you reference the USB in the node, so phy-provider
> references the phy-consumer. That's reverse. If this is PHY, it's USB's
> HSIC phy, thus this needs to be referenced by USB.
>
> If this is power sequencing, then it can be represented as USB device,
> just like we do for all USB devices, but then it is not PHY and
> phy-cells are not appropriate.
>
If I integrate USB controller reference into the modem, modem will not
be generic since Exynos and OMAP don't use Chipidea USB controller
(both those SoC use this modem). Modem has to control USB controllers
init and deinit in order to operate properly. I have tried to resolve
this with PHY but if you find this inappropriate, maybe you can
suggest better suited way?
>
> Best regards,
> Krzysztof
>
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* Re: [PATCH 2/5] phy: core: Define TBT phy_mode
From: Dmitry Baryshkov @ 2026-05-18 12:25 UTC (permalink / raw)
To: Konrad Dybcio
Cc: Vinod Koul, Neil Armstrong, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Bjorn Andersson, linux-kernel, linux-phy,
linux-arm-msm, devicetree, usb4-upstream, Raghavendra Thoorpu,
Mika Westerberg, Sven Peter, Konrad Dybcio
In-Reply-To: <20260518-topic-usb4phy-v1-2-71d827c49dca@oss.qualcomm.com>
On Mon, May 18, 2026 at 12:29:49PM +0200, Konrad Dybcio wrote:
> From: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
>
> There exist OS-accessible USB4 and Thunderbolt PHYs that need specific
> configuration. Define a new phy_mode for them.
>
> Currently, USB4 and TBT3 are defined as submodes, because they're quite
> distinct, most visibly in the electrical/analog aspects (slightly
> different frequencies, timings, etc.). This results in a need to make
> the PHY aware of the actual mode needed (at least in the Qualcomm
> implementation, but I believe that'll be a general need).
>
> Newer versions of TBT are basically supersets of USB4 with higher
> host-side requirements, so these are not defined. This can always be
> changed as necessary.
>
> Signed-off-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
> ---
> include/linux/phy/phy-tbt.h | 14 ++++++++++++++
> include/linux/phy/phy.h | 2 ++
> 2 files changed, 16 insertions(+)
>
> diff --git a/include/linux/phy/phy-tbt.h b/include/linux/phy/phy-tbt.h
> new file mode 100644
> index 000000000000..5f48059814e1
> --- /dev/null
> +++ b/include/linux/phy/phy-tbt.h
> @@ -0,0 +1,14 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
> + */
> +
> +#ifndef __PHY_TBT_H_
> +#define __PHY_TBT_H_
> +
> +enum tbt_phy_submode {
> + PHY_SUBMODE_TBT3,
> + PHY_SUBMODE_USB4,
Do we need TBT2 as a separate submode?
Other than that:
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
> +};
--
With best wishes
Dmitry
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* Re: [PATCH 2/5] phy: core: Define TBT phy_mode
From: Konrad Dybcio @ 2026-05-18 12:29 UTC (permalink / raw)
To: Dmitry Baryshkov, Konrad Dybcio
Cc: Vinod Koul, Neil Armstrong, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Bjorn Andersson, linux-kernel, linux-phy,
linux-arm-msm, devicetree, usb4-upstream, Raghavendra Thoorpu,
Mika Westerberg, Sven Peter
In-Reply-To: <5kwr2cbi3swgvjrzyqxa36rk2jnjlivgsw242shd3s4zbbdv5u@x3qvxkt2xm6x>
On 5/18/26 2:25 PM, Dmitry Baryshkov wrote:
> On Mon, May 18, 2026 at 12:29:49PM +0200, Konrad Dybcio wrote:
>> From: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
>>
>> There exist OS-accessible USB4 and Thunderbolt PHYs that need specific
>> configuration. Define a new phy_mode for them.
>>
>> Currently, USB4 and TBT3 are defined as submodes, because they're quite
>> distinct, most visibly in the electrical/analog aspects (slightly
>> different frequencies, timings, etc.). This results in a need to make
>> the PHY aware of the actual mode needed (at least in the Qualcomm
>> implementation, but I believe that'll be a general need).
>>
>> Newer versions of TBT are basically supersets of USB4 with higher
>> host-side requirements, so these are not defined. This can always be
>> changed as necessary.
>>
>> Signed-off-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
>> ---
>> include/linux/phy/phy-tbt.h | 14 ++++++++++++++
>> include/linux/phy/phy.h | 2 ++
>> 2 files changed, 16 insertions(+)
>>
>> diff --git a/include/linux/phy/phy-tbt.h b/include/linux/phy/phy-tbt.h
>> new file mode 100644
>> index 000000000000..5f48059814e1
>> --- /dev/null
>> +++ b/include/linux/phy/phy-tbt.h
>> @@ -0,0 +1,14 @@
>> +/* SPDX-License-Identifier: GPL-2.0 */
>> +/*
>> + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
>> + */
>> +
>> +#ifndef __PHY_TBT_H_
>> +#define __PHY_TBT_H_
>> +
>> +enum tbt_phy_submode {
>> + PHY_SUBMODE_TBT3,
>> + PHY_SUBMODE_USB4,
>
> Do we need TBT2 as a separate submode?
I would like to avoid extending that unless there's a user for it
Konrad
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* Re: [PATCH 3/5] phy: qualcomm: qmp-combo: Add preliminary USB4 support
From: Dmitry Baryshkov @ 2026-05-18 13:57 UTC (permalink / raw)
To: Konrad Dybcio
Cc: Vinod Koul, Neil Armstrong, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Bjorn Andersson, linux-kernel, linux-phy,
linux-arm-msm, devicetree, usb4-upstream, Raghavendra Thoorpu,
Mika Westerberg, Sven Peter, Konrad Dybcio
In-Reply-To: <20260518-topic-usb4phy-v1-3-71d827c49dca@oss.qualcomm.com>
On Mon, May 18, 2026 at 12:29:50PM +0200, Konrad Dybcio wrote:
> From: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
>
> Some Combo PHYs (so far only on SC8280XP, X1E80100 and Glymur), come in
> a flavor called USB43DP, which as the name implies, features USB4, USB3
> and DP signal processing capabilities. In that architecture, USB3 and
> USB4 PHYs share the same USB_PLL while featuring separate logic spaces.
> The DP part is roughly the same as on the instances without USB4.
>
> The USB4 and USB3/DP operation modes of the PHY are mutually exclusive.
> Only one USB protocol (and flavor of pipe clock) can be active at a
> given moment (not to be confused with USB3 not being able to be
> tunneled as USB4 packets - that of course remains possible).
> The DP PLL is still used for clocking tunneled DP links. It may be
> turned off to save power when no tunnels are active, but that's left as
> a TODO item for now.
>
> Due to the nature of USB4, the Type-C handling happens entirely inside
> the Host Router, and as such the QMPPHY's mux_set() function is
> nullified for the period when USB4 PHY remains active. This is strictly
> necessary, as the Host Router driver is going to excercise manual
> control over the USB4 PHY's power state, which is needed by the suspend
> and resume flows. Failure to control that synchronously with other
> parts of the code results in a SoC crash by unlocked access.
>
> Because of that, a new struct phy is spawned to expose the USB4 mode,
> along with a .set_mode callback to allow toggling between USB4 and TBT3
> submodes.
>
> Thunderbolt 3, having a number of differences vs USB4, requires a
> couple specific overrides, pertaining to electrical characteristics,
> which are easily accommodated for.
>
> Signed-off-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
> ---
> drivers/phy/qualcomm/phy-qcom-qmp-combo.c | 392 ++++++++++++++++++++++++------
> 1 file changed, 322 insertions(+), 70 deletions(-)
>
Overall it looks good. The major question (after looking at TODOs), do
we need a separate submode for USB+DP / TBT+DP?
--
With best wishes
Dmitry
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* [PATCH 0/2] Add support for EcoNet USB PHY
From: Caleb James DeLisle @ 2026-05-18 14:13 UTC (permalink / raw)
To: linux-mips
Cc: vkoul, neil.armstrong, robh, krzk+dt, conor+dt, linux-phy,
devicetree, linux-kernel, Caleb James DeLisle
Add support for the USB PHY found on EcoNet EN751221, EN751627, and
EN7528.
Caleb James DeLisle (2):
dt-bindings: phy: econet: Document EN751221 USB PHY
phy: econet: Add EcoNet USB PHY
.../bindings/phy/econet,en751221-usb-phy.yaml | 128 ++++
MAINTAINERS | 7 +
drivers/phy/Kconfig | 13 +
drivers/phy/Makefile | 1 +
drivers/phy/phy-econet-usb.c | 558 ++++++++++++++++++
5 files changed, 707 insertions(+)
create mode 100644 Documentation/devicetree/bindings/phy/econet,en751221-usb-phy.yaml
create mode 100644 drivers/phy/phy-econet-usb.c
base-commit: e98d21c170b01ddef366f023bbfcf6b31509fa83
--
2.39.5
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* [PATCH 1/2] dt-bindings: phy: econet: Document EN751221 USB PHY
From: Caleb James DeLisle @ 2026-05-18 14:13 UTC (permalink / raw)
To: linux-mips
Cc: vkoul, neil.armstrong, robh, krzk+dt, conor+dt, linux-phy,
devicetree, linux-kernel, Caleb James DeLisle
In-Reply-To: <20260518141343.401555-1-cjd@cjdns.fr>
Document the USB PHY devices which appear in EcoNet EN751221, EN751627,
and EN7528 based SoCs.
Signed-off-by: Caleb James DeLisle <cjd@cjdns.fr>
---
.../bindings/phy/econet,en751221-usb-phy.yaml | 128 ++++++++++++++++++
MAINTAINERS | 6 +
2 files changed, 134 insertions(+)
create mode 100644 Documentation/devicetree/bindings/phy/econet,en751221-usb-phy.yaml
diff --git a/Documentation/devicetree/bindings/phy/econet,en751221-usb-phy.yaml b/Documentation/devicetree/bindings/phy/econet,en751221-usb-phy.yaml
new file mode 100644
index 000000000000..a44f59601747
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/econet,en751221-usb-phy.yaml
@@ -0,0 +1,128 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+# Copyright (C) 2024 EcoNet
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/phy/econet,en751221-usb-phy.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: EcoNet EN751221 USB PHY
+
+maintainers:
+ - Caleb James DeLisle <cjd@cjdns.fr>
+
+description: |
+ USB PHY controller found on EcoNet EN751221 SoCs as well as on EN751627 and
+ EN7528. These devices generally have two ports, one of which is a USB 3.0,
+ and the other is USB 2.0. The USB 3.0 port is driven by one of two PHY
+ blocks, depending on whether the connected device has negotiated USB 3.0 or
+ 2.0. These PHYs are also used on other EcoNet silicon in varying
+ configurations, such as only port 0 (the USB 3.0 port), or only port 1 (the
+ USB 2.0 port).
+
+properties:
+ compatible:
+ enum:
+ - econet,en751221-usb-phy
+ - econet,en751627-usb-phy
+ - econet,en7528-usb-phy
+
+ reg:
+ maxItems: 1
+
+ "#address-cells": true
+ "#size-cells": true
+ ranges: true
+
+ clocks:
+ maxItems: 1
+ description: |
+ Crystal oscillator clock source. EcoNet devices run at either 20Mhz or
+ 25Mhz. 25Mhz devices require additional tuning in the USB 3.0 PHY.
+
+ clock-names:
+ items:
+ - const: xtal
+
+patternProperties:
+ "^usb-phy@[0-9a-f]+$":
+ type: object
+ description: USB 2.0 or 3.0 PHY sub-node.
+
+ properties:
+ compatible:
+ enum:
+ - econet,usb2-phy
+ - econet,usb3-phy
+
+ reg:
+ maxItems: 1
+
+ resets:
+ maxItems: 1
+
+ econet,usb-port-id:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ enum: [0, 1]
+ description: |
+ Physical port number. Since USB 3.0 requires a second PHY for the 2.0
+ fallback, multiple PHYs can map to the same physical port.
+
+ "#phy-cells":
+ const: 0
+
+ required:
+ - compatible
+ - reg
+ - econet,usb-port-id
+ - "#phy-cells"
+
+ additionalProperties: false
+
+required:
+ - compatible
+ - reg
+ - "#address-cells"
+ - "#size-cells"
+ - ranges
+ - clocks
+ - clock-names
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/reset/econet,en751221-scu.h>
+
+ usb-phy@1fa80000 {
+ compatible = "econet,en751221-usb-phy";
+ reg = <0x1fa80000 0x700>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+ clocks = <&xtalclk>;
+ clock-names = "xtal";
+
+ usb-phy@1fa80800 {
+ compatible = "econet,usb2-phy";
+ reg = <0x1fa80800 0x100>;
+ resets = <&scuclk EN751221_USB_PHY_P0_RST>;
+ econet,usb-port-id = <0>;
+ #phy-cells = <0>;
+ };
+
+ usb-phy@1fa80900 {
+ compatible = "econet,usb3-phy";
+ reg = <0x1fa80900 0x700>;
+ resets = <&scuclk EN751221_USB_PHY_P0_RST>;
+ econet,usb-port-id = <0>;
+ #phy-cells = <0>;
+ };
+
+ usb-phy@1fa81000 {
+ compatible = "econet,usb2-phy";
+ reg = <0x1fa81000 0x100>;
+ resets = <&scuclk EN751221_USB_PHY_P1_RST>;
+ econet,usb-port-id = <1>;
+ #phy-cells = <0>;
+ };
+ };
diff --git a/MAINTAINERS b/MAINTAINERS
index f877e5aaf2c7..1a90a1736294 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -9204,6 +9204,12 @@ F: drivers/irqchip/irq-econet-en751221.c
F: include/dt-bindings/clock/econet,en751221-scu.h
F: include/dt-bindings/reset/econet,en751221-scu.h
+ECONET USB PHY DRIVER
+M: Caleb James DeLisle <cjd@cjdns.fr>
+L: linux-mips@vger.kernel.org
+S: Maintained
+F: Documentation/devicetree/bindings/phy/econet,en751221-usb-phy.yaml
+
ECRYPT FILE SYSTEM
M: Tyler Hicks <code@tyhicks.com>
L: ecryptfs@vger.kernel.org
--
2.39.5
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related
* [PATCH 2/2] phy: econet: Add EcoNet USB PHY
From: Caleb James DeLisle @ 2026-05-18 14:13 UTC (permalink / raw)
To: linux-mips
Cc: vkoul, neil.armstrong, robh, krzk+dt, conor+dt, linux-phy,
devicetree, linux-kernel, Caleb James DeLisle, Benjamin Larsson,
Ahmed Naseef
In-Reply-To: <20260518141343.401555-1-cjd@cjdns.fr>
Add support for USB PHY found on EcoNet EN751221, EN751627, and
EN7528 based SoCs. This PHY is somewhat similar to Mediatek tphy-v1,
but in terms of setup ritual it has essentially nothing in common.
Based on work originally by Benjamin Larsson with bug fixes and
added support for EN751627 and EN7528.
Tested on:
* EN7526G (SmartFiber XP8421-B) USB 2.0
* EN7526F (ChinaMobile GS3101) USB 2.0
* EN7516 (Zyxel EX3301-T0) USB 2.0
Tested by Ahmed Naseef on EN7528 (Dasan H660GM) USB 2.0
Tested by Benjamin Larsson on unreleased EN751221 board with USB 3.0
Originally-by: Benjamin Larsson <benjamin.larsson@genexis.eu>
Signed-off-by: Caleb James DeLisle <cjd@cjdns.fr>
Tested-by: Ahmed Naseef <naseefkm@gmail.com>
Tested-by: Benjamin Larsson <benjamin.larsson@genexis.eu>
Link: https://github.com/openwrt/openwrt/pull/23264#issuecomment-4415906568
---
MAINTAINERS | 1 +
drivers/phy/Kconfig | 13 +
drivers/phy/Makefile | 1 +
drivers/phy/phy-econet-usb.c | 558 +++++++++++++++++++++++++++++++++++
4 files changed, 573 insertions(+)
create mode 100644 drivers/phy/phy-econet-usb.c
diff --git a/MAINTAINERS b/MAINTAINERS
index 1a90a1736294..74cf07bbc49f 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -9209,6 +9209,7 @@ M: Caleb James DeLisle <cjd@cjdns.fr>
L: linux-mips@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/phy/econet,en751221-usb-phy.yaml
+F: drivers/phy/phy-econet-usb.c
ECRYPT FILE SYSTEM
M: Tyler Hicks <code@tyhicks.com>
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index 227b9a4c612e..0a3bec9af93e 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -66,6 +66,19 @@ config PHY_CAN_TRANSCEIVER
functional modes using gpios and sets the attribute max link
rate, for CAN drivers.
+config PHY_ECONET_USB
+ tristate "EcoNet USB PHY driver"
+ depends on ECONET || COMPILE_TEST
+ depends on OF
+ select GENERIC_PHY
+ select REGMAP_MMIO
+ help
+ Enable support for the USB PHY on EcoNet EN751221, EN751627, and
+ EN7528 SoCs. These PHYs support USB 2.0 and USB 3.0. SoCs typically
+ have two ports, one supporting USB 2.0 only and the other supporting
+ USB 3.0. Though some chip configurations have only the 2.0 capable
+ port and some only have the 3.0 capable port.
+
config PHY_GOOGLE_USB
tristate "Google Tensor SoC USB PHY driver"
select GENERIC_PHY
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index f49d83f00a3d..8a58bb151198 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -9,6 +9,7 @@ obj-$(CONFIG_GENERIC_PHY) += phy-core.o
obj-$(CONFIG_GENERIC_PHY_MIPI_DPHY) += phy-core-mipi-dphy.o
obj-$(CONFIG_PHY_AIROHA_PCIE) += phy-airoha-pcie.o
obj-$(CONFIG_PHY_CAN_TRANSCEIVER) += phy-can-transceiver.o
+obj-$(CONFIG_PHY_ECONET_USB) += phy-econet-usb.o
obj-$(CONFIG_PHY_GOOGLE_USB) += phy-google-usb.o
obj-$(CONFIG_USB_LGM_PHY) += phy-lgm-usb.o
obj-$(CONFIG_PHY_LPC18XX_USB_OTG) += phy-lpc18xx-usb-otg.o
diff --git a/drivers/phy/phy-econet-usb.c b/drivers/phy/phy-econet-usb.c
new file mode 100644
index 000000000000..e8fa2e80eb13
--- /dev/null
+++ b/drivers/phy/phy-econet-usb.c
@@ -0,0 +1,558 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Author: Benjamin Larsson <benjamin.larsson@genexis.eu>
+ * Author: Caleb James DeLisle <cjd@cjdns.fr>
+ */
+
+#include <dt-bindings/phy/phy.h>
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/math.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+/* SSUSB SIFSLV SPLLC (0x0) */
+#define SPLLC 0x00
+
+/* SSUSB SIFSLV FMREG (0x100) offset based on SSUSB SIFSLV SPLLC */
+#define FMREG 0x100
+#define FMCR0 0x00
+#define RG_MONCLK_SEL GENMASK(27, 26)
+#define RG_FREQDET_EN BIT(24)
+#define RG_CYCLECNT GENMASK(23, 0)
+#define FMMONR0 0x0c
+#define RG_FM_OUT GENMASK(31, 0)
+#define FMMONR1 0x10
+#define RG_FM_VALID BIT(0)
+#define RG_FRCK_EN BIT(8)
+
+/* SSUSB SIFSLV U2PHY COM (0x800, 0x1000) */
+#define U2PHY_COM 0x00
+#define USBPHYACR0 0x10
+#define RG_HSTX_SRCAL_EN BIT(23)
+#define RG_HSTX_SRCTRL GENMASK(18, 16)
+#define USBPHYACR3 0x1C
+#define RG_PUPD GENMASK(12, 8)
+#define RG_PUPD_EN BIT(12)
+#define RG_PUPD_PD_DM BIT(10)
+#define RG_PUPD_PD_DP BIT(8)
+#define RG_REV GENMASK(7, 0)
+#define REVISION_P0 FIELD_PREP(RG_REV, 0x08)
+#define REVISION_P0_DOWN FIELD_PREP(RG_REV, 0x80)
+#define REVISION_P1 FIELD_PREP(RG_REV, 0x00)
+#define U2PHYDCR1 0x64
+#define RG_USB20_SW_PLLMODE GENMASK(19, 18)
+
+/* SSUSB SIFSLV U3PHYD (0x900) */
+#define U3PHYD 0x00
+#define LFPS1 0x0c
+#define RG_SSUSB_FWAKE_TH GENMASK(21, 16)
+
+/* SSUSB SIFSLV U3PHYD BANK2 (0xA00) offset based on SSUSB SIFSLV U3PHYD */
+#define U3PHYD_BANK2 0x100
+#define B2_PHYD_RXDET1 0x028
+#define RG_SSUSB_RXDET_STB2_SET GENMASK(17, 9)
+#define B2_PHYD_RXDET2 0x02C
+#define RG_SSUSB_RXDET_STB2_SET_P3 GENMASK(8, 0)
+
+/* SSUSB SIFSLV U3PHYA (0xB00) offset based on SSUSB SIFSLV U3PHYD */
+#define U3PHYA 0x200
+#define U3PHYA_REG2 0x008
+#define RG_SSUSB_SYSPLL_LF BIT(31)
+#define RG_SSUSB_SYSPLL_FBDIV GENMASK(30, 24)
+#define RG_SSUSB_SYSPLL_POSDIV GENMASK(23, 22)
+#define RG_SSUSB_SYSPLL_VCO_DIV_SEL BIT(21)
+#define RG_SSUSB_SYSPLL_BLP BIT(20)
+#define RG_SSUSB_SYSPLL_BP BIT(19)
+#define RG_SSUSB_SYSPLL_BR BIT(18)
+#define RG_SSUSB_SYSPLL_BC BIT(17)
+#define RG_SSUSB_SYSPLL_DIVEN GENMASK(16, 14)
+#define RG_SSUSB_SYSPLL_FPEN BIT(13)
+#define RG_SSUSB_SYSPLL_MONCK_EN BIT(12)
+#define RG_SSUSB_SYSPLL_MONVC_EN BIT(11)
+#define RG_SSUSB_SYSPLL_MONREF_EN BIT(10)
+#define RG_SSUSB_SYSPLL_VOD_EN BIT(9)
+#define RG_SSUSB_SYSPLL_CK_SEL BIT(8)
+#define U3PHYA_REG4 0x010
+#define RG_SSUSB_SYSPLL_PCW_NCPO GENMASK(31, 1)
+#define U3PHYA_REG9 0x024
+#define RG_SSUSB_PLL_DDS_DMY GENMASK(31, 16)
+#define RG_SSUSB_PLL_SSC_PRD GENMASK(15, 0)
+#define U3PHYA_REGB 0x02c
+#define RG_SSUSB_RX_50_TAR GENMASK(13, 12)
+
+/* SSUSB SIFSLV U3PHYA DA (0xC00) offset based on SSUSB SIFSLV U3PHYD */
+#define U3PHYA_DA 0x300
+#define U3PHYA_DA_REG9 0x01C
+#define RG_SSUSB_PLL_FBKDIV_PE2H GENMASK(30, 24)
+#define RG_SSUSB_PLL_FBKDIV_PE1D GENMASK(22, 16)
+#define RG_SSUSB_PLL_FBKDIV_PE1H GENMASK(14, 8)
+#define RG_SSUSB_PLL_FBKDIV_U3 GENMASK(6, 0)
+#define U3PHYA_DA_REG12 0x024
+#define RG_SSUSB_PLL_PCW_NCPO_U3 GENMASK(30, 0)
+#define U3PHYA_DA_REG13 0x028
+#define RG_SSUSB_PLL_PCW_NCPO_PE1H GENMASK(30, 0)
+#define U3PHYA_DA_REG14 0x02C
+#define RG_SSUSB_PLL_PCW_NCPO_PE1D GENMASK(30, 0)
+#define U3PHYA_DA_REG15 0x030
+#define RG_SSUSB_PLL_PCW_NCPO_PE2H GENMASK(30, 0)
+#define U3PHYA_DA_REG19 0x038
+#define RG_SSUSB_PLL_SSC_DELTA1_PE1H GENMASK(31, 16)
+#define RG_SSUSB_PLL_SSC_DELTA1_U3 GENMASK(15, 0)
+#define U3PHYA_DA_REG20 0x03C
+#define RG_SSUSB_PLL_SSC_DELTA1_PE2H GENMASK(31, 16)
+#define RG_SSUSB_PLL_SSC_DELTA1_PE1D GENMASK(15, 0)
+#define U3PHYA_DA_REG21 0x040
+#define RG_SSUSB_PLL_SSC_DELTA_U3 GENMASK(31, 16)
+#define RG_SSUSB_PLL_SSC_DELTA1_PE2D GENMASK(15, 0)
+#define U3PHYA_DA_REG23 0x044
+#define RG_SSUSB_PLL_SSC_DELTA_PE1D GENMASK(31, 16)
+#define RG_SSUSB_PLL_SSC_DELTA_PE1H GENMASK(15, 0)
+#define U3PHYA_DA_REG25 0x048
+#define RG_SSUSB_PLL_SSC_DELTA_PE2D GENMASK(31, 16)
+#define RG_SSUSB_PLL_SSC_DELTA_PE2H GENMASK(15, 0)
+
+#define ECONET_USB_PHY_U2_FM_DET_CYCLE_CNT 1024
+#define ECONET_USB_PHY_REF_CK 20
+#define ECONET_USB_PHY_U2_SR_COEF 28
+#define ECONET_USB_PHY_U2_SR_COEF_DIVISOR 1000
+#define ECONET_USB_PHY_U2_SR_DEFAULT 0x4
+
+#define ECONET_USB_PHY_FREQDET_SLEEP 1000 /* 1ms */
+#define ECONET_USB_PHY_FREQDET_TIMEOUT (ECONET_USB_PHY_FREQDET_SLEEP * 10)
+
+#define ECONET_USB_PHY_MAX_INSTANCE 3
+
+#define ECONET_PORT_ID_FIELD "econet,usb-port-id"
+
+enum econet_phy_soc {
+ SOC_EN751221 = 1,
+ SOC_EN751627,
+ SOC_EN7528,
+};
+
+/**
+ * econet_phy_instance - the individual PHY block
+ * @phy: The phy object
+ * @regmap: A regmap for the phy block, per DT subnode reg field
+ * @type: PHY_TYPE_USB2 / PHY_TYPE_USB3 depending on PHY block
+ * @port_id: Number of the physical port [0,1]
+ *
+ * There are typically 3 PHY blocks, 2x USB 2.0 blocks, and 1x USB 3.0. The USB
+ * 3.0 PHY is piggybacked on top of one of the USB2 ports and activates when
+ * the connected device negotiates a USB 3.0 link. Main actions like powering
+ * on the port are governed in the USB 2.0 block.
+ */
+struct econet_phy_instance {
+ struct phy *phy;
+ struct regmap *regmap;
+ int type;
+ int port_id;
+};
+
+/**
+ * econet_usb_phy_priv the main PHY driver structure
+ * @dev: The root device
+ * @regmap: A regmap of registers that are shared between the PHY blocks
+ * @clk: The system Xtal clock, if 25Mhz then we need additional configuration
+ * @phys: The individual PHY blocks, normally there are three: Two USB 2.0 and
+ * one USB 3.0 which is shared on the same port at one of the USB 2.0.
+ * @soc: The ID of the device, which is relevant to some of the tuning ritual.
+ */
+struct econet_usb_phy_priv {
+ struct device *dev;
+ struct regmap *regmap;
+ struct clk *clk;
+ struct econet_phy_instance phys[ECONET_USB_PHY_MAX_INSTANCE];
+ enum econet_phy_soc soc;
+};
+
+static void u2_slew_rate_calibration(struct econet_usb_phy_priv *priv,
+ struct econet_phy_instance *instance)
+{
+ struct regmap *com = instance->regmap;
+ struct regmap *regmap = priv->regmap;
+ int fm_out = 0;
+ u32 srctrl;
+
+ /* Enable HS TX SR calibration */
+ regmap_set_bits(com, U2PHY_COM + USBPHYACR0, RG_HSTX_SRCAL_EN);
+
+ usleep_range(1000, 1500);
+
+ /* Enable Free run clock */
+ regmap_set_bits(regmap, FMREG + FMMONR1, RG_FRCK_EN);
+
+ /* Select Monitor Clock */
+ regmap_update_bits(regmap, FMREG + FMCR0, RG_MONCLK_SEL,
+ FIELD_PREP(RG_MONCLK_SEL, instance->port_id));
+
+ /* Set cyclecnt */
+ regmap_update_bits(regmap, FMREG + FMCR0, RG_CYCLECNT,
+ FIELD_PREP_CONST(RG_CYCLECNT,
+ ECONET_USB_PHY_U2_FM_DET_CYCLE_CNT));
+
+ /* Enable Frequency meter */
+ regmap_set_bits(regmap, FMREG + FMCR0, RG_FREQDET_EN);
+
+ /* Timeout can happen and we will apply workaround at the end */
+ regmap_read_poll_timeout(regmap, FMREG + FMMONR0, fm_out,
+ fm_out, ECONET_USB_PHY_FREQDET_SLEEP,
+ ECONET_USB_PHY_FREQDET_TIMEOUT);
+
+ /* Disable Frequency meter */
+ regmap_clear_bits(regmap, FMREG + FMCR0, RG_FREQDET_EN);
+
+ /* Disable Free run clock */
+ regmap_clear_bits(regmap, FMREG + FMMONR1, RG_FRCK_EN);
+
+ /* Disable HS TX SR calibration */
+ regmap_clear_bits(com, U2PHY_COM + USBPHYACR0, RG_HSTX_SRCAL_EN);
+
+ usleep_range(1000, 1500);
+
+ if (!fm_out) {
+ srctrl = ECONET_USB_PHY_U2_SR_DEFAULT;
+ dev_warn(&instance->phy->dev,
+ "frequency detection failed, using default slew rate 0x%x\n",
+ srctrl);
+ } else {
+ /* (1024 / FM_OUT) * REF_CK * U2_SR_COEF (round to nearest) */
+ srctrl = ECONET_USB_PHY_REF_CK * ECONET_USB_PHY_U2_SR_COEF;
+ srctrl = (srctrl * ECONET_USB_PHY_U2_FM_DET_CYCLE_CNT) / fm_out;
+ srctrl = DIV_ROUND_CLOSEST(srctrl,
+ ECONET_USB_PHY_U2_SR_COEF_DIVISOR);
+ dev_info(&instance->phy->dev,
+ "frequency meter result 0x%x, set slew rate 0x%x\n",
+ fm_out, srctrl);
+ }
+
+ /* Set slew rate */
+ regmap_update_bits(com, U2PHY_COM + USBPHYACR0, RG_HSTX_SRCTRL,
+ FIELD_PREP(RG_HSTX_SRCTRL, srctrl));
+}
+
+static int econet_usb_phy_u2_init(struct econet_usb_phy_priv *priv,
+ struct econet_phy_instance *instance)
+{
+ struct regmap *com = instance->regmap;
+
+ regmap_update_bits(com, U2PHY_COM + USBPHYACR3, RG_PUPD | RG_REV,
+ instance->port_id == 0 ? REVISION_P0 : REVISION_P1);
+
+ /* set SW PLL Stable mode to 1 for U2 LPM device remote wakeup */
+ if (priv->soc != SOC_EN7528)
+ regmap_update_bits(com, U2PHY_COM + U2PHYDCR1,
+ RG_USB20_SW_PLLMODE,
+ FIELD_PREP(RG_USB20_SW_PLLMODE, 0x1));
+
+ u2_slew_rate_calibration(priv, instance);
+
+ usleep_range(1000, 1500);
+
+ return 0;
+}
+
+static int u3_setup_25mhz_xtal(struct econet_usb_phy_priv *priv,
+ struct econet_phy_instance *instance)
+{
+ struct regmap *u3phyd = instance->regmap;
+
+ /* Setup 25MHz XTAL */
+ regmap_update_bits(u3phyd, U3PHYA_DA + U3PHYA_DA_REG9,
+ RG_SSUSB_PLL_FBKDIV_U3,
+ FIELD_PREP(RG_SSUSB_PLL_FBKDIV_U3, 0x18));
+ regmap_update_bits(u3phyd, U3PHYA_DA + U3PHYA_DA_REG9,
+ RG_SSUSB_PLL_FBKDIV_PE1H,
+ FIELD_PREP(RG_SSUSB_PLL_FBKDIV_PE1H, 0x18));
+ regmap_update_bits(u3phyd, U3PHYA_DA + U3PHYA_DA_REG9,
+ RG_SSUSB_PLL_FBKDIV_PE2H,
+ FIELD_PREP(RG_SSUSB_PLL_FBKDIV_PE2H, 0x18));
+
+ regmap_update_bits(u3phyd, U3PHYA_DA + U3PHYA_DA_REG12,
+ RG_SSUSB_PLL_PCW_NCPO_U3,
+ FIELD_PREP(RG_SSUSB_PLL_PCW_NCPO_U3, 0x18000000));
+
+ regmap_update_bits(u3phyd, U3PHYA_DA + U3PHYA_DA_REG13,
+ RG_SSUSB_PLL_PCW_NCPO_PE1H,
+ FIELD_PREP(RG_SSUSB_PLL_PCW_NCPO_PE1H, 0x18000000));
+
+ regmap_update_bits(u3phyd, U3PHYA_DA + U3PHYA_DA_REG15,
+ RG_SSUSB_PLL_PCW_NCPO_PE2H,
+ FIELD_PREP(RG_SSUSB_PLL_PCW_NCPO_PE2H, 0x18000000));
+
+ regmap_update_bits(u3phyd, U3PHYA_DA + U3PHYA_DA_REG19,
+ RG_SSUSB_PLL_SSC_DELTA1_PE1H,
+ FIELD_PREP(RG_SSUSB_PLL_SSC_DELTA1_PE1H, 0x4a));
+ regmap_update_bits(u3phyd, U3PHYA_DA + U3PHYA_DA_REG19,
+ RG_SSUSB_PLL_SSC_DELTA1_U3,
+ FIELD_PREP(RG_SSUSB_PLL_SSC_DELTA1_U3, 0x4a));
+
+ regmap_update_bits(u3phyd, U3PHYA_DA + U3PHYA_DA_REG20,
+ RG_SSUSB_PLL_SSC_DELTA1_PE2H,
+ FIELD_PREP(RG_SSUSB_PLL_SSC_DELTA1_PE2H, 0x4a));
+
+ regmap_update_bits(u3phyd, U3PHYA_DA + U3PHYA_DA_REG21,
+ RG_SSUSB_PLL_SSC_DELTA_U3,
+ FIELD_PREP(RG_SSUSB_PLL_SSC_DELTA_U3, 0x48));
+
+ regmap_update_bits(u3phyd, U3PHYA_DA + U3PHYA_DA_REG23,
+ RG_SSUSB_PLL_SSC_DELTA_PE1H,
+ FIELD_PREP(RG_SSUSB_PLL_SSC_DELTA_PE1H, 0x48));
+
+ regmap_update_bits(u3phyd, U3PHYA_DA + U3PHYA_DA_REG25,
+ RG_SSUSB_PLL_SSC_DELTA_PE2H,
+ FIELD_PREP(RG_SSUSB_PLL_SSC_DELTA_PE2H, 0x48));
+
+ regmap_update_bits(u3phyd, U3PHYA + U3PHYA_REG9,
+ RG_SSUSB_PLL_SSC_PRD,
+ FIELD_PREP(RG_SSUSB_PLL_SSC_PRD, 0x190));
+ regmap_update_bits(u3phyd, U3PHYA + U3PHYA_REG4,
+ RG_SSUSB_SYSPLL_PCW_NCPO,
+ FIELD_PREP(RG_SSUSB_SYSPLL_PCW_NCPO, 0xe000000));
+ regmap_update_bits(u3phyd, U3PHYA + U3PHYA_REG2,
+ RG_SSUSB_SYSPLL_FBDIV,
+ FIELD_PREP(RG_SSUSB_SYSPLL_FBDIV, 0xe));
+ return 0;
+}
+
+static int econet_usb_phy_u3_init(struct econet_usb_phy_priv *priv,
+ struct econet_phy_instance *instance)
+{
+ struct regmap *u3phyd = instance->regmap;
+
+ if (priv->soc == SOC_EN751221) {
+ /* Patch TxDetRx Timing for E1 */
+ regmap_update_bits(u3phyd, U3PHYD_BANK2 + B2_PHYD_RXDET1,
+ RG_SSUSB_RXDET_STB2_SET,
+ FIELD_PREP(RG_SSUSB_RXDET_STB2_SET, 0x10));
+
+ regmap_update_bits(u3phyd, U3PHYD_BANK2 + B2_PHYD_RXDET2,
+ RG_SSUSB_RXDET_STB2_SET_P3,
+ FIELD_PREP(RG_SSUSB_RXDET_STB2_SET_P3, 0x10));
+
+ /* Patch LFPS Filter Threshold for E1 */
+ regmap_update_bits(u3phyd, U3PHYD + LFPS1, RG_SSUSB_FWAKE_TH,
+ FIELD_PREP(RG_SSUSB_FWAKE_TH, 0x34));
+
+ } else if (priv->soc == SOC_EN7528) {
+ /* combo phy Rx R FT mean value too high, target R -5 Ohm */
+ regmap_update_bits(u3phyd, U3PHYA + U3PHYA_REGB,
+ RG_SSUSB_RX_50_TAR,
+ FIELD_PREP(RG_SSUSB_RX_50_TAR, 0x01));
+ }
+
+ if (clk_get_rate(priv->clk) == 25 * 1000 * 1000)
+ u3_setup_25mhz_xtal(priv, instance);
+
+ return 0;
+}
+
+static int econet_usb_phy_init(struct phy *phy)
+{
+ struct econet_phy_instance *instance = phy_get_drvdata(phy);
+ struct econet_usb_phy_priv *priv = dev_get_drvdata(phy->dev.parent);
+
+ if (instance->type == PHY_TYPE_USB2)
+ return econet_usb_phy_u2_init(priv, instance);
+ else if (instance->type == PHY_TYPE_USB3)
+ return econet_usb_phy_u3_init(priv, instance);
+
+ return -EINVAL;
+}
+
+static int econet_usb_phy_exit(struct phy *phy)
+{
+ struct econet_phy_instance *instance = phy_get_drvdata(phy);
+
+ /*
+ * Disable the port by setting PHY revision to REVISION_P0_DOWN and
+ * enabling pulldown resistors on D+ and D- lines. The USB 3.0 PHY
+ * piggybacks on top of the USB 2.0 for the same port and does not
+ * have any such switch.
+ */
+ if (instance->type == PHY_TYPE_USB2)
+ return regmap_update_bits(instance->regmap,
+ U2PHY_COM + USBPHYACR3,
+ RG_PUPD | RG_REV,
+ RG_PUPD_EN | RG_PUPD_PD_DM |
+ RG_PUPD_PD_DP | REVISION_P0_DOWN);
+
+ return 0;
+}
+
+static struct phy *econet_usb_phy_xlate(struct device *dev,
+ const struct of_phandle_args *args)
+{
+ struct econet_usb_phy_priv *priv = dev_get_drvdata(dev);
+ struct device_node *phy_np = args->np;
+ int index;
+
+ if (!of_device_is_available(phy_np)) {
+ dev_err(dev, "can't use disabled phy\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ for (index = 0; index < ARRAY_SIZE(priv->phys); index++) {
+ /* Empty slots if the DT doesn't specify all subnodes */
+ if (!priv->phys[index].phy)
+ continue;
+
+ if (phy_np != priv->phys[index].phy->dev.of_node)
+ continue;
+
+ return priv->phys[index].phy;
+ }
+
+ dev_err(dev, "failed to find phy\n");
+ return ERR_PTR(-EINVAL);
+}
+
+static const struct phy_ops econet_phy = {
+ .init = econet_usb_phy_init,
+ .exit = econet_usb_phy_exit,
+ .owner = THIS_MODULE,
+};
+
+static const struct regmap_config econet_usb_phy_regmap_config = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+};
+
+static const struct of_device_id econet_phy_id_table[] = {
+ { .compatible = "econet,en751221-usb-phy", .data = (void *) SOC_EN751221 },
+ { .compatible = "econet,en751627-usb-phy", .data = (void *) SOC_EN751627 },
+ { .compatible = "econet,en7528-usb-phy", .data = (void *) SOC_EN7528 },
+ { },
+};
+MODULE_DEVICE_TABLE(of, econet_phy_id_table);
+
+static int econet_usb_phy_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct econet_usb_phy_priv *priv;
+ const struct of_device_id *match;
+ struct phy_provider *provider;
+ void *base;
+ int phy_n;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->dev = dev;
+
+ base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(base))
+ return dev_err_probe(dev, PTR_ERR(base), "getting reg\n");
+
+ platform_set_drvdata(pdev, priv);
+ priv->regmap = devm_regmap_init_mmio(dev, base, &econet_usb_phy_regmap_config);
+ if (IS_ERR(priv->regmap))
+ return PTR_ERR(priv->regmap);
+
+ priv->clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(priv->clk))
+ return dev_err_probe(dev, PTR_ERR(priv->clk), "getting clk\n");
+
+ match = of_match_node(econet_phy_id_table, np);
+ if (!match || !match->data)
+ return dev_err_probe(dev, -EINVAL, "no OF match data\n");
+
+ priv->soc = (enum econet_phy_soc)(uintptr_t)match->data;
+
+ phy_n = 0;
+ for_each_child_of_node_scoped(np, child_np) {
+ struct econet_phy_instance *instance;
+ void __iomem *phy_base;
+ struct device *subdev;
+ struct resource res;
+ int retval;
+
+ if (phy_n >= ARRAY_SIZE(priv->phys))
+ return dev_err_probe(dev, -EINVAL,
+ "too many PHY subnodes\n");
+
+ instance = &priv->phys[phy_n];
+
+ if (of_device_is_compatible(child_np, "econet,usb2-phy"))
+ instance->type = PHY_TYPE_USB2;
+ else if (of_device_is_compatible(child_np, "econet,usb3-phy"))
+ instance->type = PHY_TYPE_USB3;
+ else
+ return dev_err_probe(dev, -EINVAL,
+ "phy %d unknown type\n", phy_n);
+
+ instance->phy = devm_phy_create(dev, child_np, &econet_phy);
+ if (IS_ERR(instance->phy))
+ return dev_err_probe(dev, PTR_ERR(instance->phy),
+ "failed to create phy\n");
+
+ subdev = &instance->phy->dev;
+ retval = of_address_to_resource(child_np, 0, &res);
+ if (retval)
+ return dev_err_probe(subdev, retval,
+ "getting reg for phy %d\n",
+ phy_n);
+
+ phy_base = devm_ioremap_resource(subdev, &res);
+ if (IS_ERR(phy_base))
+ return dev_err_probe(subdev, PTR_ERR(phy_base),
+ "remapping reg for phy %d\n",
+ phy_n);
+
+ instance->regmap =
+ devm_regmap_init_mmio(subdev, phy_base,
+ &econet_usb_phy_regmap_config);
+ if (IS_ERR(instance->regmap))
+ return dev_err_probe(subdev, PTR_ERR(instance->regmap),
+ "making regmap for phy %d\n",
+ phy_n);
+
+ retval = device_property_read_u32(subdev, ECONET_PORT_ID_FIELD,
+ &instance->port_id);
+ if (retval)
+ return dev_err_probe(subdev, retval,
+ "getting %s for phy %d\n",
+ ECONET_PORT_ID_FIELD, phy_n);
+
+ phy_set_drvdata(instance->phy, instance);
+
+ /*
+ * Initial setup ritual disables both ports. On QFP silicon,
+ * only one port is wired (port1) but port0 still has a PHY
+ * present which is still disabled in setup.
+ */
+ retval = econet_usb_phy_exit(instance->phy);
+ if (retval)
+ dev_warn(subdev, "stopping phy %d: %pe\n", phy_n,
+ ERR_PTR(retval));
+
+ phy_n++;
+ }
+
+ provider = devm_of_phy_provider_register(dev, econet_usb_phy_xlate);
+
+ return PTR_ERR_OR_ZERO(provider);
+}
+
+static struct platform_driver econet_usb_phy_driver = {
+ .probe = econet_usb_phy_probe,
+ .driver = {
+ .name = "econet-usb-phy",
+ .of_match_table = econet_phy_id_table,
+ },
+};
+
+module_platform_driver(econet_usb_phy_driver);
+
+MODULE_AUTHOR("Benjamin Larsson <benjamin.larsson@genexis.eu>");
+MODULE_AUTHOR("Caleb James DeLisle <cjd@cjdns.fr>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Econet USB PHY driver");
--
2.39.5
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related
* Re: [PATCH 3/5] phy: qualcomm: qmp-combo: Add preliminary USB4 support
From: Konrad Dybcio @ 2026-05-18 14:15 UTC (permalink / raw)
To: Dmitry Baryshkov, Konrad Dybcio
Cc: Vinod Koul, Neil Armstrong, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Bjorn Andersson, linux-kernel, linux-phy,
linux-arm-msm, devicetree, usb4-upstream, Raghavendra Thoorpu,
Mika Westerberg, Sven Peter
In-Reply-To: <4nqlpu7qfptekyn77sd7sdn446stgn3v3lw2356bvizrnvjgnr@czqgivemigt5>
On 5/18/26 3:57 PM, Dmitry Baryshkov wrote:
> On Mon, May 18, 2026 at 12:29:50PM +0200, Konrad Dybcio wrote:
>> From: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
>>
>> Some Combo PHYs (so far only on SC8280XP, X1E80100 and Glymur), come in
>> a flavor called USB43DP, which as the name implies, features USB4, USB3
>> and DP signal processing capabilities. In that architecture, USB3 and
>> USB4 PHYs share the same USB_PLL while featuring separate logic spaces.
>> The DP part is roughly the same as on the instances without USB4.
>>
>> The USB4 and USB3/DP operation modes of the PHY are mutually exclusive.
>> Only one USB protocol (and flavor of pipe clock) can be active at a
>> given moment (not to be confused with USB3 not being able to be
>> tunneled as USB4 packets - that of course remains possible).
>> The DP PLL is still used for clocking tunneled DP links. It may be
>> turned off to save power when no tunnels are active, but that's left as
>> a TODO item for now.
>>
>> Due to the nature of USB4, the Type-C handling happens entirely inside
>> the Host Router, and as such the QMPPHY's mux_set() function is
>> nullified for the period when USB4 PHY remains active. This is strictly
>> necessary, as the Host Router driver is going to excercise manual
>> control over the USB4 PHY's power state, which is needed by the suspend
>> and resume flows. Failure to control that synchronously with other
>> parts of the code results in a SoC crash by unlocked access.
>>
>> Because of that, a new struct phy is spawned to expose the USB4 mode,
>> along with a .set_mode callback to allow toggling between USB4 and TBT3
>> submodes.
>>
>> Thunderbolt 3, having a number of differences vs USB4, requires a
>> couple specific overrides, pertaining to electrical characteristics,
>> which are easily accommodated for.
>>
>> Signed-off-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
>> ---
>> drivers/phy/qualcomm/phy-qcom-qmp-combo.c | 392 ++++++++++++++++++++++++------
>> 1 file changed, 322 insertions(+), 70 deletions(-)
>>
>
> Overall it looks good. The major question (after looking at TODOs), do
> we need a separate submode for USB+DP / TBT+DP?
The problem space is as follows:
After a TBT (collectively TBT3+ and USB4) link has been established and
we have a link partner, we may (based on the HW capabilities and user
config, such as kernel params but not only) start or stop a DP tunnel at
runtime. On Qualcomm hardware, the PHY is kept in USB4 mode and its DP
AUX lines are not used (instead, the encapsulated DP AUX packets are r/w
entirely within the USB4 subsystem via a pair of FIFOs that Linux sees
as a separate DP AUX host)
Then, on hamoa/glymur specifically, any of the 3 USB4-capable DP hosts
can be muxed to either of the 2 DPIN ports on any of the 3 USB4 routers
(and each of these routers is hardwired to one of the PHYs).
To underline, we have 3 DP producers and 6 consumers. If there's e.g. a
super high-res display at one of the physical ports, or a long
daisy-chain, we may need to use 2 DPTXes to service 1 receptacle. Then,
we would only need one of the PHYs (associated with the router that's
wired to that port) to provide a DP clock.
This, along with the normal (logical or physical) present/absent status
can change at runtime. My plan is to use phy_set_opts(dp_tunelling=true)
or something along those lines to toggle that bit as necessary
Konrad
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* [PATCH v4 linux-phy 0/3] phy: ti: add driver for TI DS125DF111 Dual-Channel Retimer
From: Ioana Ciornei @ 2026-05-18 14:20 UTC (permalink / raw)
To: vkoul, neil.armstrong, robh, krzk+dt, conor+dt, johan, linux-phy
Cc: devicetree, linux-kernel
This patch set adds a generic PHY driver and the corresponding DT
binding for the TI DS125DF111 Dual-Channel retimer. The datasheet on
which this driver was based on can be found at -
https://www.ti.com/lit/gpn/DS125DF111.
A separate generic PHY is registered for each of the two channels of the
retimer, so consumers can drive each channel independently. This allows
for independent control of the channels, which is especially important
since each channel can be routed to different SerDes lanes and it is not
guaranteed that the same retimer will do both directions of SerDes lane.
This was tested on a LS1088ARDB board with the Lynx10G SerDes PHY driver
yet to be submitted.
Changes in v4:
- Add patch 2/3 which sorts the drivers/phy/ti/ Kconfig and Makefile
files. This will generate checkpatch warnings since some of the
help text that I moved is shorter than 4 lines.
- Use lower case for hex values
- Insert the new entry in the Kconfig/Makefile so that we keep the
alphabetical order established in the previous patch
- Link to v3: https://lore.kernel.org/all/20260516060309.2282592-1-ioana.ciornei@nxp.com/
Changes in v3:
- Use reverse Christmas tree ordering
- Print a symbolic description in case of error
- Some words do not need to be capitalized
- Remove duplicated exit code path
- Return -EINVAL in case of unsupported submode received in .set_mode()
- Add a .validate() callback
- Remove comma after sentinel entry
- Add a ds125df111_rmw() helper
- Use read_poll_timeout() to wait for channel reset to complete
- Link to v2: https://lore.kernel.org/all/20260515110145.1925579-1-ioana.ciornei@nxp.com/
Changes in v2:
- Remove the label from the example
- Rename the node from 'retimer' to 'phy'
- Explicitly include all the needed headers
- Change ds125df111_xlate() so that it returns an error if args_count is
not exactly 1
- Add a MAINTAINERS entry
- Link to v1: https://lore.kernel.org/all/20260513185103.1371809-1-ioana.ciornei@nxp.com/
Ioana Ciornei (3):
dt-bindings: phy: add PHY bindings for the TI DS125DF111 Retimer PHY
phy: ti: alphabetically sort Kconfig and Makefile
phy: ti: add PHY driver for TI DS125DF111 Dual-Channel Retimer
.../bindings/phy/ti,ds125df111.yaml | 46 +++
MAINTAINERS | 7 +
drivers/phy/ti/Kconfig | 102 +++---
drivers/phy/ti/Makefile | 13 +-
drivers/phy/ti/phy-ds125df111.c | 294 ++++++++++++++++++
5 files changed, 410 insertions(+), 52 deletions(-)
create mode 100644 Documentation/devicetree/bindings/phy/ti,ds125df111.yaml
create mode 100644 drivers/phy/ti/phy-ds125df111.c
--
2.25.1
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* [PATCH v4 linux-phy 1/3] dt-bindings: phy: add PHY bindings for the TI DS125DF111 Retimer PHY
From: Ioana Ciornei @ 2026-05-18 14:20 UTC (permalink / raw)
To: vkoul, neil.armstrong, robh, krzk+dt, conor+dt, johan, linux-phy
Cc: devicetree, linux-kernel
In-Reply-To: <20260518142026.3098496-1-ioana.ciornei@nxp.com>
Add device tree binding for the TI DS125DF111 Retimer PHY.
Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
Acked-by: Conor Dooley <conor.dooley@microchip.com>
---
Changes in v4:
- none
Changes in v3:
- none
Changes in v2:
- Remove the label from the example
- Rename the node from 'retimer' to 'phy'
---
.../bindings/phy/ti,ds125df111.yaml | 46 +++++++++++++++++++
1 file changed, 46 insertions(+)
create mode 100644 Documentation/devicetree/bindings/phy/ti,ds125df111.yaml
diff --git a/Documentation/devicetree/bindings/phy/ti,ds125df111.yaml b/Documentation/devicetree/bindings/phy/ti,ds125df111.yaml
new file mode 100644
index 000000000000..ca4605f1d664
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/ti,ds125df111.yaml
@@ -0,0 +1,46 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/phy/ti,ds125df111.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: TI DS125DF111 Retimer PHY
+
+description:
+ This binding describes the TI DS125DF111 multi-protocol Retimer PHY.
+
+maintainers:
+ - Ioana Ciornei <ioana.ciornei@nxp.com>
+
+properties:
+ compatible:
+ const: ti,ds125df111
+
+ reg:
+ maxItems: 1
+
+ "#phy-cells":
+ const: 1
+ description: |
+ The phandle's argument in the PHY specifier selects one of the two
+ channels of the retimer
+
+required:
+ - compatible
+ - reg
+ - "#phy-cells"
+
+additionalProperties: false
+
+examples:
+ - |
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ phy@18 {
+ compatible = "ti,ds125df111";
+ reg = <0x18>;
+ #phy-cells = <1>;
+ };
+ };
--
2.25.1
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related
* [PATCH v4 linux-phy 2/3] phy: ti: alphabetically sort Kconfig and Makefile
From: Ioana Ciornei @ 2026-05-18 14:20 UTC (permalink / raw)
To: vkoul, neil.armstrong, robh, krzk+dt, conor+dt, johan, linux-phy
Cc: devicetree, linux-kernel
In-Reply-To: <20260518142026.3098496-1-ioana.ciornei@nxp.com>
Sort alphabetically the entries in the Kconfig and Makefile files.
Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
---
Changes in v4:
- patch is new
---
drivers/phy/ti/Kconfig | 92 ++++++++++++++++++++---------------------
drivers/phy/ti/Makefile | 12 +++---
2 files changed, 52 insertions(+), 52 deletions(-)
diff --git a/drivers/phy/ti/Kconfig b/drivers/phy/ti/Kconfig
index b40f28019131..dbe65500f20c 100644
--- a/drivers/phy/ti/Kconfig
+++ b/drivers/phy/ti/Kconfig
@@ -2,24 +2,29 @@
#
# Phy drivers for TI platforms
#
-config PHY_DA8XX_USB
- tristate "TI DA8xx USB PHY Driver"
- depends on ARCH_DAVINCI_DA8XX || COMPILE_TEST
- select GENERIC_PHY
- select MFD_SYSCON
+config OMAP_CONTROL_PHY
+ tristate "OMAP CONTROL PHY Driver"
+ depends on ARCH_OMAP2PLUS || COMPILE_TEST
help
- Enable this to support the USB PHY on DA8xx SoCs.
-
- This driver controls both the USB 1.1 PHY and the USB 2.0 PHY.
+ Enable this to add support for the PHY part present in the control
+ module. This driver has API to power on the USB2 PHY and to write to
+ the mailbox. The mailbox is present only in omap4 and the register to
+ power on the USB2 PHY is present in OMAP4 and OMAP5. OMAP5 has an
+ additional register to power on USB3 PHY/SATA PHY/PCIE PHY
+ (PIPE3 PHY).
-config PHY_DM816X_USB
- tristate "TI dm816x USB PHY driver"
- depends on ARCH_OMAP2PLUS || COMPILE_TEST
+config OMAP_USB2
+ tristate "OMAP USB2 PHY Driver"
+ depends on ARCH_OMAP2PLUS || ARCH_K3 || COMPILE_TEST
depends on USB_SUPPORT
select GENERIC_PHY
select USB_PHY
+ select OMAP_CONTROL_PHY if ARCH_OMAP2PLUS || COMPILE_TEST
help
- Enable this for dm816x USB to work.
+ Enable this to support the transceiver that is part of SOC. This
+ driver takes care of all the PHY functionality apart from comparator.
+ The USB OTG controller communicates with the comparator using this
+ driver.
config PHY_AM654_SERDES
tristate "TI AM654 SERDES support"
@@ -33,6 +38,25 @@ config PHY_AM654_SERDES
This option enables support for TI AM654 SerDes PHY used for
PCIe.
+config PHY_DA8XX_USB
+ tristate "TI DA8xx USB PHY Driver"
+ depends on ARCH_DAVINCI_DA8XX || COMPILE_TEST
+ select GENERIC_PHY
+ select MFD_SYSCON
+ help
+ Enable this to support the USB PHY on DA8xx SoCs.
+
+ This driver controls both the USB 1.1 PHY and the USB 2.0 PHY.
+
+config PHY_DM816X_USB
+ tristate "TI dm816x USB PHY driver"
+ depends on ARCH_OMAP2PLUS || COMPILE_TEST
+ depends on USB_SUPPORT
+ select GENERIC_PHY
+ select USB_PHY
+ help
+ Enable this for dm816x USB to work.
+
config PHY_J721E_WIZ
tristate "TI J721E WIZ (SERDES Wrapper) support"
depends on OF && (ARCH_K3 || COMPILE_TEST)
@@ -49,29 +73,20 @@ config PHY_J721E_WIZ
three clock selects (pll0, pll1, dig) and resets for each of the
lanes.
-config OMAP_CONTROL_PHY
- tristate "OMAP CONTROL PHY Driver"
- depends on ARCH_OMAP2PLUS || COMPILE_TEST
+config PHY_TI_GMII_SEL
+ tristate
+ select GENERIC_PHY
+ select REGMAP
help
- Enable this to add support for the PHY part present in the control
- module. This driver has API to power on the USB2 PHY and to write to
- the mailbox. The mailbox is present only in omap4 and the register to
- power on the USB2 PHY is present in OMAP4 and OMAP5. OMAP5 has an
- additional register to power on USB3 PHY/SATA PHY/PCIE PHY
- (PIPE3 PHY).
+ This driver supports configuring of the TI CPSW Port mode depending on
+ the Ethernet PHY connected to the CPSW Port.
-config OMAP_USB2
- tristate "OMAP USB2 PHY Driver"
- depends on ARCH_OMAP2PLUS || ARCH_K3 || COMPILE_TEST
- depends on USB_SUPPORT
+config PHY_TUSB1210
+ tristate "TI TUSB1210 ULPI PHY module"
+ depends on USB_ULPI_BUS
select GENERIC_PHY
- select USB_PHY
- select OMAP_CONTROL_PHY if ARCH_OMAP2PLUS || COMPILE_TEST
help
- Enable this to support the transceiver that is part of SOC. This
- driver takes care of all the PHY functionality apart from comparator.
- The USB OTG controller communicates with the comparator using this
- driver.
+ Support for TI TUSB1210 USB ULPI PHY.
config TI_PIPE3
tristate "TI PIPE3 PHY Driver"
@@ -84,13 +99,6 @@ config TI_PIPE3
This driver interacts with the "OMAP Control PHY Driver" to power
on/off the PHY.
-config PHY_TUSB1210
- tristate "TI TUSB1210 ULPI PHY module"
- depends on USB_ULPI_BUS
- select GENERIC_PHY
- help
- Support for TI TUSB1210 USB ULPI PHY.
-
config TWL4030_USB
tristate "TWL4030 USB Transceiver Driver"
depends on TWL4030_CORE && REGULATOR_TWL4030 && USB_MUSB_OMAP2PLUS
@@ -103,11 +111,3 @@ config TWL4030_USB
family chips (including the TWL5030 and TPS659x0 devices).
This transceiver supports high and full speed devices plus,
in host mode, low speed.
-
-config PHY_TI_GMII_SEL
- tristate
- select GENERIC_PHY
- select REGMAP
- help
- This driver supports configuring of the TI CPSW Port mode depending on
- the Ethernet PHY connected to the CPSW Port.
diff --git a/drivers/phy/ti/Makefile b/drivers/phy/ti/Makefile
index dcba2571c9bd..975fb8448ba5 100644
--- a/drivers/phy/ti/Makefile
+++ b/drivers/phy/ti/Makefile
@@ -1,11 +1,11 @@
# SPDX-License-Identifier: GPL-2.0
-obj-$(CONFIG_PHY_DA8XX_USB) += phy-da8xx-usb.o
-obj-$(CONFIG_PHY_DM816X_USB) += phy-dm816x-usb.o
obj-$(CONFIG_OMAP_CONTROL_PHY) += phy-omap-control.o
obj-$(CONFIG_OMAP_USB2) += phy-omap-usb2.o
-obj-$(CONFIG_TI_PIPE3) += phy-ti-pipe3.o
-obj-$(CONFIG_PHY_TUSB1210) += phy-tusb1210.o
-obj-$(CONFIG_TWL4030_USB) += phy-twl4030-usb.o
obj-$(CONFIG_PHY_AM654_SERDES) += phy-am654-serdes.o
-obj-$(CONFIG_PHY_TI_GMII_SEL) += phy-gmii-sel.o
+obj-$(CONFIG_PHY_DA8XX_USB) += phy-da8xx-usb.o
+obj-$(CONFIG_PHY_DM816X_USB) += phy-dm816x-usb.o
obj-$(CONFIG_PHY_J721E_WIZ) += phy-j721e-wiz.o
+obj-$(CONFIG_PHY_TI_GMII_SEL) += phy-gmii-sel.o
+obj-$(CONFIG_PHY_TUSB1210) += phy-tusb1210.o
+obj-$(CONFIG_TI_PIPE3) += phy-ti-pipe3.o
+obj-$(CONFIG_TWL4030_USB) += phy-twl4030-usb.o
--
2.25.1
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related
* [PATCH v4 linux-phy 3/3] phy: ti: add PHY driver for TI DS125DF111 Dual-Channel Retimer
From: Ioana Ciornei @ 2026-05-18 14:20 UTC (permalink / raw)
To: vkoul, neil.armstrong, robh, krzk+dt, conor+dt, johan, linux-phy
Cc: devicetree, linux-kernel
In-Reply-To: <20260518142026.3098496-1-ioana.ciornei@nxp.com>
Add a generic PHY driver for the TI DS125DF111 Multi-Protocol
Dual-Channel Retimer. The driver currently supports only 10G and 1G link
speeds but it can easily extended to also cover other usecases.
Since the available datasheet (https://www.ti.com/lit/gpn/DS125DF111)
does not name the registers, the name for the macros were determined by
their usage pattern.
A PHY device is created for each of the two channels present on the
retimer. This allows for independent configuration of the two channels.
This capability is especially important on retimers which have more than
2 channels that can be, depending on the board design, connected in
multiple different ways to the SerDes lanes.
Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
---
Changes in v4:
- Use lower case for hex values
- Insert the new entry in the Kconfig/Makefile so that we keep the
alphabetical order established in the previous patch
Changes in v3:
- Use reverse Christmas tree ordering
- Print a symbolic description in case of error
- Some words do not need to be capitalized
- Remove duplicated exit code path
- Return -EINVAL in case of unsupported submode received in .set_mode()
- Add a .validate() callback
- Remove comma after sentinel entry
- Add a ds125df111_rmw() helper
- Use read_poll_timeout() to wait for channel reset to complete
Changes in v2:
- Explicitly include all the needed headers
- Change ds125df111_xlate() so that it returns an error if args_count is
not exactly 1
- Add a MAINTAINERS entry
---
MAINTAINERS | 7 +
drivers/phy/ti/Kconfig | 10 ++
drivers/phy/ti/Makefile | 1 +
drivers/phy/ti/phy-ds125df111.c | 294 ++++++++++++++++++++++++++++++++
4 files changed, 312 insertions(+)
create mode 100644 drivers/phy/ti/phy-ds125df111.c
diff --git a/MAINTAINERS b/MAINTAINERS
index f877e5aaf2c7..58f410b666e7 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -26781,6 +26781,13 @@ T: git git://linuxtv.org/mhadli/v4l-dvb-davinci_devices.git
F: drivers/media/platform/ti/davinci/
F: include/media/davinci/
+TI DS125DF111 RETIMER PHY DRIVER
+M: Ioana Ciornei <ioana.ciornei@nxp.com>
+L: linux-phy@lists.infradead.org (moderated for non-subscribers)
+S: Maintained
+F: Documentation/devicetree/bindings/phy/ti,ds125df111.yaml
+F: drivers/phy/ti/phy-ds125df111.c
+
TI ENHANCED CAPTURE (eCAP) DRIVER
M: Vignesh Raghavendra <vigneshr@ti.com>
R: Julien Panis <jpanis@baylibre.com>
diff --git a/drivers/phy/ti/Kconfig b/drivers/phy/ti/Kconfig
index dbe65500f20c..b52c7eabe24c 100644
--- a/drivers/phy/ti/Kconfig
+++ b/drivers/phy/ti/Kconfig
@@ -73,6 +73,16 @@ config PHY_J721E_WIZ
three clock selects (pll0, pll1, dig) and resets for each of the
lanes.
+config PHY_TI_DS125DF111
+ tristate "TI DS125DF111 2-Channel Retimer Driver"
+ depends on OF && I2C
+ select GENERIC_PHY
+ help
+ Enable this to add support for configuration and runtime management
+ of the TI DS125DF111 Multi-Protocol 2-Channel Retimer.
+ The retimer is modeled as a Generic PHY and supports both 10G and 1G
+ link speeds.
+
config PHY_TI_GMII_SEL
tristate
select GENERIC_PHY
diff --git a/drivers/phy/ti/Makefile b/drivers/phy/ti/Makefile
index 975fb8448ba5..a002ef8764a2 100644
--- a/drivers/phy/ti/Makefile
+++ b/drivers/phy/ti/Makefile
@@ -5,6 +5,7 @@ obj-$(CONFIG_PHY_AM654_SERDES) += phy-am654-serdes.o
obj-$(CONFIG_PHY_DA8XX_USB) += phy-da8xx-usb.o
obj-$(CONFIG_PHY_DM816X_USB) += phy-dm816x-usb.o
obj-$(CONFIG_PHY_J721E_WIZ) += phy-j721e-wiz.o
+obj-$(CONFIG_PHY_TI_DS125DF111) += phy-ds125df111.o
obj-$(CONFIG_PHY_TI_GMII_SEL) += phy-gmii-sel.o
obj-$(CONFIG_PHY_TUSB1210) += phy-tusb1210.o
obj-$(CONFIG_TI_PIPE3) += phy-ti-pipe3.o
diff --git a/drivers/phy/ti/phy-ds125df111.c b/drivers/phy/ti/phy-ds125df111.c
new file mode 100644
index 000000000000..84ff96d7d589
--- /dev/null
+++ b/drivers/phy/ti/phy-ds125df111.c
@@ -0,0 +1,294 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright 2026 NXP */
+
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/i2c.h>
+#include <linux/iopoll.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/phy.h>
+#include <linux/phy/phy.h>
+#include <linux/slab.h>
+
+#define DS125DF111_NUM_CH 2
+#define DS125DF111_NUM_VCO_GROUP_REG 5
+
+#define DS125DF111_CH_SELECT 0xff
+#define DS125DF111_CH_SELECT_TARGET_MASK GENMASK(3, 0)
+#define DS125DF111_CH_SELECT_EN BIT(2)
+
+#define DS125DF111_CH_CTRL 0x00
+#define DS125DF111_CH_CTRL_RESET BIT(2) /* self clearing */
+
+#define DS125DF111_CH_RST_SLEEP_US 10
+#define DS125DF111_CH_RST_TIMEOUT_US 10000
+
+#define DS125DF111_VCO_GROUP_BASE 0x60
+
+#define DS125DF111_RATIOS 0x2f
+#define DS125DF111_RATIOS_RATE_MASK GENMASK(7, 6)
+#define DS125DF111_RATIOS_SUBRATE_MASK GENMASK(5, 4)
+#define DS125DF111_RATIOS_MASK GENMASK(7, 4)
+
+struct ds125df111_ch {
+ struct phy *phy;
+ struct ds125df111_priv *priv;
+ int idx;
+};
+
+struct ds125df111_priv {
+ struct ds125df111_ch ch[DS125DF111_NUM_CH];
+ struct i2c_client *client;
+ struct mutex mutex; /* protects access to shared registers */
+};
+
+enum ds125df111_mode {
+ FREQ_1G,
+ FREQ_10G,
+};
+
+static const struct ds125df111_config {
+ u8 vco_group[DS125DF111_NUM_VCO_GROUP_REG];
+ u8 rate;
+ u8 subrate;
+} ds125df111_cfg[] = {
+ [FREQ_1G] = {
+ /* VCO group #0 = 10GHz, VCO group #1 = 10GHz */
+ .vco_group = {0x00, 0xB2, 0x00, 0xB2, 0xCC},
+ /* By using the following combination of rate and subrate we
+ * select divide ratios of 1, 2, 4, 8 on both groups
+ */
+ .rate = 0x1,
+ .subrate = 0x2,
+ },
+
+ [FREQ_10G] = {
+ /* VCO group #0 = 10.3125GHz, VCO group #1 = 10.3125GHz */
+ .vco_group = {0x90, 0xB3, 0x90, 0xB3, 0xCD},
+ /* By using the following combination of rate and subrate we
+ * select divide ratios of 1 on both groups
+ */
+ .rate = 0x1,
+ .subrate = 0x3,
+ },
+};
+
+static int ds125df111_rmw(struct ds125df111_priv *priv, u8 reg, u8 clr, u8 set)
+{
+ struct i2c_client *i2c = priv->client;
+ int err;
+ u8 val;
+
+ err = i2c_smbus_read_byte_data(i2c, reg);
+ if (err < 0)
+ return err;
+
+ val = (u8)err;
+ val &= ~clr;
+ val |= set;
+
+ err = i2c_smbus_write_byte_data(i2c, reg, val);
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
+static int ds125df111_configure(struct phy *phy,
+ const struct ds125df111_config *cfg)
+{
+ struct ds125df111_ch *ch = phy_get_drvdata(phy);
+ struct ds125df111_priv *priv = ch->priv;
+ struct i2c_client *i2c = priv->client;
+ struct device *dev = &phy->dev;
+ u8 ratios_val;
+ int err, i;
+ int val;
+
+ mutex_lock(&priv->mutex);
+
+ /* Make sure that any subsequent read/write operation will be directed
+ * only to the registers of the selected channel
+ */
+ err = ds125df111_rmw(priv, DS125DF111_CH_SELECT,
+ DS125DF111_CH_SELECT_TARGET_MASK,
+ DS125DF111_CH_SELECT_EN | ch->idx);
+ if (err < 0) {
+ dev_err(dev, "Unable to select channel: %pe\n", ERR_PTR(err));
+ goto out;
+ }
+
+ /* Reset channel registers and wait until the bit was cleared */
+ err = ds125df111_rmw(priv, DS125DF111_CH_CTRL, 0,
+ DS125DF111_CH_CTRL_RESET);
+ if (err < 0) {
+ dev_err(dev, "Error resetting channel configuration: %pe\n",
+ ERR_PTR(err));
+ goto out;
+ }
+
+ err = read_poll_timeout(i2c_smbus_read_byte_data, val,
+ val < 0 || !(val & DS125DF111_CH_CTRL_RESET),
+ DS125DF111_CH_RST_SLEEP_US,
+ DS125DF111_CH_RST_TIMEOUT_US, false, i2c,
+ DS125DF111_CH_CTRL);
+ if (err) {
+ dev_err(dev, "Timed out waiting for channel reset: %pe\n",
+ ERR_PTR(err));
+ goto out;
+ }
+
+ if (val < 0) {
+ dev_err(dev, "Error reading reset status: %pe\n", ERR_PTR(val));
+ err = val;
+ goto out;
+ }
+
+ /* Program the VCO group frequencies */
+ for (i = 0; i < DS125DF111_NUM_VCO_GROUP_REG; i++) {
+ err = i2c_smbus_write_byte_data(i2c,
+ DS125DF111_VCO_GROUP_BASE + i,
+ cfg->vco_group[i]);
+ if (err < 0) {
+ dev_err(dev, "Error programming VCO group: %pe\n",
+ ERR_PTR(err));
+ goto out;
+ }
+ }
+
+ /* Set the divide ratios for the VCO groups */
+ ratios_val = FIELD_PREP(DS125DF111_RATIOS_RATE_MASK, cfg->rate) |
+ FIELD_PREP(DS125DF111_RATIOS_SUBRATE_MASK, cfg->subrate);
+ err = ds125df111_rmw(priv, DS125DF111_RATIOS, DS125DF111_RATIOS_MASK,
+ ratios_val);
+ if (err < 0) {
+ dev_err(dev, "Error programming the divide ratios: %pe\n",
+ ERR_PTR(err));
+ goto out;
+ }
+
+out:
+ mutex_unlock(&priv->mutex);
+
+ return err;
+}
+
+static int ds125df111_set_mode(struct phy *phy, enum phy_mode mode, int submode)
+{
+ const struct ds125df111_config *cfg;
+
+ if (mode != PHY_MODE_ETHERNET)
+ return -EINVAL;
+
+ switch (submode) {
+ case PHY_INTERFACE_MODE_10GBASER:
+ cfg = &ds125df111_cfg[FREQ_10G];
+ break;
+ case PHY_INTERFACE_MODE_1000BASEX:
+ case PHY_INTERFACE_MODE_SGMII:
+ cfg = &ds125df111_cfg[FREQ_1G];
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return ds125df111_configure(phy, cfg);
+}
+
+static int ds125df111_validate(struct phy *phy, enum phy_mode mode, int submode,
+ union phy_configure_opts *opts __always_unused)
+{
+ if (mode != PHY_MODE_ETHERNET)
+ return -EINVAL;
+
+ switch (submode) {
+ case PHY_INTERFACE_MODE_10GBASER:
+ case PHY_INTERFACE_MODE_1000BASEX:
+ case PHY_INTERFACE_MODE_SGMII:
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct phy_ops ds125df111_ops = {
+ .validate = ds125df111_validate,
+ .set_mode = ds125df111_set_mode,
+ .owner = THIS_MODULE,
+};
+
+static struct phy *ds125df111_xlate(struct device *dev,
+ const struct of_phandle_args *args)
+{
+ struct ds125df111_priv *priv = dev_get_drvdata(dev);
+ u32 idx;
+
+ if (args->args_count != 1)
+ return ERR_PTR(-EINVAL);
+
+ idx = args->args[0];
+ if (idx >= DS125DF111_NUM_CH) {
+ dev_err(dev, "Maximum number of channels is %d\n",
+ DS125DF111_NUM_CH);
+ return ERR_PTR(-EINVAL);
+ }
+
+ return priv->ch[idx].phy;
+}
+
+static int ds125df111_probe(struct i2c_client *client)
+{
+ struct device *dev = &client->dev;
+ struct phy_provider *provider;
+ struct ds125df111_priv *priv;
+ int i, err;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+ priv->client = client;
+ err = devm_mutex_init(dev, &priv->mutex);
+ if (err)
+ return err;
+
+ i2c_set_clientdata(client, priv);
+
+ for (i = 0; i < DS125DF111_NUM_CH; i++) {
+ struct ds125df111_ch *ch = &priv->ch[i];
+ struct phy *phy;
+
+ phy = devm_phy_create(dev, NULL, &ds125df111_ops);
+ if (IS_ERR(phy))
+ return PTR_ERR(phy);
+
+ ch->idx = i;
+ ch->priv = priv;
+ ch->phy = phy;
+
+ phy_set_drvdata(phy, ch);
+ }
+
+ provider = devm_of_phy_provider_register(dev, ds125df111_xlate);
+
+ return PTR_ERR_OR_ZERO(provider);
+}
+
+static const struct of_device_id ds125df111_dt_ids[] = {
+ { .compatible = "ti,ds125df111", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, ds125df111_dt_ids);
+
+static struct i2c_driver ds125df111_driver = {
+ .driver = {
+ .name = "ds125df111",
+ .of_match_table = ds125df111_dt_ids,
+ },
+ .probe = ds125df111_probe,
+};
+module_i2c_driver(ds125df111_driver);
+
+MODULE_AUTHOR("Ioana Ciornei <ioana.ciornei@nxp.com>");
+MODULE_DESCRIPTION("TI DS125DF111 Retimer driver");
+MODULE_LICENSE("GPL");
--
2.25.1
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related
* Re: [PATCH 2/2] phy: econet: Add EcoNet USB PHY
From: sashiko-bot @ 2026-05-18 14:40 UTC (permalink / raw)
To: Caleb James DeLisle
Cc: linux-phy, robh, devicetree, vkoul, neil.armstrong, conor+dt,
olteanv
In-Reply-To: <20260518141343.401555-3-cjd@cjdns.fr>
Thank you for your contribution! Sashiko AI review found 6 potential issue(s) to consider:
- [High] Race condition on shared Frequency Meter registers during concurrent PHY initialization.
- [High] Hardware state machine race due to polling data register instead of valid bit.
- [High] Devres lifecycle bug caused by attaching memory and regmap resources to the child PHY device.
- [Medium] Iteration over disabled Device Tree nodes accesses unpowered hardware.
- [Medium] Missing bounds check on dynamically calculated slew rate configuration exposes hardware to silent bit truncation.
- [Low] Pointer signedness mismatch in `regmap_read_poll_timeout` causes compiler warnings and violates type safety.
--
commit ab614fd3da75925164048ae81b01b59ec760d67e
Author: Caleb James DeLisle <cjd@cjdns.fr>
phy: econet: Add EcoNet USB PHY
This commit adds support for the USB PHY found on EcoNet EN751221, EN751627,
and EN7528 based SoCs. It implements the setup and tuning rituals for both
USB 2.0 and USB 3.0 PHY blocks.
Link: https://github.com/openwrt/openwrt/pull/23264#issuecomment-4415906568
> diff --git a/drivers/phy/phy-econet-usb.c b/drivers/phy/phy-econet-usb.c
> new file mode 100644
> index 0000000000000..e8fa2e80eb130
> --- /dev/null
> +++ b/drivers/phy/phy-econet-usb.c
[ ... ]
> +static void u2_slew_rate_calibration(struct econet_usb_phy_priv *priv,
> + struct econet_phy_instance *instance)
> +{
> + struct regmap *com = instance->regmap;
> + struct regmap *regmap = priv->regmap;
> + int fm_out = 0;
Does this pointer type cause compiler warnings?
regmap_read_poll_timeout() passes the address of fm_out to regmap_read(),
which expects an unsigned int pointer. Using a signed int can lead to
incompatible pointer type warnings.
> + u32 srctrl;
> +
> + /* Enable HS TX SR calibration */
> + regmap_set_bits(com, U2PHY_COM + USBPHYACR0, RG_HSTX_SRCAL_EN);
> +
> + usleep_range(1000, 1500);
> +
> + /* Enable Free run clock */
> + regmap_set_bits(regmap, FMREG + FMMONR1, RG_FRCK_EN);
> +
> + /* Select Monitor Clock */
> + regmap_update_bits(regmap, FMREG + FMCR0, RG_MONCLK_SEL,
> + FIELD_PREP(RG_MONCLK_SEL, instance->port_id));
Is it possible for multiple PHY ports to race when accessing these shared
FMREG registers?
The Linux PHY core serializes phy_init() only per-PHY instance, meaning
multiple ports could potentially initialize at the same time. If two
threads run this calibration concurrently, could one overwrite the active
port selection or prematurely clear the frequency detection enable bit
while the other is still polling?
Might this require a driver-level mutex to serialize access to the FMREG
hardware block?
> +
> + /* Set cyclecnt */
> + regmap_update_bits(regmap, FMREG + FMCR0, RG_CYCLECNT,
> + FIELD_PREP_CONST(RG_CYCLECNT,
> + ECONET_USB_PHY_U2_FM_DET_CYCLE_CNT));
> +
> + /* Enable Frequency meter */
> + regmap_set_bits(regmap, FMREG + FMCR0, RG_FREQDET_EN);
> +
> + /* Timeout can happen and we will apply workaround at the end */
> + regmap_read_poll_timeout(regmap, FMREG + FMMONR0, fm_out,
> + fm_out, ECONET_USB_PHY_FREQDET_SLEEP,
> + ECONET_USB_PHY_FREQDET_TIMEOUT);
Could this loop prematurely succeed by reading a stale value?
FMMONR0 holds the result of the calibration. If this function is called
a second time for another port, polling for fm_out != 0 might instantly
succeed using the previous run's result.
Would it be more robust to poll the FMMONR1 register for the RG_FM_VALID
flag before reading the result from FMMONR0?
[ ... ]
> + } else {
> + /* (1024 / FM_OUT) * REF_CK * U2_SR_COEF (round to nearest) */
> + srctrl = ECONET_USB_PHY_REF_CK * ECONET_USB_PHY_U2_SR_COEF;
> + srctrl = (srctrl * ECONET_USB_PHY_U2_FM_DET_CYCLE_CNT) / fm_out;
> + srctrl = DIV_ROUND_CLOSEST(srctrl,
> + ECONET_USB_PHY_U2_SR_COEF_DIVISOR);
> + dev_info(&instance->phy->dev,
> + "frequency meter result 0x%x, set slew rate 0x%x\n",
> + fm_out, srctrl);
> + }
> +
> + /* Set slew rate */
> + regmap_update_bits(com, U2PHY_COM + USBPHYACR0, RG_HSTX_SRCTRL,
> + FIELD_PREP(RG_HSTX_SRCTRL, srctrl));
Is there a risk of silent bit truncation here?
The target field RG_HSTX_SRCTRL is only 3 bits wide. If the frequency meter
provides a low output value (for instance, due to a stale read), the division
above could yield a value much larger than 7.
Since FIELD_PREP masks runtime values without error, could this write
an unintended configuration to the hardware? Should the calculated srctrl
value be clamped before applying it?
[ ... ]
> +static int econet_usb_phy_probe(struct platform_device *pdev)
> +{
> + struct device *dev = &pdev->dev;
> + struct device_node *np = dev->of_node;
[ ... ]
> + phy_n = 0;
> + for_each_child_of_node_scoped(np, child_np) {
Does this loop interact with disabled hardware blocks?
Using for_each_child_of_node_scoped() will iterate over all child nodes,
including those with status = "disabled" in the device tree.
This results in the driver mapping memory, initializing regmaps, and
calling econet_usb_phy_exit() to write to registers on unpowered or
unclocked hardware, which can sometimes cause system hangs.
Would it be safer to use for_each_available_child_of_node_scoped()?
> + struct econet_phy_instance *instance;
> + void __iomem *phy_base;
> + struct device *subdev;
> + struct resource res;
> + int retval;
[ ... ]
> + instance->phy = devm_phy_create(dev, child_np, &econet_phy);
> + if (IS_ERR(instance->phy))
> + return dev_err_probe(dev, PTR_ERR(instance->phy),
> + "failed to create phy\n");
> +
> + subdev = &instance->phy->dev;
> + retval = of_address_to_resource(child_np, 0, &res);
> + if (retval)
> + return dev_err_probe(subdev, retval,
> + "getting reg for phy %d\n",
> + phy_n);
> +
> + phy_base = devm_ioremap_resource(subdev, &res);
Can using the child PHY device for resource allocations cause memory leaks
and probe failures?
The subdev pointer belongs to the child PHY device created by
devm_phy_create(). Devres resources are tied to the device's reference
count reaching zero.
If userspace holds an active sysfs file descriptor for the PHY device when
the parent platform driver unbinds, the subdev kobject stays alive and
the memory region is not freed.
If the platform driver is re-probed, it might fail with -EBUSY when
requesting the same memory region. Should devm_ioremap_resource and
devm_regmap_init_mmio be associated with the parent platform device instead?
> + if (IS_ERR(phy_base))
> + return dev_err_probe(subdev, PTR_ERR(phy_base),
> + "remapping reg for phy %d\n",
> + phy_n);
> +
> + instance->regmap =
> + devm_regmap_init_mmio(subdev, phy_base,
> + &econet_usb_phy_regmap_config);
> + if (IS_ERR(instance->regmap))
> + return dev_err_probe(subdev, PTR_ERR(instance->regmap),
> + "making regmap for phy %d\n",
> + phy_n);
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260518141343.401555-1-cjd@cjdns.fr?part=2
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* Re: [PATCH 2/5] phy: core: Define TBT phy_mode
From: Dmitry Baryshkov @ 2026-05-18 15:19 UTC (permalink / raw)
To: Konrad Dybcio
Cc: Konrad Dybcio, Vinod Koul, Neil Armstrong, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson, linux-kernel,
linux-phy, linux-arm-msm, devicetree, usb4-upstream,
Raghavendra Thoorpu, Mika Westerberg, Sven Peter
In-Reply-To: <0880f634-ea56-4c0e-822d-aa7c056fdcc3@oss.qualcomm.com>
On Mon, May 18, 2026 at 02:29:26PM +0200, Konrad Dybcio wrote:
> On 5/18/26 2:25 PM, Dmitry Baryshkov wrote:
> > On Mon, May 18, 2026 at 12:29:49PM +0200, Konrad Dybcio wrote:
> >> From: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
> >>
> >> There exist OS-accessible USB4 and Thunderbolt PHYs that need specific
> >> configuration. Define a new phy_mode for them.
> >>
> >> Currently, USB4 and TBT3 are defined as submodes, because they're quite
> >> distinct, most visibly in the electrical/analog aspects (slightly
> >> different frequencies, timings, etc.). This results in a need to make
> >> the PHY aware of the actual mode needed (at least in the Qualcomm
> >> implementation, but I believe that'll be a general need).
> >>
> >> Newer versions of TBT are basically supersets of USB4 with higher
> >> host-side requirements, so these are not defined. This can always be
> >> changed as necessary.
> >>
> >> Signed-off-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
> >> ---
> >> include/linux/phy/phy-tbt.h | 14 ++++++++++++++
> >> include/linux/phy/phy.h | 2 ++
> >> 2 files changed, 16 insertions(+)
> >>
> >> diff --git a/include/linux/phy/phy-tbt.h b/include/linux/phy/phy-tbt.h
> >> new file mode 100644
> >> index 000000000000..5f48059814e1
> >> --- /dev/null
> >> +++ b/include/linux/phy/phy-tbt.h
> >> @@ -0,0 +1,14 @@
> >> +/* SPDX-License-Identifier: GPL-2.0 */
> >> +/*
> >> + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
> >> + */
> >> +
> >> +#ifndef __PHY_TBT_H_
> >> +#define __PHY_TBT_H_
> >> +
> >> +enum tbt_phy_submode {
> >> + PHY_SUBMODE_TBT3,
> >> + PHY_SUBMODE_USB4,
> >
> > Do we need TBT2 as a separate submode?
>
> I would like to avoid extending that unless there's a user for it
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
--
With best wishes
Dmitry
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* Re: [PATCH 3/5] phy: qualcomm: qmp-combo: Add preliminary USB4 support
From: Dmitry Baryshkov @ 2026-05-18 15:38 UTC (permalink / raw)
To: Konrad Dybcio
Cc: Konrad Dybcio, Vinod Koul, Neil Armstrong, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson, linux-kernel,
linux-phy, linux-arm-msm, devicetree, usb4-upstream,
Raghavendra Thoorpu, Mika Westerberg, Sven Peter
In-Reply-To: <9aad8e45-b0a5-4c59-8793-8c0747d8fafa@oss.qualcomm.com>
On Mon, May 18, 2026 at 04:15:16PM +0200, Konrad Dybcio wrote:
> On 5/18/26 3:57 PM, Dmitry Baryshkov wrote:
> > On Mon, May 18, 2026 at 12:29:50PM +0200, Konrad Dybcio wrote:
> >> From: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
> >>
> >> Some Combo PHYs (so far only on SC8280XP, X1E80100 and Glymur), come in
> >> a flavor called USB43DP, which as the name implies, features USB4, USB3
> >> and DP signal processing capabilities. In that architecture, USB3 and
> >> USB4 PHYs share the same USB_PLL while featuring separate logic spaces.
> >> The DP part is roughly the same as on the instances without USB4.
> >>
> >> The USB4 and USB3/DP operation modes of the PHY are mutually exclusive.
> >> Only one USB protocol (and flavor of pipe clock) can be active at a
> >> given moment (not to be confused with USB3 not being able to be
> >> tunneled as USB4 packets - that of course remains possible).
> >> The DP PLL is still used for clocking tunneled DP links. It may be
> >> turned off to save power when no tunnels are active, but that's left as
> >> a TODO item for now.
> >>
> >> Due to the nature of USB4, the Type-C handling happens entirely inside
> >> the Host Router, and as such the QMPPHY's mux_set() function is
> >> nullified for the period when USB4 PHY remains active. This is strictly
> >> necessary, as the Host Router driver is going to excercise manual
> >> control over the USB4 PHY's power state, which is needed by the suspend
> >> and resume flows. Failure to control that synchronously with other
> >> parts of the code results in a SoC crash by unlocked access.
> >>
> >> Because of that, a new struct phy is spawned to expose the USB4 mode,
> >> along with a .set_mode callback to allow toggling between USB4 and TBT3
> >> submodes.
> >>
> >> Thunderbolt 3, having a number of differences vs USB4, requires a
> >> couple specific overrides, pertaining to electrical characteristics,
> >> which are easily accommodated for.
> >>
> >> Signed-off-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
> >> ---
> >> drivers/phy/qualcomm/phy-qcom-qmp-combo.c | 392 ++++++++++++++++++++++++------
> >> 1 file changed, 322 insertions(+), 70 deletions(-)
> >>
> >
> > Overall it looks good. The major question (after looking at TODOs), do
> > we need a separate submode for USB+DP / TBT+DP?
>
> The problem space is as follows:
>
> After a TBT (collectively TBT3+ and USB4) link has been established and
> we have a link partner, we may (based on the HW capabilities and user
> config, such as kernel params but not only) start or stop a DP tunnel at
> runtime. On Qualcomm hardware, the PHY is kept in USB4 mode and its DP
> AUX lines are not used (instead, the encapsulated DP AUX packets are r/w
> entirely within the USB4 subsystem via a pair of FIFOs that Linux sees
> as a separate DP AUX host)
So far so good. But I still don't grok if having a DP-over-USB4 is a
separate submode or not. I.e. I see code (and TODOs) to detect and
handle DP going on and off. Would it be better if we specify that
explicitly?
> Then, on hamoa/glymur specifically, any of the 3 USB4-capable DP hosts
> can be muxed to either of the 2 DPIN ports on any of the 3 USB4 routers
> (and each of these routers is hardwired to one of the PHYs).
>
> To underline, we have 3 DP producers and 6 consumers. If there's e.g. a
> super high-res display at one of the physical ports, or a long
> daisy-chain, we may need to use 2 DPTXes to service 1 receptacle. Then,
> we would only need one of the PHYs (associated with the router that's
> wired to that port) to provide a DP clock.
>
> This, along with the normal (logical or physical) present/absent status
> can change at runtime. My plan is to use phy_set_opts(dp_tunelling=true)
> or something along those lines to toggle that bit as necessary
I don't see phy_set_opts(). So maybe a submode then...
--
With best wishes
Dmitry
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* [PATCH V1 0/3] Add Hawi UFS PHY and Controller support
From: palash.kambar @ 2026-05-18 16:53 UTC (permalink / raw)
To: vkoul, neil.armstrong, robh, krzk+dt, conor+dt, mani, alim.akhtar,
avri.altman, bvanassche, andersson, dmitry.baryshkov, abel.vesa,
luca.weiss
Cc: linux-arm-msm, linux-phy, devicetree, linux-kernel, linux-scsi,
Palash Kambar
From: Palash Kambar <palash.kambar@oss.qualcomm.com>
This series introduces devicetree binding documentation and PHY
initialization support required to enable UFS on this platform.
1. Devicetree binding documentation for the QMP UFS PHY
used on Qualcomm Hawi.
2. Devicetree binding documentation for the UFS controller
instance present on the Hawi platform.
3. Initialization sequence tables and configuration required
for the QMP UFS PHY on Hawi SoC.
Palash Kambar (3):
dt-bindings: phy: qcom,sc8280xp-qmp-ufs-phy: Add Hawi UFS PHY
compatible
dt-bindings: phy: qcom,sc8280xp-qmp-ufs-phy: Document the Hawi UFS
controller
phy: qcom-qmp-ufs: Add UFS PHY support on Hawi
.../phy/qcom,sc8280xp-qmp-ufs-phy.yaml | 1 +
.../bindings/ufs/qcom,sm8650-ufshc.yaml | 2 +
.../phy/qualcomm/phy-qcom-qmp-pcs-ufs-v7.h | 22 +++
.../phy-qcom-qmp-qserdes-txrx-ufs-v8.h | 37 +++++
drivers/phy/qualcomm/phy-qcom-qmp-ufs.c | 140 ++++++++++++++++++
5 files changed, 202 insertions(+)
create mode 100644 drivers/phy/qualcomm/phy-qcom-qmp-pcs-ufs-v7.h
create mode 100644 drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-ufs-v8.h
--
2.34.1
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* [PATCH V1 1/3] dt-bindings: phy: qcom,sc8280xp-qmp-ufs-phy: Add Hawi UFS PHY compatible
From: palash.kambar @ 2026-05-18 16:53 UTC (permalink / raw)
To: vkoul, neil.armstrong, robh, krzk+dt, conor+dt, mani, alim.akhtar,
avri.altman, bvanassche, andersson, dmitry.baryshkov, abel.vesa,
luca.weiss
Cc: linux-arm-msm, linux-phy, devicetree, linux-kernel, linux-scsi,
Palash Kambar
In-Reply-To: <20260518165346.1732548-1-palash.kambar@oss.qualcomm.com>
From: Palash Kambar <palash.kambar@oss.qualcomm.com>
Document QMP UFS PHY compatible for Hawi SoC.
Signed-off-by: Palash Kambar <palash.kambar@oss.qualcomm.com>
---
.../devicetree/bindings/phy/qcom,sc8280xp-qmp-ufs-phy.yaml | 1 +
1 file changed, 1 insertion(+)
diff --git a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-ufs-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-ufs-phy.yaml
index 9616c736b6d4..2326dcf38a46 100644
--- a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-ufs-phy.yaml
+++ b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-ufs-phy.yaml
@@ -37,6 +37,7 @@ properties:
- qcom,kaanapali-qmp-ufs-phy
- const: qcom,sm8750-qmp-ufs-phy
- enum:
+ - qcom,hawi-qmp-ufs-phy
- qcom,milos-qmp-ufs-phy
- qcom,msm8996-qmp-ufs-phy
- qcom,msm8998-qmp-ufs-phy
--
2.34.1
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related
* [PATCH V1 2/3] dt-bindings: phy: qcom,sc8280xp-qmp-ufs-phy: Document the Hawi UFS controller
From: palash.kambar @ 2026-05-18 16:53 UTC (permalink / raw)
To: vkoul, neil.armstrong, robh, krzk+dt, conor+dt, mani, alim.akhtar,
avri.altman, bvanassche, andersson, dmitry.baryshkov, abel.vesa,
luca.weiss
Cc: linux-arm-msm, linux-phy, devicetree, linux-kernel, linux-scsi,
Palash Kambar
In-Reply-To: <20260518165346.1732548-1-palash.kambar@oss.qualcomm.com>
From: Palash Kambar <palash.kambar@oss.qualcomm.com>
Document the UFS Controller on the Hawi Platform.
Signed-off-by: Palash Kambar <palash.kambar@oss.qualcomm.com>
---
Documentation/devicetree/bindings/ufs/qcom,sm8650-ufshc.yaml | 2 ++
1 file changed, 2 insertions(+)
diff --git a/Documentation/devicetree/bindings/ufs/qcom,sm8650-ufshc.yaml b/Documentation/devicetree/bindings/ufs/qcom,sm8650-ufshc.yaml
index f28641c6e68f..3de00affa4c6 100644
--- a/Documentation/devicetree/bindings/ufs/qcom,sm8650-ufshc.yaml
+++ b/Documentation/devicetree/bindings/ufs/qcom,sm8650-ufshc.yaml
@@ -16,6 +16,7 @@ select:
contains:
enum:
- qcom,eliza-ufshc
+ - qcom,hawi-ufshc
- qcom,kaanapali-ufshc
- qcom,sm8650-ufshc
- qcom,sm8750-ufshc
@@ -27,6 +28,7 @@ properties:
items:
- enum:
- qcom,eliza-ufshc
+ - qcom,hawi-ufshc
- qcom,kaanapali-ufshc
- qcom,sm8650-ufshc
- qcom,sm8750-ufshc
--
2.34.1
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related
* [PATCH V1 3/3] phy: qcom-qmp-ufs: Add UFS PHY support on Hawi
From: palash.kambar @ 2026-05-18 16:53 UTC (permalink / raw)
To: vkoul, neil.armstrong, robh, krzk+dt, conor+dt, mani, alim.akhtar,
avri.altman, bvanassche, andersson, dmitry.baryshkov, abel.vesa,
luca.weiss
Cc: linux-arm-msm, linux-phy, devicetree, linux-kernel, linux-scsi,
Palash Kambar
In-Reply-To: <20260518165346.1732548-1-palash.kambar@oss.qualcomm.com>
From: Palash Kambar <palash.kambar@oss.qualcomm.com>
Add the init sequence tables and config for the UFS QMP phy found in
the Hawi SoC.
Signed-off-by: Palash Kambar <palash.kambar@oss.qualcomm.com>
---
.../phy/qualcomm/phy-qcom-qmp-pcs-ufs-v7.h | 22 +++
.../phy-qcom-qmp-qserdes-txrx-ufs-v8.h | 37 +++++
drivers/phy/qualcomm/phy-qcom-qmp-ufs.c | 140 ++++++++++++++++++
3 files changed, 199 insertions(+)
create mode 100644 drivers/phy/qualcomm/phy-qcom-qmp-pcs-ufs-v7.h
create mode 100644 drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-ufs-v8.h
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-ufs-v7.h b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-ufs-v7.h
new file mode 100644
index 000000000000..bf914c752d22
--- /dev/null
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-ufs-v7.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2026, The Linux Foundation. All rights reserved.
+ */
+
+#ifndef QCOM_PHY_QMP_PCS_UFS_V7_H_
+#define QCOM_PHY_QMP_PCS_UFS_V7_H_
+
+/* Only for QMP V7 PHY - UFS PCS registers */
+
+#define QPHY_V7_PCS_UFS_PCS_CTRL1 0x01C
+#define QPHY_V7_PCS_UFS_PLL_CNTL 0x028
+#define QPHY_V7_PCS_UFS_TX_LARGE_AMP_DRV_LVL 0x02C
+#define QPHY_V7_PCS_UFS_TX_HSGEAR_CAPABILITY 0x060
+#define QPHY_V7_PCS_UFS_RX_HSGEAR_CAPABILITY 0x094
+#define QPHY_V7_PCS_UFS_LINECFG_DISABLE 0x140
+#define QPHY_V7_PCS_UFS_RX_SIGDET_CTRL2 0x150
+#define QPHY_V7_PCS_UFS_READY_STATUS 0x16c
+#define QPHY_V7_PCS_UFS_TX_MID_TERM_CTRL1 0x1b8
+#define QPHY_V7_PCS_UFS_MULTI_LANE_CTRL1 0x1c0
+
+#endif
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-ufs-v8.h b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-ufs-v8.h
new file mode 100644
index 000000000000..5f923c3e64ec
--- /dev/null
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-ufs-v8.h
@@ -0,0 +1,37 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2026, The Linux Foundation. All rights reserved.
+ */
+
+#ifndef QCOM_PHY_QMP_QSERDES_TXRX_UFS_V8_H_
+#define QCOM_PHY_QMP_QSERDES_TXRX_UFS_V8_H_
+
+#define QSERDES_UFS_V8_TX_RES_CODE_LANE_OFFSET_TX (0x34)
+#define QSERDES_UFS_V8_TX_RES_CODE_LANE_OFFSET_RX (0x38)
+#define QSERDES_UFS_V8_TX_LANE_MODE_1 (0x80)
+#define QSERDES_UFS_V8_RX_UCDR_FO_GAIN_RATE2 (0x1BC)
+#define QSERDES_UFS_V8_RX_UCDR_FO_GAIN_RATE4 (0x1C4)
+#define QSERDES_UFS_V8_RX_UCDR_SO_GAIN_RATE4 (0x1DC)
+#define QSERDES_UFS_V8_RX_EQ_OFFSET_ADAPTOR_CNTRL1 (0x2C8)
+#define QSERDES_UFS_V8_RX_UCDR_PI_CONTROLS (0x1E4)
+#define QSERDES_UFS_V8_RX_OFFSET_ADAPTOR_CNTRL3 (0x2D0)
+#define QSERDES_UFS_V8_RX_UCDR_FASTLOCK_COUNT_HIGH_RATE4 (0x120)
+#define QSERDES_UFS_V8_RX_UCDR_FASTLOCK_FO_GAIN_RATE4 (0xD4)
+#define QSERDES_UFS_V8_RX_UCDR_FASTLOCK_SO_GAIN_RATE4 (0xEC)
+#define QSERDES_UFS_V8_RX_VGA_CAL_MAN_VAL (0x288)
+#define QSERDES_UFS_V8_RX_EQU_ADAPTOR_CNTRL4 (0x2B0)
+#define QSERDES_UFS_V8_RX_MODE_RATE_0_1_B4 (0x324)
+#define QSERDES_UFS_V8_RX_MODE_RATE4_SA_B7 (0x3B4)
+#define QSERDES_UFS_V8_RX_MODE_RATE4_SA_B9 (0x3BC)
+#define QSERDES_UFS_V8_RX_MODE_RATE4_SB_B7 (0x3E0)
+#define QSERDES_UFS_V8_RX_MODE_RATE4_SB_B9 (0x3E8)
+#define QSERDES_UFS_V8_RX_MODE_RATE5_SA_B7 (0x40C)
+#define QSERDES_UFS_V8_RX_MODE_RATE5_SA_B9 (0x414)
+#define QSERDES_UFS_V8_RX_MODE_RATE5_SB_B7 (0x438)
+#define QSERDES_UFS_V8_RX_MODE_RATE5_SB_B9 (0x440)
+#define QSERDES_UFS_V8_RX_UCDR_SO_SATURATION (0xF4)
+#define QSERDES_UFS_V8_RX_TERM_BW_CTRL0 (0x1AC)
+#define QSERDES_UFS_V8_RX_DLL0_FTUNE_CTRL (0x498)
+#define QSERDES_UFS_V8_RX_SIGDET_CAL_TRIM (0x4d0)
+
+#endif
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c b/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c
index 771bc7c2ab50..a4801cf4b0fe 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c
@@ -29,9 +29,11 @@
#include "phy-qcom-qmp-pcs-ufs-v4.h"
#include "phy-qcom-qmp-pcs-ufs-v5.h"
#include "phy-qcom-qmp-pcs-ufs-v6.h"
+#include "phy-qcom-qmp-pcs-ufs-v7.h"
#include "phy-qcom-qmp-qserdes-txrx-ufs-v6.h"
#include "phy-qcom-qmp-qserdes-txrx-ufs-v7.h"
+#include "phy-qcom-qmp-qserdes-txrx-ufs-v8.h"
/* QPHY_PCS_READY_STATUS bit */
#define PCS_READY BIT(0)
@@ -84,6 +86,13 @@ static const unsigned int ufsphy_v6_regs_layout[QPHY_LAYOUT_SIZE] = {
[QPHY_PCS_POWER_DOWN_CONTROL] = QPHY_V6_PCS_UFS_POWER_DOWN_CONTROL,
};
+static const unsigned int ufsphy_v7_regs_layout[QPHY_LAYOUT_SIZE] = {
+ [QPHY_START_CTRL] = QPHY_V6_PCS_UFS_PHY_START,
+ [QPHY_PCS_READY_STATUS] = QPHY_V7_PCS_UFS_READY_STATUS,
+ [QPHY_SW_RESET] = QPHY_V6_PCS_UFS_SW_RESET,
+ [QPHY_PCS_POWER_DOWN_CONTROL] = QPHY_V6_PCS_UFS_POWER_DOWN_CONTROL,
+};
+
static const struct qmp_phy_init_tbl milos_ufsphy_serdes[] = {
QMP_PHY_INIT_CFG(QSERDES_V6_COM_SYSCLK_EN_SEL, 0xd9),
QMP_PHY_INIT_CFG(QSERDES_V6_COM_CMN_CONFIG_1, 0x16),
@@ -1306,6 +1315,12 @@ static const struct regulator_bulk_data sm8750_ufsphy_vreg_l[] = {
{ .supply = "vdda-pll", .init_load_uA = 18300 },
};
+static const struct regulator_bulk_data hawi_ufsphy_vreg_l[] = {
+ { .supply = "vdda-phy", .init_load_uA = 324000 },
+ { .supply = "vdda-pll", .init_load_uA = 27000 },
+
+};
+
static const struct qmp_ufs_offsets qmp_ufs_offsets = {
.serdes = 0,
.pcs = 0xc00,
@@ -1324,6 +1339,15 @@ static const struct qmp_ufs_offsets qmp_ufs_offsets_v6 = {
.rx2 = 0x1a00,
};
+static const struct qmp_ufs_offsets qmp_ufs_offsets_v7 = {
+ .serdes = 0,
+ .pcs = 0x0400,
+ .tx = 0x2000,
+ .rx = 0x2000,
+ .tx2 = 0x3000,
+ .rx2 = 0x3000,
+};
+
static const struct qmp_phy_cfg milos_ufsphy_cfg = {
.lanes = 2,
@@ -1844,6 +1868,119 @@ static const struct qmp_phy_cfg sm8750_ufsphy_cfg = {
};
+static const struct qmp_phy_init_tbl hawi_ufsphy_serdes[] = {
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_SYSCLK_EN_SEL, 0xd9),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_CMN_CONFIG_1, 0x16),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_HSCLK_SEL_1, 0x11),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_HSCLK_HS_SWITCH_SEL_1, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP_EN, 0x01),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP_CFG, 0x60),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_IVCO, 0x1f),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_IVCO_MODE1, 0x1f),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_CMN_IETRIM, 0x07),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_CMN_IPTRIM, 0x20),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE_MAP, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE_CTRL, 0x40),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_ADAPTIVE_ANALOG_CONFIG, 0x06),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_DEC_START_MODE0, 0x41),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_MODE0, 0x06),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_RCTRL_MODE0, 0x18),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_CCTRL_MODE0, 0x14),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_ADAPTIVE_MODE0, 0x06),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_RCCTRL_ADAPTIVE_MODE0, 0x18),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_CCTRL_ADAPTIVE_MODE0, 0x14),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP1_MODE0, 0x7f),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP2_MODE0, 0x06),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_BIN_VCOCAL_CMP_CODE1_MODE0, 0x92),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_BIN_VCOCAL_CMP_CODE2_MODE0, 0x1e),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_DEC_START_MODE1, 0x4c),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_MODE1, 0x06),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_RCTRL_MODE1, 0x18),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_CCTRL_MODE1, 0x14),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_ADAPTIVE_MODE1, 0x06),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_RCCTRL_ADAPTIVE_MODE1, 0x18),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_CCTRL_ADAPTIVE_MODE1, 0x14),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP1_MODE1, 0x99),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP2_MODE1, 0x07),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_BIN_VCOCAL_CMP_CODE1_MODE1, 0xbe),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_BIN_VCOCAL_CMP_CODE2_MODE1, 0x23),
+};
+
+static const struct qmp_phy_init_tbl hawi_ufsphy_tx[] = {
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V8_TX_LANE_MODE_1, 0x0c),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V8_TX_RES_CODE_LANE_OFFSET_TX, 0x07),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V8_TX_RES_CODE_LANE_OFFSET_RX, 0x17),
+};
+
+static const struct qmp_phy_init_tbl hawi_ufsphy_rx[] = {
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V8_RX_UCDR_FO_GAIN_RATE2, 0x0c),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V8_RX_UCDR_FO_GAIN_RATE4, 0x0c),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V8_RX_UCDR_SO_GAIN_RATE4, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V8_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x14),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V8_RX_UCDR_PI_CONTROLS, 0x07),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V8_RX_OFFSET_ADAPTOR_CNTRL3, 0x0e),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V8_RX_UCDR_FASTLOCK_COUNT_HIGH_RATE4, 0x02),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V8_RX_UCDR_FASTLOCK_FO_GAIN_RATE4, 0x1c),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V8_RX_UCDR_FASTLOCK_SO_GAIN_RATE4, 0x06),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V8_RX_VGA_CAL_MAN_VAL, 0x8e),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V8_RX_EQU_ADAPTOR_CNTRL4, 0x0f),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V8_RX_MODE_RATE_0_1_B4, 0xb8),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V8_RX_MODE_RATE4_SA_B7, 0x66),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V8_RX_MODE_RATE4_SA_B9, 0x1f),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V8_RX_MODE_RATE4_SB_B7, 0x66),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V8_RX_MODE_RATE4_SB_B9, 0x1f),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V8_RX_MODE_RATE5_SA_B7, 0x66),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V8_RX_MODE_RATE5_SA_B9, 0x1f),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V8_RX_MODE_RATE5_SB_B7, 0x66),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V8_RX_MODE_RATE5_SB_B9, 0x1f),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V8_RX_UCDR_SO_SATURATION, 0x1f),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V8_RX_TERM_BW_CTRL0, 0xfa),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V8_RX_DLL0_FTUNE_CTRL, 0x30),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V8_RX_SIGDET_CAL_TRIM, 0x77),
+};
+
+static const struct qmp_phy_init_tbl hawi_ufsphy_pcs[] = {
+ QMP_PHY_INIT_CFG(QPHY_V7_PCS_UFS_TX_MID_TERM_CTRL1, 0x43),
+ QMP_PHY_INIT_CFG(QPHY_V7_PCS_UFS_PCS_CTRL1, 0x42),
+ QMP_PHY_INIT_CFG(QPHY_V7_PCS_UFS_TX_LARGE_AMP_DRV_LVL, 0x0f),
+ QMP_PHY_INIT_CFG(QPHY_V7_PCS_UFS_RX_SIGDET_CTRL2, 0x68),
+ QMP_PHY_INIT_CFG(QPHY_V7_PCS_UFS_MULTI_LANE_CTRL1, 0x02),
+};
+
+static const struct qmp_phy_init_tbl hawi_ufsphy_g5_pcs[] = {
+ QMP_PHY_INIT_CFG(QPHY_V7_PCS_UFS_PLL_CNTL, 0x3b),
+ QMP_PHY_INIT_CFG(QPHY_V7_PCS_UFS_TX_HSGEAR_CAPABILITY, 0x05),
+ QMP_PHY_INIT_CFG(QPHY_V7_PCS_UFS_RX_HSGEAR_CAPABILITY, 0x05),
+};
+
+static const struct qmp_phy_cfg hawi_ufsphy_cfg = {
+ .lanes = 2,
+
+ .offsets = &qmp_ufs_offsets_v7,
+ .max_supported_gear = UFS_HS_G5,
+
+ .tbls = {
+ .serdes = hawi_ufsphy_serdes,
+ .serdes_num = ARRAY_SIZE(hawi_ufsphy_serdes),
+ .tx = hawi_ufsphy_tx,
+ .tx_num = ARRAY_SIZE(hawi_ufsphy_tx),
+ .rx = hawi_ufsphy_rx,
+ .rx_num = ARRAY_SIZE(hawi_ufsphy_rx),
+ .pcs = hawi_ufsphy_pcs,
+ .pcs_num = ARRAY_SIZE(hawi_ufsphy_pcs),
+ },
+
+ .tbls_hs_overlay[0] = {
+ .pcs = hawi_ufsphy_g5_pcs,
+ .pcs_num = ARRAY_SIZE(hawi_ufsphy_g5_pcs),
+ .max_gear = UFS_HS_G5,
+ },
+
+ .vreg_list = hawi_ufsphy_vreg_l,
+ .num_vregs = ARRAY_SIZE(hawi_ufsphy_vreg_l),
+ .regs = ufsphy_v7_regs_layout,
+};
+
static void qmp_ufs_serdes_init(struct qmp_ufs *qmp, const struct qmp_phy_cfg_tbls *tbls)
{
void __iomem *serdes = qmp->serdes;
@@ -2258,6 +2395,9 @@ static int qmp_ufs_probe(struct platform_device *pdev)
static const struct of_device_id qmp_ufs_of_match_table[] = {
{
+ .compatible = "qcom,hawi-qmp-ufs-phy",
+ .data = &hawi_ufsphy_cfg,
+ }, {
.compatible = "qcom,milos-qmp-ufs-phy",
.data = &milos_ufsphy_cfg,
}, {
--
2.34.1
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox