phy: meson-g12a-usb3-pcie: add support for PCIe ops
authorNeil Armstrong <narmstrong@baylibre.com>
Thu, 25 Feb 2021 16:53:23 +0000 (17:53 +0100)
committerTom Rini <trini@konsulko.com>
Tue, 20 Apr 2021 11:30:04 +0000 (07:30 -0400)
Add the PCIe part of the G12A USB3 PCIe Combo PHY driver.

Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
drivers/phy/meson-g12a-usb3-pcie.c

index 0433d93..8f72b5a 100644 (file)
@@ -23,6 +23,9 @@
 #include <linux/compat.h>
 #include <linux/bitfield.h>
 
+#define PHY_TYPE_PCIE           2
+#define PHY_TYPE_USB3           4
+
 #define PHY_R0                                                 0x00
        #define PHY_R0_PCIE_POWER_STATE                         GENMASK(4, 0)
        #define PHY_R0_PCIE_USB3_SWITCH                         GENMASK(6, 5)
@@ -55,6 +58,8 @@
        #define PHY_R5_PHY_CR_ACK                               BIT(16)
        #define PHY_R5_PHY_BS_OUT                               BIT(17)
 
+#define PCIE_RESET_DELAY                                       500
+
 struct phy_g12a_usb3_pcie_priv {
        struct regmap           *regmap;
 #if CONFIG_IS_ENABLED(CLK)
@@ -202,8 +207,6 @@ static int phy_meson_g12a_usb3_init(struct phy *phy)
        unsigned int data;
        int ret;
 
-       /* TOFIX Handle PCIE mode */
-
        ret = reset_assert_bulk(&priv->resets);
        udelay(1);
        ret |= reset_deassert_bulk(&priv->resets);
@@ -296,9 +299,79 @@ static int phy_meson_g12a_usb3_exit(struct phy *phy)
        return reset_assert_bulk(&priv->resets);
 }
 
+static int phy_meson_g12a_usb3_pcie_init(struct phy *phy)
+{
+       if (phy->id == PHY_TYPE_USB3)
+               return phy_meson_g12a_usb3_init(phy);
+
+       return 0;
+}
+
+static int phy_meson_g12a_usb3_pcie_exit(struct phy *phy)
+{
+       if (phy->id == PHY_TYPE_USB3)
+               return phy_meson_g12a_usb3_exit(phy);
+
+       return 0;
+}
+
+static int phy_meson_g12a_usb3_pcie_power_on(struct phy *phy)
+{
+       struct phy_g12a_usb3_pcie_priv *priv = dev_get_priv(phy->dev);
+
+       if (phy->id == PHY_TYPE_USB3)
+               return 0;
+
+       regmap_update_bits(priv->regmap, PHY_R0,
+                          PHY_R0_PCIE_POWER_STATE,
+                          FIELD_PREP(PHY_R0_PCIE_POWER_STATE, 0x1c));
+
+       return 0;
+}
+
+static int phy_meson_g12a_usb3_pcie_power_off(struct phy *phy)
+{
+       struct phy_g12a_usb3_pcie_priv *priv = dev_get_priv(phy->dev);
+
+       if (phy->id == PHY_TYPE_USB3)
+               return 0;
+
+       regmap_update_bits(priv->regmap, PHY_R0,
+                          PHY_R0_PCIE_POWER_STATE,
+                          FIELD_PREP(PHY_R0_PCIE_POWER_STATE, 0x1d));
+
+       return 0;
+}
+
+static int phy_meson_g12a_usb3_pcie_reset(struct phy *phy)
+{
+       struct phy_g12a_usb3_pcie_priv *priv = dev_get_priv(phy->dev);
+       int ret;
+
+       if (phy->id == PHY_TYPE_USB3)
+               return 0;
+
+       ret = reset_assert_bulk(&priv->resets);
+       if (ret)
+               return ret;
+
+       udelay(PCIE_RESET_DELAY);
+
+       ret = reset_deassert_bulk(&priv->resets);
+       if (ret)
+               return ret;
+
+       udelay(PCIE_RESET_DELAY);
+
+       return 0;
+}
+
 struct phy_ops meson_g12a_usb3_pcie_phy_ops = {
-       .init = phy_meson_g12a_usb3_init,
-       .exit = phy_meson_g12a_usb3_exit,
+       .init = phy_meson_g12a_usb3_pcie_init,
+       .exit = phy_meson_g12a_usb3_pcie_exit,
+       .power_on = phy_meson_g12a_usb3_pcie_power_on,
+       .power_off = phy_meson_g12a_usb3_pcie_power_off,
+       .reset = phy_meson_g12a_usb3_pcie_reset,
 };
 
 int meson_g12a_usb3_pcie_phy_probe(struct udevice *dev)