Message ID | 20201023075744.26200-6-m.szyprowski@samsung.com (mailing list archive) |
---|---|
State | Superseded, archived |
Delegated to: | Lorenzo Pieralisi |
Headers | show |
Series | Add DW PCIe support for Exynos5433 SoCs | expand |
Hi Marek,
I love your patch! Perhaps something to improve:
[auto build test WARNING on pci/next]
[also build test WARNING on linus/master next-20201023]
[cannot apply to robh/for-next linux/master v5.9]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]
url: https://github.com/0day-ci/linux/commits/Marek-Szyprowski/Add-DW-PCIe-support-for-Exynos5433-SoCs/20201023-155914
base: https://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci.git next
config: x86_64-randconfig-a015-20201023 (attached as .config)
compiler: clang version 12.0.0 (https://github.com/llvm/llvm-project 147b9497e79a98a8614b2b5eb4ba653b44f6b6f0)
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# install x86_64 cross compiling tool for clang build
# apt-get install binutils-x86-64-linux-gnu
# https://github.com/0day-ci/linux/commit/2935808380d3908b7fc99713723b4446e141868b
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review Marek-Szyprowski/Add-DW-PCIe-support-for-Exynos5433-SoCs/20201023-155914
git checkout 2935808380d3908b7fc99713723b4446e141868b
# save the attached .config to linux build tree
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross ARCH=x86_64
If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>
All warnings (new ones prefixed by >>, old ones prefixed by <<):
>> WARNING: modpost: vmlinux.o(.text+0xd0c889): Section mismatch in reference from the function exynos_pcie_probe() to the function .init.text:exynos_add_pcie_port()
The function exynos_pcie_probe() references
the function __init exynos_add_pcie_port().
This is often because exynos_pcie_probe lacks a __init
annotation or the annotation of exynos_add_pcie_port is wrong.
---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
On 10/23/20, 3:58 AM, Marek Szyprowski wrote: > > From: Jaehoon Chung <jh80.chung@samsung.com> > > Exynos5440 SoC support has been dropped since commit 8c83315da1cf ("ARM: > dts: exynos: Remove Exynos5440"). Rework this driver to support DWC PCIe > variant found in the Exynos5433 SoCs. > > The main difference in Exynos5433 variant is lack of the MSI support > (the MSI interrupt is not even routed to the CPU). > > Signed-off-by: Jaehoon Chung <jh80.chung@samsung.com> > [mszyprow: reworked the driver to support only Exynos5433 variant, > simplified code, rebased onto current kernel code, added > regulator support, converted to the regular platform driver, > removed MSI related code, rewrote commit message] > Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com> > Acked-by: Krzysztof Kozlowski <krzk@kernel.org> > --- > drivers/pci/controller/dwc/Kconfig | 3 +- > drivers/pci/controller/dwc/pci-exynos.c | 358 ++++++++++-------------- > drivers/pci/quirks.c | 1 + > 3 files changed, 145 insertions(+), 217 deletions(-) [....] > diff --git a/drivers/pci/controller/dwc/pci-exynos.c b/drivers/pci/controller/dwc/pci-exynos.c > index 242683cde04a..58056fbdc2fa 100644 > --- a/drivers/pci/controller/dwc/pci-exynos.c > +++ b/drivers/pci/controller/dwc/pci-exynos.c > @@ -2,26 +2,23 @@ > /* > * PCIe host controller driver for Samsung Exynos SoCs > * > - * Copyright (C) 2013 Samsung Electronics Co., Ltd. > + * Copyright (C) 2013-2020 Samsung Electronics Co., Ltd. > * https://www.samsung.com > * > * Author: Jingoo Han <jg1.han@samsung.com> > + * Jaehoon Chung <jh80.chung@samsung.com> Would you explain the reason why you add him as an author? If reasonable, I will accept it. Also, I want gentle discussion, not aggressive one. Thank you. Best regards, Jingoo Han > */ [....]
Dear Jingoo, On 10/24/20 12:12 PM, Jingoo Han wrote: > On 10/23/20, 3:58 AM, Marek Szyprowski wrote: >> >> From: Jaehoon Chung <jh80.chung@samsung.com> >> >> Exynos5440 SoC support has been dropped since commit 8c83315da1cf ("ARM: >> dts: exynos: Remove Exynos5440"). Rework this driver to support DWC PCIe >> variant found in the Exynos5433 SoCs. >> >> The main difference in Exynos5433 variant is lack of the MSI support >> (the MSI interrupt is not even routed to the CPU). >> >> Signed-off-by: Jaehoon Chung <jh80.chung@samsung.com> >> [mszyprow: reworked the driver to support only Exynos5433 variant, >> simplified code, rebased onto current kernel code, added >> regulator support, converted to the regular platform driver, >> removed MSI related code, rewrote commit message] >> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com> >> Acked-by: Krzysztof Kozlowski <krzk@kernel.org> >> --- >> drivers/pci/controller/dwc/Kconfig | 3 +- >> drivers/pci/controller/dwc/pci-exynos.c | 358 ++++++++++-------------- >> drivers/pci/quirks.c | 1 + >> 3 files changed, 145 insertions(+), 217 deletions(-) > > [....] > >> diff --git a/drivers/pci/controller/dwc/pci-exynos.c b/drivers/pci/controller/dwc/pci-exynos.c >> index 242683cde04a..58056fbdc2fa 100644 >> --- a/drivers/pci/controller/dwc/pci-exynos.c >> +++ b/drivers/pci/controller/dwc/pci-exynos.c >> @@ -2,26 +2,23 @@ >> /* >> * PCIe host controller driver for Samsung Exynos SoCs >> * >> - * Copyright (C) 2013 Samsung Electronics Co., Ltd. >> + * Copyright (C) 2013-2020 Samsung Electronics Co., Ltd. >> * https://www.samsung.com >> * >> * Author: Jingoo Han <jg1.han@samsung.com> >> + * Jaehoon Chung <jh80.chung@samsung.com> > > Would you explain the reason why you add him as an author? > If reasonable, I will accept it. Also, I want gentle discussion, not aggressive one. > Thank you. It's not important to add me as author. :) If you don't want to accept it, i think it can be removed it. I think that pci-exynos was supported on only exynos5440. As you know, exynos5440 was not common as compared with other exynos SoC. After this patch, pci-exynos is re-newed. Best Regards, Jaehoon Chung > > Best regards, > Jingoo Han > >> */ > > [....] >
On 10/25/20, 10:49 PM, Jaehoon Chung wrote: > > Dear Jingoo, Hi Jaehoon, > On 10/24/20 12:12 PM, Jingoo Han wrote: > > On 10/23/20, 3:58 AM, Marek Szyprowski wrote: > >> > >> From: Jaehoon Chung <jh80.chung@samsung.com> > >> > >> Exynos5440 SoC support has been dropped since commit 8c83315da1cf ("ARM: > >> dts: exynos: Remove Exynos5440"). Rework this driver to support DWC PCIe > >> variant found in the Exynos5433 SoCs. > >> > >> The main difference in Exynos5433 variant is lack of the MSI support > >> (the MSI interrupt is not even routed to the CPU). > >> > >> Signed-off-by: Jaehoon Chung <jh80.chung@samsung.com> > >> [mszyprow: reworked the driver to support only Exynos5433 variant, > >> simplified code, rebased onto current kernel code, added > >> regulator support, converted to the regular platform driver, > >> removed MSI related code, rewrote commit message] > >> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com> > >> Acked-by: Krzysztof Kozlowski <krzk@kernel.org> > >> --- > >> drivers/pci/controller/dwc/Kconfig | 3 +- > >> drivers/pci/controller/dwc/pci-exynos.c | 358 ++++++++++-------------- > >> drivers/pci/quirks.c | 1 + > >> 3 files changed, 145 insertions(+), 217 deletions(-) > > > > [....] > > > >> diff --git a/drivers/pci/controller/dwc/pci-exynos.c b/drivers/pci/controller/dwc/pci-exynos.c > >> index 242683cde04a..58056fbdc2fa 100644 > >> --- a/drivers/pci/controller/dwc/pci-exynos.c > >> +++ b/drivers/pci/controller/dwc/pci-exynos.c > >> @@ -2,26 +2,23 @@ > >> /* > >> * PCIe host controller driver for Samsung Exynos SoCs > >> * > >> - * Copyright (C) 2013 Samsung Electronics Co., Ltd. > >> + * Copyright (C) 2013-2020 Samsung Electronics Co., Ltd. > >> * https://www.samsung.com > >> * > >> * Author: Jingoo Han <jg1.han@samsung.com> > >> + * Jaehoon Chung <jh80.chung@samsung.com> > > > > Would you explain the reason why you add him as an author? > > If reasonable, I will accept it. Also, I want gentle discussion, not aggressive one. > > Thank you. > > It's not important to add me as author. :) > If you don't want to accept it, i think it can be removed it. > I think that pci-exynos was supported on only exynos5440. > As you know, exynos5440 was not common as compared with other exynos SoC. > After this patch, pci-exynos is re-newed. Ah, I just thought that you are not interested in Exynos PCIe anymore. However, if you want to submit other patches for supporting other Exynos PCIe, adding you as an author is ok. There are many Exynos SoCs that support PCIe IP. So, if someone like you who have good experience on Exynos, helps submitting patches for Exynos PCIe, it would be very helpful. :-) Thank you. Best regards, Jingoo Han > > Best Regards, > Jaehoon Chung > > > > > Best regards, > > Jingoo Han > > > >> */ > > > > [....] > >
On Fri, Oct 23, 2020 at 2:58 AM Marek Szyprowski <m.szyprowski@samsung.com> wrote: > > From: Jaehoon Chung <jh80.chung@samsung.com> > > Exynos5440 SoC support has been dropped since commit 8c83315da1cf ("ARM: > dts: exynos: Remove Exynos5440"). Rework this driver to support DWC PCIe > variant found in the Exynos5433 SoCs. > > The main difference in Exynos5433 variant is lack of the MSI support > (the MSI interrupt is not even routed to the CPU). > > Signed-off-by: Jaehoon Chung <jh80.chung@samsung.com> > [mszyprow: reworked the driver to support only Exynos5433 variant, > simplified code, rebased onto current kernel code, added > regulator support, converted to the regular platform driver, > removed MSI related code, rewrote commit message] > Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com> > Acked-by: Krzysztof Kozlowski <krzk@kernel.org> > --- > drivers/pci/controller/dwc/Kconfig | 3 +- > drivers/pci/controller/dwc/pci-exynos.c | 358 ++++++++++-------------- > drivers/pci/quirks.c | 1 + > 3 files changed, 145 insertions(+), 217 deletions(-) > > diff --git a/drivers/pci/controller/dwc/Kconfig b/drivers/pci/controller/dwc/Kconfig > index bc049865f8e0..ade07abd23c9 100644 > --- a/drivers/pci/controller/dwc/Kconfig > +++ b/drivers/pci/controller/dwc/Kconfig > @@ -84,8 +84,7 @@ config PCIE_DW_PLAT_EP > > config PCI_EXYNOS > bool "Samsung Exynos PCIe controller" > - depends on SOC_EXYNOS5440 || COMPILE_TEST > - depends on PCI_MSI_IRQ_DOMAIN > + depends on ARCH_EXYNOS || COMPILE_TEST > select PCIE_DW_HOST > > config PCI_IMX6 > diff --git a/drivers/pci/controller/dwc/pci-exynos.c b/drivers/pci/controller/dwc/pci-exynos.c > index 242683cde04a..58056fbdc2fa 100644 > --- a/drivers/pci/controller/dwc/pci-exynos.c > +++ b/drivers/pci/controller/dwc/pci-exynos.c > @@ -2,26 +2,23 @@ > /* > * PCIe host controller driver for Samsung Exynos SoCs > * > - * Copyright (C) 2013 Samsung Electronics Co., Ltd. > + * Copyright (C) 2013-2020 Samsung Electronics Co., Ltd. > * https://www.samsung.com > * > * Author: Jingoo Han <jg1.han@samsung.com> > + * Jaehoon Chung <jh80.chung@samsung.com> > */ > > #include <linux/clk.h> > #include <linux/delay.h> > -#include <linux/gpio.h> > #include <linux/interrupt.h> > #include <linux/kernel.h> > #include <linux/init.h> > #include <linux/of_device.h> > -#include <linux/of_gpio.h> > #include <linux/pci.h> > #include <linux/platform_device.h> > #include <linux/phy/phy.h> > -#include <linux/resource.h> > -#include <linux/signal.h> > -#include <linux/types.h> > +#include <linux/regulator/consumer.h> > > #include "pcie-designware.h" > > @@ -37,102 +34,47 @@ > #define PCIE_IRQ_SPECIAL 0x008 > #define PCIE_IRQ_EN_PULSE 0x00c > #define PCIE_IRQ_EN_LEVEL 0x010 > -#define IRQ_MSI_ENABLE BIT(2) > #define PCIE_IRQ_EN_SPECIAL 0x014 > -#define PCIE_PWR_RESET 0x018 > +#define PCIE_SW_WAKE 0x018 > +#define PCIE_BUS_EN BIT(1) > #define PCIE_CORE_RESET 0x01c > #define PCIE_CORE_RESET_ENABLE BIT(0) > #define PCIE_STICKY_RESET 0x020 > #define PCIE_NONSTICKY_RESET 0x024 > #define PCIE_APP_INIT_RESET 0x028 > #define PCIE_APP_LTSSM_ENABLE 0x02c > -#define PCIE_ELBI_RDLH_LINKUP 0x064 > +#define PCIE_ELBI_RDLH_LINKUP 0x074 > +#define PCIE_ELBI_XMLH_LINKUP BIT(4) > #define PCIE_ELBI_LTSSM_ENABLE 0x1 > #define PCIE_ELBI_SLV_AWMISC 0x11c > #define PCIE_ELBI_SLV_ARMISC 0x120 > #define PCIE_ELBI_SLV_DBI_ENABLE BIT(21) > > -struct exynos_pcie_mem_res { > - void __iomem *elbi_base; /* DT 0th resource: PCIe CTRL */ > -}; > - > -struct exynos_pcie_clk_res { > - struct clk *clk; > - struct clk *bus_clk; > -}; > +/* DBI register */ > +#define PCIE_MISC_CONTROL_1_OFF 0x8BC > +#define DBI_RO_WR_EN BIT(0) Standard DWC port logic register. The core already handles this mostly. And provides a function to it where it doesn't. Looking at your use, I think you can drop the access. > struct exynos_pcie { > - struct dw_pcie *pci; > - struct exynos_pcie_mem_res *mem_res; > - struct exynos_pcie_clk_res *clk_res; > - const struct exynos_pcie_ops *ops; > - int reset_gpio; > - > + struct dw_pcie pci; > + void __iomem *elbi_base; > + struct clk *clk; > + struct clk *bus_clk; > struct phy *phy; > + struct regulator_bulk_data supplies[2]; > }; > > -struct exynos_pcie_ops { > - int (*get_mem_resources)(struct platform_device *pdev, > - struct exynos_pcie *ep); > - int (*get_clk_resources)(struct exynos_pcie *ep); > - int (*init_clk_resources)(struct exynos_pcie *ep); > - void (*deinit_clk_resources)(struct exynos_pcie *ep); > -}; > - > -static int exynos5440_pcie_get_mem_resources(struct platform_device *pdev, > - struct exynos_pcie *ep) > -{ > - struct dw_pcie *pci = ep->pci; > - struct device *dev = pci->dev; > - > - ep->mem_res = devm_kzalloc(dev, sizeof(*ep->mem_res), GFP_KERNEL); > - if (!ep->mem_res) > - return -ENOMEM; > - > - ep->mem_res->elbi_base = devm_platform_ioremap_resource(pdev, 0); > - if (IS_ERR(ep->mem_res->elbi_base)) > - return PTR_ERR(ep->mem_res->elbi_base); > - > - return 0; > -} > - > -static int exynos5440_pcie_get_clk_resources(struct exynos_pcie *ep) > -{ > - struct dw_pcie *pci = ep->pci; > - struct device *dev = pci->dev; > - > - ep->clk_res = devm_kzalloc(dev, sizeof(*ep->clk_res), GFP_KERNEL); > - if (!ep->clk_res) > - return -ENOMEM; > - > - ep->clk_res->clk = devm_clk_get(dev, "pcie"); > - if (IS_ERR(ep->clk_res->clk)) { > - dev_err(dev, "Failed to get pcie rc clock\n"); > - return PTR_ERR(ep->clk_res->clk); > - } > - > - ep->clk_res->bus_clk = devm_clk_get(dev, "pcie_bus"); > - if (IS_ERR(ep->clk_res->bus_clk)) { > - dev_err(dev, "Failed to get pcie bus clock\n"); > - return PTR_ERR(ep->clk_res->bus_clk); > - } > - > - return 0; > -} > - > -static int exynos5440_pcie_init_clk_resources(struct exynos_pcie *ep) > +static int exynos_pcie_init_clk_resources(struct exynos_pcie *ep) > { > - struct dw_pcie *pci = ep->pci; > - struct device *dev = pci->dev; > + struct device *dev = ep->pci.dev; > int ret; > > - ret = clk_prepare_enable(ep->clk_res->clk); > + ret = clk_prepare_enable(ep->clk); > if (ret) { > dev_err(dev, "cannot enable pcie rc clock"); > return ret; > } > > - ret = clk_prepare_enable(ep->clk_res->bus_clk); > + ret = clk_prepare_enable(ep->bus_clk); > if (ret) { > dev_err(dev, "cannot enable pcie bus clock"); > goto err_bus_clk; > @@ -141,24 +83,17 @@ static int exynos5440_pcie_init_clk_resources(struct exynos_pcie *ep) > return 0; > > err_bus_clk: > - clk_disable_unprepare(ep->clk_res->clk); > + clk_disable_unprepare(ep->clk); > > return ret; > } > > -static void exynos5440_pcie_deinit_clk_resources(struct exynos_pcie *ep) > +static void exynos_pcie_deinit_clk_resources(struct exynos_pcie *ep) > { > - clk_disable_unprepare(ep->clk_res->bus_clk); > - clk_disable_unprepare(ep->clk_res->clk); > + clk_disable_unprepare(ep->bus_clk); > + clk_disable_unprepare(ep->clk); > } > > -static const struct exynos_pcie_ops exynos5440_pcie_ops = { > - .get_mem_resources = exynos5440_pcie_get_mem_resources, > - .get_clk_resources = exynos5440_pcie_get_clk_resources, > - .init_clk_resources = exynos5440_pcie_init_clk_resources, > - .deinit_clk_resources = exynos5440_pcie_deinit_clk_resources, > -}; > - > static void exynos_pcie_writel(void __iomem *base, u32 val, u32 reg) > { > writel(val, base + reg); > @@ -173,67 +108,57 @@ static void exynos_pcie_sideband_dbi_w_mode(struct exynos_pcie *ep, bool on) > { > u32 val; > > - val = exynos_pcie_readl(ep->mem_res->elbi_base, PCIE_ELBI_SLV_AWMISC); > + val = exynos_pcie_readl(ep->elbi_base, PCIE_ELBI_SLV_AWMISC); > if (on) > val |= PCIE_ELBI_SLV_DBI_ENABLE; > else > val &= ~PCIE_ELBI_SLV_DBI_ENABLE; > - exynos_pcie_writel(ep->mem_res->elbi_base, val, PCIE_ELBI_SLV_AWMISC); > + exynos_pcie_writel(ep->elbi_base, val, PCIE_ELBI_SLV_AWMISC); > } > > static void exynos_pcie_sideband_dbi_r_mode(struct exynos_pcie *ep, bool on) > { > u32 val; > > - val = exynos_pcie_readl(ep->mem_res->elbi_base, PCIE_ELBI_SLV_ARMISC); > + val = exynos_pcie_readl(ep->elbi_base, PCIE_ELBI_SLV_ARMISC); > if (on) > val |= PCIE_ELBI_SLV_DBI_ENABLE; > else > val &= ~PCIE_ELBI_SLV_DBI_ENABLE; > - exynos_pcie_writel(ep->mem_res->elbi_base, val, PCIE_ELBI_SLV_ARMISC); > + exynos_pcie_writel(ep->elbi_base, val, PCIE_ELBI_SLV_ARMISC); > } > > static void exynos_pcie_assert_core_reset(struct exynos_pcie *ep) > { > u32 val; > > - val = exynos_pcie_readl(ep->mem_res->elbi_base, PCIE_CORE_RESET); > + val = exynos_pcie_readl(ep->elbi_base, PCIE_CORE_RESET); > val &= ~PCIE_CORE_RESET_ENABLE; > - exynos_pcie_writel(ep->mem_res->elbi_base, val, PCIE_CORE_RESET); > - exynos_pcie_writel(ep->mem_res->elbi_base, 0, PCIE_PWR_RESET); > - exynos_pcie_writel(ep->mem_res->elbi_base, 0, PCIE_STICKY_RESET); > - exynos_pcie_writel(ep->mem_res->elbi_base, 0, PCIE_NONSTICKY_RESET); > + exynos_pcie_writel(ep->elbi_base, val, PCIE_CORE_RESET); > + exynos_pcie_writel(ep->elbi_base, 0, PCIE_STICKY_RESET); > + exynos_pcie_writel(ep->elbi_base, 0, PCIE_NONSTICKY_RESET); > } > > static void exynos_pcie_deassert_core_reset(struct exynos_pcie *ep) > { > u32 val; > > - val = exynos_pcie_readl(ep->mem_res->elbi_base, PCIE_CORE_RESET); > + val = exynos_pcie_readl(ep->elbi_base, PCIE_CORE_RESET); > val |= PCIE_CORE_RESET_ENABLE; > > - exynos_pcie_writel(ep->mem_res->elbi_base, val, PCIE_CORE_RESET); > - exynos_pcie_writel(ep->mem_res->elbi_base, 1, PCIE_STICKY_RESET); > - exynos_pcie_writel(ep->mem_res->elbi_base, 1, PCIE_NONSTICKY_RESET); > - exynos_pcie_writel(ep->mem_res->elbi_base, 1, PCIE_APP_INIT_RESET); > - exynos_pcie_writel(ep->mem_res->elbi_base, 0, PCIE_APP_INIT_RESET); > -} > - > -static void exynos_pcie_assert_reset(struct exynos_pcie *ep) > -{ > - struct dw_pcie *pci = ep->pci; > - struct device *dev = pci->dev; > - > - if (ep->reset_gpio >= 0) > - devm_gpio_request_one(dev, ep->reset_gpio, > - GPIOF_OUT_INIT_HIGH, "RESET"); > + exynos_pcie_writel(ep->elbi_base, val, PCIE_CORE_RESET); > + exynos_pcie_writel(ep->elbi_base, 1, PCIE_STICKY_RESET); > + exynos_pcie_writel(ep->elbi_base, 1, PCIE_NONSTICKY_RESET); > + exynos_pcie_writel(ep->elbi_base, 1, PCIE_APP_INIT_RESET); > + exynos_pcie_writel(ep->elbi_base, 0, PCIE_APP_INIT_RESET); > } > > static int exynos_pcie_establish_link(struct exynos_pcie *ep) > { > - struct dw_pcie *pci = ep->pci; > + struct dw_pcie *pci = &ep->pci; > struct pcie_port *pp = &pci->pp; > struct device *dev = pci->dev; > + u32 val; > > if (dw_pcie_link_up(pci)) { > dev_err(dev, "Link already up\n"); > @@ -243,19 +168,25 @@ static int exynos_pcie_establish_link(struct exynos_pcie *ep) > exynos_pcie_assert_core_reset(ep); > > phy_reset(ep->phy); > - > - exynos_pcie_writel(ep->mem_res->elbi_base, 1, > - PCIE_PWR_RESET); > - > phy_power_on(ep->phy); > phy_init(ep->phy); > > exynos_pcie_deassert_core_reset(ep); > + > + val = exynos_pcie_readl(ep->elbi_base, PCIE_SW_WAKE); > + val &= ~PCIE_BUS_EN; > + exynos_pcie_writel(ep->elbi_base, val, PCIE_SW_WAKE); > + > + /* > + * Enable DBI_RO_WR_EN bit. > + * - When set to 1, some RO and HWinit bits are wriatble from > + * the local application through the DBI. > + */ > + dw_pcie_writel_dbi(pci, PCIE_MISC_CONTROL_1_OFF, DBI_RO_WR_EN); > dw_pcie_setup_rc(pp); First thing this function does is set DBI_RO_WR_EN. > - exynos_pcie_assert_reset(ep); > > /* assert LTSSM enable */ > - exynos_pcie_writel(ep->mem_res->elbi_base, PCIE_ELBI_LTSSM_ENABLE, > + exynos_pcie_writel(ep->elbi_base, PCIE_ELBI_LTSSM_ENABLE, > PCIE_APP_LTSSM_ENABLE); > > /* check if the link is up or not */ > @@ -270,18 +201,8 @@ static void exynos_pcie_clear_irq_pulse(struct exynos_pcie *ep) > { > u32 val; > > - val = exynos_pcie_readl(ep->mem_res->elbi_base, PCIE_IRQ_PULSE); > - exynos_pcie_writel(ep->mem_res->elbi_base, val, PCIE_IRQ_PULSE); > -} > - > -static void exynos_pcie_enable_irq_pulse(struct exynos_pcie *ep) > -{ > - u32 val; > - > - /* enable INTX interrupt */ > - val = IRQ_INTA_ASSERT | IRQ_INTB_ASSERT | > - IRQ_INTC_ASSERT | IRQ_INTD_ASSERT; > - exynos_pcie_writel(ep->mem_res->elbi_base, val, PCIE_IRQ_EN_PULSE); > + val = exynos_pcie_readl(ep->elbi_base, PCIE_IRQ_PULSE); > + exynos_pcie_writel(ep->elbi_base, val, PCIE_IRQ_PULSE); > } > > static irqreturn_t exynos_pcie_irq_handler(int irq, void *arg) > @@ -292,26 +213,14 @@ static irqreturn_t exynos_pcie_irq_handler(int irq, void *arg) > return IRQ_HANDLED; > } > > -static void exynos_pcie_msi_init(struct exynos_pcie *ep) > -{ > - struct dw_pcie *pci = ep->pci; > - struct pcie_port *pp = &pci->pp; > - u32 val; > - > - dw_pcie_msi_init(pp); > - > - /* enable MSI interrupt */ > - val = exynos_pcie_readl(ep->mem_res->elbi_base, PCIE_IRQ_EN_LEVEL); > - val |= IRQ_MSI_ENABLE; > - exynos_pcie_writel(ep->mem_res->elbi_base, val, PCIE_IRQ_EN_LEVEL); > -} > - > -static void exynos_pcie_enable_interrupts(struct exynos_pcie *ep) > +static void exynos_pcie_enable_irq_pulse(struct exynos_pcie *ep) > { > - exynos_pcie_enable_irq_pulse(ep); > + u32 val = IRQ_INTA_ASSERT | IRQ_INTB_ASSERT | > + IRQ_INTC_ASSERT | IRQ_INTD_ASSERT; > > - if (IS_ENABLED(CONFIG_PCI_MSI)) > - exynos_pcie_msi_init(ep); > + exynos_pcie_writel(ep->elbi_base, val, PCIE_IRQ_EN_PULSE); > + exynos_pcie_writel(ep->elbi_base, 0, PCIE_IRQ_EN_LEVEL); > + exynos_pcie_writel(ep->elbi_base, 0, PCIE_IRQ_EN_SPECIAL); > } > > static u32 exynos_pcie_read_dbi(struct dw_pcie *pci, void __iomem *base, > @@ -372,11 +281,8 @@ static int exynos_pcie_link_up(struct dw_pcie *pci) > struct exynos_pcie *ep = to_exynos_pcie(pci); > u32 val; > > - val = exynos_pcie_readl(ep->mem_res->elbi_base, PCIE_ELBI_RDLH_LINKUP); > - if (val == PCIE_ELBI_LTSSM_ENABLE) > - return 1; > - > - return 0; > + val = exynos_pcie_readl(ep->elbi_base, PCIE_ELBI_RDLH_LINKUP); > + return (val & PCIE_ELBI_XMLH_LINKUP); > } > > static int exynos_pcie_host_init(struct pcie_port *pp) > @@ -386,10 +292,8 @@ static int exynos_pcie_host_init(struct pcie_port *pp) > > pp->bridge->ops = &exynos_pci_ops; > > - exynos_pcie_establish_link(ep); > - exynos_pcie_enable_interrupts(ep); > - > - return 0; > + exynos_pcie_enable_irq_pulse(ep); > + return exynos_pcie_establish_link(ep); > } > > static const struct dw_pcie_host_ops exynos_pcie_host_ops = { > @@ -399,28 +303,22 @@ static const struct dw_pcie_host_ops exynos_pcie_host_ops = { > static int __init exynos_add_pcie_port(struct exynos_pcie *ep, > struct platform_device *pdev) > { > - struct dw_pcie *pci = ep->pci; > + struct dw_pcie *pci = &ep->pci; > struct pcie_port *pp = &pci->pp; > struct device *dev = &pdev->dev; > int ret; > > - pp->irq = platform_get_irq(pdev, 1); > + pp->irq = platform_get_irq(pdev, 0); > if (pp->irq < 0) > return pp->irq; > > ret = devm_request_irq(dev, pp->irq, exynos_pcie_irq_handler, > - IRQF_SHARED, "exynos-pcie", ep); > + IRQF_SHARED, "exynos-pcie", ep); > if (ret) { > dev_err(dev, "failed to request irq\n"); > return ret; > } > > - if (IS_ENABLED(CONFIG_PCI_MSI)) { > - pp->msi_irq = platform_get_irq(pdev, 0); > - if (pp->msi_irq < 0) > - return pp->msi_irq; > - } > - > pp->ops = &exynos_pcie_host_ops; > > ret = dw_pcie_host_init(pp); > @@ -438,10 +336,9 @@ static const struct dw_pcie_ops dw_pcie_ops = { > .link_up = exynos_pcie_link_up, > }; > > -static int __init exynos_pcie_probe(struct platform_device *pdev) > +static int exynos_pcie_probe(struct platform_device *pdev) > { > struct device *dev = &pdev->dev; > - struct dw_pcie *pci; > struct exynos_pcie *ep; > struct device_node *np = dev->of_node; > int ret; > @@ -450,42 +347,49 @@ static int __init exynos_pcie_probe(struct platform_device *pdev) > if (!ep) > return -ENOMEM; > > - pci = devm_kzalloc(dev, sizeof(*pci), GFP_KERNEL); > - if (!pci) > - return -ENOMEM; > - > - pci->dev = dev; > - pci->ops = &dw_pcie_ops; > + ep->pci.dev = dev; > + ep->pci.ops = &dw_pcie_ops; > > - ep->pci = pci; > - ep->ops = (const struct exynos_pcie_ops *) > - of_device_get_match_data(dev); > + ep->phy = devm_of_phy_get(dev, np, NULL); > + if (IS_ERR(ep->phy)) > + return PTR_ERR(ep->phy); > > - ep->reset_gpio = of_get_named_gpio(np, "reset-gpio", 0); > + /* External Local Bus interface (ELBI) registers */ > + ep->elbi_base = devm_platform_ioremap_resource_byname(pdev, "elbi"); > + if (IS_ERR(ep->elbi_base)) > + return PTR_ERR(ep->elbi_base); > > - ep->phy = devm_of_phy_get(dev, np, NULL); > - if (IS_ERR(ep->phy)) { > - if (PTR_ERR(ep->phy) != -ENODEV) > - return PTR_ERR(ep->phy); > + /* Data Bus Interface (DBI) registers */ > + ep->pci.dbi_base = devm_platform_ioremap_resource_byname(pdev, "dbi"); > + if (IS_ERR(ep->pci.dbi_base)) > + return PTR_ERR(ep->pci.dbi_base); This is going to get moved to the DWC core code. > > - ep->phy = NULL; > + ep->clk = devm_clk_get(dev, "pcie"); > + if (IS_ERR(ep->clk)) { > + dev_err(dev, "Failed to get pcie rc clock\n"); > + return PTR_ERR(ep->clk); > } > > - if (ep->ops && ep->ops->get_mem_resources) { > - ret = ep->ops->get_mem_resources(pdev, ep); > - if (ret) > - return ret; > + ep->bus_clk = devm_clk_get(dev, "pcie_bus"); > + if (IS_ERR(ep->bus_clk)) { > + dev_err(dev, "Failed to get pcie bus clock\n"); > + return PTR_ERR(ep->bus_clk); > } > > - if (ep->ops && ep->ops->get_clk_resources && > - ep->ops->init_clk_resources) { > - ret = ep->ops->get_clk_resources(ep); > - if (ret) > - return ret; > - ret = ep->ops->init_clk_resources(ep); > - if (ret) > - return ret; > - } > + ep->supplies[0].supply = "vdd18"; > + ep->supplies[1].supply = "vdd10"; > + ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ep->supplies), > + ep->supplies); > + if (ret) > + return ret; > + > + ret = exynos_pcie_init_clk_resources(ep); > + if (ret) > + return ret; > + > + ret = regulator_bulk_enable(ARRAY_SIZE(ep->supplies), ep->supplies); > + if (ret) > + return ret; > > platform_set_drvdata(pdev, ep); > > @@ -497,9 +401,9 @@ static int __init exynos_pcie_probe(struct platform_device *pdev) > > fail_probe: > phy_exit(ep->phy); > + exynos_pcie_deinit_clk_resources(ep); > + regulator_bulk_disable(ARRAY_SIZE(ep->supplies), ep->supplies); > > - if (ep->ops && ep->ops->deinit_clk_resources) > - ep->ops->deinit_clk_resources(ep); > return ret; > } > > @@ -507,32 +411,56 @@ static int __exit exynos_pcie_remove(struct platform_device *pdev) > { > struct exynos_pcie *ep = platform_get_drvdata(pdev); > > - if (ep->ops && ep->ops->deinit_clk_resources) > - ep->ops->deinit_clk_resources(ep); > + phy_power_off(ep->phy); > + phy_exit(ep->phy); > + exynos_pcie_deinit_clk_resources(ep); > + regulator_bulk_disable(ARRAY_SIZE(ep->supplies), ep->supplies); > > return 0; > } > > +static int __maybe_unused exynos_pcie_suspend_noirq(struct device *dev) > +{ Why noirq variant needed? Lot's of PCI host drivers do this and I've yet to get a reason... Adding suspend/resume should probably be a separate patch. What I'd like to do here is have common DWC suspend/resume functions that the platform drivers can use or wrap. > + struct exynos_pcie *ep = dev_get_drvdata(dev); > + > + phy_power_off(ep->phy); > + phy_exit(ep->phy); > + regulator_bulk_disable(ARRAY_SIZE(ep->supplies), ep->supplies); > + > + return 0; > +} > + > +static int __maybe_unused exynos_pcie_resume_noirq(struct device *dev) > +{ > + struct exynos_pcie *ep = dev_get_drvdata(dev); > + struct dw_pcie *pci = &ep->pci; > + struct pcie_port *pp = &pci->pp; > + int ret; > + > + ret = regulator_bulk_enable(ARRAY_SIZE(ep->supplies), ep->supplies); > + if (ret) > + return ret; > + /* exynos_pcie_host_init controls ep->phy */ > + return exynos_pcie_host_init(pp); > +} > + > +static const struct dev_pm_ops exynos_pcie_pm_ops = { > + SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(exynos_pcie_suspend_noirq, > + exynos_pcie_resume_noirq) > +}; > + > static const struct of_device_id exynos_pcie_of_match[] = { > - { > - .compatible = "samsung,exynos5440-pcie", > - .data = &exynos5440_pcie_ops > - }, > - {}, > + { .compatible = "samsung,exynos5433-pcie", }, > + { }, > }; > > static struct platform_driver exynos_pcie_driver = { > + .probe = exynos_pcie_probe, > .remove = __exit_p(exynos_pcie_remove), > .driver = { > .name = "exynos-pcie", > .of_match_table = exynos_pcie_of_match, > + .pm = &exynos_pcie_pm_ops, > }, > }; > - > -/* Exynos PCIe driver does not allow module unload */ > - > -static int __init exynos_pcie_init(void) > -{ > - return platform_driver_probe(&exynos_pcie_driver, exynos_pcie_probe); > -} > -subsys_initcall(exynos_pcie_init); Good that this is gone, but... > +builtin_platform_driver(exynos_pcie_driver); I would like to make all the host drivers modules. Rob
Hi Rob, On 26.10.2020 20:14, Rob Herring wrote: > On Fri, Oct 23, 2020 at 2:58 AM Marek Szyprowski > <m.szyprowski@samsung.com> wrote: >> From: Jaehoon Chung <jh80.chung@samsung.com> >> >> Exynos5440 SoC support has been dropped since commit 8c83315da1cf ("ARM: >> dts: exynos: Remove Exynos5440"). Rework this driver to support DWC PCIe >> variant found in the Exynos5433 SoCs. >> >> The main difference in Exynos5433 variant is lack of the MSI support >> (the MSI interrupt is not even routed to the CPU). >> >> Signed-off-by: Jaehoon Chung <jh80.chung@samsung.com> >> [mszyprow: reworked the driver to support only Exynos5433 variant, >> simplified code, rebased onto current kernel code, added >> regulator support, converted to the regular platform driver, >> removed MSI related code, rewrote commit message] >> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com> >> Acked-by: Krzysztof Kozlowski <krzk@kernel.org> >> --- >> drivers/pci/controller/dwc/Kconfig | 3 +- >> drivers/pci/controller/dwc/pci-exynos.c | 358 ++++++++++-------------- >> drivers/pci/quirks.c | 1 + >> 3 files changed, 145 insertions(+), 217 deletions(-) >> >> diff --git a/drivers/pci/controller/dwc/Kconfig b/drivers/pci/controller/dwc/Kconfig >> index bc049865f8e0..ade07abd23c9 100644 >> --- a/drivers/pci/controller/dwc/Kconfig >> +++ b/drivers/pci/controller/dwc/Kconfig >> @@ -84,8 +84,7 @@ config PCIE_DW_PLAT_EP >> >> config PCI_EXYNOS >> bool "Samsung Exynos PCIe controller" >> - depends on SOC_EXYNOS5440 || COMPILE_TEST >> - depends on PCI_MSI_IRQ_DOMAIN >> + depends on ARCH_EXYNOS || COMPILE_TEST >> select PCIE_DW_HOST >> >> config PCI_IMX6 >> diff --git a/drivers/pci/controller/dwc/pci-exynos.c b/drivers/pci/controller/dwc/pci-exynos.c >> index 242683cde04a..58056fbdc2fa 100644 >> --- a/drivers/pci/controller/dwc/pci-exynos.c >> +++ b/drivers/pci/controller/dwc/pci-exynos.c >> @@ -2,26 +2,23 @@ >> /* >> * PCIe host controller driver for Samsung Exynos SoCs >> * >> - * Copyright (C) 2013 Samsung Electronics Co., Ltd. >> + * Copyright (C) 2013-2020 Samsung Electronics Co., Ltd. >> * https://www.samsung.com >> * >> * Author: Jingoo Han <jg1.han@samsung.com> >> + * Jaehoon Chung <jh80.chung@samsung.com> >> */ >> >> #include <linux/clk.h> >> #include <linux/delay.h> >> -#include <linux/gpio.h> >> #include <linux/interrupt.h> >> #include <linux/kernel.h> >> #include <linux/init.h> >> #include <linux/of_device.h> >> -#include <linux/of_gpio.h> >> #include <linux/pci.h> >> #include <linux/platform_device.h> >> #include <linux/phy/phy.h> >> -#include <linux/resource.h> >> -#include <linux/signal.h> >> -#include <linux/types.h> >> +#include <linux/regulator/consumer.h> >> >> #include "pcie-designware.h" >> >> @@ -37,102 +34,47 @@ >> #define PCIE_IRQ_SPECIAL 0x008 >> #define PCIE_IRQ_EN_PULSE 0x00c >> #define PCIE_IRQ_EN_LEVEL 0x010 >> -#define IRQ_MSI_ENABLE BIT(2) >> #define PCIE_IRQ_EN_SPECIAL 0x014 >> -#define PCIE_PWR_RESET 0x018 >> +#define PCIE_SW_WAKE 0x018 >> +#define PCIE_BUS_EN BIT(1) >> #define PCIE_CORE_RESET 0x01c >> #define PCIE_CORE_RESET_ENABLE BIT(0) >> #define PCIE_STICKY_RESET 0x020 >> #define PCIE_NONSTICKY_RESET 0x024 >> #define PCIE_APP_INIT_RESET 0x028 >> #define PCIE_APP_LTSSM_ENABLE 0x02c >> -#define PCIE_ELBI_RDLH_LINKUP 0x064 >> +#define PCIE_ELBI_RDLH_LINKUP 0x074 >> +#define PCIE_ELBI_XMLH_LINKUP BIT(4) >> #define PCIE_ELBI_LTSSM_ENABLE 0x1 >> #define PCIE_ELBI_SLV_AWMISC 0x11c >> #define PCIE_ELBI_SLV_ARMISC 0x120 >> #define PCIE_ELBI_SLV_DBI_ENABLE BIT(21) >> >> -struct exynos_pcie_mem_res { >> - void __iomem *elbi_base; /* DT 0th resource: PCIe CTRL */ >> -}; >> - >> -struct exynos_pcie_clk_res { >> - struct clk *clk; >> - struct clk *bus_clk; >> -}; >> +/* DBI register */ >> +#define PCIE_MISC_CONTROL_1_OFF 0x8BC >> +#define DBI_RO_WR_EN BIT(0) > Standard DWC port logic register. The core already handles this > mostly. And provides a function to it where it doesn't. Looking at > your use, I think you can drop the access. > >> ... >> @@ -243,19 +168,25 @@ static int exynos_pcie_establish_link(struct exynos_pcie *ep) >> exynos_pcie_assert_core_reset(ep); >> >> phy_reset(ep->phy); >> - >> - exynos_pcie_writel(ep->mem_res->elbi_base, 1, >> - PCIE_PWR_RESET); >> - >> phy_power_on(ep->phy); >> phy_init(ep->phy); >> >> exynos_pcie_deassert_core_reset(ep); >> + >> + val = exynos_pcie_readl(ep->elbi_base, PCIE_SW_WAKE); >> + val &= ~PCIE_BUS_EN; >> + exynos_pcie_writel(ep->elbi_base, val, PCIE_SW_WAKE); >> + >> + /* >> + * Enable DBI_RO_WR_EN bit. >> + * - When set to 1, some RO and HWinit bits are wriatble from >> + * the local application through the DBI. >> + */ >> + dw_pcie_writel_dbi(pci, PCIE_MISC_CONTROL_1_OFF, DBI_RO_WR_EN); >> dw_pcie_setup_rc(pp); > First thing this function does is set DBI_RO_WR_EN. Indeed, this has been added to dw_pcie_setup_rc() in commit 3924bc2fd1b6 ("PCI: dwc: Group DBI registers writes requiring unlocking"), after initial version of this patchset. Thanks for pointing this out. I will remove this. >> ... >> @@ -450,42 +347,49 @@ static int __init exynos_pcie_probe(struct platform_device *pdev) >> if (!ep) >> return -ENOMEM; >> >> - pci = devm_kzalloc(dev, sizeof(*pci), GFP_KERNEL); >> - if (!pci) >> - return -ENOMEM; >> - >> - pci->dev = dev; >> - pci->ops = &dw_pcie_ops; >> + ep->pci.dev = dev; >> + ep->pci.ops = &dw_pcie_ops; >> >> - ep->pci = pci; >> - ep->ops = (const struct exynos_pcie_ops *) >> - of_device_get_match_data(dev); >> + ep->phy = devm_of_phy_get(dev, np, NULL); >> + if (IS_ERR(ep->phy)) >> + return PTR_ERR(ep->phy); >> >> - ep->reset_gpio = of_get_named_gpio(np, "reset-gpio", 0); >> + /* External Local Bus interface (ELBI) registers */ >> + ep->elbi_base = devm_platform_ioremap_resource_byname(pdev, "elbi"); >> + if (IS_ERR(ep->elbi_base)) >> + return PTR_ERR(ep->elbi_base); >> >> - ep->phy = devm_of_phy_get(dev, np, NULL); >> - if (IS_ERR(ep->phy)) { >> - if (PTR_ERR(ep->phy) != -ENODEV) >> - return PTR_ERR(ep->phy); >> + /* Data Bus Interface (DBI) registers */ >> + ep->pci.dbi_base = devm_platform_ioremap_resource_byname(pdev, "dbi"); >> + if (IS_ERR(ep->pci.dbi_base)) >> + return PTR_ERR(ep->pci.dbi_base); > This is going to get moved to the DWC core code. Well, so far it is not there yet and other dw-pci drivers do it on their own. Could you point a patch that does this, so I can rebase onto it? > >> - ep->phy = NULL; >> + ep->clk = devm_clk_get(dev, "pcie"); >> + if (IS_ERR(ep->clk)) { >> + dev_err(dev, "Failed to get pcie rc clock\n"); >> + return PTR_ERR(ep->clk); >> } >> >> - if (ep->ops && ep->ops->get_mem_resources) { >> - ret = ep->ops->get_mem_resources(pdev, ep); >> - if (ret) >> - return ret; >> + ep->bus_clk = devm_clk_get(dev, "pcie_bus"); >> + if (IS_ERR(ep->bus_clk)) { >> + dev_err(dev, "Failed to get pcie bus clock\n"); >> + return PTR_ERR(ep->bus_clk); >> } >> >> - if (ep->ops && ep->ops->get_clk_resources && >> - ep->ops->init_clk_resources) { >> - ret = ep->ops->get_clk_resources(ep); >> - if (ret) >> - return ret; >> - ret = ep->ops->init_clk_resources(ep); >> - if (ret) >> - return ret; >> - } >> + ep->supplies[0].supply = "vdd18"; >> + ep->supplies[1].supply = "vdd10"; >> + ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ep->supplies), >> + ep->supplies); >> + if (ret) >> + return ret; >> + >> + ret = exynos_pcie_init_clk_resources(ep); >> + if (ret) >> + return ret; >> + >> + ret = regulator_bulk_enable(ARRAY_SIZE(ep->supplies), ep->supplies); >> + if (ret) >> + return ret; >> >> platform_set_drvdata(pdev, ep); >> >> @@ -497,9 +401,9 @@ static int __init exynos_pcie_probe(struct platform_device *pdev) >> >> fail_probe: >> phy_exit(ep->phy); >> + exynos_pcie_deinit_clk_resources(ep); >> + regulator_bulk_disable(ARRAY_SIZE(ep->supplies), ep->supplies); >> >> - if (ep->ops && ep->ops->deinit_clk_resources) >> - ep->ops->deinit_clk_resources(ep); >> return ret; >> } >> >> @@ -507,32 +411,56 @@ static int __exit exynos_pcie_remove(struct platform_device *pdev) >> { >> struct exynos_pcie *ep = platform_get_drvdata(pdev); >> >> - if (ep->ops && ep->ops->deinit_clk_resources) >> - ep->ops->deinit_clk_resources(ep); >> + phy_power_off(ep->phy); >> + phy_exit(ep->phy); >> + exynos_pcie_deinit_clk_resources(ep); >> + regulator_bulk_disable(ARRAY_SIZE(ep->supplies), ep->supplies); >> >> return 0; >> } >> >> +static int __maybe_unused exynos_pcie_suspend_noirq(struct device *dev) >> +{ > Why noirq variant needed? Lot's of PCI host drivers do this and I've > yet to get a reason... Frankly, I have no idea, but switching to SET_LATE_SYSTEM_SLEEP_PM_OPS breaks system suspend/resume operation - the board doesn't resume from suspend. If this is really important I will add some more logs and try to find what happens between late/early and noirq phases. > Adding suspend/resume should probably be a separate patch. What I'd > like to do here is have common DWC suspend/resume functions that the > platform drivers can use or wrap. Okay, I can move adding suspend/resume to the separate patch if You want. However I probably know too little about PCI to extract some common dwc suspend/resume functions. >> + struct exynos_pcie *ep = dev_get_drvdata(dev); >> + >> + phy_power_off(ep->phy); >> + phy_exit(ep->phy); >> + regulator_bulk_disable(ARRAY_SIZE(ep->supplies), ep->supplies); >> + >> + return 0; >> +} >> + >> +static int __maybe_unused exynos_pcie_resume_noirq(struct device *dev) >> +{ >> + struct exynos_pcie *ep = dev_get_drvdata(dev); >> + struct dw_pcie *pci = &ep->pci; >> + struct pcie_port *pp = &pci->pp; >> + int ret; >> + >> + ret = regulator_bulk_enable(ARRAY_SIZE(ep->supplies), ep->supplies); >> + if (ret) >> + return ret; >> + /* exynos_pcie_host_init controls ep->phy */ >> + return exynos_pcie_host_init(pp); >> +} >> + >> +static const struct dev_pm_ops exynos_pcie_pm_ops = { >> + SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(exynos_pcie_suspend_noirq, >> + exynos_pcie_resume_noirq) >> +}; >> + >> static const struct of_device_id exynos_pcie_of_match[] = { >> - { >> - .compatible = "samsung,exynos5440-pcie", >> - .data = &exynos5440_pcie_ops >> - }, >> - {}, >> + { .compatible = "samsung,exynos5433-pcie", }, >> + { }, >> }; >> >> static struct platform_driver exynos_pcie_driver = { >> + .probe = exynos_pcie_probe, >> .remove = __exit_p(exynos_pcie_remove), >> .driver = { >> .name = "exynos-pcie", >> .of_match_table = exynos_pcie_of_match, >> + .pm = &exynos_pcie_pm_ops, >> }, >> }; >> - >> -/* Exynos PCIe driver does not allow module unload */ >> - >> -static int __init exynos_pcie_init(void) >> -{ >> - return platform_driver_probe(&exynos_pcie_driver, exynos_pcie_probe); >> -} >> -subsys_initcall(exynos_pcie_init); > Good that this is gone, but... > >> +builtin_platform_driver(exynos_pcie_driver); > I would like to make all the host drivers modules. I can check if this can be easily done. If not, I would like to keep it builtin in this patch and leave modularization for the future. Best regards
Hi On 27.10.2020 13:04, Marek Szyprowski wrote: > On 26.10.2020 20:14, Rob Herring wrote: >> On Fri, Oct 23, 2020 at 2:58 AM Marek Szyprowski >> <m.szyprowski@samsung.com> wrote: >>> From: Jaehoon Chung <jh80.chung@samsung.com> >>> >>> Exynos5440 SoC support has been dropped since commit 8c83315da1cf >>> ("ARM: >>> dts: exynos: Remove Exynos5440"). Rework this driver to support DWC >>> PCIe >>> variant found in the Exynos5433 SoCs. >>> >>> The main difference in Exynos5433 variant is lack of the MSI support >>> (the MSI interrupt is not even routed to the CPU). >>> >>> Signed-off-by: Jaehoon Chung <jh80.chung@samsung.com> >>> [mszyprow: reworked the driver to support only Exynos5433 variant, >>> simplified code, rebased onto current kernel code, added >>> regulator support, converted to the regular platform >>> driver, >>> removed MSI related code, rewrote commit message] >>> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com> >>> Acked-by: Krzysztof Kozlowski <krzk@kernel.org> >>> --- >>> drivers/pci/controller/dwc/Kconfig | 3 +- >>> drivers/pci/controller/dwc/pci-exynos.c | 358 >>> ++++++++++-------------- >>> drivers/pci/quirks.c | 1 + >>> 3 files changed, 145 insertions(+), 217 deletions(-) ... >>> +static int __maybe_unused exynos_pcie_suspend_noirq(struct device >>> *dev) >>> +{ >> Why noirq variant needed? Lot's of PCI host drivers do this and I've >> yet to get a reason... > Frankly, I have no idea, but switching to SET_LATE_SYSTEM_SLEEP_PM_OPS > breaks system suspend/resume operation - the board doesn't resume from > suspend. If this is really important I will add some more logs and try > to find what happens between late/early and noirq phases. It looks that PCI framework does something with the device or controller in noirq phase, so the driver cannot shutdown the controller earlier. Here is a relevant part from the kernel log after system suspend/resume cycle captured with init_calldebug enabled: $ dmesg | grep pci brcmfmac 0000:01:00.0: calling pci_pm_suspend+0x0/0x248 @ 96, parent: 0000:00:00.0 brcmfmac 0000:01:00.0: pci_pm_suspend+0x0/0x248 returned 0 after 650 usecs pcieport 0000:00:00.0: calling pci_pm_suspend+0x0/0x248 @ 7, parent: pci0000:00 pcieport 0000:00:00.0: pci_pm_suspend+0x0/0x248 returned 0 after 85 usecs exynos-pcie 15700000.pcie: calling platform_pm_suspend+0x0/0x68 @ 447, parent: soc@0 exynos-pcie 15700000.pcie: platform_pm_suspend+0x0/0x68 returned 0 after 4 usecs exynos_pcie_phy 15680000.pcie-phy: calling platform_pm_suspend+0x0/0x68 @ 447, parent: soc@0 exynos_pcie_phy 15680000.pcie-phy: platform_pm_suspend+0x0/0x68 returned 0 after 3 usecs brcmfmac 0000:01:00.0: calling pci_pm_suspend_late+0x0/0x50 @ 448, parent: 0000:00:00.0 brcmfmac 0000:01:00.0: pci_pm_suspend_late+0x0/0x50 returned 0 after 4 usecs pcieport 0000:00:00.0: calling pci_pm_suspend_late+0x0/0x50 @ 449, parent: pci0000:00 pcieport 0000:00:00.0: pci_pm_suspend_late+0x0/0x50 returned 0 after 4 usecs exynos-pcie 15700000.pcie: calling exynos_pcie_suspend_late+0x0/0x30 @ 447, parent: soc@0 exynos-pcie 15700000.pcie: exynos_pcie_suspend_late 439 exynos-pcie 15700000.pcie: exynos_pcie_suspend_late+0x0/0x30 returned 0 after 17 usecs brcmfmac 0000:01:00.0: calling pci_pm_suspend_noirq+0x0/0x278 @ 449, parent: 0000:00:00.0 brcmfmac 0000:01:00.0: pci_pm_suspend_noirq+0x0/0x278 returned 0 after 24272 usecs pcieport 0000:00:00.0: calling pci_pm_suspend_noirq+0x0/0x278 @ 448, parent: pci0000:00 pcieport 0000:00:00.0: pci_pm_suspend_noirq+0x0/0x278 returned 0 after 196 usecs exynos-pcie 15700000.pcie: calling exynos_pcie_suspend_noirq+0x0/0x40 @ 447, parent: soc@0 exynos-pcie 15700000.pcie: exynos_pcie_suspend_noirq+0x0/0x40 returned 0 after 653 usecs exynos-pcie 15700000.pcie: calling exynos_pcie_resume_noirq+0x0/0x38 @ 447, parent: soc@0 exynos-pcie 15700000.pcie: Link up exynos-pcie 15700000.pcie: exynos_pcie_resume_noirq+0x0/0x38 returned 0 after 91433 usecs pcieport 0000:00:00.0: calling pci_pm_resume_noirq+0x0/0x140 @ 96, parent: pci0000:00 pcieport 0000:00:00.0: pci_pm_resume_noirq+0x0/0x140 returned 0 after 316 usecs brcmfmac 0000:01:00.0: calling pci_pm_resume_noirq+0x0/0x140 @ 143, parent: 0000:00:00.0 brcmfmac 0000:01:00.0: pci_pm_resume_noirq+0x0/0x140 returned 0 after 25470 usecs exynos-pcie 15700000.pcie: calling exynos_pcie_resume_late+0x0/0x30 @ 447, parent: soc@0 exynos-pcie 15700000.pcie: exynos_pcie_resume_late 445 exynos-pcie 15700000.pcie: exynos_pcie_resume_late+0x0/0x30 returned 0 after 24 usecs pcieport 0000:00:00.0: calling pci_pm_resume_early+0x0/0x48 @ 449, parent: pci0000:00 pcieport 0000:00:00.0: pci_pm_resume_early+0x0/0x48 returned 0 after 3 usecs brcmfmac 0000:01:00.0: calling pci_pm_resume_early+0x0/0x48 @ 448, parent: 0000:00:00.0 brcmfmac 0000:01:00.0: pci_pm_resume_early+0x0/0x48 returned 0 after 3 usecs exynos_pcie_phy 15680000.pcie-phy: calling platform_pm_resume+0x0/0x60 @ 447, parent: soc@0 exynos_pcie_phy 15680000.pcie-phy: platform_pm_resume+0x0/0x60 returned 0 after 4 usecs exynos-pcie 15700000.pcie: calling platform_pm_resume+0x0/0x60 @ 447, parent: soc@0 exynos-pcie 15700000.pcie: platform_pm_resume+0x0/0x60 returned 0 after 4 usecs pcieport 0000:00:00.0: calling pci_pm_resume+0x0/0xe0 @ 96, parent: pci0000:00 pcieport 0000:00:00.0: pci_pm_resume+0x0/0xe0 returned 0 after 54 usecs brcmfmac 0000:01:00.0: calling pci_pm_resume+0x0/0xe0 @ 142, parent: 0000:00:00.0 brcmfmac 0000:01:00.0: pci_pm_resume+0x0/0xe0 returned 0 after 554 usecs Best regards
diff --git a/drivers/pci/controller/dwc/Kconfig b/drivers/pci/controller/dwc/Kconfig index bc049865f8e0..ade07abd23c9 100644 --- a/drivers/pci/controller/dwc/Kconfig +++ b/drivers/pci/controller/dwc/Kconfig @@ -84,8 +84,7 @@ config PCIE_DW_PLAT_EP config PCI_EXYNOS bool "Samsung Exynos PCIe controller" - depends on SOC_EXYNOS5440 || COMPILE_TEST - depends on PCI_MSI_IRQ_DOMAIN + depends on ARCH_EXYNOS || COMPILE_TEST select PCIE_DW_HOST config PCI_IMX6 diff --git a/drivers/pci/controller/dwc/pci-exynos.c b/drivers/pci/controller/dwc/pci-exynos.c index 242683cde04a..58056fbdc2fa 100644 --- a/drivers/pci/controller/dwc/pci-exynos.c +++ b/drivers/pci/controller/dwc/pci-exynos.c @@ -2,26 +2,23 @@ /* * PCIe host controller driver for Samsung Exynos SoCs * - * Copyright (C) 2013 Samsung Electronics Co., Ltd. + * Copyright (C) 2013-2020 Samsung Electronics Co., Ltd. * https://www.samsung.com * * Author: Jingoo Han <jg1.han@samsung.com> + * Jaehoon Chung <jh80.chung@samsung.com> */ #include <linux/clk.h> #include <linux/delay.h> -#include <linux/gpio.h> #include <linux/interrupt.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/of_device.h> -#include <linux/of_gpio.h> #include <linux/pci.h> #include <linux/platform_device.h> #include <linux/phy/phy.h> -#include <linux/resource.h> -#include <linux/signal.h> -#include <linux/types.h> +#include <linux/regulator/consumer.h> #include "pcie-designware.h" @@ -37,102 +34,47 @@ #define PCIE_IRQ_SPECIAL 0x008 #define PCIE_IRQ_EN_PULSE 0x00c #define PCIE_IRQ_EN_LEVEL 0x010 -#define IRQ_MSI_ENABLE BIT(2) #define PCIE_IRQ_EN_SPECIAL 0x014 -#define PCIE_PWR_RESET 0x018 +#define PCIE_SW_WAKE 0x018 +#define PCIE_BUS_EN BIT(1) #define PCIE_CORE_RESET 0x01c #define PCIE_CORE_RESET_ENABLE BIT(0) #define PCIE_STICKY_RESET 0x020 #define PCIE_NONSTICKY_RESET 0x024 #define PCIE_APP_INIT_RESET 0x028 #define PCIE_APP_LTSSM_ENABLE 0x02c -#define PCIE_ELBI_RDLH_LINKUP 0x064 +#define PCIE_ELBI_RDLH_LINKUP 0x074 +#define PCIE_ELBI_XMLH_LINKUP BIT(4) #define PCIE_ELBI_LTSSM_ENABLE 0x1 #define PCIE_ELBI_SLV_AWMISC 0x11c #define PCIE_ELBI_SLV_ARMISC 0x120 #define PCIE_ELBI_SLV_DBI_ENABLE BIT(21) -struct exynos_pcie_mem_res { - void __iomem *elbi_base; /* DT 0th resource: PCIe CTRL */ -}; - -struct exynos_pcie_clk_res { - struct clk *clk; - struct clk *bus_clk; -}; +/* DBI register */ +#define PCIE_MISC_CONTROL_1_OFF 0x8BC +#define DBI_RO_WR_EN BIT(0) struct exynos_pcie { - struct dw_pcie *pci; - struct exynos_pcie_mem_res *mem_res; - struct exynos_pcie_clk_res *clk_res; - const struct exynos_pcie_ops *ops; - int reset_gpio; - + struct dw_pcie pci; + void __iomem *elbi_base; + struct clk *clk; + struct clk *bus_clk; struct phy *phy; + struct regulator_bulk_data supplies[2]; }; -struct exynos_pcie_ops { - int (*get_mem_resources)(struct platform_device *pdev, - struct exynos_pcie *ep); - int (*get_clk_resources)(struct exynos_pcie *ep); - int (*init_clk_resources)(struct exynos_pcie *ep); - void (*deinit_clk_resources)(struct exynos_pcie *ep); -}; - -static int exynos5440_pcie_get_mem_resources(struct platform_device *pdev, - struct exynos_pcie *ep) -{ - struct dw_pcie *pci = ep->pci; - struct device *dev = pci->dev; - - ep->mem_res = devm_kzalloc(dev, sizeof(*ep->mem_res), GFP_KERNEL); - if (!ep->mem_res) - return -ENOMEM; - - ep->mem_res->elbi_base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(ep->mem_res->elbi_base)) - return PTR_ERR(ep->mem_res->elbi_base); - - return 0; -} - -static int exynos5440_pcie_get_clk_resources(struct exynos_pcie *ep) -{ - struct dw_pcie *pci = ep->pci; - struct device *dev = pci->dev; - - ep->clk_res = devm_kzalloc(dev, sizeof(*ep->clk_res), GFP_KERNEL); - if (!ep->clk_res) - return -ENOMEM; - - ep->clk_res->clk = devm_clk_get(dev, "pcie"); - if (IS_ERR(ep->clk_res->clk)) { - dev_err(dev, "Failed to get pcie rc clock\n"); - return PTR_ERR(ep->clk_res->clk); - } - - ep->clk_res->bus_clk = devm_clk_get(dev, "pcie_bus"); - if (IS_ERR(ep->clk_res->bus_clk)) { - dev_err(dev, "Failed to get pcie bus clock\n"); - return PTR_ERR(ep->clk_res->bus_clk); - } - - return 0; -} - -static int exynos5440_pcie_init_clk_resources(struct exynos_pcie *ep) +static int exynos_pcie_init_clk_resources(struct exynos_pcie *ep) { - struct dw_pcie *pci = ep->pci; - struct device *dev = pci->dev; + struct device *dev = ep->pci.dev; int ret; - ret = clk_prepare_enable(ep->clk_res->clk); + ret = clk_prepare_enable(ep->clk); if (ret) { dev_err(dev, "cannot enable pcie rc clock"); return ret; } - ret = clk_prepare_enable(ep->clk_res->bus_clk); + ret = clk_prepare_enable(ep->bus_clk); if (ret) { dev_err(dev, "cannot enable pcie bus clock"); goto err_bus_clk; @@ -141,24 +83,17 @@ static int exynos5440_pcie_init_clk_resources(struct exynos_pcie *ep) return 0; err_bus_clk: - clk_disable_unprepare(ep->clk_res->clk); + clk_disable_unprepare(ep->clk); return ret; } -static void exynos5440_pcie_deinit_clk_resources(struct exynos_pcie *ep) +static void exynos_pcie_deinit_clk_resources(struct exynos_pcie *ep) { - clk_disable_unprepare(ep->clk_res->bus_clk); - clk_disable_unprepare(ep->clk_res->clk); + clk_disable_unprepare(ep->bus_clk); + clk_disable_unprepare(ep->clk); } -static const struct exynos_pcie_ops exynos5440_pcie_ops = { - .get_mem_resources = exynos5440_pcie_get_mem_resources, - .get_clk_resources = exynos5440_pcie_get_clk_resources, - .init_clk_resources = exynos5440_pcie_init_clk_resources, - .deinit_clk_resources = exynos5440_pcie_deinit_clk_resources, -}; - static void exynos_pcie_writel(void __iomem *base, u32 val, u32 reg) { writel(val, base + reg); @@ -173,67 +108,57 @@ static void exynos_pcie_sideband_dbi_w_mode(struct exynos_pcie *ep, bool on) { u32 val; - val = exynos_pcie_readl(ep->mem_res->elbi_base, PCIE_ELBI_SLV_AWMISC); + val = exynos_pcie_readl(ep->elbi_base, PCIE_ELBI_SLV_AWMISC); if (on) val |= PCIE_ELBI_SLV_DBI_ENABLE; else val &= ~PCIE_ELBI_SLV_DBI_ENABLE; - exynos_pcie_writel(ep->mem_res->elbi_base, val, PCIE_ELBI_SLV_AWMISC); + exynos_pcie_writel(ep->elbi_base, val, PCIE_ELBI_SLV_AWMISC); } static void exynos_pcie_sideband_dbi_r_mode(struct exynos_pcie *ep, bool on) { u32 val; - val = exynos_pcie_readl(ep->mem_res->elbi_base, PCIE_ELBI_SLV_ARMISC); + val = exynos_pcie_readl(ep->elbi_base, PCIE_ELBI_SLV_ARMISC); if (on) val |= PCIE_ELBI_SLV_DBI_ENABLE; else val &= ~PCIE_ELBI_SLV_DBI_ENABLE; - exynos_pcie_writel(ep->mem_res->elbi_base, val, PCIE_ELBI_SLV_ARMISC); + exynos_pcie_writel(ep->elbi_base, val, PCIE_ELBI_SLV_ARMISC); } static void exynos_pcie_assert_core_reset(struct exynos_pcie *ep) { u32 val; - val = exynos_pcie_readl(ep->mem_res->elbi_base, PCIE_CORE_RESET); + val = exynos_pcie_readl(ep->elbi_base, PCIE_CORE_RESET); val &= ~PCIE_CORE_RESET_ENABLE; - exynos_pcie_writel(ep->mem_res->elbi_base, val, PCIE_CORE_RESET); - exynos_pcie_writel(ep->mem_res->elbi_base, 0, PCIE_PWR_RESET); - exynos_pcie_writel(ep->mem_res->elbi_base, 0, PCIE_STICKY_RESET); - exynos_pcie_writel(ep->mem_res->elbi_base, 0, PCIE_NONSTICKY_RESET); + exynos_pcie_writel(ep->elbi_base, val, PCIE_CORE_RESET); + exynos_pcie_writel(ep->elbi_base, 0, PCIE_STICKY_RESET); + exynos_pcie_writel(ep->elbi_base, 0, PCIE_NONSTICKY_RESET); } static void exynos_pcie_deassert_core_reset(struct exynos_pcie *ep) { u32 val; - val = exynos_pcie_readl(ep->mem_res->elbi_base, PCIE_CORE_RESET); + val = exynos_pcie_readl(ep->elbi_base, PCIE_CORE_RESET); val |= PCIE_CORE_RESET_ENABLE; - exynos_pcie_writel(ep->mem_res->elbi_base, val, PCIE_CORE_RESET); - exynos_pcie_writel(ep->mem_res->elbi_base, 1, PCIE_STICKY_RESET); - exynos_pcie_writel(ep->mem_res->elbi_base, 1, PCIE_NONSTICKY_RESET); - exynos_pcie_writel(ep->mem_res->elbi_base, 1, PCIE_APP_INIT_RESET); - exynos_pcie_writel(ep->mem_res->elbi_base, 0, PCIE_APP_INIT_RESET); -} - -static void exynos_pcie_assert_reset(struct exynos_pcie *ep) -{ - struct dw_pcie *pci = ep->pci; - struct device *dev = pci->dev; - - if (ep->reset_gpio >= 0) - devm_gpio_request_one(dev, ep->reset_gpio, - GPIOF_OUT_INIT_HIGH, "RESET"); + exynos_pcie_writel(ep->elbi_base, val, PCIE_CORE_RESET); + exynos_pcie_writel(ep->elbi_base, 1, PCIE_STICKY_RESET); + exynos_pcie_writel(ep->elbi_base, 1, PCIE_NONSTICKY_RESET); + exynos_pcie_writel(ep->elbi_base, 1, PCIE_APP_INIT_RESET); + exynos_pcie_writel(ep->elbi_base, 0, PCIE_APP_INIT_RESET); } static int exynos_pcie_establish_link(struct exynos_pcie *ep) { - struct dw_pcie *pci = ep->pci; + struct dw_pcie *pci = &ep->pci; struct pcie_port *pp = &pci->pp; struct device *dev = pci->dev; + u32 val; if (dw_pcie_link_up(pci)) { dev_err(dev, "Link already up\n"); @@ -243,19 +168,25 @@ static int exynos_pcie_establish_link(struct exynos_pcie *ep) exynos_pcie_assert_core_reset(ep); phy_reset(ep->phy); - - exynos_pcie_writel(ep->mem_res->elbi_base, 1, - PCIE_PWR_RESET); - phy_power_on(ep->phy); phy_init(ep->phy); exynos_pcie_deassert_core_reset(ep); + + val = exynos_pcie_readl(ep->elbi_base, PCIE_SW_WAKE); + val &= ~PCIE_BUS_EN; + exynos_pcie_writel(ep->elbi_base, val, PCIE_SW_WAKE); + + /* + * Enable DBI_RO_WR_EN bit. + * - When set to 1, some RO and HWinit bits are wriatble from + * the local application through the DBI. + */ + dw_pcie_writel_dbi(pci, PCIE_MISC_CONTROL_1_OFF, DBI_RO_WR_EN); dw_pcie_setup_rc(pp); - exynos_pcie_assert_reset(ep); /* assert LTSSM enable */ - exynos_pcie_writel(ep->mem_res->elbi_base, PCIE_ELBI_LTSSM_ENABLE, + exynos_pcie_writel(ep->elbi_base, PCIE_ELBI_LTSSM_ENABLE, PCIE_APP_LTSSM_ENABLE); /* check if the link is up or not */ @@ -270,18 +201,8 @@ static void exynos_pcie_clear_irq_pulse(struct exynos_pcie *ep) { u32 val; - val = exynos_pcie_readl(ep->mem_res->elbi_base, PCIE_IRQ_PULSE); - exynos_pcie_writel(ep->mem_res->elbi_base, val, PCIE_IRQ_PULSE); -} - -static void exynos_pcie_enable_irq_pulse(struct exynos_pcie *ep) -{ - u32 val; - - /* enable INTX interrupt */ - val = IRQ_INTA_ASSERT | IRQ_INTB_ASSERT | - IRQ_INTC_ASSERT | IRQ_INTD_ASSERT; - exynos_pcie_writel(ep->mem_res->elbi_base, val, PCIE_IRQ_EN_PULSE); + val = exynos_pcie_readl(ep->elbi_base, PCIE_IRQ_PULSE); + exynos_pcie_writel(ep->elbi_base, val, PCIE_IRQ_PULSE); } static irqreturn_t exynos_pcie_irq_handler(int irq, void *arg) @@ -292,26 +213,14 @@ static irqreturn_t exynos_pcie_irq_handler(int irq, void *arg) return IRQ_HANDLED; } -static void exynos_pcie_msi_init(struct exynos_pcie *ep) -{ - struct dw_pcie *pci = ep->pci; - struct pcie_port *pp = &pci->pp; - u32 val; - - dw_pcie_msi_init(pp); - - /* enable MSI interrupt */ - val = exynos_pcie_readl(ep->mem_res->elbi_base, PCIE_IRQ_EN_LEVEL); - val |= IRQ_MSI_ENABLE; - exynos_pcie_writel(ep->mem_res->elbi_base, val, PCIE_IRQ_EN_LEVEL); -} - -static void exynos_pcie_enable_interrupts(struct exynos_pcie *ep) +static void exynos_pcie_enable_irq_pulse(struct exynos_pcie *ep) { - exynos_pcie_enable_irq_pulse(ep); + u32 val = IRQ_INTA_ASSERT | IRQ_INTB_ASSERT | + IRQ_INTC_ASSERT | IRQ_INTD_ASSERT; - if (IS_ENABLED(CONFIG_PCI_MSI)) - exynos_pcie_msi_init(ep); + exynos_pcie_writel(ep->elbi_base, val, PCIE_IRQ_EN_PULSE); + exynos_pcie_writel(ep->elbi_base, 0, PCIE_IRQ_EN_LEVEL); + exynos_pcie_writel(ep->elbi_base, 0, PCIE_IRQ_EN_SPECIAL); } static u32 exynos_pcie_read_dbi(struct dw_pcie *pci, void __iomem *base, @@ -372,11 +281,8 @@ static int exynos_pcie_link_up(struct dw_pcie *pci) struct exynos_pcie *ep = to_exynos_pcie(pci); u32 val; - val = exynos_pcie_readl(ep->mem_res->elbi_base, PCIE_ELBI_RDLH_LINKUP); - if (val == PCIE_ELBI_LTSSM_ENABLE) - return 1; - - return 0; + val = exynos_pcie_readl(ep->elbi_base, PCIE_ELBI_RDLH_LINKUP); + return (val & PCIE_ELBI_XMLH_LINKUP); } static int exynos_pcie_host_init(struct pcie_port *pp) @@ -386,10 +292,8 @@ static int exynos_pcie_host_init(struct pcie_port *pp) pp->bridge->ops = &exynos_pci_ops; - exynos_pcie_establish_link(ep); - exynos_pcie_enable_interrupts(ep); - - return 0; + exynos_pcie_enable_irq_pulse(ep); + return exynos_pcie_establish_link(ep); } static const struct dw_pcie_host_ops exynos_pcie_host_ops = { @@ -399,28 +303,22 @@ static const struct dw_pcie_host_ops exynos_pcie_host_ops = { static int __init exynos_add_pcie_port(struct exynos_pcie *ep, struct platform_device *pdev) { - struct dw_pcie *pci = ep->pci; + struct dw_pcie *pci = &ep->pci; struct pcie_port *pp = &pci->pp; struct device *dev = &pdev->dev; int ret; - pp->irq = platform_get_irq(pdev, 1); + pp->irq = platform_get_irq(pdev, 0); if (pp->irq < 0) return pp->irq; ret = devm_request_irq(dev, pp->irq, exynos_pcie_irq_handler, - IRQF_SHARED, "exynos-pcie", ep); + IRQF_SHARED, "exynos-pcie", ep); if (ret) { dev_err(dev, "failed to request irq\n"); return ret; } - if (IS_ENABLED(CONFIG_PCI_MSI)) { - pp->msi_irq = platform_get_irq(pdev, 0); - if (pp->msi_irq < 0) - return pp->msi_irq; - } - pp->ops = &exynos_pcie_host_ops; ret = dw_pcie_host_init(pp); @@ -438,10 +336,9 @@ static const struct dw_pcie_ops dw_pcie_ops = { .link_up = exynos_pcie_link_up, }; -static int __init exynos_pcie_probe(struct platform_device *pdev) +static int exynos_pcie_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct dw_pcie *pci; struct exynos_pcie *ep; struct device_node *np = dev->of_node; int ret; @@ -450,42 +347,49 @@ static int __init exynos_pcie_probe(struct platform_device *pdev) if (!ep) return -ENOMEM; - pci = devm_kzalloc(dev, sizeof(*pci), GFP_KERNEL); - if (!pci) - return -ENOMEM; - - pci->dev = dev; - pci->ops = &dw_pcie_ops; + ep->pci.dev = dev; + ep->pci.ops = &dw_pcie_ops; - ep->pci = pci; - ep->ops = (const struct exynos_pcie_ops *) - of_device_get_match_data(dev); + ep->phy = devm_of_phy_get(dev, np, NULL); + if (IS_ERR(ep->phy)) + return PTR_ERR(ep->phy); - ep->reset_gpio = of_get_named_gpio(np, "reset-gpio", 0); + /* External Local Bus interface (ELBI) registers */ + ep->elbi_base = devm_platform_ioremap_resource_byname(pdev, "elbi"); + if (IS_ERR(ep->elbi_base)) + return PTR_ERR(ep->elbi_base); - ep->phy = devm_of_phy_get(dev, np, NULL); - if (IS_ERR(ep->phy)) { - if (PTR_ERR(ep->phy) != -ENODEV) - return PTR_ERR(ep->phy); + /* Data Bus Interface (DBI) registers */ + ep->pci.dbi_base = devm_platform_ioremap_resource_byname(pdev, "dbi"); + if (IS_ERR(ep->pci.dbi_base)) + return PTR_ERR(ep->pci.dbi_base); - ep->phy = NULL; + ep->clk = devm_clk_get(dev, "pcie"); + if (IS_ERR(ep->clk)) { + dev_err(dev, "Failed to get pcie rc clock\n"); + return PTR_ERR(ep->clk); } - if (ep->ops && ep->ops->get_mem_resources) { - ret = ep->ops->get_mem_resources(pdev, ep); - if (ret) - return ret; + ep->bus_clk = devm_clk_get(dev, "pcie_bus"); + if (IS_ERR(ep->bus_clk)) { + dev_err(dev, "Failed to get pcie bus clock\n"); + return PTR_ERR(ep->bus_clk); } - if (ep->ops && ep->ops->get_clk_resources && - ep->ops->init_clk_resources) { - ret = ep->ops->get_clk_resources(ep); - if (ret) - return ret; - ret = ep->ops->init_clk_resources(ep); - if (ret) - return ret; - } + ep->supplies[0].supply = "vdd18"; + ep->supplies[1].supply = "vdd10"; + ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ep->supplies), + ep->supplies); + if (ret) + return ret; + + ret = exynos_pcie_init_clk_resources(ep); + if (ret) + return ret; + + ret = regulator_bulk_enable(ARRAY_SIZE(ep->supplies), ep->supplies); + if (ret) + return ret; platform_set_drvdata(pdev, ep); @@ -497,9 +401,9 @@ static int __init exynos_pcie_probe(struct platform_device *pdev) fail_probe: phy_exit(ep->phy); + exynos_pcie_deinit_clk_resources(ep); + regulator_bulk_disable(ARRAY_SIZE(ep->supplies), ep->supplies); - if (ep->ops && ep->ops->deinit_clk_resources) - ep->ops->deinit_clk_resources(ep); return ret; } @@ -507,32 +411,56 @@ static int __exit exynos_pcie_remove(struct platform_device *pdev) { struct exynos_pcie *ep = platform_get_drvdata(pdev); - if (ep->ops && ep->ops->deinit_clk_resources) - ep->ops->deinit_clk_resources(ep); + phy_power_off(ep->phy); + phy_exit(ep->phy); + exynos_pcie_deinit_clk_resources(ep); + regulator_bulk_disable(ARRAY_SIZE(ep->supplies), ep->supplies); return 0; } +static int __maybe_unused exynos_pcie_suspend_noirq(struct device *dev) +{ + struct exynos_pcie *ep = dev_get_drvdata(dev); + + phy_power_off(ep->phy); + phy_exit(ep->phy); + regulator_bulk_disable(ARRAY_SIZE(ep->supplies), ep->supplies); + + return 0; +} + +static int __maybe_unused exynos_pcie_resume_noirq(struct device *dev) +{ + struct exynos_pcie *ep = dev_get_drvdata(dev); + struct dw_pcie *pci = &ep->pci; + struct pcie_port *pp = &pci->pp; + int ret; + + ret = regulator_bulk_enable(ARRAY_SIZE(ep->supplies), ep->supplies); + if (ret) + return ret; + /* exynos_pcie_host_init controls ep->phy */ + return exynos_pcie_host_init(pp); +} + +static const struct dev_pm_ops exynos_pcie_pm_ops = { + SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(exynos_pcie_suspend_noirq, + exynos_pcie_resume_noirq) +}; + static const struct of_device_id exynos_pcie_of_match[] = { - { - .compatible = "samsung,exynos5440-pcie", - .data = &exynos5440_pcie_ops - }, - {}, + { .compatible = "samsung,exynos5433-pcie", }, + { }, }; static struct platform_driver exynos_pcie_driver = { + .probe = exynos_pcie_probe, .remove = __exit_p(exynos_pcie_remove), .driver = { .name = "exynos-pcie", .of_match_table = exynos_pcie_of_match, + .pm = &exynos_pcie_pm_ops, }, }; - -/* Exynos PCIe driver does not allow module unload */ - -static int __init exynos_pcie_init(void) -{ - return platform_driver_probe(&exynos_pcie_driver, exynos_pcie_probe); -} -subsys_initcall(exynos_pcie_init); +builtin_platform_driver(exynos_pcie_driver); diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index f70692ac79c5..8b93f0bba1f2 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -2522,6 +2522,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VT3351, quirk_disab DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VT3364, quirk_disable_all_msi); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8380_0, quirk_disable_all_msi); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI, 0x0761, quirk_disable_all_msi); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SAMSUNG, 0xa5e3, quirk_disable_all_msi); /* Disable MSI on chipsets that are known to not support it */ static void quirk_disable_msi(struct pci_dev *dev)