From 631627253de29eef733cadd9385064a9fbc39823 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Mon, 16 Sep 2019 14:50:20 +0200 Subject: phy: meson-g12a-usb3-pcie: Add support for PCIe mode This adds extended PCIe PHY functions for the Amlogic G12A USB3+PCIE Combo PHY to support reset, power_on and power_off for PCIe exclusively. With these callbacks, we can handle all the needed operations of the Amlogic PCIe controller driver. Signed-off-by: Neil Armstrong Signed-off-by: Lorenzo Pieralisi Reviewed-by: Andrew Murray --- drivers/phy/amlogic/phy-meson-g12a-usb3-pcie.c | 70 ++++++++++++++++++++++---- 1 file changed, 61 insertions(+), 9 deletions(-) (limited to 'drivers/phy/amlogic') diff --git a/drivers/phy/amlogic/phy-meson-g12a-usb3-pcie.c b/drivers/phy/amlogic/phy-meson-g12a-usb3-pcie.c index ac322d643c7a..08e322789e59 100644 --- a/drivers/phy/amlogic/phy-meson-g12a-usb3-pcie.c +++ b/drivers/phy/amlogic/phy-meson-g12a-usb3-pcie.c @@ -50,6 +50,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; struct regmap *regmap_cr; @@ -196,6 +198,10 @@ static int phy_g12a_usb3_init(struct phy *phy) struct phy_g12a_usb3_pcie_priv *priv = phy_get_drvdata(phy); int data, ret; + ret = reset_control_reset(priv->reset); + if (ret) + return ret; + /* Switch PHY to USB3 */ /* TODO figure out how to handle when PCIe was set in the bootloader */ regmap_update_bits(priv->regmap, PHY_R0, @@ -272,24 +278,64 @@ static int phy_g12a_usb3_init(struct phy *phy) return 0; } -static int phy_g12a_usb3_pcie_init(struct phy *phy) +static int phy_g12a_usb3_pcie_power_on(struct phy *phy) +{ + struct phy_g12a_usb3_pcie_priv *priv = phy_get_drvdata(phy); + + if (priv->mode == 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_g12a_usb3_pcie_power_off(struct phy *phy) +{ + struct phy_g12a_usb3_pcie_priv *priv = phy_get_drvdata(phy); + + if (priv->mode == 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_g12a_usb3_pcie_reset(struct phy *phy) { struct phy_g12a_usb3_pcie_priv *priv = phy_get_drvdata(phy); int ret; - ret = reset_control_reset(priv->reset); + if (priv->mode == PHY_TYPE_USB3) + return 0; + + ret = reset_control_assert(priv->reset); if (ret) return ret; + udelay(PCIE_RESET_DELAY); + + ret = reset_control_deassert(priv->reset); + if (ret) + return ret; + + udelay(PCIE_RESET_DELAY); + + return 0; +} + +static int phy_g12a_usb3_pcie_init(struct phy *phy) +{ + struct phy_g12a_usb3_pcie_priv *priv = phy_get_drvdata(phy); + if (priv->mode == PHY_TYPE_USB3) return phy_g12a_usb3_init(phy); - /* Power UP PCIE */ - /* TODO figure out when the bootloader has set USB3 mode before */ - regmap_update_bits(priv->regmap, PHY_R0, - PHY_R0_PCIE_POWER_STATE, - FIELD_PREP(PHY_R0_PCIE_POWER_STATE, 0x1c)); - return 0; } @@ -297,7 +343,10 @@ static int phy_g12a_usb3_pcie_exit(struct phy *phy) { struct phy_g12a_usb3_pcie_priv *priv = phy_get_drvdata(phy); - return reset_control_reset(priv->reset); + if (priv->mode == PHY_TYPE_USB3) + return reset_control_reset(priv->reset); + + return 0; } static struct phy *phy_g12a_usb3_pcie_xlate(struct device *dev, @@ -326,6 +375,9 @@ static struct phy *phy_g12a_usb3_pcie_xlate(struct device *dev, static const struct phy_ops phy_g12a_usb3_pcie_ops = { .init = phy_g12a_usb3_pcie_init, .exit = phy_g12a_usb3_pcie_exit, + .power_on = phy_g12a_usb3_pcie_power_on, + .power_off = phy_g12a_usb3_pcie_power_off, + .reset = phy_g12a_usb3_pcie_reset, .owner = THIS_MODULE, }; -- cgit v1.2.3