diff mbox series

[5/7] phy: spacemit: add USB3 support for K1 PCIe/USB3 combo PHY

Message ID 20250407-b4-k1-usb3-v3-2-v1-5-bf0bcc41c9ba@whut.edu.cn (mailing list archive)
State New
Headers show
Series Add USB3.0 PHY and host controller support for SpacemiT K1 SoC | expand

Commit Message

Ze Huang April 7, 2025, 12:38 p.m. UTC
Add support for USB 3.0 mode on the K1 PCIe/USB3 combo PHY. Currently,
only USB mode is supported; PCIe support is not included in this change.

Signed-off-by: Ze Huang <huangze@whut.edu.cn>
---
 drivers/phy/spacemit/Kconfig          |   8 ++
 drivers/phy/spacemit/Makefile         |   1 +
 drivers/phy/spacemit/phy-k1-combphy.c | 229 ++++++++++++++++++++++++++++++++++
 3 files changed, 238 insertions(+)

Comments

Krzysztof Kozlowski April 7, 2025, 1:28 p.m. UTC | #1
On 07/04/2025 14:38, Ze Huang wrote:
> Add support for USB 3.0 mode on the K1 PCIe/USB3 combo PHY. Currently,
> only USB mode is supported; PCIe support is not included in this change.
> 
> Signed-off-by: Ze Huang <huangze@whut.edu.cn>
> ---
>  drivers/phy/spacemit/Kconfig          |   8 ++
>  drivers/phy/spacemit/Makefile         |   1 +
>  drivers/phy/spacemit/phy-k1-combphy.c | 229 ++++++++++++++++++++++++++++++++++
>  3 files changed, 238 insertions(+)
> 
> diff --git a/drivers/phy/spacemit/Kconfig b/drivers/phy/spacemit/Kconfig
> index f0c2a33f53cc810e71c6140ae957aa68a2b6ff0c..12749aba756329cf64fb9199055ba484fe05f3ab 100644
> --- a/drivers/phy/spacemit/Kconfig
> +++ b/drivers/phy/spacemit/Kconfig
> @@ -10,3 +10,11 @@ config PHY_SPACEMIT_K1_USB2
>  	help
>  	  Enable this to support K1 USB 2.0 PHY driver. This driver takes care of
>  	  enabling and clock setup and will be used by K1 udc/ehci/otg driver.
> +
> +config PHY_SPACEMIT_K1_COMBPHY
> +	tristate "SpacemiT K1 PCIe/USB3 combo PHY support"
> +	depends on OF
> +	select GENERIC_PHY
> +	default ARCH_SPACEMIT && USB_DWC3_SPACEMIT
> +	help
> +	  USB3/PCIe Combo PHY Support for SpacemiT K1 SoC

Missing depends on ARCH_SPACEMIT || COMPILE_TEST

...


> +	priv->phy = devm_phy_create(dev, NULL, &spacemit_combphy_ops);
> +	if (IS_ERR(priv->phy))
> +		return dev_err_probe(dev, PTR_ERR(priv->phy),
> +				     "failed to create combphy\n");
> +
> +	dev_set_drvdata(dev, priv);
> +	phy_set_drvdata(priv->phy, priv);
Both make no sense. Look what this function does.

Best regards,
Krzysztof
Ze Huang April 9, 2025, 9:43 a.m. UTC | #2
On 4/7/25 9:28 PM, Krzysztof Kozlowski wrote:
> On 07/04/2025 14:38, Ze Huang wrote:
>> Add support for USB 3.0 mode on the K1 PCIe/USB3 combo PHY. Currently,
>> only USB mode is supported; PCIe support is not included in this change.
>>
>> Signed-off-by: Ze Huang <huangze@whut.edu.cn>
>> ---
>>   drivers/phy/spacemit/Kconfig          |   8 ++
>>   drivers/phy/spacemit/Makefile         |   1 +
>>   drivers/phy/spacemit/phy-k1-combphy.c | 229 ++++++++++++++++++++++++++++++++++
>>   3 files changed, 238 insertions(+)
>>
>> diff --git a/drivers/phy/spacemit/Kconfig b/drivers/phy/spacemit/Kconfig
>> index f0c2a33f53cc810e71c6140ae957aa68a2b6ff0c..12749aba756329cf64fb9199055ba484fe05f3ab 100644
>> --- a/drivers/phy/spacemit/Kconfig
>> +++ b/drivers/phy/spacemit/Kconfig
>> @@ -10,3 +10,11 @@ config PHY_SPACEMIT_K1_USB2
>>   	help
>>   	  Enable this to support K1 USB 2.0 PHY driver. This driver takes care of
>>   	  enabling and clock setup and will be used by K1 udc/ehci/otg driver.
>> +
>> +config PHY_SPACEMIT_K1_COMBPHY
>> +	tristate "SpacemiT K1 PCIe/USB3 combo PHY support"
>> +	depends on OF
>> +	select GENERIC_PHY
>> +	default ARCH_SPACEMIT && USB_DWC3_SPACEMIT
>> +	help
>> +	  USB3/PCIe Combo PHY Support for SpacemiT K1 SoC
> Missing depends on ARCH_SPACEMIT || COMPILE_TEST

Will fix, thanks!

>
> ...
>
>
>> +	priv->phy = devm_phy_create(dev, NULL, &spacemit_combphy_ops);
>> +	if (IS_ERR(priv->phy))
>> +		return dev_err_probe(dev, PTR_ERR(priv->phy),
>> +				     "failed to create combphy\n");
>> +
>> +	dev_set_drvdata(dev, priv);
>> +	phy_set_drvdata(priv->phy, priv);
> Both make no sense. Look what this function does.

It does seem redundant at first glance, but pdev->dev is the parent of 
phy->dev.
pdev->dev->driver_data will be used in spacemit_combphy_xlate()
phy->dev->driver_data  will be used in phy_ops functions

I've checked some other drivers that did the same:
     - phy-zynqmp.c at lines 990 and 1026
     - phy-rockchip-samsung-hdptx.c at lines 1989 and 2000

>
> Best regards,
> Krzysztof
>
>
Krzysztof Kozlowski April 9, 2025, 10:10 a.m. UTC | #3
On 09/04/2025 11:43, Ze Huang wrote:
>>> +	priv->phy = devm_phy_create(dev, NULL, &spacemit_combphy_ops);
>>> +	if (IS_ERR(priv->phy))
>>> +		return dev_err_probe(dev, PTR_ERR(priv->phy),
>>> +				     "failed to create combphy\n");
>>> +
>>> +	dev_set_drvdata(dev, priv);
>>> +	phy_set_drvdata(priv->phy, priv);
>> Both make no sense. Look what this function does.
> 
> It does seem redundant at first glance, but pdev->dev is the parent of 
> phy->dev.
> pdev->dev->driver_data will be used in spacemit_combphy_xlate()
> phy->dev->driver_data  will be used in phy_ops functions
> 
> I've checked some other drivers that did the same:
>      - phy-zynqmp.c at lines 990 and 1026
>      - phy-rockchip-samsung-hdptx.c at lines 1989 and 2000

Indeed, right. It's fine.

Best regards,
Krzysztof
Pan Junzhong April 9, 2025, 11:38 a.m. UTC | #4
Hi Ze,

> +static int spacemit_combphy_init_usb(struct spacemit_combphy_priv *priv)

The USB3 phy driver is updated in the vendor's tree. 
https://gitee.com/bianbu-linux/linux-6.6/commit/1c0b3b4b9c77d22ca886c8a4c44e62b5891f8abc

You can submit v2 together with the change of lfps_thres (writes 0x58 register)
without adding new properties for dt node.

B.R.


This message and any attachment are confidential and may be privileged or otherwise protected from disclosure. If you are not an intended recipient of this message, please delete it and any attachment from your system and notify the sender immediately by reply e-mail. Unintended recipients should not use, copy, disclose or take any action based on this message or any information contained in this message. Emails cannot be guaranteed to be secure or error free as they can be intercepted, amended, lost or destroyed, and you should take full responsibility for security checking. 
 
本邮件及其任何附件具有保密性质,并可能受其他保护或不允许被披露给第三方。如阁下误收到本邮件,敬请立即以回复电子邮件的方式通知发件人,并将本邮件及其任何附件从阁下系统中予以删除。如阁下并非本邮件写明之收件人,敬请切勿使用、复制、披露本邮件或其任何内容,亦请切勿依本邮件或其任何内容而采取任何行动。电子邮件无法保证是一种安全和不会出现任何差错的通信方式,可能会被拦截、修改、丢失或损坏,收件人需自行负责做好安全检查。
Ze Huang April 9, 2025, 11:42 a.m. UTC | #5
On 4/9/25 7:38 PM, Pan Junzhong wrote:
> Hi Ze,
>
>> +static int spacemit_combphy_init_usb(struct spacemit_combphy_priv *priv)
> The USB3 phy driver is updated in the vendor's tree.
> https://gitee.com/bianbu-linux/linux-6.6/commit/1c0b3b4b9c77d22ca886c8a4c44e62b5891f8abc
>
> You can submit v2 together with the change of lfps_thres (writes 0x58 register)
> without adding new properties for dt node.

OK, thanks!

> B.R.
>
>
> This message and any attachment are confidential and may be privileged or otherwise protected from disclosure. If you are not an intended recipient of this message, please delete it and any attachment from your system and notify the sender immediately by reply e-mail. Unintended recipients should not use, copy, disclose or take any action based on this message or any information contained in this message. Emails cannot be guaranteed to be secure or error free as they can be intercepted, amended, lost or destroyed, and you should take full responsibility for security checking.
>   
> 本邮件及其任何附件具有保密性质,并可能受其他保护或不允许被披露给第三方。如阁下误收到本邮件,敬请立即以回复电子邮件的方式通知发件人,并将本邮件及其任何附件从阁下系统中予以删除。如阁下并非本邮件写明之收件人,敬请切勿使用、复制、披露本邮件或其任何内容,亦请切勿依本邮件或其任何内容而采取任何行动。电子邮件无法保证是一种安全和不会出现任何差错的通信方式,可能会被拦截、修改、丢失或损坏,收件人需自行负责做好安全检查。
diff mbox series

Patch

diff --git a/drivers/phy/spacemit/Kconfig b/drivers/phy/spacemit/Kconfig
index f0c2a33f53cc810e71c6140ae957aa68a2b6ff0c..12749aba756329cf64fb9199055ba484fe05f3ab 100644
--- a/drivers/phy/spacemit/Kconfig
+++ b/drivers/phy/spacemit/Kconfig
@@ -10,3 +10,11 @@  config PHY_SPACEMIT_K1_USB2
 	help
 	  Enable this to support K1 USB 2.0 PHY driver. This driver takes care of
 	  enabling and clock setup and will be used by K1 udc/ehci/otg driver.
+
+config PHY_SPACEMIT_K1_COMBPHY
+	tristate "SpacemiT K1 PCIe/USB3 combo PHY support"
+	depends on OF
+	select GENERIC_PHY
+	default ARCH_SPACEMIT && USB_DWC3_SPACEMIT
+	help
+	  USB3/PCIe Combo PHY Support for SpacemiT K1 SoC
diff --git a/drivers/phy/spacemit/Makefile b/drivers/phy/spacemit/Makefile
index fec0b425a948541b39b814caef0b05e1e002d92f..1fd0c65f2c5cd10ea2f70e43e62c70588d1ffae9 100644
--- a/drivers/phy/spacemit/Makefile
+++ b/drivers/phy/spacemit/Makefile
@@ -1,2 +1,3 @@ 
 # SPDX-License-Identifier: GPL-2.0-only
+obj-$(CONFIG_PHY_SPACEMIT_K1_COMBPHY)	+= phy-k1-combphy.o
 obj-$(CONFIG_PHY_SPACEMIT_K1_USB2)		+= phy-k1-usb2.o
diff --git a/drivers/phy/spacemit/phy-k1-combphy.c b/drivers/phy/spacemit/phy-k1-combphy.c
new file mode 100644
index 0000000000000000000000000000000000000000..a4b6e77fc2b4eb5d2c45d4e76294083509a3fc9d
--- /dev/null
+++ b/drivers/phy/spacemit/phy-k1-combphy.c
@@ -0,0 +1,229 @@ 
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Spacemit K1 PCIE/USB3 PHY driver
+ *
+ * Copyright (C) 2025 SpacemiT (Hangzhou) Technology Co. Ltd
+ * Copyright (C) 2025 Ze Huang <huangze@whut.edu.cn>
+ */
+
+#include <dt-bindings/phy/phy.h>
+#include <linux/clk.h>
+#include <linux/iopoll.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+#include <linux/usb/of.h>
+
+#define COMBPHY_USB_REG1	0x68
+#define  COMBPHY_USB_REG1_VAL	0x00
+#define COMBPHY_USB_REG2	0x48
+#define  COMBPHY_USB_REG2_VAL	0x603a2276
+#define COMBPHY_USB_REG3	0x08
+#define  COMBPHY_USB_REG3_VAL	0x97c
+#define COMBPHY_USB_REG4	0x18
+#define  COMBPHY_USB_REG4_VAL	0x00
+#define COMBPHY_USB_PLL_REG	0x08
+#define  COMBPHY_USB_PLL_MASK	0x01
+#define  COMBPHY_USB_PLL_VAL	0x01
+
+#define COMBPHY_MODE_SEL	BIT(3)
+#define COMBPHY_WAIT_TIMEOUT	1000
+
+struct spacemit_combphy_priv {
+	struct device *dev;
+	struct phy *phy;
+	struct reset_control *phy_rst;
+	void __iomem *phy_ctrl;
+	void __iomem *phy_sel;
+	u8 type;
+};
+
+static void spacemit_reg_update(void __iomem *reg, u32 offset, u32 mask, u32 val)
+{
+	u32 tmp;
+
+	tmp = readl(reg + offset);
+	tmp = (tmp & ~(mask)) | val;
+	writel(tmp, reg + offset);
+}
+
+static int spacemit_combphy_wait_ready(struct spacemit_combphy_priv *priv,
+				       u32 offset, u32 mask, u32 val)
+{
+	u32 reg_val;
+	int ret = 0;
+
+	ret = read_poll_timeout(readl, reg_val, (reg_val & mask) == val,
+				1000, COMBPHY_WAIT_TIMEOUT * 1000, false,
+				priv->phy_ctrl + offset);
+
+	return ret;
+}
+
+static int spacemit_combphy_set_mode(struct spacemit_combphy_priv *priv)
+{
+	int ret = 0;
+
+	switch (priv->type) {
+	case PHY_TYPE_USB3:
+		spacemit_reg_update(priv->phy_sel, 0, 0, COMBPHY_MODE_SEL);
+		break;
+	default:
+		dev_err(priv->dev, "PHY type %x not supported\n", priv->type);
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+static int spacemit_combphy_init_usb(struct spacemit_combphy_priv *priv)
+{
+	void __iomem *base = priv->phy_ctrl;
+	int ret;
+
+	writel(COMBPHY_USB_REG1_VAL, base + COMBPHY_USB_REG1);
+	writel(COMBPHY_USB_REG2_VAL, base + COMBPHY_USB_REG2);
+	writel(COMBPHY_USB_REG3_VAL, base + COMBPHY_USB_REG3);
+	writel(COMBPHY_USB_REG4_VAL, base + COMBPHY_USB_REG4);
+
+	ret = spacemit_combphy_wait_ready(priv, COMBPHY_USB_PLL_REG,
+					  COMBPHY_USB_PLL_MASK,
+					  COMBPHY_USB_PLL_VAL);
+	if (ret)
+		dev_err(priv->dev, "USB3 PHY init timeout!\n");
+
+	return ret;
+}
+
+static int spacemit_combphy_init(struct phy *phy)
+{
+	struct spacemit_combphy_priv *priv = phy_get_drvdata(phy);
+	int ret;
+
+	ret = spacemit_combphy_set_mode(priv);
+	if (ret) {
+		dev_err(priv->dev, "failed to set mode for PHY type %x\n",
+			priv->type);
+		goto out;
+	}
+
+	ret = reset_control_deassert(priv->phy_rst);
+	if (ret) {
+		dev_err(priv->dev, "failed to deassert rst\n");
+		goto err_rst;
+	}
+
+	switch (priv->type) {
+	case PHY_TYPE_USB3:
+		ret = spacemit_combphy_init_usb(priv);
+		break;
+	default:
+		dev_err(priv->dev, "PHY type %x not supported\n", priv->type);
+		ret = -EINVAL;
+		break;
+	}
+
+	if (ret)
+		goto err_rst;
+
+	return 0;
+
+err_rst:
+	reset_control_assert(priv->phy_rst);
+out:
+	return ret;
+}
+
+static int spacemit_combphy_exit(struct phy *phy)
+{
+	struct spacemit_combphy_priv *priv = phy_get_drvdata(phy);
+
+	reset_control_assert(priv->phy_rst);
+
+	return 0;
+}
+
+static struct phy *spacemit_combphy_xlate(struct device *dev,
+					  const struct of_phandle_args *args)
+{
+	struct spacemit_combphy_priv *priv = dev_get_drvdata(dev);
+
+	if (args->args_count != 1) {
+		dev_err(dev, "invalid number of arguments\n");
+		return ERR_PTR(-EINVAL);
+	}
+
+	if (priv->type != PHY_NONE && priv->type != args->args[0])
+		dev_warn(dev, "PHY type %d is selected to override %d\n",
+			 args->args[0], priv->type);
+
+	priv->type = args->args[0];
+
+	if (args->args_count > 1)
+		dev_dbg(dev, "combo phy idx: %d selected",  args->args[1]);
+
+	return priv->phy;
+}
+
+static const struct phy_ops spacemit_combphy_ops = {
+	.init = spacemit_combphy_init,
+	.exit = spacemit_combphy_exit,
+	.owner = THIS_MODULE,
+};
+
+static int spacemit_combphy_probe(struct platform_device *pdev)
+{
+	struct spacemit_combphy_priv *priv;
+	struct phy_provider *phy_provider;
+	struct device *dev = &pdev->dev;
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->phy_ctrl = devm_platform_ioremap_resource_byname(pdev, "phy_ctrl");
+	if (IS_ERR(priv->phy_ctrl))
+		return PTR_ERR(priv->phy_ctrl);
+
+	priv->phy_sel = devm_platform_ioremap_resource_byname(pdev, "phy_sel");
+	if (IS_ERR(priv->phy_sel))
+		return PTR_ERR(priv->phy_sel);
+
+	priv->type = PHY_NONE;
+	priv->dev = dev;
+
+	priv->phy_rst = devm_reset_control_get(dev, NULL);
+	if (IS_ERR(priv->phy_rst))
+		return dev_err_probe(dev, PTR_ERR(priv->phy_rst),
+				     "failed to get phy reset\n");
+
+	priv->phy = devm_phy_create(dev, NULL, &spacemit_combphy_ops);
+	if (IS_ERR(priv->phy))
+		return dev_err_probe(dev, PTR_ERR(priv->phy),
+				     "failed to create combphy\n");
+
+	dev_set_drvdata(dev, priv);
+	phy_set_drvdata(priv->phy, priv);
+	phy_provider = devm_of_phy_provider_register(dev, spacemit_combphy_xlate);
+
+	return PTR_ERR_OR_ZERO(phy_provider);
+}
+
+static const struct of_device_id spacemit_combphy_of_match[] = {
+	{ .compatible = "spacemit,k1-combphy", },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, spacemit_combphy_of_match);
+
+static struct platform_driver spacemit_combphy_driver = {
+	.probe	= spacemit_combphy_probe,
+	.driver = {
+		.name = "spacemit-k1-combphy",
+		.of_match_table = spacemit_combphy_of_match,
+	},
+};
+module_platform_driver(spacemit_combphy_driver);
+
+MODULE_DESCRIPTION("Spacemit PCIE/USB3.0 COMBO PHY driver");
+MODULE_LICENSE("GPL");