From fda7bee6468ee5a701e268162aaa7645d98b85f0 Mon Sep 17 00:00:00 2001 From: Andrew Goodbody Date: Wed, 6 Aug 2025 17:55:04 +0100 Subject: phy: qcom: Fix ret is uninitialised In qcom_snps_eusb2_phy_probe after the call to devm_clk_get if an error is found then ret is printed but has not been assigned to by the code. Decode the error from the pointer and assign it to ret. This issue was found by Smatch. Signed-off-by: Andrew Goodbody Reviewed-by: Sumit Garg Link: https://lore.kernel.org/r/20250806-phy_qcom_snps-v1-1-5cda830026c7@linaro.org Signed-off-by: Casey Connolly --- drivers/phy/qcom/phy-qcom-snps-eusb2.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/phy') diff --git a/drivers/phy/qcom/phy-qcom-snps-eusb2.c b/drivers/phy/qcom/phy-qcom-snps-eusb2.c index b2655ac007c..28502c46f67 100644 --- a/drivers/phy/qcom/phy-qcom-snps-eusb2.c +++ b/drivers/phy/qcom/phy-qcom-snps-eusb2.c @@ -331,8 +331,9 @@ static int qcom_snps_eusb2_phy_probe(struct udevice *dev) qcom_snps_eusb2->ref_clk = devm_clk_get(dev, "ref"); if (IS_ERR(qcom_snps_eusb2->ref_clk)) { + ret = PTR_ERR(qcom_snps_eusb2->ref_clk); printf("%s: failed to get ref clk %d\n", __func__, ret); - return PTR_ERR(qcom_snps_eusb2->ref_clk); + return ret; } ret = reset_get_bulk(dev, &qcom_snps_eusb2->resets); -- cgit v1.2.3 From a75c8a4b883108edf19127fca3e6c6c590f9ba8c Mon Sep 17 00:00:00 2001 From: Andrew Goodbody Date: Wed, 6 Aug 2025 17:43:24 +0100 Subject: phy: marvell: Fix off by 1 limit checks The limit checks in get_speed_string and get_type_string are off by 1 as they do not account for the maximum index into an array that can be used is 1 less than the number of elements in that array. Adjust the limit checks to allow for this. This issue was found by Smatch. Signed-off-by: Andrew Goodbody Reviewed-by: Stefan Roese --- drivers/phy/marvell/comphy_core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/phy') diff --git a/drivers/phy/marvell/comphy_core.c b/drivers/phy/marvell/comphy_core.c index a666a4e794e..a4121423873 100644 --- a/drivers/phy/marvell/comphy_core.c +++ b/drivers/phy/marvell/comphy_core.c @@ -28,7 +28,7 @@ static const char *get_speed_string(u32 speed) "10.3125 Gbps" }; - if (speed < 0 || speed > COMPHY_SPEED_MAX) + if (speed < 0 || speed >= COMPHY_SPEED_MAX) return "invalid"; return speed_strings[speed]; @@ -44,7 +44,7 @@ static const char *get_type_string(u32 type) "IGNORE" }; - if (type < 0 || type > COMPHY_TYPE_MAX) + if (type < 0 || type >= COMPHY_TYPE_MAX) return "invalid"; return type_strings[type]; -- cgit v1.2.3 From 2e9155cb9f366a6b9191af0850efad1948b4c785 Mon Sep 17 00:00:00 2001 From: Andrew Goodbody Date: Wed, 6 Aug 2025 17:43:25 +0100 Subject: phy: marvell: Cannot test unsigned field to be negative In comphy_cp110_init_serdes_map in comphy_cp110.c there are two fields in cfg, comphy_lanes_count and comphy_mux_bitcount, which are fetched from the FDT blob with fdtdec_get_int which returns an int. These two fields are then tested for being negative. However the fields are declared as unsigned so those tests must always fail. Change the declaration of those fields to be int instead of u32 and the code will work as expected. This issue was found by Smatch. Signed-off-by: Andrew Goodbody Reviewed-by: Stefan Roese --- drivers/phy/marvell/comphy_core.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/phy') diff --git a/drivers/phy/marvell/comphy_core.h b/drivers/phy/marvell/comphy_core.h index f3d04939387..086a4d82f26 100644 --- a/drivers/phy/marvell/comphy_core.h +++ b/drivers/phy/marvell/comphy_core.h @@ -47,8 +47,8 @@ struct chip_serdes_phy_config { int (*rx_training)(struct chip_serdes_phy_config *, u32); void __iomem *comphy_base_addr; void __iomem *hpipe3_base_addr; - u32 comphy_lanes_count; - u32 comphy_mux_bitcount; + int comphy_lanes_count; + int comphy_mux_bitcount; const fdt32_t *comphy_mux_lane_order; u32 cp_index; struct comphy_map comphy_map_data[MAX_LANE_OPTIONS]; -- cgit v1.2.3 From 783ea37c7b52ae088e8c64581fbe412b5dc9a878 Mon Sep 17 00:00:00 2001 From: Andrew Goodbody Date: Mon, 18 Aug 2025 11:44:28 +0100 Subject: phy: cadence: sierra: Remove variable that is not assigned to In cdns_sierra_pll_bind_of_clocks the variable 'i' is declared but never assigned to before its value is used in a dev_err. Replace clk_names[i] by the name passed to device_bind(), i.e., "pll_mux_clk". With that, the clk_names[] array is unused and can therefore be removed. This issue was found by Smatch. Signed-off-by: Andrew Goodbody [jf: update description] Signed-off-by: Jerome Forissier --- drivers/phy/cadence/phy-cadence-sierra.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) (limited to 'drivers/phy') diff --git a/drivers/phy/cadence/phy-cadence-sierra.c b/drivers/phy/cadence/phy-cadence-sierra.c index 2c9d5a12127..bd7ab9d1b77 100644 --- a/drivers/phy/cadence/phy-cadence-sierra.c +++ b/drivers/phy/cadence/phy-cadence-sierra.c @@ -225,11 +225,6 @@ static const struct reg_field pllctrl_lock = static const struct reg_field phy_iso_link_ctrl_1 = REG_FIELD(SIERRA_PHY_ISO_LINK_CTRL, 1, 1); -static const char * const clk_names[] = { - [CDNS_SIERRA_PLL_CMNLC] = "pll_cmnlc", - [CDNS_SIERRA_PLL_CMNLC1] = "pll_cmnlc1", -}; - enum cdns_sierra_cmn_plllc { CMN_PLLLC, CMN_PLLLC1, @@ -602,7 +597,7 @@ static int cdns_sierra_pll_bind_of_clocks(struct cdns_sierra_phy *sp) struct udevice *dev = sp->dev; struct driver *cdns_sierra_clk_drv; struct cdns_sierra_pll_mux_sel *data = pll_clk_mux_sel; - int i, rc; + int rc; cdns_sierra_clk_drv = lists_driver_lookup_name("cdns_sierra_mux_clk"); if (!cdns_sierra_clk_drv) { @@ -612,10 +607,8 @@ static int cdns_sierra_pll_bind_of_clocks(struct cdns_sierra_phy *sp) rc = device_bind(dev, cdns_sierra_clk_drv, "pll_mux_clk", data, dev_ofnode(dev), NULL); - if (rc) { - dev_err(dev, "cannot bind driver for clock %s\n", - clk_names[i]); - } + if (rc) + dev_err(dev, "cannot bind driver for clock pll_mux_clk\n"); return 0; } -- cgit v1.2.3 From c4526c390a3c4ea1c4f244b6436ebbb74902769a Mon Sep 17 00:00:00 2001 From: Andrew Goodbody Date: Mon, 18 Aug 2025 11:44:29 +0100 Subject: phy: cadence: torrent: Set an error code for return In cdns_torrent_phy_probe the test for too many lanes configured does not set an error code before taking the error path. This could lead to a silent failure if the calling code does not detect the error. Add the code to return -EINVAL in this case. This issue was found by Smatch. Signed-off-by: Andrew Goodbody --- drivers/phy/cadence/phy-cadence-torrent.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/phy') diff --git a/drivers/phy/cadence/phy-cadence-torrent.c b/drivers/phy/cadence/phy-cadence-torrent.c index 1f566d082f9..28fe026223c 100644 --- a/drivers/phy/cadence/phy-cadence-torrent.c +++ b/drivers/phy/cadence/phy-cadence-torrent.c @@ -719,6 +719,7 @@ static int cdns_torrent_phy_probe(struct udevice *dev) if (total_num_lanes > MAX_NUM_LANES) { dev_err(dev, "Invalid lane configuration\n"); + ret = -EINVAL; goto put_lnk_rst; } -- cgit v1.2.3 From edbcf8e3590fb640b4709841605b0a58ef8aa7f1 Mon Sep 17 00:00:00 2001 From: Tim Harvey Date: Wed, 9 Jul 2025 08:24:08 -0700 Subject: phy: phy-imx8mq-usb: Add support for i.MX95 USB3 PHY Add initial support for i.MX95 USB.30 PHY, which is similar to the i.MX8MQ and i.MX8MP USB PHY. The i.MX95 USB3 PHY has a Type-C Assist block (TCA) consisting of two functional blocks (XBar assist and VBus assist) and is documented in the i.MX95 RM Chapter 163.3.8 Type-C assist (TCA) block. Instead of relying on an external MUX for Type-C plug orientation the XBar can handle the flip internally. Add initial support for i.MX95 by: - allowing the driver to be enabled i.MX95 - resetting the XBar - configuring the TCA in System Configuration mode (which was determined to be necessary to enable the PHY in device-mode) Follow-on support will need to be added to steer the XBar based on either board design (if only one pair is brought out) or if used with a Type-C controller. Signed-off-by: Tim Harvey Tested-by: Alice Guo --- drivers/phy/Kconfig | 6 +-- drivers/phy/phy-imx8mq-usb.c | 91 +++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 93 insertions(+), 4 deletions(-) (limited to 'drivers/phy') diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index c297fa03ea7..d36a5f00ef8 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -289,11 +289,11 @@ config PHY_NPCM_USB Support the USB PHY in NPCM SoCs config PHY_IMX8MQ_USB - bool "NXP i.MX8MQ/i.MX8MP USB PHY Driver" + bool "NXP i.MX8MQ/i.MX8MP/i.MX95 USB PHY Driver" depends on PHY - depends on IMX8MQ || IMX8MP + depends on IMX8MQ || IMX8MP || IMX95 help - Support the USB3.0 PHY in NXP i.MX8MQ or i.MX8MP SoC + Support the USB3.0 PHY in NXP i.MX8MQ, i.MX8MP, and i.MX95 SoC config PHY_IMX8M_PCIE bool "NXP i.MX8MM/i.MX8MP PCIe PHY Driver" diff --git a/drivers/phy/phy-imx8mq-usb.c b/drivers/phy/phy-imx8mq-usb.c index 75763046adc..387db843c50 100644 --- a/drivers/phy/phy-imx8mq-usb.c +++ b/drivers/phy/phy-imx8mq-usb.c @@ -71,9 +71,57 @@ #define PHY_STS0_FSVPLUS BIT(3) #define PHY_STS0_FSVMINUS BIT(2) +#define TCA_CLK_RST 0x00 +#define TCA_CLK_RST_SW BIT(9) +#define TCA_CLK_RST_REF_CLK_EN BIT(1) +#define TCA_CLK_RST_SUSPEND_CLK_EN BIT(0) + +#define TCA_INTR_EN 0x04 +#define TCA_INTR_STS 0x08 + +#define TCA_GCFG 0x10 +#define TCA_GCFG_ROLE_HSTDEV BIT(4) +#define TCA_GCFG_OP_MODE GENMASK(1, 0) +#define TCA_GCFG_OP_MODE_SYSMODE 0 +#define TCA_GCFG_OP_MODE_SYNCMODE 1 + +#define TCA_TCPC 0x14 +#define TCA_TCPC_VALID BIT(4) +#define TCA_TCPC_LOW_POWER_EN BIT(3) +#define TCA_TCPC_ORIENTATION_NORMAL BIT(2) +#define TCA_TCPC_MUX_CONTRL GENMASK(1, 0) +#define TCA_TCPC_MUX_CONTRL_NO_CONN 0 +#define TCA_TCPC_MUX_CONTRL_USB_CONN 1 + +#define TCA_SYSMODE_CFG 0x18 +#define TCA_SYSMODE_TCPC_DISABLE BIT(3) +#define TCA_SYSMODE_TCPC_FLIP BIT(2) + +#define TCA_CTRLSYNCMODE_CFG0 0x20 +#define TCA_CTRLSYNCMODE_CFG1 0x20 + +#define TCA_PSTATE 0x30 +#define TCA_PSTATE_CM_STS BIT(4) +#define TCA_PSTATE_TX_STS BIT(3) +#define TCA_PSTATE_RX_PLL_STS BIT(2) +#define TCA_PSTATE_PIPE0_POWER_DOWN GENMASK(1, 0) + +#define TCA_GEN_STATUS 0x34 +#define TCA_GEN_DEV_POR BIT(12) +#define TCA_GEN_REF_CLK_SEL BIT(8) +#define TCA_GEN_TYPEC_FLIP_INVERT BIT(4) +#define TCA_GEN_PHY_TYPEC_DISABLE BIT(3) +#define TCA_GEN_PHY_TYPEC_FLIP BIT(2) + +#define TCA_VBUS_CTRL 0x40 +#define TCA_VBUS_STATUS 0x44 + +#define TCA_INFO 0xfc + enum imx8mpq_phy_type { IMX8MQ_PHY, IMX8MP_PHY, + IMX95_PHY, }; struct imx8mq_usb_phy { @@ -81,14 +129,49 @@ struct imx8mq_usb_phy { void __iomem *base; enum imx8mpq_phy_type type; struct udevice *vbus_supply; + void __iomem *tca_base; }; static const struct udevice_id imx8mq_usb_phy_of_match[] = { { .compatible = "fsl,imx8mq-usb-phy", .data = IMX8MQ_PHY }, { .compatible = "fsl,imx8mp-usb-phy", .data = IMX8MP_PHY }, + { .compatible = "fsl,imx95-usb-phy", .data = IMX95_PHY }, {}, }; +static void tca_blk_init(struct phy *usb_phy) +{ + struct udevice *dev = usb_phy->dev; + struct imx8mq_usb_phy *imx_phy = dev_get_priv(dev); + void __iomem *base = imx_phy->tca_base; + u32 val; + + /* reset XBar block */ + val = readl(base + TCA_CLK_RST); + val &= ~TCA_CLK_RST_SW; + writel(val, base + TCA_CLK_RST); + + udelay(100); + + /* clear reset */ + val |= TCA_CLK_RST_SW; + writel(val, base + TCA_CLK_RST); + + /* + * use Controller Synced Mode for TCA low power enable and + * put PHY to USB safe state. + */ + val = FIELD_PREP(TCA_GCFG_OP_MODE, TCA_GCFG_OP_MODE_SYNCMODE); + writel(val, base + TCA_GCFG); + + val = TCA_TCPC_VALID | TCA_TCPC_LOW_POWER_EN; + writel(val, base + TCA_TCPC); + + /* use System Configuration Mode for TCA mux control. */ + val = FIELD_PREP(TCA_GCFG_OP_MODE, TCA_GCFG_OP_MODE_SYSMODE); + writel(val, base + TCA_GCFG); +} + static int imx8mq_usb_phy_init(struct phy *usb_phy) { struct udevice *dev = usb_phy->dev; @@ -154,6 +237,9 @@ static int imx8mp_usb_phy_init(struct phy *usb_phy) value &= ~(PHY_CTRL1_RESET | PHY_CTRL1_ATERESET); writel(value, imx_phy->base + PHY_CTRL1); + if (imx_phy->tca_base) + tca_blk_init(usb_phy); + return 0; } @@ -162,7 +248,7 @@ static int imx8mpq_usb_phy_init(struct phy *usb_phy) struct udevice *dev = usb_phy->dev; struct imx8mq_usb_phy *imx_phy = dev_get_priv(dev); - if (imx_phy->type == IMX8MP_PHY) + if (imx_phy->type == IMX8MP_PHY || imx_phy->type == IMX95_PHY) return imx8mp_usb_phy_init(usb_phy); else return imx8mq_usb_phy_init(usb_phy); @@ -264,6 +350,9 @@ int imx8mq_usb_phy_probe(struct udevice *dev) } } + if (priv->type == IMX95_PHY) + priv->tca_base = dev_read_addr_index_ptr(dev, 1); + return 0; } -- cgit v1.2.3