From f81f095e87715e198471f4653952fe5e3f824874 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Thu, 6 Jan 2022 07:36:45 -0300 Subject: PCI: imx6: Allow to probe when dw_pcie_wait_for_link() fails The intention of commit 886a9c134755 ("PCI: dwc: Move link handling into common code") was to standardize the behavior of link down as explained in its commit log: "The behavior for a link down was inconsistent as some drivers would fail probe in that case while others succeed. Let's standardize this to succeed as there are usecases where devices (and the link) appear later even without hotplug. For example, a reconfigured FPGA device." The pci-imx6 still fails to probe when the link is not present, which causes the following warning: imx6q-pcie 8ffc000.pcie: Phy link never came up imx6q-pcie: probe of 8ffc000.pcie failed with error -110 ------------[ cut here ]------------ WARNING: CPU: 0 PID: 30 at drivers/regulator/core.c:2257 _regulator_put.part.0+0x1b8/0x1dc Modules linked in: CPU: 0 PID: 30 Comm: kworker/u2:2 Not tainted 5.15.0-next-20211103 #1 Hardware name: Freescale i.MX6 SoloX (Device Tree) Workqueue: events_unbound async_run_entry_fn [] (unwind_backtrace) from [] (show_stack+0x10/0x14) [] (show_stack) from [] (dump_stack_lvl+0x58/0x70) [] (dump_stack_lvl) from [] (__warn+0xd4/0x154) [] (__warn) from [] (warn_slowpath_fmt+0x74/0xa8) [] (warn_slowpath_fmt) from [] (_regulator_put.part.0+0x1b8/0x1dc) [] (_regulator_put.part.0) from [] (regulator_put+0x2c/0x3c) [] (regulator_put) from [] (release_nodes+0x50/0x178) Fix this problem by ignoring the dw_pcie_wait_for_link() error like it is done on the other dwc drivers. Tested on imx6sx-sdb and imx6q-sabresd boards. Link: https://lore.kernel.org/r/20220106103645.2790803-1-festevam@gmail.com Fixes: 886a9c134755 ("PCI: dwc: Move link handling into common code") Signed-off-by: Fabio Estevam Signed-off-by: Lorenzo Pieralisi Reviewed-by: Rob Herring Reviewed-by: Richard Zhu Cc: --- drivers/pci/controller/dwc/pci-imx6.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'drivers/pci/controller/dwc') diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index 6974bd5aa116..7b200b66114a 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -809,9 +809,7 @@ static int imx6_pcie_start_link(struct dw_pcie *pci) /* Start LTSSM. */ imx6_pcie_ltssm_enable(dev); - ret = dw_pcie_wait_for_link(pci); - if (ret) - goto err_reset_phy; + dw_pcie_wait_for_link(pci); if (pci->link_gen == 2) { /* Allow Gen2 mode after the link is up. */ @@ -847,11 +845,7 @@ static int imx6_pcie_start_link(struct dw_pcie *pci) } /* Make sure link training is finished as well! */ - ret = dw_pcie_wait_for_link(pci); - if (ret) { - dev_err(dev, "Failed to bring link up!\n"); - goto err_reset_phy; - } + dw_pcie_wait_for_link(pci); } else { dev_info(dev, "Link: Gen2 disabled\n"); } -- cgit From d41584ae86169445b143bea081c43ca1587b6e46 Mon Sep 17 00:00:00 2001 From: Kunihiko Hayashi Date: Thu, 10 Feb 2022 17:09:55 +0900 Subject: PCI: uniphier-ep: Add SoC data structure Define SoC data structure that includes pci_epc_features, SoC-dependent callback functions and flags to distinguish the behavior of each SoC. The callback functions define init() to initialize the controller and wait() to wait until initialization is completed. Rename uniphier_pcie_init_ep() to uniphier_pcie_pro5_init_ep() for initializing PCIe controller implemented in Pro5 SoC. And Pro5 SoC doesn't have wait() function. Link: https://lore.kernel.org/r/1644480596-20037-3-git-send-email-hayashi.kunihiko@socionext.com Signed-off-by: Kunihiko Hayashi Signed-off-by: Lorenzo Pieralisi Reviewed-by: Rob Herring --- drivers/pci/controller/dwc/pcie-uniphier-ep.c | 61 ++++++++++++++++++--------- 1 file changed, 42 insertions(+), 19 deletions(-) (limited to 'drivers/pci/controller/dwc') diff --git a/drivers/pci/controller/dwc/pcie-uniphier-ep.c b/drivers/pci/controller/dwc/pcie-uniphier-ep.c index 69810c6b0d58..6c035fc45aaa 100644 --- a/drivers/pci/controller/dwc/pcie-uniphier-ep.c +++ b/drivers/pci/controller/dwc/pcie-uniphier-ep.c @@ -60,7 +60,14 @@ struct uniphier_pcie_ep_priv { struct clk *clk, *clk_gio; struct reset_control *rst, *rst_gio; struct phy *phy; - const struct pci_epc_features *features; + const struct uniphier_pcie_ep_soc_data *data; +}; + +struct uniphier_pcie_ep_soc_data { + bool has_gio; + void (*init)(struct uniphier_pcie_ep_priv *priv); + int (*wait)(struct uniphier_pcie_ep_priv *priv); + const struct pci_epc_features features; }; #define to_uniphier_pcie(x) dev_get_drvdata((x)->dev) @@ -91,7 +98,7 @@ static void uniphier_pcie_phy_reset(struct uniphier_pcie_ep_priv *priv, writel(val, priv->base + PCL_RSTCTRL2); } -static void uniphier_pcie_init_ep(struct uniphier_pcie_ep_priv *priv) +static void uniphier_pcie_pro5_init_ep(struct uniphier_pcie_ep_priv *priv) { u32 val; @@ -209,7 +216,7 @@ uniphier_pcie_get_features(struct dw_pcie_ep *ep) struct dw_pcie *pci = to_dw_pcie_from_ep(ep); struct uniphier_pcie_ep_priv *priv = to_uniphier_pcie(pci); - return priv->features; + return &priv->data->features; } static const struct dw_pcie_ep_ops uniphier_pcie_ep_ops = { @@ -238,7 +245,8 @@ static int uniphier_pcie_ep_enable(struct uniphier_pcie_ep_priv *priv) if (ret) goto out_rst_assert; - uniphier_pcie_init_ep(priv); + if (priv->data->init) + priv->data->init(priv); uniphier_pcie_phy_reset(priv, true); @@ -248,8 +256,16 @@ static int uniphier_pcie_ep_enable(struct uniphier_pcie_ep_priv *priv) uniphier_pcie_phy_reset(priv, false); + if (priv->data->wait) { + ret = priv->data->wait(priv); + if (ret) + goto out_phy_exit; + } + return 0; +out_phy_exit: + phy_exit(priv->phy); out_rst_gio_assert: reset_control_assert(priv->rst_gio); out_rst_assert: @@ -277,8 +293,8 @@ static int uniphier_pcie_ep_probe(struct platform_device *pdev) if (!priv) return -ENOMEM; - priv->features = of_device_get_match_data(dev); - if (WARN_ON(!priv->features)) + priv->data = of_device_get_match_data(dev); + if (WARN_ON(!priv->data)) return -EINVAL; priv->pci.dev = dev; @@ -288,13 +304,15 @@ static int uniphier_pcie_ep_probe(struct platform_device *pdev) if (IS_ERR(priv->base)) return PTR_ERR(priv->base); - priv->clk_gio = devm_clk_get(dev, "gio"); - if (IS_ERR(priv->clk_gio)) - return PTR_ERR(priv->clk_gio); + if (priv->data->has_gio) { + priv->clk_gio = devm_clk_get(dev, "gio"); + if (IS_ERR(priv->clk_gio)) + return PTR_ERR(priv->clk_gio); - priv->rst_gio = devm_reset_control_get_shared(dev, "gio"); - if (IS_ERR(priv->rst_gio)) - return PTR_ERR(priv->rst_gio); + priv->rst_gio = devm_reset_control_get_shared(dev, "gio"); + if (IS_ERR(priv->rst_gio)) + return PTR_ERR(priv->rst_gio); + } priv->clk = devm_clk_get(dev, "link"); if (IS_ERR(priv->clk)) @@ -321,13 +339,18 @@ static int uniphier_pcie_ep_probe(struct platform_device *pdev) return dw_pcie_ep_init(&priv->pci.ep); } -static const struct pci_epc_features uniphier_pro5_data = { - .linkup_notifier = false, - .msi_capable = true, - .msix_capable = false, - .align = 1 << 16, - .bar_fixed_64bit = BIT(BAR_0) | BIT(BAR_2) | BIT(BAR_4), - .reserved_bar = BIT(BAR_4), +static const struct uniphier_pcie_ep_soc_data uniphier_pro5_data = { + .has_gio = true, + .init = uniphier_pcie_pro5_init_ep, + .wait = NULL, + .features = { + .linkup_notifier = false, + .msi_capable = true, + .msix_capable = false, + .align = 1 << 16, + .bar_fixed_64bit = BIT(BAR_0) | BIT(BAR_2) | BIT(BAR_4), + .reserved_bar = BIT(BAR_4), + }, }; static const struct of_device_id uniphier_pcie_ep_match[] = { -- cgit From 892fdf15b824f89ab7ece562ee123890d6a1b3bc Mon Sep 17 00:00:00 2001 From: Kunihiko Hayashi Date: Thu, 10 Feb 2022 17:09:56 +0900 Subject: PCI: uniphier-ep: Add NX1 support Add basic support for UniPhier NX1 SoC as non-legacy SoC. This includes a compatible string, SoC-dependent data containing init() and wait() functions for the controller. Link: https://lore.kernel.org/r/1644480596-20037-4-git-send-email-hayashi.kunihiko@socionext.com Signed-off-by: Kunihiko Hayashi Signed-off-by: Lorenzo Pieralisi Reviewed-by: Rob Herring --- drivers/pci/controller/dwc/pcie-uniphier-ep.c | 81 +++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) (limited to 'drivers/pci/controller/dwc') diff --git a/drivers/pci/controller/dwc/pcie-uniphier-ep.c b/drivers/pci/controller/dwc/pcie-uniphier-ep.c index 6c035fc45aaa..4d0a587c0ba5 100644 --- a/drivers/pci/controller/dwc/pcie-uniphier-ep.c +++ b/drivers/pci/controller/dwc/pcie-uniphier-ep.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -31,6 +32,17 @@ #define PCL_RSTCTRL2 0x0024 #define PCL_RSTCTRL_PHY_RESET BIT(0) +#define PCL_PINCTRL0 0x002c +#define PCL_PERST_PLDN_REGEN BIT(12) +#define PCL_PERST_NOE_REGEN BIT(11) +#define PCL_PERST_OUT_REGEN BIT(8) +#define PCL_PERST_PLDN_REGVAL BIT(4) +#define PCL_PERST_NOE_REGVAL BIT(3) +#define PCL_PERST_OUT_REGVAL BIT(0) + +#define PCL_PIPEMON 0x0044 +#define PCL_PCLK_ALIVE BIT(15) + #define PCL_MODE 0x8000 #define PCL_MODE_REGEN BIT(8) #define PCL_MODE_REGVAL BIT(0) @@ -51,6 +63,9 @@ #define PCL_APP_INTX 0x8074 #define PCL_APP_INTX_SYS_INT BIT(0) +#define PCL_APP_PM0 0x8078 +#define PCL_SYS_AUX_PWR_DET BIT(8) + /* assertion time of INTx in usec */ #define PCL_INTX_WIDTH_USEC 30 @@ -123,6 +138,55 @@ static void uniphier_pcie_pro5_init_ep(struct uniphier_pcie_ep_priv *priv) msleep(100); } +static void uniphier_pcie_nx1_init_ep(struct uniphier_pcie_ep_priv *priv) +{ + u32 val; + + /* set EP mode */ + val = readl(priv->base + PCL_MODE); + val |= PCL_MODE_REGEN | PCL_MODE_REGVAL; + writel(val, priv->base + PCL_MODE); + + /* use auxiliary power detection */ + val = readl(priv->base + PCL_APP_PM0); + val |= PCL_SYS_AUX_PWR_DET; + writel(val, priv->base + PCL_APP_PM0); + + /* assert PERST# */ + val = readl(priv->base + PCL_PINCTRL0); + val &= ~(PCL_PERST_NOE_REGVAL | PCL_PERST_OUT_REGVAL + | PCL_PERST_PLDN_REGVAL); + val |= PCL_PERST_NOE_REGEN | PCL_PERST_OUT_REGEN + | PCL_PERST_PLDN_REGEN; + writel(val, priv->base + PCL_PINCTRL0); + + uniphier_pcie_ltssm_enable(priv, false); + + usleep_range(100000, 200000); + + /* deassert PERST# */ + val = readl(priv->base + PCL_PINCTRL0); + val |= PCL_PERST_OUT_REGVAL | PCL_PERST_OUT_REGEN; + writel(val, priv->base + PCL_PINCTRL0); +} + +static int uniphier_pcie_nx1_wait_ep(struct uniphier_pcie_ep_priv *priv) +{ + u32 status; + int ret; + + /* wait PIPE clock */ + ret = readl_poll_timeout(priv->base + PCL_PIPEMON, status, + status & PCL_PCLK_ALIVE, 100000, 1000000); + if (ret) { + dev_err(priv->pci.dev, + "Failed to initialize controller in EP mode\n"); + return ret; + } + + return 0; +} + static int uniphier_pcie_start_link(struct dw_pcie *pci) { struct uniphier_pcie_ep_priv *priv = to_uniphier_pcie(pci); @@ -353,11 +417,28 @@ static const struct uniphier_pcie_ep_soc_data uniphier_pro5_data = { }, }; +static const struct uniphier_pcie_ep_soc_data uniphier_nx1_data = { + .has_gio = false, + .init = uniphier_pcie_nx1_init_ep, + .wait = uniphier_pcie_nx1_wait_ep, + .features = { + .linkup_notifier = false, + .msi_capable = true, + .msix_capable = false, + .align = 1 << 12, + .bar_fixed_64bit = BIT(BAR_0) | BIT(BAR_2) | BIT(BAR_4), + }, +}; + static const struct of_device_id uniphier_pcie_ep_match[] = { { .compatible = "socionext,uniphier-pro5-pcie-ep", .data = &uniphier_pro5_data, }, + { + .compatible = "socionext,uniphier-nx1-pcie-ep", + .data = &uniphier_nx1_data, + }, { /* sentinel */ }, }; -- cgit From 904b10fb189cc15376e9bfce1ef0282e68b0b004 Mon Sep 17 00:00:00 2001 From: Pali Rohár Date: Mon, 14 Feb 2022 12:41:08 +0100 Subject: PCI: Add defines for normal and subtractive PCI bridges MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add these PCI class codes to pci_ids.h: PCI_CLASS_BRIDGE_PCI_NORMAL PCI_CLASS_BRIDGE_PCI_SUBTRACTIVE Use these defines in all kernel code for describing PCI class codes for normal and subtractive PCI bridges. [bhelgaas: similar change in pci-mvebu.c] Link: https://lore.kernel.org/r/20220214114109.26809-1-pali@kernel.org Signed-off-by: Pali Rohár Signed-off-by: Bjorn Helgaas --- arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h | 2 -- arch/mips/pci/fixup-sb1250.c | 2 +- arch/mips/pci/pci-bcm63xx.c | 2 +- arch/powerpc/platforms/powernv/pci.c | 2 +- arch/powerpc/sysdev/fsl_pci.c | 2 +- arch/sh/drivers/pci/pcie-sh7786.c | 2 +- drivers/pci/controller/dwc/pci-keystone.c | 8 ++++---- drivers/pci/controller/dwc/pci-meson.c | 16 ++++++++-------- drivers/pci/controller/dwc/pcie-qcom.c | 2 +- drivers/pci/controller/mobiveil/pcie-mobiveil-host.c | 2 +- drivers/pci/controller/pci-aardvark.c | 2 +- drivers/pci/controller/pci-loongson.c | 2 +- drivers/pci/controller/pci-mvebu.c | 2 +- drivers/pci/controller/pci-tegra.c | 2 +- drivers/pci/controller/pcie-iproc-bcma.c | 2 +- drivers/pci/controller/pcie-iproc.c | 2 +- drivers/pci/controller/pcie-mediatek-gen3.c | 2 +- drivers/pci/controller/pcie-rcar-host.c | 2 +- drivers/pci/controller/pcie-rockchip-host.c | 2 +- drivers/pci/controller/pcie-rockchip.h | 1 - drivers/pci/hotplug/shpchp_core.c | 2 +- drivers/pci/pci-bridge-emul.c | 8 +++++--- drivers/pci/pcie/portdrv_pci.c | 4 ++-- include/linux/pci_ids.h | 2 ++ 24 files changed, 38 insertions(+), 37 deletions(-) (limited to 'drivers/pci/controller/dwc') diff --git a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h index 9ceb5e72889f..d3f397dcab6e 100644 --- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h +++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h @@ -1380,8 +1380,6 @@ #define PCIE_IDVAL3_REG 0x43c #define IDVAL3_CLASS_CODE_MASK 0xffffff -#define IDVAL3_SUBCLASS_SHIFT 8 -#define IDVAL3_CLASS_SHIFT 16 #define PCIE_DLSTATUS_REG 0x1048 #define DLSTATUS_PHYLINKUP (1 << 13) diff --git a/arch/mips/pci/fixup-sb1250.c b/arch/mips/pci/fixup-sb1250.c index 40efc990cdce..3f914c33b7de 100644 --- a/arch/mips/pci/fixup-sb1250.c +++ b/arch/mips/pci/fixup-sb1250.c @@ -75,7 +75,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SIBYTE, PCI_DEVICE_ID_BCM1250_PCI, */ static void quirk_sb1250_ht(struct pci_dev *dev) { - dev->class = PCI_CLASS_BRIDGE_PCI << 8; + dev->class = PCI_CLASS_BRIDGE_PCI_NORMAL; } DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SIBYTE, PCI_DEVICE_ID_BCM1250_HT, quirk_sb1250_ht); diff --git a/arch/mips/pci/pci-bcm63xx.c b/arch/mips/pci/pci-bcm63xx.c index 5548365605c0..ac83243772d2 100644 --- a/arch/mips/pci/pci-bcm63xx.c +++ b/arch/mips/pci/pci-bcm63xx.c @@ -186,7 +186,7 @@ static int __init bcm63xx_register_pcie(void) /* setup class code as bridge */ val = bcm_pcie_readl(PCIE_IDVAL3_REG); val &= ~IDVAL3_CLASS_CODE_MASK; - val |= (PCI_CLASS_BRIDGE_PCI << IDVAL3_SUBCLASS_SHIFT); + val |= PCI_CLASS_BRIDGE_PCI_NORMAL; bcm_pcie_writel(val, PCIE_IDVAL3_REG); /* disable bar1 size */ diff --git a/arch/powerpc/platforms/powernv/pci.c b/arch/powerpc/platforms/powernv/pci.c index 9a8391b983d1..f7054879ecd4 100644 --- a/arch/powerpc/platforms/powernv/pci.c +++ b/arch/powerpc/platforms/powernv/pci.c @@ -815,7 +815,7 @@ void pnv_pci_shutdown(void) /* Fixup wrong class code in p7ioc and p8 root complex */ static void pnv_p7ioc_rc_quirk(struct pci_dev *dev) { - dev->class = PCI_CLASS_BRIDGE_PCI << 8; + dev->class = PCI_CLASS_BRIDGE_PCI_NORMAL; } DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_IBM, 0x3b9, pnv_p7ioc_rc_quirk); diff --git a/arch/powerpc/sysdev/fsl_pci.c b/arch/powerpc/sysdev/fsl_pci.c index 674f047b7820..a97ce602394e 100644 --- a/arch/powerpc/sysdev/fsl_pci.c +++ b/arch/powerpc/sysdev/fsl_pci.c @@ -55,7 +55,7 @@ static void quirk_fsl_pcie_early(struct pci_dev *dev) if ((hdr_type & 0x7f) != PCI_HEADER_TYPE_BRIDGE) return; - dev->class = PCI_CLASS_BRIDGE_PCI << 8; + dev->class = PCI_CLASS_BRIDGE_PCI_NORMAL; fsl_pcie_bus_fixup = 1; return; } diff --git a/arch/sh/drivers/pci/pcie-sh7786.c b/arch/sh/drivers/pci/pcie-sh7786.c index 4d499476c33a..b0c2a5238d04 100644 --- a/arch/sh/drivers/pci/pcie-sh7786.c +++ b/arch/sh/drivers/pci/pcie-sh7786.c @@ -314,7 +314,7 @@ static int __init pcie_init(struct sh7786_pcie_port *port) * class to match. Hardware takes care of propagating the IDSETR * settings, so there is no need to bother with a quirk. */ - pci_write_reg(chan, PCI_CLASS_BRIDGE_PCI << 16, SH4A_PCIEIDSETR1); + pci_write_reg(chan, PCI_CLASS_BRIDGE_PCI_NORMAL << 8, SH4A_PCIEIDSETR1); /* Initialize default capabilities. */ data = pci_read_reg(chan, SH4A_PCIEEXPCAP0); diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index 1c2ee4e13f1c..d10e5fd0f83c 100644 --- a/drivers/pci/controller/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c @@ -531,13 +531,13 @@ static void ks_pcie_quirk(struct pci_dev *dev) struct pci_dev *bridge; static const struct pci_device_id rc_pci_devids[] = { { PCI_DEVICE(PCI_VENDOR_ID_TI, PCIE_RC_K2HK), - .class = PCI_CLASS_BRIDGE_PCI << 8, .class_mask = ~0, }, + .class = PCI_CLASS_BRIDGE_PCI_NORMAL, .class_mask = ~0, }, { PCI_DEVICE(PCI_VENDOR_ID_TI, PCIE_RC_K2E), - .class = PCI_CLASS_BRIDGE_PCI << 8, .class_mask = ~0, }, + .class = PCI_CLASS_BRIDGE_PCI_NORMAL, .class_mask = ~0, }, { PCI_DEVICE(PCI_VENDOR_ID_TI, PCIE_RC_K2L), - .class = PCI_CLASS_BRIDGE_PCI << 8, .class_mask = ~0, }, + .class = PCI_CLASS_BRIDGE_PCI_NORMAL, .class_mask = ~0, }, { PCI_DEVICE(PCI_VENDOR_ID_TI, PCIE_RC_K2G), - .class = PCI_CLASS_BRIDGE_PCI << 8, .class_mask = ~0, }, + .class = PCI_CLASS_BRIDGE_PCI_NORMAL, .class_mask = ~0, }, { 0, }, }; diff --git a/drivers/pci/controller/dwc/pci-meson.c b/drivers/pci/controller/dwc/pci-meson.c index 686ded034f22..f44bf347904a 100644 --- a/drivers/pci/controller/dwc/pci-meson.c +++ b/drivers/pci/controller/dwc/pci-meson.c @@ -313,14 +313,14 @@ static int meson_pcie_rd_own_conf(struct pci_bus *bus, u32 devfn, * cannot program the PCI_CLASS_DEVICE register, so we must fabricate * the return value in the config accessors. */ - if (where == PCI_CLASS_REVISION && size == 4) - *val = (PCI_CLASS_BRIDGE_PCI << 16) | (*val & 0xffff); - else if (where == PCI_CLASS_DEVICE && size == 2) - *val = PCI_CLASS_BRIDGE_PCI; - else if (where == PCI_CLASS_DEVICE && size == 1) - *val = PCI_CLASS_BRIDGE_PCI & 0xff; - else if (where == PCI_CLASS_DEVICE + 1 && size == 1) - *val = (PCI_CLASS_BRIDGE_PCI >> 8) & 0xff; + if ((where & ~3) == PCI_CLASS_REVISION) { + if (size <= 2) + *val = (*val & ((1 << (size * 8)) - 1)) << (8 * (where & 3)); + *val &= ~0xffffff00; + *val |= PCI_CLASS_BRIDGE_PCI_NORMAL << 8; + if (size <= 2) + *val = (*val >> (8 * (where & 3))) & ((1 << (size * 8)) - 1); + } return PCIBIOS_SUCCESSFUL; } diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c index c19cd506ed3f..a47f1c0434c2 100644 --- a/drivers/pci/controller/dwc/pcie-qcom.c +++ b/drivers/pci/controller/dwc/pcie-qcom.c @@ -1634,7 +1634,7 @@ static const struct of_device_id qcom_pcie_match[] = { static void qcom_fixup_class(struct pci_dev *dev) { - dev->class = PCI_CLASS_BRIDGE_PCI << 8; + dev->class = PCI_CLASS_BRIDGE_PCI_NORMAL; } DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_QCOM, 0x0101, qcom_fixup_class); DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_QCOM, 0x0104, qcom_fixup_class); diff --git a/drivers/pci/controller/mobiveil/pcie-mobiveil-host.c b/drivers/pci/controller/mobiveil/pcie-mobiveil-host.c index f3547aa60140..31a7bdebe540 100644 --- a/drivers/pci/controller/mobiveil/pcie-mobiveil-host.c +++ b/drivers/pci/controller/mobiveil/pcie-mobiveil-host.c @@ -295,7 +295,7 @@ int mobiveil_host_init(struct mobiveil_pcie *pcie, bool reinit) /* fixup for PCIe class register */ value = mobiveil_csr_readl(pcie, PAB_INTP_AXI_PIO_CLASS); value &= 0xff; - value |= (PCI_CLASS_BRIDGE_PCI << 16); + value |= PCI_CLASS_BRIDGE_PCI_NORMAL << 8; mobiveil_csr_writel(pcie, value, PAB_INTP_AXI_PIO_CLASS); return 0; diff --git a/drivers/pci/controller/pci-aardvark.c b/drivers/pci/controller/pci-aardvark.c index 4f5b44827d21..2561326e9181 100644 --- a/drivers/pci/controller/pci-aardvark.c +++ b/drivers/pci/controller/pci-aardvark.c @@ -529,7 +529,7 @@ static void advk_pcie_setup_hw(struct advk_pcie *pcie) */ reg = advk_readl(pcie, PCIE_CORE_DEV_REV_REG); reg &= ~0xffffff00; - reg |= (PCI_CLASS_BRIDGE_PCI << 8) << 8; + reg |= PCI_CLASS_BRIDGE_PCI_NORMAL << 8; advk_writel(pcie, reg, PCIE_CORE_DEV_REV_REG); /* Disable Root Bridge I/O space, memory space and bus mastering */ diff --git a/drivers/pci/controller/pci-loongson.c b/drivers/pci/controller/pci-loongson.c index 48169b1e3817..50a8e1d6f70a 100644 --- a/drivers/pci/controller/pci-loongson.c +++ b/drivers/pci/controller/pci-loongson.c @@ -35,7 +35,7 @@ struct loongson_pci { /* Fixup wrong class code in PCIe bridges */ static void bridge_class_quirk(struct pci_dev *dev) { - dev->class = PCI_CLASS_BRIDGE_PCI << 8; + dev->class = PCI_CLASS_BRIDGE_PCI_NORMAL; } DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON, DEV_PCIE_PORT_0, bridge_class_quirk); diff --git a/drivers/pci/controller/pci-mvebu.c b/drivers/pci/controller/pci-mvebu.c index 71258ea3d35f..b0ec1c640df7 100644 --- a/drivers/pci/controller/pci-mvebu.c +++ b/drivers/pci/controller/pci-mvebu.c @@ -268,7 +268,7 @@ static void mvebu_pcie_setup_hw(struct mvebu_pcie_port *port) */ dev_rev = mvebu_readl(port, PCIE_DEV_REV_OFF); dev_rev &= ~0xffffff00; - dev_rev |= (PCI_CLASS_BRIDGE_PCI << 8) << 8; + dev_rev |= PCI_CLASS_BRIDGE_PCI_NORMAL << 8; mvebu_writel(port, dev_rev, PCIE_DEV_REV_OFF); /* Point PCIe unit MBUS decode windows to DRAM space. */ diff --git a/drivers/pci/controller/pci-tegra.c b/drivers/pci/controller/pci-tegra.c index cb0aa65d6934..0457ec02ab70 100644 --- a/drivers/pci/controller/pci-tegra.c +++ b/drivers/pci/controller/pci-tegra.c @@ -726,7 +726,7 @@ static void tegra_pcie_port_free(struct tegra_pcie_port *port) /* Tegra PCIE root complex wrongly reports device class */ static void tegra_pcie_fixup_class(struct pci_dev *dev) { - dev->class = PCI_CLASS_BRIDGE_PCI << 8; + dev->class = PCI_CLASS_BRIDGE_PCI_NORMAL; } DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_NVIDIA, 0x0bf0, tegra_pcie_fixup_class); DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_NVIDIA, 0x0bf1, tegra_pcie_fixup_class); diff --git a/drivers/pci/controller/pcie-iproc-bcma.c b/drivers/pci/controller/pcie-iproc-bcma.c index 54b6e6d5bc64..99a99900444d 100644 --- a/drivers/pci/controller/pcie-iproc-bcma.c +++ b/drivers/pci/controller/pcie-iproc-bcma.c @@ -18,7 +18,7 @@ /* NS: CLASS field is R/O, and set to wrong 0x200 value */ static void bcma_pcie2_fixup_class(struct pci_dev *dev) { - dev->class = PCI_CLASS_BRIDGE_PCI << 8; + dev->class = PCI_CLASS_BRIDGE_PCI_NORMAL; } DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_BROADCOM, 0x8011, bcma_pcie2_fixup_class); DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_BROADCOM, 0x8012, bcma_pcie2_fixup_class); diff --git a/drivers/pci/controller/pcie-iproc.c b/drivers/pci/controller/pcie-iproc.c index b3e75bc61ff1..3df4ab209253 100644 --- a/drivers/pci/controller/pcie-iproc.c +++ b/drivers/pci/controller/pcie-iproc.c @@ -1581,7 +1581,7 @@ static void quirk_paxc_bridge(struct pci_dev *pdev) * code that the bridge is not an Ethernet device. */ if (pdev->hdr_type == PCI_HEADER_TYPE_BRIDGE) - pdev->class = PCI_CLASS_BRIDGE_PCI << 8; + pdev->class = PCI_CLASS_BRIDGE_PCI_NORMAL; /* * MPSS is not being set properly (as it is currently 0). This is diff --git a/drivers/pci/controller/pcie-mediatek-gen3.c b/drivers/pci/controller/pcie-mediatek-gen3.c index 7705d61fba4c..3e8d70bfabc6 100644 --- a/drivers/pci/controller/pcie-mediatek-gen3.c +++ b/drivers/pci/controller/pcie-mediatek-gen3.c @@ -292,7 +292,7 @@ static int mtk_pcie_startup_port(struct mtk_gen3_pcie *pcie) /* Set class code */ val = readl_relaxed(pcie->base + PCIE_PCI_IDS_1); val &= ~GENMASK(31, 8); - val |= PCI_CLASS(PCI_CLASS_BRIDGE_PCI << 8); + val |= PCI_CLASS(PCI_CLASS_BRIDGE_PCI_NORMAL); writel_relaxed(val, pcie->base + PCIE_PCI_IDS_1); /* Mask all INTx interrupts */ diff --git a/drivers/pci/controller/pcie-rcar-host.c b/drivers/pci/controller/pcie-rcar-host.c index 38b6e02edfa9..dfca59c4ae34 100644 --- a/drivers/pci/controller/pcie-rcar-host.c +++ b/drivers/pci/controller/pcie-rcar-host.c @@ -370,7 +370,7 @@ static int rcar_pcie_hw_init(struct rcar_pcie *pcie) * class to match. Hardware takes care of propagating the IDSETR * settings, so there is no need to bother with a quirk. */ - rcar_pci_write_reg(pcie, PCI_CLASS_BRIDGE_PCI << 16, IDSETR1); + rcar_pci_write_reg(pcie, PCI_CLASS_BRIDGE_PCI_NORMAL << 8, IDSETR1); /* * Setup Secondary Bus Number & Subordinate Bus Number, even though diff --git a/drivers/pci/controller/pcie-rockchip-host.c b/drivers/pci/controller/pcie-rockchip-host.c index 45a28880f322..7f56f99b4116 100644 --- a/drivers/pci/controller/pcie-rockchip-host.c +++ b/drivers/pci/controller/pcie-rockchip-host.c @@ -370,7 +370,7 @@ static int rockchip_pcie_host_init_port(struct rockchip_pcie *rockchip) rockchip_pcie_write(rockchip, ROCKCHIP_VENDOR_ID, PCIE_CORE_CONFIG_VENDOR); rockchip_pcie_write(rockchip, - PCI_CLASS_BRIDGE_PCI << PCIE_RC_CONFIG_SCC_SHIFT, + PCI_CLASS_BRIDGE_PCI_NORMAL << 8, PCIE_RC_CONFIG_RID_CCR); /* Clear THP cap's next cap pointer to remove L1 substate cap */ diff --git a/drivers/pci/controller/pcie-rockchip.h b/drivers/pci/controller/pcie-rockchip.h index 1650a5087450..32c3a859c26b 100644 --- a/drivers/pci/controller/pcie-rockchip.h +++ b/drivers/pci/controller/pcie-rockchip.h @@ -134,7 +134,6 @@ #define PCIE_RC_CONFIG_NORMAL_BASE 0x800000 #define PCIE_RC_CONFIG_BASE 0xa00000 #define PCIE_RC_CONFIG_RID_CCR (PCIE_RC_CONFIG_BASE + 0x08) -#define PCIE_RC_CONFIG_SCC_SHIFT 16 #define PCIE_RC_CONFIG_DCR (PCIE_RC_CONFIG_BASE + 0xc4) #define PCIE_RC_CONFIG_DCR_CSPL_SHIFT 18 #define PCIE_RC_CONFIG_DCR_CSPL_LIMIT 0xff diff --git a/drivers/pci/hotplug/shpchp_core.c b/drivers/pci/hotplug/shpchp_core.c index 81a918d47895..53692b048301 100644 --- a/drivers/pci/hotplug/shpchp_core.c +++ b/drivers/pci/hotplug/shpchp_core.c @@ -312,7 +312,7 @@ static void shpc_remove(struct pci_dev *dev) } static const struct pci_device_id shpcd_pci_tbl[] = { - {PCI_DEVICE_CLASS(((PCI_CLASS_BRIDGE_PCI << 8) | 0x00), ~0)}, + {PCI_DEVICE_CLASS(PCI_CLASS_BRIDGE_PCI_NORMAL, ~0)}, { /* end: all zeroes */ } }; MODULE_DEVICE_TABLE(pci, shpcd_pci_tbl); diff --git a/drivers/pci/pci-bridge-emul.c b/drivers/pci/pci-bridge-emul.c index c994ebec2360..ec6ab03ae476 100644 --- a/drivers/pci/pci-bridge-emul.c +++ b/drivers/pci/pci-bridge-emul.c @@ -328,10 +328,12 @@ int pci_bridge_emul_init(struct pci_bridge_emul *bridge, BUILD_BUG_ON(sizeof(bridge->conf) != PCI_BRIDGE_CONF_END); /* - * class_revision: Class is high 24 bits and revision is low 8 bit of this member, - * while class for PCI Bridge Normal Decode has the 24-bit value: PCI_CLASS_BRIDGE_PCI << 8 + * class_revision: Class is high 24 bits and revision is low 8 bit + * of this member, while class for PCI Bridge Normal Decode has the + * 24-bit value: PCI_CLASS_BRIDGE_PCI_NORMAL */ - bridge->conf.class_revision |= cpu_to_le32((PCI_CLASS_BRIDGE_PCI << 8) << 8); + bridge->conf.class_revision |= + cpu_to_le32(PCI_CLASS_BRIDGE_PCI_NORMAL << 8); bridge->conf.header_type = PCI_HEADER_TYPE_BRIDGE; bridge->conf.cache_line_size = 0x10; bridge->conf.status = cpu_to_le16(PCI_STATUS_CAP_LIST); diff --git a/drivers/pci/pcie/portdrv_pci.c b/drivers/pci/pcie/portdrv_pci.c index 35eca6277a96..4b8801656ffb 100644 --- a/drivers/pci/pcie/portdrv_pci.c +++ b/drivers/pci/pcie/portdrv_pci.c @@ -178,9 +178,9 @@ static pci_ers_result_t pcie_portdrv_mmio_enabled(struct pci_dev *dev) */ static const struct pci_device_id port_pci_ids[] = { /* handle any PCI-Express port */ - { PCI_DEVICE_CLASS(((PCI_CLASS_BRIDGE_PCI << 8) | 0x00), ~0) }, + { PCI_DEVICE_CLASS(PCI_CLASS_BRIDGE_PCI_NORMAL, ~0) }, /* subtractive decode PCI-to-PCI bridge, class type is 060401h */ - { PCI_DEVICE_CLASS(((PCI_CLASS_BRIDGE_PCI << 8) | 0x01), ~0) }, + { PCI_DEVICE_CLASS(PCI_CLASS_BRIDGE_PCI_SUBTRACTIVE, ~0) }, /* handle any Root Complex Event Collector */ { PCI_DEVICE_CLASS(((PCI_CLASS_SYSTEM_RCEC << 8) | 0x00), ~0) }, { }, diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index aad54c666407..130949c3b486 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -60,6 +60,8 @@ #define PCI_CLASS_BRIDGE_EISA 0x0602 #define PCI_CLASS_BRIDGE_MC 0x0603 #define PCI_CLASS_BRIDGE_PCI 0x0604 +#define PCI_CLASS_BRIDGE_PCI_NORMAL 0x060400 +#define PCI_CLASS_BRIDGE_PCI_SUBTRACTIVE 0x060401 #define PCI_CLASS_BRIDGE_PCMCIA 0x0605 #define PCI_CLASS_BRIDGE_NUBUS 0x0606 #define PCI_CLASS_BRIDGE_CARDBUS 0x0607 -- cgit From f94c35e02464627536036de65720e829d3ae9898 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Wed, 23 Feb 2022 13:14:33 +0300 Subject: PCI: qcom: Remove redundancy between qcom_pcie and qcom_pcie_cfg In preparation to adding more flags to configuration data, use pointer to struct qcom_pcie_cfg directly inside struct qcom_pcie, rather than duplicating all its fields. This would save us from the boilerplate code that just copies flag values from one struct to another one. Link: https://lore.kernel.org/r/20220223101435.447839-3-dmitry.baryshkov@linaro.org Signed-off-by: Dmitry Baryshkov Signed-off-by: Lorenzo Pieralisi Reviewed-by: Bjorn Andersson Acked-by: Stanimir Varbanov --- drivers/pci/controller/dwc/pcie-qcom.c | 34 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 18 deletions(-) (limited to 'drivers/pci/controller/dwc') diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c index c19cd506ed3f..b2db2180e1bc 100644 --- a/drivers/pci/controller/dwc/pcie-qcom.c +++ b/drivers/pci/controller/dwc/pcie-qcom.c @@ -204,8 +204,7 @@ struct qcom_pcie { union qcom_pcie_resources res; struct phy *phy; struct gpio_desc *reset; - const struct qcom_pcie_ops *ops; - unsigned int pipe_clk_need_muxing:1; + const struct qcom_pcie_cfg *cfg; }; #define to_qcom_pcie(x) dev_get_drvdata((x)->dev) @@ -229,8 +228,8 @@ static int qcom_pcie_start_link(struct dw_pcie *pci) struct qcom_pcie *pcie = to_qcom_pcie(pci); /* Enable Link Training state machine */ - if (pcie->ops->ltssm_enable) - pcie->ops->ltssm_enable(pcie); + if (pcie->cfg->ops->ltssm_enable) + pcie->cfg->ops->ltssm_enable(pcie); return 0; } @@ -1176,7 +1175,7 @@ static int qcom_pcie_get_resources_2_7_0(struct qcom_pcie *pcie) if (ret < 0) return ret; - if (pcie->pipe_clk_need_muxing) { + if (pcie->cfg->pipe_clk_need_muxing) { res->pipe_clk_src = devm_clk_get(dev, "pipe_mux"); if (IS_ERR(res->pipe_clk_src)) return PTR_ERR(res->pipe_clk_src); @@ -1209,7 +1208,7 @@ static int qcom_pcie_init_2_7_0(struct qcom_pcie *pcie) } /* Set TCXO as clock source for pcie_pipe_clk_src */ - if (pcie->pipe_clk_need_muxing) + if (pcie->cfg->pipe_clk_need_muxing) clk_set_parent(res->pipe_clk_src, res->ref_clk_src); ret = clk_bulk_prepare_enable(res->num_clks, res->clks); @@ -1284,7 +1283,7 @@ static int qcom_pcie_post_init_2_7_0(struct qcom_pcie *pcie) struct qcom_pcie_resources_2_7_0 *res = &pcie->res.v2_7_0; /* Set pipe clock as clock source for pcie_pipe_clk_src */ - if (pcie->pipe_clk_need_muxing) + if (pcie->cfg->pipe_clk_need_muxing) clk_set_parent(res->pipe_clk_src, res->phy_pipe_clk); return clk_prepare_enable(res->pipe_clk); @@ -1384,7 +1383,7 @@ static int qcom_pcie_host_init(struct pcie_port *pp) qcom_ep_reset_assert(pcie); - ret = pcie->ops->init(pcie); + ret = pcie->cfg->ops->init(pcie); if (ret) return ret; @@ -1392,16 +1391,16 @@ static int qcom_pcie_host_init(struct pcie_port *pp) if (ret) goto err_deinit; - if (pcie->ops->post_init) { - ret = pcie->ops->post_init(pcie); + if (pcie->cfg->ops->post_init) { + ret = pcie->cfg->ops->post_init(pcie); if (ret) goto err_disable_phy; } qcom_ep_reset_deassert(pcie); - if (pcie->ops->config_sid) { - ret = pcie->ops->config_sid(pcie); + if (pcie->cfg->ops->config_sid) { + ret = pcie->cfg->ops->config_sid(pcie); if (ret) goto err; } @@ -1410,12 +1409,12 @@ static int qcom_pcie_host_init(struct pcie_port *pp) err: qcom_ep_reset_assert(pcie); - if (pcie->ops->post_deinit) - pcie->ops->post_deinit(pcie); + if (pcie->cfg->ops->post_deinit) + pcie->cfg->ops->post_deinit(pcie); err_disable_phy: phy_power_off(pcie->phy); err_deinit: - pcie->ops->deinit(pcie); + pcie->cfg->ops->deinit(pcie); return ret; } @@ -1559,8 +1558,7 @@ static int qcom_pcie_probe(struct platform_device *pdev) pcie->pci = pci; - pcie->ops = pcie_cfg->ops; - pcie->pipe_clk_need_muxing = pcie_cfg->pipe_clk_need_muxing; + pcie->cfg = pcie_cfg; pcie->reset = devm_gpiod_get_optional(dev, "perst", GPIOD_OUT_HIGH); if (IS_ERR(pcie->reset)) { @@ -1586,7 +1584,7 @@ static int qcom_pcie_probe(struct platform_device *pdev) goto err_pm_runtime_put; } - ret = pcie->ops->get_resources(pcie); + ret = pcie->cfg->ops->get_resources(pcie); if (ret) goto err_pm_runtime_put; -- cgit From 0614f98bbb9fa9f2262f8d79d8ad53cfae0a118c Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Wed, 23 Feb 2022 13:14:34 +0300 Subject: PCI: qcom: Add ddrss_sf_tbu flag Qualcomm PCIe driver uses compatible string to check if the ddrss_sf_tbu clock should be used. Since sc7280 support has added flags, switch to the new mechanism to check if this clock should be used. Link: https://lore.kernel.org/r/20220223101435.447839-4-dmitry.baryshkov@linaro.org Signed-off-by: Dmitry Baryshkov Signed-off-by: Lorenzo Pieralisi Reviewed-by: Bjorn Andersson Acked-by: Stanimir Varbanov --- drivers/pci/controller/dwc/pcie-qcom.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/pci/controller/dwc') diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c index b2db2180e1bc..7e97820eb575 100644 --- a/drivers/pci/controller/dwc/pcie-qcom.c +++ b/drivers/pci/controller/dwc/pcie-qcom.c @@ -195,6 +195,7 @@ struct qcom_pcie_ops { struct qcom_pcie_cfg { const struct qcom_pcie_ops *ops; unsigned int pipe_clk_need_muxing:1; + unsigned int has_ddrss_sf_tbu_clk:1; }; struct qcom_pcie { @@ -1164,7 +1165,7 @@ static int qcom_pcie_get_resources_2_7_0(struct qcom_pcie *pcie) res->clks[3].id = "bus_slave"; res->clks[4].id = "slave_q2a"; res->clks[5].id = "tbu"; - if (of_device_is_compatible(dev->of_node, "qcom,pcie-sm8250")) { + if (pcie->cfg->has_ddrss_sf_tbu_clk) { res->clks[6].id = "ddrss_sf_tbu"; res->num_clks = 7; } else { @@ -1512,6 +1513,7 @@ static const struct qcom_pcie_cfg sdm845_cfg = { static const struct qcom_pcie_cfg sm8250_cfg = { .ops = &ops_1_9_0, + .has_ddrss_sf_tbu_clk = true, }; static const struct qcom_pcie_cfg sc7280_cfg = { -- cgit From 1c5aa0372634655d47b04f82373336645719fc7c Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Wed, 23 Feb 2022 13:14:35 +0300 Subject: PCI: qcom: Add SM8450 PCIe support On SM8450 platform PCIe hosts do not use all the clocks (and add several additional clocks), so expand the driver to handle these requirements. PCIe0 and PCIe1 hosts use different sets of clocks, so separate entries are required. Link: https://lore.kernel.org/r/20220223101435.447839-5-dmitry.baryshkov@linaro.org Signed-off-by: Dmitry Baryshkov Signed-off-by: Lorenzo Pieralisi Reviewed-by: Bjorn Andersson Acked-by: Stanimir Varbanov --- drivers/pci/controller/dwc/pcie-qcom.c | 57 ++++++++++++++++++++++++++-------- 1 file changed, 44 insertions(+), 13 deletions(-) (limited to 'drivers/pci/controller/dwc') diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c index 7e97820eb575..0bb6d0e14cbb 100644 --- a/drivers/pci/controller/dwc/pcie-qcom.c +++ b/drivers/pci/controller/dwc/pcie-qcom.c @@ -161,7 +161,7 @@ struct qcom_pcie_resources_2_3_3 { /* 6 clocks typically, 7 for sm8250 */ struct qcom_pcie_resources_2_7_0 { - struct clk_bulk_data clks[7]; + struct clk_bulk_data clks[9]; int num_clks; struct regulator_bulk_data supplies[2]; struct reset_control *pci_reset; @@ -195,7 +195,10 @@ struct qcom_pcie_ops { struct qcom_pcie_cfg { const struct qcom_pcie_ops *ops; unsigned int pipe_clk_need_muxing:1; + unsigned int has_tbu_clk:1; unsigned int has_ddrss_sf_tbu_clk:1; + unsigned int has_aggre0_clk:1; + unsigned int has_aggre1_clk:1; }; struct qcom_pcie { @@ -1146,6 +1149,7 @@ static int qcom_pcie_get_resources_2_7_0(struct qcom_pcie *pcie) struct qcom_pcie_resources_2_7_0 *res = &pcie->res.v2_7_0; struct dw_pcie *pci = pcie->pci; struct device *dev = pci->dev; + unsigned int idx; int ret; res->pci_reset = devm_reset_control_get_exclusive(dev, "pci"); @@ -1159,18 +1163,22 @@ static int qcom_pcie_get_resources_2_7_0(struct qcom_pcie *pcie) if (ret) return ret; - res->clks[0].id = "aux"; - res->clks[1].id = "cfg"; - res->clks[2].id = "bus_master"; - res->clks[3].id = "bus_slave"; - res->clks[4].id = "slave_q2a"; - res->clks[5].id = "tbu"; - if (pcie->cfg->has_ddrss_sf_tbu_clk) { - res->clks[6].id = "ddrss_sf_tbu"; - res->num_clks = 7; - } else { - res->num_clks = 6; - } + idx = 0; + res->clks[idx++].id = "aux"; + res->clks[idx++].id = "cfg"; + res->clks[idx++].id = "bus_master"; + res->clks[idx++].id = "bus_slave"; + res->clks[idx++].id = "slave_q2a"; + if (pcie->cfg->has_tbu_clk) + res->clks[idx++].id = "tbu"; + if (pcie->cfg->has_ddrss_sf_tbu_clk) + res->clks[idx++].id = "ddrss_sf_tbu"; + if (pcie->cfg->has_aggre0_clk) + res->clks[idx++].id = "aggre0"; + if (pcie->cfg->has_aggre1_clk) + res->clks[idx++].id = "aggre1"; + + res->num_clks = idx; ret = devm_clk_bulk_get(dev, res->num_clks, res->clks); if (ret < 0) @@ -1236,6 +1244,9 @@ static int qcom_pcie_init_2_7_0(struct qcom_pcie *pcie) goto err_disable_clocks; } + /* Wait for reset to complete, required on SM8450 */ + usleep_range(1000, 1500); + /* configure PCIe to RC mode */ writel(DEVICE_TYPE_RC, pcie->parf + PCIE20_PARF_DEVICE_TYPE); @@ -1509,15 +1520,33 @@ static const struct qcom_pcie_cfg ipq4019_cfg = { static const struct qcom_pcie_cfg sdm845_cfg = { .ops = &ops_2_7_0, + .has_tbu_clk = true, }; static const struct qcom_pcie_cfg sm8250_cfg = { + .ops = &ops_1_9_0, + .has_tbu_clk = true, + .has_ddrss_sf_tbu_clk = true, +}; + +static const struct qcom_pcie_cfg sm8450_pcie0_cfg = { .ops = &ops_1_9_0, .has_ddrss_sf_tbu_clk = true, + .pipe_clk_need_muxing = true, + .has_aggre0_clk = true, + .has_aggre1_clk = true, +}; + +static const struct qcom_pcie_cfg sm8450_pcie1_cfg = { + .ops = &ops_1_9_0, + .has_ddrss_sf_tbu_clk = true, + .pipe_clk_need_muxing = true, + .has_aggre1_clk = true, }; static const struct qcom_pcie_cfg sc7280_cfg = { .ops = &ops_1_9_0, + .has_tbu_clk = true, .pipe_clk_need_muxing = true, }; @@ -1628,6 +1657,8 @@ static const struct of_device_id qcom_pcie_match[] = { { .compatible = "qcom,pcie-sdm845", .data = &sdm845_cfg }, { .compatible = "qcom,pcie-sm8250", .data = &sm8250_cfg }, { .compatible = "qcom,pcie-sc8180x", .data = &sm8250_cfg }, + { .compatible = "qcom,pcie-sm8450-pcie0", .data = &sm8450_pcie0_cfg }, + { .compatible = "qcom,pcie-sm8450-pcie1", .data = &sm8450_pcie1_cfg }, { .compatible = "qcom,pcie-sc7280", .data = &sc7280_cfg }, { } }; -- cgit From f81dd043ec41b71b4f6808ffe1457401de6fa8eb Mon Sep 17 00:00:00 2001 From: Richard Zhu Date: Mon, 21 Feb 2022 14:33:57 +0800 Subject: PCI: imx6: Enable i.MX6QP PCIe power management support i.MX6QP PCIe supports the reset logic, thus it can reset itself to the initialized state when exit from L2 or L3 states. Enable the i.MX6QP PCIe suspend/resume operations support. Link: https://lore.kernel.org/r/1645425237-4071-2-git-send-email-hongxing.zhu@nxp.com Signed-off-by: Richard Zhu Signed-off-by: Lorenzo Pieralisi Reviewed-by: Lucas Stach --- drivers/pci/controller/dwc/pci-imx6.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/pci/controller/dwc') diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index 7b200b66114a..5fd33e4536af 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -917,6 +917,7 @@ static void imx6_pcie_pm_turnoff(struct imx6_pcie *imx6_pcie) /* Others poke directly at IOMUXC registers */ switch (imx6_pcie->drvdata->variant) { case IMX6SX: + case IMX6QP: regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, IMX6SX_GPR12_PCIE_PM_TURN_OFF, IMX6SX_GPR12_PCIE_PM_TURN_OFF); @@ -1246,7 +1247,8 @@ static const struct imx6_pcie_drvdata drvdata[] = { [IMX6QP] = { .variant = IMX6QP, .flags = IMX6_PCIE_FLAG_IMX6_PHY | - IMX6_PCIE_FLAG_IMX6_SPEED_CHANGE, + IMX6_PCIE_FLAG_IMX6_SPEED_CHANGE | + IMX6_PCIE_FLAG_SUPPORTS_SUSPEND, .dbi_length = 0x200, }, [IMX7D] = { -- cgit From cf18fce4ed5c87def7d95554bfc864951b793e4c Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Mon, 21 Feb 2022 21:03:46 +0000 Subject: PCI: fu740: Drop redundant '-gpios' from DT GPIO lookup The calls to devm_gpiod_get_optional() have the -gpios at the end of the name but the GPIO core code is already adding the suffix during the lookup. This means the PCIe driver is not finding the necessary reset or power lines to allow initialisation of the PCIe. Drop the redundant '-gpios' when we look up GPIOs from the DT. This bug has not been noticed because if U-Boot has setup the GPIO lines for the hardware when it does the PCIe initialisation (either by booting from PCIe or user command to access PCIe) then the PCIe will work in Linux. The U-Boot as supplied by SiFive does not by default initialise any PCIe component. Link: https://lore.kernel.org/r/20220221210347.1335004-1-ben.dooks@codethink.co.uk Signed-off-by: Ben Dooks Signed-off-by: Lorenzo Pieralisi Signed-off-by: Bjorn Helgaas --- drivers/pci/controller/dwc/pcie-fu740.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/pci/controller/dwc') diff --git a/drivers/pci/controller/dwc/pcie-fu740.c b/drivers/pci/controller/dwc/pcie-fu740.c index 00cde9a248b5..842b7202b96e 100644 --- a/drivers/pci/controller/dwc/pcie-fu740.c +++ b/drivers/pci/controller/dwc/pcie-fu740.c @@ -259,11 +259,11 @@ static int fu740_pcie_probe(struct platform_device *pdev) return PTR_ERR(afp->mgmt_base); /* Fetch GPIOs */ - afp->reset = devm_gpiod_get_optional(dev, "reset-gpios", GPIOD_OUT_LOW); + afp->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(afp->reset)) return dev_err_probe(dev, PTR_ERR(afp->reset), "unable to get reset-gpios\n"); - afp->pwren = devm_gpiod_get_optional(dev, "pwren-gpios", GPIOD_OUT_LOW); + afp->pwren = devm_gpiod_get_optional(dev, "pwren", GPIOD_OUT_LOW); if (IS_ERR(afp->pwren)) return dev_err_probe(dev, PTR_ERR(afp->pwren), "unable to get pwren-gpios\n"); -- cgit From 815953dc2011ad7a34de355dfa703dcef1085219 Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Sun, 26 Dec 2021 15:40:19 +0800 Subject: PCI: dwc: Restore MSI Receiver mask during resume If a host that uses the IP's integrated MSI Receiver lost power during suspend, we call dw_pcie_setup_rc() to reinit the RC. But dw_pcie_setup_rc() always sets pp->irq_mask[ctrl] to ~0, so the mask register is always set as 0xffffffff incorrectly, thus the MSI can't work after resume. Fix this issue by moving pp->irq_mask[ctrl] initialization to dw_pcie_host_init() so we can correctly set the mask reg during both boot and resume. Tested-by: Richard Zhu Link: https://lore.kernel.org/r/20211226074019.2556-1-jszhang@kernel.org Signed-off-by: Jisheng Zhang Signed-off-by: Lorenzo Pieralisi Signed-off-by: Bjorn Helgaas --- drivers/pci/controller/dwc/pcie-designware-host.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/pci/controller/dwc') diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c index f4755f3a03be..2fa86f32d964 100644 --- a/drivers/pci/controller/dwc/pcie-designware-host.c +++ b/drivers/pci/controller/dwc/pcie-designware-host.c @@ -362,6 +362,12 @@ int dw_pcie_host_init(struct pcie_port *pp) if (ret < 0) return ret; } else if (pp->has_msi_ctrl) { + u32 ctrl, num_ctrls; + + num_ctrls = pp->num_vectors / MAX_MSI_IRQS_PER_CTRL; + for (ctrl = 0; ctrl < num_ctrls; ctrl++) + pp->irq_mask[ctrl] = ~0; + if (!pp->msi_irq) { pp->msi_irq = platform_get_irq_byname_optional(pdev, "msi"); if (pp->msi_irq < 0) { @@ -541,7 +547,6 @@ void dw_pcie_setup_rc(struct pcie_port *pp) /* Initialize IRQ Status array */ for (ctrl = 0; ctrl < num_ctrls; ctrl++) { - pp->irq_mask[ctrl] = ~0; dw_pcie_writel_dbi(pci, PCIE_MSI_INTR0_MASK + (ctrl * MSI_REG_CTRL_BLOCK_SIZE), pp->irq_mask[ctrl]); -- cgit From deaf7a2c2e4b5072a743633bf37c45f34426a093 Mon Sep 17 00:00:00 2001 From: Richard Zhu Date: Thu, 3 Mar 2022 14:34:35 +0800 Subject: PCI: imx6: Invoke the PHY exit function after PHY power off To balance phy->init_count, invoke the phy_exit() after phy_power_off(). Link: https://lore.kernel.org/r/1646289275-17813-1-git-send-email-hongxing.zhu@nxp.com Fixes: 178e244cb6e2 ("PCI: imx: Add the imx8mm pcie support") Signed-off-by: Richard Zhu Signed-off-by: Lorenzo Pieralisi Reviewed-by: Lucas Stach --- drivers/pci/controller/dwc/pci-imx6.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/pci/controller/dwc') diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index 5fd33e4536af..7035c691ffcd 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -978,6 +978,7 @@ static int imx6_pcie_suspend_noirq(struct device *dev) case IMX8MM: if (phy_power_off(imx6_pcie->phy)) dev_err(dev, "unable to power off PHY\n"); + phy_exit(imx6_pcie->phy); break; default: break; -- cgit From 45514f78c65cc9a09437f20e180625f94f769863 Mon Sep 17 00:00:00 2001 From: Richard Zhu Date: Thu, 24 Feb 2022 11:06:53 +0800 Subject: PCI: imx6: Assert i.MX8MM CLKREQ# even if no device present The CLKREQ# signal is an open drain, active low signal that is driven low by the remote Endpoint device. But it might not be driven low if no Endpoint device is connected. On i.MX8MM PCIe, phy_init() may fail and system boot may hang if no Endpoint is connected to assert CLKREQ#. Handle this as on i.MX8MQ, where we explicitly assert CLKREQ# so the PHY can be initialized. Link: https://lore.kernel.org/r/1645672013-8949-1-git-send-email-hongxing.zhu@nxp.com Fixes: 178e244cb6e2 ("PCI: imx: Add the imx8mm pcie support") Signed-off-by: Richard Zhu Signed-off-by: Lorenzo Pieralisi Reviewed-by: Lucas Stach --- drivers/pci/controller/dwc/pci-imx6.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers/pci/controller/dwc') diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index 7035c691ffcd..6619e3caffe2 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -453,10 +453,6 @@ static int imx6_pcie_enable_ref_clk(struct imx6_pcie *imx6_pcie) case IMX7D: break; case IMX8MM: - ret = clk_prepare_enable(imx6_pcie->pcie_aux); - if (ret) - dev_err(dev, "unable to enable pcie_aux clock\n"); - break; case IMX8MQ: ret = clk_prepare_enable(imx6_pcie->pcie_aux); if (ret) { -- cgit From a382c757ec5ef83137a86125f43a4c43dc2ab50b Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Fri, 18 Mar 2022 15:24:30 +0000 Subject: PCI: fu740: Force 2.5GT/s for initial device probe The fu740 PCIe core does not probe any devices on the SiFive Unmatched board without this fix (or having U-Boot explicitly start the PCIe via either boot-script or user command). The fix is to start the link at 2.5GT/s speeds and once the link is up then change the maximum speed back to the default. The U-Boot driver claims to set the link-speed to 2.5GT/s to get the probe to work (and U-Boot does print link up at 2.5GT/s) in the following code: https://source.denx.de/u-boot/u-boot/-/blob/master/drivers/pci/pcie_dw_sifive.c?id=v2022.01#L271 Link: https://lore.kernel.org/r/20220318152430.526320-1-ben.dooks@codethink.co.uk Signed-off-by: Ben Dooks Signed-off-by: Bjorn Helgaas Acked-by: Palmer Dabbelt --- drivers/pci/controller/dwc/pcie-fu740.c | 51 ++++++++++++++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) (limited to 'drivers/pci/controller/dwc') diff --git a/drivers/pci/controller/dwc/pcie-fu740.c b/drivers/pci/controller/dwc/pcie-fu740.c index 842b7202b96e..fd7b31729188 100644 --- a/drivers/pci/controller/dwc/pcie-fu740.c +++ b/drivers/pci/controller/dwc/pcie-fu740.c @@ -181,10 +181,59 @@ static int fu740_pcie_start_link(struct dw_pcie *pci) { struct device *dev = pci->dev; struct fu740_pcie *afp = dev_get_drvdata(dev); + u8 cap_exp = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP); + int ret; + u32 orig, tmp; + + /* + * Force 2.5GT/s when starting the link, due to some devices not + * probing at higher speeds. This happens with the PCIe switch + * on the Unmatched board when U-Boot has not initialised the PCIe. + * The fix in U-Boot is to force 2.5GT/s, which then gets cleared + * by the soft reset done by this driver. + */ + dev_dbg(dev, "cap_exp at %x\n", cap_exp); + dw_pcie_dbi_ro_wr_en(pci); + + tmp = dw_pcie_readl_dbi(pci, cap_exp + PCI_EXP_LNKCAP); + orig = tmp & PCI_EXP_LNKCAP_SLS; + tmp &= ~PCI_EXP_LNKCAP_SLS; + tmp |= PCI_EXP_LNKCAP_SLS_2_5GB; + dw_pcie_writel_dbi(pci, cap_exp + PCI_EXP_LNKCAP, tmp); /* Enable LTSSM */ writel_relaxed(0x1, afp->mgmt_base + PCIEX8MGMT_APP_LTSSM_ENABLE); - return 0; + + ret = dw_pcie_wait_for_link(pci); + if (ret) { + dev_err(dev, "error: link did not start\n"); + goto err; + } + + tmp = dw_pcie_readl_dbi(pci, cap_exp + PCI_EXP_LNKCAP); + if ((tmp & PCI_EXP_LNKCAP_SLS) != orig) { + dev_dbg(dev, "changing speed back to original\n"); + + tmp &= ~PCI_EXP_LNKCAP_SLS; + tmp |= orig; + dw_pcie_writel_dbi(pci, cap_exp + PCI_EXP_LNKCAP, tmp); + + tmp = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL); + tmp |= PORT_LOGIC_SPEED_CHANGE; + dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, tmp); + + ret = dw_pcie_wait_for_link(pci); + if (ret) { + dev_err(dev, "error: link did not start at new speed\n"); + goto err; + } + } + + ret = 0; +err: + WARN_ON(ret); /* we assume that errors will be very rare */ + dw_pcie_dbi_ro_wr_dis(pci); + return ret; } static int fu740_pcie_host_init(struct pcie_port *pp) -- cgit From b6829e0419e5b3deafce5455da588c39deda77fa Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Sun, 13 Mar 2022 14:29:30 -0500 Subject: PCI: kirin: Remove unused assignments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit hi3660_pcie_phy_init() assigned "pdev", but never used the value. Drop it. Found by Krzysztof using cppcheck: $ cppcheck --enable=all --force unreadVariable drivers/pci/controller/dwc/pcie-kirin.c:336 Variable 'pdev' is assigned a value that is never used. Reported-by: Krzysztof Wilczyński Link: https://lore.kernel.org/r/20220313192933.434746-3-helgaas@kernel.org Signed-off-by: Bjorn Helgaas --- drivers/pci/controller/dwc/pcie-kirin.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/pci/controller/dwc') diff --git a/drivers/pci/controller/dwc/pcie-kirin.c b/drivers/pci/controller/dwc/pcie-kirin.c index fa6886d66488..5b56cedebdf1 100644 --- a/drivers/pci/controller/dwc/pcie-kirin.c +++ b/drivers/pci/controller/dwc/pcie-kirin.c @@ -332,9 +332,6 @@ static int hi3660_pcie_phy_init(struct platform_device *pdev, pcie->phy_priv = phy; phy->dev = dev; - /* registers */ - pdev = container_of(dev, struct platform_device, dev); - ret = hi3660_pcie_phy_get_clk(phy); if (ret) return ret; -- cgit From 6f102550728838f0f83123f193740c06fdfbdd62 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Sun, 13 Mar 2022 14:29:31 -0500 Subject: PCI: fu740: Remove unused assignments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fu740_pcie_host_init() assigned "ret", but never used the value. Drop it. Found by Krzysztof using cppcheck: $ cppcheck --enable=all --force unreadVariable drivers/pci/controller/dwc/pcie-fu740.c:227 Variable 'ret' is assigned a value that is never used. Reported-by: Krzysztof Wilczyński Link: https://lore.kernel.org/r/20220313192933.434746-4-helgaas@kernel.org Signed-off-by: Bjorn Helgaas --- drivers/pci/controller/dwc/pcie-fu740.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/pci/controller/dwc') diff --git a/drivers/pci/controller/dwc/pcie-fu740.c b/drivers/pci/controller/dwc/pcie-fu740.c index 00cde9a248b5..43b7b8e18354 100644 --- a/drivers/pci/controller/dwc/pcie-fu740.c +++ b/drivers/pci/controller/dwc/pcie-fu740.c @@ -224,7 +224,7 @@ static int fu740_pcie_host_init(struct pcie_port *pp) /* Clear hold_phy_rst */ writel_relaxed(0x0, afp->mgmt_base + PCIEX8MGMT_APP_HOLD_PHY_RST); /* Enable pcieauxclk */ - ret = clk_prepare_enable(afp->pcie_aux); + clk_prepare_enable(afp->pcie_aux); /* Set RC mode */ writel_relaxed(0x4, afp->mgmt_base + PCIEX8MGMT_DEVICE_TYPE); -- cgit From 88557685cd72cf0db686a4ebff3fad4365cb6071 Mon Sep 17 00:00:00 2001 From: Jiantao Zhang Date: Wed, 9 Mar 2022 20:01:04 +0800 Subject: PCI: dwc: Fix setting error return on MSI DMA mapping failure When dma_mapping_error() returns error because of no enough memory, but dw_pcie_host_init() returns success, which will mislead the callers. Link: https://lore.kernel.org/r/30170911-0e2f-98ce-9266-70465b9073e5@huawei.com Fixes: 07940c369a6b ("PCI: dwc: Fix MSI page leakage in suspend/resume") Signed-off-by: Jianrong Zhang Signed-off-by: Jiantao Zhang Signed-off-by: Lorenzo Pieralisi Reviewed-by: Rob Herring --- drivers/pci/controller/dwc/pcie-designware-host.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/pci/controller/dwc') diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c index 2fa86f32d964..9979302532b7 100644 --- a/drivers/pci/controller/dwc/pcie-designware-host.c +++ b/drivers/pci/controller/dwc/pcie-designware-host.c @@ -396,7 +396,8 @@ int dw_pcie_host_init(struct pcie_port *pp) sizeof(pp->msi_msg), DMA_FROM_DEVICE, DMA_ATTR_SKIP_CPU_SYNC); - if (dma_mapping_error(pci->dev, pp->msi_data)) { + ret = dma_mapping_error(pci->dev, pp->msi_data); + if (ret) { dev_err(pci->dev, "Failed to map MSI data\n"); pp->msi_data = 0; goto err_free_msi; -- cgit From 571dda6ca5136c1213bd36b9f298d4487e2b6622 Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Sun, 26 Dec 2021 15:49:10 +0800 Subject: PCI: tegra194: Remove unnecessary MSI enable reg save and restore The integrated MSI Receiver enable register is always initialized in dw_pcie_setup_rc() which is also called in resume code path, so we don't need to save/restore the enable register during suspend/resume. Link: https://lore.kernel.org/r/20211226074910.2722-1-jszhang@kernel.org Signed-off-by: Jisheng Zhang Signed-off-by: Lorenzo Pieralisi Acked-by: Vidya Sagar --- drivers/pci/controller/dwc/pcie-tegra194.c | 9 --------- 1 file changed, 9 deletions(-) (limited to 'drivers/pci/controller/dwc') diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c index b1b5f836a806..cc2678490162 100644 --- a/drivers/pci/controller/dwc/pcie-tegra194.c +++ b/drivers/pci/controller/dwc/pcie-tegra194.c @@ -186,8 +186,6 @@ #define N_FTS_VAL 52 #define FTS_VAL 52 -#define PORT_LOGIC_MSI_CTRL_INT_0_EN 0x828 - #define GEN3_EQ_CONTROL_OFF 0x8a8 #define GEN3_EQ_CONTROL_OFF_PSET_REQ_VEC_SHIFT 8 #define GEN3_EQ_CONTROL_OFF_PSET_REQ_VEC_MASK GENMASK(23, 8) @@ -2189,9 +2187,6 @@ static int tegra194_pcie_suspend_noirq(struct device *dev) if (!pcie->link_state) return 0; - /* Save MSI interrupt vector */ - pcie->msi_ctrl_int = dw_pcie_readl_dbi(&pcie->pci, - PORT_LOGIC_MSI_CTRL_INT_0_EN); tegra_pcie_downstream_dev_to_D0(pcie); tegra194_pcie_pme_turnoff(pcie); tegra_pcie_unconfig_controller(pcie); @@ -2223,10 +2218,6 @@ static int tegra194_pcie_resume_noirq(struct device *dev) if (ret < 0) goto fail_host_init; - /* Restore MSI interrupt vector */ - dw_pcie_writel_dbi(&pcie->pci, PORT_LOGIC_MSI_CTRL_INT_0_EN, - pcie->msi_ctrl_int); - return 0; fail_host_init: -- cgit From 134b5ce3ed33d3857d5d6e1edcd1656ed9364bbf Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Wed, 30 Mar 2022 18:34:15 -0700 Subject: PCI: qcom: Remove ddrss_sf_tbu clock from SC8180X The Qualcomm SC8180X platform was piggy-backing on the SM8250 qcom_pcie_cfg, but SC8180X doesn't have the ddrss_sf_tbu clock, so it now fails to probe due to the missing clock. Give SC8180X its own qcom_pcie_cfg, without the ddrss_sf_tbu flag set. Fixes: 0614f98bbb9f ("PCI: qcom: Add ddrss_sf_tbu flag") Link: https://lore.kernel.org/r/20220331013415.592748-1-bjorn.andersson@linaro.org Tested-by: Steev Klimaszewski Signed-off-by: Bjorn Andersson Signed-off-by: Bjorn Helgaas Reviewed-by: Dmitry Baryshkov Acked-by: Stanimir Varbanov --- drivers/pci/controller/dwc/pcie-qcom.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/pci/controller/dwc') diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c index 6ab90891801d..816028c0f6ed 100644 --- a/drivers/pci/controller/dwc/pcie-qcom.c +++ b/drivers/pci/controller/dwc/pcie-qcom.c @@ -1550,6 +1550,11 @@ static const struct qcom_pcie_cfg sc7280_cfg = { .pipe_clk_need_muxing = true, }; +static const struct qcom_pcie_cfg sc8180x_cfg = { + .ops = &ops_1_9_0, + .has_tbu_clk = true, +}; + static const struct dw_pcie_ops dw_pcie_ops = { .link_up = qcom_pcie_link_up, .start_link = qcom_pcie_start_link, @@ -1656,7 +1661,7 @@ static const struct of_device_id qcom_pcie_match[] = { { .compatible = "qcom,pcie-qcs404", .data = &ipq4019_cfg }, { .compatible = "qcom,pcie-sdm845", .data = &sdm845_cfg }, { .compatible = "qcom,pcie-sm8250", .data = &sm8250_cfg }, - { .compatible = "qcom,pcie-sc8180x", .data = &sm8250_cfg }, + { .compatible = "qcom,pcie-sc8180x", .data = &sc8180x_cfg }, { .compatible = "qcom,pcie-sm8450-pcie0", .data = &sm8450_pcie0_cfg }, { .compatible = "qcom,pcie-sm8450-pcie1", .data = &sm8450_pcie1_cfg }, { .compatible = "qcom,pcie-sc7280", .data = &sc7280_cfg }, -- cgit From bc49681c96360e0ff9c6659e352eec3286b968ce Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Mon, 2 May 2022 16:19:38 +0530 Subject: PCI: qcom-ep: Move enable/disable resources code to common functions Remove code duplication by moving the code related to enabling/disabling the resources (PHY, CLK, Reset) to common functions so that they can be called from multiple places. [mani: renamed the functions and reworded the commit message] Link: https://lore.kernel.org/r/20220502104938.97033-1-manivannan.sadhasivam@linaro.org Signed-off-by: Dmitry Baryshkov Signed-off-by: Manivannan Sadhasivam Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/dwc/pcie-qcom-ep.c | 91 ++++++++++++++++--------------- 1 file changed, 46 insertions(+), 45 deletions(-) (limited to 'drivers/pci/controller/dwc') diff --git a/drivers/pci/controller/dwc/pcie-qcom-ep.c b/drivers/pci/controller/dwc/pcie-qcom-ep.c index 6ce8eddf3a37..ec99116ad05c 100644 --- a/drivers/pci/controller/dwc/pcie-qcom-ep.c +++ b/drivers/pci/controller/dwc/pcie-qcom-ep.c @@ -223,11 +223,8 @@ static void qcom_pcie_dw_stop_link(struct dw_pcie *pci) disable_irq(pcie_ep->perst_irq); } -static int qcom_pcie_perst_deassert(struct dw_pcie *pci) +static int qcom_pcie_enable_resources(struct qcom_pcie_ep *pcie_ep) { - struct qcom_pcie_ep *pcie_ep = to_pcie_ep(pci); - struct device *dev = pci->dev; - u32 val, offset; int ret; ret = clk_bulk_prepare_enable(ARRAY_SIZE(qcom_pcie_ep_clks), @@ -247,6 +244,38 @@ static int qcom_pcie_perst_deassert(struct dw_pcie *pci) if (ret) goto err_phy_exit; + return 0; + +err_phy_exit: + phy_exit(pcie_ep->phy); +err_disable_clk: + clk_bulk_disable_unprepare(ARRAY_SIZE(qcom_pcie_ep_clks), + qcom_pcie_ep_clks); + + return ret; +} + +static void qcom_pcie_disable_resources(struct qcom_pcie_ep *pcie_ep) +{ + phy_power_off(pcie_ep->phy); + phy_exit(pcie_ep->phy); + clk_bulk_disable_unprepare(ARRAY_SIZE(qcom_pcie_ep_clks), + qcom_pcie_ep_clks); +} + +static int qcom_pcie_perst_deassert(struct dw_pcie *pci) +{ + struct qcom_pcie_ep *pcie_ep = to_pcie_ep(pci); + struct device *dev = pci->dev; + u32 val, offset; + int ret; + + ret = qcom_pcie_enable_resources(pcie_ep); + if (ret) { + dev_err(dev, "Failed to enable resources: %d\n", ret); + return ret; + } + /* Assert WAKE# to RC to indicate device is ready */ gpiod_set_value_cansleep(pcie_ep->wake, 1); usleep_range(WAKE_DELAY_US, WAKE_DELAY_US + 500); @@ -335,7 +364,7 @@ static int qcom_pcie_perst_deassert(struct dw_pcie *pci) ret = dw_pcie_ep_init_complete(&pcie_ep->pci.ep); if (ret) { dev_err(dev, "Failed to complete initialization: %d\n", ret); - goto err_phy_power_off; + goto err_disable_resources; } /* @@ -355,13 +384,8 @@ static int qcom_pcie_perst_deassert(struct dw_pcie *pci) return 0; -err_phy_power_off: - phy_power_off(pcie_ep->phy); -err_phy_exit: - phy_exit(pcie_ep->phy); -err_disable_clk: - clk_bulk_disable_unprepare(ARRAY_SIZE(qcom_pcie_ep_clks), - qcom_pcie_ep_clks); +err_disable_resources: + qcom_pcie_disable_resources(pcie_ep); return ret; } @@ -376,10 +400,7 @@ static void qcom_pcie_perst_assert(struct dw_pcie *pci) return; } - phy_power_off(pcie_ep->phy); - phy_exit(pcie_ep->phy); - clk_bulk_disable_unprepare(ARRAY_SIZE(qcom_pcie_ep_clks), - qcom_pcie_ep_clks); + qcom_pcie_disable_resources(pcie_ep); pcie_ep->link_status = QCOM_PCIE_EP_LINK_DISABLED; } @@ -643,43 +664,26 @@ static int qcom_pcie_ep_probe(struct platform_device *pdev) if (ret) return ret; - ret = clk_bulk_prepare_enable(ARRAY_SIZE(qcom_pcie_ep_clks), - qcom_pcie_ep_clks); - if (ret) + ret = qcom_pcie_enable_resources(pcie_ep); + if (ret) { + dev_err(dev, "Failed to enable resources: %d\n", ret); return ret; - - ret = qcom_pcie_ep_core_reset(pcie_ep); - if (ret) - goto err_disable_clk; - - ret = phy_init(pcie_ep->phy); - if (ret) - goto err_disable_clk; - - /* PHY needs to be powered on for dw_pcie_ep_init() */ - ret = phy_power_on(pcie_ep->phy); - if (ret) - goto err_phy_exit; + } ret = dw_pcie_ep_init(&pcie_ep->pci.ep); if (ret) { dev_err(dev, "Failed to initialize endpoint: %d\n", ret); - goto err_phy_power_off; + goto err_disable_resources; } ret = qcom_pcie_ep_enable_irq_resources(pdev, pcie_ep); if (ret) - goto err_phy_power_off; + goto err_disable_resources; return 0; -err_phy_power_off: - phy_power_off(pcie_ep->phy); -err_phy_exit: - phy_exit(pcie_ep->phy); -err_disable_clk: - clk_bulk_disable_unprepare(ARRAY_SIZE(qcom_pcie_ep_clks), - qcom_pcie_ep_clks); +err_disable_resources: + qcom_pcie_disable_resources(pcie_ep); return ret; } @@ -691,10 +695,7 @@ static int qcom_pcie_ep_remove(struct platform_device *pdev) if (pcie_ep->link_status == QCOM_PCIE_EP_LINK_DISABLED) return 0; - phy_power_off(pcie_ep->phy); - phy_exit(pcie_ep->phy); - clk_bulk_disable_unprepare(ARRAY_SIZE(qcom_pcie_ep_clks), - qcom_pcie_ep_clks); + qcom_pcie_disable_resources(pcie_ep); return 0; } -- cgit From a6809941c1f17f455db2cf4ca19c6d8c8746ec25 Mon Sep 17 00:00:00 2001 From: Francesco Dolcini Date: Mon, 4 Apr 2022 10:15:09 +0200 Subject: PCI: imx6: Fix PERST# start-up sequence According to the PCIe standard the PERST# signal (reset-gpio in fsl,imx* compatible dts) should be kept asserted for at least 100 usec before the PCIe refclock is stable, should be kept asserted for at least 100 msec after the power rails are stable and the host should wait at least 100 msec after it is de-asserted before accessing the configuration space of any attached device. From PCIe CEM r2.0, sec 2.6.2 T-PVPERL: Power stable to PERST# inactive - 100 msec T-PERST-CLK: REFCLK stable before PERST# inactive - 100 usec. From PCIe r5.0, sec 6.6.1 With a Downstream Port that does not support Link speeds greater than 5.0 GT/s, software must wait a minimum of 100 ms before sending a Configuration Request to the device immediately below that Port. Failure to do so could prevent PCIe devices to be working correctly, and this was experienced with real devices. Move reset assert to imx6_pcie_assert_core_reset(), this way we ensure that PERST# is asserted before enabling any clock, move de-assert to the end of imx6_pcie_deassert_core_reset() after the clock is enabled and deemed stable and add a new delay of 100 msec just afterward. Link: https://lore.kernel.org/all/20220211152550.286821-1-francesco.dolcini@toradex.com Link: https://lore.kernel.org/r/20220404081509.94356-1-francesco.dolcini@toradex.com Fixes: bb38919ec56e ("PCI: imx6: Add support for i.MX6 PCIe controller") Signed-off-by: Francesco Dolcini Signed-off-by: Lorenzo Pieralisi Reviewed-by: Lucas Stach Acked-by: Richard Zhu --- drivers/pci/controller/dwc/pci-imx6.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) (limited to 'drivers/pci/controller/dwc') diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index 6619e3caffe2..7a285fb0f619 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -408,6 +408,11 @@ static void imx6_pcie_assert_core_reset(struct imx6_pcie *imx6_pcie) dev_err(dev, "failed to disable vpcie regulator: %d\n", ret); } + + /* Some boards don't have PCIe reset GPIO. */ + if (gpio_is_valid(imx6_pcie->reset_gpio)) + gpio_set_value_cansleep(imx6_pcie->reset_gpio, + imx6_pcie->gpio_active_high); } static unsigned int imx6_pcie_grp_offset(const struct imx6_pcie *imx6_pcie) @@ -540,15 +545,6 @@ static void imx6_pcie_deassert_core_reset(struct imx6_pcie *imx6_pcie) /* allow the clocks to stabilize */ usleep_range(200, 500); - /* Some boards don't have PCIe reset GPIO. */ - if (gpio_is_valid(imx6_pcie->reset_gpio)) { - gpio_set_value_cansleep(imx6_pcie->reset_gpio, - imx6_pcie->gpio_active_high); - msleep(100); - gpio_set_value_cansleep(imx6_pcie->reset_gpio, - !imx6_pcie->gpio_active_high); - } - switch (imx6_pcie->drvdata->variant) { case IMX8MQ: reset_control_deassert(imx6_pcie->pciephy_reset); @@ -595,6 +591,15 @@ static void imx6_pcie_deassert_core_reset(struct imx6_pcie *imx6_pcie) break; } + /* Some boards don't have PCIe reset GPIO. */ + if (gpio_is_valid(imx6_pcie->reset_gpio)) { + msleep(100); + gpio_set_value_cansleep(imx6_pcie->reset_gpio, + !imx6_pcie->gpio_active_high); + /* Wait for 100ms after PERST# deassertion (PCIe r5.0, 6.6.1) */ + msleep(100); + } + return; err_ref_clk: -- cgit From 431e7d2eece5b906578926d15ee22a70504c364d Mon Sep 17 00:00:00 2001 From: Peter Geis Date: Fri, 29 Apr 2022 08:38:28 -0400 Subject: PCI: rockchip-dwc: Reset core at driver probe The PCIe controller is in an unknown state at driver probe. This can lead to undesireable effects when the driver attempts to configure the controller. Prevent issues in the future by resetting the core during probe. Link: https://lore.kernel.org/r/20220429123832.2376381-3-pgwipeout@gmail.com Tested-by: Nicolas Frattaroli Signed-off-by: Peter Geis Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/dwc/pcie-dw-rockchip.c | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) (limited to 'drivers/pci/controller/dwc') diff --git a/drivers/pci/controller/dwc/pcie-dw-rockchip.c b/drivers/pci/controller/dwc/pcie-dw-rockchip.c index c9b341e55cbb..faedbd6ebc20 100644 --- a/drivers/pci/controller/dwc/pcie-dw-rockchip.c +++ b/drivers/pci/controller/dwc/pcie-dw-rockchip.c @@ -152,6 +152,11 @@ static int rockchip_pcie_resource_get(struct platform_device *pdev, if (IS_ERR(rockchip->rst_gpio)) return PTR_ERR(rockchip->rst_gpio); + rockchip->rst = devm_reset_control_array_get_exclusive(&pdev->dev); + if (IS_ERR(rockchip->rst)) + return dev_err_probe(&pdev->dev, PTR_ERR(rockchip->rst), + "failed to get reset lines\n"); + return 0; } @@ -182,18 +187,6 @@ static void rockchip_pcie_phy_deinit(struct rockchip_pcie *rockchip) phy_power_off(rockchip->phy); } -static int rockchip_pcie_reset_control_release(struct rockchip_pcie *rockchip) -{ - struct device *dev = rockchip->pci.dev; - - rockchip->rst = devm_reset_control_array_get_exclusive(dev); - if (IS_ERR(rockchip->rst)) - return dev_err_probe(dev, PTR_ERR(rockchip->rst), - "failed to get reset lines\n"); - - return reset_control_deassert(rockchip->rst); -} - static const struct dw_pcie_ops dw_pcie_ops = { .link_up = rockchip_pcie_link_up, .start_link = rockchip_pcie_start_link, @@ -222,6 +215,10 @@ static int rockchip_pcie_probe(struct platform_device *pdev) if (ret) return ret; + ret = reset_control_assert(rockchip->rst); + if (ret) + return ret; + /* DON'T MOVE ME: must be enable before PHY init */ rockchip->vpcie3v3 = devm_regulator_get_optional(dev, "vpcie3v3"); if (IS_ERR(rockchip->vpcie3v3)) { @@ -241,7 +238,7 @@ static int rockchip_pcie_probe(struct platform_device *pdev) if (ret) goto disable_regulator; - ret = rockchip_pcie_reset_control_release(rockchip); + ret = reset_control_deassert(rockchip->rst); if (ret) goto deinit_phy; -- cgit From e8aae154df6121167e5b4f156cfc2402e651d2b1 Mon Sep 17 00:00:00 2001 From: Peter Geis Date: Fri, 29 Apr 2022 08:38:29 -0400 Subject: PCI: rockchip-dwc: Add legacy interrupt support The legacy interrupts on the rk356x PCIe controller are handled by a single muxed interrupt. Add IRQ domain support to the pcie-dw-rockchip driver to support the virtual domain. Link: https://lore.kernel.org/r/20220429123832.2376381-4-pgwipeout@gmail.com Signed-off-by: Peter Geis Signed-off-by: Lorenzo Pieralisi Reviewed-by: Marc Zyngier --- drivers/pci/controller/dwc/pcie-dw-rockchip.c | 96 ++++++++++++++++++++++++++- 1 file changed, 94 insertions(+), 2 deletions(-) (limited to 'drivers/pci/controller/dwc') diff --git a/drivers/pci/controller/dwc/pcie-dw-rockchip.c b/drivers/pci/controller/dwc/pcie-dw-rockchip.c index faedbd6ebc20..8c5bb9d7cc36 100644 --- a/drivers/pci/controller/dwc/pcie-dw-rockchip.c +++ b/drivers/pci/controller/dwc/pcie-dw-rockchip.c @@ -10,9 +10,12 @@ #include #include +#include +#include #include #include #include +#include #include #include #include @@ -26,6 +29,7 @@ */ #define HIWORD_UPDATE(mask, val) (((mask) << 16) | (val)) #define HIWORD_UPDATE_BIT(val) HIWORD_UPDATE(val, val) +#define HIWORD_DISABLE_BIT(val) HIWORD_UPDATE(val, ~val) #define to_rockchip_pcie(x) dev_get_drvdata((x)->dev) @@ -36,10 +40,12 @@ #define PCIE_LINKUP (PCIE_SMLH_LINKUP | PCIE_RDLH_LINKUP) #define PCIE_L0S_ENTRY 0x11 #define PCIE_CLIENT_GENERAL_CONTROL 0x0 +#define PCIE_CLIENT_INTR_STATUS_LEGACY 0x8 +#define PCIE_CLIENT_INTR_MASK_LEGACY 0x1c #define PCIE_CLIENT_GENERAL_DEBUG 0x104 -#define PCIE_CLIENT_HOT_RESET_CTRL 0x180 +#define PCIE_CLIENT_HOT_RESET_CTRL 0x180 #define PCIE_CLIENT_LTSSM_STATUS 0x300 -#define PCIE_LTSSM_ENABLE_ENHANCE BIT(4) +#define PCIE_LTSSM_ENABLE_ENHANCE BIT(4) #define PCIE_LTSSM_STATUS_MASK GENMASK(5, 0) struct rockchip_pcie { @@ -51,6 +57,7 @@ struct rockchip_pcie { struct reset_control *rst; struct gpio_desc *rst_gpio; struct regulator *vpcie3v3; + struct irq_domain *irq_domain; }; static int rockchip_pcie_readl_apb(struct rockchip_pcie *rockchip, @@ -65,6 +72,78 @@ static void rockchip_pcie_writel_apb(struct rockchip_pcie *rockchip, writel_relaxed(val, rockchip->apb_base + reg); } +static void rockchip_pcie_legacy_int_handler(struct irq_desc *desc) +{ + struct irq_chip *chip = irq_desc_get_chip(desc); + struct rockchip_pcie *rockchip = irq_desc_get_handler_data(desc); + unsigned long reg, hwirq; + + chained_irq_enter(chip, desc); + + reg = rockchip_pcie_readl_apb(rockchip, PCIE_CLIENT_INTR_STATUS_LEGACY); + + for_each_set_bit(hwirq, ®, 4) + generic_handle_domain_irq(rockchip->irq_domain, hwirq); + + chained_irq_exit(chip, desc); +} + +static void rockchip_intx_mask(struct irq_data *data) +{ + rockchip_pcie_writel_apb(irq_data_get_irq_chip_data(data), + HIWORD_UPDATE_BIT(BIT(data->hwirq)), + PCIE_CLIENT_INTR_MASK_LEGACY); +}; + +static void rockchip_intx_unmask(struct irq_data *data) +{ + rockchip_pcie_writel_apb(irq_data_get_irq_chip_data(data), + HIWORD_DISABLE_BIT(BIT(data->hwirq)), + PCIE_CLIENT_INTR_MASK_LEGACY); +}; + +static struct irq_chip rockchip_intx_irq_chip = { + .name = "INTx", + .irq_mask = rockchip_intx_mask, + .irq_unmask = rockchip_intx_unmask, + .flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_MASK_ON_SUSPEND, +}; + +static int rockchip_pcie_intx_map(struct irq_domain *domain, unsigned int irq, + irq_hw_number_t hwirq) +{ + irq_set_chip_and_handler(irq, &rockchip_intx_irq_chip, handle_level_irq); + irq_set_chip_data(irq, domain->host_data); + + return 0; +} + +static const struct irq_domain_ops intx_domain_ops = { + .map = rockchip_pcie_intx_map, +}; + +static int rockchip_pcie_init_irq_domain(struct rockchip_pcie *rockchip) +{ + struct device *dev = rockchip->pci.dev; + struct device_node *intc; + + intc = of_get_child_by_name(dev->of_node, "legacy-interrupt-controller"); + if (!intc) { + dev_err(dev, "missing child interrupt-controller node\n"); + return -EINVAL; + } + + rockchip->irq_domain = irq_domain_add_linear(intc, PCI_NUM_INTX, + &intx_domain_ops, rockchip); + of_node_put(intc); + if (!rockchip->irq_domain) { + dev_err(dev, "failed to get a INTx IRQ domain\n"); + return -EINVAL; + } + + return 0; +} + static void rockchip_pcie_enable_ltssm(struct rockchip_pcie *rockchip) { rockchip_pcie_writel_apb(rockchip, PCIE_CLIENT_ENABLE_LTSSM, @@ -111,7 +190,20 @@ static int rockchip_pcie_host_init(struct pcie_port *pp) { struct dw_pcie *pci = to_dw_pcie_from_pp(pp); struct rockchip_pcie *rockchip = to_rockchip_pcie(pci); + struct device *dev = rockchip->pci.dev; u32 val = HIWORD_UPDATE_BIT(PCIE_LTSSM_ENABLE_ENHANCE); + int irq, ret; + + irq = of_irq_get_byname(dev->of_node, "legacy"); + if (irq < 0) + return irq; + + ret = rockchip_pcie_init_irq_domain(rockchip); + if (ret < 0) + dev_err(dev, "failed to init irq domain\n"); + + irq_set_chained_handler_and_data(irq, rockchip_pcie_legacy_int_handler, + rockchip); /* LTSSM enable control mode */ rockchip_pcie_writel_apb(rockchip, val, PCIE_CLIENT_HOT_RESET_CTRL); -- cgit From a935601eed18d739c11da5504b551c7c4754f2ec Mon Sep 17 00:00:00 2001 From: Bhupesh Sharma Date: Sat, 26 Mar 2022 11:38:10 +0530 Subject: PCI: qcom: Add SM8150 SoC support The PCIe IP (rev 1.5.0) on SM8150 SoC is similar to the one used on SM8250. Add SM8150 support, reusing the members of ops_1_9_0. Link: https://lore.kernel.org/r/20220326060810.1797516-3-bhupesh.sharma@linaro.org Signed-off-by: Bhupesh Sharma Signed-off-by: Lorenzo Pieralisi Signed-off-by: Bjorn Helgaas Reviewed-by: Dmitry Baryshkov Reviewed-by: Rob Herring Cc: Vinod Koul --- drivers/pci/controller/dwc/pcie-qcom.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/pci/controller/dwc') diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c index 6ab90891801d..375f27ab9403 100644 --- a/drivers/pci/controller/dwc/pcie-qcom.c +++ b/drivers/pci/controller/dwc/pcie-qcom.c @@ -1523,6 +1523,13 @@ static const struct qcom_pcie_cfg sdm845_cfg = { .has_tbu_clk = true, }; +static const struct qcom_pcie_cfg sm8150_cfg = { + /* sm8150 has qcom IP rev 1.5.0. However 1.5.0 ops are same as + * 1.9.0, so reuse the same. + */ + .ops = &ops_1_9_0, +}; + static const struct qcom_pcie_cfg sm8250_cfg = { .ops = &ops_1_9_0, .has_tbu_clk = true, @@ -1655,6 +1662,7 @@ static const struct of_device_id qcom_pcie_match[] = { { .compatible = "qcom,pcie-ipq4019", .data = &ipq4019_cfg }, { .compatible = "qcom,pcie-qcs404", .data = &ipq4019_cfg }, { .compatible = "qcom,pcie-sdm845", .data = &sdm845_cfg }, + { .compatible = "qcom,pcie-sm8150", .data = &sm8150_cfg }, { .compatible = "qcom,pcie-sm8250", .data = &sm8250_cfg }, { .compatible = "qcom,pcie-sc8180x", .data = &sm8250_cfg }, { .compatible = "qcom,pcie-sm8450-pcie0", .data = &sm8450_pcie0_cfg }, -- cgit From fdf6a2f533115ec5d4d9629178f8196331f1ac50 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Fri, 1 Apr 2022 15:33:51 +0200 Subject: PCI: qcom: Fix pipe clock imbalance Fix a clock imbalance introduced by ed8cc3b1fc84 ("PCI: qcom: Add support for SDM845 PCIe controller"), which enables the pipe clock both in init() and in post_init() but only disables in post_deinit(). Note that the pipe clock was also never disabled in the init() error paths and that enabling the clock before powering up the PHY looks questionable. Link: https://lore.kernel.org/r/20220401133351.10113-1-johan+linaro@kernel.org Fixes: ed8cc3b1fc84 ("PCI: qcom: Add support for SDM845 PCIe controller") Signed-off-by: Johan Hovold Signed-off-by: Lorenzo Pieralisi Signed-off-by: Bjorn Helgaas Reviewed-by: Bjorn Andersson Cc: stable@vger.kernel.org # 5.6 --- drivers/pci/controller/dwc/pcie-qcom.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers/pci/controller/dwc') diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c index 375f27ab9403..925324dece64 100644 --- a/drivers/pci/controller/dwc/pcie-qcom.c +++ b/drivers/pci/controller/dwc/pcie-qcom.c @@ -1238,12 +1238,6 @@ static int qcom_pcie_init_2_7_0(struct qcom_pcie *pcie) goto err_disable_clocks; } - ret = clk_prepare_enable(res->pipe_clk); - if (ret) { - dev_err(dev, "cannot prepare/enable pipe clock\n"); - goto err_disable_clocks; - } - /* Wait for reset to complete, required on SM8450 */ usleep_range(1000, 1500); -- cgit From 87d83b96c8d6c6c2d2096bd0bdba73bcf42b8ef0 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Fri, 1 Apr 2022 15:38:53 +0200 Subject: PCI: qcom: Fix runtime PM imbalance on probe errors Drop the leftover pm_runtime_disable() calls from the late probe error paths that would, for example, prevent runtime PM from being reenabled after a probe deferral. Link: https://lore.kernel.org/r/20220401133854.10421-2-johan+linaro@kernel.org Fixes: 6e5da6f7d824 ("PCI: qcom: Fix error handling in runtime PM support") Signed-off-by: Johan Hovold Signed-off-by: Lorenzo Pieralisi Signed-off-by: Bjorn Helgaas Reviewed-by: Manivannan Sadhasivam Acked-by: Stanimir Varbanov Cc: stable@vger.kernel.org # 4.20 Cc: Bjorn Andersson --- drivers/pci/controller/dwc/pcie-qcom.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers/pci/controller/dwc') diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c index 925324dece64..9191be96d627 100644 --- a/drivers/pci/controller/dwc/pcie-qcom.c +++ b/drivers/pci/controller/dwc/pcie-qcom.c @@ -1623,17 +1623,14 @@ static int qcom_pcie_probe(struct platform_device *pdev) pp->ops = &qcom_pcie_dw_ops; ret = phy_init(pcie->phy); - if (ret) { - pm_runtime_disable(&pdev->dev); + if (ret) goto err_pm_runtime_put; - } platform_set_drvdata(pdev, pcie); ret = dw_pcie_host_init(pp); if (ret) { dev_err(dev, "cannot initialize host\n"); - pm_runtime_disable(&pdev->dev); goto err_pm_runtime_put; } -- cgit From 83013631f0f9961416abd812e228c8efbc2f6069 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Fri, 1 Apr 2022 15:38:54 +0200 Subject: PCI: qcom: Fix unbalanced PHY init on probe errors Undo the PHY initialisation (e.g. balance runtime PM) if host initialisation fails during probe. Link: https://lore.kernel.org/r/20220401133854.10421-3-johan+linaro@kernel.org Fixes: 82a823833f4e ("PCI: qcom: Add Qualcomm PCIe controller driver") Signed-off-by: Johan Hovold Signed-off-by: Lorenzo Pieralisi Signed-off-by: Bjorn Helgaas Reviewed-by: Manivannan Sadhasivam Acked-by: Stanimir Varbanov Cc: stable@vger.kernel.org # 4.5 --- drivers/pci/controller/dwc/pcie-qcom.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/pci/controller/dwc') diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c index 9191be96d627..2e5464edc36e 100644 --- a/drivers/pci/controller/dwc/pcie-qcom.c +++ b/drivers/pci/controller/dwc/pcie-qcom.c @@ -1631,11 +1631,13 @@ static int qcom_pcie_probe(struct platform_device *pdev) ret = dw_pcie_host_init(pp); if (ret) { dev_err(dev, "cannot initialize host\n"); - goto err_pm_runtime_put; + goto err_phy_exit; } return 0; +err_phy_exit: + phy_exit(pcie->phy); err_pm_runtime_put: pm_runtime_put(dev); pm_runtime_disable(dev); -- cgit