[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); - 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
[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
[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 = &pci->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 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)&default_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)&default_data, + }, + { PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, PCI_DEVICE_ID_LS1088A), + .driver_data = (kernel_ulong_t)&default_data, + }, { PCI_DEVICE_DATA(SYNOPSYS, EDDA, NULL) }, { PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_AM654), .driver_data = (kernel_ulong_t)&am654_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 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 = &ls_pcie_ep_ops, + .dw_pcie_ops = &dw_ls_pcie_ep_ops, +}; + +static const struct ls_pcie_ep_drvdata ls2_ep_drvdata = { + .func_offset = 0x2, + .ops = &ls_pcie_ep_ops, + .dw_pcie_ops = &dw_ls_pcie_ep_ops, +}; + +static const struct of_device_id ls_pcie_ep_of_match[] = { + { .compatible = "fsl,ls1046a-pcie-ep", .data = &ls1_ep_drvdata }, + { .compatible = "fsl,ls1088a-pcie-ep", .data = &ls2_ep_drvdata }, + { .compatible = "fsl,ls2088a-pcie-ep", .data = &ls2_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 = &pci->ep; - ep->ops = &pcie_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 = &ls_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)&default_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)&am654_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 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 &ls_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 = &pdev->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 = &ls_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, &ep->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; v
[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
[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
[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 = (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 = &ls1021_pcie_host_ops, - .dw_pcie_ops = &dw_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 = &ls_pcie_host_ops, - .dw_pcie_ops = &dw_ls_pcie_ops, -}; - -static const struct ls_pcie_drvdata ls1046_drvdata = { - .lut_offset = 0x8, - .ltssm_shift = 24, - .lut_dbg = 0x407fc, - .ops = &ls_pcie_host_ops, - .dw_pcie_ops = &dw_ls_pcie_ops, -}; - -static const struct ls_pcie_drvdata ls2080_drvdata = { - .lut_offset = 0x8, - .ltssm_shift = 0, - .lut_dbg = 0x7fc, - .ops = &ls_pcie_host_ops, - .dw_pcie_ops = &dw_ls_pcie_ops, -}; - -s
[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 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 &gic 0 111 IRQ_TYPE_LEVEL_HIGH>, < 0 0 3 &gic 0 112 IRQ_TYPE_LEVEL_HIGH>, < 0 0 4 &gic 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 &gic 0 111 0x4>, < 0 0 3 &gic 0 112 0x4>, < 0 0 4 &gic 0 113 0x4>; + big-endian; status = "disabled"; }; @@ -916,6 +917,7 @@ < 0 0 2 &gic 0 121 0x4>, < 0 0 3 &gic 0 122 0x4>, < 0 0 4 &gic 0 123 0x4>; + big-endian; status = "disabled"; }; @@ -942,6 +944,7 @@ < 0 0 2 &gic 0 155 0x4>, < 0 0 3 &gic 0 156 0x4>, < 0 0 4 &gic 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 GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>, < 0 0 3 &gic GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>, < 0 0 4 &gic GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>; + big-endian; status = "disabled"; }; @@ -830,6 +831,7 @@ < 0 0 2 &gic GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>, < 0 0 3 &gic GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>, < 0 0 4 &gic GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>; + big-endian; status = "disabled"; }; @@ -866,6 +868,7 @@ < 0 0 2 &gic GIC_SPI 154 IRQ_TYPE_LEVEL_HIGH>, < 0 0 3 &gic GIC_SPI 154 IRQ_TYPE_LEVEL_HIGH>, < 0 0 4 &gic GIC_SPI 154 IRQ_TYPE_LEVEL_HIGH>; + big-endian; status = "disabled"; }; -- 2.17.1
[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 = <&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 = <&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 = <&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 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); + 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); + val &= ~PMXMTTURNOFF; + regmap_write(pcie
[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 = (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 = &ls1021_pcie_host_ops, - .dw_pcie_ops = &dw_ls1021_pcie_ops, -}; - -static const struct ls_pcie_drvdata ls1043_drvdata = { - .lut_offset = 0x1, - .ltssm_shift = 24, - .lut_dbg = 0x7fc, - .ops = &ls_pcie_host_ops, - .dw_pcie_ops = &dw_ls_pcie_ops, -}; - -static const struct ls_pcie_drvdata ls1046_drvdata = { - .lut_offset = 0x8, - .ltssm_shift = 24, - .lut_dbg = 0x407fc, - .ops = &ls_pcie_host_ops, - .dw_pcie_ops = &dw_ls_
[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
[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 &gic 0 111 IRQ_TYPE_LEVEL_HIGH>, < 0 0 3 &gic 0 112 IRQ_TYPE_LEVEL_HIGH>, < 0 0 4 &gic 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 &gic 0 111 0x4>, < 0 0 3 &gic 0 112 0x4>, < 0 0 4 &gic 0 113 0x4>; + big-endian; status = "disabled"; }; @@ -863,6 +864,7 @@ < 0 0 2 &gic 0 121 0x4>, < 0 0 3 &gic 0 122 0x4>, < 0 0 4 &gic 0 123 0x4>; + big-endian; status = "disabled"; }; @@ -889,6 +891,7 @@ < 0 0 2 &gic 0 155 0x4>, < 0 0 3 &gic 0 156 0x4>, < 0 0 4 &gic 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 GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>, < 0 0 3 &gic GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>, < 0 0 4 &gic GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>; + big-endian; status = "disabled"; }; @@ -777,6 +778,7 @@ < 0 0 2 &gic GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>, < 0 0 3 &gic GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>, < 0 0 4 &gic GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>; + big-endian; status = "disabled"; }; @@ -813,6 +815,7 @@ < 0 0 2 &gic GIC_SPI 154 IRQ_TYPE_LEVEL_HIGH>, < 0 0 3 &gic GIC_SPI 154 IRQ_TYPE_LEVEL_HIGH>, < 0 0 4 &gic 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 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); + val |= PMXMTTURNOFF; + regmap_write(pcie->scfg, SCFG_PEXPMWRCR(pcie->index), val); + + mdelay(10); + + /* Clear Turn_off message */ + regmap_
[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, &val); @@ -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, &val); @@ -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 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 = <&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 = <&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 = <&scfg 2>; #address-cells = <3>; #size-cells = <2>; device_type = "pci"; -- 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] 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
[PATCH 0/2] arm64: dts: Add ls1088a DSPI device tree nodes
From: Hou Zhiqiang LS1088A reuse LS2085A DSPI driver, this patchset just adds device tree nodes and adds compatible entry to documentation. Hou Zhiqiang (2): arm64: dts: ls1088a: add DT nodes for DSPI support Documentation: fsl: dspi: Add a compatible string for ls1088a DSPI .../devicetree/bindings/spi/spi-fsl-dspi.txt | 1 + arch/arm64/boot/dts/freescale/fsl-ls1088a-qds.dts | 28 ++ arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi | 13 ++ 3 files changed, 42 insertions(+) -- 2.14.1
[PATCH 2/2] Documentation: fsl: dspi: Add a compatible string for ls1088a DSPI
From: Hou Zhiqiang Add a new compatible string "fsl,ls1088a-dspi". Signed-off-by: Hou Zhiqiang --- Documentation/devicetree/bindings/spi/spi-fsl-dspi.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/spi/spi-fsl-dspi.txt b/Documentation/devicetree/bindings/spi/spi-fsl-dspi.txt index dcc7eaada511..5fc467211cc6 100644 --- a/Documentation/devicetree/bindings/spi/spi-fsl-dspi.txt +++ b/Documentation/devicetree/bindings/spi/spi-fsl-dspi.txt @@ -6,6 +6,7 @@ Required properties: or "fsl,ls2080a-dspi" followed by "fsl,ls2085a-dspi" "fsl,ls1012a-dspi" followed by "fsl,ls1021a-v1.0-dspi" + "fsl,ls1088a-dspi" followed by "fsl,ls2085a-dspi" - reg : Offset and length of the register set for the device - interrupts : Should contain SPI controller interrupt - clocks: from common clock binding: handle to dspi clock. -- 2.14.1
[PATCH 1/2] arm64: dts: ls1088a: add DT nodes for DSPI support
From: Hou Zhiqiang Signed-off-by: Hou Zhiqiang --- arch/arm64/boot/dts/freescale/fsl-ls1088a-qds.dts | 28 +++ arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi| 13 +++ 2 files changed, 41 insertions(+) diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1088a-qds.dts b/arch/arm64/boot/dts/freescale/fsl-ls1088a-qds.dts index 30128051d0c0..cf5b85b93ae6 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls1088a-qds.dts +++ b/arch/arm64/boot/dts/freescale/fsl-ls1088a-qds.dts @@ -134,6 +134,34 @@ }; }; +&dspi { + status = "okay"; + + dflash0: n25q128a { + #address-cells = <1>; + #size-cells = <1>; + compatible = "n25q128a11", "jedec,spi-nor"; + reg = <0>; + spi-max-frequency = <300>; + }; + + dflash1: sst25wf040b { + #address-cells = <1>; + #size-cells = <1>; + compatible = "sst,sst25wf040b", "jedec,spi-nor"; + reg = <1>; + spi-max-frequency = <300>; + }; + + dflash2: en25s64 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "eon,en25s64", "jedec,spi-nor"; + reg = <2>; + spi-max-frequency = <300>; + }; +}; + &duart0 { status = "okay"; }; diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi index bd80e9a2e67c..f5ed3878abb7 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi @@ -276,6 +276,19 @@ }; }; + dspi: dspi@210 { + compatible = "fsl,ls1088a-dspi", "fsl,ls2085a-dspi"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x0 0x210 0x0 0x1>; + interrupts = <0 26 0x4>; /* Level high type */ + clocks = <&clockgen 4 3>; + clock-names = "dspi"; + spi-num-chipselects = <5>; + bus-num = <0>; + status = "disabled"; + }; + duart0: serial@21c0500 { compatible = "fsl,ns16550", "ns16550a"; reg = <0x0 0x21c0500 0x0 0x100>; -- 2.14.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 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 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 0
[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
[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 = (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 = &ls1021_pcie_host_ops, - .dw_pcie_ops = &dw_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 = &ls_pcie_host_ops, - .dw_pcie_ops = &dw_ls_pcie_ops, -}; - -static const struct ls_pcie_drvdata ls1046_drvdata = { - .lut_offset = 0x8, - .ltssm_shift = 24, - .lut_dbg = 0x407fc, - .ops = &ls_pcie_host_ops, - .dw_pcie_ops = &dw_ls_pcie_ops, -}; - -static const struct ls_pcie_drvdata ls2080_drvdata = { - .lut_offset = 0x8, - .ltssm_shift = 0, - .lut_dbg = 0x7fc, - .ops = &ls_pcie_host_ops, - .dw_pcie_ops
[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 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 &gic 0 111 IRQ_TYPE_LEVEL_HIGH>, < 0 0 3 &gic 0 112 IRQ_TYPE_LEVEL_HIGH>, < 0 0 4 &gic 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 &gic 0 111 0x4>, < 0 0 3 &gic 0 112 0x4>, < 0 0 4 &gic 0 113 0x4>; + big-endian; status = "disabled"; }; @@ -916,6 +917,7 @@ < 0 0 2 &gic 0 121 0x4>, < 0 0 3 &gic 0 122 0x4>, < 0 0 4 &gic 0 123 0x4>; + big-endian; status = "disabled"; }; @@ -942,6 +944,7 @@ < 0 0 2 &gic 0 155 0x4>, < 0 0 3 &gic 0 156 0x4>, < 0 0 4 &gic 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 GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>, < 0 0 3 &gic GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>, < 0 0 4 &gic GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>; + big-endian; status = "disabled"; }; @@ -830,6 +831,7 @@ < 0 0 2 &gic GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>, < 0 0 3 &gic GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>, < 0 0 4 &gic GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>; + big-endian; status = "disabled"; }; @@ -866,6 +868,7 @@ < 0 0 2 &gic GIC_SPI 154 IRQ_TYPE_LEVEL_HIGH>, < 0 0 3 &gic GIC_SPI 154 IRQ_TYPE_LEVEL_HIGH>, < 0 0 4 &gic GIC_SPI 154 IRQ_TYPE_LEVEL_HIGH>; + big-endian; status = "disabled"; }; -- 2.17.1
[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 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); + 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); + val &= ~PMXMTTURNOFF; + regmap_write(pcie->scfg, SCFG_PEXPMWRCR(pcie-
[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 = <&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 = <&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 = <&scfg 2>; #address-cells = <3>; #size-cells = <2>; device_type = "pci"; -- 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 = &pci->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 = &pdev->dev; - struct dw_pcie *pci = dra7xx->pci; - ep = &pci->ep; ep->ops = &pcie_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 = &pci->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 = &pdev->dev;
[PATCHv2 1/2] PCI: Disable MSI for Freescale PCIe RC mode
From: Hou Zhiqiang The Freescale PCIe controller advertises the MSI/MSI-X capability in both RC and Endpoint mode, but in RC mode it doesn't support MSI/MSI-X by itself, it can only transfer MSI/MSI-X from downstream devices. So add this quirk to prevent use of MSI/MSI-X in RC mode. Signed-off-by: Hou Zhiqiang Acked-by: Minghuan Lian --- V2: - Fixed a typo in the commit message. drivers/pci/quirks.c | 8 1 file changed, 8 insertions(+) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index a4d33619a7bb..c1063a420f0c 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -4799,3 +4799,11 @@ static void quirk_no_ats(struct pci_dev *pdev) /* AMD Stoney platform GPU */ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x98e4, quirk_no_ats); #endif /* CONFIG_PCI_ATS */ + +/* Freescale PCIe doesn't support MSI in RC mode */ +static void quirk_fsl_no_msi(struct pci_dev *pdev) +{ + if (pci_pcie_type(pdev) == PCI_EXP_TYPE_ROOT_PORT) + pdev->no_msi = 1; +} +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_FREESCALE, PCI_ANY_ID, quirk_fsl_no_msi); -- 2.14.1
[PATCHv2 0/2] PCI: layerscape: add fixes for layerscape-pcie errata
From: Hou Zhiqiang The [1/2] is to fix layerscape PCIe MSI/MSI-X capability errata. The [2/2] is to change the default AXI system error response behavior for PCI Express outbound non-posted requests. Hou Zhiqiang (1): PCI: Disable MSI for Freescale PCIe RC mode Minghuan Lian (1): pci/layerscape: change the default error response behavior drivers/pci/dwc/pci-layerscape.c | 11 +++ drivers/pci/quirks.c | 8 2 files changed, 19 insertions(+) -- 2.14.1
[PATCHv2 2/2] pci/layerscape: change the default error response behavior
From: Minghuan Lian By default, when the PCIe controller experiences an erroneous completion from an external completer for its outbound non-posted request, it always sends an OKAY response to the device's internal AXI slave system interface. However, such default system error response behavior cannot be used for other types of outbound non-posted requests. For example, the outbound memory read transaction requires an actual ERROR response, like UR completion or completion timeout. The patch is to fix it by forwarding the error response of the non-posted request. Signed-off-by: Minghuan Lian Signed-off-by: Hou Zhiqiang --- V2: - Removed the parameter ls_pcie which is for debugging. drivers/pci/dwc/pci-layerscape.c | 11 +++ 1 file changed, 11 insertions(+) diff --git a/drivers/pci/dwc/pci-layerscape.c b/drivers/pci/dwc/pci-layerscape.c index 87fa486bee2c..3a4277a5ab2c 100644 --- a/drivers/pci/dwc/pci-layerscape.c +++ b/drivers/pci/dwc/pci-layerscape.c @@ -33,6 +33,8 @@ /* 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 @@ -124,6 +126,14 @@ 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); @@ -135,6 +145,7 @@ 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.14.1
[PATCHv2 0/3] arm64: dts: ls1012a: add the DTS node for DSPI support
From: Hou Zhiqiang Corrected the subject for 3/5 patch v1. Yuan Yao (3): arm64: dts: ls1012a: add the DTS node for DSPI support Documentation: fsl: dspi: Add fsl,ls1012a-dspi compatible string Documentation: dt: mtd: add sst25wf040b and en25s64 to the SPI NOR support list .../devicetree/bindings/mtd/jedec,spi-nor.txt | 2 ++ .../devicetree/bindings/spi/spi-fsl-dspi.txt | 1 + arch/arm64/boot/dts/freescale/fsl-ls1012a-qds.dts | 33 ++ arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi | 13 + 4 files changed, 49 insertions(+) -- 2.14.1
[PATCHv2 2/3] Documentation: fsl: dspi: Add fsl,ls1012a-dspi compatible string
From: Yuan Yao new compatible string: "fsl,ls1012a-dspi". Signed-off-by: Yuan Yao Signed-off-by: Hou Zhiqiang Acked-by: Rob Herring --- V2: - No change Documentation/devicetree/bindings/spi/spi-fsl-dspi.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/spi/spi-fsl-dspi.txt b/Documentation/devicetree/bindings/spi/spi-fsl-dspi.txt index ff5893d275a2..800c483b0076 100644 --- a/Documentation/devicetree/bindings/spi/spi-fsl-dspi.txt +++ b/Documentation/devicetree/bindings/spi/spi-fsl-dspi.txt @@ -5,6 +5,7 @@ Required properties: "fsl,ls2085a-dspi" or "fsl,ls2080a-dspi" followed by "fsl,ls2085a-dspi" + "fsl,ls1012a-dspi" followed by "fsl,ls1021a-v1.0-dspi" - reg : Offset and length of the register set for the device - interrupts : Should contain SPI controller interrupt - clocks: from common clock binding: handle to dspi clock. -- 2.14.1
[PATCHv2 1/3] arm64: dts: ls1012a: add the DTS node for DSPI support
From: Yuan Yao Signed-off-by: Yuan Yao Signed-off-by: Hou Zhiqiang --- V2: - No change arch/arm64/boot/dts/freescale/fsl-ls1012a-qds.dts | 33 +++ arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi| 13 + 2 files changed, 46 insertions(+) diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1012a-qds.dts b/arch/arm64/boot/dts/freescale/fsl-ls1012a-qds.dts index 8c013b54db14..cdc4aee75227 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls1012a-qds.dts +++ b/arch/arm64/boot/dts/freescale/fsl-ls1012a-qds.dts @@ -93,6 +93,39 @@ }; }; +&dspi { + bus-num = <0>; + status = "okay"; + + flash@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "n25q128a11", "jedec,spi-nor"; + reg = <0>; + spi-max-frequency = <1000>; + }; + + flash@1 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "sst25wf040b", "jedec,spi-nor"; + spi-cpol; + spi-cpha; + reg = <1>; + spi-max-frequency = <1000>; + }; + + flash@2 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "en25s64", "jedec,spi-nor"; + spi-cpol; + spi-cpha; + reg = <2>; + spi-max-frequency = <1000>; + }; +}; + &duart0 { status = "okay"; }; diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi index df83915d6ea6..09ce00022728 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi @@ -355,6 +355,19 @@ status = "disabled"; }; + dspi: dspi@210 { + compatible = "fsl,ls1012a-dspi", "fsl,ls1021a-v1.0-dspi"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x0 0x210 0x0 0x1>; + interrupts = <0 64 IRQ_TYPE_LEVEL_HIGH>; + clock-names = "dspi"; + clocks = <&clockgen 4 0>; + spi-num-chipselects = <5>; + big-endian; + status = "disabled"; + }; + duart0: serial@21c0500 { compatible = "fsl,ns16550", "ns16550a"; reg = <0x00 0x21c0500 0x0 0x100>; -- 2.14.1
[PATCHv2 3/3] Documentation: dt: mtd: add sst25wf040b and en25s64 to the SPI NOR support list
From: Yuan Yao The chip sst25wf040b and en25s64 are compatible with SPI NOR flash. Signed-off-by: Yuan Yao Signed-off-by: Hou Zhiqiang Acked-by: Rob Herring --- V2: - Corrected the subject. Documentation/devicetree/bindings/mtd/jedec,spi-nor.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/mtd/jedec,spi-nor.txt b/Documentation/devicetree/bindings/mtd/jedec,spi-nor.txt index 9ce35af8507c..4cab5d85cf6f 100644 --- a/Documentation/devicetree/bindings/mtd/jedec,spi-nor.txt +++ b/Documentation/devicetree/bindings/mtd/jedec,spi-nor.txt @@ -13,6 +13,7 @@ Required properties: at25df321a at25df641 at26df081a + en25s64 mr25h256 mr25h10 mr25h40 @@ -31,6 +32,7 @@ Required properties: s25fl008k s25fl064k sst25vf040b + sst25wf040b m25p40 m25p80 m25p16 -- 2.14.1
[PATCH 0/5] arm64: add ls1012a and ls1046a pcie support
From: Hou Zhiqiang This patch set adds ls1012a MSI and PCIe support, including driver and device tree nodes. The ls1046a's MSI support patch and PCIe driver patch has been applied, so only adds the PCIe device tree nodes. Hou Zhiqiang (5): irqchip/ls-scfg-msi: add LS1012a MSI support arm64: dts: ls1012a: Add MSI controller DT node PCI: layerscape: Add support for ls1012a arm64: dts: ls1012a: Add PCIe controller DT node arm64: dts: ls1046a: add PCIe controller DT nodes .../interrupt-controller/fsl,ls-scfg-msi.txt | 1 + .../devicetree/bindings/pci/layerscape-pci.txt | 1 + arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi | 31 + arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi | 75 ++ drivers/irqchip/irq-ls-scfg-msi.c | 1 + drivers/pci/dwc/pci-layerscape.c | 1 + 6 files changed, 110 insertions(+) -- 2.14.1
[PATCH 3/5] PCI: layerscape: Add support for ls1012a
From: Hou Zhiqiang Signed-off-by: Hou Zhiqiang --- Documentation/devicetree/bindings/pci/layerscape-pci.txt | 1 + drivers/pci/dwc/pci-layerscape.c | 1 + 2 files changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/pci/layerscape-pci.txt b/Documentation/devicetree/bindings/pci/layerscape-pci.txt index c0484da0f20d..66df1e81e0b8 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,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 entry for each entry in the interrupt-names property. diff --git a/drivers/pci/dwc/pci-layerscape.c b/drivers/pci/dwc/pci-layerscape.c index 87fa486bee2c..3b01e309a55e 100644 --- a/drivers/pci/dwc/pci-layerscape.c +++ b/drivers/pci/dwc/pci-layerscape.c @@ -253,6 +253,7 @@ static struct ls_pcie_drvdata ls2088_drvdata = { }; static const struct of_device_id ls_pcie_of_match[] = { + { .compatible = "fsl,ls1012a-pcie", .data = &ls1046_drvdata }, { .compatible = "fsl,ls1021a-pcie", .data = &ls1021_drvdata }, { .compatible = "fsl,ls1043a-pcie", .data = &ls1043_drvdata }, { .compatible = "fsl,ls1046a-pcie", .data = &ls1046_drvdata }, -- 2.14.1
[PATCH 5/5] arm64: dts: ls1046a: add PCIe controller DT nodes
From: Hou Zhiqiang LS1046a implements 3 PCIe 3.0 controllers. Signed-off-by: Hou Zhiqiang --- arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi | 75 ++ 1 file changed, 75 insertions(+) diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi index c8ff0baddf1d..eac8c32f64b0 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi @@ -661,6 +661,81 @@ ; }; + pcie@340 { + compatible = "fsl,ls1046a-pcie", "snps,dw-pcie"; + reg = <0x00 0x0340 0x0 0x0010 /* controller registers */ + 0x40 0x 0x0 0x2000>; /* configuration space */ + reg-names = "regs", "config"; + interrupts = , /* controller interrupt */ +; /* PME interrupt */ + interrupt-names = "aer", "pme"; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; + dma-coherent; + num-lanes = <4>; + bus-range = <0x0 0xff>; + ranges = <0x8100 0x0 0x 0x40 0x0001 0x0 0x0001 /* downstream I/O */ + 0x8200 0x0 0x4000 0x40 0x4000 0x0 0x4000>; /* non-prefetchable memory */ + msi-parent = <&msi1>, <&msi2>, <&msi3>; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 7>; + interrupt-map = < 0 0 1 &gic GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>, + < 0 0 2 &gic GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>, + < 0 0 3 &gic GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>, + < 0 0 4 &gic GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>; + }; + + pcie@350 { + compatible = "fsl,ls1046a-pcie", "snps,dw-pcie"; + reg = <0x00 0x0350 0x0 0x0010 /* controller registers */ + 0x48 0x 0x0 0x2000>; /* configuration space */ + reg-names = "regs", "config"; + interrupts = , /* controller interrupt */ +; /* PME interrupt */ + interrupt-names = "aer", "pme"; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; + dma-coherent; + num-lanes = <2>; + bus-range = <0x0 0xff>; + ranges = <0x8100 0x0 0x 0x48 0x0001 0x0 0x0001 /* downstream I/O */ + 0x8200 0x0 0x4000 0x48 0x4000 0x0 0x4000>; /* non-prefetchable memory */ + msi-parent = <&msi2>, <&msi3>, <&msi1>; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 7>; + interrupt-map = < 0 0 1 &gic GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>, + < 0 0 2 &gic GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>, + < 0 0 3 &gic GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>, + < 0 0 4 &gic GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>; + }; + + pcie@360 { + compatible = "fsl,ls1046a-pcie", "snps,dw-pcie"; + reg = <0x00 0x0360 0x0 0x0010 /* controller registers */ + 0x50 0x 0x0 0x2000>; /* configuration space */ + reg-names = "regs", "config"; + interrupts = , /* controller interrupt */ +; /* PME interrupt */ + interrupt-names = "aer", "pme"; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; + dma-coherent; + num-lanes = <2>; + bus-range = <0x0 0xff>; + ranges = <0x8100 0x0 0x 0x50 0x0001 0x0 0x0001 /* downstream I/O */ + 0x8200 0x0 0x4000 0x50 0x4000 0x0 0x4000>; /* non-prefetchable memory */ + msi-parent = <&msi3>, <&msi1>, <&msi2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 7>; + interrupt-map = < 0 0 1 &gic GIC_SPI 154 IRQ_TYPE_LEVEL_HIGH>, +
[PATCH 2/5] arm64: dts: ls1012a: Add MSI controller DT node
From: Hou Zhiqiang Add MSI controller node for ls1012a platform. Signed-off-by: Hou Zhiqiang --- arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi | 7 +++ 1 file changed, 7 insertions(+) diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi index df83915d6ea6..a7698ac7264b 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi @@ -471,5 +471,12 @@ dr_mode = "host"; phy_type = "ulpi"; }; + + msi: msi-controller1@1572000 { + compatible = "fsl,ls1012a-msi"; + reg = <0x0 0x1572000 0x0 0x8>; + msi-controller; + interrupts = <0 126 IRQ_TYPE_LEVEL_HIGH>; + }; }; }; -- 2.14.1
[PATCH 4/5] arm64: dts: ls1012a: Add PCIe controller DT node
From: Hou Zhiqiang Add PCIe controller node for ls1012a platform. Signed-off-by: Hou Zhiqiang --- arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi | 24 1 file changed, 24 insertions(+) diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi index a7698ac7264b..140570d45ff3 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi @@ -478,5 +478,29 @@ msi-controller; interrupts = <0 126 IRQ_TYPE_LEVEL_HIGH>; }; + + pcie@340 { + compatible = "fsl,ls1012a-pcie", "snps,dw-pcie"; + reg = <0x00 0x0340 0x0 0x0010 /* controller registers */ + 0x40 0x 0x0 0x2000>; /* configuration space */ + reg-names = "regs", "config"; + interrupts = <0 118 0x4>, /* controller interrupt */ +<0 117 0x4>; /* PME interrupt */ + interrupt-names = "aer", "pme"; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; + num-lanes = <4>; + bus-range = <0x0 0xff>; + ranges = <0x8100 0x0 0x 0x40 0x0001 0x0 0x0001 /* downstream I/O */ + 0x8200 0x0 0x4000 0x40 0x4000 0x0 0x4000>; /* non-prefetchable memory */ + msi-parent = <&msi>; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 7>; + interrupt-map = < 0 0 1 &gic 0 110 IRQ_TYPE_LEVEL_HIGH>, + < 0 0 2 &gic 0 111 IRQ_TYPE_LEVEL_HIGH>, + < 0 0 3 &gic 0 112 IRQ_TYPE_LEVEL_HIGH>, + < 0 0 4 &gic 0 113 IRQ_TYPE_LEVEL_HIGH>; + }; }; }; -- 2.14.1
[PATCH 1/5] irqchip/ls-scfg-msi: add LS1012a MSI support
From: Hou Zhiqiang The ls1012a implement only 1 msi controller, and it is the same as ls1043a. Signed-off-by: Hou Zhiqiang --- .../devicetree/bindings/interrupt-controller/fsl,ls-scfg-msi.txt | 1 + drivers/irqchip/irq-ls-scfg-msi.c| 1 + 2 files changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/interrupt-controller/fsl,ls-scfg-msi.txt b/Documentation/devicetree/bindings/interrupt-controller/fsl,ls-scfg-msi.txt index 49ccabbfa6f3..a4ff93d6b7f3 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/fsl,ls-scfg-msi.txt +++ b/Documentation/devicetree/bindings/interrupt-controller/fsl,ls-scfg-msi.txt @@ -8,6 +8,7 @@ Required properties: "fsl,ls1043a-msi" "fsl,ls1046a-msi" "fsl,ls1043a-v1.1-msi" + "fsl,ls1012a-msi" - msi-controller: indicates that this is a PCIe MSI controller node - reg: physical base address of the controller and length of memory mapped. - interrupts: an interrupt to the parent interrupt controller. diff --git a/drivers/irqchip/irq-ls-scfg-msi.c b/drivers/irqchip/irq-ls-scfg-msi.c index 119f4ef0d421..57e3d900f19e 100644 --- a/drivers/irqchip/irq-ls-scfg-msi.c +++ b/drivers/irqchip/irq-ls-scfg-msi.c @@ -316,6 +316,7 @@ static const struct of_device_id ls_scfg_msi_id[] = { { .compatible = "fsl,1s1021a-msi", .data = &ls1021_msi_cfg}, { .compatible = "fsl,1s1043a-msi", .data = &ls1021_msi_cfg}, + { .compatible = "fsl,ls1012a-msi", .data = &ls1021_msi_cfg }, { .compatible = "fsl,ls1021a-msi", .data = &ls1021_msi_cfg }, { .compatible = "fsl,ls1043a-msi", .data = &ls1021_msi_cfg }, { .compatible = "fsl,ls1043a-v1.1-msi", .data = &ls1043_v1_1_msi_cfg }, -- 2.14.1
[PATCH 2/2] pci/layerscape: change the default error response behavior
From: Minghuan Lian By default, when the PCIe controller experiences an erroneous completion from an external completer for its outbound non-posted request, it always sends an OKAY response to the device's internal AXI slave system interface. However, such default system error response behavior cannot be used for other types of outbound non-posted requests. For example, the outbound memory read transaction requires an actual ERROR response, like UR completion or completion timeout. The patch is to fix it by forwarding the error response of the non-posted request. Signed-off-by: Minghuan Lian Signed-off-by: Hou Zhiqiang --- drivers/pci/dwc/pci-layerscape.c | 25 + 1 file changed, 25 insertions(+) diff --git a/drivers/pci/dwc/pci-layerscape.c b/drivers/pci/dwc/pci-layerscape.c index 3b01e309a55e..a647090c140e 100644 --- a/drivers/pci/dwc/pci-layerscape.c +++ b/drivers/pci/dwc/pci-layerscape.c @@ -33,6 +33,8 @@ /* 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 @@ -54,6 +56,19 @@ struct ls_pcie { #define to_ls_pcie(x) dev_get_drvdata((x)->dev) +static int err_response_flag = 1; + +static int __init ls_pcie_param(char *p) +{ + if (p && strncmp(p, "no-err-response", 15) == 0) + err_response_flag = 0; + else + err_response_flag = 1; + + return 0; +} +early_param("ls_pcie", ls_pcie_param); + static bool ls_pcie_is_bridge(struct ls_pcie *pcie) { struct dw_pcie *pci = pcie->pci; @@ -124,6 +139,14 @@ 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); @@ -135,6 +158,8 @@ 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); + if (err_response_flag) + ls_pcie_fix_error_response(pcie); dw_pcie_dbi_ro_wr_en(pci); ls_pcie_clear_multifunction(pcie); -- 2.14.1
[PATCH 0/2] PCI: layerscape: add fixes for layerscape-pcie errata
From: Hou Zhiqiang The [1/2] is to fix layerscape PCIe MSI/MSI-X capability errata. The [2/2] is to change the default AXI system error response behavior for PCI Express outbound non-posted requests. Hou Zhiqiang (1): PCI: Disable MSI for Freescale PCIe RC mode Minghuan Lian (1): pci/layerscape: change the default error response behavior drivers/pci/dwc/pci-layerscape.c | 25 + drivers/pci/quirks.c | 8 2 files changed, 33 insertions(+) -- 2.14.1
[PATCH 1/2] PCI: Disable MSI for Freescale PCIe RC mode
From: Hou Zhiqiang The Freescale PCIe controller advertises the MSI/MSI-X capability in both RC and Endpoint mode, but in RC mode it doesn't support MSI/MSI-X by it self, it can only transfer MSI/MSI-X from downstream devices. So add this quirk to prevent use of MSI/MSI-X in RC mode. Signed-off-by: Hou Zhiqiang --- drivers/pci/quirks.c | 8 1 file changed, 8 insertions(+) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index a4d33619a7bb..c1063a420f0c 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -4799,3 +4799,11 @@ static void quirk_no_ats(struct pci_dev *pdev) /* AMD Stoney platform GPU */ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x98e4, quirk_no_ats); #endif /* CONFIG_PCI_ATS */ + +/* Freescale PCIe doesn't support MSI in RC mode */ +static void quirk_fsl_no_msi(struct pci_dev *pdev) +{ + if (pci_pcie_type(pdev) == PCI_EXP_TYPE_ROOT_PORT) + pdev->no_msi = 1; +} +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_FREESCALE, PCI_ANY_ID, quirk_fsl_no_msi); -- 2.14.1
[PATCHv4 3/9] arm64: dts: ls1043a: fix typo of MSI compatible string
From: Minghuan Lian "1" should be replaced by "l". This is a typo. The patch is to fix it. Signed-off-by: Minghuan Lian Signed-off-by: Hou Zhiqiang --- v4-v1: - None arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi index 31fd77f..7ff98f4 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi @@ -653,21 +653,21 @@ }; msi1: msi-controller1@1571000 { - compatible = "fsl,1s1043a-msi"; + compatible = "fsl,ls1043a-msi"; reg = <0x0 0x1571000 0x0 0x8>; msi-controller; interrupts = <0 116 0x4>; }; msi2: msi-controller2@1572000 { - compatible = "fsl,1s1043a-msi"; + compatible = "fsl,ls1043a-msi"; reg = <0x0 0x1572000 0x0 0x8>; msi-controller; interrupts = <0 126 0x4>; }; msi3: msi-controller3@1573000 { - compatible = "fsl,1s1043a-msi"; + compatible = "fsl,ls1043a-msi"; reg = <0x0 0x1573000 0x0 0x8>; msi-controller; interrupts = <0 160 0x4>; -- 2.1.0.27.g96db324
[PATCHv4 7/9] irqchip/ls-scfg-msi: add LS1046a MSI support
From: Minghuan Lian LS1046a includes 4 MSIRs, each MSIR is assigned a dedicate GIC SPI interrupt and provides 32 MSI interrupts. Compared to previous MSI, LS1046a's IBS(interrupt bit select) shift is changed to 2 and total MSI interrupt number is changed to 128. The patch adds structure 'ls_scfg_msir' to describe MSIR setting and 'ibs_shift' to store the different value between the SoCs. Signed-off-by: Minghuan Lian Signed-off-by: Hou Zhiqiang --- v4: - None v3-v2: - keep the old misspelled compatible strings v2-v1: - MSI dts node change has been merged into the patch 6/9 drivers/irqchip/irq-ls-scfg-msi.c | 165 ++ 1 file changed, 130 insertions(+), 35 deletions(-) diff --git a/drivers/irqchip/irq-ls-scfg-msi.c b/drivers/irqchip/irq-ls-scfg-msi.c index cef67cc..0b1f34d 100644 --- a/drivers/irqchip/irq-ls-scfg-msi.c +++ b/drivers/irqchip/irq-ls-scfg-msi.c @@ -17,13 +17,24 @@ #include #include #include +#include #include #include #include -#define MSI_MAX_IRQS 32 -#define MSI_IBS_SHIFT 3 -#define MSIR 4 +#define MSI_IRQS_PER_MSIR 32 +#define MSI_MSIR_OFFSET4 + +struct ls_scfg_msi_cfg { + u32 ibs_shift; /* Shift of interrupt bit select */ +}; + +struct ls_scfg_msir { + struct ls_scfg_msi *msi_data; + unsigned int index; + unsigned int gic_irq; + void __iomem *reg; +}; struct ls_scfg_msi { spinlock_t lock; @@ -32,8 +43,11 @@ struct ls_scfg_msi { struct irq_domain *msi_domain; void __iomem*regs; phys_addr_t msiir_addr; - int irq; - DECLARE_BITMAP(used, MSI_MAX_IRQS); + struct ls_scfg_msi_cfg *cfg; + u32 msir_num; + struct ls_scfg_msir *msir; + u32 irqs_num; + unsigned long *used; }; static struct irq_chip ls_scfg_msi_irq_chip = { @@ -55,7 +69,7 @@ static void ls_scfg_msi_compose_msg(struct irq_data *data, struct msi_msg *msg) msg->address_hi = upper_32_bits(msi_data->msiir_addr); msg->address_lo = lower_32_bits(msi_data->msiir_addr); - msg->data = data->hwirq << MSI_IBS_SHIFT; + msg->data = data->hwirq; } static int ls_scfg_msi_set_affinity(struct irq_data *irq_data, @@ -81,8 +95,8 @@ static int ls_scfg_msi_domain_irq_alloc(struct irq_domain *domain, WARN_ON(nr_irqs != 1); spin_lock(&msi_data->lock); - pos = find_first_zero_bit(msi_data->used, MSI_MAX_IRQS); - if (pos < MSI_MAX_IRQS) + pos = find_first_zero_bit(msi_data->used, msi_data->irqs_num); + if (pos < msi_data->irqs_num) __set_bit(pos, msi_data->used); else err = -ENOSPC; @@ -106,7 +120,7 @@ static void ls_scfg_msi_domain_irq_free(struct irq_domain *domain, int pos; pos = d->hwirq; - if (pos < 0 || pos >= MSI_MAX_IRQS) { + if (pos < 0 || pos >= msi_data->irqs_num) { pr_err("failed to teardown msi. Invalid hwirq %d\n", pos); return; } @@ -123,15 +137,17 @@ static const struct irq_domain_ops ls_scfg_msi_domain_ops = { static void ls_scfg_msi_irq_handler(struct irq_desc *desc) { - struct ls_scfg_msi *msi_data = irq_desc_get_handler_data(desc); + struct ls_scfg_msir *msir = irq_desc_get_handler_data(desc); + struct ls_scfg_msi *msi_data = msir->msi_data; unsigned long val; - int pos, virq; + int pos, virq, hwirq; chained_irq_enter(irq_desc_get_chip(desc), desc); - val = ioread32be(msi_data->regs + MSIR); - for_each_set_bit(pos, &val, MSI_MAX_IRQS) { - virq = irq_find_mapping(msi_data->parent, (31 - pos)); + val = ioread32be(msir->reg); + for_each_set_bit(pos, &val, MSI_IRQS_PER_MSIR) { + hwirq = ((31 - pos) << msi_data->cfg->ibs_shift) | msir->index; + virq = irq_find_mapping(msi_data->parent, hwirq); if (virq) generic_handle_irq(virq); } @@ -143,7 +159,7 @@ static int ls_scfg_msi_domains_init(struct ls_scfg_msi *msi_data) { /* Initialize MSI domain parent */ msi_data->parent = irq_domain_add_linear(NULL, -MSI_MAX_IRQS, +msi_data->irqs_num, &ls_scfg_msi_domain_ops, msi_data); if (!msi_data->parent) { @@ -164,16 +180,87 @@ static int ls_scfg_msi_domains_init(struct ls_scfg_msi *msi_data) return 0; } +static int ls_scfg_msi_setup_hwirq(struct ls_scfg_msi *msi_data, int index) +{ + struct ls_scfg_msir *msir; + int virq, i, hwirq; + + virq = platform_get_irq(msi_data->pdev, index); + if (virq <= 0) + return -ENODEV; + +
[PATCHv4 5/9] arm64: dts: ls1043a: share all MSIs
From: Minghuan Lian In order to maximize the use of MSI, a PCIe controller will share all MSI controllers. The patch changes "msi-parent" to refer to all MSI controller dts nodes. Signed-off-by: Minghuan Lian Signed-off-by: Hou Zhiqiang --- v4-v1: - None arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi index 7ff98f4..d16b9cc 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi @@ -689,7 +689,7 @@ bus-range = <0x0 0xff>; ranges = <0x8100 0x0 0x 0x40 0x0001 0x0 0x0001 /* downstream I/O */ 0x8200 0x0 0x4000 0x40 0x4000 0x0 0x4000>; /* non-prefetchable memory */ - msi-parent = <&msi1>; + msi-parent = <&msi1>, <&msi2>, <&msi3>; #interrupt-cells = <1>; interrupt-map-mask = <0 0 0 7>; interrupt-map = < 0 0 1 &gic 0 110 0x4>, @@ -714,7 +714,7 @@ bus-range = <0x0 0xff>; ranges = <0x8100 0x0 0x 0x48 0x0001 0x0 0x0001 /* downstream I/O */ 0x8200 0x0 0x4000 0x48 0x4000 0x0 0x4000>; /* non-prefetchable memory */ - msi-parent = <&msi2>; + msi-parent = <&msi1>, <&msi2>, <&msi3>; #interrupt-cells = <1>; interrupt-map-mask = <0 0 0 7>; interrupt-map = < 0 0 1 &gic 0 120 0x4>, @@ -739,7 +739,7 @@ bus-range = <0x0 0xff>; ranges = <0x8100 0x0 0x 0x50 0x0001 0x0 0x0001 /* downstream I/O */ 0x8200 0x0 0x4000 0x50 0x4000 0x0 0x4000>; /* non-prefetchable memory */ - msi-parent = <&msi3>; + msi-parent = <&msi1>, <&msi2>, <&msi3>; #interrupt-cells = <1>; interrupt-map-mask = <0 0 0 7>; interrupt-map = < 0 0 1 &gic 0 154 0x4>, -- 2.1.0.27.g96db324
[PATCHv4 2/9] arm: dts: ls1021a: fix typo of MSI compatible string
From: Minghuan Lian "1" should be replaced by "l". This is a typo. The patch is to fix it. Signed-off-by: Minghuan Lian Signed-off-by: Hou Zhiqiang --- v4-v1: - None 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 7bb9df2..51b0f69 100644 --- a/arch/arm/boot/dts/ls1021a.dtsi +++ b/arch/arm/boot/dts/ls1021a.dtsi @@ -129,14 +129,14 @@ }; msi1: msi-controller@1570e00 { - compatible = "fsl,1s1021a-msi"; + compatible = "fsl,ls1021a-msi"; reg = <0x0 0x1570e00 0x0 0x8>; msi-controller; interrupts = ; }; msi2: msi-controller@1570e08 { - compatible = "fsl,1s1021a-msi"; + compatible = "fsl,ls1021a-msi"; reg = <0x0 0x1570e08 0x0 0x8>; msi-controller; interrupts = ; -- 2.1.0.27.g96db324
[PATCHv4 9/9] irqchip/ls-scfg-msi: add MSI affinity support
From: Minghuan Lian For LS1046a and LS1043a v1.1, the MSI controller has 4 MSIRs and 4 GIC SPI interrupts which can be associated with different Core. So we can support affinity to improve the performance. The MSI message data is a byte for Layerscape MSI. 76 5 4 3 2 1 0 | - | IBS | SRS | SRS bit0-1 is to select a MSIR which is associated with a CPU. IBS bit2-6 of ls1046, bit2-4 of ls1043a v1.1 is to select bit of the MSIR. With affinity, only bits of MSIR0(srs=0 cpu0) are available. All other bits of the MSIR1-3(cpu1-3) are reserved. The MSI hwirq always equals bit index of the MSIR0. When changing affinity, MSI message data will be appended corresponding SRS then MSI will be moved to the corresponding core. But in affinity mode, there is only 8 MSI interrupts for a controller of LS1043a v1.1. It cannot meet the requirement of the some PCIe devices such as 4 ports Ethernet card. In contrast, without affinity, all MSIRs can be used for core 0, the MSI interrupts can up to 32. So the parameter is added to control affinity mode. "lsmsi=no-affinity" will disable affinity and increase MSI interrupt number. Signed-off-by: Minghuan Lian Signed-off-by: Hou Zhiqiang --- v4: - None v3-v2: - 1. update the description - 2. remove unnecessary msir_index checking v2-v1: - None drivers/irqchip/irq-ls-scfg-msi.c | 68 --- 1 file changed, 63 insertions(+), 5 deletions(-) diff --git a/drivers/irqchip/irq-ls-scfg-msi.c b/drivers/irqchip/irq-ls-scfg-msi.c index 8d57a59..119f4ef 100644 --- a/drivers/irqchip/irq-ls-scfg-msi.c +++ b/drivers/irqchip/irq-ls-scfg-msi.c @@ -40,6 +40,7 @@ struct ls_scfg_msir { unsigned int gic_irq; unsigned int bit_start; unsigned int bit_end; + unsigned int srs; /* Shared interrupt register select */ void __iomem *reg; }; @@ -70,6 +71,19 @@ static struct msi_domain_info ls_scfg_msi_domain_info = { .chip = &ls_scfg_msi_irq_chip, }; +static int msi_affinity_flag = 1; + +static int __init early_parse_ls_scfg_msi(char *p) +{ + if (p && strncmp(p, "no-affinity", 11) == 0) + msi_affinity_flag = 0; + else + msi_affinity_flag = 1; + + return 0; +} +early_param("lsmsi", early_parse_ls_scfg_msi); + static void ls_scfg_msi_compose_msg(struct irq_data *data, struct msi_msg *msg) { struct ls_scfg_msi *msi_data = irq_data_get_irq_chip_data(data); @@ -77,12 +91,36 @@ static void ls_scfg_msi_compose_msg(struct irq_data *data, struct msi_msg *msg) msg->address_hi = upper_32_bits(msi_data->msiir_addr); msg->address_lo = lower_32_bits(msi_data->msiir_addr); msg->data = data->hwirq; + + if (msi_affinity_flag) + msg->data |= cpumask_first(data->common->affinity); } static int ls_scfg_msi_set_affinity(struct irq_data *irq_data, const struct cpumask *mask, bool force) { - return -EINVAL; + struct ls_scfg_msi *msi_data = irq_data_get_irq_chip_data(irq_data); + u32 cpu; + + if (!msi_affinity_flag) + return -EINVAL; + + if (!force) + cpu = cpumask_any_and(mask, cpu_online_mask); + else + cpu = cpumask_first(mask); + + if (cpu >= msi_data->msir_num) + return -EINVAL; + + if (msi_data->msir[cpu].gic_irq <= 0) { + pr_warn("cannot bind the irq to cpu%d\n", cpu); + return -EINVAL; + } + + cpumask_copy(irq_data->common->affinity, mask); + + return IRQ_SET_MASK_OK; } static struct irq_chip ls_scfg_msi_parent_chip = { @@ -158,7 +196,7 @@ static void ls_scfg_msi_irq_handler(struct irq_desc *desc) for_each_set_bit_from(pos, &val, size) { hwirq = ((msir->bit_end - pos) << msi_data->cfg->ibs_shift) | - msir->index; + msir->srs; virq = irq_find_mapping(msi_data->parent, hwirq); if (virq) generic_handle_irq(virq); @@ -221,10 +259,19 @@ static int ls_scfg_msi_setup_hwirq(struct ls_scfg_msi *msi_data, int index) ls_scfg_msi_irq_handler, msir); + if (msi_affinity_flag) { + /* Associate MSIR interrupt to the cpu */ + irq_set_affinity(msir->gic_irq, get_cpu_mask(index)); + msir->srs = 0; /* This value is determined by the CPU */ + } else + msir->srs = index; + /* Release the hwirqs corresponding to this MSIR */ - for (i = 0; i < msi_data->cfg->msir_irqs; i++) { - hwirq = i << msi_data->cfg->ibs_shift | msir->index; - bitmap_clear(msi_data->used, hwirq, 1); + if (!msi_affinity_flag || msir->index == 0) { + for (i = 0; i < msi_data->cfg->msir_irqs; i++) { + hwirq = i <
[PATCHv4 6/9] arm64: dts: ls1046a: add MSI dts node
From: Minghuan Lian LS1046a includes 3 MSI controllers. Each controller supports 128 interrupts. Signed-off-by: Minghuan Lian Acked-by: Rob Herring Signed-off-by: Hou Zhiqiang --- v4: - rebased code v3-v2: - None v2-v1: - change whitespace number .../interrupt-controller/fsl,ls-scfg-msi.txt | 1 + arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi | 31 ++ 2 files changed, 32 insertions(+) diff --git a/Documentation/devicetree/bindings/interrupt-controller/fsl,ls-scfg-msi.txt b/Documentation/devicetree/bindings/interrupt-controller/fsl,ls-scfg-msi.txt index 2755cd1..dde4552 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/fsl,ls-scfg-msi.txt +++ b/Documentation/devicetree/bindings/interrupt-controller/fsl,ls-scfg-msi.txt @@ -6,6 +6,7 @@ Required properties: Layerscape PCIe MSI controller block such as: "fsl,ls1021a-msi" "fsl,ls1043a-msi" + "fsl,ls1046a-msi" - msi-controller: indicates that this is a PCIe MSI controller node - reg: physical base address of the controller and length of memory mapped. - interrupts: an interrupt to the parent interrupt controller. diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi index dc1640b..c8ff0ba 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi @@ -630,6 +630,37 @@ interrupts = ; clocks = <&clockgen 4 1>; }; + + msi1: msi-controller@158 { + compatible = "fsl,ls1046a-msi"; + msi-controller; + reg = <0x0 0x158 0x0 0x1>; + interrupts = , +, +, +; + }; + + msi2: msi-controller@159 { + compatible = "fsl,ls1046a-msi"; + msi-controller; + reg = <0x0 0x159 0x0 0x1>; + interrupts = , +, +, +; + }; + + msi3: msi-controller@15a { + compatible = "fsl,ls1046a-msi"; + msi-controller; + reg = <0x0 0x15a 0x0 0x1>; + interrupts = , +, +, +; + }; + }; reserved-memory { -- 2.1.0.27.g96db324
[PATCHv4 8/9] irqchip/ls-scfg-msi: add LS1043a v1.1 MSI support
From: Minghuan Lian A MSI controller of LS1043a v1.0 only includes one MSIR and is assigned one GIC interrupt. In order to support affinity, LS1043a v1.1 MSI is assigned 4 MSIRs and 4 GIC interrupts. But the MSIR has the different offset and only supports 8 MSIs. The bits between variable bit_start and bit_end in structure ls_scfg_msir are used to show 8 MSI interrupts. msir_irqs and msir_base are added to describe the difference of MSI between LS1043a v1.1 and other SoCs. Signed-off-by: Minghuan Lian Acked-by: Rob Herring Signed-off-by: Hou Zhiqiang --- v4-v1: - None .../interrupt-controller/fsl,ls-scfg-msi.txt | 1 + drivers/irqchip/irq-ls-scfg-msi.c | 45 +++--- 2 files changed, 40 insertions(+), 6 deletions(-) diff --git a/Documentation/devicetree/bindings/interrupt-controller/fsl,ls-scfg-msi.txt b/Documentation/devicetree/bindings/interrupt-controller/fsl,ls-scfg-msi.txt index dde4552..49ccabb 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/fsl,ls-scfg-msi.txt +++ b/Documentation/devicetree/bindings/interrupt-controller/fsl,ls-scfg-msi.txt @@ -7,6 +7,7 @@ Required properties: "fsl,ls1021a-msi" "fsl,ls1043a-msi" "fsl,ls1046a-msi" + "fsl,ls1043a-v1.1-msi" - msi-controller: indicates that this is a PCIe MSI controller node - reg: physical base address of the controller and length of memory mapped. - interrupts: an interrupt to the parent interrupt controller. diff --git a/drivers/irqchip/irq-ls-scfg-msi.c b/drivers/irqchip/irq-ls-scfg-msi.c index 0b1f34d..8d57a59 100644 --- a/drivers/irqchip/irq-ls-scfg-msi.c +++ b/drivers/irqchip/irq-ls-scfg-msi.c @@ -25,14 +25,21 @@ #define MSI_IRQS_PER_MSIR 32 #define MSI_MSIR_OFFSET4 +#define MSI_LS1043V1_1_IRQS_PER_MSIR 8 +#define MSI_LS1043V1_1_MSIR_OFFSET 0x10 + struct ls_scfg_msi_cfg { u32 ibs_shift; /* Shift of interrupt bit select */ + u32 msir_irqs; /* The irq number per MSIR */ + u32 msir_base; /* The base address of MSIR */ }; struct ls_scfg_msir { struct ls_scfg_msi *msi_data; unsigned int index; unsigned int gic_irq; + unsigned int bit_start; + unsigned int bit_end; void __iomem *reg; }; @@ -140,13 +147,18 @@ static void ls_scfg_msi_irq_handler(struct irq_desc *desc) struct ls_scfg_msir *msir = irq_desc_get_handler_data(desc); struct ls_scfg_msi *msi_data = msir->msi_data; unsigned long val; - int pos, virq, hwirq; + int pos, size, virq, hwirq; chained_irq_enter(irq_desc_get_chip(desc), desc); val = ioread32be(msir->reg); - for_each_set_bit(pos, &val, MSI_IRQS_PER_MSIR) { - hwirq = ((31 - pos) << msi_data->cfg->ibs_shift) | msir->index; + + pos = msir->bit_start; + size = msir->bit_end + 1; + + for_each_set_bit_from(pos, &val, size) { + hwirq = ((msir->bit_end - pos) << msi_data->cfg->ibs_shift) | + msir->index; virq = irq_find_mapping(msi_data->parent, hwirq); if (virq) generic_handle_irq(virq); @@ -193,14 +205,24 @@ static int ls_scfg_msi_setup_hwirq(struct ls_scfg_msi *msi_data, int index) msir->index = index; msir->msi_data = msi_data; msir->gic_irq = virq; - msir->reg = msi_data->regs + MSI_MSIR_OFFSET + 4 * index; + msir->reg = msi_data->regs + msi_data->cfg->msir_base + 4 * index; + + if (msi_data->cfg->msir_irqs == MSI_LS1043V1_1_IRQS_PER_MSIR) { + msir->bit_start = 32 - ((msir->index + 1) * + MSI_LS1043V1_1_IRQS_PER_MSIR); + msir->bit_end = msir->bit_start + + MSI_LS1043V1_1_IRQS_PER_MSIR - 1; + } else { + msir->bit_start = 0; + msir->bit_end = msi_data->cfg->msir_irqs - 1; + } irq_set_chained_handler_and_data(msir->gic_irq, ls_scfg_msi_irq_handler, msir); /* Release the hwirqs corresponding to this MSIR */ - for (i = 0; i < MSI_IRQS_PER_MSIR; i++) { + for (i = 0; i < msi_data->cfg->msir_irqs; i++) { hwirq = i << msi_data->cfg->ibs_shift | msir->index; bitmap_clear(msi_data->used, hwirq, 1); } @@ -216,7 +238,7 @@ static int ls_scfg_msi_teardown_hwirq(struct ls_scfg_msir *msir) if (msir->gic_irq > 0) irq_set_chained_handler_and_data(msir->gic_irq, NULL, NULL); - for (i = 0; i < MSI_IRQS_PER_MSIR; i++) { + for (i = 0; i < msi_data->cfg->msir_irqs; i++) { hwirq = i << msi_data->cfg->ibs_shift | msir->index; bitmap_set(msi_data->used, hwirq, 1); } @@ -226,10 +248,20 @@ static int ls_scfg_msi_teardown_hwirq(struct ls_scfg_msir *msir) s
[PATCHv4 4/9] arm: dts: ls1021a: share all MSIs
From: Minghuan Lian In order to maximize the use of MSI, a PCIe controller will share all MSI controllers. The patch changes msi-parent to refer to all MSI controller dts nodes. Signed-off-by: Minghuan Lian Signed-off-by: Hou Zhiqiang --- v4-v1: - None 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 51b0f69..9319e1f 100644 --- a/arch/arm/boot/dts/ls1021a.dtsi +++ b/arch/arm/boot/dts/ls1021a.dtsi @@ -699,7 +699,7 @@ bus-range = <0x0 0xff>; ranges = <0x8100 0x0 0x 0x40 0x0001 0x0 0x0001 /* downstream I/O */ 0x8200 0x0 0x4000 0x40 0x4000 0x0 0x4000>; /* non-prefetchable memory */ - msi-parent = <&msi1>; + msi-parent = <&msi1>, <&msi2>; #interrupt-cells = <1>; interrupt-map-mask = <0 0 0 7>; interrupt-map = < 0 0 1 &gic GIC_SPI 91 IRQ_TYPE_LEVEL_HIGH>, @@ -722,7 +722,7 @@ bus-range = <0x0 0xff>; ranges = <0x8100 0x0 0x 0x48 0x0001 0x0 0x0001 /* downstream I/O */ 0x8200 0x0 0x4000 0x48 0x4000 0x0 0x4000>; /* non-prefetchable memory */ - msi-parent = <&msi2>; + msi-parent = <&msi1>, <&msi2>; #interrupt-cells = <1>; interrupt-map-mask = <0 0 0 7>; interrupt-map = < 0 0 1 &gic GIC_SPI 92 IRQ_TYPE_LEVEL_HIGH>, -- 2.1.0.27.g96db324
[PATCHv4 1/9] irqchip/ls-scfg-msi: fix typo of MSI compatible strings
From: Minghuan Lian The patch is to fix typo of the Layerscape SCFG MSI dts compatible strings. "1" is replaced by "l". Signed-off-by: Minghuan Lian Acked-by: Rob Herring Signed-off-by: Hou Zhiqiang --- v4-v1: - None .../devicetree/bindings/interrupt-controller/fsl,ls-scfg-msi.txt| 6 +++--- drivers/irqchip/irq-ls-scfg-msi.c | 6 -- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/Documentation/devicetree/bindings/interrupt-controller/fsl,ls-scfg-msi.txt b/Documentation/devicetree/bindings/interrupt-controller/fsl,ls-scfg-msi.txt index 9e38949..2755cd1 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/fsl,ls-scfg-msi.txt +++ b/Documentation/devicetree/bindings/interrupt-controller/fsl,ls-scfg-msi.txt @@ -4,8 +4,8 @@ Required properties: - compatible: should be "fsl,-msi" to identify Layerscape PCIe MSI controller block such as: - "fsl,1s1021a-msi" - "fsl,1s1043a-msi" + "fsl,ls1021a-msi" + "fsl,ls1043a-msi" - msi-controller: indicates that this is a PCIe MSI controller node - reg: physical base address of the controller and length of memory mapped. - interrupts: an interrupt to the parent interrupt controller. @@ -23,7 +23,7 @@ MSI controller node Examples: msi1: msi-controller@1571000 { - compatible = "fsl,1s1043a-msi"; + compatible = "fsl,ls1043a-msi"; reg = <0x0 0x1571000 0x0 0x8>, msi-controller; interrupts = <0 116 0x4>; diff --git a/drivers/irqchip/irq-ls-scfg-msi.c b/drivers/irqchip/irq-ls-scfg-msi.c index 02cca74c..cef67cc 100644 --- a/drivers/irqchip/irq-ls-scfg-msi.c +++ b/drivers/irqchip/irq-ls-scfg-msi.c @@ -219,8 +219,10 @@ static int ls_scfg_msi_remove(struct platform_device *pdev) } static const struct of_device_id ls_scfg_msi_id[] = { - { .compatible = "fsl,1s1021a-msi", }, - { .compatible = "fsl,1s1043a-msi", }, + { .compatible = "fsl,1s1021a-msi", }, /* a typo */ + { .compatible = "fsl,1s1043a-msi", }, /* a typo */ + { .compatible = "fsl,ls1021a-msi", }, + { .compatible = "fsl,ls1043a-msi", }, {}, }; -- 2.1.0.27.g96db324
[PATCHv2 0/2] mtd: m25p80: restore the addressing mode when stop using the flash
From: Hou Zhiqiang To be compatible with legacy device, reset the addressing mode to the default mode. Such as Freescale eSPI boot, it copies the 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 stop using it 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
[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
[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(&flash->spi_nor); + /* Clean up MTD stuff. */ return mtd_device_unregister(&flash->spi_nor.mtd); } +static void m25p_shutdown(struct spi_device *spi) +{ + struct m25p *flash = spi_get_drvdata(spi); + + spi_nor_restore(&flash->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
[PATCH 1/2] mtd: spi-nor: add a API to restore the addressing mode
From: Hou Zhiqiang It's better to restore the addressing mode of the SPI flash whenever remove the driver or reboot the system. Signed-off-by: Hou Zhiqiang --- drivers/mtd/spi-nor/spi-nor.c | 8 include/linux/mtd/spi-nor.h | 1 + 2 files changed, 9 insertions(+) diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index bc266f70a15b..801cbe99b059 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -2713,6 +2713,14 @@ static void spi_nor_resume(struct mtd_info *mtd) dev_err(dev, "resume() failed\n"); } +void spi_nor_restore_addr_mode(struct spi_nor *nor) +{ + 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); +} + 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..fe9357da2049 100644 --- a/include/linux/mtd/spi-nor.h +++ b/include/linux/mtd/spi-nor.h @@ -398,5 +398,6 @@ struct spi_nor_hwcaps { */ int spi_nor_scan(struct spi_nor *nor, const char *name, const struct spi_nor_hwcaps *hwcaps); +void spi_nor_restore_addr_mode(struct spi_nor *nor); #endif -- 2.14.1
[PATCH 0/2] mtd: m25p80: restore the addressing mode when stop using the flash
From: Hou Zhiqiang To be compatible with legacy device, reset the addressing mode to the default mode. Such as Freescale eSPI boot, it copies the 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 a API to restore the addressing mode mtd: m25p80: restore the addressing mode when stop using the flash drivers/mtd/devices/m25p80.c | 8 drivers/mtd/spi-nor/spi-nor.c | 8 include/linux/mtd/spi-nor.h | 1 + 3 files changed, 17 insertions(+) -- 2.14.1
[PATCH 2/2] mtd: m25p80: restore the addressing mode when stop using the flash
From: Hou Zhiqiang Add .shutdown function to restore the addressing mode in reboot process, and add the same operation to the .remove function. Signed-off-by: Hou Zhiqiang --- drivers/mtd/devices/m25p80.c | 8 1 file changed, 8 insertions(+) diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index dbe6a1de2bb8..867bd2d5a267 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -307,10 +307,17 @@ static int m25p_remove(struct spi_device *spi) { struct m25p *flash = spi_get_drvdata(spi); + spi_nor_restore_addr_mode(&flash->spi_nor); /* Clean up MTD stuff. */ return mtd_device_unregister(&flash->spi_nor.mtd); } +static void m25p_shutdown(struct spi_device *spi) +{ + struct m25p *flash = spi_get_drvdata(spi); + + spi_nor_restore_addr_mode(&flash->spi_nor); +} /* * Do NOT add to this array without reading the following: * @@ -386,6 +393,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(&flash->spi_nor); + /* Clean up MTD stuff. */ return mtd_device_unregister(&flash->spi_nor.mtd); } +static void m25p_shutdown(struct spi_device *spi) +{ + struct m25p *flash = spi_get_drvdata(spi); + + spi_nor_restore(&flash->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 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 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, &val); @@ -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, &val); @@ -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
[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 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 &gic 0 111 IRQ_TYPE_LEVEL_HIGH>, < 0 0 3 &gic 0 112 IRQ_TYPE_LEVEL_HIGH>, < 0 0 4 &gic 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 &gic 0 111 0x4>, < 0 0 3 &gic 0 112 0x4>, < 0 0 4 &gic 0 113 0x4>; + big-endian; status = "disabled"; }; @@ -867,6 +868,7 @@ < 0 0 2 &gic 0 121 0x4>, < 0 0 3 &gic 0 122 0x4>, < 0 0 4 &gic 0 123 0x4>; + big-endian; status = "disabled"; }; @@ -893,6 +895,7 @@ < 0 0 2 &gic 0 155 0x4>, < 0 0 3 &gic 0 156 0x4>, < 0 0 4 &gic 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 GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>, < 0 0 3 &gic GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>, < 0 0 4 &gic GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>; + big-endian; status = "disabled"; }; @@ -781,6 +782,7 @@ < 0 0 2 &gic GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>, < 0 0 3 &gic GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>, < 0 0 4 &gic GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>; + big-endian; status = "disabled"; }; @@ -817,6 +819,7 @@ < 0 0 2 &gic GIC_SPI 154 IRQ_TYPE_LEVEL_HIGH>, < 0 0 3 &gic GIC_SPI 154 IRQ_TYPE_LEVEL_HIGH>, < 0 0 4 &gic GIC_SPI 154 IRQ_TYPE_LEVEL_HIGH>; + big-endian; status = "disabled"; }; -- 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 = (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 = &ls1021_pcie_host_ops, - .dw_pcie_ops = &dw_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 = &ls_pcie_host_ops, - .dw_pcie_ops = &dw_ls_pcie_ops, -}; - -static const struct ls_pcie_drvdata ls1046_drvdata = { - .lut_offset = 0x8, - .ltssm_shift = 24, - .lut_dbg = 0x407fc, - .ops = &ls_pcie_host_ops, - .dw_pcie_ops = &dw_ls_pcie_ops, -}; - -static const struct ls_pcie_drvdata ls2080_drvdata = { - .lut_offset = 0x8, - .ltssm_shift = 0, - .lut_dbg = 0x7fc, - .ops = &ls_pcie_host_ops, - .dw_pcie_ops
[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 = <&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 = <&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 = <&scfg 2>; #address-cells = <3>; #size-cells = <2>; device_type = "pci"; -- 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); + 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); + val &= ~PMXMTTURNOFF; + regmap_write(pcie->scfg, SCFG_PEXPMWRCR(pcie-
[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
[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 = &pci->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 dw_plat_pcie_ep_rais
[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 = &pci->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, hdr->s
[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 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, &ep->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(&ep->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(&ep_func->list, &ep->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
[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 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
[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 = &dw_ls_pcie_ep_ops, }; +static const struct ls_pcie_ep_drvdata lx2_ep_drvdata = { + .func_offset = 0x8000, + .ops = &ls_pcie_ep_ops, + .dw_pcie_ops = &dw_ls_pcie_ep_ops, +}; + static const struct of_device_id ls_pcie_ep_of_match[] = { { .compatible = "fsl,ls1046a-pcie-ep", .data = &ls1_ep_drvdata }, { .compatible = "fsl,ls1088a-pcie-ep", .data = &ls2_ep_drvdata }, { .compatible = "fsl,ls2088a-pcie-ep", .data = &ls2_ep_drvdata }, + { .compatible = "fsl,lx2160ar2-pcie-ep", .data = &lx2_ep_drvdata }, { }, }; -- 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
[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: 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