diff options
Diffstat (limited to 'drivers/pci/controller/dwc/pci-imx6.c')
-rw-r--r-- | drivers/pci/controller/dwc/pci-imx6.c | 77 |
1 files changed, 75 insertions, 2 deletions
diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index 11b73d733dae..c1d434ba3642 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c | |||
@@ -8,6 +8,7 @@ | |||
8 | * Author: Sean Cross <xobs@kosagi.com> | 8 | * Author: Sean Cross <xobs@kosagi.com> |
9 | */ | 9 | */ |
10 | 10 | ||
11 | #include <linux/bitfield.h> | ||
11 | #include <linux/clk.h> | 12 | #include <linux/clk.h> |
12 | #include <linux/delay.h> | 13 | #include <linux/delay.h> |
13 | #include <linux/gpio.h> | 14 | #include <linux/gpio.h> |
@@ -32,6 +33,12 @@ | |||
32 | 33 | ||
33 | #include "pcie-designware.h" | 34 | #include "pcie-designware.h" |
34 | 35 | ||
36 | #define IMX8MQ_GPR_PCIE_REF_USE_PAD BIT(9) | ||
37 | #define IMX8MQ_GPR_PCIE_CLK_REQ_OVERRIDE_EN BIT(10) | ||
38 | #define IMX8MQ_GPR_PCIE_CLK_REQ_OVERRIDE BIT(11) | ||
39 | #define IMX8MQ_GPR12_PCIE2_CTRL_DEVICE_TYPE GENMASK(11, 8) | ||
40 | #define IMX8MQ_PCIE2_BASE_ADDR 0x33c00000 | ||
41 | |||
35 | #define to_imx6_pcie(x) dev_get_drvdata((x)->dev) | 42 | #define to_imx6_pcie(x) dev_get_drvdata((x)->dev) |
36 | 43 | ||
37 | enum imx6_pcie_variants { | 44 | enum imx6_pcie_variants { |
@@ -39,6 +46,7 @@ enum imx6_pcie_variants { | |||
39 | IMX6SX, | 46 | IMX6SX, |
40 | IMX6QP, | 47 | IMX6QP, |
41 | IMX7D, | 48 | IMX7D, |
49 | IMX8MQ, | ||
42 | }; | 50 | }; |
43 | 51 | ||
44 | #define IMX6_PCIE_FLAG_IMX6_PHY BIT(0) | 52 | #define IMX6_PCIE_FLAG_IMX6_PHY BIT(0) |
@@ -58,6 +66,7 @@ struct imx6_pcie { | |||
58 | struct clk *pcie_inbound_axi; | 66 | struct clk *pcie_inbound_axi; |
59 | struct clk *pcie; | 67 | struct clk *pcie; |
60 | struct regmap *iomuxc_gpr; | 68 | struct regmap *iomuxc_gpr; |
69 | u32 controller_id; | ||
61 | struct reset_control *pciephy_reset; | 70 | struct reset_control *pciephy_reset; |
62 | struct reset_control *apps_reset; | 71 | struct reset_control *apps_reset; |
63 | struct reset_control *turnoff_reset; | 72 | struct reset_control *turnoff_reset; |
@@ -275,6 +284,7 @@ static void imx6_pcie_reset_phy(struct imx6_pcie *imx6_pcie) | |||
275 | pcie_phy_write(imx6_pcie, PHY_RX_OVRD_IN_LO, tmp); | 284 | pcie_phy_write(imx6_pcie, PHY_RX_OVRD_IN_LO, tmp); |
276 | } | 285 | } |
277 | 286 | ||
287 | #ifdef CONFIG_ARM | ||
278 | /* Added for PCI abort handling */ | 288 | /* Added for PCI abort handling */ |
279 | static int imx6q_pcie_abort_handler(unsigned long addr, | 289 | static int imx6q_pcie_abort_handler(unsigned long addr, |
280 | unsigned int fsr, struct pt_regs *regs) | 290 | unsigned int fsr, struct pt_regs *regs) |
@@ -308,6 +318,7 @@ static int imx6q_pcie_abort_handler(unsigned long addr, | |||
308 | 318 | ||
309 | return 1; | 319 | return 1; |
310 | } | 320 | } |
321 | #endif | ||
311 | 322 | ||
312 | static int imx6_pcie_attach_pd(struct device *dev) | 323 | static int imx6_pcie_attach_pd(struct device *dev) |
313 | { | 324 | { |
@@ -352,6 +363,7 @@ static void imx6_pcie_assert_core_reset(struct imx6_pcie *imx6_pcie) | |||
352 | 363 | ||
353 | switch (imx6_pcie->drvdata->variant) { | 364 | switch (imx6_pcie->drvdata->variant) { |
354 | case IMX7D: | 365 | case IMX7D: |
366 | case IMX8MQ: | ||
355 | reset_control_assert(imx6_pcie->pciephy_reset); | 367 | reset_control_assert(imx6_pcie->pciephy_reset); |
356 | reset_control_assert(imx6_pcie->apps_reset); | 368 | reset_control_assert(imx6_pcie->apps_reset); |
357 | break; | 369 | break; |
@@ -386,10 +398,17 @@ static void imx6_pcie_assert_core_reset(struct imx6_pcie *imx6_pcie) | |||
386 | } | 398 | } |
387 | } | 399 | } |
388 | 400 | ||
401 | static unsigned int imx6_pcie_grp_offset(const struct imx6_pcie *imx6_pcie) | ||
402 | { | ||
403 | WARN_ON(imx6_pcie->drvdata->variant != IMX8MQ); | ||
404 | return imx6_pcie->controller_id == 1 ? IOMUXC_GPR16 : IOMUXC_GPR14; | ||
405 | } | ||
406 | |||
389 | static int imx6_pcie_enable_ref_clk(struct imx6_pcie *imx6_pcie) | 407 | static int imx6_pcie_enable_ref_clk(struct imx6_pcie *imx6_pcie) |
390 | { | 408 | { |
391 | struct dw_pcie *pci = imx6_pcie->pci; | 409 | struct dw_pcie *pci = imx6_pcie->pci; |
392 | struct device *dev = pci->dev; | 410 | struct device *dev = pci->dev; |
411 | unsigned int offset; | ||
393 | int ret = 0; | 412 | int ret = 0; |
394 | 413 | ||
395 | switch (imx6_pcie->drvdata->variant) { | 414 | switch (imx6_pcie->drvdata->variant) { |
@@ -420,6 +439,19 @@ static int imx6_pcie_enable_ref_clk(struct imx6_pcie *imx6_pcie) | |||
420 | break; | 439 | break; |
421 | case IMX7D: | 440 | case IMX7D: |
422 | break; | 441 | break; |
442 | case IMX8MQ: | ||
443 | offset = imx6_pcie_grp_offset(imx6_pcie); | ||
444 | /* | ||
445 | * Set the over ride low and enabled | ||
446 | * make sure that REF_CLK is turned on. | ||
447 | */ | ||
448 | regmap_update_bits(imx6_pcie->iomuxc_gpr, offset, | ||
449 | IMX8MQ_GPR_PCIE_CLK_REQ_OVERRIDE, | ||
450 | 0); | ||
451 | regmap_update_bits(imx6_pcie->iomuxc_gpr, offset, | ||
452 | IMX8MQ_GPR_PCIE_CLK_REQ_OVERRIDE_EN, | ||
453 | IMX8MQ_GPR_PCIE_CLK_REQ_OVERRIDE_EN); | ||
454 | break; | ||
423 | } | 455 | } |
424 | 456 | ||
425 | return ret; | 457 | return ret; |
@@ -496,6 +528,9 @@ static void imx6_pcie_deassert_core_reset(struct imx6_pcie *imx6_pcie) | |||
496 | } | 528 | } |
497 | 529 | ||
498 | switch (imx6_pcie->drvdata->variant) { | 530 | switch (imx6_pcie->drvdata->variant) { |
531 | case IMX8MQ: | ||
532 | reset_control_deassert(imx6_pcie->pciephy_reset); | ||
533 | break; | ||
499 | case IMX7D: | 534 | case IMX7D: |
500 | reset_control_deassert(imx6_pcie->pciephy_reset); | 535 | reset_control_deassert(imx6_pcie->pciephy_reset); |
501 | imx7d_pcie_wait_for_phy_pll_lock(imx6_pcie); | 536 | imx7d_pcie_wait_for_phy_pll_lock(imx6_pcie); |
@@ -531,9 +566,37 @@ err_pcie_phy: | |||
531 | } | 566 | } |
532 | } | 567 | } |
533 | 568 | ||
569 | static void imx6_pcie_configure_type(struct imx6_pcie *imx6_pcie) | ||
570 | { | ||
571 | unsigned int mask, val; | ||
572 | |||
573 | if (imx6_pcie->drvdata->variant == IMX8MQ && | ||
574 | imx6_pcie->controller_id == 1) { | ||
575 | mask = IMX8MQ_GPR12_PCIE2_CTRL_DEVICE_TYPE; | ||
576 | val = FIELD_PREP(IMX8MQ_GPR12_PCIE2_CTRL_DEVICE_TYPE, | ||
577 | PCI_EXP_TYPE_ROOT_PORT); | ||
578 | } else { | ||
579 | mask = IMX6Q_GPR12_DEVICE_TYPE; | ||
580 | val = FIELD_PREP(IMX6Q_GPR12_DEVICE_TYPE, | ||
581 | PCI_EXP_TYPE_ROOT_PORT); | ||
582 | } | ||
583 | |||
584 | regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, mask, val); | ||
585 | } | ||
586 | |||
534 | static void imx6_pcie_init_phy(struct imx6_pcie *imx6_pcie) | 587 | static void imx6_pcie_init_phy(struct imx6_pcie *imx6_pcie) |
535 | { | 588 | { |
536 | switch (imx6_pcie->drvdata->variant) { | 589 | switch (imx6_pcie->drvdata->variant) { |
590 | case IMX8MQ: | ||
591 | /* | ||
592 | * TODO: Currently this code assumes external | ||
593 | * oscillator is being used | ||
594 | */ | ||
595 | regmap_update_bits(imx6_pcie->iomuxc_gpr, | ||
596 | imx6_pcie_grp_offset(imx6_pcie), | ||
597 | IMX8MQ_GPR_PCIE_REF_USE_PAD, | ||
598 | IMX8MQ_GPR_PCIE_REF_USE_PAD); | ||
599 | break; | ||
537 | case IMX7D: | 600 | case IMX7D: |
538 | regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, | 601 | regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, |
539 | IMX7D_GPR12_PCIE_PHY_REFCLK_SEL, 0); | 602 | IMX7D_GPR12_PCIE_PHY_REFCLK_SEL, 0); |
@@ -569,8 +632,7 @@ static void imx6_pcie_init_phy(struct imx6_pcie *imx6_pcie) | |||
569 | break; | 632 | break; |
570 | } | 633 | } |
571 | 634 | ||
572 | regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, | 635 | imx6_pcie_configure_type(imx6_pcie); |
573 | IMX6Q_GPR12_DEVICE_TYPE, PCI_EXP_TYPE_ROOT_PORT << 12); | ||
574 | } | 636 | } |
575 | 637 | ||
576 | static int imx6_setup_phy_mpll(struct imx6_pcie *imx6_pcie) | 638 | static int imx6_setup_phy_mpll(struct imx6_pcie *imx6_pcie) |
@@ -667,6 +729,7 @@ static void imx6_pcie_ltssm_enable(struct device *dev) | |||
667 | IMX6Q_GPR12_PCIE_CTL_2); | 729 | IMX6Q_GPR12_PCIE_CTL_2); |
668 | break; | 730 | break; |
669 | case IMX7D: | 731 | case IMX7D: |
732 | case IMX8MQ: | ||
670 | reset_control_deassert(imx6_pcie->apps_reset); | 733 | reset_control_deassert(imx6_pcie->apps_reset); |
671 | break; | 734 | break; |
672 | } | 735 | } |
@@ -1002,6 +1065,10 @@ static int imx6_pcie_probe(struct platform_device *pdev) | |||
1002 | } | 1065 | } |
1003 | break; | 1066 | break; |
1004 | case IMX7D: | 1067 | case IMX7D: |
1068 | case IMX8MQ: | ||
1069 | if (dbi_base->start == IMX8MQ_PCIE2_BASE_ADDR) | ||
1070 | imx6_pcie->controller_id = 1; | ||
1071 | |||
1005 | imx6_pcie->pciephy_reset = devm_reset_control_get_exclusive(dev, | 1072 | imx6_pcie->pciephy_reset = devm_reset_control_get_exclusive(dev, |
1006 | "pciephy"); | 1073 | "pciephy"); |
1007 | if (IS_ERR(imx6_pcie->pciephy_reset)) { | 1074 | if (IS_ERR(imx6_pcie->pciephy_reset)) { |
@@ -1117,6 +1184,9 @@ static const struct imx6_pcie_drvdata drvdata[] = { | |||
1117 | [IMX7D] = { | 1184 | [IMX7D] = { |
1118 | .variant = IMX7D, | 1185 | .variant = IMX7D, |
1119 | }, | 1186 | }, |
1187 | [IMX8MQ] = { | ||
1188 | .variant = IMX8MQ, | ||
1189 | }, | ||
1120 | }; | 1190 | }; |
1121 | 1191 | ||
1122 | static const struct of_device_id imx6_pcie_of_match[] = { | 1192 | static const struct of_device_id imx6_pcie_of_match[] = { |
@@ -1124,6 +1194,7 @@ static const struct of_device_id imx6_pcie_of_match[] = { | |||
1124 | { .compatible = "fsl,imx6sx-pcie", .data = &drvdata[IMX6SX], }, | 1194 | { .compatible = "fsl,imx6sx-pcie", .data = &drvdata[IMX6SX], }, |
1125 | { .compatible = "fsl,imx6qp-pcie", .data = &drvdata[IMX6QP], }, | 1195 | { .compatible = "fsl,imx6qp-pcie", .data = &drvdata[IMX6QP], }, |
1126 | { .compatible = "fsl,imx7d-pcie", .data = &drvdata[IMX7D], }, | 1196 | { .compatible = "fsl,imx7d-pcie", .data = &drvdata[IMX7D], }, |
1197 | { .compatible = "fsl,imx8mq-pcie", .data = &drvdata[IMX8MQ], } , | ||
1127 | {}, | 1198 | {}, |
1128 | }; | 1199 | }; |
1129 | 1200 | ||
@@ -1140,6 +1211,7 @@ static struct platform_driver imx6_pcie_driver = { | |||
1140 | 1211 | ||
1141 | static int __init imx6_pcie_init(void) | 1212 | static int __init imx6_pcie_init(void) |
1142 | { | 1213 | { |
1214 | #ifdef CONFIG_ARM | ||
1143 | /* | 1215 | /* |
1144 | * Since probe() can be deferred we need to make sure that | 1216 | * Since probe() can be deferred we need to make sure that |
1145 | * hook_fault_code is not called after __init memory is freed | 1217 | * hook_fault_code is not called after __init memory is freed |
@@ -1149,6 +1221,7 @@ static int __init imx6_pcie_init(void) | |||
1149 | */ | 1221 | */ |
1150 | hook_fault_code(8, imx6q_pcie_abort_handler, SIGBUS, 0, | 1222 | hook_fault_code(8, imx6q_pcie_abort_handler, SIGBUS, 0, |
1151 | "external abort on non-linefetch"); | 1223 | "external abort on non-linefetch"); |
1224 | #endif | ||
1152 | 1225 | ||
1153 | return platform_driver_register(&imx6_pcie_driver); | 1226 | return platform_driver_register(&imx6_pcie_driver); |
1154 | } | 1227 | } |