diff options
Diffstat (limited to 'drivers/pci/host/pci-imx6.c')
-rw-r--r-- | drivers/pci/host/pci-imx6.c | 147 |
1 files changed, 55 insertions, 92 deletions
diff --git a/drivers/pci/host/pci-imx6.c b/drivers/pci/host/pci-imx6.c index ee082509b0ba..a5645ae4aef0 100644 --- a/drivers/pci/host/pci-imx6.c +++ b/drivers/pci/host/pci-imx6.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include <linux/resource.h> | 25 | #include <linux/resource.h> |
26 | #include <linux/signal.h> | 26 | #include <linux/signal.h> |
27 | #include <linux/types.h> | 27 | #include <linux/types.h> |
28 | #include <linux/interrupt.h> | ||
28 | 29 | ||
29 | #include "pcie-designware.h" | 30 | #include "pcie-designware.h" |
30 | 31 | ||
@@ -32,13 +33,9 @@ | |||
32 | 33 | ||
33 | struct imx6_pcie { | 34 | struct imx6_pcie { |
34 | int reset_gpio; | 35 | int reset_gpio; |
35 | int power_on_gpio; | 36 | struct clk *pcie_bus; |
36 | int wake_up_gpio; | 37 | struct clk *pcie_phy; |
37 | int disable_gpio; | 38 | struct clk *pcie; |
38 | struct clk *lvds_gate; | ||
39 | struct clk *sata_ref_100m; | ||
40 | struct clk *pcie_ref_125m; | ||
41 | struct clk *pcie_axi; | ||
42 | struct pcie_port pp; | 39 | struct pcie_port pp; |
43 | struct regmap *iomuxc_gpr; | 40 | struct regmap *iomuxc_gpr; |
44 | void __iomem *mem_base; | 41 | void __iomem *mem_base; |
@@ -231,36 +228,27 @@ static int imx6_pcie_deassert_core_reset(struct pcie_port *pp) | |||
231 | struct imx6_pcie *imx6_pcie = to_imx6_pcie(pp); | 228 | struct imx6_pcie *imx6_pcie = to_imx6_pcie(pp); |
232 | int ret; | 229 | int ret; |
233 | 230 | ||
234 | if (gpio_is_valid(imx6_pcie->power_on_gpio)) | ||
235 | gpio_set_value(imx6_pcie->power_on_gpio, 1); | ||
236 | |||
237 | regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1, | 231 | regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1, |
238 | IMX6Q_GPR1_PCIE_TEST_PD, 0 << 18); | 232 | IMX6Q_GPR1_PCIE_TEST_PD, 0 << 18); |
239 | regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1, | 233 | regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1, |
240 | IMX6Q_GPR1_PCIE_REF_CLK_EN, 1 << 16); | 234 | IMX6Q_GPR1_PCIE_REF_CLK_EN, 1 << 16); |
241 | 235 | ||
242 | ret = clk_prepare_enable(imx6_pcie->sata_ref_100m); | 236 | ret = clk_prepare_enable(imx6_pcie->pcie_phy); |
243 | if (ret) { | ||
244 | dev_err(pp->dev, "unable to enable sata_ref_100m\n"); | ||
245 | goto err_sata_ref; | ||
246 | } | ||
247 | |||
248 | ret = clk_prepare_enable(imx6_pcie->pcie_ref_125m); | ||
249 | if (ret) { | 237 | if (ret) { |
250 | dev_err(pp->dev, "unable to enable pcie_ref_125m\n"); | 238 | dev_err(pp->dev, "unable to enable pcie_phy clock\n"); |
251 | goto err_pcie_ref; | 239 | goto err_pcie_phy; |
252 | } | 240 | } |
253 | 241 | ||
254 | ret = clk_prepare_enable(imx6_pcie->lvds_gate); | 242 | ret = clk_prepare_enable(imx6_pcie->pcie_bus); |
255 | if (ret) { | 243 | if (ret) { |
256 | dev_err(pp->dev, "unable to enable lvds_gate\n"); | 244 | dev_err(pp->dev, "unable to enable pcie_bus clock\n"); |
257 | goto err_lvds_gate; | 245 | goto err_pcie_bus; |
258 | } | 246 | } |
259 | 247 | ||
260 | ret = clk_prepare_enable(imx6_pcie->pcie_axi); | 248 | ret = clk_prepare_enable(imx6_pcie->pcie); |
261 | if (ret) { | 249 | if (ret) { |
262 | dev_err(pp->dev, "unable to enable pcie_axi\n"); | 250 | dev_err(pp->dev, "unable to enable pcie clock\n"); |
263 | goto err_pcie_axi; | 251 | goto err_pcie; |
264 | } | 252 | } |
265 | 253 | ||
266 | /* allow the clocks to stabilize */ | 254 | /* allow the clocks to stabilize */ |
@@ -274,13 +262,11 @@ static int imx6_pcie_deassert_core_reset(struct pcie_port *pp) | |||
274 | } | 262 | } |
275 | return 0; | 263 | return 0; |
276 | 264 | ||
277 | err_pcie_axi: | 265 | err_pcie: |
278 | clk_disable_unprepare(imx6_pcie->lvds_gate); | 266 | clk_disable_unprepare(imx6_pcie->pcie_bus); |
279 | err_lvds_gate: | 267 | err_pcie_bus: |
280 | clk_disable_unprepare(imx6_pcie->pcie_ref_125m); | 268 | clk_disable_unprepare(imx6_pcie->pcie_phy); |
281 | err_pcie_ref: | 269 | err_pcie_phy: |
282 | clk_disable_unprepare(imx6_pcie->sata_ref_100m); | ||
283 | err_sata_ref: | ||
284 | return ret; | 270 | return ret; |
285 | 271 | ||
286 | } | 272 | } |
@@ -329,6 +315,13 @@ static int imx6_pcie_wait_for_link(struct pcie_port *pp) | |||
329 | return 0; | 315 | return 0; |
330 | } | 316 | } |
331 | 317 | ||
318 | static irqreturn_t imx6_pcie_msi_handler(int irq, void *arg) | ||
319 | { | ||
320 | struct pcie_port *pp = arg; | ||
321 | |||
322 | return dw_handle_msi_irq(pp); | ||
323 | } | ||
324 | |||
332 | static int imx6_pcie_start_link(struct pcie_port *pp) | 325 | static int imx6_pcie_start_link(struct pcie_port *pp) |
333 | { | 326 | { |
334 | struct imx6_pcie *imx6_pcie = to_imx6_pcie(pp); | 327 | struct imx6_pcie *imx6_pcie = to_imx6_pcie(pp); |
@@ -403,6 +396,9 @@ static void imx6_pcie_host_init(struct pcie_port *pp) | |||
403 | dw_pcie_setup_rc(pp); | 396 | dw_pcie_setup_rc(pp); |
404 | 397 | ||
405 | imx6_pcie_start_link(pp); | 398 | imx6_pcie_start_link(pp); |
399 | |||
400 | if (IS_ENABLED(CONFIG_PCI_MSI)) | ||
401 | dw_pcie_msi_init(pp); | ||
406 | } | 402 | } |
407 | 403 | ||
408 | static void imx6_pcie_reset_phy(struct pcie_port *pp) | 404 | static void imx6_pcie_reset_phy(struct pcie_port *pp) |
@@ -487,15 +483,25 @@ static struct pcie_host_ops imx6_pcie_host_ops = { | |||
487 | .host_init = imx6_pcie_host_init, | 483 | .host_init = imx6_pcie_host_init, |
488 | }; | 484 | }; |
489 | 485 | ||
490 | static int imx6_add_pcie_port(struct pcie_port *pp, | 486 | static int __init imx6_add_pcie_port(struct pcie_port *pp, |
491 | struct platform_device *pdev) | 487 | struct platform_device *pdev) |
492 | { | 488 | { |
493 | int ret; | 489 | int ret; |
494 | 490 | ||
495 | pp->irq = platform_get_irq(pdev, 0); | 491 | if (IS_ENABLED(CONFIG_PCI_MSI)) { |
496 | if (!pp->irq) { | 492 | pp->msi_irq = platform_get_irq_byname(pdev, "msi"); |
497 | dev_err(&pdev->dev, "failed to get irq\n"); | 493 | if (pp->msi_irq <= 0) { |
498 | return -ENODEV; | 494 | dev_err(&pdev->dev, "failed to get MSI irq\n"); |
495 | return -ENODEV; | ||
496 | } | ||
497 | |||
498 | ret = devm_request_irq(&pdev->dev, pp->msi_irq, | ||
499 | imx6_pcie_msi_handler, | ||
500 | IRQF_SHARED, "mx6-pcie-msi", pp); | ||
501 | if (ret) { | ||
502 | dev_err(&pdev->dev, "failed to request MSI irq\n"); | ||
503 | return -ENODEV; | ||
504 | } | ||
499 | } | 505 | } |
500 | 506 | ||
501 | pp->root_bus_nr = -1; | 507 | pp->root_bus_nr = -1; |
@@ -546,69 +552,26 @@ static int __init imx6_pcie_probe(struct platform_device *pdev) | |||
546 | } | 552 | } |
547 | } | 553 | } |
548 | 554 | ||
549 | imx6_pcie->power_on_gpio = of_get_named_gpio(np, "power-on-gpio", 0); | ||
550 | if (gpio_is_valid(imx6_pcie->power_on_gpio)) { | ||
551 | ret = devm_gpio_request_one(&pdev->dev, | ||
552 | imx6_pcie->power_on_gpio, | ||
553 | GPIOF_OUT_INIT_LOW, | ||
554 | "PCIe power enable"); | ||
555 | if (ret) { | ||
556 | dev_err(&pdev->dev, "unable to get power-on gpio\n"); | ||
557 | return ret; | ||
558 | } | ||
559 | } | ||
560 | |||
561 | imx6_pcie->wake_up_gpio = of_get_named_gpio(np, "wake-up-gpio", 0); | ||
562 | if (gpio_is_valid(imx6_pcie->wake_up_gpio)) { | ||
563 | ret = devm_gpio_request_one(&pdev->dev, | ||
564 | imx6_pcie->wake_up_gpio, | ||
565 | GPIOF_IN, | ||
566 | "PCIe wake up"); | ||
567 | if (ret) { | ||
568 | dev_err(&pdev->dev, "unable to get wake-up gpio\n"); | ||
569 | return ret; | ||
570 | } | ||
571 | } | ||
572 | |||
573 | imx6_pcie->disable_gpio = of_get_named_gpio(np, "disable-gpio", 0); | ||
574 | if (gpio_is_valid(imx6_pcie->disable_gpio)) { | ||
575 | ret = devm_gpio_request_one(&pdev->dev, | ||
576 | imx6_pcie->disable_gpio, | ||
577 | GPIOF_OUT_INIT_HIGH, | ||
578 | "PCIe disable endpoint"); | ||
579 | if (ret) { | ||
580 | dev_err(&pdev->dev, "unable to get disable-ep gpio\n"); | ||
581 | return ret; | ||
582 | } | ||
583 | } | ||
584 | |||
585 | /* Fetch clocks */ | 555 | /* Fetch clocks */ |
586 | imx6_pcie->lvds_gate = devm_clk_get(&pdev->dev, "lvds_gate"); | 556 | imx6_pcie->pcie_phy = devm_clk_get(&pdev->dev, "pcie_phy"); |
587 | if (IS_ERR(imx6_pcie->lvds_gate)) { | 557 | if (IS_ERR(imx6_pcie->pcie_phy)) { |
588 | dev_err(&pdev->dev, | ||
589 | "lvds_gate clock select missing or invalid\n"); | ||
590 | return PTR_ERR(imx6_pcie->lvds_gate); | ||
591 | } | ||
592 | |||
593 | imx6_pcie->sata_ref_100m = devm_clk_get(&pdev->dev, "sata_ref_100m"); | ||
594 | if (IS_ERR(imx6_pcie->sata_ref_100m)) { | ||
595 | dev_err(&pdev->dev, | 558 | dev_err(&pdev->dev, |
596 | "sata_ref_100m clock source missing or invalid\n"); | 559 | "pcie_phy clock source missing or invalid\n"); |
597 | return PTR_ERR(imx6_pcie->sata_ref_100m); | 560 | return PTR_ERR(imx6_pcie->pcie_phy); |
598 | } | 561 | } |
599 | 562 | ||
600 | imx6_pcie->pcie_ref_125m = devm_clk_get(&pdev->dev, "pcie_ref_125m"); | 563 | imx6_pcie->pcie_bus = devm_clk_get(&pdev->dev, "pcie_bus"); |
601 | if (IS_ERR(imx6_pcie->pcie_ref_125m)) { | 564 | if (IS_ERR(imx6_pcie->pcie_bus)) { |
602 | dev_err(&pdev->dev, | 565 | dev_err(&pdev->dev, |
603 | "pcie_ref_125m clock source missing or invalid\n"); | 566 | "pcie_bus clock source missing or invalid\n"); |
604 | return PTR_ERR(imx6_pcie->pcie_ref_125m); | 567 | return PTR_ERR(imx6_pcie->pcie_bus); |
605 | } | 568 | } |
606 | 569 | ||
607 | imx6_pcie->pcie_axi = devm_clk_get(&pdev->dev, "pcie_axi"); | 570 | imx6_pcie->pcie = devm_clk_get(&pdev->dev, "pcie"); |
608 | if (IS_ERR(imx6_pcie->pcie_axi)) { | 571 | if (IS_ERR(imx6_pcie->pcie)) { |
609 | dev_err(&pdev->dev, | 572 | dev_err(&pdev->dev, |
610 | "pcie_axi clock source missing or invalid\n"); | 573 | "pcie clock source missing or invalid\n"); |
611 | return PTR_ERR(imx6_pcie->pcie_axi); | 574 | return PTR_ERR(imx6_pcie->pcie); |
612 | } | 575 | } |
613 | 576 | ||
614 | /* Grab GPR config register range */ | 577 | /* Grab GPR config register range */ |