diff options
author | Bjorn Helgaas <bhelgaas@google.com> | 2018-10-20 12:45:53 -0400 |
---|---|---|
committer | Bjorn Helgaas <bhelgaas@google.com> | 2018-10-20 12:45:53 -0400 |
commit | 4dd4d99636778ab610ad7ccb96a20b015991bdcf (patch) | |
tree | b8242b9f4806b2903946a20cc3d4fe406afc8782 | |
parent | fc23af0cb1efa4c5b0c7ecd226d827e4824a4dcf (diff) | |
parent | 031337ace2d1c22a447da6390716fe92592cdd6e (diff) |
Merge branch 'remotes/lorenzo/pci/mediatek'
- Fix Mediatek unchecked return value from devm_pci_remap_iospace()
(Gustavo A. R. Silva)
- Fix Mediatek endpoint/port matching logic (Honghui Zhang)
- Change Mediatek Root Port Class Code to PCI_CLASS_BRIDGE_PCI (Honghui
Zhang)
- Remove redundant Mediatek PM domain check (Honghui Zhang)
- Convert Mediatek to pci_host_probe() (Honghui Zhang)
- Fix Mediatek MSI enablement (Honghui Zhang)
- Add Mediatek system PM support for MT2712 and MT7622 (Honghui Zhang)
- Add Mediatek loadable module support (Honghui Zhang)
* remotes/lorenzo/pci/mediatek:
PCI: mediatek: Add loadable kernel module support
PCI: mediatek: Add system PM support for MT2712 and MT7622
PCI: mediatek: Fixup MSI enablement logic by enabling MSI before clocks
PCI: mediatek: Convert to use pci_host_probe()
PCI: mediatek: Remove the redundant dev->pm_domain check
PCI: mediatek: Fix class type for MT7622 to PCI_CLASS_BRIDGE_PCI
PCI: mediatek: Fix mtk_pcie_find_port() endpoint/port matching logic
PCI: mediatek: Fix unchecked return value
-rw-r--r-- | drivers/pci/controller/Kconfig | 2 | ||||
-rw-r--r-- | drivers/pci/controller/pcie-mediatek.c | 321 |
2 files changed, 206 insertions, 117 deletions
diff --git a/drivers/pci/controller/Kconfig b/drivers/pci/controller/Kconfig index 5d76ef51532d..6671946dbf66 100644 --- a/drivers/pci/controller/Kconfig +++ b/drivers/pci/controller/Kconfig | |||
@@ -233,7 +233,7 @@ config PCIE_ROCKCHIP_EP | |||
233 | available to support GEN2 with 4 slots. | 233 | available to support GEN2 with 4 slots. |
234 | 234 | ||
235 | config PCIE_MEDIATEK | 235 | config PCIE_MEDIATEK |
236 | bool "MediaTek PCIe controller" | 236 | tristate "MediaTek PCIe controller" |
237 | depends on ARCH_MEDIATEK || COMPILE_TEST | 237 | depends on ARCH_MEDIATEK || COMPILE_TEST |
238 | depends on OF | 238 | depends on OF |
239 | depends on PCI_MSI_IRQ_DOMAIN | 239 | depends on PCI_MSI_IRQ_DOMAIN |
diff --git a/drivers/pci/controller/pcie-mediatek.c b/drivers/pci/controller/pcie-mediatek.c index 861dda69f366..d069a76cbb95 100644 --- a/drivers/pci/controller/pcie-mediatek.c +++ b/drivers/pci/controller/pcie-mediatek.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/irqdomain.h> | 15 | #include <linux/irqdomain.h> |
16 | #include <linux/kernel.h> | 16 | #include <linux/kernel.h> |
17 | #include <linux/msi.h> | 17 | #include <linux/msi.h> |
18 | #include <linux/module.h> | ||
18 | #include <linux/of_address.h> | 19 | #include <linux/of_address.h> |
19 | #include <linux/of_pci.h> | 20 | #include <linux/of_pci.h> |
20 | #include <linux/of_platform.h> | 21 | #include <linux/of_platform.h> |
@@ -162,6 +163,7 @@ struct mtk_pcie_soc { | |||
162 | * @phy: pointer to PHY control block | 163 | * @phy: pointer to PHY control block |
163 | * @lane: lane count | 164 | * @lane: lane count |
164 | * @slot: port slot | 165 | * @slot: port slot |
166 | * @irq: GIC irq | ||
165 | * @irq_domain: legacy INTx IRQ domain | 167 | * @irq_domain: legacy INTx IRQ domain |
166 | * @inner_domain: inner IRQ domain | 168 | * @inner_domain: inner IRQ domain |
167 | * @msi_domain: MSI IRQ domain | 169 | * @msi_domain: MSI IRQ domain |
@@ -182,6 +184,7 @@ struct mtk_pcie_port { | |||
182 | struct phy *phy; | 184 | struct phy *phy; |
183 | u32 lane; | 185 | u32 lane; |
184 | u32 slot; | 186 | u32 slot; |
187 | int irq; | ||
185 | struct irq_domain *irq_domain; | 188 | struct irq_domain *irq_domain; |
186 | struct irq_domain *inner_domain; | 189 | struct irq_domain *inner_domain; |
187 | struct irq_domain *msi_domain; | 190 | struct irq_domain *msi_domain; |
@@ -225,10 +228,8 @@ static void mtk_pcie_subsys_powerdown(struct mtk_pcie *pcie) | |||
225 | 228 | ||
226 | clk_disable_unprepare(pcie->free_ck); | 229 | clk_disable_unprepare(pcie->free_ck); |
227 | 230 | ||
228 | if (dev->pm_domain) { | 231 | pm_runtime_put_sync(dev); |
229 | pm_runtime_put_sync(dev); | 232 | pm_runtime_disable(dev); |
230 | pm_runtime_disable(dev); | ||
231 | } | ||
232 | } | 233 | } |
233 | 234 | ||
234 | static void mtk_pcie_port_free(struct mtk_pcie_port *port) | 235 | static void mtk_pcie_port_free(struct mtk_pcie_port *port) |
@@ -337,6 +338,17 @@ static struct mtk_pcie_port *mtk_pcie_find_port(struct pci_bus *bus, | |||
337 | { | 338 | { |
338 | struct mtk_pcie *pcie = bus->sysdata; | 339 | struct mtk_pcie *pcie = bus->sysdata; |
339 | struct mtk_pcie_port *port; | 340 | struct mtk_pcie_port *port; |
341 | struct pci_dev *dev = NULL; | ||
342 | |||
343 | /* | ||
344 | * Walk the bus hierarchy to get the devfn value | ||
345 | * of the port in the root bus. | ||
346 | */ | ||
347 | while (bus && bus->number) { | ||
348 | dev = bus->self; | ||
349 | bus = dev->bus; | ||
350 | devfn = dev->devfn; | ||
351 | } | ||
340 | 352 | ||
341 | list_for_each_entry(port, &pcie->ports, list) | 353 | list_for_each_entry(port, &pcie->ports, list) |
342 | if (port->slot == PCI_SLOT(devfn)) | 354 | if (port->slot == PCI_SLOT(devfn)) |
@@ -383,75 +395,6 @@ static struct pci_ops mtk_pcie_ops_v2 = { | |||
383 | .write = mtk_pcie_config_write, | 395 | .write = mtk_pcie_config_write, |
384 | }; | 396 | }; |
385 | 397 | ||
386 | static int mtk_pcie_startup_port_v2(struct mtk_pcie_port *port) | ||
387 | { | ||
388 | struct mtk_pcie *pcie = port->pcie; | ||
389 | struct resource *mem = &pcie->mem; | ||
390 | const struct mtk_pcie_soc *soc = port->pcie->soc; | ||
391 | u32 val; | ||
392 | size_t size; | ||
393 | int err; | ||
394 | |||
395 | /* MT7622 platforms need to enable LTSSM and ASPM from PCIe subsys */ | ||
396 | if (pcie->base) { | ||
397 | val = readl(pcie->base + PCIE_SYS_CFG_V2); | ||
398 | val |= PCIE_CSR_LTSSM_EN(port->slot) | | ||
399 | PCIE_CSR_ASPM_L1_EN(port->slot); | ||
400 | writel(val, pcie->base + PCIE_SYS_CFG_V2); | ||
401 | } | ||
402 | |||
403 | /* Assert all reset signals */ | ||
404 | writel(0, port->base + PCIE_RST_CTRL); | ||
405 | |||
406 | /* | ||
407 | * Enable PCIe link down reset, if link status changed from link up to | ||
408 | * link down, this will reset MAC control registers and configuration | ||
409 | * space. | ||
410 | */ | ||
411 | writel(PCIE_LINKDOWN_RST_EN, port->base + PCIE_RST_CTRL); | ||
412 | |||
413 | /* De-assert PHY, PE, PIPE, MAC and configuration reset */ | ||
414 | val = readl(port->base + PCIE_RST_CTRL); | ||
415 | val |= PCIE_PHY_RSTB | PCIE_PERSTB | PCIE_PIPE_SRSTB | | ||
416 | PCIE_MAC_SRSTB | PCIE_CRSTB; | ||
417 | writel(val, port->base + PCIE_RST_CTRL); | ||
418 | |||
419 | /* Set up vendor ID and class code */ | ||
420 | if (soc->need_fix_class_id) { | ||
421 | val = PCI_VENDOR_ID_MEDIATEK; | ||
422 | writew(val, port->base + PCIE_CONF_VEND_ID); | ||
423 | |||
424 | val = PCI_CLASS_BRIDGE_HOST; | ||
425 | writew(val, port->base + PCIE_CONF_CLASS_ID); | ||
426 | } | ||
427 | |||
428 | /* 100ms timeout value should be enough for Gen1/2 training */ | ||
429 | err = readl_poll_timeout(port->base + PCIE_LINK_STATUS_V2, val, | ||
430 | !!(val & PCIE_PORT_LINKUP_V2), 20, | ||
431 | 100 * USEC_PER_MSEC); | ||
432 | if (err) | ||
433 | return -ETIMEDOUT; | ||
434 | |||
435 | /* Set INTx mask */ | ||
436 | val = readl(port->base + PCIE_INT_MASK); | ||
437 | val &= ~INTX_MASK; | ||
438 | writel(val, port->base + PCIE_INT_MASK); | ||
439 | |||
440 | /* Set AHB to PCIe translation windows */ | ||
441 | size = mem->end - mem->start; | ||
442 | val = lower_32_bits(mem->start) | AHB2PCIE_SIZE(fls(size)); | ||
443 | writel(val, port->base + PCIE_AHB_TRANS_BASE0_L); | ||
444 | |||
445 | val = upper_32_bits(mem->start); | ||
446 | writel(val, port->base + PCIE_AHB_TRANS_BASE0_H); | ||
447 | |||
448 | /* Set PCIe to AXI translation memory space.*/ | ||
449 | val = fls(0xffffffff) | WIN_ENABLE; | ||
450 | writel(val, port->base + PCIE_AXI_WINDOW0); | ||
451 | |||
452 | return 0; | ||
453 | } | ||
454 | |||
455 | static void mtk_compose_msi_msg(struct irq_data *data, struct msi_msg *msg) | 398 | static void mtk_compose_msi_msg(struct irq_data *data, struct msi_msg *msg) |
456 | { | 399 | { |
457 | struct mtk_pcie_port *port = irq_data_get_irq_chip_data(data); | 400 | struct mtk_pcie_port *port = irq_data_get_irq_chip_data(data); |
@@ -590,6 +533,27 @@ static void mtk_pcie_enable_msi(struct mtk_pcie_port *port) | |||
590 | writel(val, port->base + PCIE_INT_MASK); | 533 | writel(val, port->base + PCIE_INT_MASK); |
591 | } | 534 | } |
592 | 535 | ||
536 | static void mtk_pcie_irq_teardown(struct mtk_pcie *pcie) | ||
537 | { | ||
538 | struct mtk_pcie_port *port, *tmp; | ||
539 | |||
540 | list_for_each_entry_safe(port, tmp, &pcie->ports, list) { | ||
541 | irq_set_chained_handler_and_data(port->irq, NULL, NULL); | ||
542 | |||
543 | if (port->irq_domain) | ||
544 | irq_domain_remove(port->irq_domain); | ||
545 | |||
546 | if (IS_ENABLED(CONFIG_PCI_MSI)) { | ||
547 | if (port->msi_domain) | ||
548 | irq_domain_remove(port->msi_domain); | ||
549 | if (port->inner_domain) | ||
550 | irq_domain_remove(port->inner_domain); | ||
551 | } | ||
552 | |||
553 | irq_dispose_mapping(port->irq); | ||
554 | } | ||
555 | } | ||
556 | |||
593 | static int mtk_pcie_intx_map(struct irq_domain *domain, unsigned int irq, | 557 | static int mtk_pcie_intx_map(struct irq_domain *domain, unsigned int irq, |
594 | irq_hw_number_t hwirq) | 558 | irq_hw_number_t hwirq) |
595 | { | 559 | { |
@@ -628,8 +592,6 @@ static int mtk_pcie_init_irq_domain(struct mtk_pcie_port *port, | |||
628 | ret = mtk_pcie_allocate_msi_domains(port); | 592 | ret = mtk_pcie_allocate_msi_domains(port); |
629 | if (ret) | 593 | if (ret) |
630 | return ret; | 594 | return ret; |
631 | |||
632 | mtk_pcie_enable_msi(port); | ||
633 | } | 595 | } |
634 | 596 | ||
635 | return 0; | 597 | return 0; |
@@ -682,7 +644,7 @@ static int mtk_pcie_setup_irq(struct mtk_pcie_port *port, | |||
682 | struct mtk_pcie *pcie = port->pcie; | 644 | struct mtk_pcie *pcie = port->pcie; |
683 | struct device *dev = pcie->dev; | 645 | struct device *dev = pcie->dev; |
684 | struct platform_device *pdev = to_platform_device(dev); | 646 | struct platform_device *pdev = to_platform_device(dev); |
685 | int err, irq; | 647 | int err; |
686 | 648 | ||
687 | err = mtk_pcie_init_irq_domain(port, node); | 649 | err = mtk_pcie_init_irq_domain(port, node); |
688 | if (err) { | 650 | if (err) { |
@@ -690,8 +652,81 @@ static int mtk_pcie_setup_irq(struct mtk_pcie_port *port, | |||
690 | return err; | 652 | return err; |
691 | } | 653 | } |
692 | 654 | ||
693 | irq = platform_get_irq(pdev, port->slot); | 655 | port->irq = platform_get_irq(pdev, port->slot); |
694 | irq_set_chained_handler_and_data(irq, mtk_pcie_intr_handler, port); | 656 | irq_set_chained_handler_and_data(port->irq, |
657 | mtk_pcie_intr_handler, port); | ||
658 | |||
659 | return 0; | ||
660 | } | ||
661 | |||
662 | static int mtk_pcie_startup_port_v2(struct mtk_pcie_port *port) | ||
663 | { | ||
664 | struct mtk_pcie *pcie = port->pcie; | ||
665 | struct resource *mem = &pcie->mem; | ||
666 | const struct mtk_pcie_soc *soc = port->pcie->soc; | ||
667 | u32 val; | ||
668 | size_t size; | ||
669 | int err; | ||
670 | |||
671 | /* MT7622 platforms need to enable LTSSM and ASPM from PCIe subsys */ | ||
672 | if (pcie->base) { | ||
673 | val = readl(pcie->base + PCIE_SYS_CFG_V2); | ||
674 | val |= PCIE_CSR_LTSSM_EN(port->slot) | | ||
675 | PCIE_CSR_ASPM_L1_EN(port->slot); | ||
676 | writel(val, pcie->base + PCIE_SYS_CFG_V2); | ||
677 | } | ||
678 | |||
679 | /* Assert all reset signals */ | ||
680 | writel(0, port->base + PCIE_RST_CTRL); | ||
681 | |||
682 | /* | ||
683 | * Enable PCIe link down reset, if link status changed from link up to | ||
684 | * link down, this will reset MAC control registers and configuration | ||
685 | * space. | ||
686 | */ | ||
687 | writel(PCIE_LINKDOWN_RST_EN, port->base + PCIE_RST_CTRL); | ||
688 | |||
689 | /* De-assert PHY, PE, PIPE, MAC and configuration reset */ | ||
690 | val = readl(port->base + PCIE_RST_CTRL); | ||
691 | val |= PCIE_PHY_RSTB | PCIE_PERSTB | PCIE_PIPE_SRSTB | | ||
692 | PCIE_MAC_SRSTB | PCIE_CRSTB; | ||
693 | writel(val, port->base + PCIE_RST_CTRL); | ||
694 | |||
695 | /* Set up vendor ID and class code */ | ||
696 | if (soc->need_fix_class_id) { | ||
697 | val = PCI_VENDOR_ID_MEDIATEK; | ||
698 | writew(val, port->base + PCIE_CONF_VEND_ID); | ||
699 | |||
700 | val = PCI_CLASS_BRIDGE_PCI; | ||
701 | writew(val, port->base + PCIE_CONF_CLASS_ID); | ||
702 | } | ||
703 | |||
704 | /* 100ms timeout value should be enough for Gen1/2 training */ | ||
705 | err = readl_poll_timeout(port->base + PCIE_LINK_STATUS_V2, val, | ||
706 | !!(val & PCIE_PORT_LINKUP_V2), 20, | ||
707 | 100 * USEC_PER_MSEC); | ||
708 | if (err) | ||
709 | return -ETIMEDOUT; | ||
710 | |||
711 | /* Set INTx mask */ | ||
712 | val = readl(port->base + PCIE_INT_MASK); | ||
713 | val &= ~INTX_MASK; | ||
714 | writel(val, port->base + PCIE_INT_MASK); | ||
715 | |||
716 | if (IS_ENABLED(CONFIG_PCI_MSI)) | ||
717 | mtk_pcie_enable_msi(port); | ||
718 | |||
719 | /* Set AHB to PCIe translation windows */ | ||
720 | size = mem->end - mem->start; | ||
721 | val = lower_32_bits(mem->start) | AHB2PCIE_SIZE(fls(size)); | ||
722 | writel(val, port->base + PCIE_AHB_TRANS_BASE0_L); | ||
723 | |||
724 | val = upper_32_bits(mem->start); | ||
725 | writel(val, port->base + PCIE_AHB_TRANS_BASE0_H); | ||
726 | |||
727 | /* Set PCIe to AXI translation memory space.*/ | ||
728 | val = fls(0xffffffff) | WIN_ENABLE; | ||
729 | writel(val, port->base + PCIE_AXI_WINDOW0); | ||
695 | 730 | ||
696 | return 0; | 731 | return 0; |
697 | } | 732 | } |
@@ -987,10 +1022,8 @@ static int mtk_pcie_subsys_powerup(struct mtk_pcie *pcie) | |||
987 | pcie->free_ck = NULL; | 1022 | pcie->free_ck = NULL; |
988 | } | 1023 | } |
989 | 1024 | ||
990 | if (dev->pm_domain) { | 1025 | pm_runtime_enable(dev); |
991 | pm_runtime_enable(dev); | 1026 | pm_runtime_get_sync(dev); |
992 | pm_runtime_get_sync(dev); | ||
993 | } | ||
994 | 1027 | ||
995 | /* enable top level clock */ | 1028 | /* enable top level clock */ |
996 | err = clk_prepare_enable(pcie->free_ck); | 1029 | err = clk_prepare_enable(pcie->free_ck); |
@@ -1002,10 +1035,8 @@ static int mtk_pcie_subsys_powerup(struct mtk_pcie *pcie) | |||
1002 | return 0; | 1035 | return 0; |
1003 | 1036 | ||
1004 | err_free_ck: | 1037 | err_free_ck: |
1005 | if (dev->pm_domain) { | 1038 | pm_runtime_put_sync(dev); |
1006 | pm_runtime_put_sync(dev); | 1039 | pm_runtime_disable(dev); |
1007 | pm_runtime_disable(dev); | ||
1008 | } | ||
1009 | 1040 | ||
1010 | return err; | 1041 | return err; |
1011 | } | 1042 | } |
@@ -1109,36 +1140,10 @@ static int mtk_pcie_request_resources(struct mtk_pcie *pcie) | |||
1109 | if (err < 0) | 1140 | if (err < 0) |
1110 | return err; | 1141 | return err; |
1111 | 1142 | ||
1112 | devm_pci_remap_iospace(dev, &pcie->pio, pcie->io.start); | 1143 | err = devm_pci_remap_iospace(dev, &pcie->pio, pcie->io.start); |
1113 | 1144 | if (err) | |
1114 | return 0; | ||
1115 | } | ||
1116 | |||
1117 | static int mtk_pcie_register_host(struct pci_host_bridge *host) | ||
1118 | { | ||
1119 | struct mtk_pcie *pcie = pci_host_bridge_priv(host); | ||
1120 | struct pci_bus *child; | ||
1121 | int err; | ||
1122 | |||
1123 | host->busnr = pcie->busn.start; | ||
1124 | host->dev.parent = pcie->dev; | ||
1125 | host->ops = pcie->soc->ops; | ||
1126 | host->map_irq = of_irq_parse_and_map_pci; | ||
1127 | host->swizzle_irq = pci_common_swizzle; | ||
1128 | host->sysdata = pcie; | ||
1129 | |||
1130 | err = pci_scan_root_bus_bridge(host); | ||
1131 | if (err < 0) | ||
1132 | return err; | 1145 | return err; |
1133 | 1146 | ||
1134 | pci_bus_size_bridges(host->bus); | ||
1135 | pci_bus_assign_resources(host->bus); | ||
1136 | |||
1137 | list_for_each_entry(child, &host->bus->children, node) | ||
1138 | pcie_bus_configure_settings(child); | ||
1139 | |||
1140 | pci_bus_add_devices(host->bus); | ||
1141 | |||
1142 | return 0; | 1147 | return 0; |
1143 | } | 1148 | } |
1144 | 1149 | ||
@@ -1168,7 +1173,14 @@ static int mtk_pcie_probe(struct platform_device *pdev) | |||
1168 | if (err) | 1173 | if (err) |
1169 | goto put_resources; | 1174 | goto put_resources; |
1170 | 1175 | ||
1171 | err = mtk_pcie_register_host(host); | 1176 | host->busnr = pcie->busn.start; |
1177 | host->dev.parent = pcie->dev; | ||
1178 | host->ops = pcie->soc->ops; | ||
1179 | host->map_irq = of_irq_parse_and_map_pci; | ||
1180 | host->swizzle_irq = pci_common_swizzle; | ||
1181 | host->sysdata = pcie; | ||
1182 | |||
1183 | err = pci_host_probe(host); | ||
1172 | if (err) | 1184 | if (err) |
1173 | goto put_resources; | 1185 | goto put_resources; |
1174 | 1186 | ||
@@ -1181,6 +1193,80 @@ put_resources: | |||
1181 | return err; | 1193 | return err; |
1182 | } | 1194 | } |
1183 | 1195 | ||
1196 | |||
1197 | static void mtk_pcie_free_resources(struct mtk_pcie *pcie) | ||
1198 | { | ||
1199 | struct pci_host_bridge *host = pci_host_bridge_from_priv(pcie); | ||
1200 | struct list_head *windows = &host->windows; | ||
1201 | |||
1202 | pci_free_resource_list(windows); | ||
1203 | } | ||
1204 | |||
1205 | static int mtk_pcie_remove(struct platform_device *pdev) | ||
1206 | { | ||
1207 | struct mtk_pcie *pcie = platform_get_drvdata(pdev); | ||
1208 | struct pci_host_bridge *host = pci_host_bridge_from_priv(pcie); | ||
1209 | |||
1210 | pci_stop_root_bus(host->bus); | ||
1211 | pci_remove_root_bus(host->bus); | ||
1212 | mtk_pcie_free_resources(pcie); | ||
1213 | |||
1214 | mtk_pcie_irq_teardown(pcie); | ||
1215 | |||
1216 | mtk_pcie_put_resources(pcie); | ||
1217 | |||
1218 | return 0; | ||
1219 | } | ||
1220 | |||
1221 | static int __maybe_unused mtk_pcie_suspend_noirq(struct device *dev) | ||
1222 | { | ||
1223 | struct mtk_pcie *pcie = dev_get_drvdata(dev); | ||
1224 | struct mtk_pcie_port *port; | ||
1225 | |||
1226 | if (list_empty(&pcie->ports)) | ||
1227 | return 0; | ||
1228 | |||
1229 | list_for_each_entry(port, &pcie->ports, list) { | ||
1230 | clk_disable_unprepare(port->pipe_ck); | ||
1231 | clk_disable_unprepare(port->obff_ck); | ||
1232 | clk_disable_unprepare(port->axi_ck); | ||
1233 | clk_disable_unprepare(port->aux_ck); | ||
1234 | clk_disable_unprepare(port->ahb_ck); | ||
1235 | clk_disable_unprepare(port->sys_ck); | ||
1236 | phy_power_off(port->phy); | ||
1237 | phy_exit(port->phy); | ||
1238 | } | ||
1239 | |||
1240 | clk_disable_unprepare(pcie->free_ck); | ||
1241 | |||
1242 | return 0; | ||
1243 | } | ||
1244 | |||
1245 | static int __maybe_unused mtk_pcie_resume_noirq(struct device *dev) | ||
1246 | { | ||
1247 | struct mtk_pcie *pcie = dev_get_drvdata(dev); | ||
1248 | struct mtk_pcie_port *port, *tmp; | ||
1249 | |||
1250 | if (list_empty(&pcie->ports)) | ||
1251 | return 0; | ||
1252 | |||
1253 | clk_prepare_enable(pcie->free_ck); | ||
1254 | |||
1255 | list_for_each_entry_safe(port, tmp, &pcie->ports, list) | ||
1256 | mtk_pcie_enable_port(port); | ||
1257 | |||
1258 | /* In case of EP was removed while system suspend. */ | ||
1259 | if (list_empty(&pcie->ports)) | ||
1260 | clk_disable_unprepare(pcie->free_ck); | ||
1261 | |||
1262 | return 0; | ||
1263 | } | ||
1264 | |||
1265 | static const struct dev_pm_ops mtk_pcie_pm_ops = { | ||
1266 | SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(mtk_pcie_suspend_noirq, | ||
1267 | mtk_pcie_resume_noirq) | ||
1268 | }; | ||
1269 | |||
1184 | static const struct mtk_pcie_soc mtk_pcie_soc_v1 = { | 1270 | static const struct mtk_pcie_soc mtk_pcie_soc_v1 = { |
1185 | .ops = &mtk_pcie_ops, | 1271 | .ops = &mtk_pcie_ops, |
1186 | .startup = mtk_pcie_startup_port, | 1272 | .startup = mtk_pcie_startup_port, |
@@ -1209,10 +1295,13 @@ static const struct of_device_id mtk_pcie_ids[] = { | |||
1209 | 1295 | ||
1210 | static struct platform_driver mtk_pcie_driver = { | 1296 | static struct platform_driver mtk_pcie_driver = { |
1211 | .probe = mtk_pcie_probe, | 1297 | .probe = mtk_pcie_probe, |
1298 | .remove = mtk_pcie_remove, | ||
1212 | .driver = { | 1299 | .driver = { |
1213 | .name = "mtk-pcie", | 1300 | .name = "mtk-pcie", |
1214 | .of_match_table = mtk_pcie_ids, | 1301 | .of_match_table = mtk_pcie_ids, |
1215 | .suppress_bind_attrs = true, | 1302 | .suppress_bind_attrs = true, |
1303 | .pm = &mtk_pcie_pm_ops, | ||
1216 | }, | 1304 | }, |
1217 | }; | 1305 | }; |
1218 | builtin_platform_driver(mtk_pcie_driver); | 1306 | module_platform_driver(mtk_pcie_driver); |
1307 | MODULE_LICENSE("GPL v2"); | ||