diff options
| author | Ingo Molnar <mingo@kernel.org> | 2024-03-25 13:32:29 +0300 | 
|---|---|---|
| committer | Ingo Molnar <mingo@kernel.org> | 2024-03-25 13:32:29 +0300 | 
| commit | f4566a1e73957800df75a3dd2dccee8a4697f327 (patch) | |
| tree | b043b875228c0b25988af66c680d60cae69d761d /drivers/pci/controller/dwc/pci-imx6.c | |
| parent | b9e6e28663928cab836a19abbdec3d036a07db3b (diff) | |
| parent | 4cece764965020c22cff7665b18a012006359095 (diff) | |
| download | linux-f4566a1e73957800df75a3dd2dccee8a4697f327.tar.xz | |
Merge tag 'v6.9-rc1' into sched/core, to pick up fixes and to refresh the branch
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'drivers/pci/controller/dwc/pci-imx6.c')
| -rw-r--r-- | drivers/pci/controller/dwc/pci-imx6.c | 630 | 
1 files changed, 354 insertions, 276 deletions
diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index dc2c036ab28c..99a60270b26c 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -42,6 +42,19 @@  #define IMX8MQ_GPR12_PCIE2_CTRL_DEVICE_TYPE	GENMASK(11, 8)  #define IMX8MQ_PCIE2_BASE_ADDR			0x33c00000 +#define IMX95_PCIE_PHY_GEN_CTRL			0x0 +#define IMX95_PCIE_REF_USE_PAD			BIT(17) + +#define IMX95_PCIE_SS_RW_REG_0			0xf0 +#define IMX95_PCIE_REF_CLKEN			BIT(23) +#define IMX95_PCIE_PHY_CR_PARA_SEL		BIT(9) + +#define IMX95_PE0_GEN_CTRL_1			0x1050 +#define IMX95_PCIE_DEVICE_TYPE			GENMASK(3, 0) + +#define IMX95_PE0_GEN_CTRL_3			0x1058 +#define IMX95_PCIE_LTSSM_EN			BIT(0) +  #define to_imx6_pcie(x)	dev_get_drvdata((x)->dev)  enum imx6_pcie_variants { @@ -52,14 +65,29 @@ enum imx6_pcie_variants {  	IMX8MQ,  	IMX8MM,  	IMX8MP, +	IMX95,  	IMX8MQ_EP,  	IMX8MM_EP,  	IMX8MP_EP, +	IMX95_EP,  };  #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) +#define IMX6_PCIE_FLAG_HAS_PHYDRV			BIT(3) +#define IMX6_PCIE_FLAG_HAS_APP_RESET		BIT(4) +#define IMX6_PCIE_FLAG_HAS_PHY_RESET		BIT(5) +#define IMX6_PCIE_FLAG_HAS_SERDES		BIT(6) +#define IMX6_PCIE_FLAG_SUPPORT_64BIT		BIT(7) + +#define imx6_check_flag(pci, val)     (pci->drvdata->flags & val) + +#define IMX6_PCIE_MAX_CLKS       6 + +#define IMX6_PCIE_MAX_INSTANCES			2 + +struct imx6_pcie;  struct imx6_pcie_drvdata {  	enum imx6_pcie_variants variant; @@ -67,6 +95,14 @@ struct imx6_pcie_drvdata {  	u32 flags;  	int dbi_length;  	const char *gpr; +	const char * const *clk_names; +	const u32 clks_cnt; +	const u32 ltssm_off; +	const u32 ltssm_mask; +	const u32 mode_off[IMX6_PCIE_MAX_INSTANCES]; +	const u32 mode_mask[IMX6_PCIE_MAX_INSTANCES]; +	const struct pci_epc_features *epc_features; +	int (*init_phy)(struct imx6_pcie *pcie);  };  struct imx6_pcie { @@ -74,11 +110,7 @@ struct imx6_pcie {  	int			reset_gpio;  	bool			gpio_active_high;  	bool			link_is_up; -	struct clk		*pcie_bus; -	struct clk		*pcie_phy; -	struct clk		*pcie_inbound_axi; -	struct clk		*pcie; -	struct clk		*pcie_aux; +	struct clk_bulk_data	clks[IMX6_PCIE_MAX_CLKS];  	struct regmap		*iomuxc_gpr;  	u16			msi_ctrl;  	u32			controller_id; @@ -165,34 +197,44 @@ static unsigned int imx6_pcie_grp_offset(const struct imx6_pcie *imx6_pcie)  	return imx6_pcie->controller_id == 1 ? IOMUXC_GPR16 : IOMUXC_GPR14;  } +static int imx95_pcie_init_phy(struct imx6_pcie *imx6_pcie) +{ +	regmap_update_bits(imx6_pcie->iomuxc_gpr, +			IMX95_PCIE_SS_RW_REG_0, +			IMX95_PCIE_PHY_CR_PARA_SEL, +			IMX95_PCIE_PHY_CR_PARA_SEL); + +	regmap_update_bits(imx6_pcie->iomuxc_gpr, +			   IMX95_PCIE_PHY_GEN_CTRL, +			   IMX95_PCIE_REF_USE_PAD, 0); +	regmap_update_bits(imx6_pcie->iomuxc_gpr, +			   IMX95_PCIE_SS_RW_REG_0, +			   IMX95_PCIE_REF_CLKEN, +			   IMX95_PCIE_REF_CLKEN); + +	return 0; +} +  static void imx6_pcie_configure_type(struct imx6_pcie *imx6_pcie)  { -	unsigned int mask, val, mode; +	const struct imx6_pcie_drvdata *drvdata = imx6_pcie->drvdata; +	unsigned int mask, val, mode, id; -	if (imx6_pcie->drvdata->mode == DW_PCIE_EP_TYPE) +	if (drvdata->mode == DW_PCIE_EP_TYPE)  		mode = PCI_EXP_TYPE_ENDPOINT;  	else  		mode = PCI_EXP_TYPE_ROOT_PORT; -	switch (imx6_pcie->drvdata->variant) { -	case IMX8MQ: -	case IMX8MQ_EP: -		if (imx6_pcie->controller_id == 1) { -			mask = IMX8MQ_GPR12_PCIE2_CTRL_DEVICE_TYPE; -			val  = FIELD_PREP(IMX8MQ_GPR12_PCIE2_CTRL_DEVICE_TYPE, -					  mode); -		} else { -			mask = IMX6Q_GPR12_DEVICE_TYPE; -			val  = FIELD_PREP(IMX6Q_GPR12_DEVICE_TYPE, mode); -		} -		break; -	default: -		mask = IMX6Q_GPR12_DEVICE_TYPE; -		val  = FIELD_PREP(IMX6Q_GPR12_DEVICE_TYPE, mode); -		break; -	} +	id = imx6_pcie->controller_id; + +	/* If mode_mask[id] is zero, means each controller have its individual gpr */ +	if (!drvdata->mode_mask[id]) +		id = 0; + +	mask = drvdata->mode_mask[id]; +	val = mode << (ffs(mask) - 1); -	regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, mask, val); +	regmap_update_bits(imx6_pcie->iomuxc_gpr, drvdata->mode_off[id], mask, val);  }  static int pcie_phy_poll_ack(struct imx6_pcie *imx6_pcie, bool exp_val) @@ -320,76 +362,66 @@ static int pcie_phy_write(struct imx6_pcie *imx6_pcie, int addr, u16 data)  	return 0;  } -static void imx6_pcie_init_phy(struct imx6_pcie *imx6_pcie) +static int imx8mq_pcie_init_phy(struct imx6_pcie *imx6_pcie)  { -	switch (imx6_pcie->drvdata->variant) { -	case IMX8MM: -	case IMX8MM_EP: -	case IMX8MP: -	case IMX8MP_EP: -		/* -		 * The PHY initialization had been done in the PHY -		 * driver, break here directly. -		 */ -		break; -	case IMX8MQ: -	case IMX8MQ_EP: -		/* -		 * TODO: Currently this code assumes external -		 * oscillator is being used -		 */ +	/* TODO: Currently this code assumes external oscillator is being used */ +	regmap_update_bits(imx6_pcie->iomuxc_gpr, +			   imx6_pcie_grp_offset(imx6_pcie), +			   IMX8MQ_GPR_PCIE_REF_USE_PAD, +			   IMX8MQ_GPR_PCIE_REF_USE_PAD); +	/* +	 * Regarding the datasheet, the PCIE_VPH is suggested to be 1.8V. If the PCIE_VPH is +	 * supplied by 3.3V, the VREG_BYPASS should be cleared to zero. +	 */ +	if (imx6_pcie->vph && regulator_get_voltage(imx6_pcie->vph) > 3000000)  		regmap_update_bits(imx6_pcie->iomuxc_gpr,  				   imx6_pcie_grp_offset(imx6_pcie), -				   IMX8MQ_GPR_PCIE_REF_USE_PAD, -				   IMX8MQ_GPR_PCIE_REF_USE_PAD); -		/* -		 * Regarding the datasheet, the PCIE_VPH is suggested -		 * to be 1.8V. If the PCIE_VPH is supplied by 3.3V, the -		 * VREG_BYPASS should be cleared to zero. -		 */ -		if (imx6_pcie->vph && -		    regulator_get_voltage(imx6_pcie->vph) > 3000000) -			regmap_update_bits(imx6_pcie->iomuxc_gpr, -					   imx6_pcie_grp_offset(imx6_pcie), -					   IMX8MQ_GPR_PCIE_VREG_BYPASS, -					   0); -		break; -	case IMX7D: -		regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, -				   IMX7D_GPR12_PCIE_PHY_REFCLK_SEL, 0); -		break; -	case IMX6SX: -		regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, -				   IMX6SX_GPR12_PCIE_RX_EQ_MASK, -				   IMX6SX_GPR12_PCIE_RX_EQ_2); -		fallthrough; -	default: -		regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, +				   IMX8MQ_GPR_PCIE_VREG_BYPASS, +				   0); + +	return 0; +} + +static int imx7d_pcie_init_phy(struct imx6_pcie *imx6_pcie) +{ +	regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, IMX7D_GPR12_PCIE_PHY_REFCLK_SEL, 0); + +	return 0; +} + +static int imx6_pcie_init_phy(struct imx6_pcie *imx6_pcie) +{ +	regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,  				   IMX6Q_GPR12_PCIE_CTL_2, 0 << 10); -		/* configure constant input signal to the pcie ctrl and phy */ -		regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, -				   IMX6Q_GPR12_LOS_LEVEL, 9 << 4); - -		regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR8, -				   IMX6Q_GPR8_TX_DEEMPH_GEN1, -				   imx6_pcie->tx_deemph_gen1 << 0); -		regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR8, -				   IMX6Q_GPR8_TX_DEEMPH_GEN2_3P5DB, -				   imx6_pcie->tx_deemph_gen2_3p5db << 6); -		regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR8, -				   IMX6Q_GPR8_TX_DEEMPH_GEN2_6DB, -				   imx6_pcie->tx_deemph_gen2_6db << 12); -		regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR8, -				   IMX6Q_GPR8_TX_SWING_FULL, -				   imx6_pcie->tx_swing_full << 18); -		regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR8, -				   IMX6Q_GPR8_TX_SWING_LOW, -				   imx6_pcie->tx_swing_low << 25); -		break; -	} +	/* configure constant input signal to the pcie ctrl and phy */ +	regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, +			   IMX6Q_GPR12_LOS_LEVEL, 9 << 4); + +	regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR8, +			   IMX6Q_GPR8_TX_DEEMPH_GEN1, +			   imx6_pcie->tx_deemph_gen1 << 0); +	regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR8, +			   IMX6Q_GPR8_TX_DEEMPH_GEN2_3P5DB, +			   imx6_pcie->tx_deemph_gen2_3p5db << 6); +	regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR8, +			   IMX6Q_GPR8_TX_DEEMPH_GEN2_6DB, +			   imx6_pcie->tx_deemph_gen2_6db << 12); +	regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR8, +			   IMX6Q_GPR8_TX_SWING_FULL, +			   imx6_pcie->tx_swing_full << 18); +	regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR8, +			   IMX6Q_GPR8_TX_SWING_LOW, +			   imx6_pcie->tx_swing_low << 25); +	return 0; +} -	imx6_pcie_configure_type(imx6_pcie); +static int imx6sx_pcie_init_phy(struct imx6_pcie *imx6_pcie) +{ +	regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, +			   IMX6SX_GPR12_PCIE_RX_EQ_MASK, IMX6SX_GPR12_PCIE_RX_EQ_2); + +	return imx6_pcie_init_phy(imx6_pcie);  }  static void imx7d_pcie_wait_for_phy_pll_lock(struct imx6_pcie *imx6_pcie) @@ -407,13 +439,18 @@ static void imx7d_pcie_wait_for_phy_pll_lock(struct imx6_pcie *imx6_pcie)  static int imx6_setup_phy_mpll(struct imx6_pcie *imx6_pcie)  { -	unsigned long phy_rate = clk_get_rate(imx6_pcie->pcie_phy); +	unsigned long phy_rate = 0;  	int mult, div;  	u16 val; +	int i;  	if (!(imx6_pcie->drvdata->flags & IMX6_PCIE_FLAG_IMX6_PHY))  		return 0; +	for (i = 0; i < imx6_pcie->drvdata->clks_cnt; i++) +		if (strncmp(imx6_pcie->clks[i].id, "pcie_phy", 8) == 0) +			phy_rate = clk_get_rate(imx6_pcie->clks[i].clk); +  	switch (phy_rate) {  	case 125000000:  		/* @@ -550,19 +587,11 @@ static int imx6_pcie_attach_pd(struct device *dev)  static int imx6_pcie_enable_ref_clk(struct imx6_pcie *imx6_pcie)  { -	struct dw_pcie *pci = imx6_pcie->pci; -	struct device *dev = pci->dev;  	unsigned int offset;  	int ret = 0;  	switch (imx6_pcie->drvdata->variant) {  	case IMX6SX: -		ret = clk_prepare_enable(imx6_pcie->pcie_inbound_axi); -		if (ret) { -			dev_err(dev, "unable to enable pcie_axi clock\n"); -			break; -		} -  		regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,  				   IMX6SX_GPR12_PCIE_TEST_POWERDOWN, 0);  		break; @@ -582,6 +611,8 @@ static int imx6_pcie_enable_ref_clk(struct imx6_pcie *imx6_pcie)  				   IMX6Q_GPR1_PCIE_REF_CLK_EN, 1 << 16);  		break;  	case IMX7D: +	case IMX95: +	case IMX95_EP:  		break;  	case IMX8MM:  	case IMX8MM_EP: @@ -589,12 +620,6 @@ static int imx6_pcie_enable_ref_clk(struct imx6_pcie *imx6_pcie)  	case IMX8MQ_EP:  	case IMX8MP:  	case IMX8MP_EP: -		ret = clk_prepare_enable(imx6_pcie->pcie_aux); -		if (ret) { -			dev_err(dev, "unable to enable pcie_aux clock\n"); -			break; -		} -  		offset = imx6_pcie_grp_offset(imx6_pcie);  		/*  		 * Set the over ride low and enabled @@ -615,9 +640,6 @@ static int imx6_pcie_enable_ref_clk(struct imx6_pcie *imx6_pcie)  static void imx6_pcie_disable_ref_clk(struct imx6_pcie *imx6_pcie)  {  	switch (imx6_pcie->drvdata->variant) { -	case IMX6SX: -		clk_disable_unprepare(imx6_pcie->pcie_inbound_axi); -		break;  	case IMX6QP:  	case IMX6Q:  		regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1, @@ -631,14 +653,6 @@ static void imx6_pcie_disable_ref_clk(struct imx6_pcie *imx6_pcie)  				   IMX7D_GPR12_PCIE_PHY_REFCLK_SEL,  				   IMX7D_GPR12_PCIE_PHY_REFCLK_SEL);  		break; -	case IMX8MM: -	case IMX8MM_EP: -	case IMX8MQ: -	case IMX8MQ_EP: -	case IMX8MP: -	case IMX8MP_EP: -		clk_disable_unprepare(imx6_pcie->pcie_aux); -		break;  	default:  		break;  	} @@ -650,23 +664,9 @@ static int imx6_pcie_clk_enable(struct imx6_pcie *imx6_pcie)  	struct device *dev = pci->dev;  	int ret; -	ret = clk_prepare_enable(imx6_pcie->pcie_phy); -	if (ret) { -		dev_err(dev, "unable to enable pcie_phy clock\n"); +	ret = clk_bulk_prepare_enable(imx6_pcie->drvdata->clks_cnt, imx6_pcie->clks); +	if (ret)  		return ret; -	} - -	ret = clk_prepare_enable(imx6_pcie->pcie_bus); -	if (ret) { -		dev_err(dev, "unable to enable pcie_bus clock\n"); -		goto err_pcie_bus; -	} - -	ret = clk_prepare_enable(imx6_pcie->pcie); -	if (ret) { -		dev_err(dev, "unable to enable pcie clock\n"); -		goto err_pcie; -	}  	ret = imx6_pcie_enable_ref_clk(imx6_pcie);  	if (ret) { @@ -679,11 +679,7 @@ static int imx6_pcie_clk_enable(struct imx6_pcie *imx6_pcie)  	return 0;  err_ref_clk: -	clk_disable_unprepare(imx6_pcie->pcie); -err_pcie: -	clk_disable_unprepare(imx6_pcie->pcie_bus); -err_pcie_bus: -	clk_disable_unprepare(imx6_pcie->pcie_phy); +	clk_bulk_disable_unprepare(imx6_pcie->drvdata->clks_cnt, imx6_pcie->clks);  	return ret;  } @@ -691,25 +687,15 @@ err_pcie_bus:  static void imx6_pcie_clk_disable(struct imx6_pcie *imx6_pcie)  {  	imx6_pcie_disable_ref_clk(imx6_pcie); -	clk_disable_unprepare(imx6_pcie->pcie); -	clk_disable_unprepare(imx6_pcie->pcie_bus); -	clk_disable_unprepare(imx6_pcie->pcie_phy); +	clk_bulk_disable_unprepare(imx6_pcie->drvdata->clks_cnt, imx6_pcie->clks);  }  static void imx6_pcie_assert_core_reset(struct imx6_pcie *imx6_pcie)  { +	reset_control_assert(imx6_pcie->pciephy_reset); +	reset_control_assert(imx6_pcie->apps_reset); +  	switch (imx6_pcie->drvdata->variant) { -	case IMX7D: -	case IMX8MQ: -	case IMX8MQ_EP: -		reset_control_assert(imx6_pcie->pciephy_reset); -		fallthrough; -	case IMX8MM: -	case IMX8MM_EP: -	case IMX8MP: -	case IMX8MP_EP: -		reset_control_assert(imx6_pcie->apps_reset); -		break;  	case IMX6SX:  		regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,  				   IMX6SX_GPR12_PCIE_TEST_POWERDOWN, @@ -730,6 +716,8 @@ static void imx6_pcie_assert_core_reset(struct imx6_pcie *imx6_pcie)  		regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1,  				   IMX6Q_GPR1_PCIE_REF_CLK_EN, 0 << 16);  		break; +	default: +		break;  	}  	/* Some boards don't have PCIe reset GPIO. */ @@ -743,14 +731,10 @@ static int imx6_pcie_deassert_core_reset(struct imx6_pcie *imx6_pcie)  	struct dw_pcie *pci = imx6_pcie->pci;  	struct device *dev = pci->dev; +	reset_control_deassert(imx6_pcie->pciephy_reset); +  	switch (imx6_pcie->drvdata->variant) { -	case IMX8MQ: -	case IMX8MQ_EP: -		reset_control_deassert(imx6_pcie->pciephy_reset); -		break;  	case IMX7D: -		reset_control_deassert(imx6_pcie->pciephy_reset); -  		/* Workaround for ERR010728, failure of PCI-e PLL VCO to  		 * oscillate, especially when cold.  This turns off "Duty-cycle  		 * Corrector" and other mysterious undocumented things. @@ -782,11 +766,7 @@ static int imx6_pcie_deassert_core_reset(struct imx6_pcie *imx6_pcie)  		usleep_range(200, 500);  		break; -	case IMX6Q:		/* Nothing to do */ -	case IMX8MM: -	case IMX8MM_EP: -	case IMX8MP: -	case IMX8MP_EP: +	default:  		break;  	} @@ -824,48 +804,25 @@ static int imx6_pcie_wait_for_speed_change(struct imx6_pcie *imx6_pcie)  static void imx6_pcie_ltssm_enable(struct device *dev)  {  	struct imx6_pcie *imx6_pcie = dev_get_drvdata(dev); +	const struct imx6_pcie_drvdata *drvdata = imx6_pcie->drvdata; -	switch (imx6_pcie->drvdata->variant) { -	case IMX6Q: -	case IMX6SX: -	case IMX6QP: -		regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, -				   IMX6Q_GPR12_PCIE_CTL_2, -				   IMX6Q_GPR12_PCIE_CTL_2); -		break; -	case IMX7D: -	case IMX8MQ: -	case IMX8MQ_EP: -	case IMX8MM: -	case IMX8MM_EP: -	case IMX8MP: -	case IMX8MP_EP: -		reset_control_deassert(imx6_pcie->apps_reset); -		break; -	} +	if (drvdata->ltssm_mask) +		regmap_update_bits(imx6_pcie->iomuxc_gpr, drvdata->ltssm_off, drvdata->ltssm_mask, +				   drvdata->ltssm_mask); + +	reset_control_deassert(imx6_pcie->apps_reset);  }  static void imx6_pcie_ltssm_disable(struct device *dev)  {  	struct imx6_pcie *imx6_pcie = dev_get_drvdata(dev); +	const struct imx6_pcie_drvdata *drvdata = imx6_pcie->drvdata; -	switch (imx6_pcie->drvdata->variant) { -	case IMX6Q: -	case IMX6SX: -	case IMX6QP: -		regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, -				   IMX6Q_GPR12_PCIE_CTL_2, 0); -		break; -	case IMX7D: -	case IMX8MQ: -	case IMX8MQ_EP: -	case IMX8MM: -	case IMX8MM_EP: -	case IMX8MP: -	case IMX8MP_EP: -		reset_control_assert(imx6_pcie->apps_reset); -		break; -	} +	if (drvdata->ltssm_mask) +		regmap_update_bits(imx6_pcie->iomuxc_gpr, drvdata->ltssm_off, +				   drvdata->ltssm_mask, 0); + +	reset_control_assert(imx6_pcie->apps_reset);  }  static int imx6_pcie_start_link(struct dw_pcie *pci) @@ -977,7 +934,11 @@ static int imx6_pcie_host_init(struct dw_pcie_rp *pp)  	}  	imx6_pcie_assert_core_reset(imx6_pcie); -	imx6_pcie_init_phy(imx6_pcie); + +	if (imx6_pcie->drvdata->init_phy) +		imx6_pcie->drvdata->init_phy(imx6_pcie); + +	imx6_pcie_configure_type(imx6_pcie);  	ret = imx6_pcie_clk_enable(imx6_pcie);  	if (ret) { @@ -1081,14 +1042,35 @@ static const struct pci_epc_features imx8m_pcie_epc_features = {  	.linkup_notifier = false,  	.msi_capable = true,  	.msix_capable = false, -	.reserved_bar = 1 << BAR_1 | 1 << BAR_3, +	.bar[BAR_1] = { .type = BAR_RESERVED, }, +	.bar[BAR_3] = { .type = BAR_RESERVED, },  	.align = SZ_64K,  }; +/* + * BAR#	| Default BAR enable	| Default BAR Type	| Default BAR Size	| BAR Sizing Scheme + * ================================================================================================ + * BAR0	| Enable		| 64-bit		| 1 MB			| Programmable Size + * BAR1	| Disable		| 32-bit		| 64 KB			| Fixed Size + *        BAR1 should be disabled if BAR0 is 64bit. + * BAR2	| Enable		| 32-bit		| 1 MB			| Programmable Size + * BAR3	| Enable		| 32-bit		| 64 KB			| Programmable Size + * BAR4	| Enable		| 32-bit		| 1M			| Programmable Size + * BAR5	| Enable		| 32-bit		| 64 KB			| Programmable Size + */ +static const struct pci_epc_features imx95_pcie_epc_features = { +	.msi_capable = true, +	.bar[BAR_1] = { .type = BAR_FIXED, .fixed_size = SZ_64K, }, +	.align = SZ_4K, +}; +  static const struct pci_epc_features*  imx6_pcie_ep_get_features(struct dw_pcie_ep *ep)  { -	return &imx8m_pcie_epc_features; +	struct dw_pcie *pci = to_dw_pcie_from_ep(ep); +	struct imx6_pcie *imx6_pcie = to_imx6_pcie(pci); + +	return imx6_pcie->drvdata->epc_features;  }  static const struct dw_pcie_ep_ops pcie_ep_ops = { @@ -1103,7 +1085,6 @@ static int imx6_add_pcie_ep(struct imx6_pcie *imx6_pcie,  	int ret;  	unsigned int pcie_dbi2_offset;  	struct dw_pcie_ep *ep; -	struct resource *res;  	struct dw_pcie *pci = imx6_pcie->pci;  	struct dw_pcie_rp *pp = &pci->pp;  	struct device *dev = pci->dev; @@ -1122,14 +1103,20 @@ static int imx6_add_pcie_ep(struct imx6_pcie *imx6_pcie,  		pcie_dbi2_offset = SZ_4K;  		break;  	} +  	pci->dbi_base2 = pci->dbi_base + pcie_dbi2_offset; -	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "addr_space"); -	if (!res) -		return -EINVAL; -	ep->phys_base = res->start; -	ep->addr_size = resource_size(res); -	ep->page_size = SZ_64K; +	/* +	 * FIXME: Ideally, dbi2 base address should come from DT. But since only IMX95 is defining +	 * "dbi2" in DT, "dbi_base2" is set to NULL here for that platform alone so that the DWC +	 * core code can fetch that from DT. But once all platform DTs were fixed, this and the +	 * above "dbi_base2" setting should be removed. +	 */ +	if (device_property_match_string(dev, "reg-names", "dbi2") >= 0) +		pci->dbi_base2 = NULL; + +	if (imx6_check_flag(imx6_pcie, IMX6_PCIE_FLAG_SUPPORT_64BIT)) +		dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64));  	ret = dw_pcie_ep_init(ep);  	if (ret) { @@ -1251,6 +1238,7 @@ static int imx6_pcie_probe(struct platform_device *pdev)  	struct device_node *node = dev->of_node;  	int ret;  	u16 val; +	int i;  	imx6_pcie = devm_kzalloc(dev, sizeof(*imx6_pcie), GFP_KERNEL);  	if (!imx6_pcie) @@ -1304,81 +1292,48 @@ static int imx6_pcie_probe(struct platform_device *pdev)  		return imx6_pcie->reset_gpio;  	} -	/* Fetch clocks */ -	imx6_pcie->pcie_bus = devm_clk_get(dev, "pcie_bus"); -	if (IS_ERR(imx6_pcie->pcie_bus)) -		return dev_err_probe(dev, PTR_ERR(imx6_pcie->pcie_bus), -				     "pcie_bus clock source missing or invalid\n"); +	if (imx6_pcie->drvdata->clks_cnt >= IMX6_PCIE_MAX_CLKS) +		return dev_err_probe(dev, -ENOMEM, "clks_cnt is too big\n"); -	imx6_pcie->pcie = devm_clk_get(dev, "pcie"); -	if (IS_ERR(imx6_pcie->pcie)) -		return dev_err_probe(dev, PTR_ERR(imx6_pcie->pcie), -				     "pcie clock source missing or invalid\n"); +	for (i = 0; i < imx6_pcie->drvdata->clks_cnt; i++) +		imx6_pcie->clks[i].id = imx6_pcie->drvdata->clk_names[i]; -	switch (imx6_pcie->drvdata->variant) { -	case IMX6SX: -		imx6_pcie->pcie_inbound_axi = devm_clk_get(dev, -							   "pcie_inbound_axi"); -		if (IS_ERR(imx6_pcie->pcie_inbound_axi)) -			return dev_err_probe(dev, PTR_ERR(imx6_pcie->pcie_inbound_axi), -					     "pcie_inbound_axi clock missing or invalid\n"); -		break; -	case IMX8MQ: -	case IMX8MQ_EP: -		imx6_pcie->pcie_aux = devm_clk_get(dev, "pcie_aux"); -		if (IS_ERR(imx6_pcie->pcie_aux)) -			return dev_err_probe(dev, PTR_ERR(imx6_pcie->pcie_aux), -					     "pcie_aux clock source missing or invalid\n"); -		fallthrough; -	case IMX7D: -		if (dbi_base->start == IMX8MQ_PCIE2_BASE_ADDR) -			imx6_pcie->controller_id = 1; +	/* Fetch clocks */ +	ret = devm_clk_bulk_get(dev, imx6_pcie->drvdata->clks_cnt, imx6_pcie->clks); +	if (ret) +		return ret; -		imx6_pcie->pciephy_reset = devm_reset_control_get_exclusive(dev, -									    "pciephy"); -		if (IS_ERR(imx6_pcie->pciephy_reset)) { -			dev_err(dev, "Failed to get PCIEPHY reset control\n"); -			return PTR_ERR(imx6_pcie->pciephy_reset); -		} +	if (imx6_check_flag(imx6_pcie, IMX6_PCIE_FLAG_HAS_PHYDRV)) { +		imx6_pcie->phy = devm_phy_get(dev, "pcie-phy"); +		if (IS_ERR(imx6_pcie->phy)) +			return dev_err_probe(dev, PTR_ERR(imx6_pcie->phy), +					     "failed to get pcie phy\n"); +	} -		imx6_pcie->apps_reset = devm_reset_control_get_exclusive(dev, -									 "apps"); -		if (IS_ERR(imx6_pcie->apps_reset)) { -			dev_err(dev, "Failed to get PCIE APPS reset control\n"); -			return PTR_ERR(imx6_pcie->apps_reset); -		} -		break; -	case IMX8MM: -	case IMX8MM_EP: -	case IMX8MP: -	case IMX8MP_EP: -		imx6_pcie->pcie_aux = devm_clk_get(dev, "pcie_aux"); -		if (IS_ERR(imx6_pcie->pcie_aux)) -			return dev_err_probe(dev, PTR_ERR(imx6_pcie->pcie_aux), -					     "pcie_aux clock source missing or invalid\n"); -		imx6_pcie->apps_reset = devm_reset_control_get_exclusive(dev, -									 "apps"); +	if (imx6_check_flag(imx6_pcie, IMX6_PCIE_FLAG_HAS_APP_RESET)) { +		imx6_pcie->apps_reset = devm_reset_control_get_exclusive(dev, "apps");  		if (IS_ERR(imx6_pcie->apps_reset))  			return dev_err_probe(dev, PTR_ERR(imx6_pcie->apps_reset),  					     "failed to get pcie apps reset control\n"); +	} -		imx6_pcie->phy = devm_phy_get(dev, "pcie-phy"); -		if (IS_ERR(imx6_pcie->phy)) -			return dev_err_probe(dev, PTR_ERR(imx6_pcie->phy), -					     "failed to get pcie phy\n"); +	if (imx6_check_flag(imx6_pcie, IMX6_PCIE_FLAG_HAS_PHY_RESET)) { +		imx6_pcie->pciephy_reset = devm_reset_control_get_exclusive(dev, "pciephy"); +		if (IS_ERR(imx6_pcie->pciephy_reset)) +			return dev_err_probe(dev, PTR_ERR(imx6_pcie->pciephy_reset), +					     "Failed to get PCIEPHY reset control\n"); +	} +	switch (imx6_pcie->drvdata->variant) { +	case IMX8MQ: +	case IMX8MQ_EP: +	case IMX7D: +		if (dbi_base->start == IMX8MQ_PCIE2_BASE_ADDR) +			imx6_pcie->controller_id = 1;  		break;  	default:  		break;  	} -	/* Don't fetch the pcie_phy clock, if it has abstract PHY driver */ -	if (imx6_pcie->phy == NULL) { -		imx6_pcie->pcie_phy = devm_clk_get(dev, "pcie_phy"); -		if (IS_ERR(imx6_pcie->pcie_phy)) -			return dev_err_probe(dev, PTR_ERR(imx6_pcie->pcie_phy), -					     "pcie_phy clock source missing or invalid\n"); -	} -  	/* Grab turnoff reset */  	imx6_pcie->turnoff_reset = devm_reset_control_get_optional_exclusive(dev, "turnoff"); @@ -1387,12 +1342,32 @@ static int imx6_pcie_probe(struct platform_device *pdev)  		return PTR_ERR(imx6_pcie->turnoff_reset);  	} +	if (imx6_pcie->drvdata->gpr) {  	/* Grab GPR config register range */ -	imx6_pcie->iomuxc_gpr = -		 syscon_regmap_lookup_by_compatible(imx6_pcie->drvdata->gpr); -	if (IS_ERR(imx6_pcie->iomuxc_gpr)) { -		dev_err(dev, "unable to find iomuxc registers\n"); -		return PTR_ERR(imx6_pcie->iomuxc_gpr); +		imx6_pcie->iomuxc_gpr = +			 syscon_regmap_lookup_by_compatible(imx6_pcie->drvdata->gpr); +		if (IS_ERR(imx6_pcie->iomuxc_gpr)) +			return dev_err_probe(dev, PTR_ERR(imx6_pcie->iomuxc_gpr), +					     "unable to find iomuxc registers\n"); +	} + +	if (imx6_check_flag(imx6_pcie, IMX6_PCIE_FLAG_HAS_SERDES)) { +		void __iomem *off = devm_platform_ioremap_resource_byname(pdev, "app"); + +		if (IS_ERR(off)) +			return dev_err_probe(dev, PTR_ERR(off), +					     "unable to find serdes registers\n"); + +		static const struct regmap_config regmap_config = { +			.reg_bits = 32, +			.val_bits = 32, +			.reg_stride = 4, +		}; + +		imx6_pcie->iomuxc_gpr = devm_regmap_init_mmio(dev, off, ®map_config); +		if (IS_ERR(imx6_pcie->iomuxc_gpr)) +			return dev_err_probe(dev, PTR_ERR(imx6_pcie->iomuxc_gpr), +					     "unable to find iomuxc registers\n");  	}  	/* Grab PCIe PHY Tx Settings */ @@ -1469,6 +1444,11 @@ static void imx6_pcie_shutdown(struct platform_device *pdev)  	imx6_pcie_assert_core_reset(imx6_pcie);  } +static const char * const imx6q_clks[] = {"pcie_bus", "pcie", "pcie_phy"}; +static const char * const imx8mm_clks[] = {"pcie_bus", "pcie", "pcie_aux"}; +static const char * const imx8mq_clks[] = {"pcie_bus", "pcie", "pcie_phy", "pcie_aux"}; +static const char * const imx6sx_clks[] = {"pcie_bus", "pcie", "pcie_phy", "pcie_inbound_axi"}; +  static const struct imx6_pcie_drvdata drvdata[] = {  	[IMX6Q] = {  		.variant = IMX6Q, @@ -1476,6 +1456,13 @@ static const struct imx6_pcie_drvdata drvdata[] = {  			 IMX6_PCIE_FLAG_IMX6_SPEED_CHANGE,  		.dbi_length = 0x200,  		.gpr = "fsl,imx6q-iomuxc-gpr", +		.clk_names = imx6q_clks, +		.clks_cnt = ARRAY_SIZE(imx6q_clks), +		.ltssm_off = IOMUXC_GPR12, +		.ltssm_mask = IMX6Q_GPR12_PCIE_CTL_2, +		.mode_off[0] = IOMUXC_GPR12, +		.mode_mask[0] = IMX6Q_GPR12_DEVICE_TYPE, +		.init_phy = imx6_pcie_init_phy,  	},  	[IMX6SX] = {  		.variant = IMX6SX, @@ -1483,6 +1470,13 @@ static const struct imx6_pcie_drvdata drvdata[] = {  			 IMX6_PCIE_FLAG_IMX6_SPEED_CHANGE |  			 IMX6_PCIE_FLAG_SUPPORTS_SUSPEND,  		.gpr = "fsl,imx6q-iomuxc-gpr", +		.clk_names = imx6sx_clks, +		.clks_cnt = ARRAY_SIZE(imx6sx_clks), +		.ltssm_off = IOMUXC_GPR12, +		.ltssm_mask = IMX6Q_GPR12_PCIE_CTL_2, +		.mode_off[0] = IOMUXC_GPR12, +		.mode_mask[0] = IMX6Q_GPR12_DEVICE_TYPE, +		.init_phy = imx6sx_pcie_init_phy,  	},  	[IMX6QP] = {  		.variant = IMX6QP, @@ -1491,40 +1485,122 @@ static const struct imx6_pcie_drvdata drvdata[] = {  			 IMX6_PCIE_FLAG_SUPPORTS_SUSPEND,  		.dbi_length = 0x200,  		.gpr = "fsl,imx6q-iomuxc-gpr", +		.clk_names = imx6q_clks, +		.clks_cnt = ARRAY_SIZE(imx6q_clks), +		.ltssm_off = IOMUXC_GPR12, +		.ltssm_mask = IMX6Q_GPR12_PCIE_CTL_2, +		.mode_off[0] = IOMUXC_GPR12, +		.mode_mask[0] = IMX6Q_GPR12_DEVICE_TYPE, +		.init_phy = imx6_pcie_init_phy,  	},  	[IMX7D] = {  		.variant = IMX7D, -		.flags = IMX6_PCIE_FLAG_SUPPORTS_SUSPEND, +		.flags = IMX6_PCIE_FLAG_SUPPORTS_SUSPEND | +			 IMX6_PCIE_FLAG_HAS_APP_RESET | +			 IMX6_PCIE_FLAG_HAS_PHY_RESET,  		.gpr = "fsl,imx7d-iomuxc-gpr", +		.clk_names = imx6q_clks, +		.clks_cnt = ARRAY_SIZE(imx6q_clks), +		.mode_off[0] = IOMUXC_GPR12, +		.mode_mask[0] = IMX6Q_GPR12_DEVICE_TYPE, +		.init_phy = imx7d_pcie_init_phy,  	},  	[IMX8MQ] = {  		.variant = IMX8MQ, +		.flags = IMX6_PCIE_FLAG_HAS_APP_RESET | +			 IMX6_PCIE_FLAG_HAS_PHY_RESET,  		.gpr = "fsl,imx8mq-iomuxc-gpr", +		.clk_names = imx8mq_clks, +		.clks_cnt = ARRAY_SIZE(imx8mq_clks), +		.mode_off[0] = IOMUXC_GPR12, +		.mode_mask[0] = IMX6Q_GPR12_DEVICE_TYPE, +		.mode_off[1] = IOMUXC_GPR12, +		.mode_mask[1] = IMX8MQ_GPR12_PCIE2_CTRL_DEVICE_TYPE, +		.init_phy = imx8mq_pcie_init_phy,  	},  	[IMX8MM] = {  		.variant = IMX8MM, -		.flags = IMX6_PCIE_FLAG_SUPPORTS_SUSPEND, +		.flags = IMX6_PCIE_FLAG_SUPPORTS_SUSPEND | +			 IMX6_PCIE_FLAG_HAS_PHYDRV | +			 IMX6_PCIE_FLAG_HAS_APP_RESET,  		.gpr = "fsl,imx8mm-iomuxc-gpr", +		.clk_names = imx8mm_clks, +		.clks_cnt = ARRAY_SIZE(imx8mm_clks), +		.mode_off[0] = IOMUXC_GPR12, +		.mode_mask[0] = IMX6Q_GPR12_DEVICE_TYPE,  	},  	[IMX8MP] = {  		.variant = IMX8MP, -		.flags = IMX6_PCIE_FLAG_SUPPORTS_SUSPEND, +		.flags = IMX6_PCIE_FLAG_SUPPORTS_SUSPEND | +			 IMX6_PCIE_FLAG_HAS_PHYDRV | +			 IMX6_PCIE_FLAG_HAS_APP_RESET,  		.gpr = "fsl,imx8mp-iomuxc-gpr", +		.clk_names = imx8mm_clks, +		.clks_cnt = ARRAY_SIZE(imx8mm_clks), +		.mode_off[0] = IOMUXC_GPR12, +		.mode_mask[0] = IMX6Q_GPR12_DEVICE_TYPE, +	}, +	[IMX95] = { +		.variant = IMX95, +		.flags = IMX6_PCIE_FLAG_HAS_SERDES, +		.clk_names = imx8mq_clks, +		.clks_cnt = ARRAY_SIZE(imx8mq_clks), +		.ltssm_off = IMX95_PE0_GEN_CTRL_3, +		.ltssm_mask = IMX95_PCIE_LTSSM_EN, +		.mode_off[0]  = IMX95_PE0_GEN_CTRL_1, +		.mode_mask[0] = IMX95_PCIE_DEVICE_TYPE, +		.init_phy = imx95_pcie_init_phy,  	},  	[IMX8MQ_EP] = {  		.variant = IMX8MQ_EP, +		.flags = IMX6_PCIE_FLAG_HAS_APP_RESET | +			 IMX6_PCIE_FLAG_HAS_PHY_RESET,  		.mode = DW_PCIE_EP_TYPE,  		.gpr = "fsl,imx8mq-iomuxc-gpr", +		.clk_names = imx8mq_clks, +		.clks_cnt = ARRAY_SIZE(imx8mq_clks), +		.mode_off[0] = IOMUXC_GPR12, +		.mode_mask[0] = IMX6Q_GPR12_DEVICE_TYPE, +		.mode_off[1] = IOMUXC_GPR12, +		.mode_mask[1] = IMX8MQ_GPR12_PCIE2_CTRL_DEVICE_TYPE, +		.epc_features = &imx8m_pcie_epc_features, +		.init_phy = imx8mq_pcie_init_phy,  	},  	[IMX8MM_EP] = {  		.variant = IMX8MM_EP, +		.flags = IMX6_PCIE_FLAG_HAS_PHYDRV,  		.mode = DW_PCIE_EP_TYPE,  		.gpr = "fsl,imx8mm-iomuxc-gpr", +		.clk_names = imx8mm_clks, +		.clks_cnt = ARRAY_SIZE(imx8mm_clks), +		.mode_off[0] = IOMUXC_GPR12, +		.mode_mask[0] = IMX6Q_GPR12_DEVICE_TYPE, +		.epc_features = &imx8m_pcie_epc_features,  	},  	[IMX8MP_EP] = {  		.variant = IMX8MP_EP, +		.flags = IMX6_PCIE_FLAG_HAS_PHYDRV,  		.mode = DW_PCIE_EP_TYPE,  		.gpr = "fsl,imx8mp-iomuxc-gpr", +		.clk_names = imx8mm_clks, +		.clks_cnt = ARRAY_SIZE(imx8mm_clks), +		.mode_off[0] = IOMUXC_GPR12, +		.mode_mask[0] = IMX6Q_GPR12_DEVICE_TYPE, +		.epc_features = &imx8m_pcie_epc_features, +	}, +	[IMX95_EP] = { +		.variant = IMX95_EP, +		.flags = IMX6_PCIE_FLAG_HAS_SERDES | +			 IMX6_PCIE_FLAG_SUPPORT_64BIT, +		.clk_names = imx8mq_clks, +		.clks_cnt = ARRAY_SIZE(imx8mq_clks), +		.ltssm_off = IMX95_PE0_GEN_CTRL_3, +		.ltssm_mask = IMX95_PCIE_LTSSM_EN, +		.mode_off[0]  = IMX95_PE0_GEN_CTRL_1, +		.mode_mask[0] = IMX95_PCIE_DEVICE_TYPE, +		.init_phy = imx95_pcie_init_phy, +		.epc_features = &imx95_pcie_epc_features, +		.mode = DW_PCIE_EP_TYPE,  	},  }; @@ -1536,9 +1612,11 @@ static const struct of_device_id imx6_pcie_of_match[] = {  	{ .compatible = "fsl,imx8mq-pcie", .data = &drvdata[IMX8MQ], },  	{ .compatible = "fsl,imx8mm-pcie", .data = &drvdata[IMX8MM], },  	{ .compatible = "fsl,imx8mp-pcie", .data = &drvdata[IMX8MP], }, +	{ .compatible = "fsl,imx95-pcie", .data = &drvdata[IMX95], },  	{ .compatible = "fsl,imx8mq-pcie-ep", .data = &drvdata[IMX8MQ_EP], },  	{ .compatible = "fsl,imx8mm-pcie-ep", .data = &drvdata[IMX8MM_EP], },  	{ .compatible = "fsl,imx8mp-pcie-ep", .data = &drvdata[IMX8MP_EP], }, +	{ .compatible = "fsl,imx95-pcie-ep", .data = &drvdata[IMX95_EP], },  	{},  };  | 
