Re: [PATCH v3 2/3] PCI: ultrarisc: get and enable DP1000 PCIe clocks
Jia Wang <[email protected]> Thu, 30 Jul 2026 16:26:29 +0800
| Newsgroups | org.kernel.vger.linux-pci,org.kernel.vger.linux-devicetree,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <178539998982.1582149.3956352602743263407.b4-reply@b4> |
On 2026-07-30 10:00 +0200, Manivannan Sadhasivam wrote: > On Thu, Jul 30, 2026 at 02:48:23PM +0800, Jia Wang wrote: > > On 2026-07-29 15:48 +0200, Manivannan Sadhasivam wrote: > > > On Tue, Jul 14, 2026 at 09:11:03AM +0800, Jia Wang via B4 Relay wrote: > > > > From: Jia Wang <[email protected]> > > > > > > > > Add the required core, dbi, and aux clocks for the DP1000 PCIe > > > > controller and enable them before initializing the DesignWare host. > > > > > > > > Also manage the clocks across system suspend and resume. > > > > > > > > Fixes: 5fc35740c3b3 ("PCI: ultrarisc: Add UltraRISC DP1000 PCIe Root Complex driver") > > > > Signed-off-by: Jia Wang <[email protected]> > > > > --- > > > > drivers/pci/controller/dwc/pcie-ultrarisc.c | 102 ++++++++++++++++++++++++++-- > > > > 1 file changed, 95 insertions(+), 7 deletions(-) > > > > > > > > diff --git a/drivers/pci/controller/dwc/pcie-ultrarisc.c b/drivers/pci/controller/dwc/pcie-ultrarisc.c > > > > index 6ee661ceff67..72ba5840b62d 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 <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[3]; > > > > + bool clks_enabled; > > > > +}; > > > > + > > > > static struct pci_ops ultrarisc_pci_ops = { > > > > .map_bus = dw_pcie_own_conf_map_bus, > > > > .read = pci_generic_config_read32, > > > > @@ -98,17 +105,66 @@ 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) > > > > +{ > > > > + int ret; > > > > + > > > > + if (ultra->clks_enabled) > > > > + return 0; > > > > + > > > > > > This check looks redundant and I don't see a need for the 'clks_enabled' flag. > > > Just do: > > > > > > return clk_bulk_prepare_enable(); > > > > > > > Thanks for the review. > > > > Agreed. I will remove clks_enabled and have ultrarisc_pcie_enable_clks() > > return clk_bulk_prepare_enable() directly in the next version. > > > > > > + ret = clk_bulk_prepare_enable(ARRAY_SIZE(ultra->clks), ultra->clks); > > > > + if (ret) > > > > + return ret; > > > > + > > > > + ultra->clks_enabled = true; > > > > + > > > > + return 0; > > > > +} > > > > + > > > > +static void ultrarisc_pcie_disable_clks(void *data) > > > > +{ > > > > + struct ultrarisc_pcie *ultra = data; > > > > + > > > > + if (!ultra->clks_enabled) > > > > + return; > > > > + > > > > + clk_bulk_disable_unprepare(ARRAY_SIZE(ultra->clks), ultra->clks); > > > > + ultra->clks_enabled = false; > > > > > > Same here. > > > > > > > Agreed. I will make ultrarisc_pcie_disable_clks() call > > clk_bulk_disable_unprepare() unconditionally in the next version. > > > > > > +} > > > > + > > > > +static int ultrarisc_pcie_init_clks(struct ultrarisc_pcie *ultra) > > > > +{ > > > > + struct device *dev = ultra->pci.dev; > > > > + int ret; > > > > + > > > > + ultra->clks[0].id = "core"; > > > > + ultra->clks[1].id = "dbi"; > > > > + ultra->clks[2].id = "aux"; > > > > + > > > > + ret = devm_clk_bulk_get(dev, ARRAY_SIZE(ultra->clks), ultra->clks); > > > > > > Use devm_clk_bulk_get_all() > > > > > > > I used `devm_clk_bulk_get()` to make the driver require the "core", "dbi", > > and "aux" clock names. Using `devm_clk_bulk_get_all()` would instead accept > > the clocks without requiring those names. Is that intended, or is there a > > requirement or convention I am missing? > > > > Your DT binding should ensure that the DTS supplies the required clocks. So the > driver shouldn't hardcode the clock name and just get whatever clocks DTS > passes. Otherwise, the driver will become a DTS validator. > Agreed. I will use devm_clk_bulk_get_all() and rely on the DT binding to validate the required clocks in v4. Thanks! > > > > + if (ret) > > > > + return dev_err_probe(dev, ret, "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 +173,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 +195,44 @@ 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; > > > > + > > > > + if (pci->suspended) { > > > > + ultrarisc_pcie_disable_clks(ultra); > > > > + return 0; > > > > + } > > > > > > Same as above. This looks redundant. Actually, it is wrong too as there cannot > > > be more than one suspend callback invocations. > > > > > > > Agreed that suspend_noirq() is invoked once per transition. However, a > > failed resume leaves pci->suspended set and the clocks disabled. The PM > > core records the resume error and continues the transition, so a later, > > independent system suspend can invoke this callback again. In the next > > version, I will keep the entry check as an early return for that case, > > without disabling the clocks again. > > > > OK! > > - Mani > > -- > மணிவண்ணன் சதாசிவம் > Best regards, Jia Wang