aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/controller/dwc
diff options
context:
space:
mode:
authorAndrey Smirnov <andrew.smirnov@gmail.com>2019-02-01 19:15:23 -0500
committerLorenzo Pieralisi <lorenzo.pieralisi@arm.com>2019-02-04 07:04:53 -0500
commit2d8ed461dbc9bc734185db92d2b9d1bb7b586b30 (patch)
tree75307ad84cf3b69422bf7ba6ac1272c52ac3d7d9 /drivers/pci/controller/dwc
parent4c458bb347ae016e75f6c61dab95ce530f4ff6fc (diff)
PCI: imx6: Add support for i.MX8MQ
Add code needed to support i.MX8MQ variant. Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com> Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> Reviewed-by: Lucas Stach <l.stach@pengutronix.de> Cc: Bjorn Helgaas <bhelgaas@google.com> Cc: Fabio Estevam <fabio.estevam@nxp.com> Cc: Chris Healy <cphealy@gmail.com> Cc: Lucas Stach <l.stach@pengutronix.de> Cc: Leonard Crestez <leonard.crestez@nxp.com> Cc: "A.s. Dong" <aisheng.dong@nxp.com> Cc: Richard Zhu <hongxing.zhu@nxp.com>
Diffstat (limited to 'drivers/pci/controller/dwc')
-rw-r--r--drivers/pci/controller/dwc/Kconfig4
-rw-r--r--drivers/pci/controller/dwc/pci-imx6.c77
2 files changed, 77 insertions, 4 deletions
diff --git a/drivers/pci/controller/dwc/Kconfig b/drivers/pci/controller/dwc/Kconfig
index 548c58223868..6ea74b1c0d94 100644
--- a/drivers/pci/controller/dwc/Kconfig
+++ b/drivers/pci/controller/dwc/Kconfig
@@ -89,8 +89,8 @@ config PCI_EXYNOS
89 select PCIE_DW_HOST 89 select PCIE_DW_HOST
90 90
91config PCI_IMX6 91config PCI_IMX6
92 bool "Freescale i.MX6/7 PCIe controller" 92 bool "Freescale i.MX6/7/8 PCIe controller"
93 depends on SOC_IMX6Q || SOC_IMX7D || (ARM && COMPILE_TEST) 93 depends on SOC_IMX6Q || SOC_IMX7D || (ARM64 && ARCH_MXC) || COMPILE_TEST
94 depends on PCI_MSI_IRQ_DOMAIN 94 depends on PCI_MSI_IRQ_DOMAIN
95 select PCIE_DW_HOST 95 select PCIE_DW_HOST
96 96
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
37enum imx6_pcie_variants { 44enum 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 */
279static int imx6q_pcie_abort_handler(unsigned long addr, 289static 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
312static int imx6_pcie_attach_pd(struct device *dev) 323static 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
401static 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
389static int imx6_pcie_enable_ref_clk(struct imx6_pcie *imx6_pcie) 407static 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
569static 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
534static void imx6_pcie_init_phy(struct imx6_pcie *imx6_pcie) 587static 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
576static int imx6_setup_phy_mpll(struct imx6_pcie *imx6_pcie) 638static 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
1122static const struct of_device_id imx6_pcie_of_match[] = { 1192static 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
1141static int __init imx6_pcie_init(void) 1212static 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}