diff options
Diffstat (limited to 'drivers/pci/controller/dwc/pci-dra7xx.c')
-rw-r--r-- | drivers/pci/controller/dwc/pci-dra7xx.c | 77 |
1 files changed, 77 insertions, 0 deletions
diff --git a/drivers/pci/controller/dwc/pci-dra7xx.c b/drivers/pci/controller/dwc/pci-dra7xx.c index a32d6dde7a57..5c72acb49c11 100644 --- a/drivers/pci/controller/dwc/pci-dra7xx.c +++ b/drivers/pci/controller/dwc/pci-dra7xx.c | |||
@@ -81,6 +81,10 @@ | |||
81 | #define MSI_REQ_GRANT BIT(0) | 81 | #define MSI_REQ_GRANT BIT(0) |
82 | #define MSI_VECTOR_SHIFT 7 | 82 | #define MSI_VECTOR_SHIFT 7 |
83 | 83 | ||
84 | #define PCIE_1LANE_2LANE_SELECTION BIT(13) | ||
85 | #define PCIE_B1C0_MODE_SEL BIT(2) | ||
86 | #define PCIE_B0_B1_TSYNCEN BIT(0) | ||
87 | |||
84 | struct dra7xx_pcie { | 88 | struct dra7xx_pcie { |
85 | struct dw_pcie *pci; | 89 | struct dw_pcie *pci; |
86 | void __iomem *base; /* DT ti_conf */ | 90 | void __iomem *base; /* DT ti_conf */ |
@@ -93,6 +97,7 @@ struct dra7xx_pcie { | |||
93 | 97 | ||
94 | struct dra7xx_pcie_of_data { | 98 | struct dra7xx_pcie_of_data { |
95 | enum dw_pcie_device_mode mode; | 99 | enum dw_pcie_device_mode mode; |
100 | u32 b1co_mode_sel_mask; | ||
96 | }; | 101 | }; |
97 | 102 | ||
98 | #define to_dra7xx_pcie(x) dev_get_drvdata((x)->dev) | 103 | #define to_dra7xx_pcie(x) dev_get_drvdata((x)->dev) |
@@ -529,6 +534,26 @@ static const struct dra7xx_pcie_of_data dra7xx_pcie_ep_of_data = { | |||
529 | .mode = DW_PCIE_EP_TYPE, | 534 | .mode = DW_PCIE_EP_TYPE, |
530 | }; | 535 | }; |
531 | 536 | ||
537 | static const struct dra7xx_pcie_of_data dra746_pcie_rc_of_data = { | ||
538 | .b1co_mode_sel_mask = BIT(2), | ||
539 | .mode = DW_PCIE_RC_TYPE, | ||
540 | }; | ||
541 | |||
542 | static const struct dra7xx_pcie_of_data dra726_pcie_rc_of_data = { | ||
543 | .b1co_mode_sel_mask = GENMASK(3, 2), | ||
544 | .mode = DW_PCIE_RC_TYPE, | ||
545 | }; | ||
546 | |||
547 | static const struct dra7xx_pcie_of_data dra746_pcie_ep_of_data = { | ||
548 | .b1co_mode_sel_mask = BIT(2), | ||
549 | .mode = DW_PCIE_EP_TYPE, | ||
550 | }; | ||
551 | |||
552 | static const struct dra7xx_pcie_of_data dra726_pcie_ep_of_data = { | ||
553 | .b1co_mode_sel_mask = GENMASK(3, 2), | ||
554 | .mode = DW_PCIE_EP_TYPE, | ||
555 | }; | ||
556 | |||
532 | static const struct of_device_id of_dra7xx_pcie_match[] = { | 557 | static const struct of_device_id of_dra7xx_pcie_match[] = { |
533 | { | 558 | { |
534 | .compatible = "ti,dra7-pcie", | 559 | .compatible = "ti,dra7-pcie", |
@@ -538,6 +563,22 @@ static const struct of_device_id of_dra7xx_pcie_match[] = { | |||
538 | .compatible = "ti,dra7-pcie-ep", | 563 | .compatible = "ti,dra7-pcie-ep", |
539 | .data = &dra7xx_pcie_ep_of_data, | 564 | .data = &dra7xx_pcie_ep_of_data, |
540 | }, | 565 | }, |
566 | { | ||
567 | .compatible = "ti,dra746-pcie-rc", | ||
568 | .data = &dra746_pcie_rc_of_data, | ||
569 | }, | ||
570 | { | ||
571 | .compatible = "ti,dra726-pcie-rc", | ||
572 | .data = &dra726_pcie_rc_of_data, | ||
573 | }, | ||
574 | { | ||
575 | .compatible = "ti,dra746-pcie-ep", | ||
576 | .data = &dra746_pcie_ep_of_data, | ||
577 | }, | ||
578 | { | ||
579 | .compatible = "ti,dra726-pcie-ep", | ||
580 | .data = &dra726_pcie_ep_of_data, | ||
581 | }, | ||
541 | {}, | 582 | {}, |
542 | }; | 583 | }; |
543 | 584 | ||
@@ -583,6 +624,34 @@ static int dra7xx_pcie_unaligned_memaccess(struct device *dev) | |||
583 | return ret; | 624 | return ret; |
584 | } | 625 | } |
585 | 626 | ||
627 | static int dra7xx_pcie_configure_two_lane(struct device *dev, | ||
628 | u32 b1co_mode_sel_mask) | ||
629 | { | ||
630 | struct device_node *np = dev->of_node; | ||
631 | struct regmap *pcie_syscon; | ||
632 | unsigned int pcie_reg; | ||
633 | u32 mask; | ||
634 | u32 val; | ||
635 | |||
636 | pcie_syscon = syscon_regmap_lookup_by_phandle(np, "ti,syscon-lane-sel"); | ||
637 | if (IS_ERR(pcie_syscon)) { | ||
638 | dev_err(dev, "unable to get ti,syscon-lane-sel\n"); | ||
639 | return -EINVAL; | ||
640 | } | ||
641 | |||
642 | if (of_property_read_u32_index(np, "ti,syscon-lane-sel", 1, | ||
643 | &pcie_reg)) { | ||
644 | dev_err(dev, "couldn't get lane selection reg offset\n"); | ||
645 | return -EINVAL; | ||
646 | } | ||
647 | |||
648 | mask = b1co_mode_sel_mask | PCIE_B0_B1_TSYNCEN; | ||
649 | val = PCIE_B1C0_MODE_SEL | PCIE_B0_B1_TSYNCEN; | ||
650 | regmap_update_bits(pcie_syscon, pcie_reg, mask, val); | ||
651 | |||
652 | return 0; | ||
653 | } | ||
654 | |||
586 | static int __init dra7xx_pcie_probe(struct platform_device *pdev) | 655 | static int __init dra7xx_pcie_probe(struct platform_device *pdev) |
587 | { | 656 | { |
588 | u32 reg; | 657 | u32 reg; |
@@ -603,6 +672,7 @@ static int __init dra7xx_pcie_probe(struct platform_device *pdev) | |||
603 | const struct of_device_id *match; | 672 | const struct of_device_id *match; |
604 | const struct dra7xx_pcie_of_data *data; | 673 | const struct dra7xx_pcie_of_data *data; |
605 | enum dw_pcie_device_mode mode; | 674 | enum dw_pcie_device_mode mode; |
675 | u32 b1co_mode_sel_mask; | ||
606 | 676 | ||
607 | match = of_match_device(of_match_ptr(of_dra7xx_pcie_match), dev); | 677 | match = of_match_device(of_match_ptr(of_dra7xx_pcie_match), dev); |
608 | if (!match) | 678 | if (!match) |
@@ -610,6 +680,7 @@ static int __init dra7xx_pcie_probe(struct platform_device *pdev) | |||
610 | 680 | ||
611 | data = (struct dra7xx_pcie_of_data *)match->data; | 681 | data = (struct dra7xx_pcie_of_data *)match->data; |
612 | mode = (enum dw_pcie_device_mode)data->mode; | 682 | mode = (enum dw_pcie_device_mode)data->mode; |
683 | b1co_mode_sel_mask = data->b1co_mode_sel_mask; | ||
613 | 684 | ||
614 | dra7xx = devm_kzalloc(dev, sizeof(*dra7xx), GFP_KERNEL); | 685 | dra7xx = devm_kzalloc(dev, sizeof(*dra7xx), GFP_KERNEL); |
615 | if (!dra7xx) | 686 | if (!dra7xx) |
@@ -665,6 +736,12 @@ static int __init dra7xx_pcie_probe(struct platform_device *pdev) | |||
665 | dra7xx->pci = pci; | 736 | dra7xx->pci = pci; |
666 | dra7xx->phy_count = phy_count; | 737 | dra7xx->phy_count = phy_count; |
667 | 738 | ||
739 | if (phy_count == 2) { | ||
740 | ret = dra7xx_pcie_configure_two_lane(dev, b1co_mode_sel_mask); | ||
741 | if (ret < 0) | ||
742 | dra7xx->phy_count = 1; /* Fallback to x1 lane mode */ | ||
743 | } | ||
744 | |||
668 | ret = dra7xx_pcie_enable_phy(dra7xx); | 745 | ret = dra7xx_pcie_enable_phy(dra7xx); |
669 | if (ret) { | 746 | if (ret) { |
670 | dev_err(dev, "failed to enable phy\n"); | 747 | dev_err(dev, "failed to enable phy\n"); |