Merge branch 'pci/controller/dwc-ultrarisc'

- Add 'core', 'dbi', and 'aux' clocks to DT binding and manage them in the
  driver (Jia Wang)

- Use module_platform_driver() since this may be built as a module, though
  not removable because IRQs can't be safely disposed (Jia Wang)

* pci/controller/dwc-ultrarisc:
  PCI: ultrarisc: Use module_platform_driver()
  PCI: ultrarisc: Get and enable DP1000 PCIe controller clocks
  dt-bindings: PCI: ultrarisc: Add required DP1000 PCIe clocks
This commit is contained in:
Bjorn Helgaas
2026-08-21 16:40:44 -05:00
2 changed files with 95 additions and 8 deletions

View File

@@ -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>;

View File

@@ -5,6 +5,7 @@
* Copyright (C) 2026 UltraRISC Technology (Shanghai) Co., Ltd.
*/
#include <linux/clk.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of_device.h>
@@ -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");