diff options
author | Andrey Smirnov <andrew.smirnov@gmail.com> | 2017-03-28 11:42:49 -0400 |
---|---|---|
committer | Bjorn Helgaas <bhelgaas@google.com> | 2017-04-04 18:50:07 -0400 |
commit | 9b3fe6796d7c0e0c2b87243ce0c7f4744c54efad (patch) | |
tree | 04b82d3c59830ad25e07d8659f1df5391ecd19bb | |
parent | c1ae3cfa0e89fa1a7ecc4c99031f5e9ae99d9201 (diff) |
PCI: imx6: Add code to support i.MX7D
Add various bits of code needed to support i.MX7D variant of the IP.
Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Lucas Stach <l.stach@pengutronix.de>
Acked-by: Lee Jones <lee.jones@linaro.org>
Acked-by: Rob Herring <robh@kernel.org>
Cc: yurovsky@gmail.com
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Fabio Estevam <fabio.estevam@nxp.com>
Cc: Dong Aisheng <dongas86@gmail.com>
Cc: linux-arm-kernel@lists.infradead.org
Cc: devicetree@vger.kernel.org
-rw-r--r-- | Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.txt | 14 | ||||
-rw-r--r-- | drivers/pci/dwc/pci-imx6.c | 120 | ||||
-rw-r--r-- | include/linux/mfd/syscon/imx7-iomuxc-gpr.h | 4 |
3 files changed, 112 insertions, 26 deletions
diff --git a/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.txt b/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.txt index 83aeb1f5a645..e3d5680875b1 100644 --- a/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.txt +++ b/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.txt | |||
@@ -4,7 +4,11 @@ This PCIe host controller is based on the Synopsis Designware PCIe IP | |||
4 | and thus inherits all the common properties defined in designware-pcie.txt. | 4 | and thus inherits all the common properties defined in designware-pcie.txt. |
5 | 5 | ||
6 | Required properties: | 6 | Required properties: |
7 | - compatible: "fsl,imx6q-pcie", "fsl,imx6sx-pcie", "fsl,imx6qp-pcie" | 7 | - compatible: |
8 | - "fsl,imx6q-pcie" | ||
9 | - "fsl,imx6sx-pcie", | ||
10 | - "fsl,imx6qp-pcie" | ||
11 | - "fsl,imx7d-pcie" | ||
8 | - reg: base address and length of the PCIe controller | 12 | - reg: base address and length of the PCIe controller |
9 | - interrupts: A list of interrupt outputs of the controller. Must contain an | 13 | - interrupts: A list of interrupt outputs of the controller. Must contain an |
10 | entry for each entry in the interrupt-names property. | 14 | entry for each entry in the interrupt-names property. |
@@ -34,6 +38,14 @@ Additional required properties for imx6sx-pcie: | |||
34 | - clock names: Must include the following additional entries: | 38 | - clock names: Must include the following additional entries: |
35 | - "pcie_inbound_axi" | 39 | - "pcie_inbound_axi" |
36 | 40 | ||
41 | Additional required properties for imx7d-pcie: | ||
42 | - power-domains: Must be set to a phandle pointing to PCIE_PHY power domain | ||
43 | - resets: Must contain phandles to PCIe-related reset lines exposed by SRC | ||
44 | IP block | ||
45 | - reset-names: Must contain the following entires: | ||
46 | - "pciephy" | ||
47 | - "apps" | ||
48 | |||
37 | Example: | 49 | Example: |
38 | 50 | ||
39 | pcie@0x01000000 { | 51 | pcie@0x01000000 { |
diff --git a/drivers/pci/dwc/pci-imx6.c b/drivers/pci/dwc/pci-imx6.c index 801e46cd266d..e0c36d6f5a21 100644 --- a/drivers/pci/dwc/pci-imx6.c +++ b/drivers/pci/dwc/pci-imx6.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/kernel.h> | 17 | #include <linux/kernel.h> |
18 | #include <linux/mfd/syscon.h> | 18 | #include <linux/mfd/syscon.h> |
19 | #include <linux/mfd/syscon/imx6q-iomuxc-gpr.h> | 19 | #include <linux/mfd/syscon/imx6q-iomuxc-gpr.h> |
20 | #include <linux/mfd/syscon/imx7-iomuxc-gpr.h> | ||
20 | #include <linux/module.h> | 21 | #include <linux/module.h> |
21 | #include <linux/of_gpio.h> | 22 | #include <linux/of_gpio.h> |
22 | #include <linux/of_device.h> | 23 | #include <linux/of_device.h> |
@@ -27,6 +28,7 @@ | |||
27 | #include <linux/signal.h> | 28 | #include <linux/signal.h> |
28 | #include <linux/types.h> | 29 | #include <linux/types.h> |
29 | #include <linux/interrupt.h> | 30 | #include <linux/interrupt.h> |
31 | #include <linux/reset.h> | ||
30 | 32 | ||
31 | #include "pcie-designware.h" | 33 | #include "pcie-designware.h" |
32 | 34 | ||
@@ -36,6 +38,7 @@ enum imx6_pcie_variants { | |||
36 | IMX6Q, | 38 | IMX6Q, |
37 | IMX6SX, | 39 | IMX6SX, |
38 | IMX6QP, | 40 | IMX6QP, |
41 | IMX7D, | ||
39 | }; | 42 | }; |
40 | 43 | ||
41 | struct imx6_pcie { | 44 | struct imx6_pcie { |
@@ -47,6 +50,8 @@ struct imx6_pcie { | |||
47 | struct clk *pcie_inbound_axi; | 50 | struct clk *pcie_inbound_axi; |
48 | struct clk *pcie; | 51 | struct clk *pcie; |
49 | struct regmap *iomuxc_gpr; | 52 | struct regmap *iomuxc_gpr; |
53 | struct reset_control *pciephy_reset; | ||
54 | struct reset_control *apps_reset; | ||
50 | enum imx6_pcie_variants variant; | 55 | enum imx6_pcie_variants variant; |
51 | u32 tx_deemph_gen1; | 56 | u32 tx_deemph_gen1; |
52 | u32 tx_deemph_gen2_3p5db; | 57 | u32 tx_deemph_gen2_3p5db; |
@@ -56,6 +61,11 @@ struct imx6_pcie { | |||
56 | int link_gen; | 61 | int link_gen; |
57 | }; | 62 | }; |
58 | 63 | ||
64 | /* Parameters for the waiting for PCIe PHY PLL to lock on i.MX7 */ | ||
65 | #define PHY_PLL_LOCK_WAIT_MAX_RETRIES 2000 | ||
66 | #define PHY_PLL_LOCK_WAIT_USLEEP_MIN 50 | ||
67 | #define PHY_PLL_LOCK_WAIT_USLEEP_MAX 200 | ||
68 | |||
59 | /* PCIe Root Complex registers (memory-mapped) */ | 69 | /* PCIe Root Complex registers (memory-mapped) */ |
60 | #define PCIE_RC_LCR 0x7c | 70 | #define PCIE_RC_LCR 0x7c |
61 | #define PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN1 0x1 | 71 | #define PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN1 0x1 |
@@ -248,6 +258,10 @@ static int imx6q_pcie_abort_handler(unsigned long addr, | |||
248 | static void imx6_pcie_assert_core_reset(struct imx6_pcie *imx6_pcie) | 258 | static void imx6_pcie_assert_core_reset(struct imx6_pcie *imx6_pcie) |
249 | { | 259 | { |
250 | switch (imx6_pcie->variant) { | 260 | switch (imx6_pcie->variant) { |
261 | case IMX7D: | ||
262 | reset_control_assert(imx6_pcie->pciephy_reset); | ||
263 | reset_control_assert(imx6_pcie->apps_reset); | ||
264 | break; | ||
251 | case IMX6SX: | 265 | case IMX6SX: |
252 | regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, | 266 | regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, |
253 | IMX6SX_GPR12_PCIE_TEST_POWERDOWN, | 267 | IMX6SX_GPR12_PCIE_TEST_POWERDOWN, |
@@ -303,11 +317,32 @@ static int imx6_pcie_enable_ref_clk(struct imx6_pcie *imx6_pcie) | |||
303 | regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1, | 317 | regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1, |
304 | IMX6Q_GPR1_PCIE_REF_CLK_EN, 1 << 16); | 318 | IMX6Q_GPR1_PCIE_REF_CLK_EN, 1 << 16); |
305 | break; | 319 | break; |
320 | case IMX7D: | ||
321 | break; | ||
306 | } | 322 | } |
307 | 323 | ||
308 | return ret; | 324 | return ret; |
309 | } | 325 | } |
310 | 326 | ||
327 | static void imx7d_pcie_wait_for_phy_pll_lock(struct imx6_pcie *imx6_pcie) | ||
328 | { | ||
329 | u32 val; | ||
330 | unsigned int retries; | ||
331 | struct device *dev = imx6_pcie->pci->dev; | ||
332 | |||
333 | for (retries = 0; retries < PHY_PLL_LOCK_WAIT_MAX_RETRIES; retries++) { | ||
334 | regmap_read(imx6_pcie->iomuxc_gpr, IOMUXC_GPR22, &val); | ||
335 | |||
336 | if (val & IMX7D_GPR22_PCIE_PHY_PLL_LOCKED) | ||
337 | return; | ||
338 | |||
339 | usleep_range(PHY_PLL_LOCK_WAIT_USLEEP_MIN, | ||
340 | PHY_PLL_LOCK_WAIT_USLEEP_MAX); | ||
341 | } | ||
342 | |||
343 | dev_err(dev, "PCIe PLL lock timeout\n"); | ||
344 | } | ||
345 | |||
311 | static void imx6_pcie_deassert_core_reset(struct imx6_pcie *imx6_pcie) | 346 | static void imx6_pcie_deassert_core_reset(struct imx6_pcie *imx6_pcie) |
312 | { | 347 | { |
313 | struct dw_pcie *pci = imx6_pcie->pci; | 348 | struct dw_pcie *pci = imx6_pcie->pci; |
@@ -351,6 +386,10 @@ static void imx6_pcie_deassert_core_reset(struct imx6_pcie *imx6_pcie) | |||
351 | } | 386 | } |
352 | 387 | ||
353 | switch (imx6_pcie->variant) { | 388 | switch (imx6_pcie->variant) { |
389 | case IMX7D: | ||
390 | reset_control_deassert(imx6_pcie->pciephy_reset); | ||
391 | imx7d_pcie_wait_for_phy_pll_lock(imx6_pcie); | ||
392 | break; | ||
354 | case IMX6SX: | 393 | case IMX6SX: |
355 | regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR5, | 394 | regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR5, |
356 | IMX6SX_GPR5_PCIE_BTNRST_RESET, 0); | 395 | IMX6SX_GPR5_PCIE_BTNRST_RESET, 0); |
@@ -377,35 +416,44 @@ err_pcie_bus: | |||
377 | 416 | ||
378 | static void imx6_pcie_init_phy(struct imx6_pcie *imx6_pcie) | 417 | static void imx6_pcie_init_phy(struct imx6_pcie *imx6_pcie) |
379 | { | 418 | { |
380 | if (imx6_pcie->variant == IMX6SX) | 419 | switch (imx6_pcie->variant) { |
420 | case IMX7D: | ||
421 | regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, | ||
422 | IMX7D_GPR12_PCIE_PHY_REFCLK_SEL, 0); | ||
423 | break; | ||
424 | case IMX6SX: | ||
381 | regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, | 425 | regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, |
382 | IMX6SX_GPR12_PCIE_RX_EQ_MASK, | 426 | IMX6SX_GPR12_PCIE_RX_EQ_MASK, |
383 | IMX6SX_GPR12_PCIE_RX_EQ_2); | 427 | IMX6SX_GPR12_PCIE_RX_EQ_2); |
428 | /* FALLTHROUGH */ | ||
429 | default: | ||
430 | regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, | ||
431 | IMX6Q_GPR12_PCIE_CTL_2, 0 << 10); | ||
384 | 432 | ||
385 | regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, | 433 | /* configure constant input signal to the pcie ctrl and phy */ |
386 | IMX6Q_GPR12_PCIE_CTL_2, 0 << 10); | 434 | regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, |
435 | IMX6Q_GPR12_LOS_LEVEL, 9 << 4); | ||
436 | |||
437 | regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR8, | ||
438 | IMX6Q_GPR8_TX_DEEMPH_GEN1, | ||
439 | imx6_pcie->tx_deemph_gen1 << 0); | ||
440 | regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR8, | ||
441 | IMX6Q_GPR8_TX_DEEMPH_GEN2_3P5DB, | ||
442 | imx6_pcie->tx_deemph_gen2_3p5db << 6); | ||
443 | regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR8, | ||
444 | IMX6Q_GPR8_TX_DEEMPH_GEN2_6DB, | ||
445 | imx6_pcie->tx_deemph_gen2_6db << 12); | ||
446 | regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR8, | ||
447 | IMX6Q_GPR8_TX_SWING_FULL, | ||
448 | imx6_pcie->tx_swing_full << 18); | ||
449 | regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR8, | ||
450 | IMX6Q_GPR8_TX_SWING_LOW, | ||
451 | imx6_pcie->tx_swing_low << 25); | ||
452 | break; | ||
453 | } | ||
387 | 454 | ||
388 | /* configure constant input signal to the pcie ctrl and phy */ | ||
389 | regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, | 455 | regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, |
390 | IMX6Q_GPR12_DEVICE_TYPE, PCI_EXP_TYPE_ROOT_PORT << 12); | 456 | IMX6Q_GPR12_DEVICE_TYPE, PCI_EXP_TYPE_ROOT_PORT << 12); |
391 | regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, | ||
392 | IMX6Q_GPR12_LOS_LEVEL, 9 << 4); | ||
393 | |||
394 | regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR8, | ||
395 | IMX6Q_GPR8_TX_DEEMPH_GEN1, | ||
396 | imx6_pcie->tx_deemph_gen1 << 0); | ||
397 | regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR8, | ||
398 | IMX6Q_GPR8_TX_DEEMPH_GEN2_3P5DB, | ||
399 | imx6_pcie->tx_deemph_gen2_3p5db << 6); | ||
400 | regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR8, | ||
401 | IMX6Q_GPR8_TX_DEEMPH_GEN2_6DB, | ||
402 | imx6_pcie->tx_deemph_gen2_6db << 12); | ||
403 | regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR8, | ||
404 | IMX6Q_GPR8_TX_SWING_FULL, | ||
405 | imx6_pcie->tx_swing_full << 18); | ||
406 | regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR8, | ||
407 | IMX6Q_GPR8_TX_SWING_LOW, | ||
408 | imx6_pcie->tx_swing_low << 25); | ||
409 | } | 457 | } |
410 | 458 | ||
411 | static int imx6_pcie_wait_for_link(struct imx6_pcie *imx6_pcie) | 459 | static int imx6_pcie_wait_for_link(struct imx6_pcie *imx6_pcie) |
@@ -469,8 +517,11 @@ static int imx6_pcie_establish_link(struct imx6_pcie *imx6_pcie) | |||
469 | dw_pcie_writel_dbi(pci, PCIE_RC_LCR, tmp); | 517 | dw_pcie_writel_dbi(pci, PCIE_RC_LCR, tmp); |
470 | 518 | ||
471 | /* Start LTSSM. */ | 519 | /* Start LTSSM. */ |
472 | regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, | 520 | if (imx6_pcie->variant == IMX7D) |
473 | IMX6Q_GPR12_PCIE_CTL_2, 1 << 10); | 521 | reset_control_deassert(imx6_pcie->apps_reset); |
522 | else | ||
523 | regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, | ||
524 | IMX6Q_GPR12_PCIE_CTL_2, 1 << 10); | ||
474 | 525 | ||
475 | ret = imx6_pcie_wait_for_link(imx6_pcie); | 526 | ret = imx6_pcie_wait_for_link(imx6_pcie); |
476 | if (ret) | 527 | if (ret) |
@@ -653,13 +704,31 @@ static int __init imx6_pcie_probe(struct platform_device *pdev) | |||
653 | return PTR_ERR(imx6_pcie->pcie); | 704 | return PTR_ERR(imx6_pcie->pcie); |
654 | } | 705 | } |
655 | 706 | ||
656 | if (imx6_pcie->variant == IMX6SX) { | 707 | switch (imx6_pcie->variant) { |
708 | case IMX6SX: | ||
657 | imx6_pcie->pcie_inbound_axi = devm_clk_get(dev, | 709 | imx6_pcie->pcie_inbound_axi = devm_clk_get(dev, |
658 | "pcie_inbound_axi"); | 710 | "pcie_inbound_axi"); |
659 | if (IS_ERR(imx6_pcie->pcie_inbound_axi)) { | 711 | if (IS_ERR(imx6_pcie->pcie_inbound_axi)) { |
660 | dev_err(dev, "pcie_inbound_axi clock missing or invalid\n"); | 712 | dev_err(dev, "pcie_inbound_axi clock missing or invalid\n"); |
661 | return PTR_ERR(imx6_pcie->pcie_inbound_axi); | 713 | return PTR_ERR(imx6_pcie->pcie_inbound_axi); |
662 | } | 714 | } |
715 | break; | ||
716 | case IMX7D: | ||
717 | imx6_pcie->pciephy_reset = devm_reset_control_get(dev, | ||
718 | "pciephy"); | ||
719 | if (IS_ERR(imx6_pcie->pciephy_reset)) { | ||
720 | dev_err(dev, "Failed to get PCIEPHY reset contol\n"); | ||
721 | return PTR_ERR(imx6_pcie->pciephy_reset); | ||
722 | } | ||
723 | |||
724 | imx6_pcie->apps_reset = devm_reset_control_get(dev, "apps"); | ||
725 | if (IS_ERR(imx6_pcie->apps_reset)) { | ||
726 | dev_err(dev, "Failed to get PCIE APPS reset contol\n"); | ||
727 | return PTR_ERR(imx6_pcie->apps_reset); | ||
728 | } | ||
729 | break; | ||
730 | default: | ||
731 | break; | ||
663 | } | 732 | } |
664 | 733 | ||
665 | /* Grab GPR config register range */ | 734 | /* Grab GPR config register range */ |
@@ -718,6 +787,7 @@ static const struct of_device_id imx6_pcie_of_match[] = { | |||
718 | { .compatible = "fsl,imx6q-pcie", .data = (void *)IMX6Q, }, | 787 | { .compatible = "fsl,imx6q-pcie", .data = (void *)IMX6Q, }, |
719 | { .compatible = "fsl,imx6sx-pcie", .data = (void *)IMX6SX, }, | 788 | { .compatible = "fsl,imx6sx-pcie", .data = (void *)IMX6SX, }, |
720 | { .compatible = "fsl,imx6qp-pcie", .data = (void *)IMX6QP, }, | 789 | { .compatible = "fsl,imx6qp-pcie", .data = (void *)IMX6QP, }, |
790 | { .compatible = "fsl,imx7d-pcie", .data = (void *)IMX7D, }, | ||
721 | {}, | 791 | {}, |
722 | }; | 792 | }; |
723 | 793 | ||
diff --git a/include/linux/mfd/syscon/imx7-iomuxc-gpr.h b/include/linux/mfd/syscon/imx7-iomuxc-gpr.h index 4585d6105d68..abbd52466573 100644 --- a/include/linux/mfd/syscon/imx7-iomuxc-gpr.h +++ b/include/linux/mfd/syscon/imx7-iomuxc-gpr.h | |||
@@ -44,4 +44,8 @@ | |||
44 | 44 | ||
45 | #define IMX7D_GPR5_CSI_MUX_CONTROL_MIPI (0x1 << 4) | 45 | #define IMX7D_GPR5_CSI_MUX_CONTROL_MIPI (0x1 << 4) |
46 | 46 | ||
47 | #define IMX7D_GPR12_PCIE_PHY_REFCLK_SEL BIT(5) | ||
48 | |||
49 | #define IMX7D_GPR22_PCIE_PHY_PLL_LOCKED BIT(31) | ||
50 | |||
47 | #endif /* __LINUX_IMX7_IOMUXC_GPR_H */ | 51 | #endif /* __LINUX_IMX7_IOMUXC_GPR_H */ |