aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBjorn Helgaas <bhelgaas@google.com>2016-12-12 12:25:10 -0500
committerBjorn Helgaas <bhelgaas@google.com>2016-12-12 12:25:10 -0500
commitaee10cd4c12aaa4d89d3355e669eb5025885094d (patch)
tree7f6d4263234ce9eac67c320e0310e10a0c9c1755
parent46275d43c8dbf13d8b0c6e7a455608eeb220a677 (diff)
parentd0491fc39bdd45575cd0094af18703d38665a309 (diff)
Merge branch 'pci/host-qcom' into next
* pci/host-qcom: PCI: qcom: Add support for MSM8996 PCIe controller
-rw-r--r--Documentation/devicetree/bindings/pci/qcom,pcie.txt14
-rw-r--r--drivers/pci/host/pcie-qcom.c177
2 files changed, 185 insertions, 6 deletions
diff --git a/Documentation/devicetree/bindings/pci/qcom,pcie.txt b/Documentation/devicetree/bindings/pci/qcom,pcie.txt
index 4059a6f89bc1..e15f9b19901f 100644
--- a/Documentation/devicetree/bindings/pci/qcom,pcie.txt
+++ b/Documentation/devicetree/bindings/pci/qcom,pcie.txt
@@ -7,6 +7,7 @@
7 - "qcom,pcie-ipq8064" for ipq8064 7 - "qcom,pcie-ipq8064" for ipq8064
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 11
11- reg: 12- reg:
12 Usage: required 13 Usage: required
@@ -92,6 +93,17 @@
92 - "aux" Auxiliary (AUX) clock 93 - "aux" Auxiliary (AUX) clock
93 - "bus_master" Master AXI clock 94 - "bus_master" Master AXI clock
94 - "bus_slave" Slave AXI clock 95 - "bus_slave" Slave AXI clock
96
97- clock-names:
98 Usage: required for msm8996/apq8096
99 Value type: <stringlist>
100 Definition: Should contain the following entries
101 - "pipe" Pipe Clock driving internal logic
102 - "aux" Auxiliary (AUX) clock
103 - "cfg" Configuration clock
104 - "bus_master" Master AXI clock
105 - "bus_slave" Slave AXI clock
106
95- resets: 107- resets:
96 Usage: required 108 Usage: required
97 Value type: <prop-encoded-array> 109 Value type: <prop-encoded-array>
@@ -115,7 +127,7 @@
115 - "core" Core reset 127 - "core" Core reset
116 128
117- power-domains: 129- power-domains:
118 Usage: required for apq8084 130 Usage: required for apq8084 and msm8996/apq8096
119 Value type: <prop-encoded-array> 131 Value type: <prop-encoded-array>
120 Definition: A phandle and power domain specifier pair to the 132 Definition: A phandle and power domain specifier pair to the
121 power domain which is responsible for collapsing 133 power domain which is responsible for collapsing
diff --git a/drivers/pci/host/pcie-qcom.c b/drivers/pci/host/pcie-qcom.c
index ef0a84c7a588..8b02db2da6cc 100644
--- a/drivers/pci/host/pcie-qcom.c
+++ b/drivers/pci/host/pcie-qcom.c
@@ -36,11 +36,17 @@
36 36
37#include "pcie-designware.h" 37#include "pcie-designware.h"
38 38
39#define PCIE20_PARF_SYS_CTRL 0x00
39#define PCIE20_PARF_PHY_CTRL 0x40 40#define PCIE20_PARF_PHY_CTRL 0x40
40#define PCIE20_PARF_PHY_REFCLK 0x4C 41#define PCIE20_PARF_PHY_REFCLK 0x4C
41#define PCIE20_PARF_DBI_BASE_ADDR 0x168 42#define PCIE20_PARF_DBI_BASE_ADDR 0x168
42#define PCIE20_PARF_SLV_ADDR_SPACE_SIZE 0x16c 43#define PCIE20_PARF_SLV_ADDR_SPACE_SIZE 0x16C
44#define PCIE20_PARF_MHI_CLOCK_RESET_CTRL 0x174
43#define PCIE20_PARF_AXI_MSTR_WR_ADDR_HALT 0x178 45#define PCIE20_PARF_AXI_MSTR_WR_ADDR_HALT 0x178
46#define PCIE20_PARF_AXI_MSTR_WR_ADDR_HALT_V2 0x1A8
47#define PCIE20_PARF_LTSSM 0x1B0
48#define PCIE20_PARF_SID_OFFSET 0x234
49#define PCIE20_PARF_BDF_TRANSLATE_CFG 0x24C
44 50
45#define PCIE20_ELBI_SYS_CTRL 0x04 51#define PCIE20_ELBI_SYS_CTRL 0x04
46#define PCIE20_ELBI_SYS_CTRL_LT_ENABLE BIT(0) 52#define PCIE20_ELBI_SYS_CTRL_LT_ENABLE BIT(0)
@@ -72,9 +78,18 @@ struct qcom_pcie_resources_v1 {
72 struct regulator *vdda; 78 struct regulator *vdda;
73}; 79};
74 80
81struct qcom_pcie_resources_v2 {
82 struct clk *aux_clk;
83 struct clk *master_clk;
84 struct clk *slave_clk;
85 struct clk *cfg_clk;
86 struct clk *pipe_clk;
87};
88
75union qcom_pcie_resources { 89union qcom_pcie_resources {
76 struct qcom_pcie_resources_v0 v0; 90 struct qcom_pcie_resources_v0 v0;
77 struct qcom_pcie_resources_v1 v1; 91 struct qcom_pcie_resources_v1 v1;
92 struct qcom_pcie_resources_v2 v2;
78}; 93};
79 94
80struct qcom_pcie; 95struct qcom_pcie;
@@ -82,7 +97,9 @@ struct qcom_pcie;
82struct qcom_pcie_ops { 97struct qcom_pcie_ops {
83 int (*get_resources)(struct qcom_pcie *pcie); 98 int (*get_resources)(struct qcom_pcie *pcie);
84 int (*init)(struct qcom_pcie *pcie); 99 int (*init)(struct qcom_pcie *pcie);
100 int (*post_init)(struct qcom_pcie *pcie);
85 void (*deinit)(struct qcom_pcie *pcie); 101 void (*deinit)(struct qcom_pcie *pcie);
102 void (*ltssm_enable)(struct qcom_pcie *pcie);
86}; 103};
87 104
88struct qcom_pcie { 105struct qcom_pcie {
@@ -116,17 +133,35 @@ static irqreturn_t qcom_pcie_msi_irq_handler(int irq, void *arg)
116 return dw_handle_msi_irq(pp); 133 return dw_handle_msi_irq(pp);
117} 134}
118 135
119static int qcom_pcie_establish_link(struct qcom_pcie *pcie) 136static void qcom_pcie_v0_v1_ltssm_enable(struct qcom_pcie *pcie)
120{ 137{
121 u32 val; 138 u32 val;
122 139
123 if (dw_pcie_link_up(&pcie->pp))
124 return 0;
125
126 /* enable link training */ 140 /* enable link training */
127 val = readl(pcie->elbi + PCIE20_ELBI_SYS_CTRL); 141 val = readl(pcie->elbi + PCIE20_ELBI_SYS_CTRL);
128 val |= PCIE20_ELBI_SYS_CTRL_LT_ENABLE; 142 val |= PCIE20_ELBI_SYS_CTRL_LT_ENABLE;
129 writel(val, pcie->elbi + PCIE20_ELBI_SYS_CTRL); 143 writel(val, pcie->elbi + PCIE20_ELBI_SYS_CTRL);
144}
145
146static 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
156static int qcom_pcie_establish_link(struct qcom_pcie *pcie)
157{
158
159 if (dw_pcie_link_up(&pcie->pp))
160 return 0;
161
162 /* Enable Link Training state machine */
163 if (pcie->ops->ltssm_enable)
164 pcie->ops->ltssm_enable(pcie);
130 165
131 return dw_pcie_wait_for_link(&pcie->pp); 166 return dw_pcie_wait_for_link(&pcie->pp);
132} 167}
@@ -421,6 +456,113 @@ err_res:
421 return ret; 456 return ret;
422} 457}
423 458
459static int qcom_pcie_get_resources_v2(struct qcom_pcie *pcie)
460{
461 struct qcom_pcie_resources_v2 *res = &pcie->res.v2;
462 struct device *dev = pcie->pp.dev;
463
464 res->aux_clk = devm_clk_get(dev, "aux");
465 if (IS_ERR(res->aux_clk))
466 return PTR_ERR(res->aux_clk);
467
468 res->cfg_clk = devm_clk_get(dev, "cfg");
469 if (IS_ERR(res->cfg_clk))
470 return PTR_ERR(res->cfg_clk);
471
472 res->master_clk = devm_clk_get(dev, "bus_master");
473 if (IS_ERR(res->master_clk))
474 return PTR_ERR(res->master_clk);
475
476 res->slave_clk = devm_clk_get(dev, "bus_slave");
477 if (IS_ERR(res->slave_clk))
478 return PTR_ERR(res->slave_clk);
479
480 res->pipe_clk = devm_clk_get(dev, "pipe");
481 if (IS_ERR(res->pipe_clk))
482 return PTR_ERR(res->pipe_clk);
483
484 return 0;
485}
486
487static int qcom_pcie_init_v2(struct qcom_pcie *pcie)
488{
489 struct qcom_pcie_resources_v2 *res = &pcie->res.v2;
490 struct device *dev = pcie->pp.dev;
491 u32 val;
492 int ret;
493
494 ret = clk_prepare_enable(res->aux_clk);
495 if (ret) {
496 dev_err(dev, "cannot prepare/enable aux clock\n");
497 return ret;
498 }
499
500 ret = clk_prepare_enable(res->cfg_clk);
501 if (ret) {
502 dev_err(dev, "cannot prepare/enable cfg clock\n");
503 goto err_cfg_clk;
504 }
505
506 ret = clk_prepare_enable(res->master_clk);
507 if (ret) {
508 dev_err(dev, "cannot prepare/enable master clock\n");
509 goto err_master_clk;
510 }
511
512 ret = clk_prepare_enable(res->slave_clk);
513 if (ret) {
514 dev_err(dev, "cannot prepare/enable slave clock\n");
515 goto err_slave_clk;
516 }
517
518 /* enable PCIe clocks and resets */
519 val = readl(pcie->parf + PCIE20_PARF_PHY_CTRL);
520 val &= ~BIT(0);
521 writel(val, pcie->parf + PCIE20_PARF_PHY_CTRL);
522
523 /* change DBI base address */
524 writel(0, pcie->parf + PCIE20_PARF_DBI_BASE_ADDR);
525
526 /* MAC PHY_POWERDOWN MUX DISABLE */
527 val = readl(pcie->parf + PCIE20_PARF_SYS_CTRL);
528 val &= ~BIT(29);
529 writel(val, pcie->parf + PCIE20_PARF_SYS_CTRL);
530
531 val = readl(pcie->parf + PCIE20_PARF_MHI_CLOCK_RESET_CTRL);
532 val |= BIT(4);
533 writel(val, pcie->parf + PCIE20_PARF_MHI_CLOCK_RESET_CTRL);
534
535 val = readl(pcie->parf + PCIE20_PARF_AXI_MSTR_WR_ADDR_HALT_V2);
536 val |= BIT(31);
537 writel(val, pcie->parf + PCIE20_PARF_AXI_MSTR_WR_ADDR_HALT_V2);
538
539 return 0;
540
541err_slave_clk:
542 clk_disable_unprepare(res->master_clk);
543err_master_clk:
544 clk_disable_unprepare(res->cfg_clk);
545err_cfg_clk:
546 clk_disable_unprepare(res->aux_clk);
547
548 return ret;
549}
550
551static int qcom_pcie_post_init_v2(struct qcom_pcie *pcie)
552{
553 struct qcom_pcie_resources_v2 *res = &pcie->res.v2;
554 struct device *dev = pcie->pp.dev;
555 int ret;
556
557 ret = clk_prepare_enable(res->pipe_clk);
558 if (ret) {
559 dev_err(dev, "cannot prepare/enable pipe clock\n");
560 return ret;
561 }
562
563 return 0;
564}
565
424static int qcom_pcie_link_up(struct pcie_port *pp) 566static int qcom_pcie_link_up(struct pcie_port *pp)
425{ 567{
426 struct qcom_pcie *pcie = to_qcom_pcie(pp); 568 struct qcom_pcie *pcie = to_qcom_pcie(pp);
@@ -429,6 +571,17 @@ static int qcom_pcie_link_up(struct pcie_port *pp)
429 return !!(val & PCI_EXP_LNKSTA_DLLLA); 571 return !!(val & PCI_EXP_LNKSTA_DLLLA);
430} 572}
431 573
574static void qcom_pcie_deinit_v2(struct qcom_pcie *pcie)
575{
576 struct qcom_pcie_resources_v2 *res = &pcie->res.v2;
577
578 clk_disable_unprepare(res->pipe_clk);
579 clk_disable_unprepare(res->slave_clk);
580 clk_disable_unprepare(res->master_clk);
581 clk_disable_unprepare(res->cfg_clk);
582 clk_disable_unprepare(res->aux_clk);
583}
584
432static void qcom_pcie_host_init(struct pcie_port *pp) 585static void qcom_pcie_host_init(struct pcie_port *pp)
433{ 586{
434 struct qcom_pcie *pcie = to_qcom_pcie(pp); 587 struct qcom_pcie *pcie = to_qcom_pcie(pp);
@@ -444,6 +597,9 @@ static void qcom_pcie_host_init(struct pcie_port *pp)
444 if (ret) 597 if (ret)
445 goto err_deinit; 598 goto err_deinit;
446 599
600 if (pcie->ops->post_init)
601 pcie->ops->post_init(pcie);
602
447 dw_pcie_setup_rc(pp); 603 dw_pcie_setup_rc(pp);
448 604
449 if (IS_ENABLED(CONFIG_PCI_MSI)) 605 if (IS_ENABLED(CONFIG_PCI_MSI))
@@ -487,12 +643,22 @@ static const struct qcom_pcie_ops ops_v0 = {
487 .get_resources = qcom_pcie_get_resources_v0, 643 .get_resources = qcom_pcie_get_resources_v0,
488 .init = qcom_pcie_init_v0, 644 .init = qcom_pcie_init_v0,
489 .deinit = qcom_pcie_deinit_v0, 645 .deinit = qcom_pcie_deinit_v0,
646 .ltssm_enable = qcom_pcie_v0_v1_ltssm_enable,
490}; 647};
491 648
492static const struct qcom_pcie_ops ops_v1 = { 649static const struct qcom_pcie_ops ops_v1 = {
493 .get_resources = qcom_pcie_get_resources_v1, 650 .get_resources = qcom_pcie_get_resources_v1,
494 .init = qcom_pcie_init_v1, 651 .init = qcom_pcie_init_v1,
495 .deinit = qcom_pcie_deinit_v1, 652 .deinit = qcom_pcie_deinit_v1,
653 .ltssm_enable = qcom_pcie_v0_v1_ltssm_enable,
654};
655
656static const struct qcom_pcie_ops ops_v2 = {
657 .get_resources = qcom_pcie_get_resources_v2,
658 .init = qcom_pcie_init_v2,
659 .post_init = qcom_pcie_post_init_v2,
660 .deinit = qcom_pcie_deinit_v2,
661 .ltssm_enable = qcom_pcie_v2_ltssm_enable,
496}; 662};
497 663
498static int qcom_pcie_probe(struct platform_device *pdev) 664static int qcom_pcie_probe(struct platform_device *pdev)
@@ -572,6 +738,7 @@ static const struct of_device_id qcom_pcie_match[] = {
572 { .compatible = "qcom,pcie-ipq8064", .data = &ops_v0 }, 738 { .compatible = "qcom,pcie-ipq8064", .data = &ops_v0 },
573 { .compatible = "qcom,pcie-apq8064", .data = &ops_v0 }, 739 { .compatible = "qcom,pcie-apq8064", .data = &ops_v0 },
574 { .compatible = "qcom,pcie-apq8084", .data = &ops_v1 }, 740 { .compatible = "qcom,pcie-apq8084", .data = &ops_v1 },
741 { .compatible = "qcom,pcie-msm8996", .data = &ops_v2 },
575 { } 742 { }
576}; 743};
577 744