From: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
To: Christian Bruel <christian.bruel@foss.st.com>
Cc: lpieralisi@kernel.org, kw@linux.com, robh@kernel.org,
bhelgaas@google.com, krzk+dt@kernel.org, conor+dt@kernel.org,
mcoquelin.stm32@gmail.com, alexandre.torgue@foss.st.com,
p.zabel@pengutronix.de, cassel@kernel.org,
quic_schintav@quicinc.com, fabrice.gasnier@foss.st.com,
linux-pci@vger.kernel.org, devicetree@vger.kernel.org,
linux-stm32@st-md-mailman.stormreply.com,
linux-arm-kernel@lists.infradead.org,
linux-kernel@vger.kernel.org
Subject: Re: [PATCH v2 2/5] PCI: stm32: Add PCIe host support for STM32MP25
Date: Tue, 3 Dec 2024 20:22:44 +0530 [thread overview]
Message-ID: <20241203145244.trgrobtfmumtiwuc@thinkpad> (raw)
In-Reply-To: <20241126155119.1574564-3-christian.bruel@foss.st.com>
On Tue, Nov 26, 2024 at 04:51:16PM +0100, Christian Bruel wrote:
> Add driver for the STM32MP25 SoC PCIe Gen2 controller based on the
> DesignWare PCIe core.
>
> Supports MSI via GICv2m, Single Virtual Channel, Single Function
>
> Signed-off-by: Christian Bruel <christian.bruel@foss.st.com>
> ---
> drivers/pci/controller/dwc/Kconfig | 12 +
> drivers/pci/controller/dwc/Makefile | 1 +
> drivers/pci/controller/dwc/pcie-stm32.c | 402 ++++++++++++++++++++++++
> drivers/pci/controller/dwc/pcie-stm32.h | 15 +
> 4 files changed, 430 insertions(+)
> create mode 100644 drivers/pci/controller/dwc/pcie-stm32.c
> create mode 100644 drivers/pci/controller/dwc/pcie-stm32.h
>
> diff --git a/drivers/pci/controller/dwc/Kconfig b/drivers/pci/controller/dwc/Kconfig
> index b6d6778b0698..0c18879b604c 100644
> --- a/drivers/pci/controller/dwc/Kconfig
> +++ b/drivers/pci/controller/dwc/Kconfig
> @@ -389,6 +389,18 @@ config PCIE_SPEAR13XX
> help
> Say Y here if you want PCIe support on SPEAr13XX SoCs.
>
> +config PCIE_STM32
> + tristate "STMicroelectronics STM32MP25 PCIe Controller (host mode)"
> + depends on ARCH_STM32 || COMPILE_TEST
> + depends on PCI_MSI
> + select PCIE_DW_HOST
> + help
> + Enables support for the DesignWare core based PCIe host controller
> + found in STM32MP25 SoC.
> +
> + This driver can also be built as a module. If so, the module
> + will be called pcie-stm32.
> +
> config PCI_DRA7XX
> tristate
>
> diff --git a/drivers/pci/controller/dwc/Makefile b/drivers/pci/controller/dwc/Makefile
> index a8308d9ea986..576d99cb3bc5 100644
> --- a/drivers/pci/controller/dwc/Makefile
> +++ b/drivers/pci/controller/dwc/Makefile
> @@ -28,6 +28,7 @@ obj-$(CONFIG_PCIE_UNIPHIER) += pcie-uniphier.o
> obj-$(CONFIG_PCIE_UNIPHIER_EP) += pcie-uniphier-ep.o
> obj-$(CONFIG_PCIE_VISCONTI_HOST) += pcie-visconti.o
> obj-$(CONFIG_PCIE_RCAR_GEN4) += pcie-rcar-gen4.o
> +obj-$(CONFIG_PCIE_STM32) += pcie-stm32.o
>
> # The following drivers are for devices that use the generic ACPI
> # pci_root.c driver but don't support standard ECAM config access.
> diff --git a/drivers/pci/controller/dwc/pcie-stm32.c b/drivers/pci/controller/dwc/pcie-stm32.c
> new file mode 100644
> index 000000000000..fa787406c0e4
> --- /dev/null
> +++ b/drivers/pci/controller/dwc/pcie-stm32.c
> @@ -0,0 +1,402 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * STMicroelectronics STM32MP25 PCIe root complex driver.
> + *
> + * Copyright (C) 2024 STMicroelectronics
> + * Author: Christian Bruel <christian.bruel@foss.st.com>
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/mfd/syscon.h>
> +#include <linux/of_platform.h>
> +#include <linux/phy/phy.h>
> +#include <linux/pinctrl/devinfo.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/platform_device.h>
> +#include <linux/regmap.h>
> +#include <linux/reset.h>
> +#include "pcie-designware.h"
> +#include "pcie-stm32.h"
> +#include "../../pci.h"
> +
> +struct stm32_pcie {
> + struct dw_pcie *pci;
> + struct regmap *regmap;
> + struct reset_control *rst;
> + struct phy *phy;
> + struct clk *clk;
> + struct gpio_desc *perst_gpio;
> + struct gpio_desc *wake_gpio;
> + unsigned int wake_irq;
> + bool link_is_up;
> +};
> +
> +static int stm32_pcie_start_link(struct dw_pcie *pci)
> +{
> + struct stm32_pcie *stm32_pcie = to_stm32_pcie(pci);
> + u32 ret;
> +
> + if (stm32_pcie->perst_gpio) {
gpiod_set_value() will bail out if 'perst_gpio' is NULL. So no need to add a
check.
> + /* Make sure PERST# is asserted. */
Why?
> + gpiod_set_value(stm32_pcie->perst_gpio, 1);
> +
> + fsleep(PCIE_T_PERST_CLK_US);
> + gpiod_set_value(stm32_pcie->perst_gpio, 0);
Why can't you deassert PERST# in stm32_add_pcie_port()?
> + }
> +
> + ret = regmap_update_bits(stm32_pcie->regmap, SYSCFG_PCIECR,
> + STM32MP25_PCIECR_LTSSM_EN,
> + STM32MP25_PCIECR_LTSSM_EN);
> +
> + if (stm32_pcie->perst_gpio)
It doesn't hurt to call msleep() always.
> + msleep(PCIE_T_RRS_READY_MS);
> +
> + return ret;
> +}
> +
> +static void stm32_pcie_stop_link(struct dw_pcie *pci)
> +{
> + struct stm32_pcie *stm32_pcie = to_stm32_pcie(pci);
> +
> + regmap_update_bits(stm32_pcie->regmap, SYSCFG_PCIECR,
> + STM32MP25_PCIECR_LTSSM_EN, 0);
> +
> + /* Assert PERST# */
> + if (stm32_pcie->perst_gpio)
> + gpiod_set_value(stm32_pcie->perst_gpio, 1);
I don't like tying PERST# handling with start/stop link. PERST# should be
handled based on the power/clock state.
> +}
> +
> +static int stm32_pcie_suspend(struct device *dev)
> +{
> + struct stm32_pcie *stm32_pcie = dev_get_drvdata(dev);
> +
> + if (device_may_wakeup(dev) || device_wakeup_path(dev))
> + enable_irq_wake(stm32_pcie->wake_irq);
> +
> + return 0;
> +}
> +
> +static int stm32_pcie_resume(struct device *dev)
> +{
> + struct stm32_pcie *stm32_pcie = dev_get_drvdata(dev);
> +
> + if (device_may_wakeup(dev) || device_wakeup_path(dev))
> + disable_irq_wake(stm32_pcie->wake_irq);
> +
> + return 0;
> +}
> +
> +static int stm32_pcie_suspend_noirq(struct device *dev)
> +{
> + struct stm32_pcie *stm32_pcie = dev_get_drvdata(dev);
> +
> + stm32_pcie->link_is_up = dw_pcie_link_up(stm32_pcie->pci);
> +
> + stm32_pcie_stop_link(stm32_pcie->pci);
I don't understand how endpoint can wakeup the host if PERST# gets asserted.
> + clk_disable_unprepare(stm32_pcie->clk);
> +
> + if (!device_may_wakeup(dev) && !device_wakeup_path(dev))
> + phy_exit(stm32_pcie->phy);
> +
> + return pinctrl_pm_select_sleep_state(dev);
> +}
> +
> +static int stm32_pcie_resume_noirq(struct device *dev)
> +{
> + struct stm32_pcie *stm32_pcie = dev_get_drvdata(dev);
> + struct dw_pcie *pci = stm32_pcie->pci;
> + struct dw_pcie_rp *pp = &pci->pp;
> + int ret;
> +
> + /* init_state must be called first to force clk_req# gpio when no
CLKREQ#
Why RC should control CLKREQ#?
Also please use preferred style for multi-line comments:
/*
* ...
*/
> + * device is plugged.
> + */
> + if (!IS_ERR(dev->pins->init_state))
> + ret = pinctrl_select_state(dev->pins->p, dev->pins->init_state);
> + else
> + ret = pinctrl_pm_select_default_state(dev);
> +
> + if (ret) {
> + dev_err(dev, "Failed to activate pinctrl pm state: %d\n", ret);
> + return ret;
> + }
> +
> + if (!device_may_wakeup(dev) && !device_wakeup_path(dev)) {
> + ret = phy_init(stm32_pcie->phy);
> + if (ret) {
> + pinctrl_pm_select_default_state(dev);
> + return ret;
> + }
> + }
> +
> + ret = clk_prepare_enable(stm32_pcie->clk);
> + if (ret)
> + goto clk_err;
Please name the goto labels of their purpose. Like err_phy_exit.
> +
> + ret = dw_pcie_setup_rc(pp);
> + if (ret)
> + goto pcie_err;
This should be, 'err_disable_clk'.
> +
> + if (stm32_pcie->link_is_up) {
Why do you need this check? You cannot start the link in the absence of an
endpoint?
> + ret = stm32_pcie_start_link(stm32_pcie->pci);
> + if (ret)
> + goto pcie_err;
> +
> + /* Ignore errors, the link may come up later */
> + dw_pcie_wait_for_link(stm32_pcie->pci);
> + }
> +
> + pinctrl_pm_select_default_state(dev);
> +
> + return 0;
> +
> +pcie_err:
> + dw_pcie_host_deinit(pp);
> + clk_disable_unprepare(stm32_pcie->clk);
> +clk_err:
> + phy_exit(stm32_pcie->phy);
> + pinctrl_pm_select_default_state(dev);
> +
> + return ret;
> +}
> +
> +static const struct dev_pm_ops stm32_pcie_pm_ops = {
> + NOIRQ_SYSTEM_SLEEP_PM_OPS(stm32_pcie_suspend_noirq,
> + stm32_pcie_resume_noirq)
Can you make use of dw_pcie_{suspend/resume}_noirq() APIs?
> + SYSTEM_SLEEP_PM_OPS(stm32_pcie_suspend, stm32_pcie_resume)
> +};
> +
> +static const struct dw_pcie_host_ops stm32_pcie_host_ops = {
> +};
> +
> +static const struct dw_pcie_ops dw_pcie_ops = {
> + .start_link = stm32_pcie_start_link,
> + .stop_link = stm32_pcie_stop_link
> +};
> +
[...]
> + if (device_property_read_bool(dev, "wakeup-source")) {
> + stm32_pcie->wake_gpio = devm_gpiod_get_optional(dev, "wake",
> + GPIOD_IN);
> + if (IS_ERR(stm32_pcie->wake_gpio))
> + return dev_err_probe(dev, PTR_ERR(stm32_pcie->wake_gpio),
> + "Failed to get wake GPIO\n");
> + }
> +
> + if (stm32_pcie->wake_gpio) {
> + stm32_pcie->wake_irq = gpiod_to_irq(stm32_pcie->wake_gpio);
> +
> + ret = devm_request_threaded_irq(&pdev->dev,
> + stm32_pcie->wake_irq, NULL,
> + stm32_pcie_wake_irq_handler,
> + IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
> + "wake_irq", stm32_pcie);
> +
> + if (ret)
> + return dev_err_probe(dev, ret, "Failed to request WAKE IRQ: %d\n", ret);
> + }
Can we move WAKE# gpio handling to DWC core? There is nothing STM32 specific
here.
> +
> + ret = devm_pm_runtime_enable(dev);
> + if (ret < 0) {
> + dev_err(dev, "Failed to enable runtime PM %d\n", ret);
> + return ret;
> + }
> +
> + ret = pm_runtime_resume_and_get(dev);
> + if (ret < 0) {
> + dev_err(dev, "Failed to get runtime PM %d\n", ret);
> + return ret;
> + }
> +
> + ret = stm32_add_pcie_port(stm32_pcie, pdev);
> + if (ret) {
> + pm_runtime_put_sync(&pdev->dev);
> + return ret;
> + }
> +
> + if (stm32_pcie->wake_gpio)
> + device_set_wakeup_capable(dev, true);
> +
> + return 0;
> +}
> +
> +static void stm32_pcie_remove(struct platform_device *pdev)
> +{
> + struct stm32_pcie *stm32_pcie = platform_get_drvdata(pdev);
> + struct dw_pcie_rp *pp = &stm32_pcie->pci->pp;
> +
> + if (stm32_pcie->wake_gpio)
> + device_init_wakeup(&pdev->dev, false);
> +
> + dw_pcie_host_deinit(pp);
> + clk_disable_unprepare(stm32_pcie->clk);
> +
> + phy_exit(stm32_pcie->phy);
> +
> + pm_runtime_put_sync(&pdev->dev);
> +}
> +
> +static const struct of_device_id stm32_pcie_of_match[] = {
> + { .compatible = "st,stm32mp25-pcie-rc" },
> + {},
> +};
> +
> +static struct platform_driver stm32_pcie_driver = {
> + .probe = stm32_pcie_probe,
> + .remove = stm32_pcie_remove,
> + .driver = {
> + .name = "stm32-pcie",
> + .of_match_table = stm32_pcie_of_match,
> + .pm = &stm32_pcie_pm_ops,
Just use a single space instead of tab.
Could you also set PROBE_PREFER_ASYNCHRONOUS to allow async probing of
controller drivers?
> + },
> +};
> +
> +static bool is_stm32_pcie_driver(struct device *dev)
> +{
> + /* PCI bridge */
> + dev = get_device(dev);
> +
> + /* Platform driver */
> + dev = get_device(dev->parent);
> +
> + return (dev->driver == &stm32_pcie_driver.driver);
> +}
> +
> +/*
> + * DMA masters can only access the first 4GB of memory space,
> + * so we setup the bus DMA limit accordingly.
> + */
> +static int stm32_dma_limit(struct pci_dev *pdev, void *data)
> +{
> + dev_dbg(&pdev->dev, "disabling DMA DAC for device");
> +
> + pdev->dev.bus_dma_limit = DMA_BIT_MASK(32);
> +
> + return 0;
> +}
> +
> +static void quirk_stm32_dma_mask(struct pci_dev *pci)
> +{
> + struct pci_dev *root_port;
> +
> + root_port = pcie_find_root_port(pci);
> +
> + if (root_port && is_stm32_pcie_driver(root_port->dev.parent))
> + pci_walk_bus(pci->bus, stm32_dma_limit, NULL);
> +}
> +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SYNOPSYS, 0x0550, quirk_stm32_dma_mask);
This is not the correct way of using DMA masks as Bjorn noted.
- Mani
--
மணிவண்ணன் சதாசிவம்
next prev parent reply other threads:[~2024-12-03 14:54 UTC|newest]
Thread overview: 42+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-11-26 15:51 [PATCH v2 0/5] Add STM32MP25 PCIe drivers Christian Bruel
2024-11-26 15:51 ` [PATCH v2 1/5] dt-bindings: PCI: Add STM32MP25 PCIe root complex bindings Christian Bruel
2024-11-27 14:50 ` Rob Herring
2024-12-03 13:34 ` Manivannan Sadhasivam
2024-12-03 16:55 ` Christian Bruel
2024-12-03 22:25 ` Bjorn Helgaas
2024-12-05 13:41 ` Christian Bruel
2024-12-05 17:20 ` Bjorn Helgaas
2024-12-17 15:53 ` Christian Bruel
2024-12-17 17:25 ` Manivannan Sadhasivam
2024-12-18 8:42 ` Christian Bruel
2024-12-18 9:06 ` Manivannan Sadhasivam
2024-12-17 17:20 ` Manivannan Sadhasivam
2024-12-05 17:23 ` Bjorn Helgaas
2024-11-26 15:51 ` [PATCH v2 2/5] PCI: stm32: Add PCIe host support for STM32MP25 Christian Bruel
2024-11-29 20:58 ` Bjorn Helgaas
2024-11-29 21:18 ` Lucas Stach
2024-12-05 11:46 ` Christian Bruel
2024-12-03 14:52 ` Manivannan Sadhasivam [this message]
2024-12-16 9:00 ` Christian Bruel
2024-12-18 9:46 ` Manivannan Sadhasivam
2024-12-18 11:24 ` Christian Bruel
2024-12-18 11:46 ` Manivannan Sadhasivam
2024-12-09 4:34 ` kernel test robot
2024-11-26 15:51 ` [PATCH v2 3/5] dt-bindings: PCI: Add STM32MP25 PCIe endpoint bindings Christian Bruel
2024-11-27 14:51 ` Rob Herring
2024-11-27 14:59 ` Rob Herring (Arm)
2024-12-03 14:54 ` Manivannan Sadhasivam
2024-11-26 15:51 ` [PATCH v2 4/5] PCI: stm32: Add PCIe endpoint support for STM32MP25 Christian Bruel
2024-12-03 15:22 ` Manivannan Sadhasivam
2024-12-16 10:02 ` Christian Bruel
2024-12-16 16:17 ` Manivannan Sadhasivam
2024-12-17 9:48 ` Christian Bruel
2024-12-18 9:08 ` Manivannan Sadhasivam
2024-12-18 9:21 ` Christian Bruel
2025-01-10 15:33 ` Christian Bruel
2025-01-10 14:49 ` Christian Bruel
2024-12-05 17:27 ` Bjorn Helgaas
2024-12-16 14:00 ` Christian Bruel
2025-01-14 17:05 ` Bjorn Helgaas
2025-01-14 12:10 ` Christian Bruel
2024-11-26 15:51 ` [PATCH v2 5/5] MAINTAINERS: add entry for ST STM32MP25 PCIe drivers Christian Bruel
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20241203145244.trgrobtfmumtiwuc@thinkpad \
--to=manivannan.sadhasivam@linaro.org \
--cc=alexandre.torgue@foss.st.com \
--cc=bhelgaas@google.com \
--cc=cassel@kernel.org \
--cc=christian.bruel@foss.st.com \
--cc=conor+dt@kernel.org \
--cc=devicetree@vger.kernel.org \
--cc=fabrice.gasnier@foss.st.com \
--cc=krzk+dt@kernel.org \
--cc=kw@linux.com \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-pci@vger.kernel.org \
--cc=linux-stm32@st-md-mailman.stormreply.com \
--cc=lpieralisi@kernel.org \
--cc=mcoquelin.stm32@gmail.com \
--cc=p.zabel@pengutronix.de \
--cc=quic_schintav@quicinc.com \
--cc=robh@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.