[PATCHv5 6/6] PCI: layerscape: Add power management support
From: Hou Zhiqiang Add PME_Turn_Off/PME_TO_Ack handshake sequence, and finally put the PCIe controller into D3 state after the L2/L3 ready state transition process completion. Signed-off-by: Hou Zhiqiang --- V5: - Fix a typo of the parameter given to function dw_pcie_setup_rc() drivers/pci/controller/dwc/pci-layerscape.c | 382 ++- drivers/pci/controller/dwc/pcie-designware.h | 1 + 2 files changed, 381 insertions(+), 2 deletions(-) diff --git a/drivers/pci/controller/dwc/pci-layerscape.c b/drivers/pci/controller/dwc/pci-layerscape.c index 71911ca4c589..868e18b12e4a 100644 --- a/drivers/pci/controller/dwc/pci-layerscape.c +++ b/drivers/pci/controller/dwc/pci-layerscape.c @@ -3,13 +3,16 @@ * PCIe host controller driver for Freescale Layerscape SoCs * * Copyright (C) 2014 Freescale Semiconductor. + * Copyright 2020 NXP * * Author: Minghuan Lian */ +#include #include #include #include +#include #include #include #include @@ -27,17 +30,60 @@ #define PCIE_ABSERR0x8d0 /* Bridge Slave Error Response Register */ #define PCIE_ABSERR_SETTING0x9401 /* Forward error of non-posted request */ +/* PF Message Command Register */ +#define LS_PCIE_PF_MCR 0x2c +#define PF_MCR_PTOMR BIT(0) +#define PF_MCR_EXL2S BIT(1) + +/* LS1021A PEXn PM Write Control Register */ +#define SCFG_PEXPMWRCR(idx)(0x5c + (idx) * 0x64) +#define PMXMTTURNOFF BIT(31) +#define SCFG_PEXSFTRSTCR 0x190 +#define PEXSR(idx) BIT(idx) + +/* LS1043A PEX PME control register */ +#define SCFG_PEXPMECR 0x144 +#define PEXPME(idx)BIT(31 - (idx) * 4) + +/* LS1043A PEX LUT debug register */ +#define LS_PCIE_LDBG 0x7fc +#define LDBG_SRBIT(30) +#define LDBG_WEBIT(31) + #define PCIE_IATU_NUM 6 +#define LS_PCIE_IS_L2(v) \ + (((v) & PORT_LOGIC_LTSSM_STATE_MASK) == PORT_LOGIC_LTSSM_STATE_L2) + +struct ls_pcie; + +struct ls_pcie_host_pm_ops { + int (*pm_init)(struct ls_pcie *pcie); + void (*send_turn_off_message)(struct ls_pcie *pcie); + void (*exit_from_l2)(struct ls_pcie *pcie); +}; + struct ls_pcie_drvdata { + const u32 pf_off; + const u32 lut_off; const struct dw_pcie_host_ops *ops; + const struct ls_pcie_host_pm_ops *pm_ops; }; struct ls_pcie { struct dw_pcie *pci; const struct ls_pcie_drvdata *drvdata; + void __iomem *pf_base; + void __iomem *lut_base; + bool big_endian; + bool ep_presence; + bool pm_support; + struct regmap *scfg; + int index; }; +#define ls_pcie_lut_readl_addr(addr) ls_pcie_lut_readl(pcie, addr) +#define ls_pcie_pf_readl_addr(addr)ls_pcie_pf_readl(pcie, addr) #define to_ls_pcie(x) dev_get_drvdata((x)->dev) static bool ls_pcie_is_bridge(struct ls_pcie *pcie) @@ -78,6 +124,210 @@ static void ls_pcie_fix_error_response(struct ls_pcie *pcie) iowrite32(PCIE_ABSERR_SETTING, pci->dbi_base + PCIE_ABSERR); } +static u32 ls_pcie_lut_readl(struct ls_pcie *pcie, u32 off) +{ + if (pcie->big_endian) + return ioread32be(pcie->lut_base + off); + + return ioread32(pcie->lut_base + off); +} + +static void ls_pcie_lut_writel(struct ls_pcie *pcie, u32 off, u32 val) +{ + if (pcie->big_endian) + return iowrite32be(val, pcie->lut_base + off); + + return iowrite32(val, pcie->lut_base + off); + +} + +static u32 ls_pcie_pf_readl(struct ls_pcie *pcie, u32 off) +{ + if (pcie->big_endian) + return ioread32be(pcie->pf_base + off); + + return ioread32(pcie->pf_base + off); +} + +static void ls_pcie_pf_writel(struct ls_pcie *pcie, u32 off, u32 val) +{ + if (pcie->big_endian) + return iowrite32be(val, pcie->pf_base + off); + + return iowrite32(val, pcie->pf_base + off); + +} + +static void ls_pcie_send_turnoff_msg(struct ls_pcie *pcie) +{ + u32 val; + int ret; + + val = ls_pcie_pf_readl(pcie, LS_PCIE_PF_MCR); + val |= PF_MCR_PTOMR; + ls_pcie_pf_writel(pcie, LS_PCIE_PF_MCR, val); + + ret = readx_poll_timeout(ls_pcie_pf_readl_addr, LS_PCIE_PF_MCR, +val, !(val & PF_MCR_PTOMR), 100, 1); + if (ret) + dev_info(pcie->pci->dev, "poll turn off message timeout\n"); +} + +static void ls1021a_pcie_send_turnoff_msg(struct ls_pcie *pcie) +{ + u32 val; + + if (!pcie->scfg) { + dev_dbg(pcie->pci->dev, "SYSCFG is NULL\n"); + return; + } + + /* Send Turn_off message */ + regmap_read(pcie->scfg, SCFG_PEXPMWRCR(pcie->index), ); + val |= PMXMTTURNOFF; + regmap_write(pcie->scfg, SCFG_PEXPMWRCR(pcie->index), val); + + mdelay(10); + + /* Clear Turn_off message */ + regmap_read(pcie->scfg, SCFG_PEXPMWRCR(pcie->index), ); + val &= ~PMXMTTURNOFF; + regmap_write(pcie->scfg,
[PATCHv5 5/6] arm64: dts: ls1043a: Add SCFG phandle for PCIe nodes
From: Hou Zhiqiang The LS1043A PCIe controller has some control registers in SCFG block, so add the SCFG phandle for each PCIe controller DT node. Signed-off-by: Hou Zhiqiang --- V5: - No change arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi index 46826752a691..704e9e249729 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi @@ -875,6 +875,7 @@ interrupts = <0 118 0x4>, /* controller interrupt */ <0 117 0x4>; /* PME interrupt */ interrupt-names = "intr", "pme"; + fsl,pcie-scfg = < 0>; #address-cells = <3>; #size-cells = <2>; device_type = "pci"; @@ -902,6 +903,7 @@ interrupts = <0 128 0x4>, <0 127 0x4>; interrupt-names = "intr", "pme"; + fsl,pcie-scfg = < 1>; #address-cells = <3>; #size-cells = <2>; device_type = "pci"; @@ -929,6 +931,7 @@ interrupts = <0 162 0x4>, <0 161 0x4>; interrupt-names = "intr", "pme"; + fsl,pcie-scfg = < 2>; #address-cells = <3>; #size-cells = <2>; device_type = "pci"; -- 2.17.1
[PATCHv5 4/6] dt-bindings: pci: layerscape-pci: Update the description of SCFG property
From: Hou Zhiqiang Update the description of the second entry of 'fsl,pcie-scfg' property, as the LS1043A PCIe controller also has some control registers in SCFG block, while it has 3 controllers. Signed-off-by: Hou Zhiqiang Acked-by: Rob Herring --- V5: - No change Documentation/devicetree/bindings/pci/layerscape-pci.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/pci/layerscape-pci.txt b/Documentation/devicetree/bindings/pci/layerscape-pci.txt index d633c1fabdb4..8231f6729385 100644 --- a/Documentation/devicetree/bindings/pci/layerscape-pci.txt +++ b/Documentation/devicetree/bindings/pci/layerscape-pci.txt @@ -34,7 +34,7 @@ Required properties: "intr": The interrupt that is asserted for controller interrupts - fsl,pcie-scfg: Must include two entries. The first entry must be a link to the SCFG device node - The second entry must be '0' or '1' based on physical PCIe controller index. + The second entry is the physical PCIe controller index starting from '0'. This is used to get SCFG PEXN registers - dma-coherent: Indicates that the hardware IP block can ensure the coherency of the data transferred from/to the IP block. This can avoid the software -- 2.17.1
[PATCHv5 3/6] arm64: dts: layerscape: Add big-endian property for PCIe nodes
From: Hou Zhiqiang Add the big-endian property for LS1012A, LS1043A and LS1046A PCIe devicetree nodes. Signed-off-by: Hou Zhiqiang --- V5: - No change arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi | 1 + arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi | 3 +++ arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi | 3 +++ 3 files changed, 7 insertions(+) diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi index 9058cfa4980f..ac23e938fd1d 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi @@ -542,6 +542,7 @@ < 0 0 2 0 111 IRQ_TYPE_LEVEL_HIGH>, < 0 0 3 0 112 IRQ_TYPE_LEVEL_HIGH>, < 0 0 4 0 113 IRQ_TYPE_LEVEL_HIGH>; + big-endian; status = "disabled"; }; diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi index 28c51e521cb2..46826752a691 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi @@ -890,6 +890,7 @@ < 0 0 2 0 111 0x4>, < 0 0 3 0 112 0x4>, < 0 0 4 0 113 0x4>; + big-endian; status = "disabled"; }; @@ -916,6 +917,7 @@ < 0 0 2 0 121 0x4>, < 0 0 3 0 122 0x4>, < 0 0 4 0 123 0x4>; + big-endian; status = "disabled"; }; @@ -942,6 +944,7 @@ < 0 0 2 0 155 0x4>, < 0 0 3 0 156 0x4>, < 0 0 4 0 157 0x4>; + big-endian; status = "disabled"; }; diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi index 39458305e333..f21ee7825d40 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi @@ -794,6 +794,7 @@ < 0 0 2 GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>, < 0 0 3 GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>, < 0 0 4 GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>; + big-endian; status = "disabled"; }; @@ -830,6 +831,7 @@ < 0 0 2 GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>, < 0 0 3 GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>, < 0 0 4 GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>; + big-endian; status = "disabled"; }; @@ -866,6 +868,7 @@ < 0 0 2 GIC_SPI 154 IRQ_TYPE_LEVEL_HIGH>, < 0 0 3 GIC_SPI 154 IRQ_TYPE_LEVEL_HIGH>, < 0 0 4 GIC_SPI 154 IRQ_TYPE_LEVEL_HIGH>; + big-endian; status = "disabled"; }; -- 2.17.1
[PATCHv5 2/6] dt-bindings: pci: layerscape-pci: Add a optional property big-endian
From: Hou Zhiqiang This property is to indicate the endianness when accessing the PEX_LUT and PF register block, so if these registers are implemented in big-endian, specify this property. Signed-off-by: Hou Zhiqiang Acked-by: Rob Herring --- V5: - No change Documentation/devicetree/bindings/pci/layerscape-pci.txt | 4 1 file changed, 4 insertions(+) diff --git a/Documentation/devicetree/bindings/pci/layerscape-pci.txt b/Documentation/devicetree/bindings/pci/layerscape-pci.txt index 6d898dd4a8e2..d633c1fabdb4 100644 --- a/Documentation/devicetree/bindings/pci/layerscape-pci.txt +++ b/Documentation/devicetree/bindings/pci/layerscape-pci.txt @@ -40,6 +40,10 @@ Required properties: of the data transferred from/to the IP block. This can avoid the software cache flush/invalid actions, and improve the performance significantly. +Optional properties: +- big-endian: If the PEX_LUT and PF register block is in big-endian, specify + this property. + Example: pcie@340 { -- 2.17.1
[PATCHv5 1/6] PCI: layerscape: Change to use the DWC common link-up check function
From: Hou Zhiqiang The current Layerscape PCIe driver directly uses the physical layer LTSSM code to check the link-up state, which treats the > L0 states as link-up. This is not correct, since there is not explicit map between link-up state and LTSSM. So this patch changes to use the DWC common link-up check function. Signed-off-by: Hou Zhiqiang Reviewed-by: Rob Herring --- V5: - No change drivers/pci/controller/dwc/pci-layerscape.c | 140 ++-- 1 file changed, 10 insertions(+), 130 deletions(-) diff --git a/drivers/pci/controller/dwc/pci-layerscape.c b/drivers/pci/controller/dwc/pci-layerscape.c index 5b9c625df7b8..71911ca4c589 100644 --- a/drivers/pci/controller/dwc/pci-layerscape.c +++ b/drivers/pci/controller/dwc/pci-layerscape.c @@ -22,12 +22,6 @@ #include "pcie-designware.h" -/* PEX1/2 Misc Ports Status Register */ -#define SCFG_PEXMSCPORTSR(pex_idx) (0x94 + (pex_idx) * 4) -#define LTSSM_STATE_SHIFT 20 -#define LTSSM_STATE_MASK 0x3f -#define LTSSM_PCIE_L0 0x11 /* L0 state */ - /* PEX Internal Configuration Registers */ #define PCIE_STRFMR1 0x71c /* Symbol Timer & Filter Mask Register1 */ #define PCIE_ABSERR0x8d0 /* Bridge Slave Error Response Register */ @@ -36,19 +30,12 @@ #define PCIE_IATU_NUM 6 struct ls_pcie_drvdata { - u32 lut_offset; - u32 ltssm_shift; - u32 lut_dbg; const struct dw_pcie_host_ops *ops; - const struct dw_pcie_ops *dw_pcie_ops; }; struct ls_pcie { struct dw_pcie *pci; - void __iomem *lut; - struct regmap *scfg; const struct ls_pcie_drvdata *drvdata; - int index; }; #define to_ls_pcie(x) dev_get_drvdata((x)->dev) @@ -83,38 +70,6 @@ static void ls_pcie_drop_msg_tlp(struct ls_pcie *pcie) iowrite32(val, pci->dbi_base + PCIE_STRFMR1); } -static int ls1021_pcie_link_up(struct dw_pcie *pci) -{ - u32 state; - struct ls_pcie *pcie = to_ls_pcie(pci); - - if (!pcie->scfg) - return 0; - - regmap_read(pcie->scfg, SCFG_PEXMSCPORTSR(pcie->index), ); - state = (state >> LTSSM_STATE_SHIFT) & LTSSM_STATE_MASK; - - if (state < LTSSM_PCIE_L0) - return 0; - - return 1; -} - -static int ls_pcie_link_up(struct dw_pcie *pci) -{ - struct ls_pcie *pcie = to_ls_pcie(pci); - u32 state; - - state = (ioread32(pcie->lut + pcie->drvdata->lut_dbg) >> -pcie->drvdata->ltssm_shift) & -LTSSM_STATE_MASK; - - if (state < LTSSM_PCIE_L0) - return 0; - - return 1; -} - /* Forward error response of outbound non-posted requests */ static void ls_pcie_fix_error_response(struct ls_pcie *pcie) { @@ -139,96 +94,24 @@ static int ls_pcie_host_init(struct pcie_port *pp) return 0; } -static int ls1021_pcie_host_init(struct pcie_port *pp) -{ - struct dw_pcie *pci = to_dw_pcie_from_pp(pp); - struct ls_pcie *pcie = to_ls_pcie(pci); - struct device *dev = pci->dev; - u32 index[2]; - int ret; - - pcie->scfg = syscon_regmap_lookup_by_phandle(dev->of_node, -"fsl,pcie-scfg"); - if (IS_ERR(pcie->scfg)) { - ret = PTR_ERR(pcie->scfg); - dev_err(dev, "No syscfg phandle specified\n"); - pcie->scfg = NULL; - return ret; - } - - if (of_property_read_u32_array(dev->of_node, - "fsl,pcie-scfg", index, 2)) { - pcie->scfg = NULL; - return -EINVAL; - } - pcie->index = index[1]; - - return ls_pcie_host_init(pp); -} - -static const struct dw_pcie_host_ops ls1021_pcie_host_ops = { - .host_init = ls1021_pcie_host_init, -}; - static const struct dw_pcie_host_ops ls_pcie_host_ops = { .host_init = ls_pcie_host_init, }; -static const struct dw_pcie_ops dw_ls1021_pcie_ops = { - .link_up = ls1021_pcie_link_up, -}; - -static const struct dw_pcie_ops dw_ls_pcie_ops = { - .link_up = ls_pcie_link_up, -}; - -static const struct ls_pcie_drvdata ls1021_drvdata = { - .ops = _pcie_host_ops, - .dw_pcie_ops = _ls1021_pcie_ops, -}; - -static const struct ls_pcie_drvdata ls1043_drvdata = { - .lut_offset = 0x1, - .ltssm_shift = 24, - .lut_dbg = 0x7fc, +static const struct ls_pcie_drvdata layerscape_drvdata = { .ops = _pcie_host_ops, - .dw_pcie_ops = _ls_pcie_ops, -}; - -static const struct ls_pcie_drvdata ls1046_drvdata = { - .lut_offset = 0x8, - .ltssm_shift = 24, - .lut_dbg = 0x407fc, - .ops = _pcie_host_ops, - .dw_pcie_ops = _ls_pcie_ops, -}; - -static const struct ls_pcie_drvdata ls2080_drvdata = { - .lut_offset = 0x8, - .ltssm_shift = 0, - .lut_dbg = 0x7fc, - .ops = _pcie_host_ops, - .dw_pcie_ops = _ls_pcie_ops, -}; - -static const struct
[PATCHv5 0/6] PCI: layerscape: Add power management support
From: Hou Zhiqiang This patch series is to add PCIe power management support for NXP Layerscape platforms. Hou Zhiqiang (6): PCI: layerscape: Change to use the DWC common link-up check function dt-bindings: pci: layerscape-pci: Add a optional property big-endian arm64: dts: layerscape: Add big-endian property for PCIe nodes dt-bindings: pci: layerscape-pci: Update the description of SCFG property arm64: dts: ls1043a: Add SCFG phandle for PCIe nodes PCI: layerscape: Add power management support .../bindings/pci/layerscape-pci.txt | 6 +- .../arm64/boot/dts/freescale/fsl-ls1012a.dtsi | 1 + .../arm64/boot/dts/freescale/fsl-ls1043a.dtsi | 6 + .../arm64/boot/dts/freescale/fsl-ls1046a.dtsi | 3 + drivers/pci/controller/dwc/pci-layerscape.c | 450 ++ drivers/pci/controller/dwc/pcie-designware.h | 1 + 6 files changed, 370 insertions(+), 97 deletions(-) -- 2.17.1
[PATCH] PCI: dwc: Change the inheritance between the abstracted structures
From: Hou Zhiqiang Currently the core struct dw_pcie includes both struct pcie_port and dw_pcie_ep and the RC and EP platform drivers directly includes the dw_pcie. So it results in a RC or EP platform driver has 2 indirect parents pcie_port and dw_pcie_ep, but it doesn't make sense let RC platform driver includes the dw_pcie_ep and so does the EP platform driver. This patch makes the struct pcie_port and dw_pcie_ep includes the core struct dw_pcie and the RC and EP platform drivers include struct pcie_port and dw_pcie_ep respectively. Signed-off-by: Hou Zhiqiang Cc: Kishon Vijay Abraham I Cc: Lorenzo Pieralisi Cc: Rob Herring Cc: Bjorn Helgaas Cc: Jingoo Han Cc: Richard Zhu Cc: Lucas Stach Cc: Murali Karicheri Cc: Minghuan Lian Cc: Mingkai Hu Cc: Roy Zang Cc: Yue Wang Cc: Jonathan Chocron Cc: Thomas Petazzoni Cc: Jesper Nilsson Cc: Gustavo Pimentel Cc: Xiaowei Song Cc: Binghui Wang Cc: Stanimir Varbanov Cc: Pratyush Anand Cc: Kunihiko Hayashi Cc: Jason Yan Cc: Thierry Reding --- drivers/pci/controller/dwc/pci-dra7xx.c | 74 +--- drivers/pci/controller/dwc/pci-exynos.c | 26 +-- drivers/pci/controller/dwc/pci-imx6.c | 46 +++-- drivers/pci/controller/dwc/pci-keystone.c | 79 +--- .../pci/controller/dwc/pci-layerscape-ep.c| 18 +- drivers/pci/controller/dwc/pci-layerscape.c | 51 +++--- drivers/pci/controller/dwc/pci-meson.c| 25 +-- drivers/pci/controller/dwc/pcie-al.c | 21 ++- drivers/pci/controller/dwc/pcie-armada8k.c| 17 +- drivers/pci/controller/dwc/pcie-artpec6.c | 74 +--- .../pci/controller/dwc/pcie-designware-host.c | 2 +- .../pci/controller/dwc/pcie-designware-plat.c | 38 ++-- drivers/pci/controller/dwc/pcie-designware.h | 72 drivers/pci/controller/dwc/pcie-histb.c | 27 +-- drivers/pci/controller/dwc/pcie-intel-gw.c| 42 +++-- drivers/pci/controller/dwc/pcie-kirin.c | 42 +++-- drivers/pci/controller/dwc/pcie-qcom.c| 40 ++--- drivers/pci/controller/dwc/pcie-spear13xx.c | 16 +- drivers/pci/controller/dwc/pcie-tegra194.c| 169 +++--- drivers/pci/controller/dwc/pcie-uniphier-ep.c | 14 +- drivers/pci/controller/dwc/pcie-uniphier.c| 17 +- 21 files changed, 557 insertions(+), 353 deletions(-) diff --git a/drivers/pci/controller/dwc/pci-dra7xx.c b/drivers/pci/controller/dwc/pci-dra7xx.c index 12726c63366f..0e914df6eaba 100644 --- a/drivers/pci/controller/dwc/pci-dra7xx.c +++ b/drivers/pci/controller/dwc/pci-dra7xx.c @@ -85,7 +85,8 @@ #define PCIE_B0_B1_TSYNCEN BIT(0) struct dra7xx_pcie { - struct dw_pcie *pci; + struct pcie_port*pp; + struct dw_pcie_ep *ep; void __iomem*base; /* DT ti_conf */ int phy_count; /* DT phy-names count */ struct phy **phy; @@ -290,11 +291,19 @@ static void dra7xx_pcie_msi_irq_handler(struct irq_desc *desc) static irqreturn_t dra7xx_pcie_irq_handler(int irq, void *arg) { struct dra7xx_pcie *dra7xx = arg; - struct dw_pcie *pci = dra7xx->pci; - struct device *dev = pci->dev; - struct dw_pcie_ep *ep = >ep; + struct dw_pcie_ep *ep; + struct dw_pcie *pci; + struct device *dev; u32 reg; + if (dra7xx->mode == DW_PCIE_RC_TYPE) { + pci = to_dw_pcie_from_pp(dra7xx->pp); + } else { + ep = dra7xx->ep; + pci = to_dw_pcie_from_ep(ep); + } + + dev = pci->dev; reg = dra7xx_pcie_readl(dra7xx, PCIECTRL_DRA7XX_CONF_IRQSTATUS_MAIN); if (reg & ERR_SYS) @@ -447,11 +456,10 @@ static int __init dra7xx_add_pcie_ep(struct dra7xx_pcie *dra7xx, struct platform_device *pdev) { int ret; - struct dw_pcie_ep *ep; + struct dw_pcie_ep *ep = dra7xx->ep; + struct dw_pcie *pci = to_dw_pcie_from_ep(ep); struct device *dev = >dev; - struct dw_pcie *pci = dra7xx->pci; - ep = >ep; ep->ops = _ep_ops; pci->dbi_base = devm_platform_ioremap_resource_byname(pdev, "ep_dbics"); @@ -476,8 +484,8 @@ static int __init dra7xx_add_pcie_port(struct dra7xx_pcie *dra7xx, struct platform_device *pdev) { int ret; - struct dw_pcie *pci = dra7xx->pci; - struct pcie_port *pp = >pp; + struct pcie_port *pp = dra7xx->pp; + struct dw_pcie *pci = to_dw_pcie_from_pp(pp); struct device *dev = pci->dev; pp->irq = platform_get_irq(pdev, 1); @@ -693,6 +701,8 @@ static int __init dra7xx_pcie_probe(struct platform_device *pdev) struct device_link **link; void __iomem *base; struct dw_pcie *pci; + struct pcie_port *pp; + struct dw_pcie_ep *ep; struct dra7xx_pcie *dra7xx; struct device *dev = >dev; struct device_node *np =
[PATCHv4 5/6] arm64: dts: ls1043a: Add SCFG phandle for PCIe nodes
From: Hou Zhiqiang The LS1043A PCIe controller has some control registers in SCFG block, so add the SCFG phandle for each PCIe controller DT node. Signed-off-by: Hou Zhiqiang --- V4: - Rebased against the latest code base arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi index 46826752a691..704e9e249729 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi @@ -875,6 +875,7 @@ interrupts = <0 118 0x4>, /* controller interrupt */ <0 117 0x4>; /* PME interrupt */ interrupt-names = "intr", "pme"; + fsl,pcie-scfg = < 0>; #address-cells = <3>; #size-cells = <2>; device_type = "pci"; @@ -902,6 +903,7 @@ interrupts = <0 128 0x4>, <0 127 0x4>; interrupt-names = "intr", "pme"; + fsl,pcie-scfg = < 1>; #address-cells = <3>; #size-cells = <2>; device_type = "pci"; @@ -929,6 +931,7 @@ interrupts = <0 162 0x4>, <0 161 0x4>; interrupt-names = "intr", "pme"; + fsl,pcie-scfg = < 2>; #address-cells = <3>; #size-cells = <2>; device_type = "pci"; -- 2.17.1
[PATCHv4 6/6] PCI: layerscape: Add power management support
From: Hou Zhiqiang Add PME_Turn_Off/PME_TO_Ack handshake sequence, and finally put the PCIe controller into D3 state after the L2/L3 ready state transition process completion. Signed-off-by: Hou Zhiqiang --- V4: - Rebased against the latest code base drivers/pci/controller/dwc/pci-layerscape.c | 382 ++- drivers/pci/controller/dwc/pcie-designware.h | 1 + 2 files changed, 381 insertions(+), 2 deletions(-) diff --git a/drivers/pci/controller/dwc/pci-layerscape.c b/drivers/pci/controller/dwc/pci-layerscape.c index 71911ca4c589..868e18b12e4a 100644 --- a/drivers/pci/controller/dwc/pci-layerscape.c +++ b/drivers/pci/controller/dwc/pci-layerscape.c @@ -3,13 +3,16 @@ * PCIe host controller driver for Freescale Layerscape SoCs * * Copyright (C) 2014 Freescale Semiconductor. + * Copyright 2020 NXP * * Author: Minghuan Lian */ +#include #include #include #include +#include #include #include #include @@ -27,17 +30,60 @@ #define PCIE_ABSERR0x8d0 /* Bridge Slave Error Response Register */ #define PCIE_ABSERR_SETTING0x9401 /* Forward error of non-posted request */ +/* PF Message Command Register */ +#define LS_PCIE_PF_MCR 0x2c +#define PF_MCR_PTOMR BIT(0) +#define PF_MCR_EXL2S BIT(1) + +/* LS1021A PEXn PM Write Control Register */ +#define SCFG_PEXPMWRCR(idx)(0x5c + (idx) * 0x64) +#define PMXMTTURNOFF BIT(31) +#define SCFG_PEXSFTRSTCR 0x190 +#define PEXSR(idx) BIT(idx) + +/* LS1043A PEX PME control register */ +#define SCFG_PEXPMECR 0x144 +#define PEXPME(idx)BIT(31 - (idx) * 4) + +/* LS1043A PEX LUT debug register */ +#define LS_PCIE_LDBG 0x7fc +#define LDBG_SRBIT(30) +#define LDBG_WEBIT(31) + #define PCIE_IATU_NUM 6 +#define LS_PCIE_IS_L2(v) \ + (((v) & PORT_LOGIC_LTSSM_STATE_MASK) == PORT_LOGIC_LTSSM_STATE_L2) + +struct ls_pcie; + +struct ls_pcie_host_pm_ops { + int (*pm_init)(struct ls_pcie *pcie); + void (*send_turn_off_message)(struct ls_pcie *pcie); + void (*exit_from_l2)(struct ls_pcie *pcie); +}; + struct ls_pcie_drvdata { + const u32 pf_off; + const u32 lut_off; const struct dw_pcie_host_ops *ops; + const struct ls_pcie_host_pm_ops *pm_ops; }; struct ls_pcie { struct dw_pcie *pci; const struct ls_pcie_drvdata *drvdata; + void __iomem *pf_base; + void __iomem *lut_base; + bool big_endian; + bool ep_presence; + bool pm_support; + struct regmap *scfg; + int index; }; +#define ls_pcie_lut_readl_addr(addr) ls_pcie_lut_readl(pcie, addr) +#define ls_pcie_pf_readl_addr(addr)ls_pcie_pf_readl(pcie, addr) #define to_ls_pcie(x) dev_get_drvdata((x)->dev) static bool ls_pcie_is_bridge(struct ls_pcie *pcie) @@ -78,6 +124,210 @@ static void ls_pcie_fix_error_response(struct ls_pcie *pcie) iowrite32(PCIE_ABSERR_SETTING, pci->dbi_base + PCIE_ABSERR); } +static u32 ls_pcie_lut_readl(struct ls_pcie *pcie, u32 off) +{ + if (pcie->big_endian) + return ioread32be(pcie->lut_base + off); + + return ioread32(pcie->lut_base + off); +} + +static void ls_pcie_lut_writel(struct ls_pcie *pcie, u32 off, u32 val) +{ + if (pcie->big_endian) + return iowrite32be(val, pcie->lut_base + off); + + return iowrite32(val, pcie->lut_base + off); + +} + +static u32 ls_pcie_pf_readl(struct ls_pcie *pcie, u32 off) +{ + if (pcie->big_endian) + return ioread32be(pcie->pf_base + off); + + return ioread32(pcie->pf_base + off); +} + +static void ls_pcie_pf_writel(struct ls_pcie *pcie, u32 off, u32 val) +{ + if (pcie->big_endian) + return iowrite32be(val, pcie->pf_base + off); + + return iowrite32(val, pcie->pf_base + off); + +} + +static void ls_pcie_send_turnoff_msg(struct ls_pcie *pcie) +{ + u32 val; + int ret; + + val = ls_pcie_pf_readl(pcie, LS_PCIE_PF_MCR); + val |= PF_MCR_PTOMR; + ls_pcie_pf_writel(pcie, LS_PCIE_PF_MCR, val); + + ret = readx_poll_timeout(ls_pcie_pf_readl_addr, LS_PCIE_PF_MCR, +val, !(val & PF_MCR_PTOMR), 100, 1); + if (ret) + dev_info(pcie->pci->dev, "poll turn off message timeout\n"); +} + +static void ls1021a_pcie_send_turnoff_msg(struct ls_pcie *pcie) +{ + u32 val; + + if (!pcie->scfg) { + dev_dbg(pcie->pci->dev, "SYSCFG is NULL\n"); + return; + } + + /* Send Turn_off message */ + regmap_read(pcie->scfg, SCFG_PEXPMWRCR(pcie->index), ); + val |= PMXMTTURNOFF; + regmap_write(pcie->scfg, SCFG_PEXPMWRCR(pcie->index), val); + + mdelay(10); + + /* Clear Turn_off message */ + regmap_read(pcie->scfg, SCFG_PEXPMWRCR(pcie->index), ); + val &= ~PMXMTTURNOFF; + regmap_write(pcie->scfg,
[PATCHv4 4/6] dt-bindings: pci: layerscape-pci: Update the description of SCFG property
From: Hou Zhiqiang Update the description of the second entry of 'fsl,pcie-scfg' property, as the LS1043A PCIe controller also has some control registers in SCFG block, while it has 3 controllers. Signed-off-by: Hou Zhiqiang Acked-by: Rob Herring --- V4: - Rebased against the latest code base Documentation/devicetree/bindings/pci/layerscape-pci.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/pci/layerscape-pci.txt b/Documentation/devicetree/bindings/pci/layerscape-pci.txt index d633c1fabdb4..8231f6729385 100644 --- a/Documentation/devicetree/bindings/pci/layerscape-pci.txt +++ b/Documentation/devicetree/bindings/pci/layerscape-pci.txt @@ -34,7 +34,7 @@ Required properties: "intr": The interrupt that is asserted for controller interrupts - fsl,pcie-scfg: Must include two entries. The first entry must be a link to the SCFG device node - The second entry must be '0' or '1' based on physical PCIe controller index. + The second entry is the physical PCIe controller index starting from '0'. This is used to get SCFG PEXN registers - dma-coherent: Indicates that the hardware IP block can ensure the coherency of the data transferred from/to the IP block. This can avoid the software -- 2.17.1
[PATCHv4 3/6] arm64: dts: layerscape: Add big-endian property for PCIe nodes
From: Hou Zhiqiang Add the big-endian property for LS1012A, LS1043A and LS1046A PCIe devicetree nodes. Signed-off-by: Hou Zhiqiang --- V4: - Rebased against the latest code base arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi | 1 + arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi | 3 +++ arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi | 3 +++ 3 files changed, 7 insertions(+) diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi index 9058cfa4980f..ac23e938fd1d 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi @@ -542,6 +542,7 @@ < 0 0 2 0 111 IRQ_TYPE_LEVEL_HIGH>, < 0 0 3 0 112 IRQ_TYPE_LEVEL_HIGH>, < 0 0 4 0 113 IRQ_TYPE_LEVEL_HIGH>; + big-endian; status = "disabled"; }; diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi index 28c51e521cb2..46826752a691 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi @@ -890,6 +890,7 @@ < 0 0 2 0 111 0x4>, < 0 0 3 0 112 0x4>, < 0 0 4 0 113 0x4>; + big-endian; status = "disabled"; }; @@ -916,6 +917,7 @@ < 0 0 2 0 121 0x4>, < 0 0 3 0 122 0x4>, < 0 0 4 0 123 0x4>; + big-endian; status = "disabled"; }; @@ -942,6 +944,7 @@ < 0 0 2 0 155 0x4>, < 0 0 3 0 156 0x4>, < 0 0 4 0 157 0x4>; + big-endian; status = "disabled"; }; diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi index 39458305e333..f21ee7825d40 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi @@ -794,6 +794,7 @@ < 0 0 2 GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>, < 0 0 3 GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>, < 0 0 4 GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>; + big-endian; status = "disabled"; }; @@ -830,6 +831,7 @@ < 0 0 2 GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>, < 0 0 3 GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>, < 0 0 4 GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>; + big-endian; status = "disabled"; }; @@ -866,6 +868,7 @@ < 0 0 2 GIC_SPI 154 IRQ_TYPE_LEVEL_HIGH>, < 0 0 3 GIC_SPI 154 IRQ_TYPE_LEVEL_HIGH>, < 0 0 4 GIC_SPI 154 IRQ_TYPE_LEVEL_HIGH>; + big-endian; status = "disabled"; }; -- 2.17.1
[PATCHv4 2/6] dt-bindings: pci: layerscape-pci: Add a optional property big-endian
From: Hou Zhiqiang This property is to indicate the endianness when accessing the PEX_LUT and PF register block, so if these registers are implemented in big-endian, specify this property. Signed-off-by: Hou Zhiqiang Acked-by: Rob Herring --- V4: - Rebased against the latest code base Documentation/devicetree/bindings/pci/layerscape-pci.txt | 4 1 file changed, 4 insertions(+) diff --git a/Documentation/devicetree/bindings/pci/layerscape-pci.txt b/Documentation/devicetree/bindings/pci/layerscape-pci.txt index 6d898dd4a8e2..d633c1fabdb4 100644 --- a/Documentation/devicetree/bindings/pci/layerscape-pci.txt +++ b/Documentation/devicetree/bindings/pci/layerscape-pci.txt @@ -40,6 +40,10 @@ Required properties: of the data transferred from/to the IP block. This can avoid the software cache flush/invalid actions, and improve the performance significantly. +Optional properties: +- big-endian: If the PEX_LUT and PF register block is in big-endian, specify + this property. + Example: pcie@340 { -- 2.17.1
[PATCHv4 1/6] PCI: layerscape: Change to use the DWC common link-up check function
From: Hou Zhiqiang The current Layerscape PCIe driver directly uses the physical layer LTSSM code to check the link-up state, which treats the > L0 states as link-up. This is not correct, since there is not explicit map between link-up state and LTSSM. So this patch changes to use the DWC common link-up check function. Signed-off-by: Hou Zhiqiang Reviewed-by: Rob Herring --- V4: - Rebased against the latest code base drivers/pci/controller/dwc/pci-layerscape.c | 140 ++-- 1 file changed, 10 insertions(+), 130 deletions(-) diff --git a/drivers/pci/controller/dwc/pci-layerscape.c b/drivers/pci/controller/dwc/pci-layerscape.c index 5b9c625df7b8..71911ca4c589 100644 --- a/drivers/pci/controller/dwc/pci-layerscape.c +++ b/drivers/pci/controller/dwc/pci-layerscape.c @@ -22,12 +22,6 @@ #include "pcie-designware.h" -/* PEX1/2 Misc Ports Status Register */ -#define SCFG_PEXMSCPORTSR(pex_idx) (0x94 + (pex_idx) * 4) -#define LTSSM_STATE_SHIFT 20 -#define LTSSM_STATE_MASK 0x3f -#define LTSSM_PCIE_L0 0x11 /* L0 state */ - /* PEX Internal Configuration Registers */ #define PCIE_STRFMR1 0x71c /* Symbol Timer & Filter Mask Register1 */ #define PCIE_ABSERR0x8d0 /* Bridge Slave Error Response Register */ @@ -36,19 +30,12 @@ #define PCIE_IATU_NUM 6 struct ls_pcie_drvdata { - u32 lut_offset; - u32 ltssm_shift; - u32 lut_dbg; const struct dw_pcie_host_ops *ops; - const struct dw_pcie_ops *dw_pcie_ops; }; struct ls_pcie { struct dw_pcie *pci; - void __iomem *lut; - struct regmap *scfg; const struct ls_pcie_drvdata *drvdata; - int index; }; #define to_ls_pcie(x) dev_get_drvdata((x)->dev) @@ -83,38 +70,6 @@ static void ls_pcie_drop_msg_tlp(struct ls_pcie *pcie) iowrite32(val, pci->dbi_base + PCIE_STRFMR1); } -static int ls1021_pcie_link_up(struct dw_pcie *pci) -{ - u32 state; - struct ls_pcie *pcie = to_ls_pcie(pci); - - if (!pcie->scfg) - return 0; - - regmap_read(pcie->scfg, SCFG_PEXMSCPORTSR(pcie->index), ); - state = (state >> LTSSM_STATE_SHIFT) & LTSSM_STATE_MASK; - - if (state < LTSSM_PCIE_L0) - return 0; - - return 1; -} - -static int ls_pcie_link_up(struct dw_pcie *pci) -{ - struct ls_pcie *pcie = to_ls_pcie(pci); - u32 state; - - state = (ioread32(pcie->lut + pcie->drvdata->lut_dbg) >> -pcie->drvdata->ltssm_shift) & -LTSSM_STATE_MASK; - - if (state < LTSSM_PCIE_L0) - return 0; - - return 1; -} - /* Forward error response of outbound non-posted requests */ static void ls_pcie_fix_error_response(struct ls_pcie *pcie) { @@ -139,96 +94,24 @@ static int ls_pcie_host_init(struct pcie_port *pp) return 0; } -static int ls1021_pcie_host_init(struct pcie_port *pp) -{ - struct dw_pcie *pci = to_dw_pcie_from_pp(pp); - struct ls_pcie *pcie = to_ls_pcie(pci); - struct device *dev = pci->dev; - u32 index[2]; - int ret; - - pcie->scfg = syscon_regmap_lookup_by_phandle(dev->of_node, -"fsl,pcie-scfg"); - if (IS_ERR(pcie->scfg)) { - ret = PTR_ERR(pcie->scfg); - dev_err(dev, "No syscfg phandle specified\n"); - pcie->scfg = NULL; - return ret; - } - - if (of_property_read_u32_array(dev->of_node, - "fsl,pcie-scfg", index, 2)) { - pcie->scfg = NULL; - return -EINVAL; - } - pcie->index = index[1]; - - return ls_pcie_host_init(pp); -} - -static const struct dw_pcie_host_ops ls1021_pcie_host_ops = { - .host_init = ls1021_pcie_host_init, -}; - static const struct dw_pcie_host_ops ls_pcie_host_ops = { .host_init = ls_pcie_host_init, }; -static const struct dw_pcie_ops dw_ls1021_pcie_ops = { - .link_up = ls1021_pcie_link_up, -}; - -static const struct dw_pcie_ops dw_ls_pcie_ops = { - .link_up = ls_pcie_link_up, -}; - -static const struct ls_pcie_drvdata ls1021_drvdata = { - .ops = _pcie_host_ops, - .dw_pcie_ops = _ls1021_pcie_ops, -}; - -static const struct ls_pcie_drvdata ls1043_drvdata = { - .lut_offset = 0x1, - .ltssm_shift = 24, - .lut_dbg = 0x7fc, +static const struct ls_pcie_drvdata layerscape_drvdata = { .ops = _pcie_host_ops, - .dw_pcie_ops = _ls_pcie_ops, -}; - -static const struct ls_pcie_drvdata ls1046_drvdata = { - .lut_offset = 0x8, - .ltssm_shift = 24, - .lut_dbg = 0x407fc, - .ops = _pcie_host_ops, - .dw_pcie_ops = _ls_pcie_ops, -}; - -static const struct ls_pcie_drvdata ls2080_drvdata = { - .lut_offset = 0x8, - .ltssm_shift = 0, - .lut_dbg = 0x7fc, - .ops = _pcie_host_ops, - .dw_pcie_ops = _ls_pcie_ops, -}; - -static
[PATCHv4 0/6] PCI: layerscape: Add power management support
From: Hou Zhiqiang This patch series is to add PCIe power management support for NXP Layerscape platforms. Hou Zhiqiang (6): PCI: layerscape: Change to use the DWC common link-up check function dt-bindings: pci: layerscape-pci: Add a optional property big-endian arm64: dts: layerscape: Add big-endian property for PCIe nodes dt-bindings: pci: layerscape-pci: Update the description of SCFG property arm64: dts: ls1043a: Add SCFG phandle for PCIe nodes PCI: layerscape: Add power management support .../bindings/pci/layerscape-pci.txt | 6 +- .../arm64/boot/dts/freescale/fsl-ls1012a.dtsi | 1 + .../arm64/boot/dts/freescale/fsl-ls1043a.dtsi | 6 + .../arm64/boot/dts/freescale/fsl-ls1046a.dtsi | 3 + drivers/pci/controller/dwc/pci-layerscape.c | 450 ++ drivers/pci/controller/dwc/pcie-designware.h | 1 + 6 files changed, 370 insertions(+), 97 deletions(-) -- 2.17.1
[PATCH] PCI: dwc: Move forward the iATU detection process
From: Hou Zhiqiang In the dw_pcie_ep_init(), it depends on the detected iATU region numbers to allocate the in/outbound window management bit map. It fails after the commit 281f1f99cf3a ("PCI: dwc: Detect number of iATU windows"). So this patch move the iATU region detection into a new function, move forward the detection to the very beginning of functions dw_pcie_host_init() and dw_pcie_ep_init(). And also remove it from the dw_pcie_setup(), since it's more like a software perspective initialization step than hardware setup. Fixes: 281f1f99cf3a ("PCI: dwc: Detect number of iATU windows") Signed-off-by: Hou Zhiqiang --- drivers/pci/controller/dwc/pcie-designware-ep.c | 2 ++ drivers/pci/controller/dwc/pcie-designware-host.c | 2 ++ drivers/pci/controller/dwc/pcie-designware.c | 11 --- drivers/pci/controller/dwc/pcie-designware.h | 1 + 4 files changed, 13 insertions(+), 3 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c index bcd1cd9ba8c8..fcf935bf6f5e 100644 --- a/drivers/pci/controller/dwc/pcie-designware-ep.c +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c @@ -707,6 +707,8 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep) } } + dw_pcie_iatu_detect(pci); + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "addr_space"); if (!res) return -EINVAL; diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c index 8a84c005f32b..8eae817c138d 100644 --- a/drivers/pci/controller/dwc/pcie-designware-host.c +++ b/drivers/pci/controller/dwc/pcie-designware-host.c @@ -316,6 +316,8 @@ int dw_pcie_host_init(struct pcie_port *pp) return PTR_ERR(pci->dbi_base); } + dw_pcie_iatu_detect(pci); + bridge = devm_pci_alloc_host_bridge(dev, 0); if (!bridge) return -ENOMEM; diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c index 5b72a5448d2e..5b9bf02d918b 100644 --- a/drivers/pci/controller/dwc/pcie-designware.c +++ b/drivers/pci/controller/dwc/pcie-designware.c @@ -654,11 +654,9 @@ static void dw_pcie_iatu_detect_regions(struct dw_pcie *pci) pci->num_ob_windows = ob; } -void dw_pcie_setup(struct dw_pcie *pci) +void dw_pcie_iatu_detect(struct dw_pcie *pci) { - u32 val; struct device *dev = pci->dev; - struct device_node *np = dev->of_node; struct platform_device *pdev = to_platform_device(dev); if (pci->version >= 0x480A || (!pci->version && @@ -687,6 +685,13 @@ void dw_pcie_setup(struct dw_pcie *pci) dev_info(pci->dev, "Detected iATU regions: %u outbound, %u inbound", pci->num_ob_windows, pci->num_ib_windows); +} + +void dw_pcie_setup(struct dw_pcie *pci) +{ + u32 val; + struct device *dev = pci->dev; + struct device_node *np = dev->of_node; if (pci->link_gen > 0) dw_pcie_link_set_max_speed(pci, pci->link_gen); diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index 5d979953800d..867369d4c4f7 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -305,6 +305,7 @@ int dw_pcie_prog_inbound_atu(struct dw_pcie *pci, u8 func_no, int index, void dw_pcie_disable_atu(struct dw_pcie *pci, int index, enum dw_pcie_region_type type); void dw_pcie_setup(struct dw_pcie *pci); +void dw_pcie_iatu_detect(struct dw_pcie *pci); static inline void dw_pcie_writel_dbi(struct dw_pcie *pci, u32 reg, u32 val) { -- 2.17.1
[PATCHv3 2/7] PCI: layerscape: Change to use the DWC common link-up check function
From: Hou Zhiqiang The current Layerscape PCIe driver directly uses the physical layer LTSSM code to check the link-up state, which treats the > L0 states as link-up. This is not correct, since there is not explicit map between link-up state and LTSSM. So this patch changes to use the DWC common link-up check function. Signed-off-by: Hou Zhiqiang Reviewed-by: Rob Herring --- V3: - Rebased against the latest code base drivers/pci/controller/dwc/pci-layerscape.c | 140 ++-- 1 file changed, 10 insertions(+), 130 deletions(-) diff --git a/drivers/pci/controller/dwc/pci-layerscape.c b/drivers/pci/controller/dwc/pci-layerscape.c index 44ad34cdc3bc..906fac676b6f 100644 --- a/drivers/pci/controller/dwc/pci-layerscape.c +++ b/drivers/pci/controller/dwc/pci-layerscape.c @@ -22,12 +22,6 @@ #include "pcie-designware.h" -/* PEX1/2 Misc Ports Status Register */ -#define SCFG_PEXMSCPORTSR(pex_idx) (0x94 + (pex_idx) * 4) -#define LTSSM_STATE_SHIFT 20 -#define LTSSM_STATE_MASK 0x3f -#define LTSSM_PCIE_L0 0x11 /* L0 state */ - /* PEX Internal Configuration Registers */ #define PCIE_STRFMR1 0x71c /* Symbol Timer & Filter Mask Register1 */ #define PCIE_ABSERR0x8d0 /* Bridge Slave Error Response Register */ @@ -36,19 +30,12 @@ #define PCIE_IATU_NUM 6 struct ls_pcie_drvdata { - u32 lut_offset; - u32 ltssm_shift; - u32 lut_dbg; const struct dw_pcie_host_ops *ops; - const struct dw_pcie_ops *dw_pcie_ops; }; struct ls_pcie { struct dw_pcie *pci; - void __iomem *lut; - struct regmap *scfg; const struct ls_pcie_drvdata *drvdata; - int index; }; #define to_ls_pcie(x) dev_get_drvdata((x)->dev) @@ -83,38 +70,6 @@ static void ls_pcie_drop_msg_tlp(struct ls_pcie *pcie) iowrite32(val, pci->dbi_base + PCIE_STRFMR1); } -static int ls1021_pcie_link_up(struct dw_pcie *pci) -{ - u32 state; - struct ls_pcie *pcie = to_ls_pcie(pci); - - if (!pcie->scfg) - return 0; - - regmap_read(pcie->scfg, SCFG_PEXMSCPORTSR(pcie->index), ); - state = (state >> LTSSM_STATE_SHIFT) & LTSSM_STATE_MASK; - - if (state < LTSSM_PCIE_L0) - return 0; - - return 1; -} - -static int ls_pcie_link_up(struct dw_pcie *pci) -{ - struct ls_pcie *pcie = to_ls_pcie(pci); - u32 state; - - state = (ioread32(pcie->lut + pcie->drvdata->lut_dbg) >> -pcie->drvdata->ltssm_shift) & -LTSSM_STATE_MASK; - - if (state < LTSSM_PCIE_L0) - return 0; - - return 1; -} - /* Forward error response of outbound non-posted requests */ static void ls_pcie_fix_error_response(struct ls_pcie *pcie) { @@ -139,96 +94,24 @@ static int ls_pcie_host_init(struct pcie_port *pp) return 0; } -static int ls1021_pcie_host_init(struct pcie_port *pp) -{ - struct dw_pcie *pci = to_dw_pcie_from_pp(pp); - struct ls_pcie *pcie = to_ls_pcie(pci); - struct device *dev = pci->dev; - u32 index[2]; - int ret; - - pcie->scfg = syscon_regmap_lookup_by_phandle(dev->of_node, -"fsl,pcie-scfg"); - if (IS_ERR(pcie->scfg)) { - ret = PTR_ERR(pcie->scfg); - dev_err(dev, "No syscfg phandle specified\n"); - pcie->scfg = NULL; - return ret; - } - - if (of_property_read_u32_array(dev->of_node, - "fsl,pcie-scfg", index, 2)) { - pcie->scfg = NULL; - return -EINVAL; - } - pcie->index = index[1]; - - return ls_pcie_host_init(pp); -} - -static const struct dw_pcie_host_ops ls1021_pcie_host_ops = { - .host_init = ls1021_pcie_host_init, -}; - static const struct dw_pcie_host_ops ls_pcie_host_ops = { .host_init = ls_pcie_host_init, }; -static const struct dw_pcie_ops dw_ls1021_pcie_ops = { - .link_up = ls1021_pcie_link_up, -}; - -static const struct dw_pcie_ops dw_ls_pcie_ops = { - .link_up = ls_pcie_link_up, -}; - -static const struct ls_pcie_drvdata ls1021_drvdata = { - .ops = _pcie_host_ops, - .dw_pcie_ops = _ls1021_pcie_ops, -}; - -static const struct ls_pcie_drvdata ls1043_drvdata = { - .lut_offset = 0x1, - .ltssm_shift = 24, - .lut_dbg = 0x7fc, +static const struct ls_pcie_drvdata layerscape_drvdata = { .ops = _pcie_host_ops, - .dw_pcie_ops = _ls_pcie_ops, -}; - -static const struct ls_pcie_drvdata ls1046_drvdata = { - .lut_offset = 0x8, - .ltssm_shift = 24, - .lut_dbg = 0x407fc, - .ops = _pcie_host_ops, - .dw_pcie_ops = _ls_pcie_ops, -}; - -static const struct ls_pcie_drvdata ls2080_drvdata = { - .lut_offset = 0x8, - .ltssm_shift = 0, - .lut_dbg = 0x7fc, - .ops = _pcie_host_ops, - .dw_pcie_ops = _ls_pcie_ops, -}; - -static
[PATCHv3 4/7] arm64: dts: layerscape: Add big-endian property for PCIe nodes
From: Hou Zhiqiang Add the big-endian property for LS1012A, LS1043A and LS1046A PCIe devicetree nodes. Signed-off-by: Hou Zhiqiang --- V3: - Rebased against the latest code base arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi | 1 + arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi | 3 +++ arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi | 3 +++ 3 files changed, 7 insertions(+) diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi index 626b709d1fb9..3c1ecb9d843f 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi @@ -515,6 +515,7 @@ < 0 0 2 0 111 IRQ_TYPE_LEVEL_HIGH>, < 0 0 3 0 112 IRQ_TYPE_LEVEL_HIGH>, < 0 0 4 0 113 IRQ_TYPE_LEVEL_HIGH>; + big-endian; status = "disabled"; }; diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi index bbae4b353d3f..aca45bf348b4 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi @@ -841,6 +841,7 @@ < 0 0 2 0 111 0x4>, < 0 0 3 0 112 0x4>, < 0 0 4 0 113 0x4>; + big-endian; status = "disabled"; }; @@ -867,6 +868,7 @@ < 0 0 2 0 121 0x4>, < 0 0 3 0 122 0x4>, < 0 0 4 0 123 0x4>; + big-endian; status = "disabled"; }; @@ -893,6 +895,7 @@ < 0 0 2 0 155 0x4>, < 0 0 3 0 156 0x4>, < 0 0 4 0 157 0x4>; + big-endian; status = "disabled"; }; diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi index 025e1f587662..facf396ce08a 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi @@ -745,6 +745,7 @@ < 0 0 2 GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>, < 0 0 3 GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>, < 0 0 4 GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>; + big-endian; status = "disabled"; }; @@ -781,6 +782,7 @@ < 0 0 2 GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>, < 0 0 3 GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>, < 0 0 4 GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>; + big-endian; status = "disabled"; }; @@ -817,6 +819,7 @@ < 0 0 2 GIC_SPI 154 IRQ_TYPE_LEVEL_HIGH>, < 0 0 3 GIC_SPI 154 IRQ_TYPE_LEVEL_HIGH>, < 0 0 4 GIC_SPI 154 IRQ_TYPE_LEVEL_HIGH>; + big-endian; status = "disabled"; }; -- 2.17.1
[PATCHv3 7/7] PCI: layerscape: Add power management support
From: Hou Zhiqiang Add PME_Turn_Off/PME_TO_Ack handshake sequence, and finally put the PCIe controller into D3 state after the L2/L3 ready state transition process completion. Signed-off-by: Hou Zhiqiang --- V3: - Rebased against the latest code base drivers/pci/controller/dwc/pci-layerscape.c | 380 ++- drivers/pci/controller/dwc/pcie-designware.h | 1 + 2 files changed, 379 insertions(+), 2 deletions(-) diff --git a/drivers/pci/controller/dwc/pci-layerscape.c b/drivers/pci/controller/dwc/pci-layerscape.c index 906fac676b6f..a590194c0f95 100644 --- a/drivers/pci/controller/dwc/pci-layerscape.c +++ b/drivers/pci/controller/dwc/pci-layerscape.c @@ -3,13 +3,16 @@ * PCIe host controller driver for Freescale Layerscape SoCs * * Copyright (C) 2014 Freescale Semiconductor. + * Copyright 2020 NXP * * Author: Minghuan Lian */ +#include #include #include #include +#include #include #include #include @@ -27,17 +30,60 @@ #define PCIE_ABSERR0x8d0 /* Bridge Slave Error Response Register */ #define PCIE_ABSERR_SETTING0x9401 /* Forward error of non-posted request */ +/* PF Message Command Register */ +#define LS_PCIE_PF_MCR 0x2c +#define PF_MCR_PTOMR BIT(0) +#define PF_MCR_EXL2S BIT(1) + +/* LS1021A PEXn PM Write Control Register */ +#define SCFG_PEXPMWRCR(idx)(0x5c + (idx) * 0x64) +#define PMXMTTURNOFF BIT(31) +#define SCFG_PEXSFTRSTCR 0x190 +#define PEXSR(idx) BIT(idx) + +/* LS1043A PEX PME control register */ +#define SCFG_PEXPMECR 0x144 +#define PEXPME(idx)BIT(31 - (idx) * 4) + +/* LS1043A PEX LUT debug register */ +#define LS_PCIE_LDBG 0x7fc +#define LDBG_SRBIT(30) +#define LDBG_WEBIT(31) + #define PCIE_IATU_NUM 6 +#define LS_PCIE_IS_L2(v) \ + (((v) & PORT_LOGIC_LTSSM_STATE_MASK) == PORT_LOGIC_LTSSM_STATE_L2) + +struct ls_pcie; + +struct ls_pcie_host_pm_ops { + int (*pm_init)(struct ls_pcie *pcie); + void (*send_turn_off_message)(struct ls_pcie *pcie); + void (*exit_from_l2)(struct ls_pcie *pcie); +}; + struct ls_pcie_drvdata { + const u32 pf_off; + const u32 lut_off; const struct dw_pcie_host_ops *ops; + const struct ls_pcie_host_pm_ops *pm_ops; }; struct ls_pcie { struct dw_pcie *pci; const struct ls_pcie_drvdata *drvdata; + void __iomem *pf_base; + void __iomem *lut_base; + bool big_endian; + bool ep_presence; + bool pm_support; + struct regmap *scfg; + int index; }; +#define ls_pcie_lut_readl_addr(addr) ls_pcie_lut_readl(pcie, addr) +#define ls_pcie_pf_readl_addr(addr)ls_pcie_pf_readl(pcie, addr) #define to_ls_pcie(x) dev_get_drvdata((x)->dev) static bool ls_pcie_is_bridge(struct ls_pcie *pcie) @@ -78,6 +124,210 @@ static void ls_pcie_fix_error_response(struct ls_pcie *pcie) iowrite32(PCIE_ABSERR_SETTING, pci->dbi_base + PCIE_ABSERR); } +static u32 ls_pcie_lut_readl(struct ls_pcie *pcie, u32 off) +{ + if (pcie->big_endian) + return ioread32be(pcie->lut_base + off); + + return ioread32(pcie->lut_base + off); +} + +static void ls_pcie_lut_writel(struct ls_pcie *pcie, u32 off, u32 val) +{ + if (pcie->big_endian) + return iowrite32be(val, pcie->lut_base + off); + + return iowrite32(val, pcie->lut_base + off); + +} + +static u32 ls_pcie_pf_readl(struct ls_pcie *pcie, u32 off) +{ + if (pcie->big_endian) + return ioread32be(pcie->pf_base + off); + + return ioread32(pcie->pf_base + off); +} + +static void ls_pcie_pf_writel(struct ls_pcie *pcie, u32 off, u32 val) +{ + if (pcie->big_endian) + return iowrite32be(val, pcie->pf_base + off); + + return iowrite32(val, pcie->pf_base + off); + +} + +static void ls_pcie_send_turnoff_msg(struct ls_pcie *pcie) +{ + u32 val; + int ret; + + val = ls_pcie_pf_readl(pcie, LS_PCIE_PF_MCR); + val |= PF_MCR_PTOMR; + ls_pcie_pf_writel(pcie, LS_PCIE_PF_MCR, val); + + ret = readx_poll_timeout(ls_pcie_pf_readl_addr, LS_PCIE_PF_MCR, +val, !(val & PF_MCR_PTOMR), 100, 1); + if (ret) + dev_info(pcie->pci->dev, "poll turn off message timeout\n"); +} + +static void ls1021a_pcie_send_turnoff_msg(struct ls_pcie *pcie) +{ + u32 val; + + if (!pcie->scfg) { + dev_dbg(pcie->pci->dev, "SYSCFG is NULL\n"); + return; + } + + /* Send Turn_off message */ + regmap_read(pcie->scfg, SCFG_PEXPMWRCR(pcie->index), ); + val |= PMXMTTURNOFF; + regmap_write(pcie->scfg, SCFG_PEXPMWRCR(pcie->index), val); + + mdelay(10); + + /* Clear Turn_off message */ + regmap_read(pcie->scfg, SCFG_PEXPMWRCR(pcie->index), ); + val &= ~PMXMTTURNOFF; + regmap_write(pcie->scfg,
[PATCHv3 3/7] dt-bindings: pci: layerscape-pci: Add a optional property big-endian
From: Hou Zhiqiang This property is to indicate the endianness when accessing the PEX_LUT and PF register block, so if these registers are implemented in big-endian, specify this property. Signed-off-by: Hou Zhiqiang Acked-by: Rob Herring --- V3: - Rebased against the latest code base Documentation/devicetree/bindings/pci/layerscape-pci.txt | 4 1 file changed, 4 insertions(+) diff --git a/Documentation/devicetree/bindings/pci/layerscape-pci.txt b/Documentation/devicetree/bindings/pci/layerscape-pci.txt index daa99f7d4c3f..0033c898976e 100644 --- a/Documentation/devicetree/bindings/pci/layerscape-pci.txt +++ b/Documentation/devicetree/bindings/pci/layerscape-pci.txt @@ -39,6 +39,10 @@ Required properties: of the data transferred from/to the IP block. This can avoid the software cache flush/invalid actions, and improve the performance significantly. +Optional properties: +- big-endian: If the PEX_LUT and PF register block is in big-endian, specify + this property. + Example: pcie@340 { -- 2.17.1
[PATCHv3 5/7] dt-bindings: pci: layerscape-pci: Update the description of SCFG property
From: Hou Zhiqiang Update the description of the second entry of 'fsl,pcie-scfg' property, as the LS1043A PCIe controller also has some control registers in SCFG block, while it has 3 controllers. Signed-off-by: Hou Zhiqiang Acked-by: Rob Herring --- V3: - Rebased against the latest code base Documentation/devicetree/bindings/pci/layerscape-pci.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/pci/layerscape-pci.txt b/Documentation/devicetree/bindings/pci/layerscape-pci.txt index 0033c898976e..4228562be505 100644 --- a/Documentation/devicetree/bindings/pci/layerscape-pci.txt +++ b/Documentation/devicetree/bindings/pci/layerscape-pci.txt @@ -33,7 +33,7 @@ Required properties: "intr": The interrupt that is asserted for controller interrupts - fsl,pcie-scfg: Must include two entries. The first entry must be a link to the SCFG device node - The second entry must be '0' or '1' based on physical PCIe controller index. + The second entry is the physical PCIe controller index starting from '0'. This is used to get SCFG PEXN registers - dma-coherent: Indicates that the hardware IP block can ensure the coherency of the data transferred from/to the IP block. This can avoid the software -- 2.17.1
[PATCHv3 0/7] PCI: layerscape: Add power management support
From: Hou Zhiqiang This patch series is to add PCIe power management support for NXP Layerscape platfroms. Hou Zhiqiang (7): PCI: dwc: Fix a bug of the case dw_pci->ops is NULL PCI: layerscape: Change to use the DWC common link-up check function dt-bindings: pci: layerscape-pci: Add a optional property big-endian arm64: dts: layerscape: Add big-endian property for PCIe nodes dt-bindings: pci: layerscape-pci: Update the description of SCFG property arm64: dts: ls1043a: Add SCFG phandle for PCIe nodes PCI: layerscape: Add power management support .../bindings/pci/layerscape-pci.txt | 6 +- .../arm64/boot/dts/freescale/fsl-ls1012a.dtsi | 1 + .../arm64/boot/dts/freescale/fsl-ls1043a.dtsi | 6 + .../arm64/boot/dts/freescale/fsl-ls1046a.dtsi | 3 + drivers/pci/controller/dwc/pci-layerscape.c | 448 ++ .../pci/controller/dwc/pcie-designware-host.c | 2 +- drivers/pci/controller/dwc/pcie-designware.c | 14 +- drivers/pci/controller/dwc/pcie-designware.h | 1 + 8 files changed, 376 insertions(+), 105 deletions(-) -- 2.17.1
[PATCHv3 6/7] arm64: dts: ls1043a: Add SCFG phandle for PCIe nodes
From: Hou Zhiqiang The LS1043A PCIe controller has some control registers in SCFG block, so add the SCFG phandle for each PCIe controller DT node. Signed-off-by: Hou Zhiqiang --- V3: - Rebased against the latest code base arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi index aca45bf348b4..862c6ac0df83 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi @@ -826,6 +826,7 @@ interrupts = <0 118 0x4>, /* controller interrupt */ <0 117 0x4>; /* PME interrupt */ interrupt-names = "intr", "pme"; + fsl,pcie-scfg = < 0>; #address-cells = <3>; #size-cells = <2>; device_type = "pci"; @@ -853,6 +854,7 @@ interrupts = <0 128 0x4>, <0 127 0x4>; interrupt-names = "intr", "pme"; + fsl,pcie-scfg = < 1>; #address-cells = <3>; #size-cells = <2>; device_type = "pci"; @@ -880,6 +882,7 @@ interrupts = <0 162 0x4>, <0 161 0x4>; interrupt-names = "intr", "pme"; + fsl,pcie-scfg = < 2>; #address-cells = <3>; #size-cells = <2>; device_type = "pci"; -- 2.17.1
[PATCHv3 1/7] PCI: dwc: Fix a bug of the case dw_pci->ops is NULL
From: Hou Zhiqiang The dw_pci->ops may be a NULL, and fix it by adding one more check. Signed-off-by: Hou Zhiqiang Reviewed-by: Rob Herring Acked-by: Gustavo Pimentel --- V3: - Rebased against the latest code base drivers/pci/controller/dwc/pcie-designware-host.c | 2 +- drivers/pci/controller/dwc/pcie-designware.c | 14 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c index 516b151e0ef3..0413284fdd93 100644 --- a/drivers/pci/controller/dwc/pcie-designware-host.c +++ b/drivers/pci/controller/dwc/pcie-designware-host.c @@ -429,7 +429,7 @@ int dw_pcie_host_init(struct pcie_port *pp) dw_pcie_setup_rc(pp); dw_pcie_msi_init(pp); - if (!dw_pcie_link_up(pci) && pci->ops->start_link) { + if (!dw_pcie_link_up(pci) && pci->ops && pci->ops->start_link) { ret = pci->ops->start_link(pci); if (ret) goto err_free_msi; diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c index 645fa1892375..cf895c12f71f 100644 --- a/drivers/pci/controller/dwc/pcie-designware.c +++ b/drivers/pci/controller/dwc/pcie-designware.c @@ -141,7 +141,7 @@ u32 dw_pcie_read_dbi(struct dw_pcie *pci, u32 reg, size_t size) int ret; u32 val; - if (pci->ops->read_dbi) + if (pci->ops && pci->ops->read_dbi) return pci->ops->read_dbi(pci, pci->dbi_base, reg, size); ret = dw_pcie_read(pci->dbi_base + reg, size, ); @@ -156,7 +156,7 @@ void dw_pcie_write_dbi(struct dw_pcie *pci, u32 reg, size_t size, u32 val) { int ret; - if (pci->ops->write_dbi) { + if (pci->ops && pci->ops->write_dbi) { pci->ops->write_dbi(pci, pci->dbi_base, reg, size, val); return; } @@ -171,7 +171,7 @@ void dw_pcie_write_dbi2(struct dw_pcie *pci, u32 reg, size_t size, u32 val) { int ret; - if (pci->ops->write_dbi2) { + if (pci->ops && pci->ops->write_dbi2) { pci->ops->write_dbi2(pci, pci->dbi_base2, reg, size, val); return; } @@ -186,7 +186,7 @@ static u32 dw_pcie_readl_atu(struct dw_pcie *pci, u32 reg) int ret; u32 val; - if (pci->ops->read_dbi) + if (pci->ops && pci->ops->read_dbi) return pci->ops->read_dbi(pci, pci->atu_base, reg, 4); ret = dw_pcie_read(pci->atu_base + reg, 4, ); @@ -200,7 +200,7 @@ static void dw_pcie_writel_atu(struct dw_pcie *pci, u32 reg, u32 val) { int ret; - if (pci->ops->write_dbi) { + if (pci->ops && pci->ops->write_dbi) { pci->ops->write_dbi(pci, pci->atu_base, reg, 4, val); return; } @@ -273,7 +273,7 @@ static void __dw_pcie_prog_outbound_atu(struct dw_pcie *pci, u8 func_no, { u32 retries, val; - if (pci->ops->cpu_addr_fixup) + if (pci->ops && pci->ops->cpu_addr_fixup) cpu_addr = pci->ops->cpu_addr_fixup(pci, cpu_addr); if (pci->iatu_unroll_enabled) { @@ -481,7 +481,7 @@ int dw_pcie_link_up(struct dw_pcie *pci) { u32 val; - if (pci->ops->link_up) + if (pci->ops && pci->ops->link_up) return pci->ops->link_up(pci); val = readl(pci->dbi_base + PCIE_PORT_DEBUG1); -- 2.17.1
[PATCH 3/4] PCI: dwc: Rename callback function func_conf_select and its instance
From: Hou Zhiqiang Rename the callback func_conf_select() and its instance and wrapper to *get_func_cfg_addr(), such that the code becomes more readable. Signed-off-by: Hou Zhiqiang --- drivers/pci/controller/dwc/pci-layerscape-ep.c | 6 +++--- drivers/pci/controller/dwc/pcie-designware-ep.c | 9 + drivers/pci/controller/dwc/pcie-designware.h| 2 +- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/pci/controller/dwc/pci-layerscape-ep.c b/drivers/pci/controller/dwc/pci-layerscape-ep.c index 4d12efdacd2f..0f5e4104c06c 100644 --- a/drivers/pci/controller/dwc/pci-layerscape-ep.c +++ b/drivers/pci/controller/dwc/pci-layerscape-ep.c @@ -87,8 +87,8 @@ static int ls_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no, } } -static unsigned int ls_pcie_ep_func_conf_select(struct dw_pcie_ep *ep, - u8 func_no) +static unsigned int ls_pcie_ep_get_func_cfg_addr(struct dw_pcie_ep *ep, +u8 func_no) { struct dw_pcie *pci = to_dw_pcie_from_ep(ep); struct ls_pcie_ep *pcie = to_ls_pcie_ep(pci); @@ -101,7 +101,7 @@ static const struct dw_pcie_ep_ops ls_pcie_ep_ops = { .ep_init = ls_pcie_ep_init, .raise_irq = ls_pcie_ep_raise_irq, .get_features = ls_pcie_ep_get_features, - .func_conf_select = ls_pcie_ep_func_conf_select, + .get_func_cfg_addr = ls_pcie_ep_get_func_cfg_addr, }; static const struct ls_pcie_ep_drvdata ls1_ep_drvdata = { diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c index bc6ad1f96a48..d8eb9a984547 100644 --- a/drivers/pci/controller/dwc/pcie-designware-ep.c +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c @@ -40,10 +40,11 @@ dw_pcie_ep_get_func_from_ep(struct dw_pcie_ep *ep, u8 func_no) return NULL; } -static unsigned int dw_pcie_ep_func_select(struct dw_pcie_ep *ep, u8 func_no) +static unsigned int dw_pcie_ep_get_func_cfg_addr(struct dw_pcie_ep *ep, +u8 func_no) { - if (ep->ops->func_conf_select) - return ep->ops->func_conf_select(ep, func_no); + if (ep->ops->get_func_cfg_addr) + return ep->ops->get_func_cfg_addr(ep, func_no); return 0; } @@ -730,7 +731,7 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep) for (i = 0; i < epc->max_functions; i++) { funcs[i].func_no = i; - funcs[i].cfg_off = dw_pcie_ep_func_select(ep, i); + funcs[i].cfg_off = dw_pcie_ep_get_func_cfg_addr(ep, i); funcs[i].msi_cap = dw_pcie_ep_find_capability(ep, i, PCI_CAP_ID_MSI); funcs[i].msix_cap = dw_pcie_ep_find_capability(ep, i, diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index 8ee67d4b8109..b8cbe266e01c 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -217,7 +217,7 @@ struct dw_pcie_ep_ops { * return a 0, and implement code in callback function of platform * driver. */ - unsigned int (*func_conf_select)(struct dw_pcie_ep *ep, u8 func_no); + unsigned int (*get_func_cfg_addr)(struct dw_pcie_ep *ep, u8 func_no); }; struct dw_pcie_ep_func { -- 2.17.1
[PATCH 4/4] PCI: dwc: Change the parameter of function dw_pcie_ep_reset_bar()
From: Hou Zhiqiang This helper is endpoint mode specific, so change to use a pointer of 'struct dw_pcie_ep' as the parameter. Signed-off-by: Hou Zhiqiang --- drivers/pci/controller/dwc/pci-dra7xx.c | 2 +- drivers/pci/controller/dwc/pci-layerscape-ep.c | 2 +- drivers/pci/controller/dwc/pcie-artpec6.c| 2 +- drivers/pci/controller/dwc/pcie-designware-ep.c | 16 +++- .../pci/controller/dwc/pcie-designware-plat.c| 3 +-- drivers/pci/controller/dwc/pcie-designware.h | 5 +++-- drivers/pci/controller/dwc/pcie-uniphier-ep.c| 3 +-- 7 files changed, 15 insertions(+), 18 deletions(-) diff --git a/drivers/pci/controller/dwc/pci-dra7xx.c b/drivers/pci/controller/dwc/pci-dra7xx.c index b105af63854a..12726c63366f 100644 --- a/drivers/pci/controller/dwc/pci-dra7xx.c +++ b/drivers/pci/controller/dwc/pci-dra7xx.c @@ -383,7 +383,7 @@ static void dra7xx_pcie_ep_init(struct dw_pcie_ep *ep) enum pci_barno bar; for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) - dw_pcie_ep_reset_bar(pci, bar); + dw_pcie_ep_reset_bar(ep, bar); dra7xx_pcie_enable_wrapper_interrupts(dra7xx); } diff --git a/drivers/pci/controller/dwc/pci-layerscape-ep.c b/drivers/pci/controller/dwc/pci-layerscape-ep.c index 0f5e4104c06c..dcee95e16139 100644 --- a/drivers/pci/controller/dwc/pci-layerscape-ep.c +++ b/drivers/pci/controller/dwc/pci-layerscape-ep.c @@ -62,7 +62,7 @@ static void ls_pcie_ep_init(struct dw_pcie_ep *ep) return; for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) - dw_pcie_ep_reset_bar(pci, bar); + dw_pcie_ep_reset_bar(ep, bar); pcie->ls_epc->msi_capable = ep_func->msi_cap ? true : false; pcie->ls_epc->msix_capable = ep_func->msix_cap ? true : false; diff --git a/drivers/pci/controller/dwc/pcie-artpec6.c b/drivers/pci/controller/dwc/pcie-artpec6.c index 597c282f586c..f833daf6d422 100644 --- a/drivers/pci/controller/dwc/pcie-artpec6.c +++ b/drivers/pci/controller/dwc/pcie-artpec6.c @@ -348,7 +348,7 @@ static void artpec6_pcie_ep_init(struct dw_pcie_ep *ep) artpec6_pcie_wait_for_phy(artpec6_pcie); for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) - dw_pcie_ep_reset_bar(pci, bar); + dw_pcie_ep_reset_bar(ep, bar); } static int artpec6_pcie_raise_irq(struct dw_pcie_ep *ep, u8 func_no, diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c index d8eb9a984547..2dc960e74fd0 100644 --- a/drivers/pci/controller/dwc/pcie-designware-ep.c +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c @@ -49,11 +49,11 @@ static unsigned int dw_pcie_ep_get_func_cfg_addr(struct dw_pcie_ep *ep, return 0; } -static void __dw_pcie_ep_reset_bar(struct dw_pcie *pci, u8 func_no, +static void __dw_pcie_ep_reset_bar(struct dw_pcie_ep *ep, u8 func_no, enum pci_barno bar, int flags) { u32 reg; - struct dw_pcie_ep *ep = >ep; + struct dw_pcie *pci = to_dw_pcie_from_ep(ep); struct dw_pcie_ep_func *func = dw_pcie_ep_get_func_from_ep(ep, func_no); if (!func) @@ -70,14 +70,12 @@ static void __dw_pcie_ep_reset_bar(struct dw_pcie *pci, u8 func_no, dw_pcie_dbi_ro_wr_dis(pci); } -void dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar) +void dw_pcie_ep_reset_bar(struct dw_pcie_ep *ep, enum pci_barno bar) { - u8 func_no, funcs; - - funcs = pci->ep.epc->max_functions; + u8 func_no; - for (func_no = 0; func_no < funcs; func_no++) - __dw_pcie_ep_reset_bar(pci, func_no, bar, 0); + for (func_no = 0; func_no < ep->epc->max_functions; func_no++) + __dw_pcie_ep_reset_bar(ep, func_no, bar, 0); } static u8 __dw_pcie_ep_find_next_cap(struct dw_pcie_ep *ep, u8 func_no, @@ -208,7 +206,7 @@ static void dw_pcie_ep_clear_bar(struct pci_epc *epc, u8 func_no, enum pci_barno bar = epf_bar->barno; u32 atu_index = ep->bar_to_atu[bar]; - __dw_pcie_ep_reset_bar(pci, func_no, bar, epf_bar->flags); + __dw_pcie_ep_reset_bar(ep, func_no, bar, epf_bar->flags); dw_pcie_disable_atu(pci, atu_index, DW_PCIE_REGION_INBOUND); clear_bit(atu_index, ep->ib_window_map); diff --git a/drivers/pci/controller/dwc/pcie-designware-plat.c b/drivers/pci/controller/dwc/pcie-designware-plat.c index 9b397c807261..49d51584a547 100644 --- a/drivers/pci/controller/dwc/pcie-designware-plat.c +++ b/drivers/pci/controller/dwc/pcie-designware-plat.c @@ -47,11 +47,10 @@ static const struct dw_pcie_ops dw_pcie_ops = { static void dw_plat_pcie_ep_init(struct dw_pcie_ep *ep) { - struct dw_pcie *pci = to_dw_pcie_from_ep(ep); enum pci_barno bar; for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) - dw_pcie_ep_reset_bar(pci, bar); + dw_pcie_ep_reset_bar(ep, bar); } static int
[PATCH 2/4] PCI: dwc: Add CFG offset info into function's represented structure
From: Hou Zhiqiang To avoid multiple calculating of the CFG offset for each function, store the CFG offset info to the function's represented structure, and only do one time calculation during the initialization. Signed-off-by: Hou Zhiqiang --- .../pci/controller/dwc/pcie-designware-ep.c | 138 -- drivers/pci/controller/dwc/pcie-designware.h | 1 + 2 files changed, 59 insertions(+), 80 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c index e583700b5ba3..bc6ad1f96a48 100644 --- a/drivers/pci/controller/dwc/pcie-designware-ep.c +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c @@ -42,24 +42,23 @@ dw_pcie_ep_get_func_from_ep(struct dw_pcie_ep *ep, u8 func_no) static unsigned int dw_pcie_ep_func_select(struct dw_pcie_ep *ep, u8 func_no) { - unsigned int func_offset = 0; - if (ep->ops->func_conf_select) - func_offset = ep->ops->func_conf_select(ep, func_no); + return ep->ops->func_conf_select(ep, func_no); - return func_offset; + return 0; } static void __dw_pcie_ep_reset_bar(struct dw_pcie *pci, u8 func_no, enum pci_barno bar, int flags) { u32 reg; - unsigned int func_offset = 0; struct dw_pcie_ep *ep = >ep; + struct dw_pcie_ep_func *func = dw_pcie_ep_get_func_from_ep(ep, func_no); - func_offset = dw_pcie_ep_func_select(ep, func_no); + if (!func) + return; - reg = func_offset + PCI_BASE_ADDRESS_0 + (4 * bar); + reg = func->cfg_off + PCI_BASE_ADDRESS_0 + (4 * bar); dw_pcie_dbi_ro_wr_en(pci); dw_pcie_writel_dbi2(pci, reg, 0x0); dw_pcie_writel_dbi(pci, reg, 0x0); @@ -83,17 +82,15 @@ void dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar) static u8 __dw_pcie_ep_find_next_cap(struct dw_pcie_ep *ep, u8 func_no, u8 cap_ptr, u8 cap) { + struct dw_pcie_ep_func *func = dw_pcie_ep_get_func_from_ep(ep, func_no); struct dw_pcie *pci = to_dw_pcie_from_ep(ep); - unsigned int func_offset = 0; u8 cap_id, next_cap_ptr; u16 reg; - if (!cap_ptr) + if (!cap_ptr || !func) return 0; - func_offset = dw_pcie_ep_func_select(ep, func_no); - - reg = dw_pcie_readw_dbi(pci, func_offset + cap_ptr); + reg = dw_pcie_readw_dbi(pci, func->cfg_off + cap_ptr); cap_id = (reg & 0x00ff); if (cap_id > PCI_CAP_ID_MAX) @@ -108,14 +105,15 @@ static u8 __dw_pcie_ep_find_next_cap(struct dw_pcie_ep *ep, u8 func_no, static u8 dw_pcie_ep_find_capability(struct dw_pcie_ep *ep, u8 func_no, u8 cap) { + struct dw_pcie_ep_func *func = dw_pcie_ep_get_func_from_ep(ep, func_no); struct dw_pcie *pci = to_dw_pcie_from_ep(ep); - unsigned int func_offset = 0; u8 next_cap_ptr; u16 reg; - func_offset = dw_pcie_ep_func_select(ep, func_no); + if (!func) + return 0; - reg = dw_pcie_readw_dbi(pci, func_offset + PCI_CAPABILITY_LIST); + reg = dw_pcie_readw_dbi(pci, func->cfg_off + PCI_CAPABILITY_LIST); next_cap_ptr = (reg & 0x00ff); return __dw_pcie_ep_find_next_cap(ep, func_no, next_cap_ptr, cap); @@ -126,23 +124,26 @@ static int dw_pcie_ep_write_header(struct pci_epc *epc, u8 func_no, { struct dw_pcie_ep *ep = epc_get_drvdata(epc); struct dw_pcie *pci = to_dw_pcie_from_ep(ep); - unsigned int func_offset = 0; + struct dw_pcie_ep_func *func = dw_pcie_ep_get_func_from_ep(ep, func_no); + u32 cfg_off; - func_offset = dw_pcie_ep_func_select(ep, func_no); + if (!func) + return -EINVAL; + cfg_off = func->cfg_off; dw_pcie_dbi_ro_wr_en(pci); - dw_pcie_writew_dbi(pci, func_offset + PCI_VENDOR_ID, hdr->vendorid); - dw_pcie_writew_dbi(pci, func_offset + PCI_DEVICE_ID, hdr->deviceid); - dw_pcie_writeb_dbi(pci, func_offset + PCI_REVISION_ID, hdr->revid); - dw_pcie_writeb_dbi(pci, func_offset + PCI_CLASS_PROG, hdr->progif_code); - dw_pcie_writew_dbi(pci, func_offset + PCI_CLASS_DEVICE, + dw_pcie_writew_dbi(pci, cfg_off + PCI_VENDOR_ID, hdr->vendorid); + dw_pcie_writew_dbi(pci, cfg_off + PCI_DEVICE_ID, hdr->deviceid); + dw_pcie_writeb_dbi(pci, cfg_off + PCI_REVISION_ID, hdr->revid); + dw_pcie_writeb_dbi(pci, cfg_off + PCI_CLASS_PROG, hdr->progif_code); + dw_pcie_writew_dbi(pci, cfg_off + PCI_CLASS_DEVICE, hdr->subclass_code | hdr->baseclass_code << 8); - dw_pcie_writeb_dbi(pci, func_offset + PCI_CACHE_LINE_SIZE, + dw_pcie_writeb_dbi(pci, cfg_off + PCI_CACHE_LINE_SIZE, hdr->cache_line_size); - dw_pcie_writew_dbi(pci, func_offset + PCI_SUBSYSTEM_VENDOR_ID, + dw_pcie_writew_dbi(pci, cfg_off + PCI_SUBSYSTEM_VENDOR_ID,
[PATCH 1/4] PCI: dwc: Change to use an array to store the structure of functions
From: Hou Zhiqiang As there isn't dynamically adding and deleting a function's structure, the list_head is not necessary for this case. Array is easier and more efficient to search. Signed-off-by: Hou Zhiqiang --- .../pci/controller/dwc/pcie-designware-ep.c | 33 --- drivers/pci/controller/dwc/pcie-designware.h | 3 +- 2 files changed, 15 insertions(+), 21 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c index bcd1cd9ba8c8..e583700b5ba3 100644 --- a/drivers/pci/controller/dwc/pcie-designware-ep.c +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c @@ -34,12 +34,8 @@ EXPORT_SYMBOL_GPL(dw_pcie_ep_init_notify); struct dw_pcie_ep_func * dw_pcie_ep_get_func_from_ep(struct dw_pcie_ep *ep, u8 func_no) { - struct dw_pcie_ep_func *ep_func; - - list_for_each_entry(ep_func, >func_list, list) { - if (ep_func->func_no == func_no) - return ep_func; - } + if (func_no < ep->epc->max_functions) + return ep->funcs + func_no; return NULL; } @@ -675,9 +671,9 @@ EXPORT_SYMBOL_GPL(dw_pcie_ep_init_complete); int dw_pcie_ep_init(struct dw_pcie_ep *ep) { + u8 i; int ret; void *addr; - u8 func_no; struct resource *res; struct pci_epc *epc; struct dw_pcie *pci = to_dw_pcie_from_ep(ep); @@ -685,9 +681,7 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep) struct platform_device *pdev = to_platform_device(dev); struct device_node *np = dev->of_node; const struct pci_epc_features *epc_features; - struct dw_pcie_ep_func *ep_func; - - INIT_LIST_HEAD(>func_list); + struct dw_pcie_ep_func *funcs; if (!pci->dbi_base) { res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi"); @@ -750,18 +744,19 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep) if (ret < 0) epc->max_functions = 1; - for (func_no = 0; func_no < epc->max_functions; func_no++) { - ep_func = devm_kzalloc(dev, sizeof(*ep_func), GFP_KERNEL); - if (!ep_func) - return -ENOMEM; + funcs = devm_kcalloc(dev, epc->max_functions, sizeof(*funcs), +GFP_KERNEL); + if (!funcs) + return -ENOMEM; + + ep->funcs = funcs; - ep_func->func_no = func_no; - ep_func->msi_cap = dw_pcie_ep_find_capability(ep, func_no, + for (i = 0; i < epc->max_functions; i++) { + funcs[i].func_no = i; + funcs[i].msi_cap = dw_pcie_ep_find_capability(ep, i, PCI_CAP_ID_MSI); - ep_func->msix_cap = dw_pcie_ep_find_capability(ep, func_no, + funcs[i].msix_cap = dw_pcie_ep_find_capability(ep, i, PCI_CAP_ID_MSIX); - - list_add_tail(_func->list, >func_list); } if (ep->ops->ep_init) diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index 98710bf5ab0e..16d239c4d09b 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -221,7 +221,6 @@ struct dw_pcie_ep_ops { }; struct dw_pcie_ep_func { - struct list_headlist; u8 func_no; u8 msi_cap;/* MSI capability offset */ u8 msix_cap; /* MSI-X capability offset */ @@ -229,7 +228,7 @@ struct dw_pcie_ep_func { struct dw_pcie_ep { struct pci_epc *epc; - struct list_headfunc_list; + struct dw_pcie_ep_func *funcs; const struct dw_pcie_ep_ops *ops; phys_addr_t phys_base; size_t addr_size; -- 2.17.1
[PATCH 0/4] PCI: dwc: Refine the EP code no functionality change
From: Hou Zhiqiang Tune the EP mode code slightly to make it more readable. Hou Zhiqiang (4): PCI: dwc: Change to use an array to store the structure of functions PCI: dwc: Add CFG offset info into function's represented structure PCI: dwc: Rename callback function func_conf_select and its instance PCI: dwc: Change the parameter of function dw_pcie_ep_reset_bar() drivers/pci/controller/dwc/pci-dra7xx.c | 2 +- .../pci/controller/dwc/pci-layerscape-ep.c| 8 +- drivers/pci/controller/dwc/pcie-artpec6.c | 2 +- .../pci/controller/dwc/pcie-designware-ep.c | 192 -- .../pci/controller/dwc/pcie-designware-plat.c | 3 +- drivers/pci/controller/dwc/pcie-designware.h | 11 +- drivers/pci/controller/dwc/pcie-uniphier-ep.c | 3 +- 7 files changed, 96 insertions(+), 125 deletions(-) -- 2.17.1
[PATCHv10] arm64: dts: layerscape: Add PCIe EP node for ls1088a
From: Xiaowei Bao Add PCIe EP node for ls1088a to support EP mode. Signed-off-by: Xiaowei Bao Signed-off-by: Hou Zhiqiang Reviewed-by: Andrew Murray --- V10: - Add a space between compatibles. .../arm64/boot/dts/freescale/fsl-ls1088a.dtsi | 31 +++ 1 file changed, 31 insertions(+) diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi index ff5805206a28..8d8e610acba6 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi @@ -517,6 +517,17 @@ status = "disabled"; }; + pcie_ep1: pcie-ep@340 { + compatible = "fsl,ls1088a-pcie-ep", "fsl,ls-pcie-ep"; + reg = <0x00 0x0340 0x0 0x0010 + 0x20 0x 0x8 0x>; + reg-names = "regs", "addr_space"; + num-ib-windows = <24>; + num-ob-windows = <256>; + max-functions = /bits/ 8 <2>; + status = "disabled"; + }; + pcie2: pcie@350 { compatible = "fsl,ls1088a-pcie"; reg = <0x00 0x0350 0x0 0x0010 /* controller registers */ @@ -543,6 +554,16 @@ status = "disabled"; }; + pcie_ep2: pcie-ep@350 { + compatible = "fsl,ls1088a-pcie-ep", "fsl,ls-pcie-ep"; + reg = <0x00 0x0350 0x0 0x0010 + 0x28 0x 0x8 0x>; + reg-names = "regs", "addr_space"; + num-ib-windows = <6>; + num-ob-windows = <6>; + status = "disabled"; + }; + pcie3: pcie@360 { compatible = "fsl,ls1088a-pcie"; reg = <0x00 0x0360 0x0 0x0010 /* controller registers */ @@ -569,6 +590,16 @@ status = "disabled"; }; + pcie_ep3: pcie-ep@360 { + compatible = "fsl,ls1088a-pcie-ep", "fsl,ls-pcie-ep"; + reg = <0x00 0x0360 0x0 0x0010 + 0x30 0x 0x8 0x>; + reg-names = "regs", "addr_space"; + num-ib-windows = <6>; + num-ob-windows = <6>; + status = "disabled"; + }; + smmu: iommu@500 { compatible = "arm,mmu-500"; reg = <0 0x500 0 0x80>; -- 2.17.1
[PATCHv2 7/7] PCI: layerscape: Add power management support
From: Hou Zhiqiang Add PME_Turn_Off/PME_TO_Ack handshake sequence, and finally put the PCIe controller into D3 state after the L2/L3 ready state transition process completion. Signed-off-by: Hou Zhiqiang --- V2: - Change to use the common defines to access the RC configuration registers. drivers/pci/controller/dwc/pci-layerscape.c | 380 ++- drivers/pci/controller/dwc/pcie-designware.h | 1 + 2 files changed, 379 insertions(+), 2 deletions(-) diff --git a/drivers/pci/controller/dwc/pci-layerscape.c b/drivers/pci/controller/dwc/pci-layerscape.c index be404c16bcbe..9886eaead593 100644 --- a/drivers/pci/controller/dwc/pci-layerscape.c +++ b/drivers/pci/controller/dwc/pci-layerscape.c @@ -3,13 +3,16 @@ * PCIe host controller driver for Freescale Layerscape SoCs * * Copyright (C) 2014 Freescale Semiconductor. + * Copyright 2020 NXP * * Author: Minghuan Lian */ +#include #include #include #include +#include #include #include #include @@ -27,17 +30,60 @@ #define PCIE_ABSERR0x8d0 /* Bridge Slave Error Response Register */ #define PCIE_ABSERR_SETTING0x9401 /* Forward error of non-posted request */ +/* PF Message Command Register */ +#define LS_PCIE_PF_MCR 0x2c +#define PF_MCR_PTOMR BIT(0) +#define PF_MCR_EXL2S BIT(1) + +/* LS1021A PEXn PM Write Control Register */ +#define SCFG_PEXPMWRCR(idx)(0x5c + (idx) * 0x64) +#define PMXMTTURNOFF BIT(31) +#define SCFG_PEXSFTRSTCR 0x190 +#define PEXSR(idx) BIT(idx) + +/* LS1043A PEX PME control register */ +#define SCFG_PEXPMECR 0x144 +#define PEXPME(idx)BIT(31 - (idx) * 4) + +/* LS1043A PEX LUT debug register */ +#define LS_PCIE_LDBG 0x7fc +#define LDBG_SRBIT(30) +#define LDBG_WEBIT(31) + #define PCIE_IATU_NUM 6 +#define LS_PCIE_IS_L2(v) \ + (((v) & PORT_LOGIC_LTSSM_STATE_MASK) == PORT_LOGIC_LTSSM_STATE_L2) + +struct ls_pcie; + +struct ls_pcie_host_pm_ops { + int (*pm_init)(struct ls_pcie *pcie); + void (*send_turn_off_message)(struct ls_pcie *pcie); + void (*exit_from_l2)(struct ls_pcie *pcie); +}; + struct ls_pcie_drvdata { + const u32 pf_off; + const u32 lut_off; const struct dw_pcie_host_ops *ops; + const struct ls_pcie_host_pm_ops *pm_ops; }; struct ls_pcie { struct dw_pcie *pci; const struct ls_pcie_drvdata *drvdata; + void __iomem *pf_base; + void __iomem *lut_base; + bool big_endian; + bool ep_presence; + bool pm_support; + struct regmap *scfg; + int index; }; +#define ls_pcie_lut_readl_addr(addr) ls_pcie_lut_readl(pcie, addr) +#define ls_pcie_pf_readl_addr(addr)ls_pcie_pf_readl(pcie, addr) #define to_ls_pcie(x) dev_get_drvdata((x)->dev) static bool ls_pcie_is_bridge(struct ls_pcie *pcie) @@ -86,6 +132,210 @@ static void ls_pcie_fix_error_response(struct ls_pcie *pcie) iowrite32(PCIE_ABSERR_SETTING, pci->dbi_base + PCIE_ABSERR); } +static u32 ls_pcie_lut_readl(struct ls_pcie *pcie, u32 off) +{ + if (pcie->big_endian) + return ioread32be(pcie->lut_base + off); + + return ioread32(pcie->lut_base + off); +} + +static void ls_pcie_lut_writel(struct ls_pcie *pcie, u32 off, u32 val) +{ + if (pcie->big_endian) + return iowrite32be(val, pcie->lut_base + off); + + return iowrite32(val, pcie->lut_base + off); + +} + +static u32 ls_pcie_pf_readl(struct ls_pcie *pcie, u32 off) +{ + if (pcie->big_endian) + return ioread32be(pcie->pf_base + off); + + return ioread32(pcie->pf_base + off); +} + +static void ls_pcie_pf_writel(struct ls_pcie *pcie, u32 off, u32 val) +{ + if (pcie->big_endian) + return iowrite32be(val, pcie->pf_base + off); + + return iowrite32(val, pcie->pf_base + off); + +} + +static void ls_pcie_send_turnoff_msg(struct ls_pcie *pcie) +{ + u32 val; + int ret; + + val = ls_pcie_pf_readl(pcie, LS_PCIE_PF_MCR); + val |= PF_MCR_PTOMR; + ls_pcie_pf_writel(pcie, LS_PCIE_PF_MCR, val); + + ret = readx_poll_timeout(ls_pcie_pf_readl_addr, LS_PCIE_PF_MCR, +val, !(val & PF_MCR_PTOMR), 100, 1); + if (ret) + dev_info(pcie->pci->dev, "poll turn off message timeout\n"); +} + +static void ls1021a_pcie_send_turnoff_msg(struct ls_pcie *pcie) +{ + u32 val; + + if (!pcie->scfg) { + dev_dbg(pcie->pci->dev, "SYSCFG is NULL\n"); + return; + } + + /* Send Turn_off message */ + regmap_read(pcie->scfg, SCFG_PEXPMWRCR(pcie->index), ); + val |= PMXMTTURNOFF; + regmap_write(pcie->scfg, SCFG_PEXPMWRCR(pcie->index), val); + + mdelay(10); + + /* Clear Turn_off message */ + regmap_read(pcie->scfg, SCFG_PEXPMWRCR(pcie->index), ); + val &= ~PMXMTTURNOFF; +
[PATCHv2 6/7] arm64: dts: ls1043a: Add SCFG phandle for PCIe nodes
From: Hou Zhiqiang The LS1043A PCIe controller has some control registers in SCFG block, so add the SCFG phandle for each PCIe controller DT node. Signed-off-by: Hou Zhiqiang --- V2: - Correct the order of the subject prefixes. arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi index d33a64ae8b0f..23bf3796d98f 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi @@ -822,6 +822,7 @@ interrupts = <0 118 0x4>, /* controller interrupt */ <0 117 0x4>; /* PME interrupt */ interrupt-names = "intr", "pme"; + fsl,pcie-scfg = < 0>; #address-cells = <3>; #size-cells = <2>; device_type = "pci"; @@ -849,6 +850,7 @@ interrupts = <0 128 0x4>, <0 127 0x4>; interrupt-names = "intr", "pme"; + fsl,pcie-scfg = < 1>; #address-cells = <3>; #size-cells = <2>; device_type = "pci"; @@ -876,6 +878,7 @@ interrupts = <0 162 0x4>, <0 161 0x4>; interrupt-names = "intr", "pme"; + fsl,pcie-scfg = < 2>; #address-cells = <3>; #size-cells = <2>; device_type = "pci"; -- 2.17.1
[PATCHv2 5/7] dt-bindings: pci: layerscape-pci: Update the description of SCFG property
From: Hou Zhiqiang Update the description of the second entry of 'fsl,pcie-scfg' property, as the LS1043A PCIe controller also has some control registers in SCFG block, while it has 3 controllers. Signed-off-by: Hou Zhiqiang Acked-by: Rob Herring --- V2: - No change. Documentation/devicetree/bindings/pci/layerscape-pci.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/pci/layerscape-pci.txt b/Documentation/devicetree/bindings/pci/layerscape-pci.txt index 0033c898976e..4228562be505 100644 --- a/Documentation/devicetree/bindings/pci/layerscape-pci.txt +++ b/Documentation/devicetree/bindings/pci/layerscape-pci.txt @@ -33,7 +33,7 @@ Required properties: "intr": The interrupt that is asserted for controller interrupts - fsl,pcie-scfg: Must include two entries. The first entry must be a link to the SCFG device node - The second entry must be '0' or '1' based on physical PCIe controller index. + The second entry is the physical PCIe controller index starting from '0'. This is used to get SCFG PEXN registers - dma-coherent: Indicates that the hardware IP block can ensure the coherency of the data transferred from/to the IP block. This can avoid the software -- 2.17.1
[PATCHv2 4/7] arm64: dts: layerscape: Add big-endian property for PCIe nodes
From: Hou Zhiqiang Add the big-endian property for LS1012A, LS1043A and LS1046A PCIe devicetree nodes. Signed-off-by: Hou Zhiqiang --- V2: - No change. arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi | 1 + arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi | 3 +++ arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi | 3 +++ 3 files changed, 7 insertions(+) diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi index 6a2c09199047..0f63aea30477 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi @@ -512,6 +512,7 @@ < 0 0 2 0 111 IRQ_TYPE_LEVEL_HIGH>, < 0 0 3 0 112 IRQ_TYPE_LEVEL_HIGH>, < 0 0 4 0 113 IRQ_TYPE_LEVEL_HIGH>; + big-endian; status = "disabled"; }; diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi index 0464b8aa4bc4..d33a64ae8b0f 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi @@ -837,6 +837,7 @@ < 0 0 2 0 111 0x4>, < 0 0 3 0 112 0x4>, < 0 0 4 0 113 0x4>; + big-endian; status = "disabled"; }; @@ -863,6 +864,7 @@ < 0 0 2 0 121 0x4>, < 0 0 3 0 122 0x4>, < 0 0 4 0 123 0x4>; + big-endian; status = "disabled"; }; @@ -889,6 +891,7 @@ < 0 0 2 0 155 0x4>, < 0 0 3 0 156 0x4>, < 0 0 4 0 157 0x4>; + big-endian; status = "disabled"; }; diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi index 1fa39bacff4b..b01fb93f7d19 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi @@ -741,6 +741,7 @@ < 0 0 2 GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>, < 0 0 3 GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>, < 0 0 4 GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>; + big-endian; status = "disabled"; }; @@ -777,6 +778,7 @@ < 0 0 2 GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>, < 0 0 3 GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>, < 0 0 4 GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>; + big-endian; status = "disabled"; }; @@ -813,6 +815,7 @@ < 0 0 2 GIC_SPI 154 IRQ_TYPE_LEVEL_HIGH>, < 0 0 3 GIC_SPI 154 IRQ_TYPE_LEVEL_HIGH>, < 0 0 4 GIC_SPI 154 IRQ_TYPE_LEVEL_HIGH>; + big-endian; status = "disabled"; }; -- 2.17.1
[PATCHv2 2/7] PCI: layerscape: Change to use the DWC common link-up check function
From: Hou Zhiqiang The current Layerscape PCIe driver directly uses the physical layer LTSSM code to check the link-up state, which treats the > L0 states as link-up. This is not correct, since there is not explicit map between link-up state and LTSSM. So this patch changes to use the DWC common link-up check function. Signed-off-by: Hou Zhiqiang Reviewed-by: Rob Herring --- V2: - No change. drivers/pci/controller/dwc/pci-layerscape.c | 141 ++-- 1 file changed, 10 insertions(+), 131 deletions(-) diff --git a/drivers/pci/controller/dwc/pci-layerscape.c b/drivers/pci/controller/dwc/pci-layerscape.c index f24f79a70d9a..be404c16bcbe 100644 --- a/drivers/pci/controller/dwc/pci-layerscape.c +++ b/drivers/pci/controller/dwc/pci-layerscape.c @@ -22,12 +22,6 @@ #include "pcie-designware.h" -/* PEX1/2 Misc Ports Status Register */ -#define SCFG_PEXMSCPORTSR(pex_idx) (0x94 + (pex_idx) * 4) -#define LTSSM_STATE_SHIFT 20 -#define LTSSM_STATE_MASK 0x3f -#define LTSSM_PCIE_L0 0x11 /* L0 state */ - /* PEX Internal Configuration Registers */ #define PCIE_STRFMR1 0x71c /* Symbol Timer & Filter Mask Register1 */ #define PCIE_ABSERR0x8d0 /* Bridge Slave Error Response Register */ @@ -36,19 +30,12 @@ #define PCIE_IATU_NUM 6 struct ls_pcie_drvdata { - u32 lut_offset; - u32 ltssm_shift; - u32 lut_dbg; const struct dw_pcie_host_ops *ops; - const struct dw_pcie_ops *dw_pcie_ops; }; struct ls_pcie { struct dw_pcie *pci; - void __iomem *lut; - struct regmap *scfg; const struct ls_pcie_drvdata *drvdata; - int index; }; #define to_ls_pcie(x) dev_get_drvdata((x)->dev) @@ -91,38 +78,6 @@ static void ls_pcie_disable_outbound_atus(struct ls_pcie *pcie) dw_pcie_disable_atu(pcie->pci, i, DW_PCIE_REGION_OUTBOUND); } -static int ls1021_pcie_link_up(struct dw_pcie *pci) -{ - u32 state; - struct ls_pcie *pcie = to_ls_pcie(pci); - - if (!pcie->scfg) - return 0; - - regmap_read(pcie->scfg, SCFG_PEXMSCPORTSR(pcie->index), ); - state = (state >> LTSSM_STATE_SHIFT) & LTSSM_STATE_MASK; - - if (state < LTSSM_PCIE_L0) - return 0; - - return 1; -} - -static int ls_pcie_link_up(struct dw_pcie *pci) -{ - struct ls_pcie *pcie = to_ls_pcie(pci); - u32 state; - - state = (ioread32(pcie->lut + pcie->drvdata->lut_dbg) >> -pcie->drvdata->ltssm_shift) & -LTSSM_STATE_MASK; - - if (state < LTSSM_PCIE_L0) - return 0; - - return 1; -} - /* Forward error response of outbound non-posted requests */ static void ls_pcie_fix_error_response(struct ls_pcie *pcie) { @@ -155,33 +110,6 @@ static int ls_pcie_host_init(struct pcie_port *pp) return 0; } -static int ls1021_pcie_host_init(struct pcie_port *pp) -{ - struct dw_pcie *pci = to_dw_pcie_from_pp(pp); - struct ls_pcie *pcie = to_ls_pcie(pci); - struct device *dev = pci->dev; - u32 index[2]; - int ret; - - pcie->scfg = syscon_regmap_lookup_by_phandle(dev->of_node, -"fsl,pcie-scfg"); - if (IS_ERR(pcie->scfg)) { - ret = PTR_ERR(pcie->scfg); - dev_err(dev, "No syscfg phandle specified\n"); - pcie->scfg = NULL; - return ret; - } - - if (of_property_read_u32_array(dev->of_node, - "fsl,pcie-scfg", index, 2)) { - pcie->scfg = NULL; - return -EINVAL; - } - pcie->index = index[1]; - - return ls_pcie_host_init(pp); -} - static int ls_pcie_msi_host_init(struct pcie_port *pp) { struct dw_pcie *pci = to_dw_pcie_from_pp(pp); @@ -205,71 +133,25 @@ static int ls_pcie_msi_host_init(struct pcie_port *pp) return 0; } -static const struct dw_pcie_host_ops ls1021_pcie_host_ops = { - .host_init = ls1021_pcie_host_init, - .msi_host_init = ls_pcie_msi_host_init, -}; - static const struct dw_pcie_host_ops ls_pcie_host_ops = { .host_init = ls_pcie_host_init, .msi_host_init = ls_pcie_msi_host_init, }; -static const struct dw_pcie_ops dw_ls1021_pcie_ops = { - .link_up = ls1021_pcie_link_up, -}; - -static const struct dw_pcie_ops dw_ls_pcie_ops = { - .link_up = ls_pcie_link_up, -}; - -static const struct ls_pcie_drvdata ls1021_drvdata = { - .ops = _pcie_host_ops, - .dw_pcie_ops = _ls1021_pcie_ops, -}; - -static const struct ls_pcie_drvdata ls1043_drvdata = { - .lut_offset = 0x1, - .ltssm_shift = 24, - .lut_dbg = 0x7fc, - .ops = _pcie_host_ops, - .dw_pcie_ops = _ls_pcie_ops, -}; - -static const struct ls_pcie_drvdata ls1046_drvdata = { - .lut_offset = 0x8, - .ltssm_shift = 24, - .lut_dbg = 0x407fc, - .ops = _pcie_host_ops, -
[PATCHv2 3/7] dt-bindings: pci: layerscape-pci: Add a optional property big-endian
From: Hou Zhiqiang This property is to indicate the endianness when accessing the PEX_LUT and PF register block, so if these registers are implemented in big-endian, specify this property. Signed-off-by: Hou Zhiqiang Acked-by: Rob Herring --- V2: - No change. Documentation/devicetree/bindings/pci/layerscape-pci.txt | 4 1 file changed, 4 insertions(+) diff --git a/Documentation/devicetree/bindings/pci/layerscape-pci.txt b/Documentation/devicetree/bindings/pci/layerscape-pci.txt index daa99f7d4c3f..0033c898976e 100644 --- a/Documentation/devicetree/bindings/pci/layerscape-pci.txt +++ b/Documentation/devicetree/bindings/pci/layerscape-pci.txt @@ -39,6 +39,10 @@ Required properties: of the data transferred from/to the IP block. This can avoid the software cache flush/invalid actions, and improve the performance significantly. +Optional properties: +- big-endian: If the PEX_LUT and PF register block is in big-endian, specify + this property. + Example: pcie@340 { -- 2.17.1
[PATCHv2 1/7] PCI: dwc: Fix a bug of the case dw_pci->ops is NULL
From: Hou Zhiqiang The dw_pci->ops may be a NULL, and fix it by adding one more check. Signed-off-by: Hou Zhiqiang Reviewed-by: Rob Herring Acked-by: Gustavo Pimentel --- V2: - Rebased the patch against the latest code. drivers/pci/controller/dwc/pcie-designware.c | 14 +++--- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c index c2dea8fc97c8..7a5024450c4d 100644 --- a/drivers/pci/controller/dwc/pcie-designware.c +++ b/drivers/pci/controller/dwc/pcie-designware.c @@ -141,7 +141,7 @@ u32 dw_pcie_read_dbi(struct dw_pcie *pci, u32 reg, size_t size) int ret; u32 val; - if (pci->ops->read_dbi) + if (pci->ops && pci->ops->read_dbi) return pci->ops->read_dbi(pci, pci->dbi_base, reg, size); ret = dw_pcie_read(pci->dbi_base + reg, size, ); @@ -156,7 +156,7 @@ void dw_pcie_write_dbi(struct dw_pcie *pci, u32 reg, size_t size, u32 val) { int ret; - if (pci->ops->write_dbi) { + if (pci->ops && pci->ops->write_dbi) { pci->ops->write_dbi(pci, pci->dbi_base, reg, size, val); return; } @@ -171,7 +171,7 @@ void dw_pcie_write_dbi2(struct dw_pcie *pci, u32 reg, size_t size, u32 val) { int ret; - if (pci->ops->write_dbi2) { + if (pci->ops && pci->ops->write_dbi2) { pci->ops->write_dbi2(pci, pci->dbi_base2, reg, size, val); return; } @@ -186,7 +186,7 @@ static u32 dw_pcie_readl_atu(struct dw_pcie *pci, u32 reg) int ret; u32 val; - if (pci->ops->read_dbi) + if (pci->ops && pci->ops->read_dbi) return pci->ops->read_dbi(pci, pci->atu_base, reg, 4); ret = dw_pcie_read(pci->atu_base + reg, 4, ); @@ -200,7 +200,7 @@ static void dw_pcie_writel_atu(struct dw_pcie *pci, u32 reg, u32 val) { int ret; - if (pci->ops->write_dbi) { + if (pci->ops && pci->ops->write_dbi) { pci->ops->write_dbi(pci, pci->atu_base, reg, 4, val); return; } @@ -271,7 +271,7 @@ static void __dw_pcie_prog_outbound_atu(struct dw_pcie *pci, u8 func_no, { u32 retries, val; - if (pci->ops->cpu_addr_fixup) + if (pci->ops && pci->ops->cpu_addr_fixup) cpu_addr = pci->ops->cpu_addr_fixup(pci, cpu_addr); if (pci->iatu_unroll_enabled) { @@ -479,7 +479,7 @@ int dw_pcie_link_up(struct dw_pcie *pci) { u32 val; - if (pci->ops->link_up) + if (pci->ops && pci->ops->link_up) return pci->ops->link_up(pci); val = readl(pci->dbi_base + PCIE_PORT_DEBUG1); -- 2.17.1
[PATCHv2 0/7] PCI: layerscape: Add power management support
From: Hou Zhiqiang This patch series is to add PCIe power management support for NXP Layerscape platfroms. Hou Zhiqiang (7): PCI: dwc: Fix a bug of the case dw_pci->ops is NULL PCI: layerscape: Change to use the DWC common link-up check function dt-bindings: pci: layerscape-pci: Add a optional property big-endian arm64: dts: layerscape: Add big-endian property for PCIe nodes dt-bindings: pci: layerscape-pci: Update the description of SCFG property dts: arm64: ls1043a: Add SCFG phandle for PCIe nodes PCI: layerscape: Add power management support .../bindings/pci/layerscape-pci.txt | 6 +- .../arm64/boot/dts/freescale/fsl-ls1012a.dtsi | 1 + .../arm64/boot/dts/freescale/fsl-ls1043a.dtsi | 6 + .../arm64/boot/dts/freescale/fsl-ls1046a.dtsi | 3 + drivers/pci/controller/dwc/pci-layerscape.c | 469 ++ drivers/pci/controller/dwc/pcie-designware.c | 14 +- drivers/pci/controller/dwc/pcie-designware.h | 1 + 7 files changed, 385 insertions(+), 115 deletions(-) -- 2.17.1
[PATCH 2/2] PCI: layerscape: Add EP mode support for LX2160A rev2
From: Hou Zhiqiang The LX2160A rev2 uses the same PCIe IP as LS2088A, but LX2160A rev2 PCIe controller is integrated with different stride between PFs' register address. Signed-off-by: Hou Zhiqiang --- drivers/pci/controller/dwc/pci-layerscape-ep.c | 7 +++ 1 file changed, 7 insertions(+) diff --git a/drivers/pci/controller/dwc/pci-layerscape-ep.c b/drivers/pci/controller/dwc/pci-layerscape-ep.c index 84206f265e54..b125fa1519c8 100644 --- a/drivers/pci/controller/dwc/pci-layerscape-ep.c +++ b/drivers/pci/controller/dwc/pci-layerscape-ep.c @@ -117,10 +117,17 @@ static const struct ls_pcie_ep_drvdata ls2_ep_drvdata = { .dw_pcie_ops = _ls_pcie_ep_ops, }; +static const struct ls_pcie_ep_drvdata lx2_ep_drvdata = { + .func_offset = 0x8000, + .ops = _pcie_ep_ops, + .dw_pcie_ops = _ls_pcie_ep_ops, +}; + static const struct of_device_id ls_pcie_ep_of_match[] = { { .compatible = "fsl,ls1046a-pcie-ep", .data = _ep_drvdata }, { .compatible = "fsl,ls1088a-pcie-ep", .data = _ep_drvdata }, { .compatible = "fsl,ls2088a-pcie-ep", .data = _ep_drvdata }, + { .compatible = "fsl,lx2160ar2-pcie-ep", .data = _ep_drvdata }, { }, }; -- 2.17.1
[PATCH 1/2] dt-bindings: pci: layerscape-pci: Add compatible strings for LX2160A rev2
From: Hou Zhiqiang Add PCIe Endpoint mode compatible string "fsl,lx2160ar2-pcie-ep" Signed-off-by: Hou Zhiqiang --- Documentation/devicetree/bindings/pci/layerscape-pci.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/pci/layerscape-pci.txt b/Documentation/devicetree/bindings/pci/layerscape-pci.txt index daa99f7d4c3f..6d898dd4a8e2 100644 --- a/Documentation/devicetree/bindings/pci/layerscape-pci.txt +++ b/Documentation/devicetree/bindings/pci/layerscape-pci.txt @@ -26,6 +26,7 @@ Required properties: "fsl,ls1046a-pcie-ep", "fsl,ls-pcie-ep" "fsl,ls1088a-pcie-ep", "fsl,ls-pcie-ep" "fsl,ls2088a-pcie-ep", "fsl,ls-pcie-ep" + "fsl,lx2160ar2-pcie-ep", "fsl,ls-pcie-ep" - reg: base addresses and lengths of the PCIe controller register blocks. - interrupts: A list of interrupt outputs of the controller. Must contain an entry for each entry in the interrupt-names property. -- 2.17.1
[PATCHv9] arm64: dts: layerscape: Add PCIe EP node for ls1088a
From: Xiaowei Bao Add PCIe EP node for ls1088a to support EP mode. Signed-off-by: Xiaowei Bao Signed-off-by: Hou Zhiqiang Reviewed-by: Andrew Murray --- V9: - Rebase the patch since V8 patch was not accepted due to conflict. - Correct the number of outbound windows. - Add lables for EP nodes. .../arm64/boot/dts/freescale/fsl-ls1088a.dtsi | 31 +++ 1 file changed, 31 insertions(+) diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi index ff5805206a28..8d8e610acba6 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi @@ -517,6 +517,17 @@ status = "disabled"; }; + pcie_ep1: pcie-ep@340 { + compatible = "fsl,ls1088a-pcie-ep","fsl,ls-pcie-ep"; + reg = <0x00 0x0340 0x0 0x0010 + 0x20 0x 0x8 0x>; + reg-names = "regs", "addr_space"; + num-ib-windows = <24>; + num-ob-windows = <256>; + max-functions = /bits/ 8 <2>; + status = "disabled"; + }; + pcie2: pcie@350 { compatible = "fsl,ls1088a-pcie"; reg = <0x00 0x0350 0x0 0x0010 /* controller registers */ @@ -543,6 +554,16 @@ status = "disabled"; }; + pcie_ep2: pcie-ep@350 { + compatible = "fsl,ls1088a-pcie-ep","fsl,ls-pcie-ep"; + reg = <0x00 0x0350 0x0 0x0010 + 0x28 0x 0x8 0x>; + reg-names = "regs", "addr_space"; + num-ib-windows = <6>; + num-ob-windows = <6>; + status = "disabled"; + }; + pcie3: pcie@360 { compatible = "fsl,ls1088a-pcie"; reg = <0x00 0x0360 0x0 0x0010 /* controller registers */ @@ -569,6 +590,16 @@ status = "disabled"; }; + pcie_ep3: pcie-ep@360 { + compatible = "fsl,ls1088a-pcie-ep","fsl,ls-pcie-ep"; + reg = <0x00 0x0360 0x0 0x0010 + 0x30 0x 0x8 0x>; + reg-names = "regs", "addr_space"; + num-ib-windows = <6>; + num-ob-windows = <6>; + status = "disabled"; + }; + smmu: iommu@500 { compatible = "arm,mmu-500"; reg = <0 0x500 0 0x80>; -- 2.17.1
[PATCH] PCI: layerscape: Change back to the default error response behavior
From: Hou Zhiqiang In the current error response behavior, it will send a SLVERR response to device's internal AXI slave system interface when the PCIe controller experiences an erroneous completion (UR, CA and CT) from an external completer for its outbound non-posted request, which will result in SError and crash the kernel directly. This patch change back it to the default behavior to increase the robustness of the kernel. In the default behavior, it always sends an OKAY response to the internal AXI slave interface when the controller gets these erroneous completions. And the AER driver will report and try to recover these errors. Signed-off-by: Hou Zhiqiang --- drivers/pci/controller/dwc/pci-layerscape.c | 11 --- 1 file changed, 11 deletions(-) diff --git a/drivers/pci/controller/dwc/pci-layerscape.c b/drivers/pci/controller/dwc/pci-layerscape.c index f24f79a70d9a..e92ab8a77046 100644 --- a/drivers/pci/controller/dwc/pci-layerscape.c +++ b/drivers/pci/controller/dwc/pci-layerscape.c @@ -30,8 +30,6 @@ /* PEX Internal Configuration Registers */ #define PCIE_STRFMR1 0x71c /* Symbol Timer & Filter Mask Register1 */ -#define PCIE_ABSERR0x8d0 /* Bridge Slave Error Response Register */ -#define PCIE_ABSERR_SETTING0x9401 /* Forward error of non-posted request */ #define PCIE_IATU_NUM 6 @@ -123,14 +121,6 @@ static int ls_pcie_link_up(struct dw_pcie *pci) return 1; } -/* Forward error response of outbound non-posted requests */ -static void ls_pcie_fix_error_response(struct ls_pcie *pcie) -{ - struct dw_pcie *pci = pcie->pci; - - iowrite32(PCIE_ABSERR_SETTING, pci->dbi_base + PCIE_ABSERR); -} - static int ls_pcie_host_init(struct pcie_port *pp) { struct dw_pcie *pci = to_dw_pcie_from_pp(pp); @@ -142,7 +132,6 @@ static int ls_pcie_host_init(struct pcie_port *pp) * dw_pcie_setup_rc() will reconfigure the outbound windows. */ ls_pcie_disable_outbound_atus(pcie); - ls_pcie_fix_error_response(pcie); dw_pcie_dbi_ro_wr_en(pci); ls_pcie_clear_multifunction(pcie); -- 2.17.1
[PATCHv8 03/12] PCI: designware-ep: Move the function of getting MSI capability forward
From: Xiaowei Bao Move the function of getting MSI capability to the front of init function, because the init function of the EP platform driver will use the return value by the function of getting MSI capability. Signed-off-by: Xiaowei Bao Signed-off-by: Hou Zhiqiang Reviewed-by: Andrew Murray --- V8: - No change. drivers/pci/controller/dwc/pcie-designware-ep.c | 8 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c index 5ae87e8ffb85..25767a334259 100644 --- a/drivers/pci/controller/dwc/pcie-designware-ep.c +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c @@ -582,10 +582,6 @@ int dw_pcie_ep_init_complete(struct dw_pcie_ep *ep) return -EIO; } - ep->msi_cap = dw_pcie_find_capability(pci, PCI_CAP_ID_MSI); - - ep->msix_cap = dw_pcie_find_capability(pci, PCI_CAP_ID_MSIX); - offset = dw_pcie_ep_find_ext_capability(pci, PCI_EXT_CAP_ID_REBAR); dw_pcie_dbi_ro_wr_en(pci); @@ -677,6 +673,10 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep) if (ret < 0) epc->max_functions = 1; + ep->msi_cap = dw_pcie_find_capability(pci, PCI_CAP_ID_MSI); + + ep->msix_cap = dw_pcie_find_capability(pci, PCI_CAP_ID_MSIX); + if (ep->ops->ep_init) ep->ops->ep_init(ep); -- 2.17.1
[PATCHv8 01/12] PCI: designware-ep: Add multiple PFs support for DWC
From: Xiaowei Bao Add multiple PFs support for DWC, due to different PF have different config space, we use func_conf_select callback function to access the different PF's config space, the different chip company need to implement this callback function when use the DWC IP core and intend to support multiple PFs feature. Signed-off-by: Xiaowei Bao Signed-off-by: Hou Zhiqiang Reviewed-by: Rob Herring Acked-by: Gustavo Pimentel --- V8: - No change. .../pci/controller/dwc/pcie-designware-ep.c | 125 -- drivers/pci/controller/dwc/pcie-designware.c | 59 ++--- drivers/pci/controller/dwc/pcie-designware.h | 18 ++- 3 files changed, 143 insertions(+), 59 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c index 05415a82e9f4..500d4ca04947 100644 --- a/drivers/pci/controller/dwc/pcie-designware-ep.c +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c @@ -30,12 +30,26 @@ void dw_pcie_ep_init_notify(struct dw_pcie_ep *ep) } EXPORT_SYMBOL_GPL(dw_pcie_ep_init_notify); -static void __dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar, - int flags) +static unsigned int dw_pcie_ep_func_select(struct dw_pcie_ep *ep, u8 func_no) +{ + unsigned int func_offset = 0; + + if (ep->ops->func_conf_select) + func_offset = ep->ops->func_conf_select(ep, func_no); + + return func_offset; +} + +static void __dw_pcie_ep_reset_bar(struct dw_pcie *pci, u8 func_no, + enum pci_barno bar, int flags) { u32 reg; + unsigned int func_offset = 0; + struct dw_pcie_ep *ep = >ep; + + func_offset = dw_pcie_ep_func_select(ep, func_no); - reg = PCI_BASE_ADDRESS_0 + (4 * bar); + reg = func_offset + PCI_BASE_ADDRESS_0 + (4 * bar); dw_pcie_dbi_ro_wr_en(pci); dw_pcie_writel_dbi2(pci, reg, 0x0); dw_pcie_writel_dbi(pci, reg, 0x0); @@ -48,7 +62,12 @@ static void __dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar, void dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar) { - __dw_pcie_ep_reset_bar(pci, bar, 0); + u8 func_no, funcs; + + funcs = pci->ep.epc->max_functions; + + for (func_no = 0; func_no < funcs; func_no++) + __dw_pcie_ep_reset_bar(pci, func_no, bar, 0); } static int dw_pcie_ep_write_header(struct pci_epc *epc, u8 func_no, @@ -56,28 +75,31 @@ static int dw_pcie_ep_write_header(struct pci_epc *epc, u8 func_no, { struct dw_pcie_ep *ep = epc_get_drvdata(epc); struct dw_pcie *pci = to_dw_pcie_from_ep(ep); + unsigned int func_offset = 0; + + func_offset = dw_pcie_ep_func_select(ep, func_no); dw_pcie_dbi_ro_wr_en(pci); - dw_pcie_writew_dbi(pci, PCI_VENDOR_ID, hdr->vendorid); - dw_pcie_writew_dbi(pci, PCI_DEVICE_ID, hdr->deviceid); - dw_pcie_writeb_dbi(pci, PCI_REVISION_ID, hdr->revid); - dw_pcie_writeb_dbi(pci, PCI_CLASS_PROG, hdr->progif_code); - dw_pcie_writew_dbi(pci, PCI_CLASS_DEVICE, + dw_pcie_writew_dbi(pci, func_offset + PCI_VENDOR_ID, hdr->vendorid); + dw_pcie_writew_dbi(pci, func_offset + PCI_DEVICE_ID, hdr->deviceid); + dw_pcie_writeb_dbi(pci, func_offset + PCI_REVISION_ID, hdr->revid); + dw_pcie_writeb_dbi(pci, func_offset + PCI_CLASS_PROG, hdr->progif_code); + dw_pcie_writew_dbi(pci, func_offset + PCI_CLASS_DEVICE, hdr->subclass_code | hdr->baseclass_code << 8); - dw_pcie_writeb_dbi(pci, PCI_CACHE_LINE_SIZE, + dw_pcie_writeb_dbi(pci, func_offset + PCI_CACHE_LINE_SIZE, hdr->cache_line_size); - dw_pcie_writew_dbi(pci, PCI_SUBSYSTEM_VENDOR_ID, + dw_pcie_writew_dbi(pci, func_offset + PCI_SUBSYSTEM_VENDOR_ID, hdr->subsys_vendor_id); - dw_pcie_writew_dbi(pci, PCI_SUBSYSTEM_ID, hdr->subsys_id); - dw_pcie_writeb_dbi(pci, PCI_INTERRUPT_PIN, + dw_pcie_writew_dbi(pci, func_offset + PCI_SUBSYSTEM_ID, hdr->subsys_id); + dw_pcie_writeb_dbi(pci, func_offset + PCI_INTERRUPT_PIN, hdr->interrupt_pin); dw_pcie_dbi_ro_wr_dis(pci); return 0; } -static int dw_pcie_ep_inbound_atu(struct dw_pcie_ep *ep, enum pci_barno bar, - dma_addr_t cpu_addr, +static int dw_pcie_ep_inbound_atu(struct dw_pcie_ep *ep, u8 func_no, + enum pci_barno bar, dma_addr_t cpu_addr, enum dw_pcie_as_type as_type) { int ret; @@ -90,7 +112,7 @@ static int dw_pcie_ep_inbound_atu(struct dw_pcie_ep *ep, enum pci_barno bar, return -EINVAL; } - ret = dw_pcie_prog_inbound_atu(pci, free_win, bar, cpu_addr, + ret = dw_pcie_prog_inbound_atu(pci, func_no, free_win, bar, cpu_addr, as_type); if
[PATCHv8 02/12] PCI: designware-ep: Add the doorbell mode of MSI-X in EP mode
From: Xiaowei Bao Add the doorbell mode of MSI-X in DWC EP driver. Signed-off-by: Xiaowei Bao Signed-off-by: Hou Zhiqiang Reviewed-by: Andrew Murray --- V8: - Add msix cap check. .../pci/controller/dwc/pcie-designware-ep.c | 19 +++ drivers/pci/controller/dwc/pcie-designware.h | 12 2 files changed, 31 insertions(+) diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c index 500d4ca04947..5ae87e8ffb85 100644 --- a/drivers/pci/controller/dwc/pcie-designware-ep.c +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c @@ -473,6 +473,25 @@ int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no, return 0; } +int dw_pcie_ep_raise_msix_irq_doorbell(struct dw_pcie_ep *ep, u8 func_no, + u16 interrupt_num) +{ + struct dw_pcie *pci = to_dw_pcie_from_ep(ep); + struct dw_pcie_ep_func *ep_func; + u32 msg_data; + + ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no); + if (!ep_func || !ep_func->msix_cap) + return -EINVAL; + + msg_data = (func_no << PCIE_MSIX_DOORBELL_PF_SHIFT) | + (interrupt_num - 1); + + dw_pcie_writel_dbi(pci, PCIE_MSIX_DOORBELL, msg_data); + + return 0; +} + int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no, u16 interrupt_num) { diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index 32102ebc5c37..4b75b798de98 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -105,6 +105,9 @@ #define PCIE_MISC_CONTROL_1_OFF0x8BC #define PCIE_DBI_RO_WR_EN BIT(0) +#define PCIE_MSIX_DOORBELL 0x948 +#define PCIE_MSIX_DOORBELL_PF_SHIFT24 + #define PCIE_PL_CHK_REG_CONTROL_STATUS 0xB20 #define PCIE_PL_CHK_REG_CHK_REG_START BIT(0) #define PCIE_PL_CHK_REG_CHK_REG_CONTINUOUS BIT(1) @@ -414,6 +417,8 @@ int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no, u8 interrupt_num); int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no, u16 interrupt_num); +int dw_pcie_ep_raise_msix_irq_doorbell(struct dw_pcie_ep *ep, u8 func_no, + u16 interrupt_num); void dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar); #else static inline void dw_pcie_ep_linkup(struct dw_pcie_ep *ep) @@ -455,6 +460,13 @@ static inline int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no, return 0; } +static inline int dw_pcie_ep_raise_msix_irq_doorbell(struct dw_pcie_ep *ep, +u8 func_no, +u16 interrupt_num) +{ + return 0; +} + static inline void dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar) { } -- 2.17.1
[PATCHv8 00/12]PCI: dwc: Add the multiple PF support for DWC and Layerscape
From: Hou Zhiqiang Add the PCIe EP multiple PF support for DWC and Layerscape, and use a list to manage the PFs of each PCIe controller; add the doorbell MSIX function for DWC; and refactor the Layerscape EP driver due to some difference in Layercape platforms PCIe integration. Rebased this series against pci/dwc branch of git tree: https://git.kernel.org/pub/scm/linux/kernel/git/lpieralisi/pci.git Hou Zhiqiang (1): misc: pci_endpoint_test: Add driver data for Layerscape PCIe controllers Xiaowei Bao (11): PCI: designware-ep: Add multiple PFs support for DWC PCI: designware-ep: Add the doorbell mode of MSI-X in EP mode PCI: designware-ep: Move the function of getting MSI capability forward PCI: designware-ep: Modify MSI and MSIX CAP way of finding dt-bindings: pci: layerscape-pci: Add compatible strings for ls1088a and ls2088a PCI: layerscape: Fix some format issue of the code PCI: layerscape: Modify the way of getting capability with different PEX PCI: layerscape: Modify the MSIX to the doorbell mode PCI: layerscape: Add EP mode support for ls1088a and ls2088a arm64: dts: layerscape: Add PCIe EP node for ls1088a misc: pci_endpoint_test: Add LS1088a in pci_device_id table .../bindings/pci/layerscape-pci.txt | 2 + .../arm64/boot/dts/freescale/fsl-ls1088a.dtsi | 31 +++ drivers/misc/pci_endpoint_test.c | 8 +- .../pci/controller/dwc/pci-layerscape-ep.c| 100 +-- .../pci/controller/dwc/pcie-designware-ep.c | 245 ++ drivers/pci/controller/dwc/pcie-designware.c | 59 +++-- drivers/pci/controller/dwc/pcie-designware.h | 48 +++- 7 files changed, 397 insertions(+), 96 deletions(-) -- 2.17.1
[PATCHv8 05/12] dt-bindings: pci: layerscape-pci: Add compatible strings for ls1088a and ls2088a
From: Xiaowei Bao Add compatible strings for ls1088a and ls2088a. Signed-off-by: Xiaowei Bao Signed-off-by: Hou Zhiqiang Acked-by: Rob Herring --- V8: - No change. Documentation/devicetree/bindings/pci/layerscape-pci.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/pci/layerscape-pci.txt b/Documentation/devicetree/bindings/pci/layerscape-pci.txt index 99a386ea691c..daa99f7d4c3f 100644 --- a/Documentation/devicetree/bindings/pci/layerscape-pci.txt +++ b/Documentation/devicetree/bindings/pci/layerscape-pci.txt @@ -24,6 +24,8 @@ Required properties: "fsl,ls1028a-pcie" EP mode: "fsl,ls1046a-pcie-ep", "fsl,ls-pcie-ep" + "fsl,ls1088a-pcie-ep", "fsl,ls-pcie-ep" + "fsl,ls2088a-pcie-ep", "fsl,ls-pcie-ep" - reg: base addresses and lengths of the PCIe controller register blocks. - interrupts: A list of interrupt outputs of the controller. Must contain an entry for each entry in the interrupt-names property. -- 2.17.1
[PATCHv8 07/12] PCI: layerscape: Modify the way of getting capability with different PEX
From: Xiaowei Bao The different PCIe controller in one board may be have different capability of MSI or MSIX, so change the way of getting the MSI capability, make it more flexible. Signed-off-by: Xiaowei Bao Signed-off-by: Hou Zhiqiang Reviewed-by: Rob Herring --- V8: - No change. .../pci/controller/dwc/pci-layerscape-ep.c| 31 ++- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/drivers/pci/controller/dwc/pci-layerscape-ep.c b/drivers/pci/controller/dwc/pci-layerscape-ep.c index 0691d9ad1356..9601f9c09cb1 100644 --- a/drivers/pci/controller/dwc/pci-layerscape-ep.c +++ b/drivers/pci/controller/dwc/pci-layerscape-ep.c @@ -22,6 +22,7 @@ struct ls_pcie_ep { struct dw_pcie *pci; + struct pci_epc_features *ls_epc; }; #define to_ls_pcie_ep(x) dev_get_drvdata((x)->dev) @@ -40,26 +41,31 @@ static const struct of_device_id ls_pcie_ep_of_match[] = { { }, }; -static const struct pci_epc_features ls_pcie_epc_features = { - .linkup_notifier = false, - .msi_capable = true, - .msix_capable = false, - .bar_fixed_64bit = (1 << BAR_2) | (1 << BAR_4), -}; - static const struct pci_epc_features* ls_pcie_ep_get_features(struct dw_pcie_ep *ep) { - return _pcie_epc_features; + struct dw_pcie *pci = to_dw_pcie_from_ep(ep); + struct ls_pcie_ep *pcie = to_ls_pcie_ep(pci); + + return pcie->ls_epc; } static void ls_pcie_ep_init(struct dw_pcie_ep *ep) { struct dw_pcie *pci = to_dw_pcie_from_ep(ep); + struct ls_pcie_ep *pcie = to_ls_pcie_ep(pci); + struct dw_pcie_ep_func *ep_func; enum pci_barno bar; + ep_func = dw_pcie_ep_get_func_from_ep(ep, 0); + if (!ep_func) + return; + for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) dw_pcie_ep_reset_bar(pci, bar); + + pcie->ls_epc->msi_capable = ep_func->msi_cap ? true : false; + pcie->ls_epc->msix_capable = ep_func->msix_cap ? true : false; } static int ls_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no, @@ -119,6 +125,7 @@ static int __init ls_pcie_ep_probe(struct platform_device *pdev) struct device *dev = >dev; struct dw_pcie *pci; struct ls_pcie_ep *pcie; + struct pci_epc_features *ls_epc; struct resource *dbi_base; int ret; @@ -130,6 +137,10 @@ static int __init ls_pcie_ep_probe(struct platform_device *pdev) if (!pci) return -ENOMEM; + ls_epc = devm_kzalloc(dev, sizeof(*ls_epc), GFP_KERNEL); + if (!ls_epc) + return -ENOMEM; + dbi_base = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs"); pci->dbi_base = devm_pci_remap_cfg_resource(dev, dbi_base); if (IS_ERR(pci->dbi_base)) @@ -140,6 +151,10 @@ static int __init ls_pcie_ep_probe(struct platform_device *pdev) pci->ops = _pcie_ep_ops; pcie->pci = pci; + ls_epc->bar_fixed_64bit = (1 << BAR_2) | (1 << BAR_4), + + pcie->ls_epc = ls_epc; + platform_set_drvdata(pdev, pcie); ret = ls_add_pcie_ep(pcie, pdev); -- 2.17.1
[PATCHv8 12/12] misc: pci_endpoint_test: Add driver data for Layerscape PCIe controllers
From: Hou Zhiqiang The commit 0a121f9bc3f5 ("misc: pci_endpoint_test: Use streaming DMA APIs for buffer allocation") changed to use streaming DMA APIs, however, dma_map_single() might not return a 4KB aligned address, so add the default_data as driver data for Layerscape PCIe controllers to make it 4KB aligned. Signed-off-by: Hou Zhiqiang Acked-by: Rob Herring --- V8: - No change. drivers/misc/pci_endpoint_test.c | 8 ++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/misc/pci_endpoint_test.c b/drivers/misc/pci_endpoint_test.c index 4a17f08de60f..70a790cd14c5 100644 --- a/drivers/misc/pci_endpoint_test.c +++ b/drivers/misc/pci_endpoint_test.c @@ -946,8 +946,12 @@ static const struct pci_device_id pci_endpoint_test_tbl[] = { { PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_DRA72x), .driver_data = (kernel_ulong_t)_data, }, - { PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, 0x81c0) }, - { PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, PCI_DEVICE_ID_LS1088A) }, + { PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, 0x81c0), + .driver_data = (kernel_ulong_t)_data, + }, + { PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, PCI_DEVICE_ID_LS1088A), + .driver_data = (kernel_ulong_t)_data, + }, { PCI_DEVICE_DATA(SYNOPSYS, EDDA, NULL) }, { PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_AM654), .driver_data = (kernel_ulong_t)_data -- 2.17.1
[PATCHv8 06/12] PCI: layerscape: Fix some format issue of the code
From: Xiaowei Bao Fix some format issue of the code in EP driver. Signed-off-by: Xiaowei Bao Signed-off-by: Hou Zhiqiang Reviewed-by: Andrew Murray --- V8: - No change. drivers/pci/controller/dwc/pci-layerscape-ep.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/pci/controller/dwc/pci-layerscape-ep.c b/drivers/pci/controller/dwc/pci-layerscape-ep.c index 0d151cead1b7..0691d9ad1356 100644 --- a/drivers/pci/controller/dwc/pci-layerscape-ep.c +++ b/drivers/pci/controller/dwc/pci-layerscape-ep.c @@ -63,7 +63,7 @@ static void ls_pcie_ep_init(struct dw_pcie_ep *ep) } static int ls_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no, - enum pci_epc_irq_type type, u16 interrupt_num) + enum pci_epc_irq_type type, u16 interrupt_num) { struct dw_pcie *pci = to_dw_pcie_from_ep(ep); @@ -87,7 +87,7 @@ static const struct dw_pcie_ep_ops pcie_ep_ops = { }; static int __init ls_add_pcie_ep(struct ls_pcie_ep *pcie, - struct platform_device *pdev) +struct platform_device *pdev) { struct dw_pcie *pci = pcie->pci; struct device *dev = pci->dev; -- 2.17.1
[PATCHv8 10/12] arm64: dts: layerscape: Add PCIe EP node for ls1088a
From: Xiaowei Bao Add PCIe EP node for ls1088a to support EP mode. Signed-off-by: Xiaowei Bao Signed-off-by: Hou Zhiqiang Reviewed-by: Andrew Murray --- V8: - s/pcie_ep/pcie-ep. .../arm64/boot/dts/freescale/fsl-ls1088a.dtsi | 31 +++ 1 file changed, 31 insertions(+) diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi index 169f4742ae3b..f21dd143ab6d 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi @@ -499,6 +499,17 @@ status = "disabled"; }; + pcie-ep@340 { + compatible = "fsl,ls1088a-pcie-ep","fsl,ls-pcie-ep"; + reg = <0x00 0x0340 0x0 0x0010 + 0x20 0x 0x8 0x>; + reg-names = "regs", "addr_space"; + num-ib-windows = <24>; + num-ob-windows = <128>; + max-functions = /bits/ 8 <2>; + status = "disabled"; + }; + pcie@350 { compatible = "fsl,ls1088a-pcie"; reg = <0x00 0x0350 0x0 0x0010 /* controller registers */ @@ -525,6 +536,16 @@ status = "disabled"; }; + pcie-ep@350 { + compatible = "fsl,ls1088a-pcie-ep","fsl,ls-pcie-ep"; + reg = <0x00 0x0350 0x0 0x0010 + 0x28 0x 0x8 0x>; + reg-names = "regs", "addr_space"; + num-ib-windows = <6>; + num-ob-windows = <8>; + status = "disabled"; + }; + pcie@360 { compatible = "fsl,ls1088a-pcie"; reg = <0x00 0x0360 0x0 0x0010 /* controller registers */ @@ -551,6 +572,16 @@ status = "disabled"; }; + pcie-ep@360 { + compatible = "fsl,ls1088a-pcie-ep","fsl,ls-pcie-ep"; + reg = <0x00 0x0360 0x0 0x0010 + 0x30 0x 0x8 0x>; + reg-names = "regs", "addr_space"; + num-ib-windows = <6>; + num-ob-windows = <8>; + status = "disabled"; + }; + smmu: iommu@500 { compatible = "arm,mmu-500"; reg = <0 0x500 0 0x80>; -- 2.17.1
[PATCHv8 08/12] PCI: layerscape: Modify the MSIX to the doorbell mode
From: Xiaowei Bao dw_pcie_ep_raise_msix_irq was never called in the exisitng driver before, because the ls1046a platform don't support the MSIX feature and msix_capable was always set to false. Now that add the ls1088a platform with MSIX support, use the doorbell method to support the MSIX feature. Signed-off-by: Xiaowei Bao Signed-off-by: Hou Zhiqiang Reviewed-by: Andrew Murray --- V8: - No change. drivers/pci/controller/dwc/pci-layerscape-ep.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/pci/controller/dwc/pci-layerscape-ep.c b/drivers/pci/controller/dwc/pci-layerscape-ep.c index 9601f9c09cb1..bfab1c694f00 100644 --- a/drivers/pci/controller/dwc/pci-layerscape-ep.c +++ b/drivers/pci/controller/dwc/pci-layerscape-ep.c @@ -79,7 +79,8 @@ static int ls_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no, case PCI_EPC_IRQ_MSI: return dw_pcie_ep_raise_msi_irq(ep, func_no, interrupt_num); case PCI_EPC_IRQ_MSIX: - return dw_pcie_ep_raise_msix_irq(ep, func_no, interrupt_num); + return dw_pcie_ep_raise_msix_irq_doorbell(ep, func_no, + interrupt_num); default: dev_err(pci->dev, "UNKNOWN IRQ type\n"); return -EINVAL; -- 2.17.1
[PATCHv8 04/12] PCI: designware-ep: Modify MSI and MSIX CAP way of finding
From: Xiaowei Bao Each PF of EP device should have its own MSI or MSIX capabitily struct, so create a dw_pcie_ep_func struct and move the msi_cap and msix_cap to this struct from dw_pcie_ep, and manage the PFs via a list. Signed-off-by: Xiaowei Bao Signed-off-by: Hou Zhiqiang --- V8: - Put the ep_func and ep_func->msi_cap pointer checking in one line. .../pci/controller/dwc/pcie-designware-ep.c | 121 +++--- drivers/pci/controller/dwc/pcie-designware.h | 18 ++- 2 files changed, 118 insertions(+), 21 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c index 25767a334259..ad7da4ea43a5 100644 --- a/drivers/pci/controller/dwc/pcie-designware-ep.c +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c @@ -30,6 +30,19 @@ void dw_pcie_ep_init_notify(struct dw_pcie_ep *ep) } EXPORT_SYMBOL_GPL(dw_pcie_ep_init_notify); +struct dw_pcie_ep_func * +dw_pcie_ep_get_func_from_ep(struct dw_pcie_ep *ep, u8 func_no) +{ + struct dw_pcie_ep_func *ep_func; + + list_for_each_entry(ep_func, >func_list, list) { + if (ep_func->func_no == func_no) + return ep_func; + } + + return NULL; +} + static unsigned int dw_pcie_ep_func_select(struct dw_pcie_ep *ep, u8 func_no) { unsigned int func_offset = 0; @@ -70,6 +83,47 @@ void dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar) __dw_pcie_ep_reset_bar(pci, func_no, bar, 0); } +static u8 __dw_pcie_ep_find_next_cap(struct dw_pcie_ep *ep, u8 func_no, + u8 cap_ptr, u8 cap) +{ + struct dw_pcie *pci = to_dw_pcie_from_ep(ep); + unsigned int func_offset = 0; + u8 cap_id, next_cap_ptr; + u16 reg; + + if (!cap_ptr) + return 0; + + func_offset = dw_pcie_ep_func_select(ep, func_no); + + reg = dw_pcie_readw_dbi(pci, func_offset + cap_ptr); + cap_id = (reg & 0x00ff); + + if (cap_id > PCI_CAP_ID_MAX) + return 0; + + if (cap_id == cap) + return cap_ptr; + + next_cap_ptr = (reg & 0xff00) >> 8; + return __dw_pcie_ep_find_next_cap(ep, func_no, next_cap_ptr, cap); +} + +static u8 dw_pcie_ep_find_capability(struct dw_pcie_ep *ep, u8 func_no, u8 cap) +{ + struct dw_pcie *pci = to_dw_pcie_from_ep(ep); + unsigned int func_offset = 0; + u8 next_cap_ptr; + u16 reg; + + func_offset = dw_pcie_ep_func_select(ep, func_no); + + reg = dw_pcie_readw_dbi(pci, func_offset + PCI_CAPABILITY_LIST); + next_cap_ptr = (reg & 0x00ff); + + return __dw_pcie_ep_find_next_cap(ep, func_no, next_cap_ptr, cap); +} + static int dw_pcie_ep_write_header(struct pci_epc *epc, u8 func_no, struct pci_epf_header *hdr) { @@ -259,13 +313,15 @@ static int dw_pcie_ep_get_msi(struct pci_epc *epc, u8 func_no) struct dw_pcie *pci = to_dw_pcie_from_ep(ep); u32 val, reg; unsigned int func_offset = 0; + struct dw_pcie_ep_func *ep_func; - if (!ep->msi_cap) + ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no); + if (!ep_func || !ep_func->msi_cap) return -EINVAL; func_offset = dw_pcie_ep_func_select(ep, func_no); - reg = ep->msi_cap + func_offset + PCI_MSI_FLAGS; + reg = ep_func->msi_cap + func_offset + PCI_MSI_FLAGS; val = dw_pcie_readw_dbi(pci, reg); if (!(val & PCI_MSI_FLAGS_ENABLE)) return -EINVAL; @@ -281,13 +337,15 @@ static int dw_pcie_ep_set_msi(struct pci_epc *epc, u8 func_no, u8 interrupts) struct dw_pcie *pci = to_dw_pcie_from_ep(ep); u32 val, reg; unsigned int func_offset = 0; + struct dw_pcie_ep_func *ep_func; - if (!ep->msi_cap) + ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no); + if (!ep_func || !ep_func->msi_cap) return -EINVAL; func_offset = dw_pcie_ep_func_select(ep, func_no); - reg = ep->msi_cap + func_offset + PCI_MSI_FLAGS; + reg = ep_func->msi_cap + func_offset + PCI_MSI_FLAGS; val = dw_pcie_readw_dbi(pci, reg); val &= ~PCI_MSI_FLAGS_QMASK; val |= (interrupts << 1) & PCI_MSI_FLAGS_QMASK; @@ -304,13 +362,15 @@ static int dw_pcie_ep_get_msix(struct pci_epc *epc, u8 func_no) struct dw_pcie *pci = to_dw_pcie_from_ep(ep); u32 val, reg; unsigned int func_offset = 0; + struct dw_pcie_ep_func *ep_func; - if (!ep->msix_cap) + ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no); + if (!ep_func || !ep_func->msix_cap) return -EINVAL; func_offset = dw_pcie_ep_func_select(ep, func_no); - reg = ep->msix_cap + func_offset + PCI_MSIX_FLAGS; + reg = ep_func->msix_cap + func_offset + PCI_MSIX_FLAGS; val = dw_pcie_readw_dbi(pci, reg); if (!(val & PCI_MSIX_FLAGS_ENABLE)) return -EINVAL; @@
[PATCHv8 11/12] misc: pci_endpoint_test: Add LS1088a in pci_device_id table
From: Xiaowei Bao Add LS1088a in pci_device_id table so that pci-epf-test can be used for testing PCIe EP in LS1088a. Signed-off-by: Xiaowei Bao Signed-off-by: Hou Zhiqiang Reviewed-by: Andrew Murray --- V8: - No change. drivers/misc/pci_endpoint_test.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/misc/pci_endpoint_test.c b/drivers/misc/pci_endpoint_test.c index e060796f9caa..4a17f08de60f 100644 --- a/drivers/misc/pci_endpoint_test.c +++ b/drivers/misc/pci_endpoint_test.c @@ -70,6 +70,7 @@ #define PCI_DEVICE_ID_TI_J721E 0xb00d #define PCI_DEVICE_ID_TI_AM654 0xb00c +#define PCI_DEVICE_ID_LS1088A 0x80c0 #define is_am654_pci_dev(pdev) \ ((pdev)->device == PCI_DEVICE_ID_TI_AM654) @@ -946,6 +947,7 @@ static const struct pci_device_id pci_endpoint_test_tbl[] = { .driver_data = (kernel_ulong_t)_data, }, { PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, 0x81c0) }, + { PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, PCI_DEVICE_ID_LS1088A) }, { PCI_DEVICE_DATA(SYNOPSYS, EDDA, NULL) }, { PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_AM654), .driver_data = (kernel_ulong_t)_data -- 2.17.1
[PATCHv8 09/12] PCI: layerscape: Add EP mode support for ls1088a and ls2088a
From: Xiaowei Bao Add PCIe EP mode support for ls1088a and ls2088a, there are some difference between LS1 and LS2 platform, so refactor the code of the EP driver. Signed-off-by: Xiaowei Bao Signed-off-by: Hou Zhiqiang Reviewed-by: Rob Herring --- V8: - No change. .../pci/controller/dwc/pci-layerscape-ep.c| 72 ++- 1 file changed, 53 insertions(+), 19 deletions(-) diff --git a/drivers/pci/controller/dwc/pci-layerscape-ep.c b/drivers/pci/controller/dwc/pci-layerscape-ep.c index bfab1c694f00..84206f265e54 100644 --- a/drivers/pci/controller/dwc/pci-layerscape-ep.c +++ b/drivers/pci/controller/dwc/pci-layerscape-ep.c @@ -20,27 +20,29 @@ #define PCIE_DBI2_OFFSET 0x1000 /* DBI2 base address*/ -struct ls_pcie_ep { - struct dw_pcie *pci; - struct pci_epc_features *ls_epc; +#define to_ls_pcie_ep(x) dev_get_drvdata((x)->dev) + +struct ls_pcie_ep_drvdata { + u32 func_offset; + const struct dw_pcie_ep_ops *ops; + const struct dw_pcie_ops*dw_pcie_ops; }; -#define to_ls_pcie_ep(x) dev_get_drvdata((x)->dev) +struct ls_pcie_ep { + struct dw_pcie *pci; + struct pci_epc_features *ls_epc; + const struct ls_pcie_ep_drvdata *drvdata; +}; static int ls_pcie_establish_link(struct dw_pcie *pci) { return 0; } -static const struct dw_pcie_ops ls_pcie_ep_ops = { +static const struct dw_pcie_ops dw_ls_pcie_ep_ops = { .start_link = ls_pcie_establish_link, }; -static const struct of_device_id ls_pcie_ep_of_match[] = { - { .compatible = "fsl,ls-pcie-ep",}, - { }, -}; - static const struct pci_epc_features* ls_pcie_ep_get_features(struct dw_pcie_ep *ep) { @@ -87,10 +89,39 @@ static int ls_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no, } } -static const struct dw_pcie_ep_ops pcie_ep_ops = { +static unsigned int ls_pcie_ep_func_conf_select(struct dw_pcie_ep *ep, + u8 func_no) +{ + struct dw_pcie *pci = to_dw_pcie_from_ep(ep); + struct ls_pcie_ep *pcie = to_ls_pcie_ep(pci); + + WARN_ON(func_no && !pcie->drvdata->func_offset); + return pcie->drvdata->func_offset * func_no; +} + +static const struct dw_pcie_ep_ops ls_pcie_ep_ops = { .ep_init = ls_pcie_ep_init, .raise_irq = ls_pcie_ep_raise_irq, .get_features = ls_pcie_ep_get_features, + .func_conf_select = ls_pcie_ep_func_conf_select, +}; + +static const struct ls_pcie_ep_drvdata ls1_ep_drvdata = { + .ops = _pcie_ep_ops, + .dw_pcie_ops = _ls_pcie_ep_ops, +}; + +static const struct ls_pcie_ep_drvdata ls2_ep_drvdata = { + .func_offset = 0x2, + .ops = _pcie_ep_ops, + .dw_pcie_ops = _ls_pcie_ep_ops, +}; + +static const struct of_device_id ls_pcie_ep_of_match[] = { + { .compatible = "fsl,ls1046a-pcie-ep", .data = _ep_drvdata }, + { .compatible = "fsl,ls1088a-pcie-ep", .data = _ep_drvdata }, + { .compatible = "fsl,ls2088a-pcie-ep", .data = _ep_drvdata }, + { }, }; static int __init ls_add_pcie_ep(struct ls_pcie_ep *pcie, @@ -103,7 +134,7 @@ static int __init ls_add_pcie_ep(struct ls_pcie_ep *pcie, int ret; ep = >ep; - ep->ops = _ep_ops; + ep->ops = pcie->drvdata->ops; res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "addr_space"); if (!res) @@ -142,20 +173,23 @@ static int __init ls_pcie_ep_probe(struct platform_device *pdev) if (!ls_epc) return -ENOMEM; - dbi_base = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs"); - pci->dbi_base = devm_pci_remap_cfg_resource(dev, dbi_base); - if (IS_ERR(pci->dbi_base)) - return PTR_ERR(pci->dbi_base); + pcie->drvdata = of_device_get_match_data(dev); - pci->dbi_base2 = pci->dbi_base + PCIE_DBI2_OFFSET; pci->dev = dev; - pci->ops = _pcie_ep_ops; - pcie->pci = pci; + pci->ops = pcie->drvdata->dw_pcie_ops; ls_epc->bar_fixed_64bit = (1 << BAR_2) | (1 << BAR_4), + pcie->pci = pci; pcie->ls_epc = ls_epc; + dbi_base = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs"); + pci->dbi_base = devm_pci_remap_cfg_resource(dev, dbi_base); + if (IS_ERR(pci->dbi_base)) + return PTR_ERR(pci->dbi_base); + + pci->dbi_base2 = pci->dbi_base + PCIE_DBI2_OFFSET; + platform_set_drvdata(pdev, pcie); ret = ls_add_pcie_ep(pcie, pdev); -- 2.17.1
[PATCH] PCI: dwc: Added link up check in map_bus of dw_child_pcie_ops
From: Hou Zhiqiang On NXP Layerscape platforms, it results in SError in the enumeration of the PCIe controller, which is not connecting with an Endpoint device. And it doesn't make sense to enumerate the Endpoints when the PCIe link is down. So this patch added the link up check to avoid to fire configuration transactions on link down bus. [0.807773] SError Interrupt on CPU2, code 0xbf02 -- SError [0.807775] CPU: 2 PID: 1 Comm: swapper/0 Not tainted 5.9.0-rc5-next-20200914-1-gf965d3ec86fa #67 [0.807776] Hardware name: LS1046A RDB Board (DT) [0.80] pstate: 2085 (nzCv daIf -PAN -UAO BTYPE=--) [0.807778] pc : pci_generic_config_read+0x3c/0xe0 [0.807778] lr : pci_generic_config_read+0x24/0xe0 [0.807779] sp : 80001003b7b0 [0.807780] x29: 80001003b7b0 x28: 80001003ba74 [0.807782] x27: 000971d96800 x26: 00096e77e0a8 [0.807784] x25: 80001003b874 x24: 80001003b924 [0.807786] x23: 0004 x22: [0.807788] x21: x20: 80001003b874 [0.807790] x19: 0004 x18: [0.807791] x17: 00c0 x16: fe0025981840 [0.807793] x15: b94c75b69948 x14: 62203a383634203a [0.807795] x13: 666e6f635f726568 x12: 202c31203d207265 [0.807797] x11: 626d756e3e2d7375 x10: 656877202c307830 [0.807799] x9 : 203d206e66766564 x8 : 0908 [0.807801] x7 : 0908 x6 : 80001090 [0.807802] x5 : 00096e77e080 x4 : [0.807804] x3 : 0003 x2 : 84fa3440ff7e7000 [0.807806] x1 : x0 : 800010034000 [0.807808] Kernel panic - not syncing: Asynchronous SError Interrupt [0.807809] CPU: 2 PID: 1 Comm: swapper/0 Not tainted 5.9.0-rc5-next-20200914-1-gf965d3ec86fa #67 [0.807810] Hardware name: LS1046A RDB Board (DT) [0.807811] Call trace: [0.807812] dump_backtrace+0x0/0x1c0 [0.807813] show_stack+0x18/0x28 [0.807814] dump_stack+0xd8/0x134 [0.807814] panic+0x180/0x398 [0.807815] add_taint+0x0/0xb0 [0.807816] arm64_serror_panic+0x78/0x88 [0.807817] do_serror+0x68/0x180 [0.807818] el1_error+0x84/0x100 [0.807818] pci_generic_config_read+0x3c/0xe0 [0.807819] dw_pcie_rd_other_conf+0x78/0x110 [0.807820] pci_bus_read_config_dword+0x88/0xe8 [0.807821] pci_bus_generic_read_dev_vendor_id+0x30/0x1b0 [0.807822] pci_bus_read_dev_vendor_id+0x4c/0x78 [0.807823] pci_scan_single_device+0x80/0x100 [0.807824] pci_scan_slot+0x38/0x130 [0.807825] pci_scan_child_bus_extend+0x54/0x2a0 [0.807826] pci_scan_child_bus+0x14/0x20 [0.807827] pci_scan_bridge_extend+0x230/0x570 [0.807828] pci_scan_child_bus_extend+0x134/0x2a0 [0.807829] pci_scan_root_bus_bridge+0x64/0xf0 [0.807829] pci_host_probe+0x18/0xc8 [0.807830] dw_pcie_host_init+0x220/0x378 [0.807831] ls_pcie_probe+0x104/0x140 [0.807832] platform_drv_probe+0x54/0xa8 [0.807833] really_probe+0x118/0x3e0 [0.807834] driver_probe_device+0x5c/0xc0 [0.807835] device_driver_attach+0x74/0x80 [0.807835] __driver_attach+0x8c/0xd8 [0.807836] bus_for_each_dev+0x7c/0xd8 [0.807837] driver_attach+0x24/0x30 [0.807838] bus_add_driver+0x154/0x200 [0.807839] driver_register+0x64/0x120 [0.807839] __platform_driver_probe+0x7c/0x148 [0.807840] ls_pcie_driver_init+0x24/0x30 [0.807841] do_one_initcall+0x60/0x1d8 [0.807842] kernel_init_freeable+0x1f4/0x24c [0.807843] kernel_init+0x14/0x118 [0.807843] ret_from_fork+0x10/0x34 [0.807854] SMP: stopping secondary CPUs [0.807855] Kernel Offset: 0x394c6408 from 0x80001000 [0.807856] PHYS_OFFSET: 0x8bfd4000 [0.807856] CPU features: 0x0240022,21806000 [0.807857] Memory Limit: none Fixes: c2b0c098fbd1 ("PCI: dwc: Use generic config accessors") Signed-off-by: Hou Zhiqiang --- drivers/pci/controller/dwc/pcie-designware-host.c | 6 ++ 1 file changed, 6 insertions(+) diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c index c01c9d2fb3f9..e82b518430c5 100644 --- a/drivers/pci/controller/dwc/pcie-designware-host.c +++ b/drivers/pci/controller/dwc/pcie-designware-host.c @@ -442,6 +442,9 @@ static void __iomem *dw_pcie_other_conf_map_bus(struct pci_bus *bus, struct pcie_port *pp = bus->sysdata; struct dw_pcie *pci = to_dw_pcie_from_pp(pp); + if (!dw_pcie_link_up(pci)) + return NULL; + busdev = PCIE_ATU_BUS(bus->number) | PCIE_ATU_DEV(PCI_SLOT(devfn)) | PCIE_ATU_FUNC(PCI_FUNC(devfn)); -- 2.17.1
[PATCH 5/7] dt-bindings: pci: layerscape-pci: Update the description of SCFG property
From: Hou Zhiqiang Update the description of the second entry of 'fsl,pcie-scfg' property, as the LS1043A PCIe controller also has some control registers in SCFG block, while it has 3 controllers. Signed-off-by: Hou Zhiqiang --- Documentation/devicetree/bindings/pci/layerscape-pci.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/pci/layerscape-pci.txt b/Documentation/devicetree/bindings/pci/layerscape-pci.txt index 2236d3f3089b..e992ec712bf6 100644 --- a/Documentation/devicetree/bindings/pci/layerscape-pci.txt +++ b/Documentation/devicetree/bindings/pci/layerscape-pci.txt @@ -31,7 +31,7 @@ Required properties: "intr": The interrupt that is asserted for controller interrupts - fsl,pcie-scfg: Must include two entries. The first entry must be a link to the SCFG device node - The second entry must be '0' or '1' based on physical PCIe controller index. + The second entry is the physical PCIe controller index starting from '0'. This is used to get SCFG PEXN registers - dma-coherent: Indicates that the hardware IP block can ensure the coherency of the data transferred from/to the IP block. This can avoid the software -- 2.17.1
[PATCH 6/7] dts: arm64: ls1043a: Add SCFG phandle for PCIe nodes
From: Hou Zhiqiang The LS1043A PCIe controller has some control registers in SCFG block, so add the SCFG phandle for each PCIe controller DT node. Signed-off-by: Hou Zhiqiang --- arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi index 70e07612da12..30ccf1fdb851 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi @@ -822,6 +822,7 @@ interrupts = <0 118 0x4>, /* controller interrupt */ <0 117 0x4>; /* PME interrupt */ interrupt-names = "intr", "pme"; + fsl,pcie-scfg = < 0>; #address-cells = <3>; #size-cells = <2>; device_type = "pci"; @@ -849,6 +850,7 @@ interrupts = <0 128 0x4>, <0 127 0x4>; interrupt-names = "intr", "pme"; + fsl,pcie-scfg = < 1>; #address-cells = <3>; #size-cells = <2>; device_type = "pci"; @@ -876,6 +878,7 @@ interrupts = <0 162 0x4>, <0 161 0x4>; interrupt-names = "intr", "pme"; + fsl,pcie-scfg = < 2>; #address-cells = <3>; #size-cells = <2>; device_type = "pci"; -- 2.17.1
[PATCH 7/7] PCI: layerscape: Add power management support
From: Hou Zhiqiang Add PME_Turn_Off/PME_TO_Ack handshake sequence, and finally put the PCIe controller into D3 state after the L2/L3 ready state transition process completion. Signed-off-by: Hou Zhiqiang --- drivers/pci/controller/dwc/pci-layerscape.c | 384 ++- drivers/pci/controller/dwc/pcie-designware.h | 1 + 2 files changed, 383 insertions(+), 2 deletions(-) diff --git a/drivers/pci/controller/dwc/pci-layerscape.c b/drivers/pci/controller/dwc/pci-layerscape.c index be404c16bcbe..ca9ea07f77c1 100644 --- a/drivers/pci/controller/dwc/pci-layerscape.c +++ b/drivers/pci/controller/dwc/pci-layerscape.c @@ -3,13 +3,16 @@ * PCIe host controller driver for Freescale Layerscape SoCs * * Copyright (C) 2014 Freescale Semiconductor. + * Copyright 2020 NXP * * Author: Minghuan Lian */ +#include #include #include #include +#include #include #include #include @@ -27,17 +30,66 @@ #define PCIE_ABSERR0x8d0 /* Bridge Slave Error Response Register */ #define PCIE_ABSERR_SETTING0x9401 /* Forward error of non-posted request */ +#define PCIE_PM_SCR0x44 +#define PCIE_PM_SCR_PMEPS_D0 0x0 +#define PCIE_PM_SCR_PMEPS_D3 0x3 + +#define PCIE_LNKCTL0x80 /* PCIe link ctrl Register */ + +/* PF Message Command Register */ +#define LS_PCIE_PF_MCR 0x2c +#define PF_MCR_PTOMR BIT(0) +#define PF_MCR_EXL2S BIT(1) + +/* LS1021A PEXn PM Write Control Register */ +#define SCFG_PEXPMWRCR(idx)(0x5c + (idx) * 0x64) +#define PMXMTTURNOFF BIT(31) +#define SCFG_PEXSFTRSTCR 0x190 +#define PEXSR(idx) BIT(idx) + +/* LS1043A PEX PME control register */ +#define SCFG_PEXPMECR 0x144 +#define PEXPME(idx)BIT(31 - (idx) * 4) + +/* LS1043A PEX LUT debug register */ +#define LS_PCIE_LDBG 0x7fc +#define LDBG_SRBIT(30) +#define LDBG_WEBIT(31) + #define PCIE_IATU_NUM 6 +#define LS_PCIE_IS_L2(v) \ + (((v) & PORT_LOGIC_LTSSM_STATE_MASK) == PORT_LOGIC_LTSSM_STATE_L2) + +struct ls_pcie; + +struct ls_pcie_host_pm_ops { + int (*pm_init)(struct ls_pcie *pcie); + void (*send_turn_off_message)(struct ls_pcie *pcie); + void (*exit_from_l2)(struct ls_pcie *pcie); +}; + struct ls_pcie_drvdata { + const u32 pf_off; + const u32 lut_off; const struct dw_pcie_host_ops *ops; + const struct ls_pcie_host_pm_ops *pm_ops; }; struct ls_pcie { struct dw_pcie *pci; const struct ls_pcie_drvdata *drvdata; + void __iomem *pf_base; + void __iomem *lut_base; + bool big_endian; + bool ep_presence; + bool pm_support; + struct regmap *scfg; + int index; }; +#define ls_pcie_lut_readl_addr(addr) ls_pcie_lut_readl(pcie, addr) +#define ls_pcie_pf_readl_addr(addr)ls_pcie_pf_readl(pcie, addr) #define to_ls_pcie(x) dev_get_drvdata((x)->dev) static bool ls_pcie_is_bridge(struct ls_pcie *pcie) @@ -86,6 +138,208 @@ static void ls_pcie_fix_error_response(struct ls_pcie *pcie) iowrite32(PCIE_ABSERR_SETTING, pci->dbi_base + PCIE_ABSERR); } +static u32 ls_pcie_lut_readl(struct ls_pcie *pcie, u32 off) +{ + if (pcie->big_endian) + return ioread32be(pcie->lut_base + off); + + return ioread32(pcie->lut_base + off); +} + +static void ls_pcie_lut_writel(struct ls_pcie *pcie, u32 off, u32 val) +{ + if (pcie->big_endian) + return iowrite32be(val, pcie->lut_base + off); + + return iowrite32(val, pcie->lut_base + off); + +} + +static u32 ls_pcie_pf_readl(struct ls_pcie *pcie, u32 off) +{ + if (pcie->big_endian) + return ioread32be(pcie->pf_base + off); + + return ioread32(pcie->pf_base + off); +} + +static void ls_pcie_pf_writel(struct ls_pcie *pcie, u32 off, u32 val) +{ + if (pcie->big_endian) + return iowrite32be(val, pcie->pf_base + off); + + return iowrite32(val, pcie->pf_base + off); + +} + +static void ls_pcie_send_turnoff_msg(struct ls_pcie *pcie) +{ + u32 val; + int ret; + + val = ls_pcie_pf_readl(pcie, LS_PCIE_PF_MCR); + val |= PF_MCR_PTOMR; + ls_pcie_pf_writel(pcie, LS_PCIE_PF_MCR, val); + + ret = readx_poll_timeout(ls_pcie_pf_readl_addr, LS_PCIE_PF_MCR, +val, !(val & PF_MCR_PTOMR), 100, 1); + if (ret) + dev_info(pcie->pci->dev, "poll turn off message timeout\n"); +} + +static void ls1021a_pcie_send_turnoff_msg(struct ls_pcie *pcie) +{ + u32 val; + + if (!pcie->scfg) { + dev_dbg(pcie->pci->dev, "SYSCFG is NULL\n"); + return; + } + + /* Send Turn_off message */ + regmap_read(pcie->scfg, SCFG_PEXPMWRCR(pcie->index), ); + val |= PMXMTTURNOFF; + regmap_write(pcie->scfg, SCFG_PEXPMWRCR(pcie->index), val); + + mdelay(10); + + /* Clear Turn_off message */ +
[PATCH 1/7] PCI: dwc: Fix a bug of the case dw_pci->ops is NULL
From: Hou Zhiqiang The dw_pci->ops may be a NULL, and fix it by adding one more check. Signed-off-by: Hou Zhiqiang --- drivers/pci/controller/dwc/pcie-designware.c | 12 ++-- 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c index b723e0cc41fb..bdf8938da9cd 100644 --- a/drivers/pci/controller/dwc/pcie-designware.c +++ b/drivers/pci/controller/dwc/pcie-designware.c @@ -140,7 +140,7 @@ u32 dw_pcie_read_dbi(struct dw_pcie *pci, u32 reg, size_t size) int ret; u32 val; - if (pci->ops->read_dbi) + if (pci->ops && pci->ops->read_dbi) return pci->ops->read_dbi(pci, pci->dbi_base, reg, size); ret = dw_pcie_read(pci->dbi_base + reg, size, ); @@ -155,7 +155,7 @@ void dw_pcie_write_dbi(struct dw_pcie *pci, u32 reg, size_t size, u32 val) { int ret; - if (pci->ops->write_dbi) { + if (pci->ops && pci->ops->write_dbi) { pci->ops->write_dbi(pci, pci->dbi_base, reg, size, val); return; } @@ -200,7 +200,7 @@ u32 dw_pcie_read_atu(struct dw_pcie *pci, u32 reg, size_t size) int ret; u32 val; - if (pci->ops->read_dbi) + if (pci->ops && pci->ops->read_dbi) return pci->ops->read_dbi(pci, pci->atu_base, reg, size); ret = dw_pcie_read(pci->atu_base + reg, size, ); @@ -214,7 +214,7 @@ void dw_pcie_write_atu(struct dw_pcie *pci, u32 reg, size_t size, u32 val) { int ret; - if (pci->ops->write_dbi) { + if (pci->ops && pci->ops->write_dbi) { pci->ops->write_dbi(pci, pci->atu_base, reg, size, val); return; } @@ -283,7 +283,7 @@ void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index, int type, { u32 retries, val; - if (pci->ops->cpu_addr_fixup) + if (pci->ops && pci->ops->cpu_addr_fixup) cpu_addr = pci->ops->cpu_addr_fixup(pci, cpu_addr); if (pci->iatu_unroll_enabled) { @@ -470,7 +470,7 @@ int dw_pcie_link_up(struct dw_pcie *pci) { u32 val; - if (pci->ops->link_up) + if (pci->ops && pci->ops->link_up) return pci->ops->link_up(pci); val = readl(pci->dbi_base + PCIE_PORT_DEBUG1); -- 2.17.1
[PATCH 4/7] arm64: dts: layerscape: Add big-endian property for PCIe nodes
From: Hou Zhiqiang Add the big-endian property for LS1012A, LS1043A and LS1046A PCIe devicetree nodes. Signed-off-by: Hou Zhiqiang --- arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi | 1 + arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi | 3 +++ arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi | 3 +++ 3 files changed, 7 insertions(+) diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi index ff19ec415b60..77a0d401c177 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi @@ -511,6 +511,7 @@ < 0 0 2 0 111 IRQ_TYPE_LEVEL_HIGH>, < 0 0 3 0 112 IRQ_TYPE_LEVEL_HIGH>, < 0 0 4 0 113 IRQ_TYPE_LEVEL_HIGH>; + big-endian; status = "disabled"; }; diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi index 5c2e370f6316..70e07612da12 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi @@ -837,6 +837,7 @@ < 0 0 2 0 111 0x4>, < 0 0 3 0 112 0x4>, < 0 0 4 0 113 0x4>; + big-endian; status = "disabled"; }; @@ -863,6 +864,7 @@ < 0 0 2 0 121 0x4>, < 0 0 3 0 122 0x4>, < 0 0 4 0 123 0x4>; + big-endian; status = "disabled"; }; @@ -889,6 +891,7 @@ < 0 0 2 0 155 0x4>, < 0 0 3 0 156 0x4>, < 0 0 4 0 157 0x4>; + big-endian; status = "disabled"; }; diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi index 0246d975a206..efcbfe8e5e1d 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi @@ -741,6 +741,7 @@ < 0 0 2 GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>, < 0 0 3 GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>, < 0 0 4 GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>; + big-endian; status = "disabled"; }; @@ -777,6 +778,7 @@ < 0 0 2 GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>, < 0 0 3 GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>, < 0 0 4 GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>; + big-endian; status = "disabled"; }; @@ -813,6 +815,7 @@ < 0 0 2 GIC_SPI 154 IRQ_TYPE_LEVEL_HIGH>, < 0 0 3 GIC_SPI 154 IRQ_TYPE_LEVEL_HIGH>, < 0 0 4 GIC_SPI 154 IRQ_TYPE_LEVEL_HIGH>; + big-endian; status = "disabled"; }; -- 2.17.1
[PATCH 3/7] dt-bindings: pci: layerscape-pci: Add a optional property big-endian
From: Hou Zhiqiang This property is to indicate the endianness when accessing the PEX_LUT and PF register block, so if these registers are implemented in big-endian, specify this property. Signed-off-by: Hou Zhiqiang --- Documentation/devicetree/bindings/pci/layerscape-pci.txt | 4 1 file changed, 4 insertions(+) diff --git a/Documentation/devicetree/bindings/pci/layerscape-pci.txt b/Documentation/devicetree/bindings/pci/layerscape-pci.txt index 99a386ea691c..2236d3f3089b 100644 --- a/Documentation/devicetree/bindings/pci/layerscape-pci.txt +++ b/Documentation/devicetree/bindings/pci/layerscape-pci.txt @@ -37,6 +37,10 @@ Required properties: of the data transferred from/to the IP block. This can avoid the software cache flush/invalid actions, and improve the performance significantly. +Optional properties: +- big-endian: If the PEX_LUT and PF register block is in big-endian, specify + this property. + Example: pcie@340 { -- 2.17.1
[PATCH 2/7] PCI: layerscape: Change to use the DWC common link-up check function
From: Hou Zhiqiang The current Layerscape PCIe driver directly uses the physical layer LTSSM code to check the link-up state, which treats the > L0 states as link-up. This is not correct, since there is not explicit map between link-up state and LTSSM. So this patch changes to use the DWC common link-up check function. Signed-off-by: Hou Zhiqiang --- drivers/pci/controller/dwc/pci-layerscape.c | 141 ++-- 1 file changed, 10 insertions(+), 131 deletions(-) diff --git a/drivers/pci/controller/dwc/pci-layerscape.c b/drivers/pci/controller/dwc/pci-layerscape.c index f24f79a70d9a..be404c16bcbe 100644 --- a/drivers/pci/controller/dwc/pci-layerscape.c +++ b/drivers/pci/controller/dwc/pci-layerscape.c @@ -22,12 +22,6 @@ #include "pcie-designware.h" -/* PEX1/2 Misc Ports Status Register */ -#define SCFG_PEXMSCPORTSR(pex_idx) (0x94 + (pex_idx) * 4) -#define LTSSM_STATE_SHIFT 20 -#define LTSSM_STATE_MASK 0x3f -#define LTSSM_PCIE_L0 0x11 /* L0 state */ - /* PEX Internal Configuration Registers */ #define PCIE_STRFMR1 0x71c /* Symbol Timer & Filter Mask Register1 */ #define PCIE_ABSERR0x8d0 /* Bridge Slave Error Response Register */ @@ -36,19 +30,12 @@ #define PCIE_IATU_NUM 6 struct ls_pcie_drvdata { - u32 lut_offset; - u32 ltssm_shift; - u32 lut_dbg; const struct dw_pcie_host_ops *ops; - const struct dw_pcie_ops *dw_pcie_ops; }; struct ls_pcie { struct dw_pcie *pci; - void __iomem *lut; - struct regmap *scfg; const struct ls_pcie_drvdata *drvdata; - int index; }; #define to_ls_pcie(x) dev_get_drvdata((x)->dev) @@ -91,38 +78,6 @@ static void ls_pcie_disable_outbound_atus(struct ls_pcie *pcie) dw_pcie_disable_atu(pcie->pci, i, DW_PCIE_REGION_OUTBOUND); } -static int ls1021_pcie_link_up(struct dw_pcie *pci) -{ - u32 state; - struct ls_pcie *pcie = to_ls_pcie(pci); - - if (!pcie->scfg) - return 0; - - regmap_read(pcie->scfg, SCFG_PEXMSCPORTSR(pcie->index), ); - state = (state >> LTSSM_STATE_SHIFT) & LTSSM_STATE_MASK; - - if (state < LTSSM_PCIE_L0) - return 0; - - return 1; -} - -static int ls_pcie_link_up(struct dw_pcie *pci) -{ - struct ls_pcie *pcie = to_ls_pcie(pci); - u32 state; - - state = (ioread32(pcie->lut + pcie->drvdata->lut_dbg) >> -pcie->drvdata->ltssm_shift) & -LTSSM_STATE_MASK; - - if (state < LTSSM_PCIE_L0) - return 0; - - return 1; -} - /* Forward error response of outbound non-posted requests */ static void ls_pcie_fix_error_response(struct ls_pcie *pcie) { @@ -155,33 +110,6 @@ static int ls_pcie_host_init(struct pcie_port *pp) return 0; } -static int ls1021_pcie_host_init(struct pcie_port *pp) -{ - struct dw_pcie *pci = to_dw_pcie_from_pp(pp); - struct ls_pcie *pcie = to_ls_pcie(pci); - struct device *dev = pci->dev; - u32 index[2]; - int ret; - - pcie->scfg = syscon_regmap_lookup_by_phandle(dev->of_node, -"fsl,pcie-scfg"); - if (IS_ERR(pcie->scfg)) { - ret = PTR_ERR(pcie->scfg); - dev_err(dev, "No syscfg phandle specified\n"); - pcie->scfg = NULL; - return ret; - } - - if (of_property_read_u32_array(dev->of_node, - "fsl,pcie-scfg", index, 2)) { - pcie->scfg = NULL; - return -EINVAL; - } - pcie->index = index[1]; - - return ls_pcie_host_init(pp); -} - static int ls_pcie_msi_host_init(struct pcie_port *pp) { struct dw_pcie *pci = to_dw_pcie_from_pp(pp); @@ -205,71 +133,25 @@ static int ls_pcie_msi_host_init(struct pcie_port *pp) return 0; } -static const struct dw_pcie_host_ops ls1021_pcie_host_ops = { - .host_init = ls1021_pcie_host_init, - .msi_host_init = ls_pcie_msi_host_init, -}; - static const struct dw_pcie_host_ops ls_pcie_host_ops = { .host_init = ls_pcie_host_init, .msi_host_init = ls_pcie_msi_host_init, }; -static const struct dw_pcie_ops dw_ls1021_pcie_ops = { - .link_up = ls1021_pcie_link_up, -}; - -static const struct dw_pcie_ops dw_ls_pcie_ops = { - .link_up = ls_pcie_link_up, -}; - -static const struct ls_pcie_drvdata ls1021_drvdata = { - .ops = _pcie_host_ops, - .dw_pcie_ops = _ls1021_pcie_ops, -}; - -static const struct ls_pcie_drvdata ls1043_drvdata = { - .lut_offset = 0x1, - .ltssm_shift = 24, - .lut_dbg = 0x7fc, - .ops = _pcie_host_ops, - .dw_pcie_ops = _ls_pcie_ops, -}; - -static const struct ls_pcie_drvdata ls1046_drvdata = { - .lut_offset = 0x8, - .ltssm_shift = 24, - .lut_dbg = 0x407fc, - .ops = _pcie_host_ops, - .dw_pcie_ops = _ls_pcie_ops, -}; - -static
[PATCH 0/7] PCI: layerscape: Add power management support
From: Hou Zhiqiang This patch series is to add PCIe power management support for NXP Layerscape platfroms. Hou Zhiqiang (7): PCI: dwc: Fix a bug of the case dw_pci->ops is NULL PCI: layerscape: Change to use the DWC common link-up check function dt-bindings: pci: layerscape-pci: Add a optional property big-endian arm64: dts: layerscape: Add big-endian property for PCIe nodes dt-bindings: pci: layerscape-pci: Update the description of SCFG property dts: arm64: ls1043a: Add SCFG phandle for PCIe nodes PCI: layerscape: Add power management support .../bindings/pci/layerscape-pci.txt | 6 +- .../arm64/boot/dts/freescale/fsl-ls1012a.dtsi | 1 + .../arm64/boot/dts/freescale/fsl-ls1043a.dtsi | 6 + .../arm64/boot/dts/freescale/fsl-ls1046a.dtsi | 3 + drivers/pci/controller/dwc/pci-layerscape.c | 473 ++ drivers/pci/controller/dwc/pcie-designware.c | 12 +- drivers/pci/controller/dwc/pcie-designware.h | 1 + 7 files changed, 388 insertions(+), 114 deletions(-) -- 2.17.1
[PATCHv2] PCI: designware-ep: Fix the Header Type check
From: Hou Zhiqiang The current check will result in the multiple function device fails to initialize. So fix the check by masking out the multiple function bit. Fixes: 0b24134f7888 ("PCI: dwc: Add validation that PCIe core is set to correct mode") Signed-off-by: Hou Zhiqiang --- V2: - Add marco PCI_HEADER_TYPE_MASK and print the masked value. drivers/pci/controller/dwc/pcie-designware-ep.c | 3 ++- include/uapi/linux/pci_regs.h | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c index 4680a51c49c0..0634bd3a0b96 100644 --- a/drivers/pci/controller/dwc/pcie-designware-ep.c +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c @@ -653,7 +653,8 @@ int dw_pcie_ep_init_complete(struct dw_pcie_ep *ep) u32 reg; int i; - hdr_type = dw_pcie_readb_dbi(pci, PCI_HEADER_TYPE); + hdr_type = dw_pcie_readb_dbi(pci, PCI_HEADER_TYPE) & + PCI_HEADER_TYPE_MASK; if (hdr_type != PCI_HEADER_TYPE_NORMAL) { dev_err(pci->dev, "PCIe controller is not set to EP mode (hdr_type:0x%x)!\n", diff --git a/include/uapi/linux/pci_regs.h b/include/uapi/linux/pci_regs.h index f9701410d3b5..57a222014cd2 100644 --- a/include/uapi/linux/pci_regs.h +++ b/include/uapi/linux/pci_regs.h @@ -76,6 +76,7 @@ #define PCI_CACHE_LINE_SIZE0x0c/* 8 bits */ #define PCI_LATENCY_TIMER 0x0d/* 8 bits */ #define PCI_HEADER_TYPE0x0e/* 8 bits */ +#define PCI_HEADER_TYPE_MASK 0x7f #define PCI_HEADER_TYPE_NORMAL0 #define PCI_HEADER_TYPE_BRIDGE1 #define PCI_HEADER_TYPE_CARDBUS 2 -- 2.17.1
[PATCH] PCI: designware-ep: Fix the Header Type check
From: Hou Zhiqiang The current check will result in the multiple function device fails to initialize. So fix the check by masking out the multiple function bit. Fixes: 0b24134f7888 ("PCI: dwc: Add validation that PCIe core is set to correct mode") Signed-off-by: Hou Zhiqiang --- drivers/pci/controller/dwc/pcie-designware-ep.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c index 4680a51c49c0..4b7abfb1e669 100644 --- a/drivers/pci/controller/dwc/pcie-designware-ep.c +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c @@ -654,7 +654,7 @@ int dw_pcie_ep_init_complete(struct dw_pcie_ep *ep) int i; hdr_type = dw_pcie_readb_dbi(pci, PCI_HEADER_TYPE); - if (hdr_type != PCI_HEADER_TYPE_NORMAL) { + if (hdr_type & 0x7f != PCI_HEADER_TYPE_NORMAL) { dev_err(pci->dev, "PCIe controller is not set to EP mode (hdr_type:0x%x)!\n", hdr_type); -- 2.17.1
[PATCHv7 08/12] PCI: layerscape: Modify the MSIX to the doorbell mode
From: Xiaowei Bao dw_pcie_ep_raise_msix_irq was never called in the exisitng driver before, because the ls1046a platform don't support the MSIX feature and msix_capable was always set to false. Now that add the ls1088a platform with MSIX support, use the doorbell method to support the MSIX feature. Signed-off-by: Xiaowei Bao Reviewed-by: Andrew Murray Signed-off-by: Hou Zhiqiang --- V7: - Rebase the patch without functionality change. drivers/pci/controller/dwc/pci-layerscape-ep.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/pci/controller/dwc/pci-layerscape-ep.c b/drivers/pci/controller/dwc/pci-layerscape-ep.c index 9601f9c09cb1..bfab1c694f00 100644 --- a/drivers/pci/controller/dwc/pci-layerscape-ep.c +++ b/drivers/pci/controller/dwc/pci-layerscape-ep.c @@ -79,7 +79,8 @@ static int ls_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no, case PCI_EPC_IRQ_MSI: return dw_pcie_ep_raise_msi_irq(ep, func_no, interrupt_num); case PCI_EPC_IRQ_MSIX: - return dw_pcie_ep_raise_msix_irq(ep, func_no, interrupt_num); + return dw_pcie_ep_raise_msix_irq_doorbell(ep, func_no, + interrupt_num); default: dev_err(pci->dev, "UNKNOWN IRQ type\n"); return -EINVAL; -- 2.17.1
[PATCHv7 10/12] arm64: dts: layerscape: Add PCIe EP node for ls1088a
From: Xiaowei Bao Add PCIe EP node for ls1088a to support EP mode. Signed-off-by: Xiaowei Bao Reviewed-by: Andrew Murray Signed-off-by: Hou Zhiqiang --- V7: - Rebase the patch without functionality change. .../arm64/boot/dts/freescale/fsl-ls1088a.dtsi | 31 +++ 1 file changed, 31 insertions(+) diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi index 169f4742ae3b..915592141f1b 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi @@ -499,6 +499,17 @@ status = "disabled"; }; + pcie_ep@340 { + compatible = "fsl,ls1088a-pcie-ep","fsl,ls-pcie-ep"; + reg = <0x00 0x0340 0x0 0x0010 + 0x20 0x 0x8 0x>; + reg-names = "regs", "addr_space"; + num-ib-windows = <24>; + num-ob-windows = <128>; + max-functions = /bits/ 8 <2>; + status = "disabled"; + }; + pcie@350 { compatible = "fsl,ls1088a-pcie"; reg = <0x00 0x0350 0x0 0x0010 /* controller registers */ @@ -525,6 +536,16 @@ status = "disabled"; }; + pcie_ep@350 { + compatible = "fsl,ls1088a-pcie-ep","fsl,ls-pcie-ep"; + reg = <0x00 0x0350 0x0 0x0010 + 0x28 0x 0x8 0x>; + reg-names = "regs", "addr_space"; + num-ib-windows = <6>; + num-ob-windows = <8>; + status = "disabled"; + }; + pcie@360 { compatible = "fsl,ls1088a-pcie"; reg = <0x00 0x0360 0x0 0x0010 /* controller registers */ @@ -551,6 +572,16 @@ status = "disabled"; }; + pcie_ep@360 { + compatible = "fsl,ls1088a-pcie-ep","fsl,ls-pcie-ep"; + reg = <0x00 0x0360 0x0 0x0010 + 0x30 0x 0x8 0x>; + reg-names = "regs", "addr_space"; + num-ib-windows = <6>; + num-ob-windows = <8>; + status = "disabled"; + }; + smmu: iommu@500 { compatible = "arm,mmu-500"; reg = <0 0x500 0 0x80>; -- 2.17.1
[PATCHv7 07/12] PCI: layerscape: Modify the way of getting capability with different PEX
From: Xiaowei Bao The different PCIe controller in one board may be have different capability of MSI or MSIX, so change the way of getting the MSI capability, make it more flexible. Signed-off-by: Xiaowei Bao Reviewed-by: Rob Herring Signed-off-by: Hou Zhiqiang --- V7: - Rebase the patch without functionality change. .../pci/controller/dwc/pci-layerscape-ep.c| 31 ++- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/drivers/pci/controller/dwc/pci-layerscape-ep.c b/drivers/pci/controller/dwc/pci-layerscape-ep.c index 0691d9ad1356..9601f9c09cb1 100644 --- a/drivers/pci/controller/dwc/pci-layerscape-ep.c +++ b/drivers/pci/controller/dwc/pci-layerscape-ep.c @@ -22,6 +22,7 @@ struct ls_pcie_ep { struct dw_pcie *pci; + struct pci_epc_features *ls_epc; }; #define to_ls_pcie_ep(x) dev_get_drvdata((x)->dev) @@ -40,26 +41,31 @@ static const struct of_device_id ls_pcie_ep_of_match[] = { { }, }; -static const struct pci_epc_features ls_pcie_epc_features = { - .linkup_notifier = false, - .msi_capable = true, - .msix_capable = false, - .bar_fixed_64bit = (1 << BAR_2) | (1 << BAR_4), -}; - static const struct pci_epc_features* ls_pcie_ep_get_features(struct dw_pcie_ep *ep) { - return _pcie_epc_features; + struct dw_pcie *pci = to_dw_pcie_from_ep(ep); + struct ls_pcie_ep *pcie = to_ls_pcie_ep(pci); + + return pcie->ls_epc; } static void ls_pcie_ep_init(struct dw_pcie_ep *ep) { struct dw_pcie *pci = to_dw_pcie_from_ep(ep); + struct ls_pcie_ep *pcie = to_ls_pcie_ep(pci); + struct dw_pcie_ep_func *ep_func; enum pci_barno bar; + ep_func = dw_pcie_ep_get_func_from_ep(ep, 0); + if (!ep_func) + return; + for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) dw_pcie_ep_reset_bar(pci, bar); + + pcie->ls_epc->msi_capable = ep_func->msi_cap ? true : false; + pcie->ls_epc->msix_capable = ep_func->msix_cap ? true : false; } static int ls_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no, @@ -119,6 +125,7 @@ static int __init ls_pcie_ep_probe(struct platform_device *pdev) struct device *dev = >dev; struct dw_pcie *pci; struct ls_pcie_ep *pcie; + struct pci_epc_features *ls_epc; struct resource *dbi_base; int ret; @@ -130,6 +137,10 @@ static int __init ls_pcie_ep_probe(struct platform_device *pdev) if (!pci) return -ENOMEM; + ls_epc = devm_kzalloc(dev, sizeof(*ls_epc), GFP_KERNEL); + if (!ls_epc) + return -ENOMEM; + dbi_base = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs"); pci->dbi_base = devm_pci_remap_cfg_resource(dev, dbi_base); if (IS_ERR(pci->dbi_base)) @@ -140,6 +151,10 @@ static int __init ls_pcie_ep_probe(struct platform_device *pdev) pci->ops = _pcie_ep_ops; pcie->pci = pci; + ls_epc->bar_fixed_64bit = (1 << BAR_2) | (1 << BAR_4), + + pcie->ls_epc = ls_epc; + platform_set_drvdata(pdev, pcie); ret = ls_add_pcie_ep(pcie, pdev); -- 2.17.1
[PATCHv7 04/12] PCI: designware-ep: Modify MSI and MSIX CAP way of finding
From: Xiaowei Bao Each PF of EP device should have its own MSI or MSIX capabitily struct, so create a dw_pcie_ep_func struct and move the msi_cap and msix_cap to this struct from dw_pcie_ep, and manage the PFs via a list. Signed-off-by: Xiaowei Bao Signed-off-by: Hou Zhiqiang --- V7: - Rebase the patch without functionality change. .../pci/controller/dwc/pcie-designware-ep.c | 139 +++--- drivers/pci/controller/dwc/pcie-designware.h | 18 ++- 2 files changed, 136 insertions(+), 21 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c index 56bd1cd71f16..4680a51c49c0 100644 --- a/drivers/pci/controller/dwc/pcie-designware-ep.c +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c @@ -28,6 +28,19 @@ void dw_pcie_ep_init_notify(struct dw_pcie_ep *ep) } EXPORT_SYMBOL_GPL(dw_pcie_ep_init_notify); +struct dw_pcie_ep_func * +dw_pcie_ep_get_func_from_ep(struct dw_pcie_ep *ep, u8 func_no) +{ + struct dw_pcie_ep_func *ep_func; + + list_for_each_entry(ep_func, >func_list, list) { + if (ep_func->func_no == func_no) + return ep_func; + } + + return NULL; +} + static unsigned int dw_pcie_ep_func_select(struct dw_pcie_ep *ep, u8 func_no) { unsigned int func_offset = 0; @@ -68,6 +81,47 @@ void dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar) __dw_pcie_ep_reset_bar(pci, func_no, bar, 0); } +static u8 __dw_pcie_ep_find_next_cap(struct dw_pcie_ep *ep, u8 func_no, + u8 cap_ptr, u8 cap) +{ + struct dw_pcie *pci = to_dw_pcie_from_ep(ep); + unsigned int func_offset = 0; + u8 cap_id, next_cap_ptr; + u16 reg; + + if (!cap_ptr) + return 0; + + func_offset = dw_pcie_ep_func_select(ep, func_no); + + reg = dw_pcie_readw_dbi(pci, func_offset + cap_ptr); + cap_id = (reg & 0x00ff); + + if (cap_id > PCI_CAP_ID_MAX) + return 0; + + if (cap_id == cap) + return cap_ptr; + + next_cap_ptr = (reg & 0xff00) >> 8; + return __dw_pcie_ep_find_next_cap(ep, func_no, next_cap_ptr, cap); +} + +static u8 dw_pcie_ep_find_capability(struct dw_pcie_ep *ep, u8 func_no, u8 cap) +{ + struct dw_pcie *pci = to_dw_pcie_from_ep(ep); + unsigned int func_offset = 0; + u8 next_cap_ptr; + u16 reg; + + func_offset = dw_pcie_ep_func_select(ep, func_no); + + reg = dw_pcie_readw_dbi(pci, func_offset + PCI_CAPABILITY_LIST); + next_cap_ptr = (reg & 0x00ff); + + return __dw_pcie_ep_find_next_cap(ep, func_no, next_cap_ptr, cap); +} + static int dw_pcie_ep_write_header(struct pci_epc *epc, u8 func_no, struct pci_epf_header *hdr) { @@ -257,13 +311,18 @@ static int dw_pcie_ep_get_msi(struct pci_epc *epc, u8 func_no) struct dw_pcie *pci = to_dw_pcie_from_ep(ep); u32 val, reg; unsigned int func_offset = 0; + struct dw_pcie_ep_func *ep_func; - if (!ep->msi_cap) + ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no); + if (!ep_func) + return -EINVAL; + + if (!ep_func->msi_cap) return -EINVAL; func_offset = dw_pcie_ep_func_select(ep, func_no); - reg = ep->msi_cap + func_offset + PCI_MSI_FLAGS; + reg = ep_func->msi_cap + func_offset + PCI_MSI_FLAGS; val = dw_pcie_readw_dbi(pci, reg); if (!(val & PCI_MSI_FLAGS_ENABLE)) return -EINVAL; @@ -279,13 +338,18 @@ static int dw_pcie_ep_set_msi(struct pci_epc *epc, u8 func_no, u8 interrupts) struct dw_pcie *pci = to_dw_pcie_from_ep(ep); u32 val, reg; unsigned int func_offset = 0; + struct dw_pcie_ep_func *ep_func; + + ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no); + if (!ep_func) + return -EINVAL; - if (!ep->msi_cap) + if (!ep_func->msi_cap) return -EINVAL; func_offset = dw_pcie_ep_func_select(ep, func_no); - reg = ep->msi_cap + func_offset + PCI_MSI_FLAGS; + reg = ep_func->msi_cap + func_offset + PCI_MSI_FLAGS; val = dw_pcie_readw_dbi(pci, reg); val &= ~PCI_MSI_FLAGS_QMASK; val |= (interrupts << 1) & PCI_MSI_FLAGS_QMASK; @@ -302,13 +366,18 @@ static int dw_pcie_ep_get_msix(struct pci_epc *epc, u8 func_no) struct dw_pcie *pci = to_dw_pcie_from_ep(ep); u32 val, reg; unsigned int func_offset = 0; + struct dw_pcie_ep_func *ep_func; + + ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no); + if (!ep_func) + return -EINVAL; - if (!ep->msix_cap) + if (!ep_func->msix_cap) return -EINVAL; func_offset = dw_pcie_ep_func_select(ep, func_no); - reg = ep->msix_cap + func_offset + PCI_MSIX_FLAGS; + reg = ep_func->msix_cap + func_offset + PCI_MSIX_FLAGS; val
[PATCHv7 09/12] PCI: layerscape: Add EP mode support for ls1088a and ls2088a
From: Xiaowei Bao Add PCIe EP mode support for ls1088a and ls2088a, there are some difference between LS1 and LS2 platform, so refactor the code of the EP driver. Signed-off-by: Xiaowei Bao Reviewed-by: Rob Herring Signed-off-by: Hou Zhiqiang --- V7: - Rebase the patch without functionality change. .../pci/controller/dwc/pci-layerscape-ep.c| 72 ++- 1 file changed, 53 insertions(+), 19 deletions(-) diff --git a/drivers/pci/controller/dwc/pci-layerscape-ep.c b/drivers/pci/controller/dwc/pci-layerscape-ep.c index bfab1c694f00..84206f265e54 100644 --- a/drivers/pci/controller/dwc/pci-layerscape-ep.c +++ b/drivers/pci/controller/dwc/pci-layerscape-ep.c @@ -20,27 +20,29 @@ #define PCIE_DBI2_OFFSET 0x1000 /* DBI2 base address*/ -struct ls_pcie_ep { - struct dw_pcie *pci; - struct pci_epc_features *ls_epc; +#define to_ls_pcie_ep(x) dev_get_drvdata((x)->dev) + +struct ls_pcie_ep_drvdata { + u32 func_offset; + const struct dw_pcie_ep_ops *ops; + const struct dw_pcie_ops*dw_pcie_ops; }; -#define to_ls_pcie_ep(x) dev_get_drvdata((x)->dev) +struct ls_pcie_ep { + struct dw_pcie *pci; + struct pci_epc_features *ls_epc; + const struct ls_pcie_ep_drvdata *drvdata; +}; static int ls_pcie_establish_link(struct dw_pcie *pci) { return 0; } -static const struct dw_pcie_ops ls_pcie_ep_ops = { +static const struct dw_pcie_ops dw_ls_pcie_ep_ops = { .start_link = ls_pcie_establish_link, }; -static const struct of_device_id ls_pcie_ep_of_match[] = { - { .compatible = "fsl,ls-pcie-ep",}, - { }, -}; - static const struct pci_epc_features* ls_pcie_ep_get_features(struct dw_pcie_ep *ep) { @@ -87,10 +89,39 @@ static int ls_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no, } } -static const struct dw_pcie_ep_ops pcie_ep_ops = { +static unsigned int ls_pcie_ep_func_conf_select(struct dw_pcie_ep *ep, + u8 func_no) +{ + struct dw_pcie *pci = to_dw_pcie_from_ep(ep); + struct ls_pcie_ep *pcie = to_ls_pcie_ep(pci); + + WARN_ON(func_no && !pcie->drvdata->func_offset); + return pcie->drvdata->func_offset * func_no; +} + +static const struct dw_pcie_ep_ops ls_pcie_ep_ops = { .ep_init = ls_pcie_ep_init, .raise_irq = ls_pcie_ep_raise_irq, .get_features = ls_pcie_ep_get_features, + .func_conf_select = ls_pcie_ep_func_conf_select, +}; + +static const struct ls_pcie_ep_drvdata ls1_ep_drvdata = { + .ops = _pcie_ep_ops, + .dw_pcie_ops = _ls_pcie_ep_ops, +}; + +static const struct ls_pcie_ep_drvdata ls2_ep_drvdata = { + .func_offset = 0x2, + .ops = _pcie_ep_ops, + .dw_pcie_ops = _ls_pcie_ep_ops, +}; + +static const struct of_device_id ls_pcie_ep_of_match[] = { + { .compatible = "fsl,ls1046a-pcie-ep", .data = _ep_drvdata }, + { .compatible = "fsl,ls1088a-pcie-ep", .data = _ep_drvdata }, + { .compatible = "fsl,ls2088a-pcie-ep", .data = _ep_drvdata }, + { }, }; static int __init ls_add_pcie_ep(struct ls_pcie_ep *pcie, @@ -103,7 +134,7 @@ static int __init ls_add_pcie_ep(struct ls_pcie_ep *pcie, int ret; ep = >ep; - ep->ops = _ep_ops; + ep->ops = pcie->drvdata->ops; res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "addr_space"); if (!res) @@ -142,20 +173,23 @@ static int __init ls_pcie_ep_probe(struct platform_device *pdev) if (!ls_epc) return -ENOMEM; - dbi_base = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs"); - pci->dbi_base = devm_pci_remap_cfg_resource(dev, dbi_base); - if (IS_ERR(pci->dbi_base)) - return PTR_ERR(pci->dbi_base); + pcie->drvdata = of_device_get_match_data(dev); - pci->dbi_base2 = pci->dbi_base + PCIE_DBI2_OFFSET; pci->dev = dev; - pci->ops = _pcie_ep_ops; - pcie->pci = pci; + pci->ops = pcie->drvdata->dw_pcie_ops; ls_epc->bar_fixed_64bit = (1 << BAR_2) | (1 << BAR_4), + pcie->pci = pci; pcie->ls_epc = ls_epc; + dbi_base = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs"); + pci->dbi_base = devm_pci_remap_cfg_resource(dev, dbi_base); + if (IS_ERR(pci->dbi_base)) + return PTR_ERR(pci->dbi_base); + + pci->dbi_base2 = pci->dbi_base + PCIE_DBI2_OFFSET; + platform_set_drvdata(pdev, pcie); ret = ls_add_pcie_ep(pcie, pdev); -- 2.17.1
[PATCHv7 05/12] dt-bindings: pci: layerscape-pci: Add compatible strings for ls1088a and ls2088a
From: Xiaowei Bao Add compatible strings for ls1088a and ls2088a. Signed-off-by: Xiaowei Bao Acked-by: Rob Herring Signed-off-by: Hou Zhiqiang --- V7: - Rebase the patch without functionality change. Documentation/devicetree/bindings/pci/layerscape-pci.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/pci/layerscape-pci.txt b/Documentation/devicetree/bindings/pci/layerscape-pci.txt index 99a386ea691c..daa99f7d4c3f 100644 --- a/Documentation/devicetree/bindings/pci/layerscape-pci.txt +++ b/Documentation/devicetree/bindings/pci/layerscape-pci.txt @@ -24,6 +24,8 @@ Required properties: "fsl,ls1028a-pcie" EP mode: "fsl,ls1046a-pcie-ep", "fsl,ls-pcie-ep" + "fsl,ls1088a-pcie-ep", "fsl,ls-pcie-ep" + "fsl,ls2088a-pcie-ep", "fsl,ls-pcie-ep" - reg: base addresses and lengths of the PCIe controller register blocks. - interrupts: A list of interrupt outputs of the controller. Must contain an entry for each entry in the interrupt-names property. -- 2.17.1
[PATCHv7 11/12] misc: pci_endpoint_test: Add LS1088a in pci_device_id table
From: Xiaowei Bao Add LS1088a in pci_device_id table so that pci-epf-test can be used for testing PCIe EP in LS1088a. Signed-off-by: Xiaowei Bao Reviewed-by: Andrew Murray Signed-off-by: Hou Zhiqiang --- V7: - Rebase the patch without functionality change. drivers/misc/pci_endpoint_test.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/misc/pci_endpoint_test.c b/drivers/misc/pci_endpoint_test.c index e060796f9caa..4a17f08de60f 100644 --- a/drivers/misc/pci_endpoint_test.c +++ b/drivers/misc/pci_endpoint_test.c @@ -70,6 +70,7 @@ #define PCI_DEVICE_ID_TI_J721E 0xb00d #define PCI_DEVICE_ID_TI_AM654 0xb00c +#define PCI_DEVICE_ID_LS1088A 0x80c0 #define is_am654_pci_dev(pdev) \ ((pdev)->device == PCI_DEVICE_ID_TI_AM654) @@ -946,6 +947,7 @@ static const struct pci_device_id pci_endpoint_test_tbl[] = { .driver_data = (kernel_ulong_t)_data, }, { PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, 0x81c0) }, + { PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, PCI_DEVICE_ID_LS1088A) }, { PCI_DEVICE_DATA(SYNOPSYS, EDDA, NULL) }, { PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_AM654), .driver_data = (kernel_ulong_t)_data -- 2.17.1
[PATCHv7 03/12] PCI: designware-ep: Move the function of getting MSI capability forward
From: Xiaowei Bao Move the function of getting MSI capability to the front of init function, because the init function of the EP platform driver will use the return value by the function of getting MSI capability. Signed-off-by: Xiaowei Bao Reviewed-by: Andrew Murray Signed-off-by: Hou Zhiqiang --- V7: - Rebase the patch without functionality change. drivers/pci/controller/dwc/pcie-designware-ep.c | 8 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c index e76b504ed465..56bd1cd71f16 100644 --- a/drivers/pci/controller/dwc/pcie-designware-ep.c +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c @@ -574,10 +574,6 @@ int dw_pcie_ep_init_complete(struct dw_pcie_ep *ep) return -EIO; } - ep->msi_cap = dw_pcie_find_capability(pci, PCI_CAP_ID_MSI); - - ep->msix_cap = dw_pcie_find_capability(pci, PCI_CAP_ID_MSIX); - offset = dw_pcie_ep_find_ext_capability(pci, PCI_EXT_CAP_ID_REBAR); if (offset) { reg = dw_pcie_readl_dbi(pci, offset + PCI_REBAR_CTRL); @@ -664,6 +660,10 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep) if (ret < 0) epc->max_functions = 1; + ep->msi_cap = dw_pcie_find_capability(pci, PCI_CAP_ID_MSI); + + ep->msix_cap = dw_pcie_find_capability(pci, PCI_CAP_ID_MSIX); + if (ep->ops->ep_init) ep->ops->ep_init(ep); -- 2.17.1
[PATCHv7 12/12] misc: pci_endpoint_test: Add driver data for Layerscape PCIe controllers
From: Hou Zhiqiang The commit 0a121f9bc3f5 ("misc: pci_endpoint_test: Use streaming DMA APIs for buffer allocation") changed to use streaming DMA APIs, however, dma_map_single() might not return a 4KB aligned address, so add the default_data as driver data for Layerscape PCIe controllers to make it 4KB aligned. Signed-off-by: Hou Zhiqiang --- V7: - New patch. drivers/misc/pci_endpoint_test.c | 8 ++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/misc/pci_endpoint_test.c b/drivers/misc/pci_endpoint_test.c index 4a17f08de60f..70a790cd14c5 100644 --- a/drivers/misc/pci_endpoint_test.c +++ b/drivers/misc/pci_endpoint_test.c @@ -946,8 +946,12 @@ static const struct pci_device_id pci_endpoint_test_tbl[] = { { PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_DRA72x), .driver_data = (kernel_ulong_t)_data, }, - { PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, 0x81c0) }, - { PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, PCI_DEVICE_ID_LS1088A) }, + { PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, 0x81c0), + .driver_data = (kernel_ulong_t)_data, + }, + { PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, PCI_DEVICE_ID_LS1088A), + .driver_data = (kernel_ulong_t)_data, + }, { PCI_DEVICE_DATA(SYNOPSYS, EDDA, NULL) }, { PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_AM654), .driver_data = (kernel_ulong_t)_data -- 2.17.1
[PATCHv7 06/12] PCI: layerscape: Fix some format issue of the code
From: Xiaowei Bao Fix some format issue of the code in EP driver. Signed-off-by: Xiaowei Bao Reviewed-by: Andrew Murray Signed-off-by: Hou Zhiqiang --- V7: - Rebase the patch without functionality change. drivers/pci/controller/dwc/pci-layerscape-ep.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/pci/controller/dwc/pci-layerscape-ep.c b/drivers/pci/controller/dwc/pci-layerscape-ep.c index 0d151cead1b7..0691d9ad1356 100644 --- a/drivers/pci/controller/dwc/pci-layerscape-ep.c +++ b/drivers/pci/controller/dwc/pci-layerscape-ep.c @@ -63,7 +63,7 @@ static void ls_pcie_ep_init(struct dw_pcie_ep *ep) } static int ls_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no, - enum pci_epc_irq_type type, u16 interrupt_num) + enum pci_epc_irq_type type, u16 interrupt_num) { struct dw_pcie *pci = to_dw_pcie_from_ep(ep); @@ -87,7 +87,7 @@ static const struct dw_pcie_ep_ops pcie_ep_ops = { }; static int __init ls_add_pcie_ep(struct ls_pcie_ep *pcie, - struct platform_device *pdev) +struct platform_device *pdev) { struct dw_pcie *pci = pcie->pci; struct device *dev = pci->dev; -- 2.17.1
[PATCHv7 01/12] PCI: designware-ep: Add multiple PFs support for DWC
From: Xiaowei Bao Add multiple PFs support for DWC, due to different PF have different config space, we use func_conf_select callback function to access the different PF's config space, the different chip company need to implement this callback function when use the DWC IP core and intend to support multiple PFs feature. Signed-off-by: Xiaowei Bao Acked-by: Gustavo Pimentel Reviewed-by: Rob Herring Signed-off-by: Hou Zhiqiang --- V7: - Rebase the patch without functionality change. .../pci/controller/dwc/pcie-designware-ep.c | 125 -- drivers/pci/controller/dwc/pcie-designware.c | 59 ++--- drivers/pci/controller/dwc/pcie-designware.h | 18 ++- 3 files changed, 143 insertions(+), 59 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c index 305bfec2424d..e5bd3a5ef380 100644 --- a/drivers/pci/controller/dwc/pcie-designware-ep.c +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c @@ -28,12 +28,26 @@ void dw_pcie_ep_init_notify(struct dw_pcie_ep *ep) } EXPORT_SYMBOL_GPL(dw_pcie_ep_init_notify); -static void __dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar, - int flags) +static unsigned int dw_pcie_ep_func_select(struct dw_pcie_ep *ep, u8 func_no) +{ + unsigned int func_offset = 0; + + if (ep->ops->func_conf_select) + func_offset = ep->ops->func_conf_select(ep, func_no); + + return func_offset; +} + +static void __dw_pcie_ep_reset_bar(struct dw_pcie *pci, u8 func_no, + enum pci_barno bar, int flags) { u32 reg; + unsigned int func_offset = 0; + struct dw_pcie_ep *ep = >ep; + + func_offset = dw_pcie_ep_func_select(ep, func_no); - reg = PCI_BASE_ADDRESS_0 + (4 * bar); + reg = func_offset + PCI_BASE_ADDRESS_0 + (4 * bar); dw_pcie_dbi_ro_wr_en(pci); dw_pcie_writel_dbi2(pci, reg, 0x0); dw_pcie_writel_dbi(pci, reg, 0x0); @@ -46,7 +60,12 @@ static void __dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar, void dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar) { - __dw_pcie_ep_reset_bar(pci, bar, 0); + u8 func_no, funcs; + + funcs = pci->ep.epc->max_functions; + + for (func_no = 0; func_no < funcs; func_no++) + __dw_pcie_ep_reset_bar(pci, func_no, bar, 0); } static int dw_pcie_ep_write_header(struct pci_epc *epc, u8 func_no, @@ -54,28 +73,31 @@ static int dw_pcie_ep_write_header(struct pci_epc *epc, u8 func_no, { struct dw_pcie_ep *ep = epc_get_drvdata(epc); struct dw_pcie *pci = to_dw_pcie_from_ep(ep); + unsigned int func_offset = 0; + + func_offset = dw_pcie_ep_func_select(ep, func_no); dw_pcie_dbi_ro_wr_en(pci); - dw_pcie_writew_dbi(pci, PCI_VENDOR_ID, hdr->vendorid); - dw_pcie_writew_dbi(pci, PCI_DEVICE_ID, hdr->deviceid); - dw_pcie_writeb_dbi(pci, PCI_REVISION_ID, hdr->revid); - dw_pcie_writeb_dbi(pci, PCI_CLASS_PROG, hdr->progif_code); - dw_pcie_writew_dbi(pci, PCI_CLASS_DEVICE, + dw_pcie_writew_dbi(pci, func_offset + PCI_VENDOR_ID, hdr->vendorid); + dw_pcie_writew_dbi(pci, func_offset + PCI_DEVICE_ID, hdr->deviceid); + dw_pcie_writeb_dbi(pci, func_offset + PCI_REVISION_ID, hdr->revid); + dw_pcie_writeb_dbi(pci, func_offset + PCI_CLASS_PROG, hdr->progif_code); + dw_pcie_writew_dbi(pci, func_offset + PCI_CLASS_DEVICE, hdr->subclass_code | hdr->baseclass_code << 8); - dw_pcie_writeb_dbi(pci, PCI_CACHE_LINE_SIZE, + dw_pcie_writeb_dbi(pci, func_offset + PCI_CACHE_LINE_SIZE, hdr->cache_line_size); - dw_pcie_writew_dbi(pci, PCI_SUBSYSTEM_VENDOR_ID, + dw_pcie_writew_dbi(pci, func_offset + PCI_SUBSYSTEM_VENDOR_ID, hdr->subsys_vendor_id); - dw_pcie_writew_dbi(pci, PCI_SUBSYSTEM_ID, hdr->subsys_id); - dw_pcie_writeb_dbi(pci, PCI_INTERRUPT_PIN, + dw_pcie_writew_dbi(pci, func_offset + PCI_SUBSYSTEM_ID, hdr->subsys_id); + dw_pcie_writeb_dbi(pci, func_offset + PCI_INTERRUPT_PIN, hdr->interrupt_pin); dw_pcie_dbi_ro_wr_dis(pci); return 0; } -static int dw_pcie_ep_inbound_atu(struct dw_pcie_ep *ep, enum pci_barno bar, - dma_addr_t cpu_addr, +static int dw_pcie_ep_inbound_atu(struct dw_pcie_ep *ep, u8 func_no, + enum pci_barno bar, dma_addr_t cpu_addr, enum dw_pcie_as_type as_type) { int ret; @@ -88,7 +110,7 @@ static int dw_pcie_ep_inbound_atu(struct dw_pcie_ep *ep, enum pci_barno bar, return -EINVAL; } - ret = dw_pcie_prog_inbound_atu(pci, free_win, bar, cpu_addr, + ret = dw_pcie_prog_inbound_atu(pci, func_no, free_win, bar, cpu_addr,
[PATCHv7 02/12] PCI: designware-ep: Add the doorbell mode of MSI-X in EP mode
From: Xiaowei Bao Add the doorbell mode of MSI-X in DWC EP driver. Signed-off-by: Xiaowei Bao Reviewed-by: Andrew Murray Signed-off-by: Hou Zhiqiang --- V7: - Rebase the patch without functionality change. drivers/pci/controller/dwc/pcie-designware-ep.c | 14 ++ drivers/pci/controller/dwc/pcie-designware.h| 12 2 files changed, 26 insertions(+) diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c index e5bd3a5ef380..e76b504ed465 100644 --- a/drivers/pci/controller/dwc/pcie-designware-ep.c +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c @@ -471,6 +471,20 @@ int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no, return 0; } +int dw_pcie_ep_raise_msix_irq_doorbell(struct dw_pcie_ep *ep, u8 func_no, + u16 interrupt_num) +{ + struct dw_pcie *pci = to_dw_pcie_from_ep(ep); + u32 msg_data; + + msg_data = (func_no << PCIE_MSIX_DOORBELL_PF_SHIFT) | + (interrupt_num - 1); + + dw_pcie_writel_dbi(pci, PCIE_MSIX_DOORBELL, msg_data); + + return 0; +} + int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no, u16 interrupt_num) { diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index 89f8271ec5ee..745b4938225a 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -97,6 +97,9 @@ #define PCIE_MISC_CONTROL_1_OFF0x8BC #define PCIE_DBI_RO_WR_EN BIT(0) +#define PCIE_MSIX_DOORBELL 0x948 +#define PCIE_MSIX_DOORBELL_PF_SHIFT24 + #define PCIE_PL_CHK_REG_CONTROL_STATUS 0xB20 #define PCIE_PL_CHK_REG_CHK_REG_START BIT(0) #define PCIE_PL_CHK_REG_CHK_REG_CONTINUOUS BIT(1) @@ -434,6 +437,8 @@ int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no, u8 interrupt_num); int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no, u16 interrupt_num); +int dw_pcie_ep_raise_msix_irq_doorbell(struct dw_pcie_ep *ep, u8 func_no, + u16 interrupt_num); void dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar); #else static inline void dw_pcie_ep_linkup(struct dw_pcie_ep *ep) @@ -475,6 +480,13 @@ static inline int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no, return 0; } +static inline int dw_pcie_ep_raise_msix_irq_doorbell(struct dw_pcie_ep *ep, +u8 func_no, +u16 interrupt_num) +{ + return 0; +} + static inline void dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar) { } -- 2.17.1
[PATCHv7 00/12]PCI: dwc: Add the multiple PF support for DWC and Layerscape
From: Hou Zhiqiang Add the PCIe EP multiple PF support for DWC and Layerscape, and use a list to manage the PFs of each PCIe controller; add the doorbell MSIX function for DWC; and refactor the Layerscape EP driver due to some difference in Layercape platforms PCIe integration. Hou Zhiqiang (1): misc: pci_endpoint_test: Add driver data for Layerscape PCIe controllers Xiaowei Bao (11): PCI: designware-ep: Add multiple PFs support for DWC PCI: designware-ep: Add the doorbell mode of MSI-X in EP mode PCI: designware-ep: Move the function of getting MSI capability forward PCI: designware-ep: Modify MSI and MSIX CAP way of finding dt-bindings: pci: layerscape-pci: Add compatible strings for ls1088a and ls2088a PCI: layerscape: Fix some format issue of the code PCI: layerscape: Modify the way of getting capability with different PEX PCI: layerscape: Modify the MSIX to the doorbell mode PCI: layerscape: Add EP mode support for ls1088a and ls2088a arm64: dts: layerscape: Add PCIe EP node for ls1088a misc: pci_endpoint_test: Add LS1088a in pci_device_id table .../bindings/pci/layerscape-pci.txt | 2 + .../arm64/boot/dts/freescale/fsl-ls1088a.dtsi | 31 +++ drivers/misc/pci_endpoint_test.c | 8 +- .../pci/controller/dwc/pci-layerscape-ep.c| 100 +-- .../pci/controller/dwc/pcie-designware-ep.c | 258 ++ drivers/pci/controller/dwc/pcie-designware.c | 59 ++-- drivers/pci/controller/dwc/pcie-designware.h | 48 +++- 7 files changed, 410 insertions(+), 96 deletions(-) -- 2.17.1
[PATCH] PCI: ERR: Don't override the status returned by error_detect()
From: Hou Zhiqiang The commit 6d2c89441571 ("PCI/ERR: Update error status after reset_link()") overrode the 'status' returned by the error_detect() call back function, which is depended on by the next step. This overriding makes the Endpoint driver's required info (kept in the var status) lost, so it results in the fatal errors' recovery failed and then kernel panic. In the e1000e case, the error logs: pcieport 0002:00:00.0: AER: Uncorrected (Fatal) error received: 0002:01:00.0 e1000e 0002:01:00.0: AER: PCIe Bus Error: severity=Uncorrected (Fatal), type=Inaccessible, (Unregistered Agent ID) pcieport 0002:00:00.0: AER: Root Port link has been reset SError Interrupt on CPU0, code 0xbf02 -- SError CPU: 0 PID: 111 Comm: irq/76-aerdrv Not tainted 5.7.0-rc7-next-20200526 #8 Hardware name: LS1046A RDB Board (DT) pstate: 8005 (Nzcv daif -PAN -UAO BTYPE=--) pc : __pci_enable_msix_range+0x4c8/0x5b8 lr : __pci_enable_msix_range+0x480/0x5b8 sp : 80001116bb30 x29: 80001116bb30 x28: 0003 x27: 0003 x26: x25: 00097243e0a8 x24: 0001 x23: 00097243e2d8 x22: x21: 0003 x20: 00095bd46080 x19: 00097243e000 x18: x17: x16: x15: b958fa0e9948 x14: 00095bd46303 x13: 00095bd46302 x12: 0038 x11: 0040 x10: b958fa101e68 x9 : b958fa101e60 x8 : 0908 x7 : 0908 x6 : 80001160 x5 : 00095bd46800 x4 : 00096e7f6080 x3 : x2 : x1 : x0 : Kernel panic - not syncing: Asynchronous SError Interrupt CPU: 0 PID: 111 Comm: irq/76-aerdrv Not tainted 5.7.0-rc7-next-20200526 #8 I think it's the expected result that "if the initial value of error status is PCI_ERS_RESULT_DISCONNECT or PCI_ERS_RESULT_NO_AER_DRIVER then even after successful recovery (using reset_link()) pcie_do_recovery() will report the recovery result as failure" which is described in commit 6d2c89441571 ("PCI/ERR: Update error status after reset_link()"). Refer to the Documentation/PCI/pci-error-recovery.rst. As the error_detect() is mandatory callback if the pci_err_handlers is implemented, if it return the PCI_ERS_RESULT_DISCONNECT, it means the driver doesn't want to recover at all; For the case PCI_ERS_RESULT_NO_AER_DRIVER, if the pci_err_handlers is not implemented, the failure is more expected. Fixes: commit 6d2c89441571 ("PCI/ERR: Update error status after reset_link()") Signed-off-by: Hou Zhiqiang --- drivers/pci/pcie/err.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/pci/pcie/err.c b/drivers/pci/pcie/err.c index 14bb8f54723e..84f72342259c 100644 --- a/drivers/pci/pcie/err.c +++ b/drivers/pci/pcie/err.c @@ -165,8 +165,7 @@ pci_ers_result_t pcie_do_recovery(struct pci_dev *dev, pci_dbg(dev, "broadcast error_detected message\n"); if (state == pci_channel_io_frozen) { pci_walk_bus(bus, report_frozen_detected, ); - status = reset_link(dev); - if (status != PCI_ERS_RESULT_RECOVERED) { + if (reset_link(dev) != PCI_ERS_RESULT_RECOVERED) { pci_warn(dev, "link reset failed\n"); goto failed; } -- 2.17.1
[PATCH 4/4] dts/arm64/layerscape: Clean PCIe controller compatible strings
From: Hou Zhiqiang Removed the wrong compatible string "snps,dw-pcie", in case match incorrect driver. Signed-off-by: Hou Zhiqiang --- arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi | 2 +- arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi | 6 +++--- arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi | 6 +++--- arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi | 6 +++--- arch/arm64/boot/dts/freescale/fsl-ls2088a.dtsi | 8 arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi | 12 6 files changed, 18 insertions(+), 22 deletions(-) diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi index 68ac78c4564d..d3fe0771d3a0 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi @@ -475,7 +475,7 @@ }; pcie@340 { - compatible = "fsl,ls1012a-pcie", "snps,dw-pcie"; + compatible = "fsl,ls1012a-pcie"; reg = <0x00 0x0340 0x0 0x0010 /* controller registers */ 0x40 0x 0x0 0x2000>; /* configuration space */ reg-names = "regs", "config"; diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi index 6cc4c87614b6..1b61782df73e 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi @@ -661,7 +661,7 @@ }; pcie@340 { - compatible = "fsl,ls1043a-pcie", "snps,dw-pcie"; + compatible = "fsl,ls1043a-pcie"; reg = <0x00 0x0340 0x0 0x0010 /* controller registers */ 0x40 0x 0x0 0x2000>; /* configuration space */ reg-names = "regs", "config"; @@ -686,7 +686,7 @@ }; pcie@350 { - compatible = "fsl,ls1043a-pcie", "snps,dw-pcie"; + compatible = "fsl,ls1043a-pcie"; reg = <0x00 0x0350 0x0 0x0010 /* controller registers */ 0x48 0x 0x0 0x2000>; /* configuration space */ reg-names = "regs", "config"; @@ -711,7 +711,7 @@ }; pcie@360 { - compatible = "fsl,ls1043a-pcie", "snps,dw-pcie"; + compatible = "fsl,ls1043a-pcie"; reg = <0x00 0x0360 0x0 0x0010 /* controller registers */ 0x50 0x 0x0 0x2000>; /* configuration space */ reg-names = "regs", "config"; diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi index 3a2a14a8e187..71585aefe1ef 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi @@ -630,7 +630,7 @@ }; pcie@340 { - compatible = "fsl,ls1046a-pcie", "snps,dw-pcie"; + compatible = "fsl,ls1046a-pcie"; reg = <0x00 0x0340 0x0 0x0010 /* controller registers */ 0x40 0x 0x0 0x2000>; /* configuration space */ reg-names = "regs", "config"; @@ -655,7 +655,7 @@ }; pcie@350 { - compatible = "fsl,ls1046a-pcie", "snps,dw-pcie"; + compatible = "fsl,ls1046a-pcie"; reg = <0x00 0x0350 0x0 0x0010 /* controller registers */ 0x48 0x 0x0 0x2000>; /* configuration space */ reg-names = "regs", "config"; @@ -680,7 +680,7 @@ }; pcie@360 { - compatible = "fsl,ls1046a-pcie", "snps,dw-pcie"; + compatible = "fsl,ls1046a-pcie"; reg = <0x00 0x0360 0x0 0x0010 /* controller registers */ 0x50 0x 0x0 0x2000>; /* configuration space */ reg-names = "regs", "config"; diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi index a07f612ab56b..10b253c88a16 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi @@ -512,7 +512,7 @@ }; pcie@340 { - compatible = "fsl,ls1088a-pcie", "snps,dw-pcie"; + compatible = "fsl,ls1088a-pcie"; reg = <0x00 0x0340 0x0 0x0010 /* controller registers */ 0x20 0x 0x0
[PATCH 4/4] dts/arm64/layerscape: Clean PCIe controller compatible strings
From: Hou Zhiqiang Removed the wrong compatible string "snps,dw-pcie", in case match incorrect driver. Signed-off-by: Hou Zhiqiang --- arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi | 2 +- arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi | 6 +++--- arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi | 6 +++--- arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi | 6 +++--- arch/arm64/boot/dts/freescale/fsl-ls2088a.dtsi | 8 arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi | 12 6 files changed, 18 insertions(+), 22 deletions(-) diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi index 68ac78c4564d..d3fe0771d3a0 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi @@ -475,7 +475,7 @@ }; pcie@340 { - compatible = "fsl,ls1012a-pcie", "snps,dw-pcie"; + compatible = "fsl,ls1012a-pcie"; reg = <0x00 0x0340 0x0 0x0010 /* controller registers */ 0x40 0x 0x0 0x2000>; /* configuration space */ reg-names = "regs", "config"; diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi index 6cc4c87614b6..1b61782df73e 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi @@ -661,7 +661,7 @@ }; pcie@340 { - compatible = "fsl,ls1043a-pcie", "snps,dw-pcie"; + compatible = "fsl,ls1043a-pcie"; reg = <0x00 0x0340 0x0 0x0010 /* controller registers */ 0x40 0x 0x0 0x2000>; /* configuration space */ reg-names = "regs", "config"; @@ -686,7 +686,7 @@ }; pcie@350 { - compatible = "fsl,ls1043a-pcie", "snps,dw-pcie"; + compatible = "fsl,ls1043a-pcie"; reg = <0x00 0x0350 0x0 0x0010 /* controller registers */ 0x48 0x 0x0 0x2000>; /* configuration space */ reg-names = "regs", "config"; @@ -711,7 +711,7 @@ }; pcie@360 { - compatible = "fsl,ls1043a-pcie", "snps,dw-pcie"; + compatible = "fsl,ls1043a-pcie"; reg = <0x00 0x0360 0x0 0x0010 /* controller registers */ 0x50 0x 0x0 0x2000>; /* configuration space */ reg-names = "regs", "config"; diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi index 3a2a14a8e187..71585aefe1ef 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi @@ -630,7 +630,7 @@ }; pcie@340 { - compatible = "fsl,ls1046a-pcie", "snps,dw-pcie"; + compatible = "fsl,ls1046a-pcie"; reg = <0x00 0x0340 0x0 0x0010 /* controller registers */ 0x40 0x 0x0 0x2000>; /* configuration space */ reg-names = "regs", "config"; @@ -655,7 +655,7 @@ }; pcie@350 { - compatible = "fsl,ls1046a-pcie", "snps,dw-pcie"; + compatible = "fsl,ls1046a-pcie"; reg = <0x00 0x0350 0x0 0x0010 /* controller registers */ 0x48 0x 0x0 0x2000>; /* configuration space */ reg-names = "regs", "config"; @@ -680,7 +680,7 @@ }; pcie@360 { - compatible = "fsl,ls1046a-pcie", "snps,dw-pcie"; + compatible = "fsl,ls1046a-pcie"; reg = <0x00 0x0360 0x0 0x0010 /* controller registers */ 0x50 0x 0x0 0x2000>; /* configuration space */ reg-names = "regs", "config"; diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi index a07f612ab56b..10b253c88a16 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi @@ -512,7 +512,7 @@ }; pcie@340 { - compatible = "fsl,ls1088a-pcie", "snps,dw-pcie"; + compatible = "fsl,ls1088a-pcie"; reg = <0x00 0x0340 0x0 0x0010 /* controller registers */ 0x20 0x 0x0
[PATCH 2/4] doc/layerscape-pci: removed unsuitable compatible string
From: Hou Zhiqiang Removed the compatible string "snps,dw-pcie", it is for the reference platform driver for PCI RC IP Protoyping Kits based on the ARC SDP, so it is not suitable for all platform with designware PCIe controller, and platform vendors have themselves' drivers. The compatible string "snsp,dw-pcie" was added by mistake and it's not matched that time, but it is matched because pcie drivers has been collected recently. Signed-off-by: Hou Zhiqiang --- Documentation/devicetree/bindings/pci/layerscape-pci.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/pci/layerscape-pci.txt b/Documentation/devicetree/bindings/pci/layerscape-pci.txt index 5eb1c202932f..9b2b8d66d1f4 100644 --- a/Documentation/devicetree/bindings/pci/layerscape-pci.txt +++ b/Documentation/devicetree/bindings/pci/layerscape-pci.txt @@ -13,8 +13,8 @@ information. Required properties: - compatible: should contain the platform identifier such as: -"fsl,ls1021a-pcie", "snps,dw-pcie" -"fsl,ls2080a-pcie", "fsl,ls2085a-pcie", "snps,dw-pcie" +"fsl,ls1021a-pcie" +"fsl,ls2080a-pcie", "fsl,ls2085a-pcie" "fsl,ls2088a-pcie" "fsl,ls1088a-pcie" "fsl,ls1046a-pcie" @@ -36,7 +36,7 @@ Required properties: Example: pcie@340 { - compatible = "fsl,ls1021a-pcie", "snps,dw-pcie"; + compatible = "fsl,ls1021a-pcie"; reg = <0x00 0x0340 0x0 0x0001 /* controller registers */ 0x40 0x 0x0 0x2000>; /* configuration space */ reg-names = "regs", "config"; -- 2.17.1
[PATCH 3/4] dts/arm/ls1021a: Clean PCIe controller compatible strings
From: Hou Zhiqiang Removed the wrong compatible string "snps,dw-pcie", in case match incorrect driver. Signed-off-by: Hou Zhiqiang --- arch/arm/boot/dts/ls1021a.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/ls1021a.dtsi b/arch/arm/boot/dts/ls1021a.dtsi index f70025c2ab0f..13e91d577a26 100644 --- a/arch/arm/boot/dts/ls1021a.dtsi +++ b/arch/arm/boot/dts/ls1021a.dtsi @@ -716,7 +716,7 @@ }; pcie@340 { - compatible = "fsl,ls1021a-pcie", "snps,dw-pcie"; + compatible = "fsl,ls1021a-pcie"; reg = <0x00 0x0340 0x0 0x0001 /* controller registers */ 0x40 0x 0x0 0x2000>; /* configuration space */ reg-names = "regs", "config"; @@ -739,7 +739,7 @@ }; pcie@350 { - compatible = "fsl,ls1021a-pcie", "snps,dw-pcie"; + compatible = "fsl,ls1021a-pcie"; reg = <0x00 0x0350 0x0 0x0001 /* controller registers */ 0x48 0x 0x0 0x2000>; /* configuration space */ reg-names = "regs", "config"; -- 2.17.1
[PATCH 2/4] doc/layerscape-pci: removed unsuitable compatible string
From: Hou Zhiqiang Removed the compatible string "snps,dw-pcie", it is for the reference platform driver for PCI RC IP Protoyping Kits based on the ARC SDP, so it is not suitable for all platform with designware PCIe controller, and platform vendors have themselves' drivers. The compatible string "snsp,dw-pcie" was added by mistake and it's not matched that time, but it is matched because pcie drivers has been collected recently. Signed-off-by: Hou Zhiqiang --- Documentation/devicetree/bindings/pci/layerscape-pci.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/pci/layerscape-pci.txt b/Documentation/devicetree/bindings/pci/layerscape-pci.txt index 5eb1c202932f..9b2b8d66d1f4 100644 --- a/Documentation/devicetree/bindings/pci/layerscape-pci.txt +++ b/Documentation/devicetree/bindings/pci/layerscape-pci.txt @@ -13,8 +13,8 @@ information. Required properties: - compatible: should contain the platform identifier such as: -"fsl,ls1021a-pcie", "snps,dw-pcie" -"fsl,ls2080a-pcie", "fsl,ls2085a-pcie", "snps,dw-pcie" +"fsl,ls1021a-pcie" +"fsl,ls2080a-pcie", "fsl,ls2085a-pcie" "fsl,ls2088a-pcie" "fsl,ls1088a-pcie" "fsl,ls1046a-pcie" @@ -36,7 +36,7 @@ Required properties: Example: pcie@340 { - compatible = "fsl,ls1021a-pcie", "snps,dw-pcie"; + compatible = "fsl,ls1021a-pcie"; reg = <0x00 0x0340 0x0 0x0001 /* controller registers */ 0x40 0x 0x0 0x2000>; /* configuration space */ reg-names = "regs", "config"; -- 2.17.1
[PATCH 3/4] dts/arm/ls1021a: Clean PCIe controller compatible strings
From: Hou Zhiqiang Removed the wrong compatible string "snps,dw-pcie", in case match incorrect driver. Signed-off-by: Hou Zhiqiang --- arch/arm/boot/dts/ls1021a.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/ls1021a.dtsi b/arch/arm/boot/dts/ls1021a.dtsi index f70025c2ab0f..13e91d577a26 100644 --- a/arch/arm/boot/dts/ls1021a.dtsi +++ b/arch/arm/boot/dts/ls1021a.dtsi @@ -716,7 +716,7 @@ }; pcie@340 { - compatible = "fsl,ls1021a-pcie", "snps,dw-pcie"; + compatible = "fsl,ls1021a-pcie"; reg = <0x00 0x0340 0x0 0x0001 /* controller registers */ 0x40 0x 0x0 0x2000>; /* configuration space */ reg-names = "regs", "config"; @@ -739,7 +739,7 @@ }; pcie@350 { - compatible = "fsl,ls1021a-pcie", "snps,dw-pcie"; + compatible = "fsl,ls1021a-pcie"; reg = <0x00 0x0350 0x0 0x0001 /* controller registers */ 0x48 0x 0x0 0x2000>; /* configuration space */ reg-names = "regs", "config"; -- 2.17.1
[PATCH 1/4] doc/layerscape-pci: update the PCIe compatible strings
From: Hou Zhiqiang The pcie compatible string for LS1043A was lost, so add it. Signed-off-by: Hou Zhiqiang --- Documentation/devicetree/bindings/pci/layerscape-pci.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/pci/layerscape-pci.txt b/Documentation/devicetree/bindings/pci/layerscape-pci.txt index 66df1e81e0b8..5eb1c202932f 100644 --- a/Documentation/devicetree/bindings/pci/layerscape-pci.txt +++ b/Documentation/devicetree/bindings/pci/layerscape-pci.txt @@ -18,6 +18,7 @@ Required properties: "fsl,ls2088a-pcie" "fsl,ls1088a-pcie" "fsl,ls1046a-pcie" +"fsl,ls1043a-pcie" "fsl,ls1012a-pcie" - reg: base addresses and lengths of the PCIe controller register blocks. - interrupts: A list of interrupt outputs of the controller. Must contain an -- 2.17.1
[PATCH 0/4] dts/layerscape-pci: removed unsuitable compatible string
From: Hou Zhiqiang Removed the compatible string "snps,dw-pcie" from FSL layerscape-pci compatible string list. Hou Zhiqiang (4): doc/layerscape-pci: update the PCIe compatible strings doc/layerscape-pci: removed unsuitable compatible string dts/arm/ls1021a: Clean PCIe controller compatible strings dts/arm64/layerscape: Clean PCIe controller compatible strings .../devicetree/bindings/pci/layerscape-pci.txt | 7 --- arch/arm/boot/dts/ls1021a.dtsi | 4 ++-- arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi | 2 +- arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi | 6 +++--- arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi | 6 +++--- arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi | 6 +++--- arch/arm64/boot/dts/freescale/fsl-ls2088a.dtsi | 8 arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi | 12 8 files changed, 24 insertions(+), 27 deletions(-) -- 2.17.1
[PATCH 1/4] doc/layerscape-pci: update the PCIe compatible strings
From: Hou Zhiqiang The pcie compatible string for LS1043A was lost, so add it. Signed-off-by: Hou Zhiqiang --- Documentation/devicetree/bindings/pci/layerscape-pci.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/pci/layerscape-pci.txt b/Documentation/devicetree/bindings/pci/layerscape-pci.txt index 66df1e81e0b8..5eb1c202932f 100644 --- a/Documentation/devicetree/bindings/pci/layerscape-pci.txt +++ b/Documentation/devicetree/bindings/pci/layerscape-pci.txt @@ -18,6 +18,7 @@ Required properties: "fsl,ls2088a-pcie" "fsl,ls1088a-pcie" "fsl,ls1046a-pcie" +"fsl,ls1043a-pcie" "fsl,ls1012a-pcie" - reg: base addresses and lengths of the PCIe controller register blocks. - interrupts: A list of interrupt outputs of the controller. Must contain an -- 2.17.1
[PATCH 0/4] dts/layerscape-pci: removed unsuitable compatible string
From: Hou Zhiqiang Removed the compatible string "snps,dw-pcie" from FSL layerscape-pci compatible string list. Hou Zhiqiang (4): doc/layerscape-pci: update the PCIe compatible strings doc/layerscape-pci: removed unsuitable compatible string dts/arm/ls1021a: Clean PCIe controller compatible strings dts/arm64/layerscape: Clean PCIe controller compatible strings .../devicetree/bindings/pci/layerscape-pci.txt | 7 --- arch/arm/boot/dts/ls1021a.dtsi | 4 ++-- arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi | 2 +- arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi | 6 +++--- arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi | 6 +++--- arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi | 6 +++--- arch/arm64/boot/dts/freescale/fsl-ls2088a.dtsi | 8 arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi | 12 8 files changed, 24 insertions(+), 27 deletions(-) -- 2.17.1
[PATCHv3 0/2] mtd: m25p80: restore the addressing mode when exiting
From: Hou ZhiqiangRestore the status to be compatible with legacy devices. Take Freescale eSPI boot for example, it copies (in 3 Byte addressing mode) the RCW and bootloader images from SPI flash without firing a reset signal previously, so the reboot command will fail without reseting the addressing mode of SPI flash. Hou Zhiqiang (2): mtd: spi-nor: add an API to restore the status of SPI flash chip mtd: m25p80: restore the status of SPI flash when exiting Documentation/mtd/spi-nor.txt | 3 +++ drivers/mtd/devices/m25p80.c | 9 + drivers/mtd/spi-nor/spi-nor.c | 10 ++ include/linux/mtd/spi-nor.h | 6 ++ 4 files changed, 28 insertions(+) -- 2.14.1
[PATCHv3 1/2] mtd: spi-nor: add an API to restore the status of SPI flash chip
From: Hou ZhiqiangAdd this API to restore the status of SPI flash chip to the default such as addressing mode, whenever detach the driver from device or reboot the system. Signed-off-by: Hou Zhiqiang --- V3: - no change. Documentation/mtd/spi-nor.txt | 3 +++ drivers/mtd/spi-nor/spi-nor.c | 10 ++ include/linux/mtd/spi-nor.h | 6 ++ 3 files changed, 19 insertions(+) diff --git a/Documentation/mtd/spi-nor.txt b/Documentation/mtd/spi-nor.txt index 548d6306ebca..da1fbff5a24c 100644 --- a/Documentation/mtd/spi-nor.txt +++ b/Documentation/mtd/spi-nor.txt @@ -60,3 +60,6 @@ The main API is spi_nor_scan(). Before you call the hook, a driver should initialize the necessary fields for spi_nor{}. Please see drivers/mtd/spi-nor/spi-nor.c for detail. Please also refer to fsl-quadspi.c when you want to write a new driver for a SPI NOR controller. +Another API is spi_nor_restore(), this is used to restore the status of SPI +flash chip such as addressing mode. Call it whenever detach the driver from +device or reboot the system. diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index bc266f70a15b..4a925378d434 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -2713,6 +2713,16 @@ static void spi_nor_resume(struct mtd_info *mtd) dev_err(dev, "resume() failed\n"); } +void spi_nor_restore(struct spi_nor *nor) +{ + /* restore the addressing mode */ + if ((nor->addr_width == 4) && + (JEDEC_MFR(nor->info) != SNOR_MFR_SPANSION) && + !(nor->info->flags & SPI_NOR_4B_OPCODES)) + set_4byte(nor, nor->info, 0); +} +EXPORT_SYMBOL_GPL(spi_nor_restore); + int spi_nor_scan(struct spi_nor *nor, const char *name, const struct spi_nor_hwcaps *hwcaps) { diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h index d0c66a0975cf..0a182c3d0884 100644 --- a/include/linux/mtd/spi-nor.h +++ b/include/linux/mtd/spi-nor.h @@ -399,4 +399,10 @@ struct spi_nor_hwcaps { int spi_nor_scan(struct spi_nor *nor, const char *name, const struct spi_nor_hwcaps *hwcaps); +/* + * spi_nor_restore_addr_mode() - restore the status of SPI NOR + * @nor: the spi_nor structure + */ +void spi_nor_restore(struct spi_nor *nor); + #endif -- 2.14.1
[PATCHv3 0/2] mtd: m25p80: restore the addressing mode when exiting
From: Hou Zhiqiang Restore the status to be compatible with legacy devices. Take Freescale eSPI boot for example, it copies (in 3 Byte addressing mode) the RCW and bootloader images from SPI flash without firing a reset signal previously, so the reboot command will fail without reseting the addressing mode of SPI flash. Hou Zhiqiang (2): mtd: spi-nor: add an API to restore the status of SPI flash chip mtd: m25p80: restore the status of SPI flash when exiting Documentation/mtd/spi-nor.txt | 3 +++ drivers/mtd/devices/m25p80.c | 9 + drivers/mtd/spi-nor/spi-nor.c | 10 ++ include/linux/mtd/spi-nor.h | 6 ++ 4 files changed, 28 insertions(+) -- 2.14.1
[PATCHv3 1/2] mtd: spi-nor: add an API to restore the status of SPI flash chip
From: Hou Zhiqiang Add this API to restore the status of SPI flash chip to the default such as addressing mode, whenever detach the driver from device or reboot the system. Signed-off-by: Hou Zhiqiang --- V3: - no change. Documentation/mtd/spi-nor.txt | 3 +++ drivers/mtd/spi-nor/spi-nor.c | 10 ++ include/linux/mtd/spi-nor.h | 6 ++ 3 files changed, 19 insertions(+) diff --git a/Documentation/mtd/spi-nor.txt b/Documentation/mtd/spi-nor.txt index 548d6306ebca..da1fbff5a24c 100644 --- a/Documentation/mtd/spi-nor.txt +++ b/Documentation/mtd/spi-nor.txt @@ -60,3 +60,6 @@ The main API is spi_nor_scan(). Before you call the hook, a driver should initialize the necessary fields for spi_nor{}. Please see drivers/mtd/spi-nor/spi-nor.c for detail. Please also refer to fsl-quadspi.c when you want to write a new driver for a SPI NOR controller. +Another API is spi_nor_restore(), this is used to restore the status of SPI +flash chip such as addressing mode. Call it whenever detach the driver from +device or reboot the system. diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index bc266f70a15b..4a925378d434 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -2713,6 +2713,16 @@ static void spi_nor_resume(struct mtd_info *mtd) dev_err(dev, "resume() failed\n"); } +void spi_nor_restore(struct spi_nor *nor) +{ + /* restore the addressing mode */ + if ((nor->addr_width == 4) && + (JEDEC_MFR(nor->info) != SNOR_MFR_SPANSION) && + !(nor->info->flags & SPI_NOR_4B_OPCODES)) + set_4byte(nor, nor->info, 0); +} +EXPORT_SYMBOL_GPL(spi_nor_restore); + int spi_nor_scan(struct spi_nor *nor, const char *name, const struct spi_nor_hwcaps *hwcaps) { diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h index d0c66a0975cf..0a182c3d0884 100644 --- a/include/linux/mtd/spi-nor.h +++ b/include/linux/mtd/spi-nor.h @@ -399,4 +399,10 @@ struct spi_nor_hwcaps { int spi_nor_scan(struct spi_nor *nor, const char *name, const struct spi_nor_hwcaps *hwcaps); +/* + * spi_nor_restore_addr_mode() - restore the status of SPI NOR + * @nor: the spi_nor structure + */ +void spi_nor_restore(struct spi_nor *nor); + #endif -- 2.14.1
[PATCHv3 2/2] mtd: m25p80: restore the status of SPI flash when exiting
From: Hou ZhiqiangRestore the status to be compatible with legacy devices. Take Freescale eSPI boot for example, it copies (in 3 Byte addressing mode) the RCW and bootloader images from SPI flash without firing a reset signal previously, so the reboot command will fail without reseting the addressing mode of SPI flash. This patch implement .shutdown function to restore the status in reboot process, and add the same operation to the .remove function. Signed-off-by: Hou Zhiqiang --- V3: - Modified the commit to make this patch specific. drivers/mtd/devices/m25p80.c | 9 + 1 file changed, 9 insertions(+) diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index dbe6a1de2bb8..a4e18f6aaa33 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -307,10 +307,18 @@ static int m25p_remove(struct spi_device *spi) { struct m25p *flash = spi_get_drvdata(spi); + spi_nor_restore(>spi_nor); + /* Clean up MTD stuff. */ return mtd_device_unregister(>spi_nor.mtd); } +static void m25p_shutdown(struct spi_device *spi) +{ + struct m25p *flash = spi_get_drvdata(spi); + + spi_nor_restore(>spi_nor); +} /* * Do NOT add to this array without reading the following: * @@ -386,6 +394,7 @@ static struct spi_driver m25p80_driver = { .id_table = m25p_ids, .probe = m25p_probe, .remove = m25p_remove, + .shutdown = m25p_shutdown, /* REVISIT: many of these chips have deep power-down modes, which * should clearly be entered on suspend() to minimize power use. -- 2.14.1
[PATCHv3 2/2] mtd: m25p80: restore the status of SPI flash when exiting
From: Hou Zhiqiang Restore the status to be compatible with legacy devices. Take Freescale eSPI boot for example, it copies (in 3 Byte addressing mode) the RCW and bootloader images from SPI flash without firing a reset signal previously, so the reboot command will fail without reseting the addressing mode of SPI flash. This patch implement .shutdown function to restore the status in reboot process, and add the same operation to the .remove function. Signed-off-by: Hou Zhiqiang --- V3: - Modified the commit to make this patch specific. drivers/mtd/devices/m25p80.c | 9 + 1 file changed, 9 insertions(+) diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index dbe6a1de2bb8..a4e18f6aaa33 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -307,10 +307,18 @@ static int m25p_remove(struct spi_device *spi) { struct m25p *flash = spi_get_drvdata(spi); + spi_nor_restore(>spi_nor); + /* Clean up MTD stuff. */ return mtd_device_unregister(>spi_nor.mtd); } +static void m25p_shutdown(struct spi_device *spi) +{ + struct m25p *flash = spi_get_drvdata(spi); + + spi_nor_restore(>spi_nor); +} /* * Do NOT add to this array without reading the following: * @@ -386,6 +394,7 @@ static struct spi_driver m25p80_driver = { .id_table = m25p_ids, .probe = m25p_probe, .remove = m25p_remove, + .shutdown = m25p_shutdown, /* REVISIT: many of these chips have deep power-down modes, which * should clearly be entered on suspend() to minimize power use. -- 2.14.1
[PATCHv2 2/2] mtd: m25p80: restore the status of SPI flash when stop using it
From: Hou ZhiqiangImplement .shutdown function to restore the status in reboot process, and add the same operation to the .remove function. Signed-off-by: Hou Zhiqiang --- V2: - Changed code format slightly. drivers/mtd/devices/m25p80.c | 9 + 1 file changed, 9 insertions(+) diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index dbe6a1de2bb8..a4e18f6aaa33 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -307,10 +307,18 @@ static int m25p_remove(struct spi_device *spi) { struct m25p *flash = spi_get_drvdata(spi); + spi_nor_restore(>spi_nor); + /* Clean up MTD stuff. */ return mtd_device_unregister(>spi_nor.mtd); } +static void m25p_shutdown(struct spi_device *spi) +{ + struct m25p *flash = spi_get_drvdata(spi); + + spi_nor_restore(>spi_nor); +} /* * Do NOT add to this array without reading the following: * @@ -386,6 +394,7 @@ static struct spi_driver m25p80_driver = { .id_table = m25p_ids, .probe = m25p_probe, .remove = m25p_remove, + .shutdown = m25p_shutdown, /* REVISIT: many of these chips have deep power-down modes, which * should clearly be entered on suspend() to minimize power use. -- 2.14.1
[PATCHv2 2/2] mtd: m25p80: restore the status of SPI flash when stop using it
From: Hou Zhiqiang Implement .shutdown function to restore the status in reboot process, and add the same operation to the .remove function. Signed-off-by: Hou Zhiqiang --- V2: - Changed code format slightly. drivers/mtd/devices/m25p80.c | 9 + 1 file changed, 9 insertions(+) diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index dbe6a1de2bb8..a4e18f6aaa33 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -307,10 +307,18 @@ static int m25p_remove(struct spi_device *spi) { struct m25p *flash = spi_get_drvdata(spi); + spi_nor_restore(>spi_nor); + /* Clean up MTD stuff. */ return mtd_device_unregister(>spi_nor.mtd); } +static void m25p_shutdown(struct spi_device *spi) +{ + struct m25p *flash = spi_get_drvdata(spi); + + spi_nor_restore(>spi_nor); +} /* * Do NOT add to this array without reading the following: * @@ -386,6 +394,7 @@ static struct spi_driver m25p80_driver = { .id_table = m25p_ids, .probe = m25p_probe, .remove = m25p_remove, + .shutdown = m25p_shutdown, /* REVISIT: many of these chips have deep power-down modes, which * should clearly be entered on suspend() to minimize power use. -- 2.14.1
[PATCHv2 1/2] mtd: spi-nor: add an API to restore the status of SPI flash chip
From: Hou ZhiqiangAdd this API to restore the status of SPI flash chip to the default such as addressing mode, whenever detach the driver from device or reboot the system. Signed-off-by: Hou Zhiqiang --- V2: - Changed the API name and added the comments and kernel document for it. - Export this symbol for modules. Documentation/mtd/spi-nor.txt | 3 +++ drivers/mtd/spi-nor/spi-nor.c | 10 ++ include/linux/mtd/spi-nor.h | 6 ++ 3 files changed, 19 insertions(+) diff --git a/Documentation/mtd/spi-nor.txt b/Documentation/mtd/spi-nor.txt index 548d6306ebca..da1fbff5a24c 100644 --- a/Documentation/mtd/spi-nor.txt +++ b/Documentation/mtd/spi-nor.txt @@ -60,3 +60,6 @@ The main API is spi_nor_scan(). Before you call the hook, a driver should initialize the necessary fields for spi_nor{}. Please see drivers/mtd/spi-nor/spi-nor.c for detail. Please also refer to fsl-quadspi.c when you want to write a new driver for a SPI NOR controller. +Another API is spi_nor_restore(), this is used to restore the status of SPI +flash chip such as addressing mode. Call it whenever detach the driver from +device or reboot the system. diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index bc266f70a15b..4a925378d434 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -2713,6 +2713,16 @@ static void spi_nor_resume(struct mtd_info *mtd) dev_err(dev, "resume() failed\n"); } +void spi_nor_restore(struct spi_nor *nor) +{ + /* restore the addressing mode */ + if ((nor->addr_width == 4) && + (JEDEC_MFR(nor->info) != SNOR_MFR_SPANSION) && + !(nor->info->flags & SPI_NOR_4B_OPCODES)) + set_4byte(nor, nor->info, 0); +} +EXPORT_SYMBOL_GPL(spi_nor_restore); + int spi_nor_scan(struct spi_nor *nor, const char *name, const struct spi_nor_hwcaps *hwcaps) { diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h index d0c66a0975cf..0a182c3d0884 100644 --- a/include/linux/mtd/spi-nor.h +++ b/include/linux/mtd/spi-nor.h @@ -399,4 +399,10 @@ struct spi_nor_hwcaps { int spi_nor_scan(struct spi_nor *nor, const char *name, const struct spi_nor_hwcaps *hwcaps); +/* + * spi_nor_restore_addr_mode() - restore the status of SPI NOR + * @nor: the spi_nor structure + */ +void spi_nor_restore(struct spi_nor *nor); + #endif -- 2.14.1
[PATCHv2 1/2] mtd: spi-nor: add an API to restore the status of SPI flash chip
From: Hou Zhiqiang Add this API to restore the status of SPI flash chip to the default such as addressing mode, whenever detach the driver from device or reboot the system. Signed-off-by: Hou Zhiqiang --- V2: - Changed the API name and added the comments and kernel document for it. - Export this symbol for modules. Documentation/mtd/spi-nor.txt | 3 +++ drivers/mtd/spi-nor/spi-nor.c | 10 ++ include/linux/mtd/spi-nor.h | 6 ++ 3 files changed, 19 insertions(+) diff --git a/Documentation/mtd/spi-nor.txt b/Documentation/mtd/spi-nor.txt index 548d6306ebca..da1fbff5a24c 100644 --- a/Documentation/mtd/spi-nor.txt +++ b/Documentation/mtd/spi-nor.txt @@ -60,3 +60,6 @@ The main API is spi_nor_scan(). Before you call the hook, a driver should initialize the necessary fields for spi_nor{}. Please see drivers/mtd/spi-nor/spi-nor.c for detail. Please also refer to fsl-quadspi.c when you want to write a new driver for a SPI NOR controller. +Another API is spi_nor_restore(), this is used to restore the status of SPI +flash chip such as addressing mode. Call it whenever detach the driver from +device or reboot the system. diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index bc266f70a15b..4a925378d434 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -2713,6 +2713,16 @@ static void spi_nor_resume(struct mtd_info *mtd) dev_err(dev, "resume() failed\n"); } +void spi_nor_restore(struct spi_nor *nor) +{ + /* restore the addressing mode */ + if ((nor->addr_width == 4) && + (JEDEC_MFR(nor->info) != SNOR_MFR_SPANSION) && + !(nor->info->flags & SPI_NOR_4B_OPCODES)) + set_4byte(nor, nor->info, 0); +} +EXPORT_SYMBOL_GPL(spi_nor_restore); + int spi_nor_scan(struct spi_nor *nor, const char *name, const struct spi_nor_hwcaps *hwcaps) { diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h index d0c66a0975cf..0a182c3d0884 100644 --- a/include/linux/mtd/spi-nor.h +++ b/include/linux/mtd/spi-nor.h @@ -399,4 +399,10 @@ struct spi_nor_hwcaps { int spi_nor_scan(struct spi_nor *nor, const char *name, const struct spi_nor_hwcaps *hwcaps); +/* + * spi_nor_restore_addr_mode() - restore the status of SPI NOR + * @nor: the spi_nor structure + */ +void spi_nor_restore(struct spi_nor *nor); + #endif -- 2.14.1