1
0
Fork 0

PCI: imx: enable imx8mm pcie support

Enable iMX8MM PCIe support.

Signed-off-by: Richard Zhu <hongxing.zhu@nxp.com>
5.4-rM2-2.2.x-imx-squashed
Richard Zhu 2019-08-20 05:13:21 -04:00 committed by Dong Aisheng
parent b71e692290
commit 46a288f17b
1 changed files with 155 additions and 52 deletions

View File

@ -51,6 +51,7 @@ enum imx6_pcie_variants {
IMX6QP,
IMX7D,
IMX8MQ,
IMX8MM,
IMX8QM,
IMX8QXP,
};
@ -167,6 +168,17 @@ struct imx6_pcie {
#define PCIE_PHY_CMN_REG26 0x98
#define PCIE_PHY_CMN_REG26_ATT_MODE 0xBC
#define PCIE_PHY_CMN_REG62 0x188
#define PCIE_PHY_CMN_REG62_PLL_CLK_OUT 0x08
#define PCIE_PHY_CMN_REG64 0x190
#define PCIE_PHY_CMN_REG64_AUX_RX_TX_TERM 0x8C
#define PCIE_PHY_CMN_REG75 0x1D4
#define PCIE_PHY_CMN_REG75_PLL_DONE 0x3
#define PCIE_PHY_TRSV_REG5 0x414
#define PCIE_PHY_TRSV_REG5_GEN1_DEEMP 0x2D
#define PCIE_PHY_TRSV_REG6 0x418
#define PCIE_PHY_TRSV_REG6_GEN2_DEEMP 0xF
#define PHY_RX_OVRD_IN_LO 0x1005
#define PHY_RX_OVRD_IN_LO_RX_DATA_EN BIT(5)
#define PHY_RX_OVRD_IN_LO_RX_PLL_EN BIT(3)
@ -208,6 +220,14 @@ struct imx6_pcie {
#define IMX8QM_MISC_PHYX1_EPCS_SEL BIT(12)
#define IMX8QM_MISC_PCIE_AB_SELECT BIT(13)
#define IMX8MM_GPR_PCIE_REF_CLK_SEL (0x3 << 24)
#define IMX8MM_GPR_PCIE_REF_CLK_PLL (0x3 << 24)
#define IMX8MM_GPR_PCIE_REF_CLK_EXT (0x2 << 24)
#define IMX8MM_GPR_PCIE_AUX_EN BIT(19)
#define IMX8MM_GPR_PCIE_CMN_RST BIT(18)
#define IMX8MM_GPR_PCIE_POWER_OFF BIT(17)
#define IMX8MM_GPR_PCIE_SSC_EN BIT(16)
static bool imx6_pcie_readable_reg(struct device *dev, unsigned int reg)
{
enum imx6_pcie_variants variant;
@ -532,7 +552,6 @@ static int imx6_pcie_attach_pd(struct device *dev)
static unsigned int imx6_pcie_grp_offset(const struct imx6_pcie *imx6_pcie)
{
WARN_ON(imx6_pcie->drvdata->variant != IMX8MQ);
return imx6_pcie->controller_id == 1 ? IOMUXC_GPR16 : IOMUXC_GPR14;
}
@ -572,6 +591,7 @@ static int imx6_pcie_enable_ref_clk(struct imx6_pcie *imx6_pcie)
case IMX7D:
break;
case IMX8MQ:
case IMX8MM:
ret = clk_prepare_enable(imx6_pcie->pcie_aux);
if (ret) {
dev_err(dev, "unable to enable pcie_aux clock\n");
@ -635,52 +655,64 @@ static void imx7d_pcie_wait_for_phy_pll_lock(struct imx6_pcie *imx6_pcie)
PHY_PLL_LOCK_WAIT_TIMEOUT))
dev_err(dev, "PCIe PLL lock timeout\n");
}
static int imx8_hsio_pcie_wait_for_phy_pll_lock(struct imx6_pcie *imx6_pcie)
static void imx8_pcie_wait_for_phy_pll_lock(struct imx6_pcie *imx6_pcie)
{
u32 val, retries = 0, tmp = 0, orig = 0;
int ret;
struct dw_pcie *pci = imx6_pcie->pci;
struct device *dev = pci->dev;
for (retries = 0; retries < PHY_PLL_LOCK_WAIT_MAX_RETRIES; retries++) {
if (imx6_pcie->hsio_cfg == PCIEAX1PCIEBX1SATA) {
regmap_read(imx6_pcie->iomuxc_gpr,
IMX8QM_CSR_PHYX2_OFFSET + 0x4,
&tmp);
if (imx6_pcie->controller_id == 0) /* pciea 1 lanes */
orig = IMX8QM_STTS0_LANE0_TX_PLL_LOCK;
else /* pcieb 1 lanes */
orig = IMX8QM_STTS0_LANE1_TX_PLL_LOCK;
} else if (imx6_pcie->hsio_cfg == PCIEAX2PCIEBX1) {
val = IMX8QM_CSR_PHYX2_OFFSET
+ imx6_pcie->controller_id * SZ_64K;
regmap_read(imx6_pcie->iomuxc_gpr,
val + IMX8QM_CSR_PHYX_STTS0_OFFSET,
&tmp);
orig = IMX8QM_STTS0_LANE0_TX_PLL_LOCK;
if (imx6_pcie->controller_id == 0) /* pciea 2 lanes */
orig |= IMX8QM_STTS0_LANE1_TX_PLL_LOCK;
} else if (imx6_pcie->hsio_cfg == PCIEAX2SATA) {
regmap_read(imx6_pcie->iomuxc_gpr,
IMX8QM_CSR_PHYX2_OFFSET + 0x4,
&tmp);
orig = IMX8QM_STTS0_LANE0_TX_PLL_LOCK;
orig |= IMX8QM_STTS0_LANE1_TX_PLL_LOCK;
switch (imx6_pcie->drvdata->variant) {
case IMX8MM:
for (retries = 0; retries < PHY_PLL_LOCK_WAIT_MAX_RETRIES;
retries++) {
tmp = readl(imx6_pcie->phy_base + PCIE_PHY_CMN_REG75);
if (tmp == PCIE_PHY_CMN_REG75_PLL_DONE)
break;
udelay(10);
}
tmp &= orig;
if (tmp == orig)
break;
udelay(10);
break;
case IMX8QXP:
case IMX8QM:
for (retries = 0; retries < PHY_PLL_LOCK_WAIT_MAX_RETRIES;
retries++) {
if (imx6_pcie->hsio_cfg == PCIEAX1PCIEBX1SATA) {
regmap_read(imx6_pcie->iomuxc_gpr,
IMX8QM_CSR_PHYX2_OFFSET + 0x4,
&tmp);
if (imx6_pcie->controller_id == 0) /* pciea 1 lanes */
orig = IMX8QM_STTS0_LANE0_TX_PLL_LOCK;
else /* pcieb 1 lanes */
orig = IMX8QM_STTS0_LANE1_TX_PLL_LOCK;
} else if (imx6_pcie->hsio_cfg == PCIEAX2PCIEBX1) {
val = IMX8QM_CSR_PHYX2_OFFSET
+ imx6_pcie->controller_id * SZ_64K;
regmap_read(imx6_pcie->iomuxc_gpr,
val + IMX8QM_CSR_PHYX_STTS0_OFFSET,
&tmp);
orig = IMX8QM_STTS0_LANE0_TX_PLL_LOCK;
if (imx6_pcie->controller_id == 0) /* pciea 2 lanes */
orig |= IMX8QM_STTS0_LANE1_TX_PLL_LOCK;
} else if (imx6_pcie->hsio_cfg == PCIEAX2SATA) {
regmap_read(imx6_pcie->iomuxc_gpr,
IMX8QM_CSR_PHYX2_OFFSET + 0x4,
&tmp);
orig = IMX8QM_STTS0_LANE0_TX_PLL_LOCK;
orig |= IMX8QM_STTS0_LANE1_TX_PLL_LOCK;
}
tmp &= orig;
if (tmp == orig)
break;
udelay(10);
}
break;
default:
break;
}
if (retries >= PHY_PLL_LOCK_WAIT_MAX_RETRIES) {
dev_info(dev, "pcie phy pll can't be locked.\n");
ret = -ENODEV;
} else {
dev_info(dev, "pcie phy pll is locked.\n");
}
return ret;
if (retries >= PHY_PLL_LOCK_WAIT_MAX_RETRIES)
dev_err(dev, "PCIe PLL lock timeout\n");
}
static void imx6_pcie_clk_enable(struct imx6_pcie *imx6_pcie)
@ -725,6 +757,7 @@ static void imx6_pcie_clk_disable(struct imx6_pcie *imx6_pcie)
IMX7D_GPR12_PCIE_PHY_REFCLK_SEL);
break;
case IMX8MQ:
case IMX8MM:
clk_disable_unprepare(imx6_pcie->pcie_aux);
break;
case IMX8QXP:
@ -748,6 +781,7 @@ static void imx6_pcie_assert_core_reset(struct imx6_pcie *imx6_pcie)
switch (imx6_pcie->drvdata->variant) {
case IMX7D:
case IMX8MQ:
case IMX8MM:
reset_control_assert(imx6_pcie->pciephy_reset);
reset_control_assert(imx6_pcie->apps_reset);
break;
@ -870,13 +904,13 @@ static void imx6_pcie_deassert_core_reset(struct imx6_pcie *imx6_pcie)
dev_err(dev, "ERROR PM_REQ_CORE_RST is still set.\n");
/* wait for phy pll lock firstly. */
if (imx8_hsio_pcie_wait_for_phy_pll_lock(imx6_pcie)) {
ret = -ENODEV;
goto err_pcie_phy;
}
imx8_pcie_wait_for_phy_pll_lock(imx6_pcie);
break;
case IMX8MQ:
case IMX8MM:
reset_control_deassert(imx6_pcie->pciephy_reset);
imx8_pcie_wait_for_phy_pll_lock(imx6_pcie);
break;
case IMX7D:
reset_control_deassert(imx6_pcie->pciephy_reset);
@ -917,14 +951,6 @@ static void imx6_pcie_deassert_core_reset(struct imx6_pcie *imx6_pcie)
}
return;
err_pcie_phy:
if (imx6_pcie->vpcie && regulator_is_enabled(imx6_pcie->vpcie) > 0) {
ret = regulator_disable(imx6_pcie->vpcie);
if (ret)
dev_err(dev, "failed to disable vpcie regulator: %d\n",
ret);
}
}
static void imx6_pcie_configure_type(struct imx6_pcie *imx6_pcie)
@ -956,6 +982,8 @@ static void imx6_pcie_configure_type(struct imx6_pcie *imx6_pcie)
static void imx6_pcie_init_phy(struct imx6_pcie *imx6_pcie)
{
unsigned int offset;
switch (imx6_pcie->drvdata->variant) {
case IMX8QXP:
case IMX8QM:
@ -1049,6 +1077,73 @@ static void imx6_pcie_init_phy(struct imx6_pcie *imx6_pcie)
| IMX8QM_CSR_MISC_IOB_A_0_M1M0_2);
}
break;
case IMX8MM:
offset = imx6_pcie_grp_offset(imx6_pcie);
dev_info(imx6_pcie->pci->dev, "%s REF_CLK is used!.\n",
imx6_pcie->ext_osc ? "EXT" : "PLL");
if (imx6_pcie->ext_osc) {
regmap_update_bits(imx6_pcie->iomuxc_gpr, offset,
IMX8MQ_GPR_PCIE_REF_USE_PAD, 0);
regmap_update_bits(imx6_pcie->iomuxc_gpr, offset,
IMX8MM_GPR_PCIE_REF_CLK_SEL,
IMX8MM_GPR_PCIE_REF_CLK_SEL);
regmap_update_bits(imx6_pcie->iomuxc_gpr, offset,
IMX8MM_GPR_PCIE_AUX_EN,
IMX8MM_GPR_PCIE_AUX_EN);
regmap_update_bits(imx6_pcie->iomuxc_gpr, offset,
IMX8MM_GPR_PCIE_POWER_OFF, 0);
regmap_update_bits(imx6_pcie->iomuxc_gpr, offset,
IMX8MM_GPR_PCIE_SSC_EN, 0);
regmap_update_bits(imx6_pcie->iomuxc_gpr, offset,
IMX8MM_GPR_PCIE_REF_CLK_SEL,
IMX8MM_GPR_PCIE_REF_CLK_EXT);
udelay(100);
/* Do the PHY common block reset */
regmap_update_bits(imx6_pcie->iomuxc_gpr, offset,
IMX8MM_GPR_PCIE_CMN_RST,
IMX8MM_GPR_PCIE_CMN_RST);
udelay(200);
} else {
/* Configure the internal PLL as REF clock */
regmap_update_bits(imx6_pcie->iomuxc_gpr, offset,
IMX8MQ_GPR_PCIE_REF_USE_PAD, 0);
regmap_update_bits(imx6_pcie->iomuxc_gpr, offset,
IMX8MM_GPR_PCIE_REF_CLK_SEL,
IMX8MM_GPR_PCIE_REF_CLK_SEL);
regmap_update_bits(imx6_pcie->iomuxc_gpr, offset,
IMX8MM_GPR_PCIE_AUX_EN,
IMX8MM_GPR_PCIE_AUX_EN);
regmap_update_bits(imx6_pcie->iomuxc_gpr, offset,
IMX8MM_GPR_PCIE_POWER_OFF, 0);
regmap_update_bits(imx6_pcie->iomuxc_gpr, offset,
IMX8MM_GPR_PCIE_SSC_EN, 0);
regmap_update_bits(imx6_pcie->iomuxc_gpr, offset,
IMX8MM_GPR_PCIE_REF_CLK_SEL,
IMX8MM_GPR_PCIE_REF_CLK_PLL);
udelay(100);
/* Configure the PHY */
writel(PCIE_PHY_CMN_REG62_PLL_CLK_OUT,
imx6_pcie->phy_base + PCIE_PHY_CMN_REG62);
writel(PCIE_PHY_CMN_REG64_AUX_RX_TX_TERM,
imx6_pcie->phy_base + PCIE_PHY_CMN_REG64);
/* Do the PHY common block reset */
regmap_update_bits(imx6_pcie->iomuxc_gpr, offset,
IMX8MM_GPR_PCIE_CMN_RST,
IMX8MM_GPR_PCIE_CMN_RST);
udelay(200);
}
/*
* In order to pass the compliance tests.
* Configure the TRSV regiser of iMX8MM PCIe PHY.
*/
writel(PCIE_PHY_TRSV_REG5_GEN1_DEEMP,
imx6_pcie->phy_base + PCIE_PHY_TRSV_REG5);
writel(PCIE_PHY_TRSV_REG6_GEN2_DEEMP,
imx6_pcie->phy_base + PCIE_PHY_TRSV_REG6);
break;
case IMX8MQ:
/*
@ -1179,6 +1274,7 @@ static void imx6_pcie_ltssm_enable(struct device *dev)
break;
case IMX7D:
case IMX8MQ:
case IMX8MM:
reset_control_deassert(imx6_pcie->apps_reset);
break;
case IMX8QXP:
@ -1365,6 +1461,8 @@ static void imx6_pcie_ltssm_disable(struct device *dev)
IMX6Q_GPR12_PCIE_CTL_2, 0);
break;
case IMX7D:
case IMX8MQ:
case IMX8MM:
reset_control_assert(imx6_pcie->apps_reset);
break;
case IMX8QXP:
@ -1615,6 +1713,7 @@ static int imx6_pcie_probe(struct platform_device *pdev)
}
break;
case IMX8MQ:
case IMX8MM:
imx6_pcie->pcie_aux = devm_clk_get(dev, "pcie_aux");
if (IS_ERR(imx6_pcie->pcie_aux)) {
dev_err(dev, "pcie_aux clock source missing or invalid\n");
@ -1789,6 +1888,9 @@ static const struct imx6_pcie_drvdata drvdata[] = {
[IMX8MQ] = {
.variant = IMX8MQ,
},
[IMX8MM] = {
.variant = IMX8MM,
},
[IMX8QM] = {
.variant = IMX8QM,
.flags = IMX6_PCIE_FLAG_IMX6_CPU_ADDR_FIXUP,
@ -1804,7 +1906,8 @@ static const struct of_device_id imx6_pcie_of_match[] = {
{ .compatible = "fsl,imx6sx-pcie", .data = &drvdata[IMX6SX], },
{ .compatible = "fsl,imx6qp-pcie", .data = &drvdata[IMX6QP], },
{ .compatible = "fsl,imx7d-pcie", .data = &drvdata[IMX7D], },
{ .compatible = "fsl,imx8mq-pcie", .data = &drvdata[IMX8MQ], } ,
{ .compatible = "fsl,imx8mq-pcie", .data = &drvdata[IMX8MQ], },
{ .compatible = "fsl,imx8mm-pcie", .data = &drvdata[IMX8MM], },
{ .compatible = "fsl,imx8qm-pcie", .data = &drvdata[IMX8QM], },
{ .compatible = "fsl,imx8qxp-pcie", .data = &drvdata[IMX8QXP], },
{},