summaryrefslogtreecommitdiff
path: root/drivers/pci
diff options
context:
space:
mode:
authorRichard Zhu <Richard.Zhu@freescale.com>2015-09-15 07:41:33 +0800
committerNitin Garg <nitin.garg@nxp.com>2016-01-14 11:01:37 -0600
commitb914282ab2c01d80d6c8e28fefe8ddbc9956ac4d (patch)
tree89a07b91c028137f1a2fae18586949b331cf06be /drivers/pci
parent98e341fc7984db86407160c8b0449175ca198bdf (diff)
MLK-11561-3 PCI: imx: enable imx6sx pcie support
enable imx6sx pci support Signed-off-by: Richard Zhu <Richard.Zhu@freescale.com>
Diffstat (limited to 'drivers/pci')
-rw-r--r--drivers/pci/host/Kconfig2
-rw-r--r--drivers/pci/host/pci-imx6.c113
2 files changed, 104 insertions, 11 deletions
diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig
index 1d0981f5d310..d19adfca7217 100644
--- a/drivers/pci/host/Kconfig
+++ b/drivers/pci/host/Kconfig
@@ -26,7 +26,7 @@ config PCI_EXYNOS
config PCI_IMX6
bool "Freescale i.MX6 PCIe controller"
- depends on SOC_IMX6Q || SOC_IMX7D
+ depends on SOC_IMX6Q || SOC_IMX6SX || SOC_IMX7D
select PCIEPORTBUS
select PCIE_DW
diff --git a/drivers/pci/host/pci-imx6.c b/drivers/pci/host/pci-imx6.c
index 5d44879b43c7..f9650868f308 100644
--- a/drivers/pci/host/pci-imx6.c
+++ b/drivers/pci/host/pci-imx6.c
@@ -51,6 +51,7 @@ struct imx6_pcie {
int power_on_gpio;
int reset_gpio;
struct clk *pcie_bus;
+ struct clk *pcie_inbound_axi;
struct clk *pcie_phy;
struct clk *pcie;
struct pcie_port pp;
@@ -104,6 +105,14 @@ static inline bool is_imx7d_pcie(struct imx6_pcie *imx6_pcie)
return of_device_is_compatible(np, "fsl,imx7d-pcie");
}
+static inline bool is_imx6sx_pcie(struct imx6_pcie *imx6_pcie)
+{
+ struct pcie_port *pp = &imx6_pcie->pp;
+ struct device_node *np = pp->dev->of_node;
+
+ return of_device_is_compatible(np, "fsl,imx6sx-pcie");
+}
+
static int pcie_phy_poll_ack(void __iomem *dbi_base, int exp_val)
{
u32 val;
@@ -252,6 +261,14 @@ static int imx6_pcie_assert_core_reset(struct pcie_port *pp)
/* BTNRST */
regmap_update_bits(imx6_pcie->reg_src, 0x2c, BIT(2), BIT(2));
+ } else if (is_imx6sx_pcie(imx6_pcie)) {
+ regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
+ IMX6SX_GPR12_PCIE_TEST_PD,
+ IMX6SX_GPR12_PCIE_TEST_PD);
+ /* Force PCIe PHY reset */
+ regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR5,
+ IMX6SX_GPR5_PCIE_BTNRST,
+ IMX6SX_GPR5_PCIE_BTNRST);
} else {
/*
* If the bootloader already enabled the link we need some
@@ -333,7 +350,17 @@ static int imx6_pcie_deassert_core_reset(struct pcie_port *pp)
dev_err(pp->dev, "unable to enable pcie clock\n");
goto err_pcie;
}
- if (!is_imx7d_pcie(imx6_pcie)) {
+
+ if (is_imx6sx_pcie(imx6_pcie)) {
+ ret = clk_prepare_enable(imx6_pcie->pcie_inbound_axi);
+ if (ret) {
+ dev_err(pp->dev, "unable to enable pcie clock\n");
+ goto err_inbound_axi;
+ }
+
+ regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
+ IMX6SX_GPR12_PCIE_TEST_PD, 0);
+ } else if (!is_imx7d_pcie(imx6_pcie)) {
/* power up core phy and enable ref clock */
regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1,
IMX6Q_GPR1_PCIE_TEST_PD, 0 << 18);
@@ -370,10 +397,15 @@ static int imx6_pcie_deassert_core_reset(struct pcie_port *pp)
/* wait for phy pll lock firstly. */
pci_imx_phy_pll_locked(imx6_pcie);
+ } else if (is_imx6sx_pcie(imx6_pcie)) {
+ regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR5,
+ IMX6SX_GPR5_PCIE_BTNRST, 0);
}
return 0;
+err_inbound_axi:
+ clk_disable_unprepare(imx6_pcie->pcie);
err_pcie:
if (!IS_ENABLED(CONFIG_EP_MODE_IN_EP_RC_SYS)
&& !IS_ENABLED(CONFIG_RC_MODE_IN_EP_RC_SYS))
@@ -401,13 +433,28 @@ static void imx6_pcie_init_phy(struct pcie_port *pp)
/* pcie phy ref clock select; 1? internal pll : external osc */
regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
BIT(5), 0);
- } else {
+ } else if (is_imx6sx_pcie(imx6_pcie)) {
+ /* Force PCIe PHY reset */
+ regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR5,
+ IMX6SX_GPR5_PCIE_BTNRST,
+ IMX6SX_GPR5_PCIE_BTNRST);
+
+ regulator_set_voltage(imx6_pcie->pcie_phy_regulator,
+ 1100000, 1100000);
+ ret = regulator_enable(imx6_pcie->pcie_phy_regulator);
+ if (ret)
+ dev_err(pp->dev, "failed to enable pcie regulator.\n");
+ regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
+ IMX6SX_GPR12_RX_EQ_MASK, IMX6SX_GPR12_RX_EQ_2);
+ }
+
+ if (!is_imx7d_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);
+ IMX6Q_GPR12_LOS_LEVEL, IMX6Q_GPR12_LOS_LEVEL_9);
regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR8,
IMX6Q_GPR8_TX_DEEMPH_GEN1, 0 << 0);
@@ -695,6 +742,8 @@ static void imx_pcie_regions_setup(struct device *dev)
if (is_imx7d_pcie(imx6_pcie) && ddr_test_region == 0)
ddr_test_region = 0xb0000000;
+ else if (is_imx6sx_pcie(imx6_pcie) && ddr_test_region == 0)
+ ddr_test_region = 0xb0000000;
else if (ddr_test_region == 0)
ddr_test_region = 0x40000000;
@@ -729,7 +778,7 @@ imx_pcie_memw_start(struct device *dev, struct device_attribute *attr,
sscanf(buf, "%x\n", &memw_start);
- if (is_imx7d_pcie(imx6_pcie)) {
+ if (is_imx7d_pcie(imx6_pcie) || is_imx6sx_pcie(imx6_pcie)) {
if (memw_start < 0x80000000 || memw_start > 0xb0000000) {
dev_err(dev, "Invalid memory start addr.\n");
dev_info(dev, "e.x: echo 0xb0000000 > /sys/...");
@@ -859,6 +908,12 @@ static void pci_imx_pm_turn_off(struct imx6_pcie *imx6_pcie)
BIT(11), BIT(11));
regmap_update_bits(imx6_pcie->reg_src, 0x2c,
BIT(11), 0);
+ } else if (is_imx6sx_pcie(imx6_pcie)) {
+ regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
+ IMX6SX_GPR12_PCIE_PM_TURN_OFF,
+ IMX6SX_GPR12_PCIE_PM_TURN_OFF);
+ regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
+ IMX6SX_GPR12_PCIE_PM_TURN_OFF, 0);
} else {
pr_info("Info: don't support pm_turn_off yet.\n");
return;
@@ -879,14 +934,17 @@ static int pci_imx_suspend_noirq(struct device *dev)
pci_imx_pm_turn_off(imx6_pcie);
- if (is_imx7d_pcie(imx6_pcie)) {
+ if (is_imx6sx_pcie(imx6_pcie) || is_imx7d_pcie(imx6_pcie)) {
/* Disable clks */
clk_disable_unprepare(imx6_pcie->pcie);
clk_disable_unprepare(imx6_pcie->pcie_phy);
clk_disable_unprepare(imx6_pcie->pcie_bus);
- /* turn off external osc input */
- regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
- BIT(5), BIT(5));
+ if (is_imx6sx_pcie(imx6_pcie))
+ clk_disable_unprepare(imx6_pcie->pcie_inbound_axi);
+ else
+ /* turn off external osc input */
+ regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
+ BIT(5), BIT(5));
release_bus_freq(BUS_FREQ_HIGH);
/* Power down PCIe PHY. */
@@ -914,8 +972,12 @@ static int pci_imx_resume_noirq(struct device *dev)
struct imx6_pcie *imx6_pcie = dev_get_drvdata(dev);
struct pcie_port *pp = &imx6_pcie->pp;
- if (is_imx7d_pcie(imx6_pcie)) {
- regmap_update_bits(imx6_pcie->reg_src, 0x2c, BIT(6), 0);
+ if (is_imx6sx_pcie(imx6_pcie) || is_imx7d_pcie(imx6_pcie)) {
+ if (is_imx7d_pcie(imx6_pcie))
+ regmap_update_bits(imx6_pcie->reg_src, 0x2c, BIT(6), 0);
+ else
+ regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
+ IMX6Q_GPR12_PCIE_CTL_2, 0);
imx6_pcie_assert_core_reset(pp);
@@ -938,6 +1000,10 @@ static int pci_imx_resume_noirq(struct device *dev)
pci_imx_phy_pll_locked(imx6_pcie);
regmap_update_bits(imx6_pcie->reg_src, 0x2c,
BIT(6), BIT(6));
+ } else {
+ regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
+ IMX6Q_GPR12_PCIE_CTL_2,
+ IMX6Q_GPR12_PCIE_CTL_2);
}
ret = imx6_pcie_wait_for_link(pp);
@@ -1067,6 +1133,21 @@ static int __init imx6_pcie_probe(struct platform_device *pdev)
}
imx6_pcie->pcie_phy_regulator = devm_regulator_get(pp->dev,
"pcie-phy");
+ } else if (is_imx6sx_pcie(imx6_pcie)) {
+ imx6_pcie->pcie_inbound_axi = devm_clk_get(&pdev->dev,
+ "pcie_inbound_axi");
+ if (IS_ERR(imx6_pcie->pcie_inbound_axi)) {
+ dev_err(&pdev->dev,
+ "pcie clock source missing or invalid\n");
+ return PTR_ERR(imx6_pcie->pcie_inbound_axi);
+ }
+
+ imx6_pcie->pcie_phy_regulator = devm_regulator_get(pp->dev,
+ "pcie-phy");
+
+ imx6_pcie->iomuxc_gpr =
+ syscon_regmap_lookup_by_compatible
+ ("fsl,imx6sx-iomuxc-gpr");
} else {
imx6_pcie->iomuxc_gpr =
syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr");
@@ -1116,6 +1197,17 @@ static int __init imx6_pcie_probe(struct platform_device *pdev)
return ret;
}
+ /*
+ * iMX6SX PCIe has the stand-alone power domain.
+ * refer to the initialization for iMX6SX PCIe,
+ * release the PCIe PHY reset here,
+ * before LTSSM enable is set
+ * .
+ */
+ if (is_imx6sx_pcie(imx6_pcie))
+ regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR5,
+ BIT(19), 0 << 19);
+
/* assert LTSSM enable */
if (is_imx7d_pcie(imx6_pcie)) {
regmap_update_bits(imx6_pcie->reg_src, 0x2c,
@@ -1241,6 +1333,7 @@ static void imx6_pcie_shutdown(struct platform_device *pdev)
static const struct of_device_id imx6_pcie_of_match[] = {
{ .compatible = "fsl,imx6q-pcie", },
+ { .compatible = "fsl,imx6sx-pcie", },
{ .compatible = "fsl,imx7d-pcie", },
{},
};