diff options
Diffstat (limited to 'drivers')
| -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"); |
