> > > > On 04/07/2024 08:50, Minda Chen wrote: > > Add Starfive JH7110 PCIe 2.0 PHY driver, which is generic PHY driver > > and can be used as USB 3.0 driver. > > > > Signed-off-by: Minda Chen <minda.c...@starfivetech.com> > > --- > > drivers/phy/starfive/Kconfig | 7 + > > drivers/phy/starfive/Makefile | 1 + > > drivers/phy/starfive/phy-jh7110-pcie.c | 202 > > +++++++++++++++++++++++++ > > 3 files changed, 210 insertions(+) > > create mode 100644 drivers/phy/starfive/phy-jh7110-pcie.c > > > > diff --git a/drivers/phy/starfive/Kconfig > > b/drivers/phy/starfive/Kconfig index 11a819f8b2..5d49684bc7 100644 > > --- a/drivers/phy/starfive/Kconfig > > +++ b/drivers/phy/starfive/Kconfig > > @@ -4,6 +4,13 @@ > > > > menu "Starfive PHY driver" > > > > +config PHY_STARFIVE_JH7110_PCIE > > + bool "Starfive JH7110 PCIe 2.0 PHY driver" > > + select PHY > > + help > > + Enable this to support the Starfive JH7110 PCIE 2.0/USB 3.0 PHY. > > + Generic PHY driver JH7110 USB 3.0/ PCIe 2.0. > > Should be aligned to previous line. > > > + > > config PHY_STARFIVE_JH7110_USB2 > > bool "Starfive JH7110 USB 2.0 PHY driver" > > select PHY > > diff --git a/drivers/phy/starfive/Makefile > > b/drivers/phy/starfive/Makefile index a405a75e34..82f25aa21b 100644 > > --- a/drivers/phy/starfive/Makefile > > +++ b/drivers/phy/starfive/Makefile > > @@ -3,4 +3,5 @@ > > # Copyright (C) 2023 Starfive > > # > > > > +obj-$(CONFIG_PHY_STARFIVE_JH7110_PCIE) += phy-jh7110-pcie.o > > obj-$(CONFIG_PHY_STARFIVE_JH7110_USB2) += phy-jh7110-usb2.o > > diff --git a/drivers/phy/starfive/phy-jh7110-pcie.c > > b/drivers/phy/starfive/phy-jh7110-pcie.c > > new file mode 100644 > > index 0000000000..57d5d8bf53 > > --- /dev/null > > +++ b/drivers/phy/starfive/phy-jh7110-pcie.c > > @@ -0,0 +1,202 @@ > > +// SPDX-License-Identifier: GPL-2.0+ > > +/* > > + * StarFive JH7110 PCIe 2.0 PHY driver > > + * > > + * Copyright (C) 2024 StarFive Technology Co., Ltd. > > + * Author: Minda Chen <minda.c...@starfivetech.com> */ #include > > +<asm/io.h> #include <dm.h> #include <dm/device_compat.h> #include > > +<errno.h> #include <generic-phy.h> #include <regmap.h> #include > > +<soc.h> #include <syscon.h> #include <linux/bitops.h> #include > > +<linux/err.h> > > + > > +#define PCIE_KVCO_LEVEL_OFF 0x28 > > +#define PCIE_USB3_PHY_PLL_CTL_OFF 0x7c > > +#define PCIE_USB3_PHY_SS_MODE BIT(4) > > extra tab? > > > +#define PCIE_KVCO_TUNE_SIGNAL_OFF 0x80 > > +#define PHY_KVCO_FINE_TUNE_LEVEL 0x91 > > +#define PHY_KVCO_FINE_TUNE_SIGNALS 0xc > > + > > +#define USB_PDRSTN_SPLIT BIT(17) > > + > > +#define PCIE_USB3_PHY_MODE BIT(20) > > +#define PCIE_PHY_MODE_MASK GENMASK(21, 20) > > +#define PCIE_USB3_BUS_WIDTH_MASK GENMASK(3, 2) > > +#define PCIE_BUS_WIDTH BIT(3) > > +#define PCIE_USB3_RATE_MASK GENMASK(6, 5) > > +#define PCIE_USB3_RX_STANDBY_MASK BIT(7) > > +#define PCIE_USB3_PHY_ENABLE BIT(4) > > Why not use define and use regmap_fields? You are already using regmap. > > > + > > +struct jh7110_pcie_phy { > > + struct phy *phy; > > + struct regmap *stg_syscon; > > + struct regmap *sys_syscon; > > + void __iomem *regs; > > + u32 sys_phy_connect; > > + u32 stg_pcie_mode; > > + u32 stg_pcie_usb; > > + enum phy_mode mode; > > +}; > > + > > +static int phy_pcie_mode_set(struct jh7110_pcie_phy *data, bool > > +usb_mode) { > > + unsigned int phy_mode, width, usb3_phy, ss_mode; > > + > > + /* default is PCIe mode */ > > + if (!data->stg_syscon || !data->sys_syscon) { > > + if (usb_mode) { > > + dev_err(data->phy->dev, "doesn't support usb3 mode\n"); > > + return -EINVAL; > > + } > > + return 0; > > + } > > + > > + if (usb_mode) { > > + phy_mode = PCIE_USB3_PHY_MODE; > > + width = 0; > > + usb3_phy = PCIE_USB3_PHY_ENABLE; > > + ss_mode = PCIE_USB3_PHY_SS_MODE; > > + } else { > > + phy_mode = 0; > > + width = PCIE_BUS_WIDTH; > > + usb3_phy = 0; > > + ss_mode = 0; > > + } > > + > > + regmap_update_bits(data->stg_syscon, data->stg_pcie_mode, > > + PCIE_PHY_MODE_MASK, phy_mode); > > + regmap_update_bits(data->stg_syscon, data->stg_pcie_usb, > > + PCIE_USB3_BUS_WIDTH_MASK, width); > > + regmap_update_bits(data->stg_syscon, data->stg_pcie_usb, > > + PCIE_USB3_PHY_ENABLE, usb3_phy); > > + clrsetbits_le32(data->regs + PCIE_USB3_PHY_PLL_CTL_OFF, > > + PCIE_USB3_PHY_SS_MODE, ss_mode); > > + > > + regmap_update_bits(data->sys_syscon, data->sys_phy_connect, > > + USB_PDRSTN_SPLIT, 0); > > + > > + return 0; > > +} > > + > > +static void phy_kvco_gain_set(struct jh7110_pcie_phy *phy) { > > + /* PCIe Multi-PHY PLL KVCO Gain fine tune settings: */ > > + writel(PHY_KVCO_FINE_TUNE_LEVEL, phy->regs + > PCIE_KVCO_LEVEL_OFF); > > + writel(PHY_KVCO_FINE_TUNE_SIGNALS, phy->regs + > > +PCIE_KVCO_TUNE_SIGNAL_OFF); } > > + > > +static int jh7110_pcie_phy_set_mode(struct phy *_phy, > > + enum phy_mode mode, int submode) { > > + struct udevice *dev = _phy->dev; > > + struct jh7110_pcie_phy *phy = dev_get_priv(dev); > > + int ret; > > + > > + if (mode == phy->mode) > > + return 0; > > + > > + switch (mode) { > > + case PHY_MODE_USB_HOST: > > + case PHY_MODE_USB_DEVICE: > > + case PHY_MODE_USB_OTG: > > + ret = phy_pcie_mode_set(phy, 1); > > + if (ret) > > + return ret; > > + break; > > + case PHY_MODE_PCIE: > > + phy_pcie_mode_set(phy, 0); > > + break; > > + default: > > + return -EINVAL; > > + } > > + > > + dev_dbg(_phy->dev, "Changing phy mode to %d\n", mode); > > + phy->mode = mode; > > + > > + return 0; > > +} > > + > > +static const struct phy_ops jh7110_pcie_phy_ops = { > > + .set_mode = jh7110_pcie_phy_set_mode, > > +}; > > + > > +static int starfive_pcie_phy_get_syscon(struct udevice *dev) { > > + struct jh7110_pcie_phy *phy = dev_get_priv(dev); > > + struct ofnode_phandle_args sys_phandle, stg_phandle; > > + int ret; > > + > > + /* get corresponding syscon phandle */ > > + ret = dev_read_phandle_with_args(dev, "starfive,sys-syscon", NULL, 1, 0, > > + &sys_phandle); > > + > > + if (ret < 0) { > > + dev_err(dev, "Can't get sys cfg phandle: %d\n", ret); > > + return ret; > > + } > > + > > + ret = dev_read_phandle_with_args(dev, "starfive,stg-syscon", NULL, 2, 0, > > + &stg_phandle); > > + > > + if (ret < 0) { > > + dev_err(dev, "Can't get stg cfg phandle: %d\n", ret); > > + return ret; > > + } > > + > > + phy->sys_syscon = syscon_node_to_regmap(sys_phandle.node); > > + if (!IS_ERR_OR_NULL(phy->sys_syscon)) { > > + /* get syscon register offset */ > > + phy->sys_phy_connect = sys_phandle.args[0]; > > + } else { > > + phy->sys_syscon = NULL; > > Why not error out if you could not get the sys_syscon regmap? > The syscon is optional in USB2.0 only case.
> > + } > > + > > + phy->stg_syscon = syscon_node_to_regmap(stg_phandle.node); > > + if (!IS_ERR_OR_NULL(phy->stg_syscon)) { > > + phy->stg_pcie_mode = stg_phandle.args[0]; > > + phy->stg_pcie_usb = stg_phandle.args[1]; > > + } else { > > + phy->stg_syscon = NULL; > > same here? > > > + } > > + > > + return 0; > > +} > > + > > +int jh7110_pcie_phy_probe(struct udevice *dev) { > > + struct jh7110_pcie_phy *phy = dev_get_priv(dev); > > + int rc; > > + > > + phy->regs = dev_read_addr_ptr(dev); > > + if (!phy->regs) > > + return -EINVAL; > > + > > + rc = starfive_pcie_phy_get_syscon(dev); > > + if (rc) > > + return rc; > > + > > + phy_kvco_gain_set(phy); > > + > > + return 0; > > +} > > + > > +static const struct udevice_id jh7110_pcie_phy[] = { > > + { .compatible = "starfive,jh7110-pcie-phy"}, > > + {}, > > +}; > > + > > +U_BOOT_DRIVER(jh7110_pcie_phy) = { > > + .name = "jh7110_pcie_phy", > > + .id = UCLASS_PHY, > > + .of_match = jh7110_pcie_phy, > > + .probe = jh7110_pcie_phy_probe, > > + .ops = &jh7110_pcie_phy_ops, > > + .priv_auto = sizeof(struct jh7110_pcie_phy), > > need space instead of tab? > > > +}; > > + > > -- > cheers, > -roger