Commit 63162725 authored by Neil Armstrong's avatar Neil Armstrong Committed by Lorenzo Pieralisi
Browse files

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: default avatarNeil Armstrong <narmstrong@baylibre.com>
Signed-off-by: default avatarLorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Reviewed-by: default avatarAndrew Murray <andrew.murray@arm.com>
parent 4ff9f68f
Loading
Loading
Loading
Loading
+61 −9
Original line number Diff line number Diff line
@@ -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);

	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,
};