diff options
Diffstat (limited to 'drivers/pci/controller/dwc/pci-imx6.c')
| -rw-r--r-- | drivers/pci/controller/dwc/pci-imx6.c | 144 | 
1 files changed, 57 insertions, 87 deletions
| diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index 3d627f94a166..9b5cb5b70389 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -52,6 +52,7 @@ enum imx6_pcie_variants {  #define IMX6_PCIE_FLAG_IMX6_PHY			BIT(0)  #define IMX6_PCIE_FLAG_IMX6_SPEED_CHANGE	BIT(1) +#define IMX6_PCIE_FLAG_SUPPORTS_SUSPEND		BIT(2)  struct imx6_pcie_drvdata {  	enum imx6_pcie_variants variant; @@ -89,9 +90,8 @@ struct imx6_pcie {  };  /* Parameters for the waiting for PCIe PHY PLL to lock on i.MX7 */ -#define PHY_PLL_LOCK_WAIT_MAX_RETRIES	2000 -#define PHY_PLL_LOCK_WAIT_USLEEP_MIN	50  #define PHY_PLL_LOCK_WAIT_USLEEP_MAX	200 +#define PHY_PLL_LOCK_WAIT_TIMEOUT	(2000 * PHY_PLL_LOCK_WAIT_USLEEP_MAX)  /* PCIe Root Complex registers (memory-mapped) */  #define PCIE_RC_IMX6_MSI_CAP			0x50 @@ -104,34 +104,29 @@ struct imx6_pcie {  /* PCIe Port Logic registers (memory-mapped) */  #define PL_OFFSET 0x700 -#define PCIE_PL_PFLR (PL_OFFSET + 0x08) -#define PCIE_PL_PFLR_LINK_STATE_MASK		(0x3f << 16) -#define PCIE_PL_PFLR_FORCE_LINK			(1 << 15) -#define PCIE_PHY_DEBUG_R0 (PL_OFFSET + 0x28) -#define PCIE_PHY_DEBUG_R1 (PL_OFFSET + 0x2c)  #define PCIE_PHY_CTRL (PL_OFFSET + 0x114) -#define PCIE_PHY_CTRL_DATA_LOC 0 -#define PCIE_PHY_CTRL_CAP_ADR_LOC 16 -#define PCIE_PHY_CTRL_CAP_DAT_LOC 17 -#define PCIE_PHY_CTRL_WR_LOC 18 -#define PCIE_PHY_CTRL_RD_LOC 19 +#define PCIE_PHY_CTRL_DATA(x)		FIELD_PREP(GENMASK(15, 0), (x)) +#define PCIE_PHY_CTRL_CAP_ADR		BIT(16) +#define PCIE_PHY_CTRL_CAP_DAT		BIT(17) +#define PCIE_PHY_CTRL_WR		BIT(18) +#define PCIE_PHY_CTRL_RD		BIT(19)  #define PCIE_PHY_STAT (PL_OFFSET + 0x110) -#define PCIE_PHY_STAT_ACK_LOC 16 +#define PCIE_PHY_STAT_ACK		BIT(16)  #define PCIE_LINK_WIDTH_SPEED_CONTROL	0x80C  /* PHY registers (not memory-mapped) */  #define PCIE_PHY_ATEOVRD			0x10 -#define  PCIE_PHY_ATEOVRD_EN			(0x1 << 2) +#define  PCIE_PHY_ATEOVRD_EN			BIT(2)  #define  PCIE_PHY_ATEOVRD_REF_CLKDIV_SHIFT	0  #define  PCIE_PHY_ATEOVRD_REF_CLKDIV_MASK	0x1  #define PCIE_PHY_MPLL_OVRD_IN_LO		0x11  #define  PCIE_PHY_MPLL_MULTIPLIER_SHIFT		2  #define  PCIE_PHY_MPLL_MULTIPLIER_MASK		0x7f -#define  PCIE_PHY_MPLL_MULTIPLIER_OVRD		(0x1 << 9) +#define  PCIE_PHY_MPLL_MULTIPLIER_OVRD		BIT(9)  #define PCIE_PHY_RX_ASIC_OUT 0x100D  #define PCIE_PHY_RX_ASIC_OUT_VALID	(1 << 0) @@ -154,19 +149,19 @@ struct imx6_pcie {  #define PCIE_PHY_CMN_REG26_ATT_MODE	0xBC  #define PHY_RX_OVRD_IN_LO 0x1005 -#define PHY_RX_OVRD_IN_LO_RX_DATA_EN (1 << 5) -#define PHY_RX_OVRD_IN_LO_RX_PLL_EN (1 << 3) +#define PHY_RX_OVRD_IN_LO_RX_DATA_EN		BIT(5) +#define PHY_RX_OVRD_IN_LO_RX_PLL_EN		BIT(3) -static int pcie_phy_poll_ack(struct imx6_pcie *imx6_pcie, int exp_val) +static int pcie_phy_poll_ack(struct imx6_pcie *imx6_pcie, bool exp_val)  {  	struct dw_pcie *pci = imx6_pcie->pci; -	u32 val; +	bool val;  	u32 max_iterations = 10;  	u32 wait_counter = 0;  	do { -		val = dw_pcie_readl_dbi(pci, PCIE_PHY_STAT); -		val = (val >> PCIE_PHY_STAT_ACK_LOC) & 0x1; +		val = dw_pcie_readl_dbi(pci, PCIE_PHY_STAT) & +			PCIE_PHY_STAT_ACK;  		wait_counter++;  		if (val == exp_val) @@ -184,27 +179,27 @@ static int pcie_phy_wait_ack(struct imx6_pcie *imx6_pcie, int addr)  	u32 val;  	int ret; -	val = addr << PCIE_PHY_CTRL_DATA_LOC; +	val = PCIE_PHY_CTRL_DATA(addr);  	dw_pcie_writel_dbi(pci, PCIE_PHY_CTRL, val); -	val |= (0x1 << PCIE_PHY_CTRL_CAP_ADR_LOC); +	val |= PCIE_PHY_CTRL_CAP_ADR;  	dw_pcie_writel_dbi(pci, PCIE_PHY_CTRL, val); -	ret = pcie_phy_poll_ack(imx6_pcie, 1); +	ret = pcie_phy_poll_ack(imx6_pcie, true);  	if (ret)  		return ret; -	val = addr << PCIE_PHY_CTRL_DATA_LOC; +	val = PCIE_PHY_CTRL_DATA(addr);  	dw_pcie_writel_dbi(pci, PCIE_PHY_CTRL, val); -	return pcie_phy_poll_ack(imx6_pcie, 0); +	return pcie_phy_poll_ack(imx6_pcie, false);  }  /* Read from the 16-bit PCIe PHY control registers (not memory-mapped) */ -static int pcie_phy_read(struct imx6_pcie *imx6_pcie, int addr, int *data) +static int pcie_phy_read(struct imx6_pcie *imx6_pcie, int addr, u16 *data)  {  	struct dw_pcie *pci = imx6_pcie->pci; -	u32 val, phy_ctl; +	u32 phy_ctl;  	int ret;  	ret = pcie_phy_wait_ack(imx6_pcie, addr); @@ -212,23 +207,22 @@ static int pcie_phy_read(struct imx6_pcie *imx6_pcie, int addr, int *data)  		return ret;  	/* assert Read signal */ -	phy_ctl = 0x1 << PCIE_PHY_CTRL_RD_LOC; +	phy_ctl = PCIE_PHY_CTRL_RD;  	dw_pcie_writel_dbi(pci, PCIE_PHY_CTRL, phy_ctl); -	ret = pcie_phy_poll_ack(imx6_pcie, 1); +	ret = pcie_phy_poll_ack(imx6_pcie, true);  	if (ret)  		return ret; -	val = dw_pcie_readl_dbi(pci, PCIE_PHY_STAT); -	*data = val & 0xffff; +	*data = dw_pcie_readl_dbi(pci, PCIE_PHY_STAT);  	/* deassert Read signal */  	dw_pcie_writel_dbi(pci, PCIE_PHY_CTRL, 0x00); -	return pcie_phy_poll_ack(imx6_pcie, 0); +	return pcie_phy_poll_ack(imx6_pcie, false);  } -static int pcie_phy_write(struct imx6_pcie *imx6_pcie, int addr, int data) +static int pcie_phy_write(struct imx6_pcie *imx6_pcie, int addr, u16 data)  {  	struct dw_pcie *pci = imx6_pcie->pci;  	u32 var; @@ -240,41 +234,41 @@ static int pcie_phy_write(struct imx6_pcie *imx6_pcie, int addr, int data)  	if (ret)  		return ret; -	var = data << PCIE_PHY_CTRL_DATA_LOC; +	var = PCIE_PHY_CTRL_DATA(data);  	dw_pcie_writel_dbi(pci, PCIE_PHY_CTRL, var);  	/* capture data */ -	var |= (0x1 << PCIE_PHY_CTRL_CAP_DAT_LOC); +	var |= PCIE_PHY_CTRL_CAP_DAT;  	dw_pcie_writel_dbi(pci, PCIE_PHY_CTRL, var); -	ret = pcie_phy_poll_ack(imx6_pcie, 1); +	ret = pcie_phy_poll_ack(imx6_pcie, true);  	if (ret)  		return ret;  	/* deassert cap data */ -	var = data << PCIE_PHY_CTRL_DATA_LOC; +	var = PCIE_PHY_CTRL_DATA(data);  	dw_pcie_writel_dbi(pci, PCIE_PHY_CTRL, var);  	/* wait for ack de-assertion */ -	ret = pcie_phy_poll_ack(imx6_pcie, 0); +	ret = pcie_phy_poll_ack(imx6_pcie, false);  	if (ret)  		return ret;  	/* assert wr signal */ -	var = 0x1 << PCIE_PHY_CTRL_WR_LOC; +	var = PCIE_PHY_CTRL_WR;  	dw_pcie_writel_dbi(pci, PCIE_PHY_CTRL, var);  	/* wait for ack */ -	ret = pcie_phy_poll_ack(imx6_pcie, 1); +	ret = pcie_phy_poll_ack(imx6_pcie, true);  	if (ret)  		return ret;  	/* deassert wr signal */ -	var = data << PCIE_PHY_CTRL_DATA_LOC; +	var = PCIE_PHY_CTRL_DATA(data);  	dw_pcie_writel_dbi(pci, PCIE_PHY_CTRL, var);  	/* wait for ack de-assertion */ -	ret = pcie_phy_poll_ack(imx6_pcie, 0); +	ret = pcie_phy_poll_ack(imx6_pcie, false);  	if (ret)  		return ret; @@ -285,7 +279,7 @@ static int pcie_phy_write(struct imx6_pcie *imx6_pcie, int addr, int data)  static void imx6_pcie_reset_phy(struct imx6_pcie *imx6_pcie)  { -	u32 tmp; +	u16 tmp;  	if (!(imx6_pcie->drvdata->flags & IMX6_PCIE_FLAG_IMX6_PHY))  		return; @@ -455,7 +449,7 @@ static int imx6_pcie_enable_ref_clk(struct imx6_pcie *imx6_pcie)  		 * reset time is too short, cannot meet the requirement.  		 * add one ~10us delay here.  		 */ -		udelay(10); +		usleep_range(10, 100);  		regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1,  				   IMX6Q_GPR1_PCIE_REF_CLK_EN, 1 << 16);  		break; @@ -488,20 +482,14 @@ static int imx6_pcie_enable_ref_clk(struct imx6_pcie *imx6_pcie)  static void imx7d_pcie_wait_for_phy_pll_lock(struct imx6_pcie *imx6_pcie)  {  	u32 val; -	unsigned int retries;  	struct device *dev = imx6_pcie->pci->dev; -	for (retries = 0; retries < PHY_PLL_LOCK_WAIT_MAX_RETRIES; retries++) { -		regmap_read(imx6_pcie->iomuxc_gpr, IOMUXC_GPR22, &val); - -		if (val & IMX7D_GPR22_PCIE_PHY_PLL_LOCKED) -			return; - -		usleep_range(PHY_PLL_LOCK_WAIT_USLEEP_MIN, -			     PHY_PLL_LOCK_WAIT_USLEEP_MAX); -	} - -	dev_err(dev, "PCIe PLL lock timeout\n"); +	if (regmap_read_poll_timeout(imx6_pcie->iomuxc_gpr, +				     IOMUXC_GPR22, val, +				     val & IMX7D_GPR22_PCIE_PHY_PLL_LOCKED, +				     PHY_PLL_LOCK_WAIT_USLEEP_MAX, +				     PHY_PLL_LOCK_WAIT_TIMEOUT)) +		dev_err(dev, "PCIe PLL lock timeout\n");  }  static void imx6_pcie_deassert_core_reset(struct imx6_pcie *imx6_pcie) @@ -687,7 +675,7 @@ static int imx6_setup_phy_mpll(struct imx6_pcie *imx6_pcie)  {  	unsigned long phy_rate = clk_get_rate(imx6_pcie->pcie_phy);  	int mult, div; -	u32 val; +	u16 val;  	if (!(imx6_pcie->drvdata->flags & IMX6_PCIE_FLAG_IMX6_PHY))  		return 0; @@ -730,21 +718,6 @@ static int imx6_setup_phy_mpll(struct imx6_pcie *imx6_pcie)  	return 0;  } -static int imx6_pcie_wait_for_link(struct imx6_pcie *imx6_pcie) -{ -	struct dw_pcie *pci = imx6_pcie->pci; -	struct device *dev = pci->dev; - -	/* check if the link is up or not */ -	if (!dw_pcie_wait_for_link(pci)) -		return 0; - -	dev_dbg(dev, "DEBUG_R0: 0x%08x, DEBUG_R1: 0x%08x\n", -		dw_pcie_readl_dbi(pci, PCIE_PHY_DEBUG_R0), -		dw_pcie_readl_dbi(pci, PCIE_PHY_DEBUG_R1)); -	return -ETIMEDOUT; -} -  static int imx6_pcie_wait_for_speed_change(struct imx6_pcie *imx6_pcie)  {  	struct dw_pcie *pci = imx6_pcie->pci; @@ -761,7 +734,7 @@ static int imx6_pcie_wait_for_speed_change(struct imx6_pcie *imx6_pcie)  	}  	dev_err(dev, "Speed change timeout\n"); -	return -EINVAL; +	return -ETIMEDOUT;  }  static void imx6_pcie_ltssm_enable(struct device *dev) @@ -803,7 +776,7 @@ static int imx6_pcie_establish_link(struct imx6_pcie *imx6_pcie)  	/* Start LTSSM. */  	imx6_pcie_ltssm_enable(dev); -	ret = imx6_pcie_wait_for_link(imx6_pcie); +	ret = dw_pcie_wait_for_link(pci);  	if (ret)  		goto err_reset_phy; @@ -841,7 +814,7 @@ static int imx6_pcie_establish_link(struct imx6_pcie *imx6_pcie)  		}  		/* Make sure link training is finished as well! */ -		ret = imx6_pcie_wait_for_link(imx6_pcie); +		ret = dw_pcie_wait_for_link(pci);  		if (ret) {  			dev_err(dev, "Failed to bring link up!\n");  			goto err_reset_phy; @@ -856,8 +829,8 @@ static int imx6_pcie_establish_link(struct imx6_pcie *imx6_pcie)  err_reset_phy:  	dev_dbg(dev, "PHY DEBUG_R0=0x%08x DEBUG_R1=0x%08x\n", -		dw_pcie_readl_dbi(pci, PCIE_PHY_DEBUG_R0), -		dw_pcie_readl_dbi(pci, PCIE_PHY_DEBUG_R1)); +		dw_pcie_readl_dbi(pci, PCIE_PORT_DEBUG0), +		dw_pcie_readl_dbi(pci, PCIE_PORT_DEBUG1));  	imx6_pcie_reset_phy(imx6_pcie);  	return ret;  } @@ -993,17 +966,11 @@ static void imx6_pcie_clk_disable(struct imx6_pcie *imx6_pcie)  	}  } -static inline bool imx6_pcie_supports_suspend(struct imx6_pcie *imx6_pcie) -{ -	return (imx6_pcie->drvdata->variant == IMX7D || -		imx6_pcie->drvdata->variant == IMX6SX); -} -  static int imx6_pcie_suspend_noirq(struct device *dev)  {  	struct imx6_pcie *imx6_pcie = dev_get_drvdata(dev); -	if (!imx6_pcie_supports_suspend(imx6_pcie)) +	if (!(imx6_pcie->drvdata->flags & IMX6_PCIE_FLAG_SUPPORTS_SUSPEND))  		return 0;  	imx6_pcie_pm_turnoff(imx6_pcie); @@ -1019,7 +986,7 @@ static int imx6_pcie_resume_noirq(struct device *dev)  	struct imx6_pcie *imx6_pcie = dev_get_drvdata(dev);  	struct pcie_port *pp = &imx6_pcie->pci->pp; -	if (!imx6_pcie_supports_suspend(imx6_pcie)) +	if (!(imx6_pcie->drvdata->flags & IMX6_PCIE_FLAG_SUPPORTS_SUSPEND))  		return 0;  	imx6_pcie_assert_core_reset(imx6_pcie); @@ -1249,7 +1216,8 @@ static const struct imx6_pcie_drvdata drvdata[] = {  	[IMX6SX] = {  		.variant = IMX6SX,  		.flags = IMX6_PCIE_FLAG_IMX6_PHY | -			 IMX6_PCIE_FLAG_IMX6_SPEED_CHANGE, +			 IMX6_PCIE_FLAG_IMX6_SPEED_CHANGE | +			 IMX6_PCIE_FLAG_SUPPORTS_SUSPEND,  	},  	[IMX6QP] = {  		.variant = IMX6QP, @@ -1258,6 +1226,7 @@ static const struct imx6_pcie_drvdata drvdata[] = {  	},  	[IMX7D] = {  		.variant = IMX7D, +		.flags = IMX6_PCIE_FLAG_SUPPORTS_SUSPEND,  	},  	[IMX8MQ] = {  		.variant = IMX8MQ, @@ -1279,6 +1248,7 @@ static struct platform_driver imx6_pcie_driver = {  		.of_match_table = imx6_pcie_of_match,  		.suppress_bind_attrs = true,  		.pm = &imx6_pcie_pm_ops, +		.probe_type = PROBE_PREFER_ASYNCHRONOUS,  	},  	.probe    = imx6_pcie_probe,  	.shutdown = imx6_pcie_shutdown, |