2020-07-22 11:04:55

by Kishon Vijay Abraham I

[permalink] [raw]
Subject: [PATCH v8 00/15] Add PCIe support to TI's J721E SoC

TI's J721E SoC uses Cadence PCIe core to implement both RC mode
and EP mode.

The high level features are:
*) Supports Legacy, MSI and MSI-X interrupt
*) Supports upto GEN4 speed mode
*) Supports SR-IOV
*) Supports multiple physical function
*) Ability to route all transactions via SMMU

This patch series
*) Add support in Cadence PCIe core to be used for TI's J721E SoC
*) Add a driver for J721E PCIe wrapper

v1 of the series can be found @ [1]
v2 of the series can be found @ [2]
v3 of the series can be found @ [5]
v4 of the series can be found @ [6]
v5 of the series can be found @ [7]
v6 of the series can be found @ [8]
v7 of the series can be found @ [9]

Changes from v7:
1) Replaced WARN with pr_warn
2) Included support for "dma-ranges" property patch in this series [10]

Changes from v6:
1) Fixed bot found errors running 'make dt_binding_check'

Changes from v5:
1) Added Reviewed-by: for PATCH #6
2) Protect writes to PCI_STATUS with spin_lock during raising interrupts
in EP mode to reduce the time between read and write of RMW.

Changes from v4:
1) Added Reviewed-by: & Acked-by: tags from RobH
2) Removed un-used accessors for pcie-cadence.h and removed having ops
for read/write accessors
3) Updated cdns,cdns-pcie-host.yaml to remove "mem" from reg

Changes from v3:
1) Changed the order of files in MAINTAINTERS file to fix Joe's comments
2) Fixed indentation and added Reviewed-by: Rob Herring <[email protected]>
3) Cleaned up computing msix_tbl
4) Fixed RobH's comment on J721E driver

Changes from v2:
1) Converting Cadence binding to YAML schema was done as a
separate series [3] & [4]. [3] is merged and [4] is
pending.
2) Included MSI-X support in this series
3) Added link down interrupt handling (only error message)
4) Rebased to latest 5.7-rc1
5) Adapted TI J721E binding to [3] & [4]

Changes from v1:
1) Added DT schemas cdns-pcie-host.yaml, cdns-pcie-ep.yaml and
cdns-pcie.yaml for Cadence PCIe core and included it in
TI's PCIe DT schema.
2) Added cpu_addr_fixup() for Cadence Platform driver.
3) Fixed subject/description/renamed functions as commented by
Andrew Murray.

[1] -> http://lore.kernel.org/r/[email protected]
[2] -> http://lore.kernel.org/r/[email protected]
[3] -> http://lore.kernel.org/r/[email protected]
[4] -> http://lore.kernel.org/r/[email protected]
[5] -> http://lore.kernel.org/r/[email protected]
[6] -> http://lore.kernel.org/r/[email protected]
[7] -> http://lore.kernel.org/r/[email protected]
[8] -> http://lore.kernel.org/r/[email protected]
[9] -> http://lore.kernel.org/r/[email protected]
[10] -> http://lore.kernel.org/r/[email protected]

Alan Douglas (1):
PCI: cadence: Add MSI-X support to Endpoint driver

Kishon Vijay Abraham I (14):
PCI: cadence: Use "dma-ranges" instead of "cdns,no-bar-match-nbits"
property
PCI: cadence: Fix cdns_pcie_{host|ep}_setup() error path
linux/kernel.h: Add PTR_ALIGN_DOWN macro
PCI: cadence: Convert all r/w accessors to perform only 32-bit
accesses
PCI: cadence: Add support to start link and verify link status
PCI: cadence: Allow pci_host_bridge to have custom pci_ops
dt-bindings: PCI: cadence: Remove "mem" from reg binding
PCI: cadence: Add new *ops* for CPU addr fixup
PCI: cadence: Fix updating Vendor ID and Subsystem Vendor ID register
dt-bindings: PCI: Add host mode dt-bindings for TI's J721E SoC
dt-bindings: PCI: Add EP mode dt-bindings for TI's J721E SoC
PCI: j721e: Add TI J721E PCIe driver
misc: pci_endpoint_test: Add J721E in pci_device_id table
MAINTAINERS: Add Kishon Vijay Abraham I for TI J721E SoC PCIe

.../bindings/pci/cdns,cdns-pcie-host.yaml | 8 +-
.../bindings/pci/ti,j721e-pci-ep.yaml | 94 ++++
.../bindings/pci/ti,j721e-pci-host.yaml | 113 ++++
MAINTAINERS | 4 +-
drivers/misc/pci_endpoint_test.c | 9 +
drivers/pci/controller/cadence/Kconfig | 23 +
drivers/pci/controller/cadence/Makefile | 1 +
drivers/pci/controller/cadence/pci-j721e.c | 493 ++++++++++++++++++
.../pci/controller/cadence/pcie-cadence-ep.c | 129 ++++-
.../controller/cadence/pcie-cadence-host.c | 310 +++++++++--
.../controller/cadence/pcie-cadence-plat.c | 13 +
drivers/pci/controller/cadence/pcie-cadence.c | 8 +-
drivers/pci/controller/cadence/pcie-cadence.h | 161 +++++-
include/linux/kernel.h | 1 +
14 files changed, 1297 insertions(+), 70 deletions(-)
create mode 100644 Documentation/devicetree/bindings/pci/ti,j721e-pci-ep.yaml
create mode 100644 Documentation/devicetree/bindings/pci/ti,j721e-pci-host.yaml
create mode 100644 drivers/pci/controller/cadence/pci-j721e.c

--
2.17.1


2020-07-22 11:05:20

by Kishon Vijay Abraham I

[permalink] [raw]
Subject: [PATCH v8 09/15] PCI: cadence: Fix updating Vendor ID and Subsystem Vendor ID register

Commit 1b79c5284439 ("PCI: cadence: Add host driver for Cadence PCIe
controller") in order to update Vendor ID, directly wrote to
PCI_VENDOR_ID register. However PCI_VENDOR_ID in root port configuration
space is read-only register and writing to it will have no effect.
Use local management register to configure Vendor ID and Subsystem Vendor
ID.

Fixes: 1b79c5284439 ("PCI: cadence: Add host driver for Cadence PCIe controller")
Reviewed-by: Rob Herring <[email protected]>
Signed-off-by: Kishon Vijay Abraham I <[email protected]>
---
drivers/pci/controller/cadence/pcie-cadence-host.c | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/drivers/pci/controller/cadence/pcie-cadence-host.c b/drivers/pci/controller/cadence/pcie-cadence-host.c
index 10127ea71b83..8935f7a37e5a 100644
--- a/drivers/pci/controller/cadence/pcie-cadence-host.c
+++ b/drivers/pci/controller/cadence/pcie-cadence-host.c
@@ -82,6 +82,7 @@ static int cdns_pcie_host_init_root_port(struct cdns_pcie_rc *rc)
{
struct cdns_pcie *pcie = &rc->pcie;
u32 value, ctrl;
+ u32 id;

/*
* Set the root complex BAR configuration register:
@@ -101,8 +102,12 @@ static int cdns_pcie_host_init_root_port(struct cdns_pcie_rc *rc)
cdns_pcie_writel(pcie, CDNS_PCIE_LM_RC_BAR_CFG, value);

/* Set root port configuration space */
- if (rc->vendor_id != 0xffff)
- cdns_pcie_rp_writew(pcie, PCI_VENDOR_ID, rc->vendor_id);
+ if (rc->vendor_id != 0xffff) {
+ id = CDNS_PCIE_LM_ID_VENDOR(rc->vendor_id) |
+ CDNS_PCIE_LM_ID_SUBSYS(rc->vendor_id);
+ cdns_pcie_writel(pcie, CDNS_PCIE_LM_ID, id);
+ }
+
if (rc->device_id != 0xffff)
cdns_pcie_rp_writew(pcie, PCI_DEVICE_ID, rc->device_id);

--
2.17.1

2020-07-22 11:05:43

by Kishon Vijay Abraham I

[permalink] [raw]
Subject: [PATCH v8 12/15] dt-bindings: PCI: Add EP mode dt-bindings for TI's J721E SoC

Add PCIe EP mode dt-bindings for TI's J721E SoC.

Signed-off-by: Kishon Vijay Abraham I <[email protected]>
Reviewed-by: Rob Herring <[email protected]>
---
.../bindings/pci/ti,j721e-pci-ep.yaml | 94 +++++++++++++++++++
1 file changed, 94 insertions(+)
create mode 100644 Documentation/devicetree/bindings/pci/ti,j721e-pci-ep.yaml

diff --git a/Documentation/devicetree/bindings/pci/ti,j721e-pci-ep.yaml b/Documentation/devicetree/bindings/pci/ti,j721e-pci-ep.yaml
new file mode 100644
index 000000000000..cfe25cface21
--- /dev/null
+++ b/Documentation/devicetree/bindings/pci/ti,j721e-pci-ep.yaml
@@ -0,0 +1,94 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+# Copyright (C) 2020 Texas Instruments Incorporated - http://www.ti.com/
+%YAML 1.2
+---
+$id: "http://devicetree.org/schemas/pci/ti,j721e-pci-ep.yaml#"
+$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+
+title: TI J721E PCI EP (PCIe Wrapper)
+
+maintainers:
+ - Kishon Vijay Abraham I <[email protected]>
+
+allOf:
+ - $ref: "cdns-pcie-ep.yaml#"
+
+properties:
+ compatible:
+ enum:
+ - ti,j721e-pcie-ep
+
+ reg:
+ maxItems: 4
+
+ reg-names:
+ items:
+ - const: intd_cfg
+ - const: user_cfg
+ - const: reg
+ - const: mem
+
+ ti,syscon-pcie-ctrl:
+ description: Phandle to the SYSCON entry required for configuring PCIe mode
+ and link speed.
+ allOf:
+ - $ref: /schemas/types.yaml#/definitions/phandle
+
+ power-domains:
+ maxItems: 1
+
+ clocks:
+ maxItems: 1
+ description: clock-specifier to represent input to the PCIe
+
+ clock-names:
+ items:
+ - const: fck
+
+ dma-coherent:
+ description: Indicates that the PCIe IP block can ensure the coherency
+
+required:
+ - compatible
+ - reg
+ - reg-names
+ - ti,syscon-pcie-ctrl
+ - max-link-speed
+ - num-lanes
+ - power-domains
+ - clocks
+ - clock-names
+ - cdns,max-outbound-regions
+ - dma-coherent
+ - max-functions
+ - phys
+ - phy-names
+
+examples:
+ - |
+ #include <dt-bindings/soc/ti,sci_pm_domain.h>
+
+ bus {
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ pcie0_ep: pcie-ep@d000000 {
+ compatible = "ti,j721e-pcie-ep";
+ reg = <0x00 0x02900000 0x00 0x1000>,
+ <0x00 0x02907000 0x00 0x400>,
+ <0x00 0x0d000000 0x00 0x00800000>,
+ <0x00 0x10000000 0x00 0x08000000>;
+ reg-names = "intd_cfg", "user_cfg", "reg", "mem";
+ ti,syscon-pcie-ctrl = <&pcie0_ctrl>;
+ max-link-speed = <3>;
+ num-lanes = <2>;
+ power-domains = <&k3_pds 239 TI_SCI_PD_EXCLUSIVE>;
+ clocks = <&k3_clks 239 1>;
+ clock-names = "fck";
+ cdns,max-outbound-regions = <16>;
+ max-functions = /bits/ 8 <6>;
+ dma-coherent;
+ phys = <&serdes0_pcie_link>;
+ phy-names = "pcie-phy";
+ };
+ };
--
2.17.1

2020-07-22 11:06:02

by Kishon Vijay Abraham I

[permalink] [raw]
Subject: [PATCH v8 10/15] PCI: cadence: Add MSI-X support to Endpoint driver

From: Alan Douglas <[email protected]>

Implement ->set_msix() and ->get_msix() callback functions in order
to configure MSIX capability in the PCIe endpoint controller.

Add cdns_pcie_ep_send_msix_irq() to send MSIX interrupts to Host.
cdns_pcie_ep_send_msix_irq() gets the MSIX table address (virtual
address) from "struct cdns_pcie_epf" that gets initialized in
->set_bar() call back function.

Signed-off-by: Alan Douglas <[email protected]>
[[email protected]: Re-implement MSIX support in accordance with the
re-designed core MSI-X interfaces]
Signed-off-by: Kishon Vijay Abraham I <[email protected]>
---
.../pci/controller/cadence/pcie-cadence-ep.c | 108 +++++++++++++++++-
drivers/pci/controller/cadence/pcie-cadence.h | 11 ++
2 files changed, 118 insertions(+), 1 deletion(-)

diff --git a/drivers/pci/controller/cadence/pcie-cadence-ep.c b/drivers/pci/controller/cadence/pcie-cadence-ep.c
index 034cb3cf726e..87c76341eab4 100644
--- a/drivers/pci/controller/cadence/pcie-cadence-ep.c
+++ b/drivers/pci/controller/cadence/pcie-cadence-ep.c
@@ -51,6 +51,7 @@ static int cdns_pcie_ep_set_bar(struct pci_epc *epc, u8 fn,
struct pci_epf_bar *epf_bar)
{
struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
+ struct cdns_pcie_epf *epf = &ep->epf[fn];
struct cdns_pcie *pcie = &ep->pcie;
dma_addr_t bar_phys = epf_bar->phys_addr;
enum pci_barno bar = epf_bar->barno;
@@ -111,6 +112,8 @@ static int cdns_pcie_ep_set_bar(struct pci_epc *epc, u8 fn,
CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_CTRL(b, ctrl));
cdns_pcie_writel(pcie, reg, cfg);

+ epf->epf_bar[bar] = epf_bar;
+
return 0;
}

@@ -118,6 +121,7 @@ static void cdns_pcie_ep_clear_bar(struct pci_epc *epc, u8 fn,
struct pci_epf_bar *epf_bar)
{
struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
+ struct cdns_pcie_epf *epf = &ep->epf[fn];
struct cdns_pcie *pcie = &ep->pcie;
enum pci_barno bar = epf_bar->barno;
u32 reg, cfg, b, ctrl;
@@ -139,6 +143,8 @@ static void cdns_pcie_ep_clear_bar(struct pci_epc *epc, u8 fn,

cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_EP_FUNC_BAR_ADDR0(fn, bar), 0);
cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_EP_FUNC_BAR_ADDR1(fn, bar), 0);
+
+ epf->epf_bar[bar] = NULL;
}

static int cdns_pcie_ep_map_addr(struct pci_epc *epc, u8 fn, phys_addr_t addr,
@@ -224,6 +230,50 @@ static int cdns_pcie_ep_get_msi(struct pci_epc *epc, u8 fn)
return mme;
}

+static int cdns_pcie_ep_get_msix(struct pci_epc *epc, u8 func_no)
+{
+ struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
+ struct cdns_pcie *pcie = &ep->pcie;
+ u32 cap = CDNS_PCIE_EP_FUNC_MSIX_CAP_OFFSET;
+ u32 val, reg;
+
+ reg = cap + PCI_MSIX_FLAGS;
+ val = cdns_pcie_ep_fn_readw(pcie, func_no, reg);
+ if (!(val & PCI_MSIX_FLAGS_ENABLE))
+ return -EINVAL;
+
+ val &= PCI_MSIX_FLAGS_QSIZE;
+
+ return val;
+}
+
+static int cdns_pcie_ep_set_msix(struct pci_epc *epc, u8 fn, u16 interrupts,
+ enum pci_barno bir, u32 offset)
+{
+ struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
+ struct cdns_pcie *pcie = &ep->pcie;
+ u32 cap = CDNS_PCIE_EP_FUNC_MSIX_CAP_OFFSET;
+ u32 val, reg;
+
+ reg = cap + PCI_MSIX_FLAGS;
+ val = cdns_pcie_ep_fn_readw(pcie, fn, reg);
+ val &= ~PCI_MSIX_FLAGS_QSIZE;
+ val |= interrupts;
+ cdns_pcie_ep_fn_writew(pcie, fn, reg, val);
+
+ /* Set MSIX BAR and offset */
+ reg = cap + PCI_MSIX_TABLE;
+ val = offset | bir;
+ cdns_pcie_ep_fn_writel(pcie, fn, reg, val);
+
+ /* Set PBA BAR and offset. BAR must match MSIX BAR */
+ reg = cap + PCI_MSIX_PBA;
+ val = (offset + (interrupts * PCI_MSIX_ENTRY_SIZE)) | bir;
+ cdns_pcie_ep_fn_writel(pcie, fn, reg, val);
+
+ return 0;
+}
+
static void cdns_pcie_ep_assert_intx(struct cdns_pcie_ep *ep, u8 fn,
u8 intx, bool is_asserted)
{
@@ -333,6 +383,52 @@ static int cdns_pcie_ep_send_msi_irq(struct cdns_pcie_ep *ep, u8 fn,
return 0;
}

+static int cdns_pcie_ep_send_msix_irq(struct cdns_pcie_ep *ep, u8 fn,
+ u16 interrupt_num)
+{
+ u32 cap = CDNS_PCIE_EP_FUNC_MSIX_CAP_OFFSET;
+ u32 tbl_offset, msg_data, reg, vec_ctrl;
+ struct cdns_pcie *pcie = &ep->pcie;
+ struct pci_epf_msix_tbl *msix_tbl;
+ struct cdns_pcie_epf *epf;
+ u64 pci_addr_mask = 0xff;
+ u64 msg_addr;
+ u16 flags;
+ u8 bir;
+
+ /* Check whether the MSI-X feature has been enabled by the PCI host. */
+ flags = cdns_pcie_ep_fn_readw(pcie, fn, cap + PCI_MSIX_FLAGS);
+ if (!(flags & PCI_MSIX_FLAGS_ENABLE))
+ return -EINVAL;
+
+ reg = cap + PCI_MSIX_TABLE;
+ tbl_offset = cdns_pcie_ep_fn_readl(pcie, fn, reg);
+ bir = tbl_offset & PCI_MSIX_TABLE_BIR;
+ tbl_offset &= PCI_MSIX_TABLE_OFFSET;
+
+ epf = &ep->epf[fn];
+ msix_tbl = epf->epf_bar[bir]->addr + tbl_offset;
+ msg_addr = msix_tbl[(interrupt_num - 1)].msg_addr;
+ msg_data = msix_tbl[(interrupt_num - 1)].msg_data;
+ vec_ctrl = msix_tbl[(interrupt_num - 1)].vector_ctrl;
+
+ /* Set the outbound region if needed. */
+ if (ep->irq_pci_addr != (msg_addr & ~pci_addr_mask) ||
+ ep->irq_pci_fn != fn) {
+ /* First region was reserved for IRQ writes. */
+ cdns_pcie_set_outbound_region(pcie, fn, 0,
+ false,
+ ep->irq_phys_addr,
+ msg_addr & ~pci_addr_mask,
+ pci_addr_mask + 1);
+ ep->irq_pci_addr = (msg_addr & ~pci_addr_mask);
+ ep->irq_pci_fn = fn;
+ }
+ writel(msg_data, ep->irq_cpu_addr + (msg_addr & pci_addr_mask));
+
+ return 0;
+}
+
static int cdns_pcie_ep_raise_irq(struct pci_epc *epc, u8 fn,
enum pci_epc_irq_type type,
u16 interrupt_num)
@@ -346,6 +442,9 @@ static int cdns_pcie_ep_raise_irq(struct pci_epc *epc, u8 fn,
case PCI_EPC_IRQ_MSI:
return cdns_pcie_ep_send_msi_irq(ep, fn, interrupt_num);

+ case PCI_EPC_IRQ_MSIX:
+ return cdns_pcie_ep_send_msix_irq(ep, fn, interrupt_num);
+
default:
break;
}
@@ -383,7 +482,7 @@ static int cdns_pcie_ep_start(struct pci_epc *epc)
static const struct pci_epc_features cdns_pcie_epc_features = {
.linkup_notifier = false,
.msi_capable = true,
- .msix_capable = false,
+ .msix_capable = true,
};

static const struct pci_epc_features*
@@ -400,6 +499,8 @@ static const struct pci_epc_ops cdns_pcie_epc_ops = {
.unmap_addr = cdns_pcie_ep_unmap_addr,
.set_msi = cdns_pcie_ep_set_msi,
.get_msi = cdns_pcie_ep_get_msi,
+ .set_msix = cdns_pcie_ep_set_msix,
+ .get_msix = cdns_pcie_ep_get_msix,
.raise_irq = cdns_pcie_ep_raise_irq,
.start = cdns_pcie_ep_start,
.get_features = cdns_pcie_ep_get_features,
@@ -458,6 +559,11 @@ int cdns_pcie_ep_setup(struct cdns_pcie_ep *ep)
if (of_property_read_u8(np, "max-functions", &epc->max_functions) < 0)
epc->max_functions = 1;

+ ep->epf = devm_kcalloc(dev, epc->max_functions, sizeof(*ep->epf),
+ GFP_KERNEL);
+ if (!ep->epf)
+ return -ENOMEM;
+
ret = pci_epc_mem_init(epc, pcie->mem_res->start,
resource_size(pcie->mem_res), PAGE_SIZE);
if (ret < 0) {
diff --git a/drivers/pci/controller/cadence/pcie-cadence.h b/drivers/pci/controller/cadence/pcie-cadence.h
index 7c804ac1dbc2..dd910a1c30fb 100644
--- a/drivers/pci/controller/cadence/pcie-cadence.h
+++ b/drivers/pci/controller/cadence/pcie-cadence.h
@@ -113,6 +113,7 @@
#define CDNS_PCIE_EP_FUNC_BASE(fn) (((fn) << 12) & GENMASK(19, 12))

#define CDNS_PCIE_EP_FUNC_MSI_CAP_OFFSET 0x90
+#define CDNS_PCIE_EP_FUNC_MSIX_CAP_OFFSET 0xb0

/*
* Root Port Registers (PCI configuration space for the root port function)
@@ -302,6 +303,14 @@ struct cdns_pcie_rc {
bool avail_ib_bar[CDNS_PCIE_RP_MAX_IB];
};

+/**
+ * struct cdns_pcie_epf - Structure to hold info about endpoint function
+ * @epf_bar: reference to the pci_epf_bar for the six Base Address Registers
+ */
+struct cdns_pcie_epf {
+ struct pci_epf_bar *epf_bar[PCI_STD_NUM_BARS];
+};
+
/**
* struct cdns_pcie_ep - private data for this PCIe endpoint controller driver
* @pcie: Cadence PCIe controller
@@ -321,6 +330,7 @@ struct cdns_pcie_rc {
* @lock: spin lock to disable interrupts while modifying PCIe controller
* registers fields (RMW) accessible by both remote RC and EP to
* minimize time between read and write
+ * @epf: Structure to hold info about endpoint function
*/
struct cdns_pcie_ep {
struct cdns_pcie pcie;
@@ -334,6 +344,7 @@ struct cdns_pcie_ep {
u8 irq_pending;
/* protect writing to PCI_STATUS while raising legacy interrupts */
spinlock_t lock;
+ struct cdns_pcie_epf *epf;
};


--
2.17.1

2020-07-22 11:06:12

by Kishon Vijay Abraham I

[permalink] [raw]
Subject: [PATCH v8 15/15] MAINTAINERS: Add Kishon Vijay Abraham I for TI J721E SoC PCIe

Add Kishon Vijay Abraham I as MAINTAINER for TI J721E SoC PCIe.

Acked-by: Rob Herring <[email protected]>
Signed-off-by: Kishon Vijay Abraham I <[email protected]>
---
MAINTAINERS | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/MAINTAINERS b/MAINTAINERS
index 68f21d46614c..6df9b54d3003 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -13149,12 +13149,14 @@ S: Maintained
F: Documentation/devicetree/bindings/pci/designware-pcie.txt
F: drivers/pci/controller/dwc/*designware*

-PCI DRIVER FOR TI DRA7XX
+PCI DRIVER FOR TI DRA7XX/J721E
M: Kishon Vijay Abraham I <[email protected]>
L: [email protected]
L: [email protected]
+L: [email protected]
S: Supported
F: Documentation/devicetree/bindings/pci/ti-pci.txt
+F: drivers/pci/controller/cadence/pci-j721e.c
F: drivers/pci/controller/dwc/pci-dra7xx.c

PCI DRIVER FOR TI KEYSTONE
--
2.17.1

2020-07-22 11:06:28

by Kishon Vijay Abraham I

[permalink] [raw]
Subject: [PATCH v8 01/15] PCI: cadence: Use "dma-ranges" instead of "cdns,no-bar-match-nbits" property

Cadence PCIe core driver (host mode) uses "cdns,no-bar-match-nbits"
property to configure the number of bits passed through from PCIe
address to internal address in Inbound Address Translation register.
This only used the NO MATCH BAR.

However standard PCI dt-binding already defines "dma-ranges" to
describe the address ranges accessible by PCIe controller. Add support
in Cadence PCIe host driver to parse dma-ranges and configure the
inbound regions for BAR0, BAR1 and NO MATCH BAR. Cadence IP specifies
maximum size for BAR0 as 256GB, maximum size for BAR1 as 2 GB.

This adds support to take the next biggest region in "dma-ranges" and
find the smallest BAR that each of the regions fit in and if there is
no BAR big enough to hold the region, split the region to see if it can
be fitted using multiple BARs.

"dma-ranges" of J721E will be
dma-ranges = <0x02000000 0x0 0x0 0x0 0x0 0x10000 0x0>;
Since there is no BAR which can hold 2^48 size, NO_MATCH_BAR will be
used here.

Legacy device tree binding compatibility is maintained by retaining
support for "cdns,no-bar-match-nbits".

Signed-off-by: Kishon Vijay Abraham I <[email protected]>
---
Changes from [1]
1) Use list_sort() for sorting the address ranges by size
2) Clear CDNS_PCIE_LM_RC_BAR_CFG register before configuring them

[1] -> http://lore.kernel.org/r/[email protected]
.../controller/cadence/pcie-cadence-host.c | 251 +++++++++++++++++-
drivers/pci/controller/cadence/pcie-cadence.h | 28 +-
2 files changed, 262 insertions(+), 17 deletions(-)

diff --git a/drivers/pci/controller/cadence/pcie-cadence-host.c b/drivers/pci/controller/cadence/pcie-cadence-host.c
index 8c2543f28ba0..f42a0acfce00 100644
--- a/drivers/pci/controller/cadence/pcie-cadence-host.c
+++ b/drivers/pci/controller/cadence/pcie-cadence-host.c
@@ -4,6 +4,7 @@
// Author: Cyrille Pitchen <[email protected]>

#include <linux/kernel.h>
+#include <linux/list_sort.h>
#include <linux/of_address.h>
#include <linux/of_pci.h>
#include <linux/platform_device.h>
@@ -11,6 +12,17 @@

#include "pcie-cadence.h"

+static u64 bar_max_size[] = {
+ [RP_BAR0] = _ULL(128 * SZ_2G),
+ [RP_BAR1] = SZ_2G,
+ [RP_NO_BAR] = _BITULL(63),
+};
+
+static u8 bar_aperture_mask[] = {
+ [RP_BAR0] = 0x1F,
+ [RP_BAR1] = 0xF,
+};
+
static void __iomem *cdns_pci_map_bus(struct pci_bus *bus, unsigned int devfn,
int where)
{
@@ -101,6 +113,217 @@ static int cdns_pcie_host_init_root_port(struct cdns_pcie_rc *rc)
return 0;
}

+static int cdns_pcie_host_bar_ib_config(struct cdns_pcie_rc *rc,
+ enum cdns_pcie_rp_bar bar,
+ u64 cpu_addr, u64 size,
+ unsigned long flags)
+{
+ struct cdns_pcie *pcie = &rc->pcie;
+ u32 addr0, addr1, aperture, value;
+
+ if (!rc->avail_ib_bar[bar])
+ return -EBUSY;
+
+ rc->avail_ib_bar[bar] = false;
+
+ aperture = ilog2(size);
+ addr0 = CDNS_PCIE_AT_IB_RP_BAR_ADDR0_NBITS(aperture) |
+ (lower_32_bits(cpu_addr) & GENMASK(31, 8));
+ addr1 = upper_32_bits(cpu_addr);
+ cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_RP_BAR_ADDR0(bar), addr0);
+ cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_RP_BAR_ADDR1(bar), addr1);
+
+ if (bar == RP_NO_BAR)
+ return 0;
+
+ value = cdns_pcie_readl(pcie, CDNS_PCIE_LM_RC_BAR_CFG);
+ value &= ~(LM_RC_BAR_CFG_CTRL_MEM_64BITS(bar) |
+ LM_RC_BAR_CFG_CTRL_PREF_MEM_64BITS(bar) |
+ LM_RC_BAR_CFG_CTRL_MEM_32BITS(bar) |
+ LM_RC_BAR_CFG_CTRL_PREF_MEM_32BITS(bar) |
+ LM_RC_BAR_CFG_APERTURE(bar, bar_aperture_mask[bar] + 2));
+ if (size + cpu_addr >= SZ_4G) {
+ if (!(flags & IORESOURCE_PREFETCH))
+ value |= LM_RC_BAR_CFG_CTRL_MEM_64BITS(bar);
+ value |= LM_RC_BAR_CFG_CTRL_PREF_MEM_64BITS(bar);
+ } else {
+ if (!(flags & IORESOURCE_PREFETCH))
+ value |= LM_RC_BAR_CFG_CTRL_MEM_32BITS(bar);
+ value |= LM_RC_BAR_CFG_CTRL_PREF_MEM_32BITS(bar);
+ }
+
+ value |= LM_RC_BAR_CFG_APERTURE(bar, aperture);
+ cdns_pcie_writel(pcie, CDNS_PCIE_LM_RC_BAR_CFG, value);
+
+ return 0;
+}
+
+static enum cdns_pcie_rp_bar
+cdns_pcie_host_find_min_bar(struct cdns_pcie_rc *rc, u64 size)
+{
+ enum cdns_pcie_rp_bar bar, sel_bar;
+
+ sel_bar = RP_BAR_UNDEFINED;
+ for (bar = RP_BAR0; bar <= RP_NO_BAR; bar++) {
+ if (!rc->avail_ib_bar[bar])
+ continue;
+
+ if (size <= bar_max_size[bar]) {
+ if (sel_bar == RP_BAR_UNDEFINED) {
+ sel_bar = bar;
+ continue;
+ }
+
+ if (bar_max_size[bar] < bar_max_size[sel_bar])
+ sel_bar = bar;
+ }
+ }
+
+ return sel_bar;
+}
+
+static enum cdns_pcie_rp_bar
+cdns_pcie_host_find_max_bar(struct cdns_pcie_rc *rc, u64 size)
+{
+ enum cdns_pcie_rp_bar bar, sel_bar;
+
+ sel_bar = RP_BAR_UNDEFINED;
+ for (bar = RP_BAR0; bar <= RP_NO_BAR; bar++) {
+ if (!rc->avail_ib_bar[bar])
+ continue;
+
+ if (size >= bar_max_size[bar]) {
+ if (sel_bar == RP_BAR_UNDEFINED) {
+ sel_bar = bar;
+ continue;
+ }
+
+ if (bar_max_size[bar] > bar_max_size[sel_bar])
+ sel_bar = bar;
+ }
+ }
+
+ return sel_bar;
+}
+
+static int cdns_pcie_host_bar_config(struct cdns_pcie_rc *rc,
+ struct resource_entry *entry)
+{
+ u64 cpu_addr, pci_addr, size, winsize;
+ struct cdns_pcie *pcie = &rc->pcie;
+ struct device *dev = pcie->dev;
+ enum cdns_pcie_rp_bar bar;
+ unsigned long flags;
+ int ret;
+
+ cpu_addr = entry->res->start;
+ pci_addr = entry->res->start - entry->offset;
+ flags = entry->res->flags;
+ size = resource_size(entry->res);
+
+ if (entry->offset) {
+ dev_err(dev, "PCI addr: %llx must be equal to CPU addr: %llx\n",
+ pci_addr, cpu_addr);
+ return -EINVAL;
+ }
+
+ while (size > 0) {
+ /*
+ * Try to find a minimum BAR whose size is greater than
+ * or equal to the remaining resource_entry size. This will
+ * fail if the size of each of the available BARs is less than
+ * the remaining resource_entry size.
+ * If a minimum BAR is found, IB ATU will be configured and
+ * exited.
+ */
+ bar = cdns_pcie_host_find_min_bar(rc, size);
+ if (bar != RP_BAR_UNDEFINED) {
+ ret = cdns_pcie_host_bar_ib_config(rc, bar, cpu_addr,
+ size, flags);
+ if (ret)
+ dev_err(dev, "IB BAR: %d config failed\n", bar);
+ return ret;
+ }
+
+ /*
+ * If the control reaches here, it would mean the remaining
+ * resource_entry size cannot be fitted in a single BAR. So we
+ * find a maximum BAR whose size is less than or equal to the
+ * remaining resource_entry size and split the resource entry
+ * so that part of resource entry is fitted inside the maximum
+ * BAR. The remaining size would be fitted during the next
+ * iteration of the loop.
+ * If a maximum BAR is not found, there is no way we can fit
+ * this resource_entry, so we error out.
+ */
+ bar = cdns_pcie_host_find_max_bar(rc, size);
+ if (bar == RP_BAR_UNDEFINED) {
+ dev_err(dev, "No free BAR to map cpu_addr %llx\n",
+ cpu_addr);
+ return -EINVAL;
+ }
+
+ winsize = bar_max_size[bar];
+ ret = cdns_pcie_host_bar_ib_config(rc, bar, cpu_addr, winsize,
+ flags);
+ if (ret) {
+ dev_err(dev, "IB BAR: %d config failed\n", bar);
+ return ret;
+ }
+
+ size -= winsize;
+ cpu_addr += winsize;
+ }
+
+ return 0;
+}
+
+static int cdns_pcie_host_dma_ranges_cmp(void *priv, struct list_head *a, struct list_head *b)
+{
+ struct resource_entry *entry1, *entry2;
+
+ entry1 = container_of(a, struct resource_entry, node);
+ entry2 = container_of(b, struct resource_entry, node);
+
+ return resource_size(entry2->res) - resource_size(entry1->res);
+}
+
+static int cdns_pcie_host_map_dma_ranges(struct cdns_pcie_rc *rc)
+{
+ struct cdns_pcie *pcie = &rc->pcie;
+ struct device *dev = pcie->dev;
+ struct device_node *np = dev->of_node;
+ struct pci_host_bridge *bridge;
+ struct resource_entry *entry;
+ u32 no_bar_nbits = 32;
+ int err;
+
+ bridge = pci_host_bridge_from_priv(rc);
+ if (!bridge)
+ return -ENOMEM;
+
+ if (list_empty(&bridge->dma_ranges)) {
+ of_property_read_u32(np, "cdns,no-bar-match-nbits",
+ &no_bar_nbits);
+ err = cdns_pcie_host_bar_ib_config(rc, RP_NO_BAR, 0x0,
+ (u64)1 << no_bar_nbits, 0);
+ if (err)
+ dev_err(dev, "IB BAR: %d config failed\n", RP_NO_BAR);
+ return err;
+ }
+
+ list_sort(NULL, &bridge->dma_ranges, cdns_pcie_host_dma_ranges_cmp);
+
+ resource_list_for_each_entry(entry, &bridge->dma_ranges) {
+ err = cdns_pcie_host_bar_config(rc, entry);
+ if (err)
+ dev_err(dev, "Fail to configure IB using dma-ranges\n");
+ return err;
+ }
+
+ return 0;
+}
+
static int cdns_pcie_host_init_address_translation(struct cdns_pcie_rc *rc)
{
struct cdns_pcie *pcie = &rc->pcie;
@@ -154,16 +377,9 @@ static int cdns_pcie_host_init_address_translation(struct cdns_pcie_rc *rc)
r++;
}

- /*
- * Set Root Port no BAR match Inbound Translation registers:
- * needed for MSI and DMA.
- * Root Port BAR0 and BAR1 are disabled, hence no need to set their
- * inbound translation registers.
- */
- addr0 = CDNS_PCIE_AT_IB_RP_BAR_ADDR0_NBITS(rc->no_bar_nbits);
- addr1 = 0;
- cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_RP_BAR_ADDR0(RP_NO_BAR), addr0);
- cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_RP_BAR_ADDR1(RP_NO_BAR), addr1);
+ err = cdns_pcie_host_map_dma_ranges(rc);
+ if (err)
+ return err;

return 0;
}
@@ -173,10 +389,16 @@ static int cdns_pcie_host_init(struct device *dev,
struct cdns_pcie_rc *rc)
{
struct resource *bus_range = NULL;
+ struct pci_host_bridge *bridge;
int err;

+ bridge = pci_host_bridge_from_priv(rc);
+ if (!bridge)
+ return -ENOMEM;
+
/* Parse our PCI ranges and request their resources */
- err = pci_parse_request_of_pci_ranges(dev, resources, NULL, &bus_range);
+ err = pci_parse_request_of_pci_ranges(dev, resources,
+ &bridge->dma_ranges, &bus_range);
if (err)
return err;

@@ -205,6 +427,7 @@ int cdns_pcie_host_setup(struct cdns_pcie_rc *rc)
struct device_node *np = dev->of_node;
struct pci_host_bridge *bridge;
struct list_head resources;
+ enum cdns_pcie_rp_bar bar;
struct cdns_pcie *pcie;
struct resource *res;
int ret;
@@ -216,9 +439,6 @@ int cdns_pcie_host_setup(struct cdns_pcie_rc *rc)
pcie = &rc->pcie;
pcie->is_rc = true;

- rc->no_bar_nbits = 32;
- of_property_read_u32(np, "cdns,no-bar-match-nbits", &rc->no_bar_nbits);
-
rc->vendor_id = 0xffff;
of_property_read_u32(np, "vendor-id", &rc->vendor_id);

@@ -248,6 +468,9 @@ int cdns_pcie_host_setup(struct cdns_pcie_rc *rc)

pcie->mem_res = res;

+ for (bar = RP_BAR0; bar <= RP_NO_BAR; bar++)
+ rc->avail_ib_bar[bar] = true;
+
ret = cdns_pcie_host_init(dev, &resources, rc);
if (ret)
goto err_init;
diff --git a/drivers/pci/controller/cadence/pcie-cadence.h b/drivers/pci/controller/cadence/pcie-cadence.h
index df14ad002fe9..bc49c22e48a9 100644
--- a/drivers/pci/controller/cadence/pcie-cadence.h
+++ b/drivers/pci/controller/cadence/pcie-cadence.h
@@ -87,6 +87,20 @@
#define CDNS_PCIE_LM_BAR_CFG_CTRL_MEM_64BITS 0x6
#define CDNS_PCIE_LM_BAR_CFG_CTRL_PREFETCH_MEM_64BITS 0x7

+#define LM_RC_BAR_CFG_CTRL_DISABLED(bar) \
+ (CDNS_PCIE_LM_BAR_CFG_CTRL_DISABLED << (((bar) * 8) + 6))
+#define LM_RC_BAR_CFG_CTRL_IO_32BITS(bar) \
+ (CDNS_PCIE_LM_BAR_CFG_CTRL_IO_32BITS << (((bar) * 8) + 6))
+#define LM_RC_BAR_CFG_CTRL_MEM_32BITS(bar) \
+ (CDNS_PCIE_LM_BAR_CFG_CTRL_MEM_32BITS << (((bar) * 8) + 6))
+#define LM_RC_BAR_CFG_CTRL_PREF_MEM_32BITS(bar) \
+ (CDNS_PCIE_LM_BAR_CFG_CTRL_PREFETCH_MEM_32BITS << (((bar) * 8) + 6))
+#define LM_RC_BAR_CFG_CTRL_MEM_64BITS(bar) \
+ (CDNS_PCIE_LM_BAR_CFG_CTRL_MEM_64BITS << (((bar) * 8) + 6))
+#define LM_RC_BAR_CFG_CTRL_PREF_MEM_64BITS(bar) \
+ (CDNS_PCIE_LM_BAR_CFG_CTRL_PREFETCH_MEM_64BITS << (((bar) * 8) + 6))
+#define LM_RC_BAR_CFG_APERTURE(bar, aperture) \
+ (((aperture) - 2) << ((bar) * 8))

/*
* Endpoint Function Registers (PCI configuration space for endpoint functions)
@@ -170,11 +184,19 @@
#define CDNS_PCIE_AT_LINKDOWN (CDNS_PCIE_AT_BASE + 0x0824)

enum cdns_pcie_rp_bar {
+ RP_BAR_UNDEFINED = -1,
RP_BAR0,
RP_BAR1,
RP_NO_BAR
};

+#define CDNS_PCIE_RP_MAX_IB 0x3
+
+struct cdns_pcie_rp_ib_bar {
+ u64 size;
+ bool free;
+};
+
/* Endpoint Function BAR Inbound PCIe to AXI Address Translation Register */
#define CDNS_PCIE_AT_IB_EP_FUNC_BAR_ADDR0(fn, bar) \
(CDNS_PCIE_AT_BASE + 0x0840 + (fn) * 0x0040 + (bar) * 0x0008)
@@ -251,19 +273,19 @@ struct cdns_pcie {
* @bus_range: first/last buses behind the PCIe host controller
* @cfg_base: IO mapped window to access the PCI configuration space of a
* single function at a time
- * @no_bar_nbits: Number of bits to keep for inbound (PCIe -> CPU) address
- * translation (nbits sets into the "no BAR match" register)
* @vendor_id: PCI vendor ID
* @device_id: PCI device ID
+ * @avail_ib_bar: Satus of RP_BAR0, RP_BAR1 and RP_NO_BAR if it's free or
+ * available
*/
struct cdns_pcie_rc {
struct cdns_pcie pcie;
struct resource *cfg_res;
struct resource *bus_range;
void __iomem *cfg_base;
- u32 no_bar_nbits;
u32 vendor_id;
u32 device_id;
+ bool avail_ib_bar[CDNS_PCIE_RP_MAX_IB];
};

/**
--
2.17.1

2020-07-22 11:06:32

by Kishon Vijay Abraham I

[permalink] [raw]
Subject: [PATCH v8 02/15] PCI: cadence: Fix cdns_pcie_{host|ep}_setup() error path

commit bd22885aa188 ("PCI: cadence: Refactor driver to use as a core
library") while refactoring the Cadence PCIe driver to be used as
library, removed pm_runtime_get_sync() from cdns_pcie_ep_setup()
and cdns_pcie_host_setup() but missed to remove the corresponding
pm_runtime_put_sync() in the error path. Fix it here.

Fixes: bd22885aa188 ("PCI: cadence: Refactor driver to use as a core library")
Reviewed-by: Rob Herring <[email protected]>
Signed-off-by: Kishon Vijay Abraham I <[email protected]>
---
drivers/pci/controller/cadence/pcie-cadence-ep.c | 9 ++-------
drivers/pci/controller/cadence/pcie-cadence-host.c | 6 +-----
2 files changed, 3 insertions(+), 12 deletions(-)

diff --git a/drivers/pci/controller/cadence/pcie-cadence-ep.c b/drivers/pci/controller/cadence/pcie-cadence-ep.c
index 1c15c8352125..4a829ccff7d0 100644
--- a/drivers/pci/controller/cadence/pcie-cadence-ep.c
+++ b/drivers/pci/controller/cadence/pcie-cadence-ep.c
@@ -8,7 +8,6 @@
#include <linux/of.h>
#include <linux/pci-epc.h>
#include <linux/platform_device.h>
-#include <linux/pm_runtime.h>
#include <linux/sizes.h>

#include "pcie-cadence.h"
@@ -440,8 +439,7 @@ int cdns_pcie_ep_setup(struct cdns_pcie_ep *ep)
epc = devm_pci_epc_create(dev, &cdns_pcie_epc_ops);
if (IS_ERR(epc)) {
dev_err(dev, "failed to create epc device\n");
- ret = PTR_ERR(epc);
- goto err_init;
+ return PTR_ERR(epc);
}

epc_set_drvdata(epc, ep);
@@ -453,7 +451,7 @@ int cdns_pcie_ep_setup(struct cdns_pcie_ep *ep)
resource_size(pcie->mem_res), PAGE_SIZE);
if (ret < 0) {
dev_err(dev, "failed to initialize the memory space\n");
- goto err_init;
+ return ret;
}

ep->irq_cpu_addr = pci_epc_mem_alloc_addr(epc, &ep->irq_phys_addr,
@@ -472,8 +470,5 @@ int cdns_pcie_ep_setup(struct cdns_pcie_ep *ep)
free_epc_mem:
pci_epc_mem_exit(epc);

- err_init:
- pm_runtime_put_sync(dev);
-
return ret;
}
diff --git a/drivers/pci/controller/cadence/pcie-cadence-host.c b/drivers/pci/controller/cadence/pcie-cadence-host.c
index f42a0acfce00..030e828bfd4c 100644
--- a/drivers/pci/controller/cadence/pcie-cadence-host.c
+++ b/drivers/pci/controller/cadence/pcie-cadence-host.c
@@ -8,7 +8,6 @@
#include <linux/of_address.h>
#include <linux/of_pci.h>
#include <linux/platform_device.h>
-#include <linux/pm_runtime.h>

#include "pcie-cadence.h"

@@ -473,7 +472,7 @@ int cdns_pcie_host_setup(struct cdns_pcie_rc *rc)

ret = cdns_pcie_host_init(dev, &resources, rc);
if (ret)
- goto err_init;
+ return ret;

list_splice_init(&resources, &bridge->windows);
bridge->dev.parent = dev;
@@ -491,8 +490,5 @@ int cdns_pcie_host_setup(struct cdns_pcie_rc *rc)
err_host_probe:
pci_free_resource_list(&resources);

- err_init:
- pm_runtime_put_sync(dev);
-
return ret;
}
--
2.17.1

2020-07-22 11:07:00

by Kishon Vijay Abraham I

[permalink] [raw]
Subject: [PATCH v8 07/15] dt-bindings: PCI: cadence: Remove "mem" from reg binding

"mem" is not a memory resource and it overlaps with PCIe config space
and memory region. Remove "mem" from reg binding.

Signed-off-by: Kishon Vijay Abraham I <[email protected]>
Reviewed-by: Rob Herring <[email protected]>
---
.../devicetree/bindings/pci/cdns,cdns-pcie-host.yaml | 8 +++-----
1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/Documentation/devicetree/bindings/pci/cdns,cdns-pcie-host.yaml b/Documentation/devicetree/bindings/pci/cdns,cdns-pcie-host.yaml
index 84a8f095d031..6d67067843bf 100644
--- a/Documentation/devicetree/bindings/pci/cdns,cdns-pcie-host.yaml
+++ b/Documentation/devicetree/bindings/pci/cdns,cdns-pcie-host.yaml
@@ -18,13 +18,12 @@ properties:
const: cdns,cdns-pcie-host

reg:
- maxItems: 3
+ maxItems: 2

reg-names:
items:
- const: reg
- const: cfg
- - const: mem

msi-parent: true

@@ -49,9 +48,8 @@ examples:
device-id = <0x0200>;

reg = <0x0 0xfb000000 0x0 0x01000000>,
- <0x0 0x41000000 0x0 0x00001000>,
- <0x0 0x40000000 0x0 0x04000000>;
- reg-names = "reg", "cfg", "mem";
+ <0x0 0x41000000 0x0 0x00001000>;
+ reg-names = "reg", "cfg";

ranges = <0x02000000 0x0 0x42000000 0x0 0x42000000 0x0 0x1000000>,
<0x01000000 0x0 0x43000000 0x0 0x43000000 0x0 0x0010000>;
--
2.17.1

2020-07-22 11:07:34

by Kishon Vijay Abraham I

[permalink] [raw]
Subject: [PATCH v8 08/15] PCI: cadence: Add new *ops* for CPU addr fixup

Cadence driver uses "mem" memory resource to obtain the offset of
configuration space address region, memory space address region and
message space address region. The obtained offset is used to program
the Address Translation Unit (ATU). However certain platforms like TI's
J721E SoC require the absolute address to be programmed in the ATU and
not just the offset. Add new *ops* for CPU addr fixup for the platform
drivers to provide the correct address to be programmed in the ATU.

Signed-off-by: Kishon Vijay Abraham I <[email protected]>
---
.../pci/controller/cadence/pcie-cadence-host.c | 15 ++++-----------
.../pci/controller/cadence/pcie-cadence-plat.c | 13 +++++++++++++
drivers/pci/controller/cadence/pcie-cadence.c | 8 ++++++--
drivers/pci/controller/cadence/pcie-cadence.h | 1 +
4 files changed, 24 insertions(+), 13 deletions(-)

diff --git a/drivers/pci/controller/cadence/pcie-cadence-host.c b/drivers/pci/controller/cadence/pcie-cadence-host.c
index a8303258874c..10127ea71b83 100644
--- a/drivers/pci/controller/cadence/pcie-cadence-host.c
+++ b/drivers/pci/controller/cadence/pcie-cadence-host.c
@@ -327,15 +327,14 @@ static int cdns_pcie_host_map_dma_ranges(struct cdns_pcie_rc *rc)
static int cdns_pcie_host_init_address_translation(struct cdns_pcie_rc *rc)
{
struct cdns_pcie *pcie = &rc->pcie;
- struct resource *mem_res = pcie->mem_res;
struct resource *bus_range = rc->bus_range;
struct resource *cfg_res = rc->cfg_res;
struct device *dev = pcie->dev;
struct device_node *np = dev->of_node;
struct of_pci_range_parser parser;
+ u64 cpu_addr = cfg_res->start;
struct of_pci_range range;
u32 addr0, addr1, desc1;
- u64 cpu_addr;
int r, err;

/*
@@ -348,7 +347,9 @@ static int cdns_pcie_host_init_address_translation(struct cdns_pcie_rc *rc)
cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_PCI_ADDR1(0), addr1);
cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC1(0), desc1);

- cpu_addr = cfg_res->start - mem_res->start;
+ if (pcie->ops->cpu_addr_fixup)
+ cpu_addr = pcie->ops->cpu_addr_fixup(pcie, cpu_addr);
+
addr0 = CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS(12) |
(lower_32_bits(cpu_addr) & GENMASK(31, 8));
addr1 = upper_32_bits(cpu_addr);
@@ -477,14 +478,6 @@ int cdns_pcie_host_setup(struct cdns_pcie_rc *rc)
}
rc->cfg_res = res;

- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mem");
- if (!res) {
- dev_err(dev, "missing \"mem\"\n");
- return -EINVAL;
- }
-
- pcie->mem_res = res;
-
ret = cdns_pcie_start_link(pcie);
if (ret) {
dev_err(dev, "Failed to start link\n");
diff --git a/drivers/pci/controller/cadence/pcie-cadence-plat.c b/drivers/pci/controller/cadence/pcie-cadence-plat.c
index f5c6bf6dfcb8..6f5f07b3eed1 100644
--- a/drivers/pci/controller/cadence/pcie-cadence-plat.c
+++ b/drivers/pci/controller/cadence/pcie-cadence-plat.c
@@ -13,6 +13,8 @@
#include <linux/of_device.h>
#include "pcie-cadence.h"

+#define CDNS_PLAT_CPU_TO_BUS_ADDR 0x0FFFFFFF
+
/**
* struct cdns_plat_pcie - private data for this PCIe platform driver
* @pcie: Cadence PCIe controller
@@ -30,6 +32,15 @@ struct cdns_plat_pcie_of_data {

static const struct of_device_id cdns_plat_pcie_of_match[];

+static u64 cdns_plat_cpu_addr_fixup(struct cdns_pcie *pcie, u64 cpu_addr)
+{
+ return cpu_addr & CDNS_PLAT_CPU_TO_BUS_ADDR;
+}
+
+static const struct cdns_pcie_ops cdns_plat_ops = {
+ .cpu_addr_fixup = cdns_plat_cpu_addr_fixup,
+};
+
static int cdns_plat_pcie_probe(struct platform_device *pdev)
{
const struct cdns_plat_pcie_of_data *data;
@@ -66,6 +77,7 @@ static int cdns_plat_pcie_probe(struct platform_device *pdev)

rc = pci_host_bridge_priv(bridge);
rc->pcie.dev = dev;
+ rc->pcie.ops = &cdns_plat_ops;
cdns_plat_pcie->pcie = &rc->pcie;
cdns_plat_pcie->is_rc = is_rc;

@@ -93,6 +105,7 @@ static int cdns_plat_pcie_probe(struct platform_device *pdev)
return -ENOMEM;

ep->pcie.dev = dev;
+ ep->pcie.ops = &cdns_plat_ops;
cdns_plat_pcie->pcie = &ep->pcie;
cdns_plat_pcie->is_rc = is_rc;

diff --git a/drivers/pci/controller/cadence/pcie-cadence.c b/drivers/pci/controller/cadence/pcie-cadence.c
index cd795f6fc1e2..8a02981fd456 100644
--- a/drivers/pci/controller/cadence/pcie-cadence.c
+++ b/drivers/pci/controller/cadence/pcie-cadence.c
@@ -73,7 +73,9 @@ void cdns_pcie_set_outbound_region(struct cdns_pcie *pcie, u8 fn,
cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC1(r), desc1);

/* Set the CPU address */
- cpu_addr -= pcie->mem_res->start;
+ if (pcie->ops->cpu_addr_fixup)
+ cpu_addr = pcie->ops->cpu_addr_fixup(pcie, cpu_addr);
+
addr0 = CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS(nbits) |
(lower_32_bits(cpu_addr) & GENMASK(31, 8));
addr1 = upper_32_bits(cpu_addr);
@@ -100,7 +102,9 @@ void cdns_pcie_set_outbound_region_for_normal_msg(struct cdns_pcie *pcie, u8 fn,
}

/* Set the CPU address */
- cpu_addr -= pcie->mem_res->start;
+ if (pcie->ops->cpu_addr_fixup)
+ cpu_addr = pcie->ops->cpu_addr_fixup(pcie, cpu_addr);
+
addr0 = CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS(17) |
(lower_32_bits(cpu_addr) & GENMASK(31, 8));
addr1 = upper_32_bits(cpu_addr);
diff --git a/drivers/pci/controller/cadence/pcie-cadence.h b/drivers/pci/controller/cadence/pcie-cadence.h
index 36c493fa4fde..7c804ac1dbc2 100644
--- a/drivers/pci/controller/cadence/pcie-cadence.h
+++ b/drivers/pci/controller/cadence/pcie-cadence.h
@@ -254,6 +254,7 @@ struct cdns_pcie_ops {
int (*start_link)(struct cdns_pcie *pcie);
void (*stop_link)(struct cdns_pcie *pcie);
bool (*link_up)(struct cdns_pcie *pcie);
+ u64 (*cpu_addr_fixup)(struct cdns_pcie *pcie, u64 cpu_addr);
};

/**
--
2.17.1

2020-07-22 11:07:36

by Kishon Vijay Abraham I

[permalink] [raw]
Subject: [PATCH v8 11/15] dt-bindings: PCI: Add host mode dt-bindings for TI's J721E SoC

Add host mode dt-bindings for TI's J721E SoC.

Signed-off-by: Kishon Vijay Abraham I <[email protected]>
Reviewed-by: Rob Herring <[email protected]>
---
.../bindings/pci/ti,j721e-pci-host.yaml | 113 ++++++++++++++++++
1 file changed, 113 insertions(+)
create mode 100644 Documentation/devicetree/bindings/pci/ti,j721e-pci-host.yaml

diff --git a/Documentation/devicetree/bindings/pci/ti,j721e-pci-host.yaml b/Documentation/devicetree/bindings/pci/ti,j721e-pci-host.yaml
new file mode 100644
index 000000000000..d7b60487c6c3
--- /dev/null
+++ b/Documentation/devicetree/bindings/pci/ti,j721e-pci-host.yaml
@@ -0,0 +1,113 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+# Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/
+%YAML 1.2
+---
+$id: "http://devicetree.org/schemas/pci/ti,j721e-pci-host.yaml#"
+$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+
+title: TI J721E PCI Host (PCIe Wrapper)
+
+maintainers:
+ - Kishon Vijay Abraham I <[email protected]>
+
+allOf:
+ - $ref: "cdns-pcie-host.yaml#"
+
+properties:
+ compatible:
+ enum:
+ - ti,j721e-pcie-host
+
+ reg:
+ maxItems: 4
+
+ reg-names:
+ items:
+ - const: intd_cfg
+ - const: user_cfg
+ - const: reg
+ - const: cfg
+
+ ti,syscon-pcie-ctrl:
+ description: Phandle to the SYSCON entry required for configuring PCIe mode
+ and link speed.
+ allOf:
+ - $ref: /schemas/types.yaml#/definitions/phandle
+
+ power-domains:
+ maxItems: 1
+
+ clocks:
+ maxItems: 1
+ description: clock-specifier to represent input to the PCIe
+
+ clock-names:
+ items:
+ - const: fck
+
+ vendor-id:
+ const: 0x104c
+
+ device-id:
+ const: 0xb00d
+
+ msi-map: true
+
+required:
+ - compatible
+ - reg
+ - reg-names
+ - ti,syscon-pcie-ctrl
+ - max-link-speed
+ - num-lanes
+ - power-domains
+ - clocks
+ - clock-names
+ - vendor-id
+ - device-id
+ - msi-map
+ - dma-coherent
+ - dma-ranges
+ - ranges
+ - reset-gpios
+ - phys
+ - phy-names
+
+examples:
+ - |
+ #include <dt-bindings/soc/ti,sci_pm_domain.h>
+ #include <dt-bindings/gpio/gpio.h>
+
+ bus {
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ pcie0_rc: pcie@2900000 {
+ compatible = "ti,j721e-pcie-host";
+ reg = <0x00 0x02900000 0x00 0x1000>,
+ <0x00 0x02907000 0x00 0x400>,
+ <0x00 0x0d000000 0x00 0x00800000>,
+ <0x00 0x10000000 0x00 0x00001000>;
+ reg-names = "intd_cfg", "user_cfg", "reg", "cfg";
+ ti,syscon-pcie-ctrl = <&pcie0_ctrl>;
+ max-link-speed = <3>;
+ num-lanes = <2>;
+ power-domains = <&k3_pds 239 TI_SCI_PD_EXCLUSIVE>;
+ clocks = <&k3_clks 239 1>;
+ clock-names = "fck";
+ device_type = "pci";
+ #address-cells = <3>;
+ #size-cells = <2>;
+ bus-range = <0x0 0xf>;
+ vendor-id = <0x104c>;
+ device-id = <0xb00d>;
+ msi-map = <0x0 &gic_its 0x0 0x10000>;
+ dma-coherent;
+ reset-gpios = <&exp1 6 GPIO_ACTIVE_HIGH>;
+ phys = <&serdes0_pcie_link>;
+ phy-names = "pcie-phy";
+ ranges = <0x01000000 0x0 0x10001000 0x00 0x10001000 0x0 0x0010000>,
+ <0x02000000 0x0 0x10011000 0x00 0x10011000 0x0 0x7fef000>;
+ dma-ranges = <0x02000000 0x0 0x0 0x0 0x0 0x10000 0x0>;
+ };
+ };
--
2.17.1

2020-07-22 11:08:08

by Kishon Vijay Abraham I

[permalink] [raw]
Subject: [PATCH v8 14/15] misc: pci_endpoint_test: Add J721E in pci_device_id table

Add J721E in pci_device_id table so that pci-epf-test can be used
for testing PCIe EP in J721E.

Reviewed-by: Rob Herring <[email protected]>
Signed-off-by: Kishon Vijay Abraham I <[email protected]>
---
drivers/misc/pci_endpoint_test.c | 9 +++++++++
1 file changed, 9 insertions(+)

diff --git a/drivers/misc/pci_endpoint_test.c b/drivers/misc/pci_endpoint_test.c
index 41c40971979e..e060796f9caa 100644
--- a/drivers/misc/pci_endpoint_test.c
+++ b/drivers/misc/pci_endpoint_test.c
@@ -68,6 +68,7 @@
#define PCI_ENDPOINT_TEST_FLAGS 0x2c
#define FLAG_USE_DMA BIT(0)

+#define PCI_DEVICE_ID_TI_J721E 0xb00d
#define PCI_DEVICE_ID_TI_AM654 0xb00c

#define is_am654_pci_dev(pdev) \
@@ -932,6 +933,11 @@ static const struct pci_endpoint_test_data am654_data = {
.irq_type = IRQ_TYPE_MSI,
};

+static const struct pci_endpoint_test_data j721e_data = {
+ .alignment = 256,
+ .irq_type = IRQ_TYPE_MSI,
+};
+
static const struct pci_device_id pci_endpoint_test_tbl[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_DRA74x),
.driver_data = (kernel_ulong_t)&default_data,
@@ -946,6 +952,9 @@ static const struct pci_device_id pci_endpoint_test_tbl[] = {
},
{ PCI_DEVICE(PCI_VENDOR_ID_RENESAS, PCI_DEVICE_ID_RENESAS_R8A774C0),
},
+ { PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_J721E),
+ .driver_data = (kernel_ulong_t)&j721e_data,
+ },
{ }
};
MODULE_DEVICE_TABLE(pci, pci_endpoint_test_tbl);
--
2.17.1

2020-07-22 11:08:06

by Kishon Vijay Abraham I

[permalink] [raw]
Subject: [PATCH v8 13/15] PCI: j721e: Add TI J721E PCIe driver

Add support for PCIe controller in J721E SoC. The controller uses the
Cadence PCIe core programmed by pcie-cadence*.c. The PCIe controller
will work in both host mode and device mode.
Some of the features of the controller are:
*) Supports both RC mode and EP mode
*) Supports MSI and MSI-X support
*) Supports upto GEN3 speed mode
*) Supports SR-IOV capability
*) Ability to route all transactions via SMMU (support will be added
in a later patch).

Signed-off-by: Kishon Vijay Abraham I <[email protected]>
---
drivers/pci/controller/cadence/Kconfig | 23 +
drivers/pci/controller/cadence/Makefile | 1 +
drivers/pci/controller/cadence/pci-j721e.c | 493 ++++++++++++++++++
.../controller/cadence/pcie-cadence-host.c | 4 +-
drivers/pci/controller/cadence/pcie-cadence.h | 8 +
5 files changed, 527 insertions(+), 2 deletions(-)
create mode 100644 drivers/pci/controller/cadence/pci-j721e.c

diff --git a/drivers/pci/controller/cadence/Kconfig b/drivers/pci/controller/cadence/Kconfig
index b76b3cf55ce5..5d30564190e1 100644
--- a/drivers/pci/controller/cadence/Kconfig
+++ b/drivers/pci/controller/cadence/Kconfig
@@ -42,4 +42,27 @@ config PCIE_CADENCE_PLAT_EP
endpoint mode. This PCIe controller may be embedded into many
different vendors SoCs.

+config PCI_J721E
+ bool
+
+config PCI_J721E_HOST
+ bool "TI J721E PCIe platform host controller"
+ depends on OF
+ select PCIE_CADENCE_HOST
+ select PCI_J721E
+ help
+ Say Y here if you want to support the TI J721E PCIe platform
+ controller in host mode. TI J721E PCIe controller uses Cadence PCIe
+ core.
+
+config PCI_J721E_EP
+ bool "TI J721E PCIe platform endpoint controller"
+ depends on OF
+ depends on PCI_ENDPOINT
+ select PCIE_CADENCE_EP
+ select PCI_J721E
+ help
+ Say Y here if you want to support the TI J721E PCIe platform
+ controller in endpoint mode. TI J721E PCIe controller uses Cadence PCIe
+ core.
endmenu
diff --git a/drivers/pci/controller/cadence/Makefile b/drivers/pci/controller/cadence/Makefile
index 232a3f20876a..9bac5fb2f13d 100644
--- a/drivers/pci/controller/cadence/Makefile
+++ b/drivers/pci/controller/cadence/Makefile
@@ -3,3 +3,4 @@ obj-$(CONFIG_PCIE_CADENCE) += pcie-cadence.o
obj-$(CONFIG_PCIE_CADENCE_HOST) += pcie-cadence-host.o
obj-$(CONFIG_PCIE_CADENCE_EP) += pcie-cadence-ep.o
obj-$(CONFIG_PCIE_CADENCE_PLAT) += pcie-cadence-plat.o
+obj-$(CONFIG_PCI_J721E) += pci-j721e.o
diff --git a/drivers/pci/controller/cadence/pci-j721e.c b/drivers/pci/controller/cadence/pci-j721e.c
new file mode 100644
index 000000000000..23ad8fa699c4
--- /dev/null
+++ b/drivers/pci/controller/cadence/pci-j721e.c
@@ -0,0 +1,493 @@
+// SPDX-License-Identifier: GPL-2.0
+/**
+ * pci-j721e - PCIe controller driver for TI's J721E SoCs
+ *
+ * Copyright (C) 2020 Texas Instruments Incorporated - http://www.ti.com
+ * Author: Kishon Vijay Abraham I <[email protected]>
+ */
+
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/io.h>
+#include <linux/irqchip/chained_irq.h>
+#include <linux/irqdomain.h>
+#include <linux/mfd/syscon.h>
+#include <linux/of_device.h>
+#include <linux/of_irq.h>
+#include <linux/pci.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+
+#include "../../pci.h"
+#include "pcie-cadence.h"
+
+#define ENABLE_REG_SYS_2 0x108
+#define STATUS_REG_SYS_2 0x508
+#define STATUS_CLR_REG_SYS_2 0x708
+#define LINK_DOWN BIT(1)
+
+#define J721E_PCIE_USER_CMD_STATUS 0x4
+#define LINK_TRAINING_ENABLE BIT(0)
+
+#define J721E_PCIE_USER_LINKSTATUS 0x14
+#define LINK_STATUS GENMASK(1, 0)
+
+enum link_status {
+ NO_RECEIVERS_DETECTED,
+ LINK_TRAINING_IN_PROGRESS,
+ LINK_UP_DL_IN_PROGRESS,
+ LINK_UP_DL_COMPLETED,
+};
+
+#define J721E_MODE_RC BIT(7)
+#define LANE_COUNT_MASK BIT(8)
+#define LANE_COUNT(n) ((n) << 8)
+
+#define GENERATION_SEL_MASK GENMASK(1, 0)
+
+#define MAX_LANES 2
+
+struct j721e_pcie {
+ struct device *dev;
+ u32 mode;
+ u32 num_lanes;
+ struct cdns_pcie *cdns_pcie;
+ void __iomem *user_cfg_base;
+ void __iomem *intd_cfg_base;
+};
+
+enum j721e_pcie_mode {
+ PCI_MODE_RC,
+ PCI_MODE_EP,
+};
+
+struct j721e_pcie_data {
+ enum j721e_pcie_mode mode;
+};
+
+static inline u32 j721e_pcie_user_readl(struct j721e_pcie *pcie, u32 offset)
+{
+ return readl(pcie->user_cfg_base + offset);
+}
+
+static inline void j721e_pcie_user_writel(struct j721e_pcie *pcie, u32 offset,
+ u32 value)
+{
+ writel(value, pcie->user_cfg_base + offset);
+}
+
+static inline u32 j721e_pcie_intd_readl(struct j721e_pcie *pcie, u32 offset)
+{
+ return readl(pcie->intd_cfg_base + offset);
+}
+
+static inline void j721e_pcie_intd_writel(struct j721e_pcie *pcie, u32 offset,
+ u32 value)
+{
+ writel(value, pcie->intd_cfg_base + offset);
+}
+
+static irqreturn_t j721e_pcie_link_irq_handler(int irq, void *priv)
+{
+ struct j721e_pcie *pcie = priv;
+ struct device *dev = pcie->dev;
+ u32 reg;
+
+ reg = j721e_pcie_intd_readl(pcie, STATUS_REG_SYS_2);
+ if (!(reg & LINK_DOWN))
+ return IRQ_NONE;
+
+ dev_err(dev, "LINK DOWN!\n");
+
+ j721e_pcie_intd_writel(pcie, STATUS_CLR_REG_SYS_2, LINK_DOWN);
+ return IRQ_HANDLED;
+}
+
+static void j721e_pcie_config_link_irq(struct j721e_pcie *pcie)
+{
+ u32 reg;
+
+ reg = j721e_pcie_intd_readl(pcie, ENABLE_REG_SYS_2);
+ reg |= LINK_DOWN;
+ j721e_pcie_intd_writel(pcie, ENABLE_REG_SYS_2, reg);
+}
+
+static int j721e_pcie_start_link(struct cdns_pcie *cdns_pcie)
+{
+ struct j721e_pcie *pcie = dev_get_drvdata(cdns_pcie->dev);
+ u32 reg;
+
+ reg = j721e_pcie_user_readl(pcie, J721E_PCIE_USER_CMD_STATUS);
+ reg |= LINK_TRAINING_ENABLE;
+ j721e_pcie_user_writel(pcie, J721E_PCIE_USER_CMD_STATUS, reg);
+
+ return 0;
+}
+
+static void j721e_pcie_stop_link(struct cdns_pcie *cdns_pcie)
+{
+ struct j721e_pcie *pcie = dev_get_drvdata(cdns_pcie->dev);
+ u32 reg;
+
+ reg = j721e_pcie_user_readl(pcie, J721E_PCIE_USER_CMD_STATUS);
+ reg &= ~LINK_TRAINING_ENABLE;
+ j721e_pcie_user_writel(pcie, J721E_PCIE_USER_CMD_STATUS, reg);
+}
+
+static bool j721e_pcie_link_up(struct cdns_pcie *cdns_pcie)
+{
+ struct j721e_pcie *pcie = dev_get_drvdata(cdns_pcie->dev);
+ u32 reg;
+
+ reg = j721e_pcie_user_readl(pcie, J721E_PCIE_USER_LINKSTATUS);
+ reg &= LINK_STATUS;
+ if (reg == LINK_UP_DL_COMPLETED)
+ return true;
+
+ return false;
+}
+
+static const struct cdns_pcie_ops j721e_pcie_ops = {
+ .start_link = j721e_pcie_start_link,
+ .stop_link = j721e_pcie_stop_link,
+ .link_up = j721e_pcie_link_up,
+};
+
+static int j721e_pcie_set_mode(struct j721e_pcie *pcie, struct regmap *syscon)
+{
+ struct device *dev = pcie->dev;
+ u32 mask = J721E_MODE_RC;
+ u32 mode = pcie->mode;
+ u32 val = 0;
+ int ret = 0;
+
+ if (mode == PCI_MODE_RC)
+ val = J721E_MODE_RC;
+
+ ret = regmap_update_bits(syscon, 0, mask, val);
+ if (ret)
+ dev_err(dev, "failed to set pcie mode\n");
+
+ return ret;
+}
+
+static int j721e_pcie_set_link_speed(struct j721e_pcie *pcie,
+ struct regmap *syscon)
+{
+ struct device *dev = pcie->dev;
+ struct device_node *np = dev->of_node;
+ int link_speed;
+ u32 val = 0;
+ int ret;
+
+ link_speed = of_pci_get_max_link_speed(np);
+ if (link_speed < 2)
+ link_speed = 2;
+
+ val = link_speed - 1;
+ ret = regmap_update_bits(syscon, 0, GENERATION_SEL_MASK, val);
+ if (ret)
+ dev_err(dev, "failed to set link speed\n");
+
+ return ret;
+}
+
+static int j721e_pcie_set_lane_count(struct j721e_pcie *pcie,
+ struct regmap *syscon)
+{
+ struct device *dev = pcie->dev;
+ u32 lanes = pcie->num_lanes;
+ u32 val = 0;
+ int ret;
+
+ val = LANE_COUNT(lanes - 1);
+ ret = regmap_update_bits(syscon, 0, LANE_COUNT_MASK, val);
+ if (ret)
+ dev_err(dev, "failed to set link count\n");
+
+ return ret;
+}
+
+static int j721e_pcie_ctrl_init(struct j721e_pcie *pcie)
+{
+ struct device *dev = pcie->dev;
+ struct device_node *node = dev->of_node;
+ struct regmap *syscon;
+ int ret;
+
+ syscon = syscon_regmap_lookup_by_phandle(node, "ti,syscon-pcie-ctrl");
+ if (IS_ERR(syscon)) {
+ dev_err(dev, "Unable to get ti,syscon-pcie-ctrl regmap\n");
+ return PTR_ERR(syscon);
+ }
+
+ ret = j721e_pcie_set_mode(pcie, syscon);
+ if (ret < 0) {
+ dev_err(dev, "Failed to set pci mode\n");
+ return ret;
+ }
+
+ ret = j721e_pcie_set_link_speed(pcie, syscon);
+ if (ret < 0) {
+ dev_err(dev, "Failed to set link speed\n");
+ return ret;
+ }
+
+ ret = j721e_pcie_set_lane_count(pcie, syscon);
+ if (ret < 0) {
+ dev_err(dev, "Failed to set num-lanes\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int cdns_ti_pcie_config_read(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 *value)
+{
+ struct pci_host_bridge *bridge = pci_find_host_bridge(bus);
+ struct cdns_pcie_rc *rc = pci_host_bridge_priv(bridge);
+ unsigned int busn = bus->number;
+
+ if (busn == rc->bus_range->start)
+ return pci_generic_config_read32(bus, devfn, where, size,
+ value);
+
+ return pci_generic_config_read(bus, devfn, where, size, value);
+}
+
+static int cdns_ti_pcie_config_write(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 value)
+{
+ struct pci_host_bridge *bridge = pci_find_host_bridge(bus);
+ struct cdns_pcie_rc *rc = pci_host_bridge_priv(bridge);
+ unsigned int busn = bus->number;
+
+ if (busn == rc->bus_range->start)
+ return pci_generic_config_write32(bus, devfn, where, size,
+ value);
+
+ return pci_generic_config_write(bus, devfn, where, size, value);
+}
+
+static struct pci_ops cdns_ti_pcie_host_ops = {
+ .map_bus = cdns_pci_map_bus,
+ .read = cdns_ti_pcie_config_read,
+ .write = cdns_ti_pcie_config_write,
+};
+
+static const struct j721e_pcie_data j721e_pcie_rc_data = {
+ .mode = PCI_MODE_RC,
+};
+
+static const struct j721e_pcie_data j721e_pcie_ep_data = {
+ .mode = PCI_MODE_EP,
+};
+
+static const struct of_device_id of_j721e_pcie_match[] = {
+ {
+ .compatible = "ti,j721e-pcie-host",
+ .data = &j721e_pcie_rc_data,
+ },
+ {
+ .compatible = "ti,j721e-pcie-ep",
+ .data = &j721e_pcie_ep_data,
+ },
+ {},
+};
+
+static int j721e_pcie_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *node = dev->of_node;
+ struct pci_host_bridge *bridge;
+ struct j721e_pcie_data *data;
+ struct cdns_pcie *cdns_pcie;
+ struct j721e_pcie *pcie;
+ struct cdns_pcie_rc *rc;
+ struct cdns_pcie_ep *ep;
+ struct gpio_desc *gpiod;
+ void __iomem *base;
+ u32 num_lanes;
+ u32 mode;
+ int ret;
+ int irq;
+
+ data = (struct j721e_pcie_data *)of_device_get_match_data(dev);
+ if (!data)
+ return -EINVAL;
+
+ mode = (u32)data->mode;
+
+ pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL);
+ if (!pcie)
+ return -ENOMEM;
+
+ pcie->dev = dev;
+ pcie->mode = mode;
+
+ base = devm_platform_ioremap_resource_byname(pdev, "intd_cfg");
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+ pcie->intd_cfg_base = base;
+
+ base = devm_platform_ioremap_resource_byname(pdev, "user_cfg");
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+ pcie->user_cfg_base = base;
+
+ ret = of_property_read_u32(node, "num-lanes", &num_lanes);
+ if (ret || num_lanes > MAX_LANES)
+ num_lanes = 1;
+ pcie->num_lanes = num_lanes;
+
+ if (dma_set_mask_and_coherent(dev, DMA_BIT_MASK(48)))
+ return -EINVAL;
+
+ irq = platform_get_irq_byname(pdev, "link_state");
+ if (irq < 0)
+ return irq;
+
+ dev_set_drvdata(dev, pcie);
+ pm_runtime_enable(dev);
+ ret = pm_runtime_get_sync(dev);
+ if (ret < 0) {
+ dev_err(dev, "pm_runtime_get_sync failed\n");
+ goto err_get_sync;
+ }
+
+ ret = j721e_pcie_ctrl_init(pcie);
+ if (ret < 0) {
+ dev_err(dev, "pm_runtime_get_sync failed\n");
+ goto err_get_sync;
+ }
+
+ ret = devm_request_irq(dev, irq, j721e_pcie_link_irq_handler, 0,
+ "j721e-pcie-link-down-irq", pcie);
+ if (ret < 0) {
+ dev_err(dev, "failed to request link state IRQ %d\n", irq);
+ goto err_get_sync;
+ }
+
+ j721e_pcie_config_link_irq(pcie);
+
+ switch (mode) {
+ case PCI_MODE_RC:
+ if (!IS_ENABLED(CONFIG_PCIE_CADENCE_HOST)) {
+ ret = -ENODEV;
+ goto err_get_sync;
+ }
+
+ bridge = devm_pci_alloc_host_bridge(dev, sizeof(*rc));
+ if (!bridge) {
+ ret = -ENOMEM;
+ goto err_get_sync;
+ }
+
+ bridge->ops = &cdns_ti_pcie_host_ops;
+ rc = pci_host_bridge_priv(bridge);
+
+ cdns_pcie = &rc->pcie;
+ cdns_pcie->dev = dev;
+ cdns_pcie->ops = &j721e_pcie_ops;
+ pcie->cdns_pcie = cdns_pcie;
+
+ gpiod = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
+ if (IS_ERR(gpiod)) {
+ ret = PTR_ERR(gpiod);
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev, "Failed to get reset GPIO\n");
+ goto err_get_sync;
+ }
+
+ ret = cdns_pcie_init_phy(dev, cdns_pcie);
+ if (ret) {
+ dev_err(dev, "Failed to init phy\n");
+ goto err_get_sync;
+ }
+
+ /*
+ * "Power Sequencing and Reset Signal Timings" table in
+ * PCI EXPRESS CARD ELECTROMECHANICAL SPECIFICATION, REV. 3.0
+ * indicates PERST# should be deasserted after minimum of 100us
+ * once REFCLK is stable. The REFCLK to the connector in RC
+ * mode is selected while enabling the PHY. So deassert PERST#
+ * after 100 us.
+ */
+ if (gpiod) {
+ usleep_range(100, 200);
+ gpiod_set_value_cansleep(gpiod, 1);
+ }
+
+ ret = cdns_pcie_host_setup(rc);
+ if (ret < 0)
+ goto err_pcie_setup;
+
+ break;
+ case PCI_MODE_EP:
+ if (!IS_ENABLED(CONFIG_PCIE_CADENCE_EP)) {
+ ret = -ENODEV;
+ goto err_get_sync;
+ }
+
+ ep = devm_kzalloc(dev, sizeof(*ep), GFP_KERNEL);
+ if (!ep) {
+ ret = -ENOMEM;
+ goto err_get_sync;
+ }
+
+ cdns_pcie = &ep->pcie;
+ cdns_pcie->dev = dev;
+ cdns_pcie->ops = &j721e_pcie_ops;
+ pcie->cdns_pcie = cdns_pcie;
+
+ ret = cdns_pcie_init_phy(dev, cdns_pcie);
+ if (ret) {
+ dev_err(dev, "Failed to init phy\n");
+ goto err_get_sync;
+ }
+
+ ret = cdns_pcie_ep_setup(ep);
+ if (ret < 0)
+ goto err_pcie_setup;
+
+ break;
+ default:
+ dev_err(dev, "INVALID device type %d\n", mode);
+ }
+
+ return 0;
+
+err_pcie_setup:
+ cdns_pcie_disable_phy(cdns_pcie);
+
+err_get_sync:
+ pm_runtime_put(dev);
+ pm_runtime_disable(dev);
+
+ return ret;
+}
+
+static int j721e_pcie_remove(struct platform_device *pdev)
+{
+ struct j721e_pcie *pcie = platform_get_drvdata(pdev);
+ struct cdns_pcie *cdns_pcie = pcie->cdns_pcie;
+ struct device *dev = &pdev->dev;
+
+ cdns_pcie_disable_phy(cdns_pcie);
+ pm_runtime_put(dev);
+ pm_runtime_disable(dev);
+
+ return 0;
+}
+
+static struct platform_driver j721e_pcie_driver = {
+ .probe = j721e_pcie_probe,
+ .remove = j721e_pcie_remove,
+ .driver = {
+ .name = "j721e-pcie",
+ .of_match_table = of_j721e_pcie_match,
+ .suppress_bind_attrs = true,
+ },
+};
+builtin_platform_driver(j721e_pcie_driver);
diff --git a/drivers/pci/controller/cadence/pcie-cadence-host.c b/drivers/pci/controller/cadence/pcie-cadence-host.c
index 8935f7a37e5a..ba157278fb0f 100644
--- a/drivers/pci/controller/cadence/pcie-cadence-host.c
+++ b/drivers/pci/controller/cadence/pcie-cadence-host.c
@@ -23,8 +23,8 @@ static u8 bar_aperture_mask[] = {
[RP_BAR1] = 0xF,
};

-static void __iomem *cdns_pci_map_bus(struct pci_bus *bus, unsigned int devfn,
- int where)
+void __iomem *cdns_pci_map_bus(struct pci_bus *bus, unsigned int devfn,
+ int where)
{
struct pci_host_bridge *bridge = pci_find_host_bridge(bus);
struct cdns_pcie_rc *rc = pci_host_bridge_priv(bridge);
diff --git a/drivers/pci/controller/cadence/pcie-cadence.h b/drivers/pci/controller/cadence/pcie-cadence.h
index dd910a1c30fb..655a6b4d4964 100644
--- a/drivers/pci/controller/cadence/pcie-cadence.h
+++ b/drivers/pci/controller/cadence/pcie-cadence.h
@@ -475,11 +475,19 @@ static inline bool cdns_pcie_link_up(struct cdns_pcie *pcie)

#ifdef CONFIG_PCIE_CADENCE_HOST
int cdns_pcie_host_setup(struct cdns_pcie_rc *rc);
+void __iomem *cdns_pci_map_bus(struct pci_bus *bus, unsigned int devfn,
+ int where);
#else
static inline int cdns_pcie_host_setup(struct cdns_pcie_rc *rc)
{
return 0;
}
+
+static void __iomem *cdns_pci_map_bus(struct pci_bus *bus, unsigned int devfn,
+ int where)
+{
+ return NULL;
+}
#endif

#ifdef CONFIG_PCIE_CADENCE_EP
--
2.17.1

2020-07-22 11:45:58

by Lorenzo Pieralisi

[permalink] [raw]
Subject: Re: [PATCH v8 01/15] PCI: cadence: Use "dma-ranges" instead of "cdns,no-bar-match-nbits" property

On Wed, Jul 22, 2020 at 04:33:03PM +0530, Kishon Vijay Abraham I wrote:
> Cadence PCIe core driver (host mode) uses "cdns,no-bar-match-nbits"
> property to configure the number of bits passed through from PCIe
> address to internal address in Inbound Address Translation register.
> This only used the NO MATCH BAR.
>
> However standard PCI dt-binding already defines "dma-ranges" to
> describe the address ranges accessible by PCIe controller. Add support
> in Cadence PCIe host driver to parse dma-ranges and configure the
> inbound regions for BAR0, BAR1 and NO MATCH BAR. Cadence IP specifies
> maximum size for BAR0 as 256GB, maximum size for BAR1 as 2 GB.
>
> This adds support to take the next biggest region in "dma-ranges" and
> find the smallest BAR that each of the regions fit in and if there is
> no BAR big enough to hold the region, split the region to see if it can
> be fitted using multiple BARs.
>
> "dma-ranges" of J721E will be
> dma-ranges = <0x02000000 0x0 0x0 0x0 0x0 0x10000 0x0>;
> Since there is no BAR which can hold 2^48 size, NO_MATCH_BAR will be
> used here.
>
> Legacy device tree binding compatibility is maintained by retaining
> support for "cdns,no-bar-match-nbits".
>
> Signed-off-by: Kishon Vijay Abraham I <[email protected]>
> ---
> Changes from [1]
> 1) Use list_sort() for sorting the address ranges by size
> 2) Clear CDNS_PCIE_LM_RC_BAR_CFG register before configuring them
>
> [1] -> http://lore.kernel.org/r/[email protected]
> .../controller/cadence/pcie-cadence-host.c | 251 +++++++++++++++++-
> drivers/pci/controller/cadence/pcie-cadence.h | 28 +-
> 2 files changed, 262 insertions(+), 17 deletions(-)
>
> diff --git a/drivers/pci/controller/cadence/pcie-cadence-host.c b/drivers/pci/controller/cadence/pcie-cadence-host.c
> index 8c2543f28ba0..f42a0acfce00 100644
> --- a/drivers/pci/controller/cadence/pcie-cadence-host.c
> +++ b/drivers/pci/controller/cadence/pcie-cadence-host.c

Hi Rob,

are you OK with this patch ? It was now made part of this series,
which I would like to pull if that's OK with you.

Thanks,
Lorenzo

> @@ -4,6 +4,7 @@
> // Author: Cyrille Pitchen <[email protected]>
>
> #include <linux/kernel.h>
> +#include <linux/list_sort.h>
> #include <linux/of_address.h>
> #include <linux/of_pci.h>
> #include <linux/platform_device.h>
> @@ -11,6 +12,17 @@
>
> #include "pcie-cadence.h"
>
> +static u64 bar_max_size[] = {
> + [RP_BAR0] = _ULL(128 * SZ_2G),
> + [RP_BAR1] = SZ_2G,
> + [RP_NO_BAR] = _BITULL(63),
> +};
> +
> +static u8 bar_aperture_mask[] = {
> + [RP_BAR0] = 0x1F,
> + [RP_BAR1] = 0xF,
> +};
> +
> static void __iomem *cdns_pci_map_bus(struct pci_bus *bus, unsigned int devfn,
> int where)
> {
> @@ -101,6 +113,217 @@ static int cdns_pcie_host_init_root_port(struct cdns_pcie_rc *rc)
> return 0;
> }
>
> +static int cdns_pcie_host_bar_ib_config(struct cdns_pcie_rc *rc,
> + enum cdns_pcie_rp_bar bar,
> + u64 cpu_addr, u64 size,
> + unsigned long flags)
> +{
> + struct cdns_pcie *pcie = &rc->pcie;
> + u32 addr0, addr1, aperture, value;
> +
> + if (!rc->avail_ib_bar[bar])
> + return -EBUSY;
> +
> + rc->avail_ib_bar[bar] = false;
> +
> + aperture = ilog2(size);
> + addr0 = CDNS_PCIE_AT_IB_RP_BAR_ADDR0_NBITS(aperture) |
> + (lower_32_bits(cpu_addr) & GENMASK(31, 8));
> + addr1 = upper_32_bits(cpu_addr);
> + cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_RP_BAR_ADDR0(bar), addr0);
> + cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_RP_BAR_ADDR1(bar), addr1);
> +
> + if (bar == RP_NO_BAR)
> + return 0;
> +
> + value = cdns_pcie_readl(pcie, CDNS_PCIE_LM_RC_BAR_CFG);
> + value &= ~(LM_RC_BAR_CFG_CTRL_MEM_64BITS(bar) |
> + LM_RC_BAR_CFG_CTRL_PREF_MEM_64BITS(bar) |
> + LM_RC_BAR_CFG_CTRL_MEM_32BITS(bar) |
> + LM_RC_BAR_CFG_CTRL_PREF_MEM_32BITS(bar) |
> + LM_RC_BAR_CFG_APERTURE(bar, bar_aperture_mask[bar] + 2));
> + if (size + cpu_addr >= SZ_4G) {
> + if (!(flags & IORESOURCE_PREFETCH))
> + value |= LM_RC_BAR_CFG_CTRL_MEM_64BITS(bar);
> + value |= LM_RC_BAR_CFG_CTRL_PREF_MEM_64BITS(bar);
> + } else {
> + if (!(flags & IORESOURCE_PREFETCH))
> + value |= LM_RC_BAR_CFG_CTRL_MEM_32BITS(bar);
> + value |= LM_RC_BAR_CFG_CTRL_PREF_MEM_32BITS(bar);
> + }
> +
> + value |= LM_RC_BAR_CFG_APERTURE(bar, aperture);
> + cdns_pcie_writel(pcie, CDNS_PCIE_LM_RC_BAR_CFG, value);
> +
> + return 0;
> +}
> +
> +static enum cdns_pcie_rp_bar
> +cdns_pcie_host_find_min_bar(struct cdns_pcie_rc *rc, u64 size)
> +{
> + enum cdns_pcie_rp_bar bar, sel_bar;
> +
> + sel_bar = RP_BAR_UNDEFINED;
> + for (bar = RP_BAR0; bar <= RP_NO_BAR; bar++) {
> + if (!rc->avail_ib_bar[bar])
> + continue;
> +
> + if (size <= bar_max_size[bar]) {
> + if (sel_bar == RP_BAR_UNDEFINED) {
> + sel_bar = bar;
> + continue;
> + }
> +
> + if (bar_max_size[bar] < bar_max_size[sel_bar])
> + sel_bar = bar;
> + }
> + }
> +
> + return sel_bar;
> +}
> +
> +static enum cdns_pcie_rp_bar
> +cdns_pcie_host_find_max_bar(struct cdns_pcie_rc *rc, u64 size)
> +{
> + enum cdns_pcie_rp_bar bar, sel_bar;
> +
> + sel_bar = RP_BAR_UNDEFINED;
> + for (bar = RP_BAR0; bar <= RP_NO_BAR; bar++) {
> + if (!rc->avail_ib_bar[bar])
> + continue;
> +
> + if (size >= bar_max_size[bar]) {
> + if (sel_bar == RP_BAR_UNDEFINED) {
> + sel_bar = bar;
> + continue;
> + }
> +
> + if (bar_max_size[bar] > bar_max_size[sel_bar])
> + sel_bar = bar;
> + }
> + }
> +
> + return sel_bar;
> +}
> +
> +static int cdns_pcie_host_bar_config(struct cdns_pcie_rc *rc,
> + struct resource_entry *entry)
> +{
> + u64 cpu_addr, pci_addr, size, winsize;
> + struct cdns_pcie *pcie = &rc->pcie;
> + struct device *dev = pcie->dev;
> + enum cdns_pcie_rp_bar bar;
> + unsigned long flags;
> + int ret;
> +
> + cpu_addr = entry->res->start;
> + pci_addr = entry->res->start - entry->offset;
> + flags = entry->res->flags;
> + size = resource_size(entry->res);
> +
> + if (entry->offset) {
> + dev_err(dev, "PCI addr: %llx must be equal to CPU addr: %llx\n",
> + pci_addr, cpu_addr);
> + return -EINVAL;
> + }
> +
> + while (size > 0) {
> + /*
> + * Try to find a minimum BAR whose size is greater than
> + * or equal to the remaining resource_entry size. This will
> + * fail if the size of each of the available BARs is less than
> + * the remaining resource_entry size.
> + * If a minimum BAR is found, IB ATU will be configured and
> + * exited.
> + */
> + bar = cdns_pcie_host_find_min_bar(rc, size);
> + if (bar != RP_BAR_UNDEFINED) {
> + ret = cdns_pcie_host_bar_ib_config(rc, bar, cpu_addr,
> + size, flags);
> + if (ret)
> + dev_err(dev, "IB BAR: %d config failed\n", bar);
> + return ret;
> + }
> +
> + /*
> + * If the control reaches here, it would mean the remaining
> + * resource_entry size cannot be fitted in a single BAR. So we
> + * find a maximum BAR whose size is less than or equal to the
> + * remaining resource_entry size and split the resource entry
> + * so that part of resource entry is fitted inside the maximum
> + * BAR. The remaining size would be fitted during the next
> + * iteration of the loop.
> + * If a maximum BAR is not found, there is no way we can fit
> + * this resource_entry, so we error out.
> + */
> + bar = cdns_pcie_host_find_max_bar(rc, size);
> + if (bar == RP_BAR_UNDEFINED) {
> + dev_err(dev, "No free BAR to map cpu_addr %llx\n",
> + cpu_addr);
> + return -EINVAL;
> + }
> +
> + winsize = bar_max_size[bar];
> + ret = cdns_pcie_host_bar_ib_config(rc, bar, cpu_addr, winsize,
> + flags);
> + if (ret) {
> + dev_err(dev, "IB BAR: %d config failed\n", bar);
> + return ret;
> + }
> +
> + size -= winsize;
> + cpu_addr += winsize;
> + }
> +
> + return 0;
> +}
> +
> +static int cdns_pcie_host_dma_ranges_cmp(void *priv, struct list_head *a, struct list_head *b)
> +{
> + struct resource_entry *entry1, *entry2;
> +
> + entry1 = container_of(a, struct resource_entry, node);
> + entry2 = container_of(b, struct resource_entry, node);
> +
> + return resource_size(entry2->res) - resource_size(entry1->res);
> +}
> +
> +static int cdns_pcie_host_map_dma_ranges(struct cdns_pcie_rc *rc)
> +{
> + struct cdns_pcie *pcie = &rc->pcie;
> + struct device *dev = pcie->dev;
> + struct device_node *np = dev->of_node;
> + struct pci_host_bridge *bridge;
> + struct resource_entry *entry;
> + u32 no_bar_nbits = 32;
> + int err;
> +
> + bridge = pci_host_bridge_from_priv(rc);
> + if (!bridge)
> + return -ENOMEM;
> +
> + if (list_empty(&bridge->dma_ranges)) {
> + of_property_read_u32(np, "cdns,no-bar-match-nbits",
> + &no_bar_nbits);
> + err = cdns_pcie_host_bar_ib_config(rc, RP_NO_BAR, 0x0,
> + (u64)1 << no_bar_nbits, 0);
> + if (err)
> + dev_err(dev, "IB BAR: %d config failed\n", RP_NO_BAR);
> + return err;
> + }
> +
> + list_sort(NULL, &bridge->dma_ranges, cdns_pcie_host_dma_ranges_cmp);
> +
> + resource_list_for_each_entry(entry, &bridge->dma_ranges) {
> + err = cdns_pcie_host_bar_config(rc, entry);
> + if (err)
> + dev_err(dev, "Fail to configure IB using dma-ranges\n");
> + return err;
> + }
> +
> + return 0;
> +}
> +
> static int cdns_pcie_host_init_address_translation(struct cdns_pcie_rc *rc)
> {
> struct cdns_pcie *pcie = &rc->pcie;
> @@ -154,16 +377,9 @@ static int cdns_pcie_host_init_address_translation(struct cdns_pcie_rc *rc)
> r++;
> }
>
> - /*
> - * Set Root Port no BAR match Inbound Translation registers:
> - * needed for MSI and DMA.
> - * Root Port BAR0 and BAR1 are disabled, hence no need to set their
> - * inbound translation registers.
> - */
> - addr0 = CDNS_PCIE_AT_IB_RP_BAR_ADDR0_NBITS(rc->no_bar_nbits);
> - addr1 = 0;
> - cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_RP_BAR_ADDR0(RP_NO_BAR), addr0);
> - cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_RP_BAR_ADDR1(RP_NO_BAR), addr1);
> + err = cdns_pcie_host_map_dma_ranges(rc);
> + if (err)
> + return err;
>
> return 0;
> }
> @@ -173,10 +389,16 @@ static int cdns_pcie_host_init(struct device *dev,
> struct cdns_pcie_rc *rc)
> {
> struct resource *bus_range = NULL;
> + struct pci_host_bridge *bridge;
> int err;
>
> + bridge = pci_host_bridge_from_priv(rc);
> + if (!bridge)
> + return -ENOMEM;
> +
> /* Parse our PCI ranges and request their resources */
> - err = pci_parse_request_of_pci_ranges(dev, resources, NULL, &bus_range);
> + err = pci_parse_request_of_pci_ranges(dev, resources,
> + &bridge->dma_ranges, &bus_range);
> if (err)
> return err;
>
> @@ -205,6 +427,7 @@ int cdns_pcie_host_setup(struct cdns_pcie_rc *rc)
> struct device_node *np = dev->of_node;
> struct pci_host_bridge *bridge;
> struct list_head resources;
> + enum cdns_pcie_rp_bar bar;
> struct cdns_pcie *pcie;
> struct resource *res;
> int ret;
> @@ -216,9 +439,6 @@ int cdns_pcie_host_setup(struct cdns_pcie_rc *rc)
> pcie = &rc->pcie;
> pcie->is_rc = true;
>
> - rc->no_bar_nbits = 32;
> - of_property_read_u32(np, "cdns,no-bar-match-nbits", &rc->no_bar_nbits);
> -
> rc->vendor_id = 0xffff;
> of_property_read_u32(np, "vendor-id", &rc->vendor_id);
>
> @@ -248,6 +468,9 @@ int cdns_pcie_host_setup(struct cdns_pcie_rc *rc)
>
> pcie->mem_res = res;
>
> + for (bar = RP_BAR0; bar <= RP_NO_BAR; bar++)
> + rc->avail_ib_bar[bar] = true;
> +
> ret = cdns_pcie_host_init(dev, &resources, rc);
> if (ret)
> goto err_init;
> diff --git a/drivers/pci/controller/cadence/pcie-cadence.h b/drivers/pci/controller/cadence/pcie-cadence.h
> index df14ad002fe9..bc49c22e48a9 100644
> --- a/drivers/pci/controller/cadence/pcie-cadence.h
> +++ b/drivers/pci/controller/cadence/pcie-cadence.h
> @@ -87,6 +87,20 @@
> #define CDNS_PCIE_LM_BAR_CFG_CTRL_MEM_64BITS 0x6
> #define CDNS_PCIE_LM_BAR_CFG_CTRL_PREFETCH_MEM_64BITS 0x7
>
> +#define LM_RC_BAR_CFG_CTRL_DISABLED(bar) \
> + (CDNS_PCIE_LM_BAR_CFG_CTRL_DISABLED << (((bar) * 8) + 6))
> +#define LM_RC_BAR_CFG_CTRL_IO_32BITS(bar) \
> + (CDNS_PCIE_LM_BAR_CFG_CTRL_IO_32BITS << (((bar) * 8) + 6))
> +#define LM_RC_BAR_CFG_CTRL_MEM_32BITS(bar) \
> + (CDNS_PCIE_LM_BAR_CFG_CTRL_MEM_32BITS << (((bar) * 8) + 6))
> +#define LM_RC_BAR_CFG_CTRL_PREF_MEM_32BITS(bar) \
> + (CDNS_PCIE_LM_BAR_CFG_CTRL_PREFETCH_MEM_32BITS << (((bar) * 8) + 6))
> +#define LM_RC_BAR_CFG_CTRL_MEM_64BITS(bar) \
> + (CDNS_PCIE_LM_BAR_CFG_CTRL_MEM_64BITS << (((bar) * 8) + 6))
> +#define LM_RC_BAR_CFG_CTRL_PREF_MEM_64BITS(bar) \
> + (CDNS_PCIE_LM_BAR_CFG_CTRL_PREFETCH_MEM_64BITS << (((bar) * 8) + 6))
> +#define LM_RC_BAR_CFG_APERTURE(bar, aperture) \
> + (((aperture) - 2) << ((bar) * 8))
>
> /*
> * Endpoint Function Registers (PCI configuration space for endpoint functions)
> @@ -170,11 +184,19 @@
> #define CDNS_PCIE_AT_LINKDOWN (CDNS_PCIE_AT_BASE + 0x0824)
>
> enum cdns_pcie_rp_bar {
> + RP_BAR_UNDEFINED = -1,
> RP_BAR0,
> RP_BAR1,
> RP_NO_BAR
> };
>
> +#define CDNS_PCIE_RP_MAX_IB 0x3
> +
> +struct cdns_pcie_rp_ib_bar {
> + u64 size;
> + bool free;
> +};
> +
> /* Endpoint Function BAR Inbound PCIe to AXI Address Translation Register */
> #define CDNS_PCIE_AT_IB_EP_FUNC_BAR_ADDR0(fn, bar) \
> (CDNS_PCIE_AT_BASE + 0x0840 + (fn) * 0x0040 + (bar) * 0x0008)
> @@ -251,19 +273,19 @@ struct cdns_pcie {
> * @bus_range: first/last buses behind the PCIe host controller
> * @cfg_base: IO mapped window to access the PCI configuration space of a
> * single function at a time
> - * @no_bar_nbits: Number of bits to keep for inbound (PCIe -> CPU) address
> - * translation (nbits sets into the "no BAR match" register)
> * @vendor_id: PCI vendor ID
> * @device_id: PCI device ID
> + * @avail_ib_bar: Satus of RP_BAR0, RP_BAR1 and RP_NO_BAR if it's free or
> + * available
> */
> struct cdns_pcie_rc {
> struct cdns_pcie pcie;
> struct resource *cfg_res;
> struct resource *bus_range;
> void __iomem *cfg_base;
> - u32 no_bar_nbits;
> u32 vendor_id;
> u32 device_id;
> + bool avail_ib_bar[CDNS_PCIE_RP_MAX_IB];
> };
>
> /**
> --
> 2.17.1
>

2020-07-22 22:32:51

by Rob Herring

[permalink] [raw]
Subject: Re: [PATCH v8 01/15] PCI: cadence: Use "dma-ranges" instead of "cdns,no-bar-match-nbits" property

On Wed, Jul 22, 2020 at 5:03 AM Kishon Vijay Abraham I <[email protected]> wrote:
>
> Cadence PCIe core driver (host mode) uses "cdns,no-bar-match-nbits"
> property to configure the number of bits passed through from PCIe
> address to internal address in Inbound Address Translation register.
> This only used the NO MATCH BAR.
>
> However standard PCI dt-binding already defines "dma-ranges" to
> describe the address ranges accessible by PCIe controller. Add support
> in Cadence PCIe host driver to parse dma-ranges and configure the
> inbound regions for BAR0, BAR1 and NO MATCH BAR. Cadence IP specifies
> maximum size for BAR0 as 256GB, maximum size for BAR1 as 2 GB.
>
> This adds support to take the next biggest region in "dma-ranges" and
> find the smallest BAR that each of the regions fit in and if there is
> no BAR big enough to hold the region, split the region to see if it can
> be fitted using multiple BARs.
>
> "dma-ranges" of J721E will be
> dma-ranges = <0x02000000 0x0 0x0 0x0 0x0 0x10000 0x0>;
> Since there is no BAR which can hold 2^48 size, NO_MATCH_BAR will be
> used here.
>
> Legacy device tree binding compatibility is maintained by retaining
> support for "cdns,no-bar-match-nbits".
>
> Signed-off-by: Kishon Vijay Abraham I <[email protected]>
> ---
> Changes from [1]
> 1) Use list_sort() for sorting the address ranges by size
> 2) Clear CDNS_PCIE_LM_RC_BAR_CFG register before configuring them
>
> [1] -> http://lore.kernel.org/r/[email protected]
> .../controller/cadence/pcie-cadence-host.c | 251 +++++++++++++++++-
> drivers/pci/controller/cadence/pcie-cadence.h | 28 +-
> 2 files changed, 262 insertions(+), 17 deletions(-)

Reviewed-by: Rob Herring <[email protected]>

2020-07-23 10:03:41

by Lorenzo Pieralisi

[permalink] [raw]
Subject: Re: [PATCH v8 00/15] Add PCIe support to TI's J721E SoC

On Wed, Jul 22, 2020 at 04:33:02PM +0530, Kishon Vijay Abraham I wrote:
> TI's J721E SoC uses Cadence PCIe core to implement both RC mode
> and EP mode.
>
> The high level features are:
> *) Supports Legacy, MSI and MSI-X interrupt
> *) Supports upto GEN4 speed mode
> *) Supports SR-IOV
> *) Supports multiple physical function
> *) Ability to route all transactions via SMMU
>
> This patch series
> *) Add support in Cadence PCIe core to be used for TI's J721E SoC
> *) Add a driver for J721E PCIe wrapper
>
> v1 of the series can be found @ [1]
> v2 of the series can be found @ [2]
> v3 of the series can be found @ [5]
> v4 of the series can be found @ [6]
> v5 of the series can be found @ [7]
> v6 of the series can be found @ [8]
> v7 of the series can be found @ [9]
>
> Changes from v7:
> 1) Replaced WARN with pr_warn
> 2) Included support for "dma-ranges" property patch in this series [10]
>
> Changes from v6:
> 1) Fixed bot found errors running 'make dt_binding_check'
>
> Changes from v5:
> 1) Added Reviewed-by: for PATCH #6
> 2) Protect writes to PCI_STATUS with spin_lock during raising interrupts
> in EP mode to reduce the time between read and write of RMW.
>
> Changes from v4:
> 1) Added Reviewed-by: & Acked-by: tags from RobH
> 2) Removed un-used accessors for pcie-cadence.h and removed having ops
> for read/write accessors
> 3) Updated cdns,cdns-pcie-host.yaml to remove "mem" from reg
>
> Changes from v3:
> 1) Changed the order of files in MAINTAINTERS file to fix Joe's comments
> 2) Fixed indentation and added Reviewed-by: Rob Herring <[email protected]>
> 3) Cleaned up computing msix_tbl
> 4) Fixed RobH's comment on J721E driver
>
> Changes from v2:
> 1) Converting Cadence binding to YAML schema was done as a
> separate series [3] & [4]. [3] is merged and [4] is
> pending.
> 2) Included MSI-X support in this series
> 3) Added link down interrupt handling (only error message)
> 4) Rebased to latest 5.7-rc1
> 5) Adapted TI J721E binding to [3] & [4]
>
> Changes from v1:
> 1) Added DT schemas cdns-pcie-host.yaml, cdns-pcie-ep.yaml and
> cdns-pcie.yaml for Cadence PCIe core and included it in
> TI's PCIe DT schema.
> 2) Added cpu_addr_fixup() for Cadence Platform driver.
> 3) Fixed subject/description/renamed functions as commented by
> Andrew Murray.
>
> [1] -> http://lore.kernel.org/r/[email protected]
> [2] -> http://lore.kernel.org/r/[email protected]
> [3] -> http://lore.kernel.org/r/[email protected]
> [4] -> http://lore.kernel.org/r/[email protected]
> [5] -> http://lore.kernel.org/r/[email protected]
> [6] -> http://lore.kernel.org/r/[email protected]
> [7] -> http://lore.kernel.org/r/[email protected]
> [8] -> http://lore.kernel.org/r/[email protected]
> [9] -> http://lore.kernel.org/r/[email protected]
> [10] -> http://lore.kernel.org/r/[email protected]
>
> Alan Douglas (1):
> PCI: cadence: Add MSI-X support to Endpoint driver
>
> Kishon Vijay Abraham I (14):
> PCI: cadence: Use "dma-ranges" instead of "cdns,no-bar-match-nbits"
> property
> PCI: cadence: Fix cdns_pcie_{host|ep}_setup() error path
> linux/kernel.h: Add PTR_ALIGN_DOWN macro
> PCI: cadence: Convert all r/w accessors to perform only 32-bit
> accesses
> PCI: cadence: Add support to start link and verify link status
> PCI: cadence: Allow pci_host_bridge to have custom pci_ops
> dt-bindings: PCI: cadence: Remove "mem" from reg binding
> PCI: cadence: Add new *ops* for CPU addr fixup
> PCI: cadence: Fix updating Vendor ID and Subsystem Vendor ID register
> dt-bindings: PCI: Add host mode dt-bindings for TI's J721E SoC
> dt-bindings: PCI: Add EP mode dt-bindings for TI's J721E SoC
> PCI: j721e: Add TI J721E PCIe driver
> misc: pci_endpoint_test: Add J721E in pci_device_id table
> MAINTAINERS: Add Kishon Vijay Abraham I for TI J721E SoC PCIe
>
> .../bindings/pci/cdns,cdns-pcie-host.yaml | 8 +-
> .../bindings/pci/ti,j721e-pci-ep.yaml | 94 ++++
> .../bindings/pci/ti,j721e-pci-host.yaml | 113 ++++
> MAINTAINERS | 4 +-
> drivers/misc/pci_endpoint_test.c | 9 +
> drivers/pci/controller/cadence/Kconfig | 23 +
> drivers/pci/controller/cadence/Makefile | 1 +
> drivers/pci/controller/cadence/pci-j721e.c | 493 ++++++++++++++++++
> .../pci/controller/cadence/pcie-cadence-ep.c | 129 ++++-
> .../controller/cadence/pcie-cadence-host.c | 310 +++++++++--
> .../controller/cadence/pcie-cadence-plat.c | 13 +
> drivers/pci/controller/cadence/pcie-cadence.c | 8 +-
> drivers/pci/controller/cadence/pcie-cadence.h | 161 +++++-
> include/linux/kernel.h | 1 +
> 14 files changed, 1297 insertions(+), 70 deletions(-)
> create mode 100644 Documentation/devicetree/bindings/pci/ti,j721e-pci-ep.yaml
> create mode 100644 Documentation/devicetree/bindings/pci/ti,j721e-pci-host.yaml
> create mode 100644 drivers/pci/controller/cadence/pci-j721e.c

Applied to pci/cadence for v5.9, thanks !

Lorenzo

2020-07-23 10:13:34

by Kishon Vijay Abraham I

[permalink] [raw]
Subject: Re: [PATCH v8 00/15] Add PCIe support to TI's J721E SoC



On 7/23/2020 3:32 PM, Lorenzo Pieralisi wrote:
> On Wed, Jul 22, 2020 at 04:33:02PM +0530, Kishon Vijay Abraham I wrote:
>> TI's J721E SoC uses Cadence PCIe core to implement both RC mode
>> and EP mode.
>>
>> The high level features are:
>> *) Supports Legacy, MSI and MSI-X interrupt
>> *) Supports upto GEN4 speed mode
>> *) Supports SR-IOV
>> *) Supports multiple physical function
>> *) Ability to route all transactions via SMMU
>>
>> This patch series
>> *) Add support in Cadence PCIe core to be used for TI's J721E SoC
>> *) Add a driver for J721E PCIe wrapper
>>
>> v1 of the series can be found @ [1]
>> v2 of the series can be found @ [2]
>> v3 of the series can be found @ [5]
>> v4 of the series can be found @ [6]
>> v5 of the series can be found @ [7]
>> v6 of the series can be found @ [8]
>> v7 of the series can be found @ [9]
>>
>> Changes from v7:
>> 1) Replaced WARN with pr_warn
>> 2) Included support for "dma-ranges" property patch in this series [10]
>>
>> Changes from v6:
>> 1) Fixed bot found errors running 'make dt_binding_check'
>>
>> Changes from v5:
>> 1) Added Reviewed-by: for PATCH #6
>> 2) Protect writes to PCI_STATUS with spin_lock during raising interrupts
>> in EP mode to reduce the time between read and write of RMW.
>>
>> Changes from v4:
>> 1) Added Reviewed-by: & Acked-by: tags from RobH
>> 2) Removed un-used accessors for pcie-cadence.h and removed having ops
>> for read/write accessors
>> 3) Updated cdns,cdns-pcie-host.yaml to remove "mem" from reg
>>
>> Changes from v3:
>> 1) Changed the order of files in MAINTAINTERS file to fix Joe's comments
>> 2) Fixed indentation and added Reviewed-by: Rob Herring <[email protected]>
>> 3) Cleaned up computing msix_tbl
>> 4) Fixed RobH's comment on J721E driver
>>
>> Changes from v2:
>> 1) Converting Cadence binding to YAML schema was done as a
>> separate series [3] & [4]. [3] is merged and [4] is
>> pending.
>> 2) Included MSI-X support in this series
>> 3) Added link down interrupt handling (only error message)
>> 4) Rebased to latest 5.7-rc1
>> 5) Adapted TI J721E binding to [3] & [4]
>>
>> Changes from v1:
>> 1) Added DT schemas cdns-pcie-host.yaml, cdns-pcie-ep.yaml and
>> cdns-pcie.yaml for Cadence PCIe core and included it in
>> TI's PCIe DT schema.
>> 2) Added cpu_addr_fixup() for Cadence Platform driver.
>> 3) Fixed subject/description/renamed functions as commented by
>> Andrew Murray.
>>
>> [1] -> http://lore.kernel.org/r/[email protected]
>> [2] -> http://lore.kernel.org/r/[email protected]
>> [3] -> http://lore.kernel.org/r/[email protected]
>> [4] -> http://lore.kernel.org/r/[email protected]
>> [5] -> http://lore.kernel.org/r/[email protected]
>> [6] -> http://lore.kernel.org/r/[email protected]
>> [7] -> http://lore.kernel.org/r/[email protected]
>> [8] -> http://lore.kernel.org/r/[email protected]
>> [9] -> http://lore.kernel.org/r/[email protected]
>> [10] -> http://lore.kernel.org/r/[email protected]
>>
>> Alan Douglas (1):
>> PCI: cadence: Add MSI-X support to Endpoint driver
>>
>> Kishon Vijay Abraham I (14):
>> PCI: cadence: Use "dma-ranges" instead of "cdns,no-bar-match-nbits"
>> property
>> PCI: cadence: Fix cdns_pcie_{host|ep}_setup() error path
>> linux/kernel.h: Add PTR_ALIGN_DOWN macro
>> PCI: cadence: Convert all r/w accessors to perform only 32-bit
>> accesses
>> PCI: cadence: Add support to start link and verify link status
>> PCI: cadence: Allow pci_host_bridge to have custom pci_ops
>> dt-bindings: PCI: cadence: Remove "mem" from reg binding
>> PCI: cadence: Add new *ops* for CPU addr fixup
>> PCI: cadence: Fix updating Vendor ID and Subsystem Vendor ID register
>> dt-bindings: PCI: Add host mode dt-bindings for TI's J721E SoC
>> dt-bindings: PCI: Add EP mode dt-bindings for TI's J721E SoC
>> PCI: j721e: Add TI J721E PCIe driver
>> misc: pci_endpoint_test: Add J721E in pci_device_id table
>> MAINTAINERS: Add Kishon Vijay Abraham I for TI J721E SoC PCIe
>>
>> .../bindings/pci/cdns,cdns-pcie-host.yaml | 8 +-
>> .../bindings/pci/ti,j721e-pci-ep.yaml | 94 ++++
>> .../bindings/pci/ti,j721e-pci-host.yaml | 113 ++++
>> MAINTAINERS | 4 +-
>> drivers/misc/pci_endpoint_test.c | 9 +
>> drivers/pci/controller/cadence/Kconfig | 23 +
>> drivers/pci/controller/cadence/Makefile | 1 +
>> drivers/pci/controller/cadence/pci-j721e.c | 493 ++++++++++++++++++
>> .../pci/controller/cadence/pcie-cadence-ep.c | 129 ++++-
>> .../controller/cadence/pcie-cadence-host.c | 310 +++++++++--
>> .../controller/cadence/pcie-cadence-plat.c | 13 +
>> drivers/pci/controller/cadence/pcie-cadence.c | 8 +-
>> drivers/pci/controller/cadence/pcie-cadence.h | 161 +++++-
>> include/linux/kernel.h | 1 +
>> 14 files changed, 1297 insertions(+), 70 deletions(-)
>> create mode 100644 Documentation/devicetree/bindings/pci/ti,j721e-pci-ep.yaml
>> create mode 100644 Documentation/devicetree/bindings/pci/ti,j721e-pci-host.yaml
>> create mode 100644 drivers/pci/controller/cadence/pci-j721e.c
>
> Applied to pci/cadence for v5.9, thanks !

Thank you Lorenzo!

Regards
Kishon