diff options
-rw-r--r-- | Documentation/devicetree/bindings/pci/qcom,pcie.txt | 20 | ||||
-rw-r--r-- | drivers/pci/dwc/pcie-qcom.c | 435 |
2 files changed, 396 insertions, 59 deletions
diff --git a/Documentation/devicetree/bindings/pci/qcom,pcie.txt b/Documentation/devicetree/bindings/pci/qcom,pcie.txt index e15f9b19901f..9d418b71774f 100644 --- a/Documentation/devicetree/bindings/pci/qcom,pcie.txt +++ b/Documentation/devicetree/bindings/pci/qcom,pcie.txt | |||
@@ -8,6 +8,7 @@ | |||
8 | - "qcom,pcie-apq8064" for apq8064 | 8 | - "qcom,pcie-apq8064" for apq8064 |
9 | - "qcom,pcie-apq8084" for apq8084 | 9 | - "qcom,pcie-apq8084" for apq8084 |
10 | - "qcom,pcie-msm8996" for msm8996 or apq8096 | 10 | - "qcom,pcie-msm8996" for msm8996 or apq8096 |
11 | - "qcom,pcie-ipq4019" for ipq4019 | ||
11 | 12 | ||
12 | - reg: | 13 | - reg: |
13 | Usage: required | 14 | Usage: required |
@@ -87,7 +88,7 @@ | |||
87 | - "core" Clocks the pcie hw block | 88 | - "core" Clocks the pcie hw block |
88 | - "phy" Clocks the pcie PHY block | 89 | - "phy" Clocks the pcie PHY block |
89 | - clock-names: | 90 | - clock-names: |
90 | Usage: required for apq8084 | 91 | Usage: required for apq8084/ipq4019 |
91 | Value type: <stringlist> | 92 | Value type: <stringlist> |
92 | Definition: Should contain the following entries | 93 | Definition: Should contain the following entries |
93 | - "aux" Auxiliary (AUX) clock | 94 | - "aux" Auxiliary (AUX) clock |
@@ -126,6 +127,23 @@ | |||
126 | Definition: Should contain the following entries | 127 | Definition: Should contain the following entries |
127 | - "core" Core reset | 128 | - "core" Core reset |
128 | 129 | ||
130 | - reset-names: | ||
131 | Usage: required for ipq/apq8064 | ||
132 | Value type: <stringlist> | ||
133 | Definition: Should contain the following entries | ||
134 | - "axi_m" AXI master reset | ||
135 | - "axi_s" AXI slave reset | ||
136 | - "pipe" PIPE reset | ||
137 | - "axi_m_vmid" VMID reset | ||
138 | - "axi_s_xpu" XPU reset | ||
139 | - "parf" PARF reset | ||
140 | - "phy" PHY reset | ||
141 | - "axi_m_sticky" AXI sticky reset | ||
142 | - "pipe_sticky" PIPE sticky reset | ||
143 | - "pwr" PWR reset | ||
144 | - "ahb" AHB reset | ||
145 | - "phy_ahb" PHY AHB reset | ||
146 | |||
129 | - power-domains: | 147 | - power-domains: |
130 | Usage: required for apq8084 and msm8996/apq8096 | 148 | Usage: required for apq8084 and msm8996/apq8096 |
131 | Value type: <prop-encoded-array> | 149 | Value type: <prop-encoded-array> |
diff --git a/drivers/pci/dwc/pcie-qcom.c b/drivers/pci/dwc/pcie-qcom.c index 39e8c0095715..68c5f2ab5bc8 100644 --- a/drivers/pci/dwc/pcie-qcom.c +++ b/drivers/pci/dwc/pcie-qcom.c | |||
@@ -51,6 +51,12 @@ | |||
51 | #define PCIE20_ELBI_SYS_CTRL 0x04 | 51 | #define PCIE20_ELBI_SYS_CTRL 0x04 |
52 | #define PCIE20_ELBI_SYS_CTRL_LT_ENABLE BIT(0) | 52 | #define PCIE20_ELBI_SYS_CTRL_LT_ENABLE BIT(0) |
53 | 53 | ||
54 | #define PCIE20_AXI_MSTR_RESP_COMP_CTRL0 0x818 | ||
55 | #define CFG_REMOTE_RD_REQ_BRIDGE_SIZE_2K 0x4 | ||
56 | #define CFG_REMOTE_RD_REQ_BRIDGE_SIZE_4K 0x5 | ||
57 | #define PCIE20_AXI_MSTR_RESP_COMP_CTRL1 0x81c | ||
58 | #define CFG_BRIDGE_SB_INIT BIT(0) | ||
59 | |||
54 | #define PCIE20_CAP 0x70 | 60 | #define PCIE20_CAP 0x70 |
55 | 61 | ||
56 | #define PERST_DELAY_US 1000 | 62 | #define PERST_DELAY_US 1000 |
@@ -86,10 +92,29 @@ struct qcom_pcie_resources_v2 { | |||
86 | struct clk *pipe_clk; | 92 | struct clk *pipe_clk; |
87 | }; | 93 | }; |
88 | 94 | ||
95 | struct qcom_pcie_resources_v3 { | ||
96 | struct clk *aux_clk; | ||
97 | struct clk *master_clk; | ||
98 | struct clk *slave_clk; | ||
99 | struct reset_control *axi_m_reset; | ||
100 | struct reset_control *axi_s_reset; | ||
101 | struct reset_control *pipe_reset; | ||
102 | struct reset_control *axi_m_vmid_reset; | ||
103 | struct reset_control *axi_s_xpu_reset; | ||
104 | struct reset_control *parf_reset; | ||
105 | struct reset_control *phy_reset; | ||
106 | struct reset_control *axi_m_sticky_reset; | ||
107 | struct reset_control *pipe_sticky_reset; | ||
108 | struct reset_control *pwr_reset; | ||
109 | struct reset_control *ahb_reset; | ||
110 | struct reset_control *phy_ahb_reset; | ||
111 | }; | ||
112 | |||
89 | union qcom_pcie_resources { | 113 | union qcom_pcie_resources { |
90 | struct qcom_pcie_resources_v0 v0; | 114 | struct qcom_pcie_resources_v0 v0; |
91 | struct qcom_pcie_resources_v1 v1; | 115 | struct qcom_pcie_resources_v1 v1; |
92 | struct qcom_pcie_resources_v2 v2; | 116 | struct qcom_pcie_resources_v2 v2; |
117 | struct qcom_pcie_resources_v3 v3; | ||
93 | }; | 118 | }; |
94 | 119 | ||
95 | struct qcom_pcie; | 120 | struct qcom_pcie; |
@@ -133,26 +158,6 @@ static irqreturn_t qcom_pcie_msi_irq_handler(int irq, void *arg) | |||
133 | return dw_handle_msi_irq(pp); | 158 | return dw_handle_msi_irq(pp); |
134 | } | 159 | } |
135 | 160 | ||
136 | static void qcom_pcie_v0_v1_ltssm_enable(struct qcom_pcie *pcie) | ||
137 | { | ||
138 | u32 val; | ||
139 | |||
140 | /* enable link training */ | ||
141 | val = readl(pcie->elbi + PCIE20_ELBI_SYS_CTRL); | ||
142 | val |= PCIE20_ELBI_SYS_CTRL_LT_ENABLE; | ||
143 | writel(val, pcie->elbi + PCIE20_ELBI_SYS_CTRL); | ||
144 | } | ||
145 | |||
146 | static void qcom_pcie_v2_ltssm_enable(struct qcom_pcie *pcie) | ||
147 | { | ||
148 | u32 val; | ||
149 | |||
150 | /* enable link training */ | ||
151 | val = readl(pcie->parf + PCIE20_PARF_LTSSM); | ||
152 | val |= BIT(8); | ||
153 | writel(val, pcie->parf + PCIE20_PARF_LTSSM); | ||
154 | } | ||
155 | |||
156 | static int qcom_pcie_establish_link(struct qcom_pcie *pcie) | 161 | static int qcom_pcie_establish_link(struct qcom_pcie *pcie) |
157 | { | 162 | { |
158 | struct dw_pcie *pci = pcie->pci; | 163 | struct dw_pcie *pci = pcie->pci; |
@@ -167,6 +172,16 @@ static int qcom_pcie_establish_link(struct qcom_pcie *pcie) | |||
167 | return dw_pcie_wait_for_link(pci); | 172 | return dw_pcie_wait_for_link(pci); |
168 | } | 173 | } |
169 | 174 | ||
175 | static void qcom_pcie_v0_v1_ltssm_enable(struct qcom_pcie *pcie) | ||
176 | { | ||
177 | u32 val; | ||
178 | |||
179 | /* enable link training */ | ||
180 | val = readl(pcie->elbi + PCIE20_ELBI_SYS_CTRL); | ||
181 | val |= PCIE20_ELBI_SYS_CTRL_LT_ENABLE; | ||
182 | writel(val, pcie->elbi + PCIE20_ELBI_SYS_CTRL); | ||
183 | } | ||
184 | |||
170 | static int qcom_pcie_get_resources_v0(struct qcom_pcie *pcie) | 185 | static int qcom_pcie_get_resources_v0(struct qcom_pcie *pcie) |
171 | { | 186 | { |
172 | struct qcom_pcie_resources_v0 *res = &pcie->res.v0; | 187 | struct qcom_pcie_resources_v0 *res = &pcie->res.v0; |
@@ -217,36 +232,6 @@ static int qcom_pcie_get_resources_v0(struct qcom_pcie *pcie) | |||
217 | return PTR_ERR_OR_ZERO(res->phy_reset); | 232 | return PTR_ERR_OR_ZERO(res->phy_reset); |
218 | } | 233 | } |
219 | 234 | ||
220 | static int qcom_pcie_get_resources_v1(struct qcom_pcie *pcie) | ||
221 | { | ||
222 | struct qcom_pcie_resources_v1 *res = &pcie->res.v1; | ||
223 | struct dw_pcie *pci = pcie->pci; | ||
224 | struct device *dev = pci->dev; | ||
225 | |||
226 | res->vdda = devm_regulator_get(dev, "vdda"); | ||
227 | if (IS_ERR(res->vdda)) | ||
228 | return PTR_ERR(res->vdda); | ||
229 | |||
230 | res->iface = devm_clk_get(dev, "iface"); | ||
231 | if (IS_ERR(res->iface)) | ||
232 | return PTR_ERR(res->iface); | ||
233 | |||
234 | res->aux = devm_clk_get(dev, "aux"); | ||
235 | if (IS_ERR(res->aux)) | ||
236 | return PTR_ERR(res->aux); | ||
237 | |||
238 | res->master_bus = devm_clk_get(dev, "master_bus"); | ||
239 | if (IS_ERR(res->master_bus)) | ||
240 | return PTR_ERR(res->master_bus); | ||
241 | |||
242 | res->slave_bus = devm_clk_get(dev, "slave_bus"); | ||
243 | if (IS_ERR(res->slave_bus)) | ||
244 | return PTR_ERR(res->slave_bus); | ||
245 | |||
246 | res->core = devm_reset_control_get(dev, "core"); | ||
247 | return PTR_ERR_OR_ZERO(res->core); | ||
248 | } | ||
249 | |||
250 | static void qcom_pcie_deinit_v0(struct qcom_pcie *pcie) | 235 | static void qcom_pcie_deinit_v0(struct qcom_pcie *pcie) |
251 | { | 236 | { |
252 | struct qcom_pcie_resources_v0 *res = &pcie->res.v0; | 237 | struct qcom_pcie_resources_v0 *res = &pcie->res.v0; |
@@ -357,6 +342,13 @@ static int qcom_pcie_init_v0(struct qcom_pcie *pcie) | |||
357 | /* wait for clock acquisition */ | 342 | /* wait for clock acquisition */ |
358 | usleep_range(1000, 1500); | 343 | usleep_range(1000, 1500); |
359 | 344 | ||
345 | |||
346 | /* Set the Max TLP size to 2K, instead of using default of 4K */ | ||
347 | writel(CFG_REMOTE_RD_REQ_BRIDGE_SIZE_2K, | ||
348 | pci->dbi_base + PCIE20_AXI_MSTR_RESP_COMP_CTRL0); | ||
349 | writel(CFG_BRIDGE_SB_INIT, | ||
350 | pci->dbi_base + PCIE20_AXI_MSTR_RESP_COMP_CTRL1); | ||
351 | |||
360 | return 0; | 352 | return 0; |
361 | 353 | ||
362 | err_deassert_ahb: | 354 | err_deassert_ahb: |
@@ -375,6 +367,36 @@ err_refclk: | |||
375 | return ret; | 367 | return ret; |
376 | } | 368 | } |
377 | 369 | ||
370 | static int qcom_pcie_get_resources_v1(struct qcom_pcie *pcie) | ||
371 | { | ||
372 | struct qcom_pcie_resources_v1 *res = &pcie->res.v1; | ||
373 | struct dw_pcie *pci = pcie->pci; | ||
374 | struct device *dev = pci->dev; | ||
375 | |||
376 | res->vdda = devm_regulator_get(dev, "vdda"); | ||
377 | if (IS_ERR(res->vdda)) | ||
378 | return PTR_ERR(res->vdda); | ||
379 | |||
380 | res->iface = devm_clk_get(dev, "iface"); | ||
381 | if (IS_ERR(res->iface)) | ||
382 | return PTR_ERR(res->iface); | ||
383 | |||
384 | res->aux = devm_clk_get(dev, "aux"); | ||
385 | if (IS_ERR(res->aux)) | ||
386 | return PTR_ERR(res->aux); | ||
387 | |||
388 | res->master_bus = devm_clk_get(dev, "master_bus"); | ||
389 | if (IS_ERR(res->master_bus)) | ||
390 | return PTR_ERR(res->master_bus); | ||
391 | |||
392 | res->slave_bus = devm_clk_get(dev, "slave_bus"); | ||
393 | if (IS_ERR(res->slave_bus)) | ||
394 | return PTR_ERR(res->slave_bus); | ||
395 | |||
396 | res->core = devm_reset_control_get(dev, "core"); | ||
397 | return PTR_ERR_OR_ZERO(res->core); | ||
398 | } | ||
399 | |||
378 | static void qcom_pcie_deinit_v1(struct qcom_pcie *pcie) | 400 | static void qcom_pcie_deinit_v1(struct qcom_pcie *pcie) |
379 | { | 401 | { |
380 | struct qcom_pcie_resources_v1 *res = &pcie->res.v1; | 402 | struct qcom_pcie_resources_v1 *res = &pcie->res.v1; |
@@ -455,6 +477,16 @@ err_res: | |||
455 | return ret; | 477 | return ret; |
456 | } | 478 | } |
457 | 479 | ||
480 | static void qcom_pcie_v2_ltssm_enable(struct qcom_pcie *pcie) | ||
481 | { | ||
482 | u32 val; | ||
483 | |||
484 | /* enable link training */ | ||
485 | val = readl(pcie->parf + PCIE20_PARF_LTSSM); | ||
486 | val |= BIT(8); | ||
487 | writel(val, pcie->parf + PCIE20_PARF_LTSSM); | ||
488 | } | ||
489 | |||
458 | static int qcom_pcie_get_resources_v2(struct qcom_pcie *pcie) | 490 | static int qcom_pcie_get_resources_v2(struct qcom_pcie *pcie) |
459 | { | 491 | { |
460 | struct qcom_pcie_resources_v2 *res = &pcie->res.v2; | 492 | struct qcom_pcie_resources_v2 *res = &pcie->res.v2; |
@@ -481,6 +513,17 @@ static int qcom_pcie_get_resources_v2(struct qcom_pcie *pcie) | |||
481 | return PTR_ERR_OR_ZERO(res->pipe_clk); | 513 | return PTR_ERR_OR_ZERO(res->pipe_clk); |
482 | } | 514 | } |
483 | 515 | ||
516 | static void qcom_pcie_deinit_v2(struct qcom_pcie *pcie) | ||
517 | { | ||
518 | struct qcom_pcie_resources_v2 *res = &pcie->res.v2; | ||
519 | |||
520 | clk_disable_unprepare(res->pipe_clk); | ||
521 | clk_disable_unprepare(res->slave_clk); | ||
522 | clk_disable_unprepare(res->master_clk); | ||
523 | clk_disable_unprepare(res->cfg_clk); | ||
524 | clk_disable_unprepare(res->aux_clk); | ||
525 | } | ||
526 | |||
484 | static int qcom_pcie_init_v2(struct qcom_pcie *pcie) | 527 | static int qcom_pcie_init_v2(struct qcom_pcie *pcie) |
485 | { | 528 | { |
486 | struct qcom_pcie_resources_v2 *res = &pcie->res.v2; | 529 | struct qcom_pcie_resources_v2 *res = &pcie->res.v2; |
@@ -562,22 +605,290 @@ static int qcom_pcie_post_init_v2(struct qcom_pcie *pcie) | |||
562 | return 0; | 605 | return 0; |
563 | } | 606 | } |
564 | 607 | ||
565 | static int qcom_pcie_link_up(struct dw_pcie *pci) | 608 | static int qcom_pcie_get_resources_v3(struct qcom_pcie *pcie) |
566 | { | 609 | { |
567 | u16 val = readw(pci->dbi_base + PCIE20_CAP + PCI_EXP_LNKSTA); | 610 | struct qcom_pcie_resources_v3 *res = &pcie->res.v3; |
611 | struct dw_pcie *pci = pcie->pci; | ||
612 | struct device *dev = pci->dev; | ||
568 | 613 | ||
569 | return !!(val & PCI_EXP_LNKSTA_DLLLA); | 614 | res->aux_clk = devm_clk_get(dev, "aux"); |
615 | if (IS_ERR(res->aux_clk)) | ||
616 | return PTR_ERR(res->aux_clk); | ||
617 | |||
618 | res->master_clk = devm_clk_get(dev, "master_bus"); | ||
619 | if (IS_ERR(res->master_clk)) | ||
620 | return PTR_ERR(res->master_clk); | ||
621 | |||
622 | res->slave_clk = devm_clk_get(dev, "slave_bus"); | ||
623 | if (IS_ERR(res->slave_clk)) | ||
624 | return PTR_ERR(res->slave_clk); | ||
625 | |||
626 | res->axi_m_reset = devm_reset_control_get(dev, "axi_m"); | ||
627 | if (IS_ERR(res->axi_m_reset)) | ||
628 | return PTR_ERR(res->axi_m_reset); | ||
629 | |||
630 | res->axi_s_reset = devm_reset_control_get(dev, "axi_s"); | ||
631 | if (IS_ERR(res->axi_s_reset)) | ||
632 | return PTR_ERR(res->axi_s_reset); | ||
633 | |||
634 | res->pipe_reset = devm_reset_control_get(dev, "pipe"); | ||
635 | if (IS_ERR(res->pipe_reset)) | ||
636 | return PTR_ERR(res->pipe_reset); | ||
637 | |||
638 | res->axi_m_vmid_reset = devm_reset_control_get(dev, "axi_m_vmid"); | ||
639 | if (IS_ERR(res->axi_m_vmid_reset)) | ||
640 | return PTR_ERR(res->axi_m_vmid_reset); | ||
641 | |||
642 | res->axi_s_xpu_reset = devm_reset_control_get(dev, "axi_s_xpu"); | ||
643 | if (IS_ERR(res->axi_s_xpu_reset)) | ||
644 | return PTR_ERR(res->axi_s_xpu_reset); | ||
645 | |||
646 | res->parf_reset = devm_reset_control_get(dev, "parf"); | ||
647 | if (IS_ERR(res->parf_reset)) | ||
648 | return PTR_ERR(res->parf_reset); | ||
649 | |||
650 | res->phy_reset = devm_reset_control_get(dev, "phy"); | ||
651 | if (IS_ERR(res->phy_reset)) | ||
652 | return PTR_ERR(res->phy_reset); | ||
653 | |||
654 | res->axi_m_sticky_reset = devm_reset_control_get(dev, "axi_m_sticky"); | ||
655 | if (IS_ERR(res->axi_m_sticky_reset)) | ||
656 | return PTR_ERR(res->axi_m_sticky_reset); | ||
657 | |||
658 | res->pipe_sticky_reset = devm_reset_control_get(dev, "pipe_sticky"); | ||
659 | if (IS_ERR(res->pipe_sticky_reset)) | ||
660 | return PTR_ERR(res->pipe_sticky_reset); | ||
661 | |||
662 | res->pwr_reset = devm_reset_control_get(dev, "pwr"); | ||
663 | if (IS_ERR(res->pwr_reset)) | ||
664 | return PTR_ERR(res->pwr_reset); | ||
665 | |||
666 | res->ahb_reset = devm_reset_control_get(dev, "ahb"); | ||
667 | if (IS_ERR(res->ahb_reset)) | ||
668 | return PTR_ERR(res->ahb_reset); | ||
669 | |||
670 | res->phy_ahb_reset = devm_reset_control_get(dev, "phy_ahb"); | ||
671 | if (IS_ERR(res->phy_ahb_reset)) | ||
672 | return PTR_ERR(res->phy_ahb_reset); | ||
673 | |||
674 | return 0; | ||
570 | } | 675 | } |
571 | 676 | ||
572 | static void qcom_pcie_deinit_v2(struct qcom_pcie *pcie) | 677 | static void qcom_pcie_deinit_v3(struct qcom_pcie *pcie) |
573 | { | 678 | { |
574 | struct qcom_pcie_resources_v2 *res = &pcie->res.v2; | 679 | struct qcom_pcie_resources_v3 *res = &pcie->res.v3; |
575 | 680 | ||
576 | clk_disable_unprepare(res->pipe_clk); | 681 | reset_control_assert(res->axi_m_reset); |
682 | reset_control_assert(res->axi_s_reset); | ||
683 | reset_control_assert(res->pipe_reset); | ||
684 | reset_control_assert(res->pipe_sticky_reset); | ||
685 | reset_control_assert(res->phy_reset); | ||
686 | reset_control_assert(res->phy_ahb_reset); | ||
687 | reset_control_assert(res->axi_m_sticky_reset); | ||
688 | reset_control_assert(res->pwr_reset); | ||
689 | reset_control_assert(res->ahb_reset); | ||
690 | clk_disable_unprepare(res->aux_clk); | ||
691 | clk_disable_unprepare(res->master_clk); | ||
577 | clk_disable_unprepare(res->slave_clk); | 692 | clk_disable_unprepare(res->slave_clk); |
693 | } | ||
694 | |||
695 | static int qcom_pcie_init_v3(struct qcom_pcie *pcie) | ||
696 | { | ||
697 | struct qcom_pcie_resources_v3 *res = &pcie->res.v3; | ||
698 | struct dw_pcie *pci = pcie->pci; | ||
699 | struct device *dev = pci->dev; | ||
700 | u32 val; | ||
701 | int ret; | ||
702 | |||
703 | ret = reset_control_assert(res->axi_m_reset); | ||
704 | if (ret) { | ||
705 | dev_err(dev, "cannot assert axi master reset\n"); | ||
706 | return ret; | ||
707 | } | ||
708 | |||
709 | ret = reset_control_assert(res->axi_s_reset); | ||
710 | if (ret) { | ||
711 | dev_err(dev, "cannot assert axi slave reset\n"); | ||
712 | return ret; | ||
713 | } | ||
714 | |||
715 | usleep_range(10000, 12000); | ||
716 | |||
717 | ret = reset_control_assert(res->pipe_reset); | ||
718 | if (ret) { | ||
719 | dev_err(dev, "cannot assert pipe reset\n"); | ||
720 | return ret; | ||
721 | } | ||
722 | |||
723 | ret = reset_control_assert(res->pipe_sticky_reset); | ||
724 | if (ret) { | ||
725 | dev_err(dev, "cannot assert pipe sticky reset\n"); | ||
726 | return ret; | ||
727 | } | ||
728 | |||
729 | ret = reset_control_assert(res->phy_reset); | ||
730 | if (ret) { | ||
731 | dev_err(dev, "cannot assert phy reset\n"); | ||
732 | return ret; | ||
733 | } | ||
734 | |||
735 | ret = reset_control_assert(res->phy_ahb_reset); | ||
736 | if (ret) { | ||
737 | dev_err(dev, "cannot assert phy ahb reset\n"); | ||
738 | return ret; | ||
739 | } | ||
740 | |||
741 | usleep_range(10000, 12000); | ||
742 | |||
743 | ret = reset_control_assert(res->axi_m_sticky_reset); | ||
744 | if (ret) { | ||
745 | dev_err(dev, "cannot assert axi master sticky reset\n"); | ||
746 | return ret; | ||
747 | } | ||
748 | |||
749 | ret = reset_control_assert(res->pwr_reset); | ||
750 | if (ret) { | ||
751 | dev_err(dev, "cannot assert power reset\n"); | ||
752 | return ret; | ||
753 | } | ||
754 | |||
755 | ret = reset_control_assert(res->ahb_reset); | ||
756 | if (ret) { | ||
757 | dev_err(dev, "cannot assert ahb reset\n"); | ||
758 | return ret; | ||
759 | } | ||
760 | |||
761 | usleep_range(10000, 12000); | ||
762 | |||
763 | ret = reset_control_deassert(res->phy_ahb_reset); | ||
764 | if (ret) { | ||
765 | dev_err(dev, "cannot deassert phy ahb reset\n"); | ||
766 | return ret; | ||
767 | } | ||
768 | |||
769 | ret = reset_control_deassert(res->phy_reset); | ||
770 | if (ret) { | ||
771 | dev_err(dev, "cannot deassert phy reset\n"); | ||
772 | goto err_rst_phy; | ||
773 | } | ||
774 | |||
775 | ret = reset_control_deassert(res->pipe_reset); | ||
776 | if (ret) { | ||
777 | dev_err(dev, "cannot deassert pipe reset\n"); | ||
778 | goto err_rst_pipe; | ||
779 | } | ||
780 | |||
781 | ret = reset_control_deassert(res->pipe_sticky_reset); | ||
782 | if (ret) { | ||
783 | dev_err(dev, "cannot deassert pipe sticky reset\n"); | ||
784 | goto err_rst_pipe_sticky; | ||
785 | } | ||
786 | |||
787 | usleep_range(10000, 12000); | ||
788 | |||
789 | ret = reset_control_deassert(res->axi_m_reset); | ||
790 | if (ret) { | ||
791 | dev_err(dev, "cannot deassert axi master reset\n"); | ||
792 | goto err_rst_axi_m; | ||
793 | } | ||
794 | |||
795 | ret = reset_control_deassert(res->axi_m_sticky_reset); | ||
796 | if (ret) { | ||
797 | dev_err(dev, "cannot deassert axi master sticky reset\n"); | ||
798 | goto err_rst_axi_m_sticky; | ||
799 | } | ||
800 | |||
801 | ret = reset_control_deassert(res->axi_s_reset); | ||
802 | if (ret) { | ||
803 | dev_err(dev, "cannot deassert axi slave reset\n"); | ||
804 | goto err_rst_axi_s; | ||
805 | } | ||
806 | |||
807 | ret = reset_control_deassert(res->pwr_reset); | ||
808 | if (ret) { | ||
809 | dev_err(dev, "cannot deassert power reset\n"); | ||
810 | goto err_rst_pwr; | ||
811 | } | ||
812 | |||
813 | ret = reset_control_deassert(res->ahb_reset); | ||
814 | if (ret) { | ||
815 | dev_err(dev, "cannot deassert ahb reset\n"); | ||
816 | goto err_rst_ahb; | ||
817 | } | ||
818 | |||
819 | usleep_range(10000, 12000); | ||
820 | |||
821 | ret = clk_prepare_enable(res->aux_clk); | ||
822 | if (ret) { | ||
823 | dev_err(dev, "cannot prepare/enable iface clock\n"); | ||
824 | goto err_clk_aux; | ||
825 | } | ||
826 | |||
827 | ret = clk_prepare_enable(res->master_clk); | ||
828 | if (ret) { | ||
829 | dev_err(dev, "cannot prepare/enable core clock\n"); | ||
830 | goto err_clk_axi_m; | ||
831 | } | ||
832 | |||
833 | ret = clk_prepare_enable(res->slave_clk); | ||
834 | if (ret) { | ||
835 | dev_err(dev, "cannot prepare/enable phy clock\n"); | ||
836 | goto err_clk_axi_s; | ||
837 | } | ||
838 | |||
839 | /* enable PCIe clocks and resets */ | ||
840 | val = readl(pcie->parf + PCIE20_PARF_PHY_CTRL); | ||
841 | val &= !BIT(0); | ||
842 | writel(val, pcie->parf + PCIE20_PARF_PHY_CTRL); | ||
843 | |||
844 | /* change DBI base address */ | ||
845 | writel(0, pcie->parf + PCIE20_PARF_DBI_BASE_ADDR); | ||
846 | |||
847 | /* MAC PHY_POWERDOWN MUX DISABLE */ | ||
848 | val = readl(pcie->parf + PCIE20_PARF_SYS_CTRL); | ||
849 | val &= ~BIT(29); | ||
850 | writel(val, pcie->parf + PCIE20_PARF_SYS_CTRL); | ||
851 | |||
852 | val = readl(pcie->parf + PCIE20_PARF_MHI_CLOCK_RESET_CTRL); | ||
853 | val |= BIT(4); | ||
854 | writel(val, pcie->parf + PCIE20_PARF_MHI_CLOCK_RESET_CTRL); | ||
855 | |||
856 | val = readl(pcie->parf + PCIE20_PARF_AXI_MSTR_WR_ADDR_HALT_V2); | ||
857 | val |= BIT(31); | ||
858 | writel(val, pcie->parf + PCIE20_PARF_AXI_MSTR_WR_ADDR_HALT_V2); | ||
859 | |||
860 | return 0; | ||
861 | |||
862 | err_clk_axi_s: | ||
578 | clk_disable_unprepare(res->master_clk); | 863 | clk_disable_unprepare(res->master_clk); |
579 | clk_disable_unprepare(res->cfg_clk); | 864 | err_clk_axi_m: |
580 | clk_disable_unprepare(res->aux_clk); | 865 | clk_disable_unprepare(res->aux_clk); |
866 | err_clk_aux: | ||
867 | reset_control_assert(res->ahb_reset); | ||
868 | err_rst_ahb: | ||
869 | reset_control_assert(res->pwr_reset); | ||
870 | err_rst_pwr: | ||
871 | reset_control_assert(res->axi_s_reset); | ||
872 | err_rst_axi_s: | ||
873 | reset_control_assert(res->axi_m_sticky_reset); | ||
874 | err_rst_axi_m_sticky: | ||
875 | reset_control_assert(res->axi_m_reset); | ||
876 | err_rst_axi_m: | ||
877 | reset_control_assert(res->pipe_sticky_reset); | ||
878 | err_rst_pipe_sticky: | ||
879 | reset_control_assert(res->pipe_reset); | ||
880 | err_rst_pipe: | ||
881 | reset_control_assert(res->phy_reset); | ||
882 | err_rst_phy: | ||
883 | reset_control_assert(res->phy_ahb_reset); | ||
884 | return ret; | ||
885 | } | ||
886 | |||
887 | static int qcom_pcie_link_up(struct dw_pcie *pci) | ||
888 | { | ||
889 | u16 val = readw(pci->dbi_base + PCIE20_CAP + PCI_EXP_LNKSTA); | ||
890 | |||
891 | return !!(val & PCI_EXP_LNKSTA_DLLLA); | ||
581 | } | 892 | } |
582 | 893 | ||
583 | static void qcom_pcie_host_init(struct pcie_port *pp) | 894 | static void qcom_pcie_host_init(struct pcie_port *pp) |
@@ -665,6 +976,13 @@ static const struct dw_pcie_ops dw_pcie_ops = { | |||
665 | .link_up = qcom_pcie_link_up, | 976 | .link_up = qcom_pcie_link_up, |
666 | }; | 977 | }; |
667 | 978 | ||
979 | static const struct qcom_pcie_ops ops_v3 = { | ||
980 | .get_resources = qcom_pcie_get_resources_v3, | ||
981 | .init = qcom_pcie_init_v3, | ||
982 | .deinit = qcom_pcie_deinit_v3, | ||
983 | .ltssm_enable = qcom_pcie_v2_ltssm_enable, | ||
984 | }; | ||
985 | |||
668 | static int qcom_pcie_probe(struct platform_device *pdev) | 986 | static int qcom_pcie_probe(struct platform_device *pdev) |
669 | { | 987 | { |
670 | struct device *dev = &pdev->dev; | 988 | struct device *dev = &pdev->dev; |
@@ -755,6 +1073,7 @@ static const struct of_device_id qcom_pcie_match[] = { | |||
755 | { .compatible = "qcom,pcie-apq8064", .data = &ops_v0 }, | 1073 | { .compatible = "qcom,pcie-apq8064", .data = &ops_v0 }, |
756 | { .compatible = "qcom,pcie-apq8084", .data = &ops_v1 }, | 1074 | { .compatible = "qcom,pcie-apq8084", .data = &ops_v1 }, |
757 | { .compatible = "qcom,pcie-msm8996", .data = &ops_v2 }, | 1075 | { .compatible = "qcom,pcie-msm8996", .data = &ops_v2 }, |
1076 | { .compatible = "qcom,pcie-ipq4019", .data = &ops_v3 }, | ||
758 | { } | 1077 | { } |
759 | }; | 1078 | }; |
760 | 1079 | ||