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
parent
b71e692290
commit
46a288f17b
|
@ -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], },
|
||||
{},
|
||||
|
|
Loading…
Reference in New Issue