diff --git a/Documentation/devicetree/bindings/pci/ultrarisc,dp1000-pcie.yaml b/Documentation/devicetree/bindings/pci/ultrarisc,dp1000-pcie.yaml index 512b935bf5d1..d9d1488e915a 100644 --- a/Documentation/devicetree/bindings/pci/ultrarisc,dp1000-pcie.yaml +++ b/Documentation/devicetree/bindings/pci/ultrarisc,dp1000-pcie.yaml @@ -43,6 +43,18 @@ properties: - description: Legacy INTC interrupt - description: Legacy INTD interrupt + clocks: + items: + - description: PCIe core clock + - description: Data Bus Interface (DBI) clock + - description: Auxiliary clock + + clock-names: + items: + - const: core + - const: dbi + - const: aux + interrupt-names: items: - const: msi @@ -55,6 +67,8 @@ required: - compatible - reg - reg-names + - clocks + - clock-names - interrupts - interrupt-names @@ -71,6 +85,8 @@ examples: reg = <0x0 0x21000000 0x0 0x01000000>, <0x0 0x4fff0000 0x0 0x00010000>; reg-names = "dbi", "config"; + clocks = <&clkc 9>, <&clkc 7>, <&clkc 10>; + clock-names = "core", "dbi", "aux"; ranges = <0x81000000 0x0 0x4fbf0000 0x0 0x4fbf0000 0x0 0x00400000>, <0x82000000 0x0 0x40000000 0x0 0x40000000 0x0 0x0fbf0000>, <0xc3000000 0x40 0x00000000 0x40 0x00000000 0xd 0x00000000>; diff --git a/drivers/pci/controller/dwc/pcie-ultrarisc.c b/drivers/pci/controller/dwc/pcie-ultrarisc.c index 6ee661ceff67..51e89180490d 100644 --- a/drivers/pci/controller/dwc/pcie-ultrarisc.c +++ b/drivers/pci/controller/dwc/pcie-ultrarisc.c @@ -5,6 +5,7 @@ * Copyright (C) 2026 UltraRISC Technology (Shanghai) Co., Ltd. */ +#include #include #include #include @@ -23,6 +24,12 @@ #define ULTRARISC_PCIE_COMP_TIMEOUT_65_210MS 0x6 +struct ultrarisc_pcie { + struct dw_pcie pci; + struct clk_bulk_data *clks; + int num_clks; +}; + static struct pci_ops ultrarisc_pci_ops = { .map_bus = dw_pcie_own_conf_map_bus, .read = pci_generic_config_read32, @@ -98,17 +105,47 @@ static const struct dw_pcie_ops dw_pcie_ops = { .start_link = ultrarisc_pcie_start_link, }; +static int ultrarisc_pcie_enable_clks(struct ultrarisc_pcie *ultra) +{ + return clk_bulk_prepare_enable(ultra->num_clks, ultra->clks); +} + +static void ultrarisc_pcie_disable_clks(void *data) +{ + struct ultrarisc_pcie *ultra = data; + + clk_bulk_disable_unprepare(ultra->num_clks, ultra->clks); +} + +static int ultrarisc_pcie_init_clks(struct ultrarisc_pcie *ultra) +{ + struct device *dev = ultra->pci.dev; + int ret; + + ultra->num_clks = devm_clk_bulk_get_all(dev, &ultra->clks); + if (ultra->num_clks < 0) + return dev_err_probe(dev, ultra->num_clks, "Failed to get clocks\n"); + + ret = ultrarisc_pcie_enable_clks(ultra); + if (ret) + return dev_err_probe(dev, ret, "Failed to enable clocks\n"); + + return devm_add_action_or_reset(dev, ultrarisc_pcie_disable_clks, ultra); +} + static int ultrarisc_pcie_probe(struct platform_device *pdev) { + struct ultrarisc_pcie *ultra; struct device *dev = &pdev->dev; struct dw_pcie_rp *pp; struct dw_pcie *pci; int ret; - pci = devm_kzalloc(dev, sizeof(*pci), GFP_KERNEL); - if (!pci) + ultra = devm_kzalloc(dev, sizeof(*ultra), GFP_KERNEL); + if (!ultra) return -ENOMEM; + pci = &ultra->pci; pci->dev = dev; pci->ops = &dw_pcie_ops; @@ -117,7 +154,11 @@ static int ultrarisc_pcie_probe(struct platform_device *pdev) pp = &pci->pp; - platform_set_drvdata(pdev, pci); + platform_set_drvdata(pdev, ultra); + + ret = ultrarisc_pcie_init_clks(ultra); + if (ret) + return ret; pp->num_vectors = MAX_MSI_IRQS; /* No L2/L3 Ready indication is available on this platform */ @@ -135,16 +176,46 @@ static int ultrarisc_pcie_probe(struct platform_device *pdev) static int ultrarisc_pcie_suspend_noirq(struct device *dev) { - struct dw_pcie *pci = dev_get_drvdata(dev); + struct ultrarisc_pcie *ultra = dev_get_drvdata(dev); + struct dw_pcie *pci = &ultra->pci; + int ret; - return dw_pcie_suspend_noirq(pci); + /* + * A failed resume leaves the DWC suspended and the clocks disabled. + * A later suspend must not access the controller or disable them again. + */ + if (pci->suspended) + return 0; + + ret = dw_pcie_suspend_noirq(pci); + if (ret) + return ret; + + if (pci->suspended) + ultrarisc_pcie_disable_clks(ultra); + + return 0; } static int ultrarisc_pcie_resume_noirq(struct device *dev) { - struct dw_pcie *pci = dev_get_drvdata(dev); + struct ultrarisc_pcie *ultra = dev_get_drvdata(dev); + struct dw_pcie *pci = &ultra->pci; + int ret; - return dw_pcie_resume_noirq(pci); + if (pci->suspended) { + ret = ultrarisc_pcie_enable_clks(ultra); + if (ret) + return ret; + + ret = dw_pcie_resume_noirq(pci); + if (ret) { + ultrarisc_pcie_disable_clks(ultra); + return ret; + } + } + + return 0; } static const struct dev_pm_ops ultrarisc_pcie_pm_ops = { @@ -169,7 +240,7 @@ static struct platform_driver ultrarisc_pcie_driver = { }, .probe = ultrarisc_pcie_probe, }; -builtin_platform_driver(ultrarisc_pcie_driver); +module_platform_driver(ultrarisc_pcie_driver); MODULE_DESCRIPTION("UltraRISC DP1000 DWC PCIe host controller"); MODULE_LICENSE("GPL");