* Re: [PATCH v4] phy: Add USB3 PHY support to Google Tensor SoC USB PHY driver
From: sashiko-bot @ 2026-07-06 23:27 UTC (permalink / raw)
To: RD Babiera; +Cc: olteanv, linux-phy, vkoul, neil.armstrong
In-Reply-To: <20260706231633.700676-2-rdbabiera@google.com>
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
New issues:
- [High] Data race on `gphy->orientation` causes redundant hardware programming and a 2.5-second timeout.
Pre-existing issues:
- [High] TOCTOU race on `pm_runtime_suspended()` allows hardware access while suspended, causing a bus fault.
--
--- Patch [1]: [PATCH v4] phy: Add USB3 PHY support to Google Tensor SoC USB PHY driver ---
commit 1008e9b0470bdcef99e7408c0e43896673f90ba3
Author: RD Babiera <rdbabiera@google.com>
phy: Add USB3 PHY support to Google Tensor SoC USB PHY driver
This patch adds USB3 PHY support for the Google Tensor G5 USB PHY driver,
including the usb3_tca register, clock, and reset functionality. It also
refactors the probe sequence and implements USB3 phy_ops.
> diff --git a/drivers/phy/phy-google-usb.c b/drivers/phy/phy-google-usb.c
> index ab20bc20f19ea..19256588d50ec 100644
> --- a/drivers/phy/phy-google-usb.c
> +++ b/drivers/phy/phy-google-usb.c
[ ... ]
> @@ -92,6 +261,9 @@ static int google_usb_set_orientation(struct typec_switch_dev *sw,
>
> set_vbus_valid(gphy);
>
> + if (gphy->phy_state == COMBO_PHY_TCA_READY && orientation != TYPEC_ORIENTATION_NONE)
> + return program_tca_locked(gphy);
> +
[Severity: High]
This is a pre-existing issue, but does this function have a race condition
with power management that could cause a bus fault?
google_usb_set_orientation() checks pm_runtime_suspended(gphy->dev) without
holding a PM runtime reference. If the USB core releases its PM reference
immediately after this check, the device could suspend and power off the PHY.
The function would then acquire the lock and call set_vbus_valid() and
program_tca_locked() on unclocked and unpowered MMIO registers, resulting
in a synchronous external abort.
Would it be safer to use pm_runtime_get_sync() to ensure the hardware
remains active during these accesses?
> return 0;
> }
[ ... ]
> +static int google_usb3_phy_power_on(struct phy *_phy)
> +{
> + struct google_usb_phy_instance *inst = phy_get_drvdata(_phy);
> + struct google_usb_phy *gphy = inst->parent;
> + int ret;
> +
> + dev_dbg(gphy->dev, "power on usb3 phy\n");
> +
> + guard(mutex)(&gphy->phy_mutex);
> +
> + if (gphy->phy_state != COMBO_PHY_TCA_READY) {
> + /* Wait for PoR -> NC transitions*/
> + ret = wait_tca_xa_ack(gphy);
> + if (ret) {
> + dev_err(gphy->dev, "PoR->NC transition timeout");
> + return ret;
> + }
> + gphy->phy_state = COMBO_PHY_TCA_READY;
> + }
> +
> + if (gphy->orientation != TYPEC_ORIENTATION_NONE)
> + return program_tca_locked(gphy);
[Severity: High]
Can this lead to redundant TCA programming and a 2.5-second timeout?
Looking at google_usb_set_orientation(), gphy->orientation is updated before
the mutex is acquired:
google_usb_set_orientation() {
gphy->orientation = orientation;
if (pm_runtime_suspended(gphy->dev))
return 0;
guard(mutex)(&gphy->phy_mutex);
...
If a Type-C plug event (Thread A) sets gphy->orientation but is preempted
before taking the lock, and the USB core concurrently calls
google_usb3_phy_power_on() (Thread B), Thread B will see the new
orientation, program the TCA, and release the lock.
When Thread A resumes, it will acquire the mutex, see COMBO_PHY_TCA_READY,
and call program_tca_locked() a second time with the identical configuration.
Since writing the same configuration to the TCA hardware doesn't trigger a
new XA_ACT_EVT interrupt, wait_tca_xa_ack() will stall for its full timeout.
Should the orientation update be moved inside the lock?
> +
> + return 0;
> +}
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260706231633.700676-2-rdbabiera@google.com?part=1
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* [PATCH v4] phy: Add USB3 PHY support to Google Tensor SoC USB PHY driver
From: RD Babiera @ 2026-07-06 23:16 UTC (permalink / raw)
To: vkoul, peter.griffin, andre.draszik, tudor.ambarus, p.zabel,
neil.armstrong
Cc: badhri, linux-arm-kernel, linux-samsung-soc, linux-phy,
linux-kernel, RD Babiera
Add USB3 PHY support for the Google Tensor G5 USB PHY driver.
This patch adds functionality for the usb3_tca register, usb3 clock,
and usb3 reset as defined in google,lga-usb-phy.yaml. Kconfig now lists
USB SuperSpeed support.
Refactor the probe sequence to initialize the USB2 and USB3 PHYs, and then
initialize clocks and resets for both PHYs afterwards.
Refactor set_vbus_valid to reduce duplicated code.
Implement USB3 phy_ops for phy_init, phy_exit, and phy_power_on.
combo_phy_state enum is added to track PHY bringup state across
PHY API calls.
Signed-off-by: RD Babiera <rdbabiera@google.com>
---
Changes since v1:
* Removed mix of goto-based and scope-based cleanup from usb3 phy_init
* Removed unused usb3_core resource from probe
* Added combo_phy_state enum to interally track ComboPHY bringup state
to allow google_usb_set_orientation() to change TCA orientation.
* Modify Kconfig documentation to reflect SuperSpeed support
Changes since v2:
* google_usb3_phy_init now sets USBDP_TOP_CFG_REG_PMGT_REF_CLK_REQ_N
to false if phy_init fails elsewhere.
* google_usb3_phy_init errors are now handled via DEFINE_FREE structures.
This affects set_pmgt_ref_clk_req_n, clk_bulk_prepare_enable, and
reset_control_bulk_deassert.
* google_usb2_phy_init also handles undoing clk_bulk_prepare_enable via
DEFINE_FREE structure.
* google_usb3_phy_power_on allows program_tca_locked in the
COMBO_PHY_TCA_READY state. Waiting for PoR=>NC is only performed once.
* Note: there are checkpatch errors for the DEFINE_FREE macros resulting
in "ERROR: trailing statements should be on next line". Other cases of
DEFINE_FREE where the line limit would otherwise exceed 100 columns
have the indentation done the same way.
Changes since v3:
* set_pmgt_ref_clk_req_n(false) in google_usb3_phy_exit() comes after
reset assertion and clock disable to match phy_init() sequence.
* program_tca_locked in usb3 power_on() now requires a valid orientation
to match google_usb_set_orientation requirements.
---
drivers/phy/Kconfig | 2 +-
drivers/phy/phy-google-usb.c | 407 +++++++++++++++++++++++++++++++----
2 files changed, 371 insertions(+), 38 deletions(-)
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index 19f3b7d12b7d..d2d401129af7 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -100,7 +100,7 @@ config PHY_GOOGLE_USB
the G5 generation (Laguna). This driver provides the PHY interfaces
to interact with the SNPS eUSB2 and USB 3.2/DisplayPort Combo PHY,
both of which are integrated with the DWC3 USB DRD controller.
- This driver currently supports USB high-speed.
+ This driver currently supports USB high-speed and SuperSpeed.
config USB_LGM_PHY
tristate "INTEL Lightning Mountain USB PHY Driver"
diff --git a/drivers/phy/phy-google-usb.c b/drivers/phy/phy-google-usb.c
index ab20bc20f19e..19256588d50e 100644
--- a/drivers/phy/phy-google-usb.c
+++ b/drivers/phy/phy-google-usb.c
@@ -20,6 +20,7 @@
#include <linux/reset.h>
#include <linux/usb/typec_mux.h>
+/* USB_CFG_CSR */
#define USBCS_USB2PHY_CFG19_OFFSET 0x0
#define USBCS_USB2PHY_CFG19_PHY_CFG_PLL_FB_DIV GENMASK(19, 8)
@@ -28,11 +29,41 @@
#define USBCS_USB2PHY_CFG21_REF_FREQ_SEL GENMASK(15, 13)
#define USBCS_USB2PHY_CFG21_PHY_TX_DIG_BYPASS_SEL BIT(19)
+/* USBDP_TOP */
#define USBCS_PHY_CFG1_OFFSET 0x28
+#define USBCS_PHY_CFG1_PHY0_MPLLA_SSC_EN BIT(1)
+#define USBCS_PHY_CFG1_PHY0_SRAM_BYPASS_MODE GENMASK(11, 10)
+#define SRAM_BYPASS_MODE_BYPASS_FIRMWARE BIT(0)
+#define SRAM_BYPASS_MODE_BYPASS_CONTEXT BIT(1)
#define USBCS_PHY_CFG1_SYS_VBUSVALID BIT(17)
+#define USBDP_TOP_CFG_REG_OFFSET 0x44
+#define USBDP_TOP_CFG_REG_PMGT_REF_CLK_REQ_N BIT(0)
+
+#define PHY_POWER_CONFIG_REG1_OFFSET 0x48
+#define PHY_POWER_CONFIG_REG1_PG_MODE_EN BIT(1)
+#define PHY_POWER_CONFIG_REG1_UPCS_PIPE_CONFIG GENMASK(31, 14)
+#define UPCS_PIPE_CONFIG_ISO_CPM BIT(5)
+#define UPCS_PIPE_CONFIG_PG_MODE_STATIC BIT(6)
+#define UPCS_PIPE_CONFIG_LANE_RESET_NO_PG_EXIT BIT(9)
+
+/* USB3_TCA */
+#define TCA_INTR_STS_OFFSET 0x8
+#define TCA_INTR_STS_XA_ACT_EVT BIT(0)
+#define TCA_TCPC_OFFSET 0x14
+#define TCA_TCPC_MUX_CONTROL GENMASK(2, 0)
+#define TCA_TCPC_MUX_CONTROL_USB_ONLY 0x1
+#define TCA_TCPC_CONNECTOR_ORIENTATION BIT(3)
+#define TCA_TCPC_VALID BIT(4)
+#define TCA_PSTATE_0_OFFSET 0x50
+#define TCA_PSTATE_0_UPCS_LANE0_PHYSTATUS BIT(8)
+
+#define GPHY_TCA_DELAY_US 10
+#define GPHY_TCA_TIMEOUT_US 2500000
+
enum google_usb_phy_id {
GOOGLE_USB2_PHY,
+ GOOGLE_USB3_PHY,
GOOGLE_USB_PHY_NUM,
};
@@ -46,34 +77,172 @@ struct google_usb_phy_instance {
struct reset_control_bulk_data *rsts;
};
+struct google_usb_phy_config {
+ const char * const *clk_names;
+ unsigned int num_clks;
+ const char * const *rst_names;
+ unsigned int num_rsts;
+};
+
+static const char * const u2phy_clk_names[] = {
+ "usb2",
+ "usb2_apb",
+};
+static const char * const u3phy_clk_names[] = {
+ "usb3"
+};
+static const char * const u2phy_rst_names[] = {
+ "usb2",
+ "usb2_apb",
+};
+static const char * const u3phy_rst_names[] = {
+ "usb3"
+};
+
+static const struct google_usb_phy_config phy_configs[GOOGLE_USB_PHY_NUM] = {
+ [GOOGLE_USB2_PHY] = {
+ .clk_names = u2phy_clk_names,
+ .num_clks = ARRAY_SIZE(u2phy_clk_names),
+ .rst_names = u2phy_rst_names,
+ .num_rsts = ARRAY_SIZE(u2phy_rst_names),
+ },
+ [GOOGLE_USB3_PHY] = {
+ .clk_names = u3phy_clk_names,
+ .num_clks = ARRAY_SIZE(u3phy_clk_names),
+ .rst_names = u3phy_rst_names,
+ .num_rsts = ARRAY_SIZE(u3phy_rst_names),
+ },
+};
+
+static inline void google_usb_phy_clk_disable(struct google_usb_phy_instance *inst)
+{
+ clk_bulk_disable_unprepare(inst->num_clks, inst->clks);
+}
+DEFINE_FREE(inst_clk_disable, struct google_usb_phy_instance *,
+ if (_T) google_usb_phy_clk_disable(_T))
+
+static inline void google_usb_phy_rst_disable(struct google_usb_phy_instance *inst)
+{
+ reset_control_bulk_assert(inst->num_rsts, inst->rsts);
+}
+DEFINE_FREE(inst_rst_disable, struct google_usb_phy_instance *,
+ if (_T) google_usb_phy_rst_disable(_T))
+
+/*
+ * combo_phy_state
+ * COMBO_PHY_IDLE: The ComboPHY has been torn down and USB3 has not completed
+ * bringup
+ * COMBO_PHY_INIT_DONE: The ComboPHY bringup sequence is complete.
+ * COMBO_PHY_TCA_READY: The PoR => NC transition is complete, and the TCA can be
+ * moved into USB.
+ */
+enum combo_phy_state {
+ COMBO_PHY_IDLE,
+ COMBO_PHY_INIT_DONE,
+ COMBO_PHY_TCA_READY,
+};
+
struct google_usb_phy {
struct device *dev;
struct regmap *usb_cfg_regmap;
unsigned int usb2_cfg_offset;
void __iomem *usbdp_top_base;
+ void __iomem *usb3_tca_base;
struct google_usb_phy_instance *insts;
/*
* Protect phy registers from concurrent access, specifically via
- * google_usb_set_orientation callback.
+ * google_usb_set_orientation callback. phy_mutex also protects
+ * concurrent access to phy_state.
*/
struct mutex phy_mutex;
struct typec_switch_dev *sw;
enum typec_orientation orientation;
+ enum combo_phy_state phy_state;
};
static void set_vbus_valid(struct google_usb_phy *gphy)
{
u32 reg;
- if (gphy->orientation == TYPEC_ORIENTATION_NONE) {
- reg = readl(gphy->usbdp_top_base + USBCS_PHY_CFG1_OFFSET);
+ reg = readl(gphy->usbdp_top_base + USBCS_PHY_CFG1_OFFSET);
+ if (gphy->orientation == TYPEC_ORIENTATION_NONE)
reg &= ~USBCS_PHY_CFG1_SYS_VBUSVALID;
- writel(reg, gphy->usbdp_top_base + USBCS_PHY_CFG1_OFFSET);
- } else {
- reg = readl(gphy->usbdp_top_base + USBCS_PHY_CFG1_OFFSET);
+ else
reg |= USBCS_PHY_CFG1_SYS_VBUSVALID;
- writel(reg, gphy->usbdp_top_base + USBCS_PHY_CFG1_OFFSET);
- }
+ writel(reg, gphy->usbdp_top_base + USBCS_PHY_CFG1_OFFSET);
+}
+
+static void set_sram_bypass(struct google_usb_phy *gphy, u32 bypass)
+{
+ u32 reg;
+
+ reg = readl(gphy->usbdp_top_base + USBCS_PHY_CFG1_OFFSET);
+ reg &= ~USBCS_PHY_CFG1_PHY0_SRAM_BYPASS_MODE;
+ reg |= FIELD_PREP(USBCS_PHY_CFG1_PHY0_SRAM_BYPASS_MODE, bypass);
+ writel(reg, gphy->usbdp_top_base + USBCS_PHY_CFG1_OFFSET);
+}
+
+static void set_pmgt_ref_clk_req_n(struct google_usb_phy *gphy, bool resume)
+{
+ u32 reg;
+
+ reg = readl(gphy->usbdp_top_base + USBDP_TOP_CFG_REG_OFFSET);
+ if (resume)
+ reg |= USBDP_TOP_CFG_REG_PMGT_REF_CLK_REQ_N;
+ else
+ reg &= ~USBDP_TOP_CFG_REG_PMGT_REF_CLK_REQ_N;
+ writel(reg, gphy->usbdp_top_base + USBDP_TOP_CFG_REG_OFFSET);
+}
+
+static inline void disable_pmgt_ref_clk_req_n(struct google_usb_phy *gphy)
+{
+ set_pmgt_ref_clk_req_n(gphy, false);
+}
+DEFINE_FREE(pmgt_ref_clk_req_n, struct google_usb_phy *, if (_T) disable_pmgt_ref_clk_req_n(_T))
+
+static int wait_tca_xa_ack(struct google_usb_phy *gphy)
+{
+ int ret;
+ u32 reg;
+
+ ret = readl_poll_timeout(gphy->usb3_tca_base + TCA_INTR_STS_OFFSET,
+ reg, !!(reg & TCA_INTR_STS_XA_ACT_EVT),
+ GPHY_TCA_DELAY_US, GPHY_TCA_TIMEOUT_US);
+ if (ret)
+ dev_err(gphy->dev, "tca xa_ack timeout, ret=%d", ret);
+
+ return ret;
+}
+
+static int program_tca_locked(struct google_usb_phy *gphy)
+ __must_hold(&gphy->phy_mutex)
+{
+ int ret;
+ u32 reg;
+
+ reg = readl(gphy->usb3_tca_base + TCA_INTR_STS_OFFSET);
+ writel(reg, gphy->usb3_tca_base + TCA_INTR_STS_OFFSET);
+
+ reg = readl(gphy->usb3_tca_base + TCA_TCPC_OFFSET);
+ reg &= ~TCA_TCPC_MUX_CONTROL;
+ reg |= FIELD_PREP(TCA_TCPC_MUX_CONTROL, TCA_TCPC_MUX_CONTROL_USB_ONLY);
+ if (gphy->orientation == TYPEC_ORIENTATION_REVERSE)
+ reg |= TCA_TCPC_CONNECTOR_ORIENTATION;
+ else
+ reg &= ~TCA_TCPC_CONNECTOR_ORIENTATION;
+ reg |= TCA_TCPC_VALID;
+ writel(reg, gphy->usb3_tca_base + TCA_TCPC_OFFSET);
+
+ ret = wait_tca_xa_ack(gphy);
+ dev_dbg(gphy->dev, "TCA switch %s, mux %lu, orientation %s",
+ ret ? "failed" : "success",
+ FIELD_GET(TCA_TCPC_MUX_CONTROL, reg),
+ FIELD_GET(TCA_TCPC_CONNECTOR_ORIENTATION, reg) ? "reverse" : "normal");
+
+ reg = readl(gphy->usb3_tca_base + TCA_INTR_STS_OFFSET);
+ writel(reg, gphy->usb3_tca_base + TCA_INTR_STS_OFFSET);
+
+ return ret;
}
static int google_usb_set_orientation(struct typec_switch_dev *sw,
@@ -92,6 +261,9 @@ static int google_usb_set_orientation(struct typec_switch_dev *sw,
set_vbus_valid(gphy);
+ if (gphy->phy_state == COMBO_PHY_TCA_READY && orientation != TYPEC_ORIENTATION_NONE)
+ return program_tca_locked(gphy);
+
return 0;
}
@@ -122,17 +294,18 @@ static int google_usb2_phy_init(struct phy *_phy)
ret = clk_bulk_prepare_enable(inst->num_clks, inst->clks);
if (ret)
return ret;
+ struct google_usb_phy_instance *clk_dev __free(inst_clk_disable) = inst;
ret = reset_control_bulk_deassert(inst->num_rsts, inst->rsts);
- if (ret) {
- clk_bulk_disable_unprepare(inst->num_clks, inst->clks);
+ if (ret)
return ret;
- }
regmap_read(gphy->usb_cfg_regmap, gphy->usb2_cfg_offset + USBCS_USB2PHY_CFG21_OFFSET, ®);
reg |= USBCS_USB2PHY_CFG21_PHY_ENABLE;
regmap_write(gphy->usb_cfg_regmap, gphy->usb2_cfg_offset + USBCS_USB2PHY_CFG21_OFFSET, reg);
+ retain_and_null_ptr(clk_dev);
+
return 0;
}
@@ -161,6 +334,119 @@ static const struct phy_ops google_usb2_phy_ops = {
.exit = google_usb2_phy_exit,
};
+static int google_usb3_phy_init(struct phy *_phy)
+{
+ struct google_usb_phy_instance *inst = phy_get_drvdata(_phy);
+ struct google_usb_phy *gphy = inst->parent;
+ int ret = 0;
+ u32 reg;
+
+ dev_dbg(gphy->dev, "initializing usb3 phy\n");
+
+ guard(mutex)(&gphy->phy_mutex);
+
+ if (gphy->phy_state != COMBO_PHY_IDLE) {
+ dev_warn(gphy->dev, "usb3 phy init called when combo phy state is not idle");
+ return 0;
+ }
+
+ reg = readl(gphy->usbdp_top_base + PHY_POWER_CONFIG_REG1_OFFSET);
+ reg |= PHY_POWER_CONFIG_REG1_PG_MODE_EN;
+ reg &= ~PHY_POWER_CONFIG_REG1_UPCS_PIPE_CONFIG;
+ reg |= FIELD_PREP(PHY_POWER_CONFIG_REG1_UPCS_PIPE_CONFIG,
+ (UPCS_PIPE_CONFIG_ISO_CPM |
+ UPCS_PIPE_CONFIG_PG_MODE_STATIC |
+ UPCS_PIPE_CONFIG_LANE_RESET_NO_PG_EXIT));
+ writel(reg, gphy->usbdp_top_base + PHY_POWER_CONFIG_REG1_OFFSET);
+
+ set_vbus_valid(gphy);
+
+ reg = readl(gphy->usbdp_top_base + USBCS_PHY_CFG1_OFFSET);
+ reg |= USBCS_PHY_CFG1_PHY0_MPLLA_SSC_EN;
+ writel(reg, gphy->usbdp_top_base + USBCS_PHY_CFG1_OFFSET);
+
+ set_sram_bypass(gphy, SRAM_BYPASS_MODE_BYPASS_FIRMWARE |
+ SRAM_BYPASS_MODE_BYPASS_CONTEXT);
+ set_pmgt_ref_clk_req_n(gphy, true);
+ struct google_usb_phy *pmgt_ref_clk_req_dev __free(pmgt_ref_clk_req_n) = gphy;
+
+ ret = clk_bulk_prepare_enable(inst->num_clks, inst->clks);
+ if (ret)
+ return ret;
+ struct google_usb_phy_instance *clk_dev __free(inst_clk_disable) = inst;
+
+ ret = reset_control_bulk_deassert(inst->num_rsts, inst->rsts);
+ if (ret)
+ return ret;
+ struct google_usb_phy_instance *rst_dev __free(inst_rst_disable) = inst;
+
+ ret = readl_poll_timeout(gphy->usb3_tca_base + TCA_PSTATE_0_OFFSET,
+ reg, !(reg & TCA_PSTATE_0_UPCS_LANE0_PHYSTATUS),
+ GPHY_TCA_DELAY_US, GPHY_TCA_TIMEOUT_US);
+ if (ret) {
+ dev_err(gphy->dev, "wait for lane0 phystatus timed out");
+ return ret;
+ }
+
+ gphy->phy_state = COMBO_PHY_INIT_DONE;
+
+ retain_and_null_ptr(rst_dev);
+ retain_and_null_ptr(clk_dev);
+ retain_and_null_ptr(pmgt_ref_clk_req_dev);
+
+ return 0;
+}
+
+static int google_usb3_phy_exit(struct phy *_phy)
+{
+ struct google_usb_phy_instance *inst = phy_get_drvdata(_phy);
+ struct google_usb_phy *gphy = inst->parent;
+
+ dev_dbg(gphy->dev, "exiting usb3 phy\n");
+
+ guard(mutex)(&gphy->phy_mutex);
+
+ reset_control_bulk_assert(inst->num_rsts, inst->rsts);
+ clk_bulk_disable_unprepare(inst->num_clks, inst->clks);
+ set_pmgt_ref_clk_req_n(gphy, false);
+
+ gphy->phy_state = COMBO_PHY_IDLE;
+
+ return 0;
+}
+
+static int google_usb3_phy_power_on(struct phy *_phy)
+{
+ struct google_usb_phy_instance *inst = phy_get_drvdata(_phy);
+ struct google_usb_phy *gphy = inst->parent;
+ int ret;
+
+ dev_dbg(gphy->dev, "power on usb3 phy\n");
+
+ guard(mutex)(&gphy->phy_mutex);
+
+ if (gphy->phy_state != COMBO_PHY_TCA_READY) {
+ /* Wait for PoR -> NC transitions*/
+ ret = wait_tca_xa_ack(gphy);
+ if (ret) {
+ dev_err(gphy->dev, "PoR->NC transition timeout");
+ return ret;
+ }
+ gphy->phy_state = COMBO_PHY_TCA_READY;
+ }
+
+ if (gphy->orientation != TYPEC_ORIENTATION_NONE)
+ return program_tca_locked(gphy);
+
+ return 0;
+}
+
+static const struct phy_ops google_usb3_phy_ops = {
+ .init = google_usb3_phy_init,
+ .exit = google_usb3_phy_exit,
+ .power_on = google_usb3_phy_power_on,
+};
+
static struct phy *google_usb_phy_xlate(struct device *dev,
const struct of_phandle_args *args)
{
@@ -173,14 +459,61 @@ static struct phy *google_usb_phy_xlate(struct device *dev,
return gphy->insts[args->args[0]].phy;
}
+static int google_usb_phy_parse_clocks(struct google_usb_phy *gphy)
+{
+ struct device *dev = gphy->dev;
+ int id, i, ret;
+
+ for (id = 0; id < GOOGLE_USB_PHY_NUM; id++) {
+ const struct google_usb_phy_config *cfg = &phy_configs[id];
+ struct google_usb_phy_instance *inst = &gphy->insts[id];
+
+ inst->num_clks = cfg->num_clks;
+ inst->clks = devm_kcalloc(dev, inst->num_clks, sizeof(*inst->clks), GFP_KERNEL);
+ if (!inst->clks)
+ return -ENOMEM;
+
+ for (i = 0; i < inst->num_clks; i++)
+ inst->clks[i].id = cfg->clk_names[i];
+
+ ret = devm_clk_bulk_get(dev, inst->num_clks, inst->clks);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to get phy%d clks\n", id);
+ }
+
+ return 0;
+}
+
+static int google_usb_phy_parse_resets(struct google_usb_phy *gphy)
+{
+ struct device *dev = gphy->dev;
+ int id, i, ret;
+
+ for (id = 0; id < GOOGLE_USB_PHY_NUM; id++) {
+ const struct google_usb_phy_config *cfg = &phy_configs[id];
+ struct google_usb_phy_instance *inst = &gphy->insts[id];
+
+ inst->num_rsts = cfg->num_rsts;
+ inst->rsts = devm_kcalloc(dev, inst->num_rsts, sizeof(*inst->rsts), GFP_KERNEL);
+ if (!inst->rsts)
+ return -ENOMEM;
+
+ for (i = 0; i < inst->num_rsts; i++)
+ inst->rsts[i].id = cfg->rst_names[i];
+ ret = devm_reset_control_bulk_get_exclusive(dev, inst->num_rsts, inst->rsts);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to get phy%d resets\n", id);
+ }
+
+ return 0;
+}
+
static int google_usb_phy_probe(struct platform_device *pdev)
{
struct typec_switch_desc sw_desc = { };
- struct google_usb_phy_instance *inst;
struct phy_provider *phy_provider;
struct device *dev = &pdev->dev;
struct google_usb_phy *gphy;
- struct phy *phy;
u32 args[1];
int ret;
@@ -212,39 +545,39 @@ static int google_usb_phy_probe(struct platform_device *pdev)
return dev_err_probe(dev, PTR_ERR(gphy->usbdp_top_base),
"invalid usbdp top\n");
+ gphy->usb3_tca_base = devm_platform_ioremap_resource_byname(pdev,
+ "usb3_tca");
+ if (IS_ERR(gphy->usb3_tca_base))
+ return dev_err_probe(dev, PTR_ERR(gphy->usb3_tca_base),
+ "invalid usb3 tca\n");
+
gphy->insts = devm_kcalloc(dev, GOOGLE_USB_PHY_NUM, sizeof(*gphy->insts), GFP_KERNEL);
if (!gphy->insts)
return -ENOMEM;
- inst = &gphy->insts[GOOGLE_USB2_PHY];
- inst->parent = gphy;
- inst->index = GOOGLE_USB2_PHY;
- phy = devm_phy_create(dev, NULL, &google_usb2_phy_ops);
- if (IS_ERR(phy))
- return dev_err_probe(dev, PTR_ERR(phy),
+ gphy->insts[GOOGLE_USB2_PHY].phy = devm_phy_create(dev, NULL, &google_usb2_phy_ops);
+ gphy->insts[GOOGLE_USB2_PHY].index = GOOGLE_USB2_PHY;
+ gphy->insts[GOOGLE_USB2_PHY].parent = gphy;
+ if (IS_ERR(gphy->insts[GOOGLE_USB2_PHY].phy))
+ return dev_err_probe(dev, PTR_ERR(gphy->insts[GOOGLE_USB2_PHY].phy),
"failed to create usb2 phy instance\n");
- inst->phy = phy;
- phy_set_drvdata(phy, inst);
+ phy_set_drvdata(gphy->insts[GOOGLE_USB2_PHY].phy, &gphy->insts[GOOGLE_USB2_PHY]);
- inst->num_clks = 2;
- inst->clks = devm_kcalloc(dev, inst->num_clks, sizeof(*inst->clks), GFP_KERNEL);
- if (!inst->clks)
- return -ENOMEM;
- inst->clks[0].id = "usb2";
- inst->clks[1].id = "usb2_apb";
- ret = devm_clk_bulk_get(dev, inst->num_clks, inst->clks);
+ gphy->insts[GOOGLE_USB3_PHY].phy = devm_phy_create(dev, NULL, &google_usb3_phy_ops);
+ gphy->insts[GOOGLE_USB3_PHY].index = GOOGLE_USB3_PHY;
+ gphy->insts[GOOGLE_USB3_PHY].parent = gphy;
+ if (IS_ERR(gphy->insts[GOOGLE_USB3_PHY].phy))
+ return dev_err_probe(dev, PTR_ERR(gphy->insts[GOOGLE_USB3_PHY].phy),
+ "failed to create usb3 phy instance\n");
+ phy_set_drvdata(gphy->insts[GOOGLE_USB3_PHY].phy, &gphy->insts[GOOGLE_USB3_PHY]);
+
+ ret = google_usb_phy_parse_clocks(gphy);
if (ret)
- return dev_err_probe(dev, ret, "failed to get u2 phy clks\n");
+ return ret;
- inst->num_rsts = 2;
- inst->rsts = devm_kcalloc(dev, inst->num_rsts, sizeof(*inst->rsts), GFP_KERNEL);
- if (!inst->rsts)
- return -ENOMEM;
- inst->rsts[0].id = "usb2";
- inst->rsts[1].id = "usb2_apb";
- ret = devm_reset_control_bulk_get_exclusive(dev, inst->num_rsts, inst->rsts);
+ ret = google_usb_phy_parse_resets(gphy);
if (ret)
- return dev_err_probe(dev, ret, "failed to get u2 phy resets\n");
+ return ret;
phy_provider = devm_of_phy_provider_register(dev, google_usb_phy_xlate);
if (IS_ERR(phy_provider))
base-commit: 2ace2e949979b82f82f12dd76d7c5a6145246ca3
--
2.55.0.rc2.803.g1fd1e6609c-goog
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related
* Re: [RFC PATCH v1 1/2] phy: rockchip: inno-usb2: keep peripheral-only OTG port active
From: sashiko-bot @ 2026-07-06 22:55 UTC (permalink / raw)
To: Andreas Zdziarstek
Cc: olteanv, vkoul, linux-phy, conor+dt, devicetree, robh,
neil.armstrong
In-Reply-To: <20260706223627.113814-2-andreas.zdziarstek@gmail.com>
Thank you for your contribution! Sashiko AI review found 6 potential issue(s) to consider:
New issues:
- [Medium] The patch introduces a permanent power state leak for peripheral-only ports by skipping autonomous PHY power-offs but failing to skip autonomous power-ons.
Pre-existing issues:
- [Critical] The charger detection logic accesses uninitialized `chg_det` registers on SoCs like RK3036, inadvertently corrupting GRF register offset 0x0.
- [High] Delayed works (`otg_sm_work`, `chg_work`, `sm_work`) are not properly canceled on driver unbind, and mutual re-arming prevents clean teardown, leading to use-after-free.
- [High] The `cable` variable in `rockchip_usb2phy_otg_sm_work` is declared as `static`, which causes state corruption if multiple OTG ports exist.
- [High] Unprotected concurrent modifications to OTG and charger state variables (`rport->state`, `rphy->chg_state`, `rphy->chg_type`).
- [Medium] Concurrent lockless access to `rport->suspended` and hardware clock/register state between workqueues and the PHY core leads to a data race and clock leaks.
--
--- Patch [1]: [RFC PATCH v1 1/2] phy: rockchip: inno-usb2: keep peripheral-only OTG port active ---
commit dc6ab852562662efe7db14ed699e4f8c82b9f053
Author: Andreas Zdziarstek <andreas.zdziarstek@gmail.com>
phy: rockchip: inno-usb2: keep peripheral-only OTG port active
This commit updates the OTG state machine to skip autonomous power-offs
when the port is peripheral-only. This prevents the state machine from
suspending the port and killing the USB gadget when booting without an
attached cable.
> diff --git a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
> index 7d8a533f24aea..9b138b7aaeb89 100644
> --- a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
> +++ b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
> @@ -670,6 +670,23 @@ static const struct phy_ops rockchip_usb2phy_ops = {
[ ... ]
> +static void rockchip_usb2phy_sm_power_off(struct rockchip_usb2phy_port *rport)
> +{
> + if (rport->mode == USB_DR_MODE_PERIPHERAL)
> + return;
> +
> + rockchip_usb2phy_power_off(rport->phy);
> +}
[Severity: Medium]
The patch updates this function to skip powering off the PHY when the mode is
USB_DR_MODE_PERIPHERAL during a cable detach. However, further down in
rockchip_usb2phy_otg_sm_work(), the state machine still autonomously powers
ON the PHY when a cable is attached.
Does this asymmetrical behavior leave the PHY powered on indefinitely after
the first cable insertion, preventing system suspend?
> +
> static void rockchip_usb2phy_otg_sm_work(struct work_struct *work)
> {
> struct rockchip_usb2phy_port *rport =
> @@ -693,7 +710,7 @@ static void rockchip_usb2phy_otg_sm_work(struct work_struct *work)
> case OTG_STATE_UNDEFINED:
> rport->state = OTG_STATE_B_IDLE;
[Severity: High]
This is a pre-existing issue, but is it safe to locklessly modify shared state
variables like rport->state here?
This state machine can run in the delayed workqueue, and is concurrently
invoked synchronously by the threaded IRQ handler
rockchip_usb2phy_bvalid_irq() as well as the rockchip_chg_detect_work()
workqueue.
Could this lack of mutual exclusion allow interleaved state transitions on
multiple CPUs and corrupt the state machine?
> if (!vbus_attach)
> - rockchip_usb2phy_power_off(rport->phy);
> + rockchip_usb2phy_sm_power_off(rport);
> fallthrough;
> case OTG_STATE_B_IDLE:
> if (extcon_get_state(rphy->edev, EXTCON_USB_HOST) > 0) {
> @@ -719,7 +736,7 @@ static void rockchip_usb2phy_otg_sm_work(struct work_struct *work)
> break;
> case POWER_SUPPLY_TYPE_USB_DCP:
> dev_dbg(&rport->phy->dev, "dcp cable is connected\n");
> - rockchip_usb2phy_power_off(rport->phy);
> + rockchip_usb2phy_sm_power_off(rport);
> notify_charger = true;
> sch_work = true;
> cable = EXTCON_CHG_USB_DCP;
[Severity: High]
This is a pre-existing issue, but does the static declaration of this cable
variable cause state corruption if multiple OTG ports exist?
SoCs like RK3399 define multiple USB2 PHY instances with OTG ports. If VBUS
events overlap or alternate between ports, could the shared cable variable be
overwritten by the latest event, causing disconnected ports to report the
charger type of a different port to extcon?
> @@ -765,7 +782,7 @@ static void rockchip_usb2phy_otg_sm_work(struct work_struct *work)
[ ... ]
> if (extcon_get_state(rphy->edev, EXTCON_USB_HOST) == 0) {
> dev_dbg(&rport->phy->dev, "usb otg host disconnect\n");
> rport->state = OTG_STATE_B_IDLE;
> - rockchip_usb2phy_power_off(rport->phy);
> + rockchip_usb2phy_sm_power_off(rport);
> }
> break;
> default:
[Severity: Medium]
This isn't a bug introduced by this patch, but does invoking the internal
power management functions directly from the workqueue bypass the generic PHY
framework mutex?
The generic PHY subsystem calls phy_power_on() (protected by phy->mutex),
which invokes rockchip_usb2phy_power_on(). Concurrently, the driver's
workqueues invoke rockchip_usb2phy_power_on() directly without acquiring
any locks.
Since rockchip_usb2phy_power_on() performs a check-then-act on
rport->suspended:
rockchip_usb2phy_power_on() {
if (!rport->suspended)
return 0;
ret = clk_prepare_enable(rphy->clk480m);
...
}
Could both threads evaluate rport->suspended as true simultaneously, causing
double clock enables but only a single disable later?
[Severity: High]
This is a pre-existing issue, but how are these delayed works safely torn
down?
The works otg_sm_work and chg_work re-arm each other. In
rockchip_usb2phy_exit(), they are cancelled sequentially:
rockchip_usb2phy_exit() {
cancel_delayed_work_sync(&rport->otg_sm_work);
cancel_delayed_work_sync(&rport->chg_work);
...
}
If chg_work executes while otg_sm_work is being cancelled, can it re-arm
otg_sm_work after the cancellation finishes?
Additionally, since these works are initialized on devm-managed memory but
there is no driver .remove callback to cancel them, could pending works
execute on devm-freed memory upon driver unbind?
> @@ -838,7 +855,7 @@ static void rockchip_chg_detect_work(struct work_struct *work)
> switch (rphy->chg_state) {
> case USB_CHG_STATE_UNDEFINED:
> if (!rport->suspended && !vbus_attach)
> - rockchip_usb2phy_power_off(rport->phy);
> + rockchip_usb2phy_sm_power_off(rport);
> /* put the controller in non-driving mode */
> if (!vbus_attach)
> property_enable(rphy->grf, &rphy->phy_cfg->chg_det.opmode, false);
[Severity: Critical]
This is a pre-existing issue, but does this logic safely handle SoCs where
chg_det is not defined?
For SoCs like RK3036, the rk3036_phy_cfgs does not define chg_det. However,
rockchip_usb2phy_otg_port_init() unconditionally initializes charger detection.
When a cable is attached, rockchip_chg_detect_work() invokes
property_enable() on the zeroed chg_det fields:
property_enable() {
...
return regmap_write(base, reg->offset, val);
}
Because it lacks validation, would this silently write to reg->offset 0x0
with a write mask, corrupting the General Register Files (GRF) at offset 0x0?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260706223627.113814-1-andreas.zdziarstek@gmail.com?part=1
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* Re: [PATCH v3] phy: Add USB3 PHY support to Google Tensor SoC USB PHY driver
From: RD Babiera @ 2026-07-06 22:43 UTC (permalink / raw)
To: sashiko-reviews, Badhri Jagan Sridharan
Cc: vkoul, neil.armstrong, olteanv, linux-phy
In-Reply-To: <20260701024002.DB4E71F000E9@smtp.kernel.org>
On Tue, Jun 30, 2026 at 7:40 PM <sashiko-bot@kernel.org> wrote:
> > +static int google_usb3_phy_exit(struct phy *_phy)
> > +{
> > + struct google_usb_phy_instance *inst = phy_get_drvdata(_phy);
> > + struct google_usb_phy *gphy = inst->parent;
> > +
> > + dev_dbg(gphy->dev, "exiting usb3 phy\n");
> > +
> > + guard(mutex)(&gphy->phy_mutex);
> > +
> > + set_pmgt_ref_clk_req_n(gphy, false);
> > + reset_control_bulk_assert(inst->num_rsts, inst->rsts);
> > + clk_bulk_disable_unprepare(inst->num_clks, inst->clks);
>
> [Severity: High]
> Is the manual teardown sequence here in the correct order?
>
> In google_usb3_phy_init(), resources are acquired in this order:
> 1) set_pmgt_ref_clk_req_n(true)
> 2) clock enable
> 3) reset deassert
>
> The __free blocks in the init function correctly establish the error cleanup
> sequence in reverse order (LIFO). However, here the upstream reference clock
> request is disabled before placing the hardware block into reset and
> disabling clocks.
>
> Could disabling the clock request before asserting reset freeze the IP in an
> invalid state and prevent subsequent wakeups?
I've verified both orderings of set_pmgt_ref_clk_req_n in phy_exit, will
change to be consistent with phy_init ordering though.
> > +
> > + return program_tca_locked(gphy);
>
> [Severity: High]
> Should this check if the Type-C port is actually connected before calling
> program_tca_locked()?
>
> If the port is disconnected (gphy->orientation == TYPEC_ORIENTATION_NONE),
> program_tca_locked() falls through its else branch, configuring the registers
> for TYPEC_ORIENTATION_NORMAL and setting TCA_TCPC_VALID.
>
> Since the Type-C switch callback google_usb_set_orientation() correctly skips
> TCA programming if the orientation is NONE, should a similar check be present
> here to prevent enabling the SuperSpeed data path for a phantom connection?
Will guard behind gphy->orientation in next version. If the port is
disconnected the
PHY will be treated as being in normal orientation, but given USB mode is being
programmed here and not NC, it's more correct to only program USB when
a port partner is actually connected.
Best,
RD
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* [RFC PATCH v1 2/2] arm64: dts: rockchip: fix gadget hot-plug on ODROID-M1S micro-USB
From: Andreas Zdziarstek @ 2026-07-06 22:36 UTC (permalink / raw)
To: Vinod Koul, Neil Armstrong
Cc: Heiko Stuebner, Jonas Karlman, Frank Wang, Louis Chauvet,
Luca Ceresoli, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
devicetree, linux-phy, linux-rockchip, linux-arm-kernel,
linux-usb, linux-kernel, Andreas Zdziarstek
In-Reply-To: <20260706223627.113814-1-andreas.zdziarstek@gmail.com>
Referencing the vcc5v0_usb2_otg switch as phy-supply of the OTG port
makes the phy core enable it as soon as the USB controller powers the
PHY, so the board permanently drives its own 5 V onto the micro-USB
connector's VBUS pin. That blinds the PHY's session detection: VBUSDET
(fed from connector VBUS through the on-board 10k/15k divider) is
always high, no bvalid edge can ever occur on plug or unplug, and the
OTG state machine never wakes from its initial state. A USB gadget
only enumerates if the cable is already attached at power-on. It also
back-drives 5 V against the host port.
The inno-usb2 driver has no role-managed VBUS supply support, and the
practical use of this port is as the board's USB device/download port.
Separate Type-A ports are available for host functions.
Drop the phy-supply so the port never sources VBUS and pin the
controller to dr_mode="peripheral" to match that.
Fixes: 10dc64fe0f98 ("arm64: dts: rockchip: Add Hardkernel ODROID-M1S")
Signed-off-by: Andreas Zdziarstek <andreas.zdziarstek@gmail.com>
---
arch/arm64/boot/dts/rockchip/rk3566-odroid-m1s.dts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm64/boot/dts/rockchip/rk3566-odroid-m1s.dts b/arch/arm64/boot/dts/rockchip/rk3566-odroid-m1s.dts
index 33bc5249d729..d9d4a31373a0 100644
--- a/arch/arm64/boot/dts/rockchip/rk3566-odroid-m1s.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3566-odroid-m1s.dts
@@ -602,6 +602,7 @@ &usb_host0_ohci {
};
&usb_host0_xhci {
+ dr_mode = "peripheral";
status = "okay";
};
@@ -627,7 +628,6 @@ &usb2phy0_host {
};
&usb2phy0_otg {
- phy-supply = <&vcc5v0_usb2_otg>;
status = "okay";
};
--
2.53.0
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related
* [RFC PATCH v1 1/2] phy: rockchip: inno-usb2: keep peripheral-only OTG port active
From: Andreas Zdziarstek @ 2026-07-06 22:36 UTC (permalink / raw)
To: Vinod Koul, Neil Armstrong
Cc: Heiko Stuebner, Jonas Karlman, Frank Wang, Louis Chauvet,
Luca Ceresoli, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
devicetree, linux-phy, linux-rockchip, linux-arm-kernel,
linux-usb, linux-kernel, Andreas Zdziarstek
In-Reply-To: <20260706223627.113814-1-andreas.zdziarstek@gmail.com>
The OTG state machine autonomously suspends the OTG port whenever it
decides no usable VBUS session is present. On the initial sample after
init, when a dedicated charger is detected, on peripheral disconnect
and on host-session end. It calls rockchip_usb2phy_power_off()
directly, underneath the USB controller.
For a dr_mode="peripheral" port this kills the USB gadget on any boot
without an attached cable. The state machine suspends the port shortly
after init, resulting in "failed to enable ep0out", ep0 start transfer
returns -EINVAL). The gadget remains unrecoverable in user space
afterwards.
Skip the state machine's autonomous power-offs when the port is
peripheral-only. VBUS detection, extcon signalling and charger
detection are unaffected, and controller-initiated power management
via phy_power_on()/phy_power_off() keeps working.
Signed-off-by: Andreas Zdziarstek <andreas.zdziarstek@gmail.com>
---
drivers/phy/rockchip/phy-rockchip-inno-usb2.c | 27 +++++++++++++++----
1 file changed, 22 insertions(+), 5 deletions(-)
diff --git a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
index 7d8a533f24ae..9b138b7aaeb8 100644
--- a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
+++ b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
@@ -670,6 +670,23 @@ static const struct phy_ops rockchip_usb2phy_ops = {
.owner = THIS_MODULE,
};
+/*
+ * Autonomous power-off from the OTG state machine or charger detection.
+ *
+ * A peripheral-only port shouldn't be power-gated behind the controller's
+ * back. If the gadget (re)binds while the PHY is suspended, the
+ * controller's ep0 setup fails and the gadget stays dead even when a VBUS
+ * session appears later. Keep the phy active on peripheral ports for
+ * correct connection detection.
+ */
+static void rockchip_usb2phy_sm_power_off(struct rockchip_usb2phy_port *rport)
+{
+ if (rport->mode == USB_DR_MODE_PERIPHERAL)
+ return;
+
+ rockchip_usb2phy_power_off(rport->phy);
+}
+
static void rockchip_usb2phy_otg_sm_work(struct work_struct *work)
{
struct rockchip_usb2phy_port *rport =
@@ -693,7 +710,7 @@ static void rockchip_usb2phy_otg_sm_work(struct work_struct *work)
case OTG_STATE_UNDEFINED:
rport->state = OTG_STATE_B_IDLE;
if (!vbus_attach)
- rockchip_usb2phy_power_off(rport->phy);
+ rockchip_usb2phy_sm_power_off(rport);
fallthrough;
case OTG_STATE_B_IDLE:
if (extcon_get_state(rphy->edev, EXTCON_USB_HOST) > 0) {
@@ -719,7 +736,7 @@ static void rockchip_usb2phy_otg_sm_work(struct work_struct *work)
break;
case POWER_SUPPLY_TYPE_USB_DCP:
dev_dbg(&rport->phy->dev, "dcp cable is connected\n");
- rockchip_usb2phy_power_off(rport->phy);
+ rockchip_usb2phy_sm_power_off(rport);
notify_charger = true;
sch_work = true;
cable = EXTCON_CHG_USB_DCP;
@@ -765,7 +782,7 @@ static void rockchip_usb2phy_otg_sm_work(struct work_struct *work)
rphy->chg_type = POWER_SUPPLY_TYPE_UNKNOWN;
rport->state = OTG_STATE_B_IDLE;
delay = 0;
- rockchip_usb2phy_power_off(rport->phy);
+ rockchip_usb2phy_sm_power_off(rport);
}
sch_work = true;
break;
@@ -773,7 +790,7 @@ static void rockchip_usb2phy_otg_sm_work(struct work_struct *work)
if (extcon_get_state(rphy->edev, EXTCON_USB_HOST) == 0) {
dev_dbg(&rport->phy->dev, "usb otg host disconnect\n");
rport->state = OTG_STATE_B_IDLE;
- rockchip_usb2phy_power_off(rport->phy);
+ rockchip_usb2phy_sm_power_off(rport);
}
break;
default:
@@ -838,7 +855,7 @@ static void rockchip_chg_detect_work(struct work_struct *work)
switch (rphy->chg_state) {
case USB_CHG_STATE_UNDEFINED:
if (!rport->suspended && !vbus_attach)
- rockchip_usb2phy_power_off(rport->phy);
+ rockchip_usb2phy_sm_power_off(rport);
/* put the controller in non-driving mode */
if (!vbus_attach)
property_enable(rphy->grf, &rphy->phy_cfg->chg_det.opmode, false);
--
2.53.0
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related
* [RFC PATCH v1 0/2] phy: rockchip: inno-usb2: fix USB gadget hot-plug on peripheral-only OTG ports
From: Andreas Zdziarstek @ 2026-07-06 22:36 UTC (permalink / raw)
To: Vinod Koul, Neil Armstrong
Cc: Heiko Stuebner, Jonas Karlman, Frank Wang, Louis Chauvet,
Luca Ceresoli, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
devicetree, linux-phy, linux-rockchip, linux-arm-kernel,
linux-usb, linux-kernel, Andreas Zdziarstek
Hi All,
I had an interesting time trying out the USB OTG micro-USB port on the
Odroid-M1S (Rockchip RK3566) on the mainline Kernel. My intention was to
set up a cdc_ncm+cdc_acm peripheral gadget as a hot-pluggable debug
port.
For the most part that went swimmingly. Just not quite with the
hot-plugging. The apparent first problem was that peripheral mode only
works if the host is connected at boot time of the RK3566 Kernel,
regardless if the dr_mode settings is "otg" or "peripheral". When no
connection is present at boot, gadget setup fails with a
"failed to enable ep0out" error and the port seems to end up in an
unrecoverable state afterwards.
I investigated a little as to why. With my very limited understanding
of the subsystems involved, I think I have identified some problems.
All seem largely related to each other.
* The M1S references its 5V OTG VBUS switch as phy-supply of the OTG
port in its DT. The phy core unconditionally enables that on phy
power_on. From then on it powers its own VBUSDET input, making further
cable VBUS detection impossible. Also, apparently, after reading the
schematic, that means even with a cable connected at boot (and
peripheral mode therefore working), the board will try to back-power
the host. Seems my host port is pretty robust, luckily.
* The inno-usb2 driver seems to generally lack DRP power supply VBUS
switching support? At least PHY and VBUS supply are semantically
treated the same.
* The inno-usb2 driver's state machine powers off the Phy in several
places: on an initial no-VBUS sample, on DCP detection and on
disconnect. That seems to happen unrelated to controller-initiated
phy_power_on/off calls and looks like the main cause the gadget setup
fails and then borks the controller state.
My proposed fixes are in two places:
* set the micro-USB M1S port to "peripheral" in DTS and remove the
supply node. The board has two USB-A host ports, so device mode is the
most likely usage scenario for the microUSB and real compliant DRP
does not seem to be in the cards in the current state. Also, this
fixes the potentially harmful back-powering issue. (2nd patch)
* keep the inno-usb2 phy driver from autonomously powering off when in
peripheral mode. This makes hot-plugging and gadget-setup without a
connected cable work. (1st patch)
This "works great for me". No issues whatsoever with the M1S in device
mode. I can plug/unplug/replug at will at any time, rock solid.
However, I am also doubting myself if I have completely misunderstood
the whole Dual-Role status quo and should have just done something
differently.
Also even if I am right about the problems, I would agree with anyone
saying that this isn't the "proper" fix for the whole situation. It
seems the rockchip vendor kernel is doing DRP related stuff differently,
e.g. an additional vbus-supply setting in DT with apparent support for
VBUS role-switching. Fully automatic OTG with gadget support *should*
be possible to do. Possibly a lot of work, though.
Still, I would say having a solid peripheral-only option including
hot-plugging is an improvement to the status-quo.
Host-only configs in other DTs should be unaffected as the inno-usb2
changes won't matter there. The autonomous power-off will still happen,
for better or worse.
Would love to get some insights on this from the experts.
Cheers,
Andy
Andreas Zdziarstek (2):
phy: rockchip: inno-usb2: keep peripheral-only OTG port active
arm64: dts: rockchip: fix gadget hot-plug on ODROID-M1S micro-USB
.../boot/dts/rockchip/rk3566-odroid-m1s.dts | 2 +-
drivers/phy/rockchip/phy-rockchip-inno-usb2.c | 27 +++++++++++++++----
2 files changed, 23 insertions(+), 6 deletions(-)
--
2.53.0
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* Re: [PATCH v3 1/4] dt-bindings: phy: motorola,cpcap-usb: add chrg_det interrupt
From: Ivaylo Dimitrov @ 2026-07-06 21:25 UTC (permalink / raw)
To: Conor Dooley
Cc: Vinod Koul, Neil Armstrong, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Aaro Koskinen, Andreas Kemnade, Kevin Hilman,
Roger Quadros, Tony Lindgren, Linus Walleij, Bartosz Golaszewski,
linux-phy, devicetree, linux-kernel, linux-omap, linux-gpio
In-Reply-To: <20260706-visitor-calorie-b805ac5af970@spud>
Hi,
On 6.07.26 г. 20:14 ч., Conor Dooley wrote:
> On Sun, Jul 05, 2026 at 01:11:02PM +0300, Ivaylo Dimitrov wrote:
>> The CPCAP USB PHY driver uses the CPCAP charger detection interrupt
>> for DCP detection.
>
> This is not currently true, the driver does not look for this interrupt
> at the time of this patch.
>
Right, this is bad wording caused by the fact that initially the driver
patch came before the binding patch.
>> Update the binding and example DTS to use the corresponding
>> "chrg_det" interrupt name.
>
> Sounds to me like this new interrupt is optional, since until now it has
> not been needed? The patch however makes it mandatory. I think your
> driver patch also makes it mandatory, which will break older
> devicetrees.
>
Oh, it is indeed not needed for proper DCP/SDP detection, after some
experiments I was able to teach the driver to do proper detection by
using current interrupts only.
> What makes this ABI break okay?
>
Will send new series with schema/DT patches dropped.
Thanks and regards,
Ivo
> Thanks,
> Conor.
>
>>
>> Signed-off-by: Ivaylo Dimitrov <ivo.g.dimitrov.75@gmail.com>
>> ---
>> .../devicetree/bindings/phy/motorola,cpcap-usb-phy.yaml | 6 ++++--
>> 1 file changed, 4 insertions(+), 2 deletions(-)
>>
>> diff --git a/Documentation/devicetree/bindings/phy/motorola,cpcap-usb-phy.yaml b/Documentation/devicetree/bindings/phy/motorola,cpcap-usb-phy.yaml
>> index 0febd04a61f4..523a8f8480d0 100644
>> --- a/Documentation/devicetree/bindings/phy/motorola,cpcap-usb-phy.yaml
>> +++ b/Documentation/devicetree/bindings/phy/motorola,cpcap-usb-phy.yaml
>> @@ -30,6 +30,7 @@ properties:
>> - description: se1 interrupt
>> - description: dm interrupt
>> - description: dp interrupt
>> + - description: charger detection interrupt
>>
>> interrupt-names:
>> description: Interrupt names
>> @@ -43,6 +44,7 @@ properties:
>> - const: se1
>> - const: dm
>> - const: dp
>> + - const: chrg_det
>>
>> io-channels:
>> description: IIO ADC channels used by the USB PHY
>> @@ -91,10 +93,10 @@ examples:
>> interrupts-extended = <
>> &cpcap 15 0 &cpcap 14 0 &cpcap 28 0 &cpcap 19 0
>> &cpcap 18 0 &cpcap 17 0 &cpcap 16 0 &cpcap 49 0
>> - &cpcap 48 1
>> + &cpcap 48 1 &cpcap 13 0
>> >;
>> interrupt-names = "id_ground", "id_float", "se0conn", "vbusvld",
>> - "sessvld", "sessend", "se1", "dm", "dp";
>> + "sessvld", "sessend", "se1", "dm", "dp", "chrg_det";
>> io-channels = <&cpcap_adc 2>, <&cpcap_adc 7>;
>> io-channel-names = "vbus", "id";
>> vusb-supply = <&vusb>;
>> --
>> 2.39.5
>>
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* Re: [PATCH 2/8] arm64: dts: qcom: sm8450: Remove unneeded reserved memory nodes
From: Dmitry Baryshkov @ 2026-07-06 18:24 UTC (permalink / raw)
To: Esteban Urrutia
Cc: Konrad Dybcio, Bjorn Andersson, Michael Turquette, Stephen Boyd,
Brian Masney, Konrad Dybcio, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Rob Clark, Will Deacon, Robin Murphy,
Joerg Roedel (AMD), Vinod Koul, Neil Armstrong, linux-arm-msm,
linux-clk, linux-kernel, devicetree, iommu, linux-arm-kernel,
linux-phy
In-Reply-To: <b3541802-3035-40ee-8327-a65bd5d2dfee@proton.me>
On Wed, Jun 24, 2026 at 01:26:06PM +0000, Esteban Urrutia wrote:
>
>
> On 6/23/26 7:03 AM, Konrad Dybcio wrote:
> >> This is mentioned in the memory map description, but is not part
> >> of it.
> >>
> >> I booted up a 8450 HDK and it doesn't even have MTE, so it's
> >> probably valid
> >
> > i.e. it doesn't report MTE to Linux. I don't know if it's Gunyah
> > trapping it.
> Then, should device trees delete these memory regions on a case-by-case
> basis, or be left as is?
Please verify that you can actually access those areas (boot with
memtest=1)
--
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 1/8] clk: qcom: dispcc-sm8450: Fix mdss clocks
From: Dmitry Baryshkov @ 2026-07-06 18:22 UTC (permalink / raw)
To: esteuwu
Cc: Bjorn Andersson, Michael Turquette, Stephen Boyd, Brian Masney,
Konrad Dybcio, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Rob Clark, Will Deacon, Robin Murphy, Joerg Roedel (AMD),
Vinod Koul, Neil Armstrong, linux-arm-msm, linux-clk,
linux-kernel, devicetree, iommu, linux-arm-kernel, linux-phy
In-Reply-To: <20260622-sm8450-qol-v1-1-37e2ee8df9da@proton.me>
On Mon, Jun 22, 2026 at 08:54:22PM -0400, Esteban Urrutia via B4 Relay wrote:
> From: Esteban Urrutia <esteuwu@proton.me>
>
> Both of these changes allow the framebuffer to show upon boot and let
> the mdss driver take over afterwards.
> Before, none of these actions were possible. Only mdss takeover was
> possible, but screen had to be turned off first.
>
> OLE configuration may have been a misinterpretation... that's not
> something that's done on the downstream driver.
As far as I can see, SM8475 uses lucid_ole for PLL0 / PLL1.
So, no, this part is correct.
>
> Changing disp_cc_mdss_mdp_clk_src from clk_rcg2_shared_ops to
> clk_rcg2_shared_no_init_park_ops fixes this warning as well:
>
--
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 1/2] dt-bindings: pci: qcom,hawi-pcie: Add Maili PCIe compatible
From: Krzysztof Kozlowski @ 2026-07-06 17:35 UTC (permalink / raw)
To: Manivannan Sadhasivam
Cc: Vivek Pernamitta, Lorenzo Pieralisi, Krzysztof Wilczyński,
Rob Herring, Bjorn Helgaas, Krzysztof Kozlowski, Conor Dooley,
Bjorn Andersson, Vinod Koul, Neil Armstrong, linux-arm-msm,
linux-pci, devicetree, linux-kernel, linux-phy
In-Reply-To: <yntj62kr7tixc7capwdr6xhv2zpisfrjg62bwftgiuujf4fzt5@cjdrkglo4dv5>
On 06/07/2026 18:36, Manivannan Sadhasivam wrote:
> On Mon, Jul 06, 2026 at 08:46:41AM +0200, Krzysztof Kozlowski wrote:
>> On Fri, Jul 03, 2026 at 05:38:40PM +0530, Vivek Pernamitta wrote:
>>> Add qcom,maili-pcie as a compatible string that falls back to
>>> qcom,hawi-pcie, as the Maili SoC reuses the Hawi PCIe controller IP.
>>>
>>> The Maili SoC is a derivative of Hawi and shares the same PCIe
>>> controller architecture, allowing reuse of the existing Hawi PCIe
>>> DT bindings.
>>>
>>> Signed-off-by: Vivek Pernamitta <vivek.pernamitta@oss.qualcomm.com>
>>> ---
>>> Dependencies:
>>> - PCI: qcom: Add PCIe support for upcoming Hawi SoC
>>> https://lore.kernel.org/all/20260625-hawi-pcie-v4-0-1a578603cd86@oss.qualcomm.com/
>>
>> Squash the patches then.
>>
>
> But these are two independent SoC additions, isn't it?
It's adding a single compatible, no? If a patch adding a single
compatible cannot be done without multi-patchset dependencies making
testing by tooling impossible, then probably that work should not be
sent separately or even as separate patch. And I am not saying anything
new because half a year ago (around Kaanapali and Glymur) I voiced
strong opinion about that.
But really, you do not need to add two compatibles in two separate patches.
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 v3 1/4] dt-bindings: phy: motorola,cpcap-usb: add chrg_det interrupt
From: Conor Dooley @ 2026-07-06 17:14 UTC (permalink / raw)
To: Ivaylo Dimitrov
Cc: Vinod Koul, Neil Armstrong, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Aaro Koskinen, Andreas Kemnade, Kevin Hilman,
Roger Quadros, Tony Lindgren, Linus Walleij, Bartosz Golaszewski,
linux-phy, devicetree, linux-kernel, linux-omap, linux-gpio
In-Reply-To: <20260705101105.1798069-2-ivo.g.dimitrov.75@gmail.com>
[-- Attachment #1.1: Type: text/plain, Size: 2329 bytes --]
On Sun, Jul 05, 2026 at 01:11:02PM +0300, Ivaylo Dimitrov wrote:
> The CPCAP USB PHY driver uses the CPCAP charger detection interrupt
> for DCP detection.
This is not currently true, the driver does not look for this interrupt
at the time of this patch.
> Update the binding and example DTS to use the corresponding
> "chrg_det" interrupt name.
Sounds to me like this new interrupt is optional, since until now it has
not been needed? The patch however makes it mandatory. I think your
driver patch also makes it mandatory, which will break older
devicetrees.
What makes this ABI break okay?
Thanks,
Conor.
>
> Signed-off-by: Ivaylo Dimitrov <ivo.g.dimitrov.75@gmail.com>
> ---
> .../devicetree/bindings/phy/motorola,cpcap-usb-phy.yaml | 6 ++++--
> 1 file changed, 4 insertions(+), 2 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/phy/motorola,cpcap-usb-phy.yaml b/Documentation/devicetree/bindings/phy/motorola,cpcap-usb-phy.yaml
> index 0febd04a61f4..523a8f8480d0 100644
> --- a/Documentation/devicetree/bindings/phy/motorola,cpcap-usb-phy.yaml
> +++ b/Documentation/devicetree/bindings/phy/motorola,cpcap-usb-phy.yaml
> @@ -30,6 +30,7 @@ properties:
> - description: se1 interrupt
> - description: dm interrupt
> - description: dp interrupt
> + - description: charger detection interrupt
>
> interrupt-names:
> description: Interrupt names
> @@ -43,6 +44,7 @@ properties:
> - const: se1
> - const: dm
> - const: dp
> + - const: chrg_det
>
> io-channels:
> description: IIO ADC channels used by the USB PHY
> @@ -91,10 +93,10 @@ examples:
> interrupts-extended = <
> &cpcap 15 0 &cpcap 14 0 &cpcap 28 0 &cpcap 19 0
> &cpcap 18 0 &cpcap 17 0 &cpcap 16 0 &cpcap 49 0
> - &cpcap 48 1
> + &cpcap 48 1 &cpcap 13 0
> >;
> interrupt-names = "id_ground", "id_float", "se0conn", "vbusvld",
> - "sessvld", "sessend", "se1", "dm", "dp";
> + "sessvld", "sessend", "se1", "dm", "dp", "chrg_det";
> io-channels = <&cpcap_adc 2>, <&cpcap_adc 7>;
> io-channel-names = "vbus", "id";
> vusb-supply = <&vusb>;
> --
> 2.39.5
>
[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
[-- Attachment #2: Type: text/plain, Size: 112 bytes --]
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* Re: [PATCH 7/8] phy: qcom: qmp-combo: Correct pre-emphasis table for QMP v4 DP PHYs
From: Konrad Dybcio @ 2026-07-06 16:36 UTC (permalink / raw)
To: Esteban Urrutia, Bjorn Andersson, Michael Turquette, Stephen Boyd,
Brian Masney, Konrad Dybcio, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Rob Clark, Will Deacon, Robin Murphy,
Joerg Roedel (AMD), Vinod Koul, Neil Armstrong, Dmitry Baryshkov
Cc: linux-arm-msm, linux-clk, linux-kernel, devicetree, iommu,
linux-arm-kernel, linux-phy
In-Reply-To: <9a203e5e-5d16-400d-a507-8b68df8eb017@proton.me>
On 7/6/26 4:44 PM, Esteban Urrutia wrote:
> On 6/23/26 7:36 AM, Konrad Dybcio wrote:
>> It seems like 8350/8450 should be using what this driver calls
>> v5 tables, with this fixup:
> Any updates on this?
Dmitry, could you take a look at my findings?
https://lore.kernel.org/linux-arm-msm/4635a665-f605-4647-810d-c9d83a271a86@oss.qualcomm.com/
Konrad
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* Re: [PATCH 1/2] dt-bindings: pci: qcom,hawi-pcie: Add Maili PCIe compatible
From: Manivannan Sadhasivam @ 2026-07-06 16:36 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: Vivek Pernamitta, Lorenzo Pieralisi, Krzysztof Wilczyński,
Rob Herring, Bjorn Helgaas, Krzysztof Kozlowski, Conor Dooley,
Bjorn Andersson, Vinod Koul, Neil Armstrong, linux-arm-msm,
linux-pci, devicetree, linux-kernel, linux-phy
In-Reply-To: <20260706-pastoral-okapi-of-reading-e5bdb3@quoll>
On Mon, Jul 06, 2026 at 08:46:41AM +0200, Krzysztof Kozlowski wrote:
> On Fri, Jul 03, 2026 at 05:38:40PM +0530, Vivek Pernamitta wrote:
> > Add qcom,maili-pcie as a compatible string that falls back to
> > qcom,hawi-pcie, as the Maili SoC reuses the Hawi PCIe controller IP.
> >
> > The Maili SoC is a derivative of Hawi and shares the same PCIe
> > controller architecture, allowing reuse of the existing Hawi PCIe
> > DT bindings.
> >
> > Signed-off-by: Vivek Pernamitta <vivek.pernamitta@oss.qualcomm.com>
> > ---
> > Dependencies:
> > - PCI: qcom: Add PCIe support for upcoming Hawi SoC
> > https://lore.kernel.org/all/20260625-hawi-pcie-v4-0-1a578603cd86@oss.qualcomm.com/
>
> Squash the patches then.
>
But these are two independent SoC additions, isn't it?
- Mani
--
மணிவண்ணன் சதாசிவம்
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* Re: [PATCH v2 1/3] phy: qcom-qusb2: enable autoresume on Talos platforms
From: Konrad Dybcio @ 2026-07-06 15:37 UTC (permalink / raw)
To: Dmitry Baryshkov, Vinod Koul, Neil Armstrong, Kathiravan T,
Baruch Siach, Dmitry Baryshkov, Krishna Kurapati, Manu Gautam,
Kishon Vijay Abraham I
Cc: linux-arm-msm, linux-phy, linux-kernel, stable
In-Reply-To: <20260706-fix-qusb2-v2-1-8d9cd73b1db7@oss.qualcomm.com>
On 7/6/26 3:53 PM, Dmitry Baryshkov wrote:
> According to Krishna, having autoresume disabled on Talos is a c&p
> error and it should be enabled.
>
> Suggested-by: Krishna Kurapati <krishna.kurapati@oss.qualcomm.com>
> Fixes: 8adbf20e0502 ("phy: qcom-qusb2: Add support for QCS615")
> Cc: stable@vger.kernel.org
> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
> ---
Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
Konrad
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* Re: [PATCH 7/8] phy: qcom: qmp-combo: Correct pre-emphasis table for QMP v4 DP PHYs
From: Esteban Urrutia @ 2026-07-06 14:44 UTC (permalink / raw)
To: Konrad Dybcio, Bjorn Andersson, Michael Turquette, Stephen Boyd,
Brian Masney, Konrad Dybcio, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Rob Clark, Will Deacon, Robin Murphy,
Joerg Roedel (AMD), Vinod Koul, Neil Armstrong, Dmitry Baryshkov
Cc: linux-arm-msm, linux-clk, linux-kernel, devicetree, iommu,
linux-arm-kernel, linux-phy
In-Reply-To: <4635a665-f605-4647-810d-c9d83a271a86@oss.qualcomm.com>
On 6/23/26 7:36 AM, Konrad Dybcio wrote:
> It seems like 8350/8450 should be using what this driver calls
> v5 tables, with this fixup:
Any updates on this?
Regards,
Esteban
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* [PATCH v2 3/3] phy: qcom-qusb2: describe autoresume bit
From: Dmitry Baryshkov @ 2026-07-06 13:53 UTC (permalink / raw)
To: Vinod Koul, Neil Armstrong, Kathiravan T, Baruch Siach,
Dmitry Baryshkov, Krishna Kurapati, Manu Gautam,
Kishon Vijay Abraham I
Cc: linux-arm-msm, linux-phy, linux-kernel
In-Reply-To: <20260706-fix-qusb2-v2-0-8d9cd73b1db7@oss.qualcomm.com>
There is a confusion regarding the autoresume bit. Some verions of the
QUSB2 PHY have it in the TEST1 register, while on the others it is a
part of the TEST_CTRL register. When adding support for autoresume bit,
the code attempted to simplify the handling of those registers, putting
both registers to the TEST1 layout entry. In the end,
ipq6018_regs_layout ended up correctly definig TEST1 register at 0x98
(because platforms using that layout didn't use autoresume), while
msm8996_regs_layout used TEST_CTRL offset (0xb8) for the TEST1
layout entry.
Update the platform data to specify the register to be used for
autoresume handling, define both TEST1 and TEST_CTRL registers and merge
ipq6018_regs_layout and msm8996_regs_layout which become identical
afterwards.
Fixes: 891a96f65ac3 ("phy: qcom-qusb2: Add support for runtime PM")
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
---
drivers/phy/qualcomm/phy-qcom-qusb2.c | 48 +++++++++++++++--------------------
1 file changed, 21 insertions(+), 27 deletions(-)
diff --git a/drivers/phy/qualcomm/phy-qcom-qusb2.c b/drivers/phy/qualcomm/phy-qcom-qusb2.c
index b1d34b080cfd..b22b3c6adfd3 100644
--- a/drivers/phy/qualcomm/phy-qcom-qusb2.c
+++ b/drivers/phy/qualcomm/phy-qcom-qusb2.c
@@ -131,8 +131,13 @@ enum qusb2phy_reg_layout {
QUSB2PHY_PORT_TUNE5,
QUSB2PHY_PORT_TEST1,
QUSB2PHY_PORT_TEST2,
+ QUSB2PHY_PORT_TEST_CTRL,
QUSB2PHY_PORT_POWERDOWN,
QUSB2PHY_INTR_CTRL,
+
+ /* layout of the autoresume bit */
+ QUSB2PHY_AUTORESUME_REG,
+ QUSB2PHY_AUTORESUME_BIT,
};
static const struct qusb2_phy_init_tbl ipq6018_init_tbl[] = {
@@ -164,19 +169,6 @@ static const struct qusb2_phy_init_tbl qcs615_init_tbl[] = {
QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_PWR_CTRL, 0x00),
};
-static const unsigned int ipq6018_regs_layout[] = {
- [QUSB2PHY_PLL_STATUS] = 0x38,
- [QUSB2PHY_PORT_TUNE1] = 0x80,
- [QUSB2PHY_PORT_TUNE2] = 0x84,
- [QUSB2PHY_PORT_TUNE3] = 0x88,
- [QUSB2PHY_PORT_TUNE4] = 0x8C,
- [QUSB2PHY_PORT_TUNE5] = 0x90,
- [QUSB2PHY_PORT_TEST1] = 0x98,
- [QUSB2PHY_PORT_TEST2] = 0x9C,
- [QUSB2PHY_PORT_POWERDOWN] = 0xB4,
- [QUSB2PHY_INTR_CTRL] = 0xBC,
-};
-
static const unsigned int msm8996_regs_layout[] = {
[QUSB2PHY_PLL_STATUS] = 0x38,
[QUSB2PHY_PORT_TUNE1] = 0x80,
@@ -184,10 +176,14 @@ static const unsigned int msm8996_regs_layout[] = {
[QUSB2PHY_PORT_TUNE3] = 0x88,
[QUSB2PHY_PORT_TUNE4] = 0x8c,
[QUSB2PHY_PORT_TUNE5] = 0x90,
- [QUSB2PHY_PORT_TEST1] = 0xb8,
+ [QUSB2PHY_PORT_TEST1] = 0x98,
[QUSB2PHY_PORT_TEST2] = 0x9c,
+ [QUSB2PHY_PORT_TEST_CTRL] = 0xb8,
[QUSB2PHY_PORT_POWERDOWN] = 0xb4,
[QUSB2PHY_INTR_CTRL] = 0xbc,
+
+ [QUSB2PHY_AUTORESUME_REG] = 0xb8, /* TEST_CTRL */
+ [QUSB2PHY_AUTORESUME_BIT] = BIT(3),
};
static const struct qusb2_phy_init_tbl msm8996_init_tbl[] = {
@@ -217,6 +213,9 @@ static const unsigned int msm8998_regs_layout[] = {
[QUSB2PHY_PORT_TEST2] = 0x250,
[QUSB2PHY_PORT_POWERDOWN] = 0x210,
[QUSB2PHY_INTR_CTRL] = 0x22c,
+
+ [QUSB2PHY_AUTORESUME_REG] = 0x24c, /* TEST1 */
+ [QUSB2PHY_AUTORESUME_BIT] = BIT(0),
};
static const struct qusb2_phy_init_tbl msm8998_init_tbl[] = {
@@ -259,6 +258,9 @@ static const unsigned int qusb2_v2_regs_layout[] = {
[QUSB2PHY_PORT_TEST2] = 0x258,
[QUSB2PHY_PORT_POWERDOWN] = 0x210,
[QUSB2PHY_INTR_CTRL] = 0x230,
+
+ [QUSB2PHY_AUTORESUME_REG] = 0x254, /* TEST1 */
+ [QUSB2PHY_AUTORESUME_BIT] = BIT(0),
};
static const struct qusb2_phy_init_tbl qusb2_v2_init_tbl[] = {
@@ -293,7 +295,6 @@ struct qusb2_phy_cfg {
const unsigned int *regs;
unsigned int mask_core_ready;
unsigned int disable_ctrl;
- unsigned int autoresume_en;
bool autoresume_disable;
/* true if PHY has PLL_TEST register to select clk_scheme */
@@ -318,7 +319,6 @@ static const struct qusb2_phy_cfg msm8996_phy_cfg = {
.se_clk_scheme_default = true,
.disable_ctrl = (CLAMP_N_EN | FREEZIO_N | POWER_DOWN),
.mask_core_ready = PLL_LOCKED,
- .autoresume_en = BIT(3),
};
static const struct qusb2_phy_cfg msm8998_phy_cfg = {
@@ -330,20 +330,18 @@ static const struct qusb2_phy_cfg msm8998_phy_cfg = {
.mask_core_ready = CORE_READY_STATUS,
.has_pll_override = true,
.se_clk_scheme_default = true,
- .autoresume_en = BIT(0),
.update_tune1_with_efuse = true,
};
static const struct qusb2_phy_cfg ipq6018_phy_cfg = {
.tbl = ipq6018_init_tbl,
.tbl_num = ARRAY_SIZE(ipq6018_init_tbl),
- .regs = ipq6018_regs_layout,
+ .regs = msm8996_regs_layout,
.disable_ctrl = POWER_DOWN,
.mask_core_ready = PLL_LOCKED,
/* autoresume not used */
.autoresume_disable = true,
- .autoresume_en = BIT(0),
};
static const struct qusb2_phy_cfg qcs615_phy_cfg = {
@@ -353,7 +351,6 @@ static const struct qusb2_phy_cfg qcs615_phy_cfg = {
.disable_ctrl = (CLAMP_N_EN | FREEZIO_N | POWER_DOWN),
.mask_core_ready = PLL_LOCKED,
- .autoresume_en = BIT(3),
};
static const struct qusb2_phy_cfg qusb2_v2_phy_cfg = {
@@ -366,7 +363,6 @@ static const struct qusb2_phy_cfg qusb2_v2_phy_cfg = {
.mask_core_ready = CORE_READY_STATUS,
.has_pll_override = true,
.se_clk_scheme_default = true,
- .autoresume_en = BIT(0),
.update_tune1_with_efuse = true,
};
@@ -379,7 +375,6 @@ static const struct qusb2_phy_cfg sdm660_phy_cfg = {
.se_clk_scheme_default = false,
.disable_ctrl = (CLAMP_N_EN | FREEZIO_N | POWER_DOWN),
.mask_core_ready = PLL_LOCKED,
- .autoresume_en = BIT(3),
};
static const struct qusb2_phy_cfg sm6115_phy_cfg = {
@@ -391,7 +386,6 @@ static const struct qusb2_phy_cfg sm6115_phy_cfg = {
.se_clk_scheme_default = true,
.disable_ctrl = (CLAMP_N_EN | FREEZIO_N | POWER_DOWN),
.mask_core_ready = PLL_LOCKED,
- .autoresume_en = BIT(3),
};
static const char * const qusb2_phy_vreg_names[] = {
@@ -679,11 +673,11 @@ static int __maybe_unused qusb2_phy_runtime_suspend(struct device *dev)
/* enable phy auto-resume only if device is connected on bus */
if (qphy->mode != PHY_MODE_INVALID && !cfg->autoresume_disable) {
- qusb2_setbits(qphy->base, cfg->regs[QUSB2PHY_PORT_TEST1],
- cfg->autoresume_en);
+ unsigned int reg = cfg->regs[QUSB2PHY_AUTORESUME_REG];
+
+ qusb2_setbits(qphy->base, reg, cfg->regs[QUSB2PHY_AUTORESUME_BIT]);
/* Autoresume bit has to be toggled in order to enable it */
- qusb2_clrbits(qphy->base, cfg->regs[QUSB2PHY_PORT_TEST1],
- cfg->autoresume_en);
+ qusb2_clrbits(qphy->base, reg, cfg->regs[QUSB2PHY_AUTORESUME_BIT]);
}
if (!qphy->has_se_clk_scheme)
--
2.47.3
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related
* [PATCH v2 2/3] phy: qcom-qusb2: correst PHY description for IPQ6018
From: Dmitry Baryshkov @ 2026-07-06 13:53 UTC (permalink / raw)
To: Vinod Koul, Neil Armstrong, Kathiravan T, Baruch Siach,
Dmitry Baryshkov, Krishna Kurapati, Manu Gautam,
Kishon Vijay Abraham I
Cc: linux-arm-msm, linux-phy, linux-kernel
In-Reply-To: <20260706-fix-qusb2-v2-0-8d9cd73b1db7@oss.qualcomm.com>
Qualcomm IPQ6018 doesn't need to reach power collapse or retention of
the USB voltage rails, so autoresume is not used on that platform.
Instead of programming a fake register bit (BIT(0) of TEST1, while the
QUSB2 platforms on that platform should use BIT(3) of TEST_CTRL),
explicitly disable autoresume programming on these devices via the flag
in the platform data.
Fixes: 2cfbe6765b7a ("phy: qcom-qusb2: add QUSB2 support for IPQ6018")
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
---
drivers/phy/qualcomm/phy-qcom-qusb2.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/phy/qualcomm/phy-qcom-qusb2.c b/drivers/phy/qualcomm/phy-qcom-qusb2.c
index 15c36b594c09..b1d34b080cfd 100644
--- a/drivers/phy/qualcomm/phy-qcom-qusb2.c
+++ b/drivers/phy/qualcomm/phy-qcom-qusb2.c
@@ -294,6 +294,7 @@ struct qusb2_phy_cfg {
unsigned int mask_core_ready;
unsigned int disable_ctrl;
unsigned int autoresume_en;
+ bool autoresume_disable;
/* true if PHY has PLL_TEST register to select clk_scheme */
bool has_pll_test;
@@ -341,6 +342,7 @@ static const struct qusb2_phy_cfg ipq6018_phy_cfg = {
.disable_ctrl = POWER_DOWN,
.mask_core_ready = PLL_LOCKED,
/* autoresume not used */
+ .autoresume_disable = true,
.autoresume_en = BIT(0),
};
@@ -676,7 +678,7 @@ static int __maybe_unused qusb2_phy_runtime_suspend(struct device *dev)
}
/* enable phy auto-resume only if device is connected on bus */
- if (qphy->mode != PHY_MODE_INVALID) {
+ if (qphy->mode != PHY_MODE_INVALID && !cfg->autoresume_disable) {
qusb2_setbits(qphy->base, cfg->regs[QUSB2PHY_PORT_TEST1],
cfg->autoresume_en);
/* Autoresume bit has to be toggled in order to enable it */
--
2.47.3
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related
* [PATCH v2 1/3] phy: qcom-qusb2: enable autoresume on Talos platforms
From: Dmitry Baryshkov @ 2026-07-06 13:53 UTC (permalink / raw)
To: Vinod Koul, Neil Armstrong, Kathiravan T, Baruch Siach,
Dmitry Baryshkov, Krishna Kurapati, Manu Gautam,
Kishon Vijay Abraham I
Cc: linux-arm-msm, linux-phy, linux-kernel, stable
In-Reply-To: <20260706-fix-qusb2-v2-0-8d9cd73b1db7@oss.qualcomm.com>
According to Krishna, having autoresume disabled on Talos is a c&p
error and it should be enabled.
Suggested-by: Krishna Kurapati <krishna.kurapati@oss.qualcomm.com>
Fixes: 8adbf20e0502 ("phy: qcom-qusb2: Add support for QCS615")
Cc: stable@vger.kernel.org
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
---
drivers/phy/qualcomm/phy-qcom-qusb2.c | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/drivers/phy/qualcomm/phy-qcom-qusb2.c b/drivers/phy/qualcomm/phy-qcom-qusb2.c
index eb93015be841..15c36b594c09 100644
--- a/drivers/phy/qualcomm/phy-qcom-qusb2.c
+++ b/drivers/phy/qualcomm/phy-qcom-qusb2.c
@@ -347,12 +347,11 @@ static const struct qusb2_phy_cfg ipq6018_phy_cfg = {
static const struct qusb2_phy_cfg qcs615_phy_cfg = {
.tbl = qcs615_init_tbl,
.tbl_num = ARRAY_SIZE(qcs615_init_tbl),
- .regs = ipq6018_regs_layout,
+ .regs = msm8996_regs_layout,
.disable_ctrl = (CLAMP_N_EN | FREEZIO_N | POWER_DOWN),
.mask_core_ready = PLL_LOCKED,
- /* autoresume not used */
- .autoresume_en = BIT(0),
+ .autoresume_en = BIT(3),
};
static const struct qusb2_phy_cfg qusb2_v2_phy_cfg = {
--
2.47.3
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related
* [PATCH v2 0/3] phy: qcom-qusb2: sort out register layouts
From: Dmitry Baryshkov @ 2026-07-06 13:53 UTC (permalink / raw)
To: Vinod Koul, Neil Armstrong, Kathiravan T, Baruch Siach,
Dmitry Baryshkov, Krishna Kurapati, Manu Gautam,
Kishon Vijay Abraham I
Cc: linux-arm-msm, linux-phy, linux-kernel, stable
IPQ6018 and MSM8996 use the same register layout, however for historical
reasons ipq6018_regs_layout ended up correctly definig TEST1 register at
0x98 (because platforms using that layout didn't use autoresume), while
msm8996_regs_layout used TEST_CTRL offset (0xb8) for the TEST1 layout
entry. Fix handling of the autoresume register and definitions of those
regs layouts.
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
---
Changes in v2:
- Reworked the series to enable autoresume on Talos
- Moved autoresume description to the regs layout, it is a property of
the regs rather than a platform.
- Link to v1: https://patch.msgid.link/20260702-fix-qusb2-v1-0-b5cf55621524@oss.qualcomm.com
To: Vinod Koul <vkoul@kernel.org>
To: Neil Armstrong <neil.armstrong@linaro.org>
To: Krishna Kurapati <krishna.kurapati@oss.qualcomm.com>
To: Dmitry Baryshkov <lumag@kernel.org>
To: Kathiravan T <quic_kathirav@quicinc.com>
To: Baruch Siach <baruch@tkos.co.il>
To: Manu Gautam <mgautam@codeaurora.org>
To: Kishon Vijay Abraham I <kishon@kernel.org>
Cc: linux-arm-msm@vger.kernel.org
Cc: linux-phy@lists.infradead.org
Cc: linux-kernel@vger.kernel.org
---
Dmitry Baryshkov (3):
phy: qcom-qusb2: enable autoresume on Talos platforms
phy: qcom-qusb2: correst PHY description for IPQ6018
phy: qcom-qusb2: describe autoresume bit
drivers/phy/qualcomm/phy-qcom-qusb2.c | 55 ++++++++++++++++-------------------
1 file changed, 25 insertions(+), 30 deletions(-)
---
base-commit: dc59e4fea9d83f03bad6bddf3fa2e52491777482
change-id: 20260702-fix-qusb2-3600a65bfcae
Best regards,
--
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 02/13] m68k/coldfire: replace linux/gpio.h inclusions
From: Greg Ungerer @ 2026-07-06 11:22 UTC (permalink / raw)
To: Arnd Bergmann, linux-gpio
Cc: Arnd Bergmann, Bartosz Golaszewski, Andrew Lunn,
Sebastian Hesselbarth, Gregory Clement, Frank Li, Robert Jarzmik,
Krzysztof Kozlowski, Thomas Bogendoerfer, Hauke Mehrtens,
Rafał Miłecki, Yoshinori Sato,
John Paul Adrian Glaubitz, Linus Walleij, Dmitry Torokhov,
Jakub Kicinski, Paolo Abeni, Dominik Brodowski, linux-kernel,
linux-arm-kernel, linux-samsung-soc, patches, linux-m68k,
linux-mips, linux-sh, linux-input, linux-media, netdev,
linux-sunxi, linux-phy, linux-rockchip, linux-sound
In-Reply-To: <20260629132633.1300009-3-arnd@kernel.org>
Hi Arnd,
On 29/6/26 23:26, Arnd Bergmann wrote:
> From: Arnd Bergmann <arnd@arndb.de>
>
> linux/gpio.h should no longer be used, convert these instead to
> linux/gpio/legacy.h for coldfire.
>
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
For the ColdFire changes, LGTM:
Reviewed-by: Greg Ungerer <gerg@linux-m68k.com>
Regards
Greg
> ---
> arch/m68k/coldfire/device.c | 2 +-
> arch/m68k/include/asm/mcfgpio.h | 2 +-
> 2 files changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/arch/m68k/coldfire/device.c b/arch/m68k/coldfire/device.c
> index 1420bae0964f..9a0258acd998 100644
> --- a/arch/m68k/coldfire/device.c
> +++ b/arch/m68k/coldfire/device.c
> @@ -12,7 +12,7 @@
> #include <linux/init.h>
> #include <linux/io.h>
> #include <linux/spi/spi.h>
> -#include <linux/gpio.h>
> +#include <linux/gpio/legacy.h>
> #include <linux/fec.h>
> #include <linux/dmaengine.h>
> #include <asm/traps.h>
> diff --git a/arch/m68k/include/asm/mcfgpio.h b/arch/m68k/include/asm/mcfgpio.h
> index 7103cfa4edb6..29726aa40eb6 100644
> --- a/arch/m68k/include/asm/mcfgpio.h
> +++ b/arch/m68k/include/asm/mcfgpio.h
> @@ -16,7 +16,7 @@ int __mcfgpio_request(unsigned gpio);
> void __mcfgpio_free(unsigned gpio);
>
> #ifdef CONFIG_GPIOLIB
> -#include <linux/gpio.h>
> +#include <linux/gpio/legacy.h>
> #else
>
> /* our alternate 'gpiolib' functions */
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* Re: [PATCH] phy: allwinner: sun4i-usb: disable the PHY2 PMU clock after SIDDQ setup
From: Andre Przywara @ 2026-07-06 10:13 UTC (permalink / raw)
To: raoxu, vkoul
Cc: wens, jernej.skrabec, samuel, neil.armstrong, marco.crivellari,
linux-phy, linux-arm-kernel, linux-sunxi, linux-kernel
In-Reply-To: <1368E4E3485E881C+20260706093549.867442-1-raoxu@uniontech.com>
Hi,
On 7/6/26 11:35, raoxu wrote:
> From: Xu Rao <raoxu@uniontech.com>
>
> sun4i_usb_phy_init() temporarily enables PHY2's clk2 when a SoC needs
> PHY2 SIDDQ setup while initializing another PHY. However, after updating
> PHY2's PMU register it disables the clk2 pointer from the PHY currently
> being initialized.
>
> This leaves PHY2's clk2 enabled and also drops an extra reference from
> the current PHY's clk2, causing the prepare/enable accounting to become
> unbalanced.
>
> Disable the same PHY2 clk2 that was enabled for the auxiliary PMU access.
>
> Signed-off-by: Xu Rao <raoxu@uniontech.com>
> ---
> drivers/phy/allwinner/phy-sun4i-usb.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/phy/allwinner/phy-sun4i-usb.c b/drivers/phy/allwinner/phy-sun4i-usb.c
> index e2fbf8ccf99e..839856c09e30 100644
> --- a/drivers/phy/allwinner/phy-sun4i-usb.c
> +++ b/drivers/phy/allwinner/phy-sun4i-usb.c
> @@ -318,7 +318,7 @@ static int sun4i_usb_phy_init(struct phy *_phy)
> writel(val, phy2->pmu + REG_HCI_PHY_CTL);
> }
>
> - clk_disable_unprepare(phy->clk2);
> + clk_disable_unprepare(phy2->clk2);
Interesting, this looks about right, and matches the comment above,
noting that phy2->clk2 is just temporarily needed. I don't remember
further details, only that this workaround was quite annoying and messy ;-)
However I am wondering how this worked so far: This should sabotage the
access to the local REG_HCI_PHY_CTL access in the next few lines ...
Any idea why this worked nevertheless?
Thanks,
Andre
> }
>
> if (phy->pmu && data->cfg->hci_phy_ctl_clear) {
> --
> 2.50.1
>
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* Re: [PATCH] phy: allwinner: sun4i-usb: disable the PHY2 PMU clock after SIDDQ setup
From: sashiko-bot @ 2026-07-06 9:51 UTC (permalink / raw)
To: raoxu; +Cc: olteanv, linux-sunxi, vkoul, linux-phy, neil.armstrong
In-Reply-To: <1368E4E3485E881C+20260706093549.867442-1-raoxu@uniontech.com>
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
Pre-existing issues:
- [High] Concurrent usage of PHY2 results in hardware malfunction because `phy2->reset` is requested as an exclusive reset control.
- [High] The clock and reset teardown order for `phy2` in `sun4i_usb_phy_exit()` is inverted and asymmetric with its initialization.
--
commit 9c33e00d3375b4a5cb06dbdb11bc874c8960fcff
Author: Xu Rao <raoxu@uniontech.com>
phy: allwinner: sun4i-usb: disable the PHY2 PMU clock after SIDDQ setup
This commit fixes a clock accounting imbalance by ensuring the same PHY2
clk2 that was enabled for auxiliary PMU access is correctly disabled,
rather than disabling the current PHY's clk2.
> diff --git a/drivers/phy/allwinner/phy-sun4i-usb.c b/drivers/phy/allwinner/phy-sun4i-usb.c
> index e2fbf8ccf99e1..839856c09e305 100644
> --- a/drivers/phy/allwinner/phy-sun4i-usb.c
> +++ b/drivers/phy/allwinner/phy-sun4i-usb.c
> @@ -318,7 +318,7 @@ static int sun4i_usb_phy_init(struct phy *_phy)
> writel(val, phy2->pmu + REG_HCI_PHY_CTL);
> }
>
> - clk_disable_unprepare(phy->clk2);
> + clk_disable_unprepare(phy2->clk2);
> }
[Severity: High]
This is a pre-existing issue, but since this patch deals with PHY2 resource
accounting, does the reset control for PHY2 also have a concurrent usage
issue?
In sun4i_usb_phy_probe(), the reset control is fetched exclusively:
sun4i_usb_phy_probe()
...
phy->reset = devm_reset_control_get(dev, name);
Because it is an exclusive reset control, it does not maintain a reference
count for assertions. When multiple PHYs (like PHY0 and PHY1) independently
use PHY2, won't one PHY exiting unconditionally assert phy2->reset and
instantly break the other active PHYs?
sun4i_usb_phy_exit()
...
reset_control_assert(phy2->reset);
[Severity: High]
This is also a pre-existing issue, but the clock and reset teardown order
for phy2 appears inverted in sun4i_usb_phy_exit() compared to how it is
safely initialized here in sun4i_usb_phy_init().
In sun4i_usb_phy_init(), phy2->clk is enabled before phy2->reset is
deasserted. However, in sun4i_usb_phy_exit(), the clock is disabled before
the reset is asserted:
sun4i_usb_phy_exit()
...
clk_disable_unprepare(phy2->clk);
reset_control_assert(phy2->reset);
Could asserting the reset on an unclocked hardware block leave the PHY2
block in an undefined or stuck state?
>
> if (phy->pmu && data->cfg->hci_phy_ctl_clear) {
--
Sashiko AI review · https://sashiko.dev/#/patchset/1368E4E3485E881C+20260706093549.867442-1-raoxu@uniontech.com?part=1
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
* [PATCH] phy: allwinner: sun4i-usb: disable the PHY2 PMU clock after SIDDQ setup
From: raoxu @ 2026-07-06 9:35 UTC (permalink / raw)
To: vkoul
Cc: wens, jernej.skrabec, samuel, neil.armstrong, andre.przywara,
raoxu, marco.crivellari, linux-phy, linux-arm-kernel, linux-sunxi,
linux-kernel
From: Xu Rao <raoxu@uniontech.com>
sun4i_usb_phy_init() temporarily enables PHY2's clk2 when a SoC needs
PHY2 SIDDQ setup while initializing another PHY. However, after updating
PHY2's PMU register it disables the clk2 pointer from the PHY currently
being initialized.
This leaves PHY2's clk2 enabled and also drops an extra reference from
the current PHY's clk2, causing the prepare/enable accounting to become
unbalanced.
Disable the same PHY2 clk2 that was enabled for the auxiliary PMU access.
Signed-off-by: Xu Rao <raoxu@uniontech.com>
---
drivers/phy/allwinner/phy-sun4i-usb.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/phy/allwinner/phy-sun4i-usb.c b/drivers/phy/allwinner/phy-sun4i-usb.c
index e2fbf8ccf99e..839856c09e30 100644
--- a/drivers/phy/allwinner/phy-sun4i-usb.c
+++ b/drivers/phy/allwinner/phy-sun4i-usb.c
@@ -318,7 +318,7 @@ static int sun4i_usb_phy_init(struct phy *_phy)
writel(val, phy2->pmu + REG_HCI_PHY_CTL);
}
- clk_disable_unprepare(phy->clk2);
+ clk_disable_unprepare(phy2->clk2);
}
if (phy->pmu && data->cfg->hci_phy_ctl_clear) {
--
2.50.1
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related
* Re: [PATCH 07/13] ASoC: replace linux/gpio.h inclusions
From: Charles Keepax @ 2026-07-06 9:01 UTC (permalink / raw)
To: Arnd Bergmann
Cc: linux-gpio, Arnd Bergmann, Bartosz Golaszewski, Andrew Lunn,
Sebastian Hesselbarth, Gregory Clement, Frank Li, Robert Jarzmik,
Krzysztof Kozlowski, Greg Ungerer, Thomas Bogendoerfer,
Hauke Mehrtens, Rafał Miłecki, Yoshinori Sato,
John Paul Adrian Glaubitz, Linus Walleij, Dmitry Torokhov,
Jakub Kicinski, Paolo Abeni, Dominik Brodowski, linux-kernel,
linux-arm-kernel, linux-samsung-soc, patches, linux-m68k,
linux-mips, linux-sh, linux-input, linux-media, netdev,
linux-sunxi, linux-phy, linux-rockchip, linux-sound
In-Reply-To: <20260629132633.1300009-8-arnd@kernel.org>
On Mon, Jun 29, 2026 at 03:26:27PM +0200, Arnd Bergmann wrote:
> From: Arnd Bergmann <arnd@arndb.de>
>
> linux/gpio.h is going away,s o use linux/gpio/consumer.h instead.
>
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
> ---
> sound/soc/codecs/cs42l84.c | 2 +-
> sound/soc/codecs/cx2072x.c | 2 +-
For the Cirrus bits:
Reviewed-by: Charles Keepax <ckeepax@opensource.cirrus.com>
Thanks,
Charles
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply
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