summaryrefslogtreecommitdiff
path: root/drivers/pci
diff options
context:
space:
mode:
authorRichard Zhu <hongxing.zhu@nxp.com>2017-06-21 10:25:08 +0800
committerJason Liu <jason.hui.liu@nxp.com>2019-02-12 10:27:11 +0800
commitbcd3e7b6ad2a8f4ce36898334537d1179638d023 (patch)
treec4290327d4bee6a219cd146eb947c1290cace895 /drivers/pci
parent055048d914ecdbda8b029b06e338fe447815befb (diff)
MLK-15307-3 PCI: imx: add the imx8mq pcie
Add the imx8mq pcie support Signed-off-by: Richard Zhu <hongxing.zhu@nxp.com>
Diffstat (limited to 'drivers/pci')
-rw-r--r--drivers/pci/dwc/pci-imx6.c232
1 files changed, 222 insertions, 10 deletions
diff --git a/drivers/pci/dwc/pci-imx6.c b/drivers/pci/dwc/pci-imx6.c
index 14a60fe06e28..a24df11743ea 100644
--- a/drivers/pci/dwc/pci-imx6.c
+++ b/drivers/pci/dwc/pci-imx6.c
@@ -47,6 +47,7 @@ enum imx6_pcie_variants {
IMX6QP,
IMX7D,
IMX8QM,
+ IMX8MQ,
};
/*
@@ -64,6 +65,7 @@ struct imx6_pcie {
u32 ext_osc;
u32 ctrl_id;
u32 cpu_base;
+ int clkreq_gpio;
int dis_gpio;
int power_on_gpio;
int reset_gpio;
@@ -85,6 +87,7 @@ struct imx6_pcie {
int link_gen;
struct regulator *vpcie;
struct regmap *reg_src;
+ struct regmap *reg_gpc;
void __iomem *phy_base;
struct regulator *pcie_phy_regulator;
struct regulator *pcie_bus_regulator;
@@ -198,6 +201,26 @@ struct imx6_pcie {
#define IMX8QM_MISC_PHYX1_EPCS_SEL BIT(12)
#define IMX8QM_MISC_PCIE_AB_SELECT BIT(13)
+#define IMX8MQ_SRC_PCIEPHY_RCR_OFFSET 0x2C
+#define IMX8MQ_SRC_PCIE2PHY_RCR_OFFSET 0x48
+#define IMX8MQ_PCIEPHY_PWR_ON_RST BIT(0)
+#define IMX8MQ_PCIEPHY_G_RST BIT(1)
+#define IMX8MQ_PCIEPHY_BTN BIT(2)
+#define IMX8MQ_PCIEPHY_PERST BIT(3)
+#define IMX8MQ_PCIE_CTRL_APPS_EN BIT(6)
+#define IMX8MQ_PCIE_CTRL_APPS_TURNOFF BIT(11)
+
+#define IMX8MQ_GPC_PGC_CPU_0_1_MAPPING_OFFSET 0xEC
+#define IMX8MQ_GPC_PU_PGC_SW_PUP_REQ_OFFSET 0xF8
+#define IMX8MQ_GPC_PU_PGC_SW_PDN_REQ_OFFSET 0x104
+#define IMX8MQ_GPC_PGC_PCIE_CTRL_OFFSET 0xC40
+#define IMX8MQ_GPC_PGC_PCIE2_CTRL_OFFSET 0xF00
+#define IMX8MQ_GPC_PGC_PCIE_A53_DOMAIN BIT(3)
+#define IMX8MQ_GPC_PU_PGC_PCIE_SW_PWR_REQ BIT(1)
+#define IMX8MQ_GPC_PGC_PCIE2_BIT_OFFSET 12
+#define IMX8MQ_GPC_PCG_PCIE_CTRL_PCR BIT(0)
+#define IMX8MQ_GPR_PCIE_REF_USE_PAD BIT(9)
+
static int pcie_phy_poll_ack(struct imx6_pcie *imx6_pcie, int exp_val)
{
struct dw_pcie *pci = imx6_pcie->pci;
@@ -427,6 +450,18 @@ static void imx6_pcie_assert_core_reset(struct imx6_pcie *imx6_pcie)
IMX8QM_CTRL_POWER_UP_RST_N,
IMX8QM_CTRL_POWER_UP_RST_N);
break;
+ case IMX8MQ:
+ if (imx6_pcie->ctrl_id == 0)
+ val = IMX8MQ_SRC_PCIEPHY_RCR_OFFSET;
+ else
+ val = IMX8MQ_SRC_PCIE2PHY_RCR_OFFSET;
+ /* Do RSTs */
+ regmap_update_bits(imx6_pcie->reg_src, val,
+ IMX8MQ_PCIEPHY_BTN,
+ IMX8MQ_PCIEPHY_BTN);
+ regmap_update_bits(imx6_pcie->reg_src, val,
+ IMX8MQ_PCIEPHY_G_RST,
+ IMX8MQ_PCIEPHY_G_RST);
}
if (imx6_pcie->vpcie && regulator_is_enabled(imx6_pcie->vpcie) > 0) {
@@ -471,6 +506,7 @@ static int imx6_pcie_enable_ref_clk(struct imx6_pcie *imx6_pcie)
IMX6Q_GPR1_PCIE_REF_CLK_EN, 1 << 16);
break;
case IMX7D:
+ case IMX8MQ:
break;
case IMX8QM:
ret = clk_prepare_enable(imx6_pcie->pcie_inbound_axi);
@@ -703,6 +739,21 @@ static int imx6_pcie_deassert_core_reset(struct imx6_pcie *imx6_pcie)
if (imx8_pcie_wait_for_phy_pll_lock(imx6_pcie))
ret = -ENODEV;
break;
+ case IMX8MQ:
+ /* wait for more than 10us to release phy g_rst and btnrst */
+ udelay(10);
+ if (imx6_pcie->ctrl_id == 0)
+ val = IMX8MQ_SRC_PCIEPHY_RCR_OFFSET;
+ else
+ val = IMX8MQ_SRC_PCIE2PHY_RCR_OFFSET;
+ regmap_update_bits(imx6_pcie->reg_src, val,
+ IMX8MQ_PCIEPHY_BTN, 0);
+ regmap_update_bits(imx6_pcie->reg_src, val,
+ IMX8MQ_PCIEPHY_G_RST, 0);
+ regmap_update_bits(imx6_pcie->reg_src, val,
+ IMX8MQ_PCIE_CTRL_APPS_EN, 0);
+ break;
+
}
/* Some boards don't have PCIe reset GPIO. */
@@ -734,6 +785,101 @@ err_pcie:
return ret;
}
+static void imx6_pcie_phy_pwr_up(struct imx6_pcie *imx6_pcie)
+{
+ u32 val, offset;
+ unsigned long timeout = jiffies + msecs_to_jiffies(500);
+
+ if (imx6_pcie->variant != IMX8MQ)
+ return;
+ /*
+ * Power up PHY.
+ * pcie phy ref clock select by gpr configuration.
+ * 1? external osc : internal pll
+ */
+
+ if (imx6_pcie->ctrl_id == 0)
+ offset = 0;
+ else
+ offset = IMX8MQ_GPC_PGC_PCIE2_BIT_OFFSET;
+
+ regmap_update_bits(imx6_pcie->reg_gpc,
+ IMX8MQ_GPC_PGC_CPU_0_1_MAPPING_OFFSET,
+ IMX8MQ_GPC_PGC_PCIE_A53_DOMAIN << offset,
+ IMX8MQ_GPC_PGC_PCIE_A53_DOMAIN << offset);
+ regmap_update_bits(imx6_pcie->reg_gpc,
+ IMX8MQ_GPC_PU_PGC_SW_PUP_REQ_OFFSET,
+ IMX8MQ_GPC_PU_PGC_PCIE_SW_PWR_REQ << offset,
+ IMX8MQ_GPC_PU_PGC_PCIE_SW_PWR_REQ << offset);
+
+ regmap_read(imx6_pcie->reg_gpc,
+ IMX8MQ_GPC_PU_PGC_SW_PUP_REQ_OFFSET,
+ &val);
+ while (val & (IMX8MQ_GPC_PU_PGC_PCIE_SW_PWR_REQ << offset)) {
+ regmap_read(imx6_pcie->reg_gpc,
+ IMX8MQ_GPC_PU_PGC_SW_PUP_REQ_OFFSET,
+ &val);
+ if (time_after(jiffies, timeout)) {
+ pr_err("CAN NOT PWR UP PCIE%d PHY!\n",
+ imx6_pcie->ctrl_id);
+ break;
+ }
+ }
+ udelay(1);
+}
+
+static void imx6_pcie_phy_pwr_dn(struct imx6_pcie *imx6_pcie)
+{
+ u32 val, offset;
+ unsigned long timeout = jiffies + msecs_to_jiffies(500);
+
+ if (imx6_pcie->variant != IMX8MQ)
+ return;
+ /*
+ * Power up PHY.
+ * pcie phy ref clock select by gpr configuration.
+ * 1? external osc : internal pll
+ */
+
+ if (imx6_pcie->ctrl_id == 0) {
+ offset = 0;
+ regmap_update_bits(imx6_pcie->reg_gpc,
+ IMX8MQ_GPC_PGC_PCIE_CTRL_OFFSET,
+ IMX8MQ_GPC_PCG_PCIE_CTRL_PCR,
+ IMX8MQ_GPC_PCG_PCIE_CTRL_PCR);
+ } else {
+ offset = IMX8MQ_GPC_PGC_PCIE2_BIT_OFFSET;
+ regmap_update_bits(imx6_pcie->reg_gpc,
+ IMX8MQ_GPC_PGC_PCIE2_CTRL_OFFSET,
+ IMX8MQ_GPC_PCG_PCIE_CTRL_PCR,
+ IMX8MQ_GPC_PCG_PCIE_CTRL_PCR);
+ }
+
+ regmap_update_bits(imx6_pcie->reg_gpc,
+ IMX8MQ_GPC_PGC_CPU_0_1_MAPPING_OFFSET,
+ IMX8MQ_GPC_PGC_PCIE_A53_DOMAIN << offset,
+ IMX8MQ_GPC_PGC_PCIE_A53_DOMAIN << offset);
+ regmap_update_bits(imx6_pcie->reg_gpc,
+ IMX8MQ_GPC_PU_PGC_SW_PDN_REQ_OFFSET,
+ IMX8MQ_GPC_PU_PGC_PCIE_SW_PWR_REQ << offset,
+ IMX8MQ_GPC_PU_PGC_PCIE_SW_PWR_REQ << offset);
+
+ regmap_read(imx6_pcie->reg_gpc,
+ IMX8MQ_GPC_PU_PGC_SW_PDN_REQ_OFFSET,
+ &val);
+ while (val & (IMX8MQ_GPC_PU_PGC_PCIE_SW_PWR_REQ << offset)) {
+ regmap_read(imx6_pcie->reg_gpc,
+ IMX8MQ_GPC_PU_PGC_SW_PDN_REQ_OFFSET,
+ &val);
+ if (time_after(jiffies, timeout)) {
+ pr_err("CAN NOT PWR DN PCIE%d PHY!\n",
+ imx6_pcie->ctrl_id);
+ break;
+ }
+ }
+ udelay(1);
+}
+
static void imx6_pcie_init_phy(struct imx6_pcie *imx6_pcie)
{
u32 tmp, val;
@@ -852,9 +998,18 @@ static void imx6_pcie_init_phy(struct imx6_pcie *imx6_pcie)
if ((tmp & IMX8QM_CTRL_STTS0_PM_REQ_CORE_RST) != 0)
pr_err("ERROR PM_REQ_CORE_RST is still set.\n");
- }
+ } else if (imx6_pcie->variant == IMX8MQ) {
+ imx6_pcie_phy_pwr_up(imx6_pcie);
- if (imx6_pcie->variant == IMX7D) {
+ if (imx6_pcie->ctrl_id == 0)
+ val = IOMUXC_GPR14;
+ else
+ val = IOMUXC_GPR16;
+
+ regmap_update_bits(imx6_pcie->iomuxc_gpr, val,
+ IMX8MQ_GPR_PCIE_REF_USE_PAD,
+ IMX8MQ_GPR_PCIE_REF_USE_PAD);
+ } else if (imx6_pcie->variant == IMX7D) {
/* Enable PCIe PHY 1P0D */
regulator_set_voltage(imx6_pcie->pcie_phy_regulator,
1000000, 1000000);
@@ -924,9 +1079,17 @@ static void imx6_pcie_init_phy(struct imx6_pcie *imx6_pcie)
val, IMX8QM_PCIE_TYPE_MASK,
PCI_EXP_TYPE_ENDPOINT << 24);
} else {
- regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
- IMX6Q_GPR12_DEVICE_TYPE,
- PCI_EXP_TYPE_ENDPOINT << 12);
+ if (unlikely(imx6_pcie->ctrl_id))
+ /* iMX8MQ second PCIE */
+ regmap_update_bits(imx6_pcie->iomuxc_gpr,
+ IOMUXC_GPR12,
+ IMX6Q_GPR12_DEVICE_TYPE >> 4,
+ PCI_EXP_TYPE_ENDPOINT << 8);
+ else
+ regmap_update_bits(imx6_pcie->iomuxc_gpr,
+ IOMUXC_GPR12,
+ IMX6Q_GPR12_DEVICE_TYPE,
+ PCI_EXP_TYPE_ENDPOINT << 12);
}
} else {
if (imx6_pcie->variant == IMX8QM) {
@@ -936,9 +1099,17 @@ static void imx6_pcie_init_phy(struct imx6_pcie *imx6_pcie)
val, IMX8QM_PCIE_TYPE_MASK,
PCI_EXP_TYPE_ROOT_PORT << 24);
} else {
- regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
- IMX6Q_GPR12_DEVICE_TYPE,
- PCI_EXP_TYPE_ROOT_PORT << 12);
+ if (unlikely(imx6_pcie->ctrl_id))
+ /* iMX8MQ second PCIE */
+ regmap_update_bits(imx6_pcie->iomuxc_gpr,
+ IOMUXC_GPR12,
+ IMX6Q_GPR12_DEVICE_TYPE >> 4,
+ PCI_EXP_TYPE_ROOT_PORT << 8);
+ else
+ regmap_update_bits(imx6_pcie->iomuxc_gpr,
+ IOMUXC_GPR12,
+ IMX6Q_GPR12_DEVICE_TYPE,
+ PCI_EXP_TYPE_ROOT_PORT << 12);
}
}
}
@@ -1021,8 +1192,15 @@ static int imx6_pcie_establish_link(struct imx6_pcie *imx6_pcie)
tmp + IMX8QM_CSR_PCIE_CTRL2_OFFSET,
IMX8QM_CTRL_LTSSM_ENABLE,
IMX8QM_CTRL_LTSSM_ENABLE);
- } else if (imx6_pcie->variant == IMX7D) {
- regmap_update_bits(imx6_pcie->reg_src, 0x2c, BIT(6), BIT(6));
+ } else if ((imx6_pcie->variant == IMX7D)
+ || (imx6_pcie->variant == IMX8MQ)) {
+ if (imx6_pcie->ctrl_id == 0)
+ tmp = IMX8MQ_SRC_PCIEPHY_RCR_OFFSET;
+ else
+ tmp = IMX8MQ_SRC_PCIE2PHY_RCR_OFFSET;
+ regmap_update_bits(imx6_pcie->reg_src, tmp,
+ IMX8MQ_PCIE_CTRL_APPS_EN,
+ IMX8MQ_PCIE_CTRL_APPS_EN);
} else {
regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
IMX6Q_GPR12_PCIE_CTL_2, 1 << 10);
@@ -1092,6 +1270,11 @@ err_reset_phy:
|| imx6_pcie->variant == IMX8QM)
clk_disable_unprepare(imx6_pcie->pcie_inbound_axi);
release_bus_freq(BUS_FREQ_HIGH);
+ if ((imx6_pcie->variant == IMX7D)
+ || (imx6_pcie->variant == IMX8QM))
+ pm_runtime_put_sync(pci->dev);
+ if (imx6_pcie->variant == IMX8MQ)
+ imx6_pcie_phy_pwr_dn(imx6_pcie);
if (imx6_pcie->pcie_phy_regulator != NULL)
regulator_disable(imx6_pcie->pcie_phy_regulator);
if (imx6_pcie->pcie_bus_regulator != NULL)
@@ -1596,6 +1779,16 @@ static int __init imx6_pcie_probe(struct platform_device *pdev)
return PTR_ERR(pci->dbi_base);
/* Fetch GPIOs */
+ imx6_pcie->clkreq_gpio = of_get_named_gpio(node, "clkreq-gpio", 0);
+ if (gpio_is_valid(imx6_pcie->clkreq_gpio)) {
+ ret = devm_gpio_request_one(&pdev->dev, imx6_pcie->clkreq_gpio,
+ GPIOF_OUT_INIT_LOW, "PCIe CLKREQ");
+ if (ret) {
+ dev_err(&pdev->dev, "unable to get clkreq gpio\n");
+ return ret;
+ }
+ }
+
imx6_pcie->dis_gpio = of_get_named_gpio(node, "disable-gpio", 0);
if (gpio_is_valid(imx6_pcie->dis_gpio)) {
ret = devm_gpio_request_one(&pdev->dev, imx6_pcie->dis_gpio,
@@ -1693,6 +1886,24 @@ static int __init imx6_pcie_probe(struct platform_device *pdev)
}
imx6_pcie->pcie_phy_regulator = devm_regulator_get(&pdev->dev,
"pcie-phy");
+ } else if (imx6_pcie->variant == IMX8MQ) {
+ imx6_pcie->iomuxc_gpr =
+ syscon_regmap_lookup_by_compatible
+ ("fsl,imx8mq-iomuxc-gpr");
+ imx6_pcie->reg_src =
+ syscon_regmap_lookup_by_compatible("fsl,imx8mq-src");
+ if (IS_ERR(imx6_pcie->reg_src)) {
+ dev_err(&pdev->dev,
+ "imx8mq pcie phy src missing or invalid\n");
+ return PTR_ERR(imx6_pcie->reg_src);
+ }
+ imx6_pcie->reg_gpc =
+ syscon_regmap_lookup_by_compatible("fsl,imx8mq-gpc");
+ if (IS_ERR(imx6_pcie->reg_gpc)) {
+ dev_err(&pdev->dev,
+ "imx8mq pcie phy src missing or invalid\n");
+ return PTR_ERR(imx6_pcie->reg_gpc);
+ }
} else if (imx6_pcie->variant == IMX6SX) {
imx6_pcie->pcie_inbound_axi = devm_clk_get(&pdev->dev,
"pcie_inbound_axi");
@@ -1958,6 +2169,7 @@ static const struct of_device_id imx6_pcie_of_match[] = {
{ .compatible = "fsl,imx6qp-pcie", .data = (void *)IMX6QP, },
{ .compatible = "fsl,imx7d-pcie", .data = (void *)IMX7D, },
{ .compatible = "fsl,imx8qm-pcie", .data = (void *)IMX8QM, },
+ { .compatible = "fsl,imx8mq-pcie", .data = (void *)IMX8MQ, },
{},
};