diff options
Diffstat (limited to 'drivers/pci/dwc/pci-imx6.c')
-rw-r--r-- | drivers/pci/dwc/pci-imx6.c | 199 |
1 files changed, 145 insertions, 54 deletions
diff --git a/drivers/pci/dwc/pci-imx6.c b/drivers/pci/dwc/pci-imx6.c index 801e46cd266d..a98cba55c7f0 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) |
@@ -482,29 +533,40 @@ static int imx6_pcie_establish_link(struct imx6_pcie *imx6_pcie) | |||
482 | tmp &= ~PCIE_RC_LCR_MAX_LINK_SPEEDS_MASK; | 533 | tmp &= ~PCIE_RC_LCR_MAX_LINK_SPEEDS_MASK; |
483 | tmp |= PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN2; | 534 | tmp |= PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN2; |
484 | dw_pcie_writel_dbi(pci, PCIE_RC_LCR, tmp); | 535 | dw_pcie_writel_dbi(pci, PCIE_RC_LCR, tmp); |
485 | } else { | ||
486 | dev_info(dev, "Link: Gen2 disabled\n"); | ||
487 | } | ||
488 | |||
489 | /* | ||
490 | * Start Directed Speed Change so the best possible speed both link | ||
491 | * partners support can be negotiated. | ||
492 | */ | ||
493 | tmp = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL); | ||
494 | tmp |= PORT_LOGIC_SPEED_CHANGE; | ||
495 | dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, tmp); | ||
496 | 536 | ||
497 | ret = imx6_pcie_wait_for_speed_change(imx6_pcie); | 537 | /* |
498 | if (ret) { | 538 | * Start Directed Speed Change so the best possible |
499 | dev_err(dev, "Failed to bring link up!\n"); | 539 | * speed both link partners support can be negotiated. |
500 | goto err_reset_phy; | 540 | */ |
501 | } | 541 | tmp = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL); |
542 | tmp |= PORT_LOGIC_SPEED_CHANGE; | ||
543 | dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, tmp); | ||
544 | |||
545 | if (imx6_pcie->variant != IMX7D) { | ||
546 | /* | ||
547 | * On i.MX7, DIRECT_SPEED_CHANGE behaves differently | ||
548 | * from i.MX6 family when no link speed transition | ||
549 | * occurs and we go Gen1 -> yep, Gen1. The difference | ||
550 | * is that, in such case, it will not be cleared by HW | ||
551 | * which will cause the following code to report false | ||
552 | * failure. | ||
553 | */ | ||
554 | |||
555 | ret = imx6_pcie_wait_for_speed_change(imx6_pcie); | ||
556 | if (ret) { | ||
557 | dev_err(dev, "Failed to bring link up!\n"); | ||
558 | goto err_reset_phy; | ||
559 | } | ||
560 | } | ||
502 | 561 | ||
503 | /* Make sure link training is finished as well! */ | 562 | /* Make sure link training is finished as well! */ |
504 | ret = imx6_pcie_wait_for_link(imx6_pcie); | 563 | ret = imx6_pcie_wait_for_link(imx6_pcie); |
505 | if (ret) { | 564 | if (ret) { |
506 | dev_err(dev, "Failed to bring link up!\n"); | 565 | dev_err(dev, "Failed to bring link up!\n"); |
507 | goto err_reset_phy; | 566 | goto err_reset_phy; |
567 | } | ||
568 | } else { | ||
569 | dev_info(dev, "Link: Gen2 disabled\n"); | ||
508 | } | 570 | } |
509 | 571 | ||
510 | tmp = dw_pcie_readl_dbi(pci, PCIE_RC_LCSR); | 572 | tmp = dw_pcie_readl_dbi(pci, PCIE_RC_LCSR); |
@@ -544,8 +606,8 @@ static struct dw_pcie_host_ops imx6_pcie_host_ops = { | |||
544 | .host_init = imx6_pcie_host_init, | 606 | .host_init = imx6_pcie_host_init, |
545 | }; | 607 | }; |
546 | 608 | ||
547 | static int __init imx6_add_pcie_port(struct imx6_pcie *imx6_pcie, | 609 | static int imx6_add_pcie_port(struct imx6_pcie *imx6_pcie, |
548 | struct platform_device *pdev) | 610 | struct platform_device *pdev) |
549 | { | 611 | { |
550 | struct dw_pcie *pci = imx6_pcie->pci; | 612 | struct dw_pcie *pci = imx6_pcie->pci; |
551 | struct pcie_port *pp = &pci->pp; | 613 | struct pcie_port *pp = &pci->pp; |
@@ -585,7 +647,7 @@ static const struct dw_pcie_ops dw_pcie_ops = { | |||
585 | .link_up = imx6_pcie_link_up, | 647 | .link_up = imx6_pcie_link_up, |
586 | }; | 648 | }; |
587 | 649 | ||
588 | static int __init imx6_pcie_probe(struct platform_device *pdev) | 650 | static int imx6_pcie_probe(struct platform_device *pdev) |
589 | { | 651 | { |
590 | struct device *dev = &pdev->dev; | 652 | struct device *dev = &pdev->dev; |
591 | struct dw_pcie *pci; | 653 | struct dw_pcie *pci; |
@@ -609,10 +671,6 @@ static int __init imx6_pcie_probe(struct platform_device *pdev) | |||
609 | imx6_pcie->variant = | 671 | imx6_pcie->variant = |
610 | (enum imx6_pcie_variants)of_device_get_match_data(dev); | 672 | (enum imx6_pcie_variants)of_device_get_match_data(dev); |
611 | 673 | ||
612 | /* Added for PCI abort handling */ | ||
613 | hook_fault_code(16 + 6, imx6q_pcie_abort_handler, SIGBUS, 0, | ||
614 | "imprecise external abort"); | ||
615 | |||
616 | dbi_base = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 674 | dbi_base = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
617 | pci->dbi_base = devm_ioremap_resource(dev, dbi_base); | 675 | pci->dbi_base = devm_ioremap_resource(dev, dbi_base); |
618 | if (IS_ERR(pci->dbi_base)) | 676 | if (IS_ERR(pci->dbi_base)) |
@@ -632,6 +690,8 @@ static int __init imx6_pcie_probe(struct platform_device *pdev) | |||
632 | dev_err(dev, "unable to get reset gpio\n"); | 690 | dev_err(dev, "unable to get reset gpio\n"); |
633 | return ret; | 691 | return ret; |
634 | } | 692 | } |
693 | } else if (imx6_pcie->reset_gpio == -EPROBE_DEFER) { | ||
694 | return imx6_pcie->reset_gpio; | ||
635 | } | 695 | } |
636 | 696 | ||
637 | /* Fetch clocks */ | 697 | /* Fetch clocks */ |
@@ -653,13 +713,31 @@ static int __init imx6_pcie_probe(struct platform_device *pdev) | |||
653 | return PTR_ERR(imx6_pcie->pcie); | 713 | return PTR_ERR(imx6_pcie->pcie); |
654 | } | 714 | } |
655 | 715 | ||
656 | if (imx6_pcie->variant == IMX6SX) { | 716 | switch (imx6_pcie->variant) { |
717 | case IMX6SX: | ||
657 | imx6_pcie->pcie_inbound_axi = devm_clk_get(dev, | 718 | imx6_pcie->pcie_inbound_axi = devm_clk_get(dev, |
658 | "pcie_inbound_axi"); | 719 | "pcie_inbound_axi"); |
659 | if (IS_ERR(imx6_pcie->pcie_inbound_axi)) { | 720 | if (IS_ERR(imx6_pcie->pcie_inbound_axi)) { |
660 | dev_err(dev, "pcie_inbound_axi clock missing or invalid\n"); | 721 | dev_err(dev, "pcie_inbound_axi clock missing or invalid\n"); |
661 | return PTR_ERR(imx6_pcie->pcie_inbound_axi); | 722 | return PTR_ERR(imx6_pcie->pcie_inbound_axi); |
662 | } | 723 | } |
724 | break; | ||
725 | case IMX7D: | ||
726 | imx6_pcie->pciephy_reset = devm_reset_control_get(dev, | ||
727 | "pciephy"); | ||
728 | if (IS_ERR(imx6_pcie->pciephy_reset)) { | ||
729 | dev_err(dev, "Failed to get PCIEPHY reset control\n"); | ||
730 | return PTR_ERR(imx6_pcie->pciephy_reset); | ||
731 | } | ||
732 | |||
733 | imx6_pcie->apps_reset = devm_reset_control_get(dev, "apps"); | ||
734 | if (IS_ERR(imx6_pcie->apps_reset)) { | ||
735 | dev_err(dev, "Failed to get PCIE APPS reset control\n"); | ||
736 | return PTR_ERR(imx6_pcie->apps_reset); | ||
737 | } | ||
738 | break; | ||
739 | default: | ||
740 | break; | ||
663 | } | 741 | } |
664 | 742 | ||
665 | /* Grab GPR config register range */ | 743 | /* Grab GPR config register range */ |
@@ -718,6 +796,7 @@ static const struct of_device_id imx6_pcie_of_match[] = { | |||
718 | { .compatible = "fsl,imx6q-pcie", .data = (void *)IMX6Q, }, | 796 | { .compatible = "fsl,imx6q-pcie", .data = (void *)IMX6Q, }, |
719 | { .compatible = "fsl,imx6sx-pcie", .data = (void *)IMX6SX, }, | 797 | { .compatible = "fsl,imx6sx-pcie", .data = (void *)IMX6SX, }, |
720 | { .compatible = "fsl,imx6qp-pcie", .data = (void *)IMX6QP, }, | 798 | { .compatible = "fsl,imx6qp-pcie", .data = (void *)IMX6QP, }, |
799 | { .compatible = "fsl,imx7d-pcie", .data = (void *)IMX7D, }, | ||
721 | {}, | 800 | {}, |
722 | }; | 801 | }; |
723 | 802 | ||
@@ -725,12 +804,24 @@ static struct platform_driver imx6_pcie_driver = { | |||
725 | .driver = { | 804 | .driver = { |
726 | .name = "imx6q-pcie", | 805 | .name = "imx6q-pcie", |
727 | .of_match_table = imx6_pcie_of_match, | 806 | .of_match_table = imx6_pcie_of_match, |
807 | .suppress_bind_attrs = true, | ||
728 | }, | 808 | }, |
809 | .probe = imx6_pcie_probe, | ||
729 | .shutdown = imx6_pcie_shutdown, | 810 | .shutdown = imx6_pcie_shutdown, |
730 | }; | 811 | }; |
731 | 812 | ||
732 | static int __init imx6_pcie_init(void) | 813 | static int __init imx6_pcie_init(void) |
733 | { | 814 | { |
734 | return platform_driver_probe(&imx6_pcie_driver, imx6_pcie_probe); | 815 | /* |
816 | * Since probe() can be deferred we need to make sure that | ||
817 | * hook_fault_code is not called after __init memory is freed | ||
818 | * by kernel and since imx6q_pcie_abort_handler() is a no-op, | ||
819 | * we can install the handler here without risking it | ||
820 | * accessing some uninitialized driver state. | ||
821 | */ | ||
822 | hook_fault_code(16 + 6, imx6q_pcie_abort_handler, SIGBUS, 0, | ||
823 | "imprecise external abort"); | ||
824 | |||
825 | return platform_driver_register(&imx6_pcie_driver); | ||
735 | } | 826 | } |
736 | device_initcall(imx6_pcie_init); | 827 | device_initcall(imx6_pcie_init); |