* [PATCH v3 0/6] PCI: Add support to the Cadence PCIe controller
@ 2018-01-10 22:47 Cyrille Pitchen
2018-01-10 22:47 ` [PATCH v3 1/6] PCI: Regroup all PCI related entries into drivers/pci/Makefile Cyrille Pitchen
` (5 more replies)
0 siblings, 6 replies; 14+ messages in thread
From: Cyrille Pitchen @ 2018-01-10 22:47 UTC (permalink / raw)
To: bhelgaas, kishon, lorenzo.pieralisi, linux-pci
Cc: adouglas, stelford, dgary, kgopi, eandrews, thomas.petazzoni,
sureshp, nsekhar, linux-kernel, robh, devicetree,
Cyrille Pitchen
Hi all,
this series of patches adds support to the Cadence PCIe controller.
It was tested on a ARM64 platform emulated by a Palladium running the
pci-next kernel.
The host mode was tested with some PCIe devices connected to the Palladium
through a speed-bridge. Some of those devices were a USB host controller
and a SATA controller. The PCIe host controller was also tested with a
second controller configured in endpoint mode and connected back to back
to the first controller.
The EndPoint Controller (EPC) driver was removed only because I didn't
have time to take all Kishon's comments into account. However, using a
fixed patch based on patch 7 of the v2 series + another patch fixing
the EPF device name chosen by pci_epf_make(), I was abled to probe
both function 0 and function 1 of the of the 2nd Cadence PCIe controller
configured in endpoint mode (new hardware design since v2 so function 1
is now available).
Currently I'm facing 2 issues, which I didn't have enough time to
investigate and to fix yet:
1 - when the vendor:device IDs are set to 104c:b500 for both functions,
then I remove both devfn (echo 1 > /sys/bus/pci/devices/$BDF/remove)
before scanning the PCI bus again (echo 1 > /sys/bus/pci/rescan),
the PCI enumeration fails reporting that the PCI memory is exhausted.
2 - when I set the vendor:device IDs to 104c:0100 for function 0 and
104c:b500 and remove only function 1 before scanning the PCI bus again,
I now pass the PCI enumeration. I also pass the 'pcitest -b <BAR>' test
but I fail on the MSI test ('pcitest -m <MSI>').
I'm still investigating on those issues.
Best regards,
Cyrille
ChangeLog
v2 -> v3:
- rebase on today's linux-pci/next (20180110)
patch1:
- rework the commit message of patch 1 and add two new comments on why endpoint
library users must be linked after the endpoint library itself and why
the dwc rule uses obj-y instead of obj-$(CONFIG_PCIE_CONFIG_DW).
- update patch 1 to add missing ifdef CONFIG_PCI / endif in
drivers/pci/dwc/Makefile around the obj-$(CONFIG_ARM64) += pcie-hisi.o rule,
like for the other obj-$(CONFIG_ARM64) rules in drivers/pci/host/Makefile.
patch2: unchanged
patch3:
- update patch 3 so the bridge hooks/members initialization is left to the
host bridges probe routines.
patch4: unchanged
patch5:
- collect 'Reviewed-by' tag from Rob Herring for the DT bindings.
patch6:
- remove explanation in the commit message on why obj-$(CONFIG_PCIE_CANDENCE) is
placed after obj-$(CONFIG_PCI_ENDPOINT) in drivers/pci/Makefile since a
comment on it has been added into patch1.
- remove menuconfig PCI_CADENCE in drivers/pci/cadence/Kconfig to match
drivers/pci/dwc/Kconfig.
- adapt patch6 to the changes done in patch3 for the pci_host_probe() function.
v1 -> v2:
- add new properties in the device-tree bindings: 'cdns,max-outbound-regions'
and 'cdns,no-bar-match-nbits'.
- add a new patch to regroup all makefile rules in drivers/pci/Makefile, hence
cleaning drivers/Makefile up.
- change the license text to use the recommanded format:
// SPDX-License-Identifier: GPL-2.0
- add a new patch updating the API of the EPC library to add support to
multi-function devices.
- add a 2 new patches to share more common code between host controller drivers
- remove some useless tests
- add more comments in both drivers.
- fix DT bindings examples
- remove useless init of the primary, secondary and sub-ordinate bus numbers in
the PCI configuration space of the root port.
- remove cdns_pcie_ep_stop() function and rework cdns_pcie_ep_start() function
Cyrille Pitchen (5):
PCI: Regroup all PCI related entries into drivers/pci/Makefile
PCI: OF: Add generic function to parse and allocate PCI resources
PCI: Add generic function to probe PCI host controllers
PCI: Add vendor ID for Cadence
PCI: cadence: Add host driver for Cadence PCIe controller
Scott Telford (1):
dt-bindings: PCI: cadence: Add DT bindings for Cadence PCIe host
controller
.../bindings/pci/cdns,cdns-pcie-host.txt | 60 ++++
MAINTAINERS | 7 +
drivers/Makefile | 5 +-
drivers/pci/Kconfig | 2 +
drivers/pci/Makefile | 14 +-
drivers/pci/cadence/Kconfig | 16 +
drivers/pci/cadence/Makefile | 3 +
drivers/pci/cadence/pcie-cadence-host.c | 336 +++++++++++++++++++++
drivers/pci/cadence/pcie-cadence.c | 68 +++++
drivers/pci/cadence/pcie-cadence.h | 196 ++++++++++++
drivers/pci/dwc/Makefile | 2 +
drivers/pci/host/Makefile | 2 +
drivers/pci/host/pci-host-common.c | 74 +----
drivers/pci/of.c | 51 ++++
drivers/pci/probe.c | 33 ++
include/linux/pci.h | 10 +
include/linux/pci_ids.h | 2 +
17 files changed, 805 insertions(+), 76 deletions(-)
create mode 100644 Documentation/devicetree/bindings/pci/cdns,cdns-pcie-host.txt
create mode 100644 drivers/pci/cadence/Kconfig
create mode 100644 drivers/pci/cadence/Makefile
create mode 100644 drivers/pci/cadence/pcie-cadence-host.c
create mode 100644 drivers/pci/cadence/pcie-cadence.c
create mode 100644 drivers/pci/cadence/pcie-cadence.h
--
2.11.0
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v3 1/6] PCI: Regroup all PCI related entries into drivers/pci/Makefile
2018-01-10 22:47 [PATCH v3 0/6] PCI: Add support to the Cadence PCIe controller Cyrille Pitchen
@ 2018-01-10 22:47 ` Cyrille Pitchen
[not found] ` <cover.1515621150.git.cyrille.pitchen-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
` (4 subsequent siblings)
5 siblings, 0 replies; 14+ messages in thread
From: Cyrille Pitchen @ 2018-01-10 22:47 UTC (permalink / raw)
To: bhelgaas, kishon, lorenzo.pieralisi, linux-pci
Cc: adouglas, stelford, dgary, kgopi, eandrews, thomas.petazzoni,
sureshp, nsekhar, linux-kernel, robh, devicetree,
Cyrille Pitchen
Clean up drivers/Makefile by moving the pci/endpoint and pci/dwc entries
from drivers/Makefile into drivers/pci/Makefile.
Since we don't want to introduce any dependency between CONFIG_PCI and
CONFIG_PCI_ENDPOINT, we now always execute drivers/pci/Makefile.
Hence all Makefiles in drivers/pci/ were updated accordingly so no file is
compiled when CONFIG_PCI is not defined.
Also, we add a comment to reinforce that EPC and EPF libraries must be
initialized before their users. Hence built-in EPC drivers, such as
those of Designware, are linked after the endpoint core libraries.
Finally, we add another comment to explain why obj-y has been chosen
instead of obj-$(CONFIG_PCIE_DW) to parse the dwc/ sub-folder.
Signed-off-by: Cyrille Pitchen <cyrille.pitchen@free-electrons.com>
---
drivers/Makefile | 5 +----
drivers/pci/Kconfig | 1 +
drivers/pci/Makefile | 13 ++++++++++---
drivers/pci/dwc/Makefile | 2 ++
drivers/pci/host/Makefile | 2 ++
5 files changed, 16 insertions(+), 7 deletions(-)
diff --git a/drivers/Makefile b/drivers/Makefile
index e06f7f633f73..8189b1edec00 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -16,10 +16,7 @@ obj-$(CONFIG_PINCTRL) += pinctrl/
obj-$(CONFIG_GPIOLIB) += gpio/
obj-y += pwm/
-obj-$(CONFIG_PCI) += pci/
-obj-$(CONFIG_PCI_ENDPOINT) += pci/endpoint/
-# PCI dwc controller drivers
-obj-y += pci/dwc/
+obj-y += pci/
obj-$(CONFIG_PARISC) += parisc/
obj-$(CONFIG_RAPIDIO) += rapidio/
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
index bda151788f3f..7eeb969ab86a 100644
--- a/drivers/pci/Kconfig
+++ b/drivers/pci/Kconfig
@@ -125,6 +125,7 @@ config PCI_PASID
config PCI_LABEL
def_bool y if (DMI || ACPI)
+ depends on PCI
select NLS
config PCI_HYPERV
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
index c7819b973df7..ddb5aa6640d7 100644
--- a/drivers/pci/Makefile
+++ b/drivers/pci/Makefile
@@ -3,12 +3,15 @@
# Makefile for the PCI bus specific drivers.
#
-obj-y += access.o bus.o probe.o host-bridge.o remove.o pci.o \
+obj-$(CONFIG_PCI) += access.o bus.o probe.o host-bridge.o remove.o pci.o \
pci-driver.o search.o pci-sysfs.o rom.o setup-res.o \
irq.o vpd.o setup-bus.o vc.o mmap.o setup-irq.o
+ifdef CONFIG_PCI
obj-$(CONFIG_PROC_FS) += proc.o
obj-$(CONFIG_SYSFS) += slot.o
+obj-$(CONFIG_OF) += of.o
+endif
obj-$(CONFIG_PCI_QUIRKS) += quirks.o
@@ -44,10 +47,14 @@ obj-$(CONFIG_PCI_ECAM) += ecam.o
obj-$(CONFIG_XEN_PCIDEV_FRONTEND) += xen-pcifront.o
-obj-$(CONFIG_OF) += of.o
-
ccflags-$(CONFIG_PCI_DEBUG) := -DDEBUG
# PCI host controller drivers
obj-y += host/
obj-y += switch/
+
+obj-$(CONFIG_PCI_ENDPOINT) += endpoint/
+
+# Endpoint library must be initialized before its users
+# pcie-hisi.o quirks are needed even without CONFIG_PCIE_DW
+obj-y += dwc/
diff --git a/drivers/pci/dwc/Makefile b/drivers/pci/dwc/Makefile
index a9d8a6fb48e3..5d2ce72c7a52 100644
--- a/drivers/pci/dwc/Makefile
+++ b/drivers/pci/dwc/Makefile
@@ -25,4 +25,6 @@ obj-$(CONFIG_PCIE_HISI_STB) += pcie-histb.o
# ARM64 and use internal ifdefs to only build the pieces we need
# depending on whether ACPI, the DT driver, or both are enabled.
+ifdef CONFIG_PCI
obj-$(CONFIG_ARM64) += pcie-hisi.o
+endif
diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile
index 34ec1d88f961..3b1059190867 100644
--- a/drivers/pci/host/Makefile
+++ b/drivers/pci/host/Makefile
@@ -34,6 +34,8 @@ obj-$(CONFIG_VMD) += vmd.o
# ARM64 and use internal ifdefs to only build the pieces we need
# depending on whether ACPI, the DT driver, or both are enabled.
+ifdef CONFIG_PCI
obj-$(CONFIG_ARM64) += pci-thunder-ecam.o
obj-$(CONFIG_ARM64) += pci-thunder-pem.o
obj-$(CONFIG_ARM64) += pci-xgene.o
+endif
--
2.11.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v3 2/6] PCI: OF: Add generic function to parse and allocate PCI resources
[not found] ` <cover.1515621150.git.cyrille.pitchen-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
@ 2018-01-10 22:47 ` Cyrille Pitchen
0 siblings, 0 replies; 14+ messages in thread
From: Cyrille Pitchen @ 2018-01-10 22:47 UTC (permalink / raw)
To: bhelgaas-hpIqsD4AKlfQT0dZR+AlfA, kishon-l0cyMroinI0,
lorenzo.pieralisi-5wv7dgnIgG8, linux-pci-u79uwXL29TY76Z2rM5mHXA
Cc: adouglas-vna1KIf7WgpBDgjK7y7TUQ, stelford-vna1KIf7WgpBDgjK7y7TUQ,
dgary-vna1KIf7WgpBDgjK7y7TUQ, kgopi-vna1KIf7WgpBDgjK7y7TUQ,
eandrews-vna1KIf7WgpBDgjK7y7TUQ,
thomas.petazzoni-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
sureshp-vna1KIf7WgpBDgjK7y7TUQ, nsekhar-l0cyMroinI0,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, robh-DgEjT+Ai2ygdnm+yROfE0A,
devicetree-u79uwXL29TY76Z2rM5mHXA, Cyrille Pitchen
The patch moves the gen_pci_parse_request_of_pci_ranges() function from
drivers/pci/host/pci-host-common.c into drivers/pci/of.c to easily share
common source code between PCI host drivers.
Signed-off-by: Cyrille Pitchen <cyrille.pitchen-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
---
drivers/pci/host/pci-host-common.c | 49 ++----------------------------------
drivers/pci/of.c | 51 ++++++++++++++++++++++++++++++++++++++
include/linux/pci.h | 9 +++++++
3 files changed, 62 insertions(+), 47 deletions(-)
diff --git a/drivers/pci/host/pci-host-common.c b/drivers/pci/host/pci-host-common.c
index c4b891c84703..a613ea310e76 100644
--- a/drivers/pci/host/pci-host-common.c
+++ b/drivers/pci/host/pci-host-common.c
@@ -24,50 +24,6 @@
#include <linux/pci-ecam.h>
#include <linux/platform_device.h>
-static int gen_pci_parse_request_of_pci_ranges(struct device *dev,
- struct list_head *resources, struct resource **bus_range)
-{
- int err, res_valid = 0;
- struct device_node *np = dev->of_node;
- resource_size_t iobase;
- struct resource_entry *win, *tmp;
-
- err = of_pci_get_host_bridge_resources(np, 0, 0xff, resources, &iobase);
- if (err)
- return err;
-
- err = devm_request_pci_bus_resources(dev, resources);
- if (err)
- return err;
-
- resource_list_for_each_entry_safe(win, tmp, resources) {
- struct resource *res = win->res;
-
- switch (resource_type(res)) {
- case IORESOURCE_IO:
- err = pci_remap_iospace(res, iobase);
- if (err) {
- dev_warn(dev, "error %d: failed to map resource %pR\n",
- err, res);
- resource_list_destroy_entry(win);
- }
- break;
- case IORESOURCE_MEM:
- res_valid |= !(res->flags & IORESOURCE_PREFETCH);
- break;
- case IORESOURCE_BUS:
- *bus_range = res;
- break;
- }
- }
-
- if (res_valid)
- return 0;
-
- dev_err(dev, "non-prefetchable memory resource required\n");
- return -EINVAL;
-}
-
static void gen_pci_unmap_cfg(void *ptr)
{
pci_ecam_free((struct pci_config_window *)ptr);
@@ -82,9 +38,9 @@ static struct pci_config_window *gen_pci_init(struct device *dev,
struct pci_config_window *cfg;
/* Parse our PCI ranges and request their resources */
- err = gen_pci_parse_request_of_pci_ranges(dev, resources, &bus_range);
+ err = pci_parse_request_of_pci_ranges(dev, resources, &bus_range);
if (err)
- goto err_out;
+ return ERR_PTR(err);
err = of_address_to_resource(dev->of_node, 0, &cfgres);
if (err) {
@@ -135,7 +91,6 @@ int pci_host_common_probe(struct platform_device *pdev,
of_pci_check_probe_only();
/* Parse and map our Configuration Space windows */
- INIT_LIST_HEAD(&resources);
cfg = gen_pci_init(dev, &resources, ops);
if (IS_ERR(cfg))
return PTR_ERR(cfg);
diff --git a/drivers/pci/of.c b/drivers/pci/of.c
index e112da11630e..54e210501b73 100644
--- a/drivers/pci/of.c
+++ b/drivers/pci/of.c
@@ -88,3 +88,54 @@ struct irq_domain *pci_host_bridge_of_msi_domain(struct pci_bus *bus)
return NULL;
#endif
}
+
+int pci_parse_request_of_pci_ranges(struct device *dev,
+ struct list_head *resources,
+ struct resource **bus_range)
+{
+ int err, res_valid = 0;
+ struct device_node *np = dev->of_node;
+ resource_size_t iobase;
+ struct resource_entry *win, *tmp;
+
+ INIT_LIST_HEAD(resources);
+ err = of_pci_get_host_bridge_resources(np, 0, 0xff, resources, &iobase);
+ if (err)
+ return err;
+
+ err = devm_request_pci_bus_resources(dev, resources);
+ if (err)
+ goto out_release_res;
+
+ resource_list_for_each_entry_safe(win, tmp, resources) {
+ struct resource *res = win->res;
+
+ switch (resource_type(res)) {
+ case IORESOURCE_IO:
+ err = pci_remap_iospace(res, iobase);
+ if (err) {
+ dev_warn(dev, "error %d: failed to map resource %pR\n",
+ err, res);
+ resource_list_destroy_entry(win);
+ }
+ break;
+ case IORESOURCE_MEM:
+ res_valid |= !(res->flags & IORESOURCE_PREFETCH);
+ break;
+ case IORESOURCE_BUS:
+ if (bus_range)
+ *bus_range = res;
+ break;
+ }
+ }
+
+ if (res_valid)
+ return 0;
+
+ dev_err(dev, "non-prefetchable memory resource required\n");
+ err = -EINVAL;
+
+ out_release_res:
+ pci_free_resource_list(resources);
+ return err;
+}
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 978aad7841e5..a1b0672fd38a 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -2163,6 +2163,9 @@ void pci_release_of_node(struct pci_dev *dev);
void pci_set_bus_of_node(struct pci_bus *bus);
void pci_release_bus_of_node(struct pci_bus *bus);
struct irq_domain *pci_host_bridge_of_msi_domain(struct pci_bus *bus);
+int pci_parse_request_of_pci_ranges(struct device *dev,
+ struct list_head *resources,
+ struct resource **bus_range);
/* Arch may override this (weak) */
struct device_node *pcibios_get_phb_of_node(struct pci_bus *bus);
@@ -2187,6 +2190,12 @@ static inline struct device_node *
pci_device_to_OF_node(const struct pci_dev *pdev) { return NULL; }
static inline struct irq_domain *
pci_host_bridge_of_msi_domain(struct pci_bus *bus) { return NULL; }
+static inline int pci_parse_request_of_pci_ranges(struct device *dev,
+ struct list_head *resources,
+ struct resource **bus_range)
+{
+ return -EINVAL;
+}
#endif /* CONFIG_OF */
#ifdef CONFIG_ACPI
--
2.11.0
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v3 3/6] PCI: Add generic function to probe PCI host controllers
2018-01-10 22:47 [PATCH v3 0/6] PCI: Add support to the Cadence PCIe controller Cyrille Pitchen
2018-01-10 22:47 ` [PATCH v3 1/6] PCI: Regroup all PCI related entries into drivers/pci/Makefile Cyrille Pitchen
[not found] ` <cover.1515621150.git.cyrille.pitchen-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
@ 2018-01-10 22:47 ` Cyrille Pitchen
2018-01-16 15:25 ` Lorenzo Pieralisi
2018-01-10 22:47 ` [PATCH v3 4/6] PCI: Add vendor ID for Cadence Cyrille Pitchen
` (2 subsequent siblings)
5 siblings, 1 reply; 14+ messages in thread
From: Cyrille Pitchen @ 2018-01-10 22:47 UTC (permalink / raw)
To: bhelgaas, kishon, lorenzo.pieralisi, linux-pci
Cc: adouglas, stelford, dgary, kgopi, eandrews, thomas.petazzoni,
sureshp, nsekhar, linux-kernel, robh, devicetree,
Cyrille Pitchen
This patchs moves generic source code from
drivers/pci/host/pci-host-common.c into drivers/pci/probe.c.
Indeed the extracted lines of code were duplicated by many host
controller drivers. Regrouping them into a generic function gives a
change to properly share this code without introducing a useless
dependency to PCI_HOST_COMMON, which selects PCI_ECAM when not needed by
most host controller drivers.
We also add a missing call of pci_free_resource_list() from
pci_host_common_probe() when probing fails, as done inside gen_pci_init()
when this later function fails.
Signed-off-by: Cyrille Pitchen <cyrille.pitchen@free-electrons.com>
---
drivers/pci/host/pci-host-common.c | 25 +++----------------------
drivers/pci/probe.c | 33 +++++++++++++++++++++++++++++++++
include/linux/pci.h | 1 +
3 files changed, 37 insertions(+), 22 deletions(-)
diff --git a/drivers/pci/host/pci-host-common.c b/drivers/pci/host/pci-host-common.c
index a613ea310e76..df25b4a4edaf 100644
--- a/drivers/pci/host/pci-host-common.c
+++ b/drivers/pci/host/pci-host-common.c
@@ -72,7 +72,6 @@ int pci_host_common_probe(struct platform_device *pdev,
const char *type;
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
- struct pci_bus *bus, *child;
struct pci_host_bridge *bridge;
struct pci_config_window *cfg;
struct list_head resources;
@@ -107,29 +106,11 @@ int pci_host_common_probe(struct platform_device *pdev,
bridge->map_irq = of_irq_parse_and_map_pci;
bridge->swizzle_irq = pci_common_swizzle;
- ret = pci_scan_root_bus_bridge(bridge);
- if (ret < 0) {
- dev_err(dev, "Scanning root bridge failed");
+ ret = pci_host_probe(bridge);
+ if (ret) {
+ pci_free_resource_list(&resources);
return ret;
}
- bus = bridge->bus;
-
- /*
- * We insert PCI resources into the iomem_resource and
- * ioport_resource trees in either pci_bus_claim_resources()
- * or pci_bus_assign_resources().
- */
- if (pci_has_flag(PCI_PROBE_ONLY)) {
- pci_bus_claim_resources(bus);
- } else {
- pci_bus_size_bridges(bus);
- pci_bus_assign_resources(bus);
-
- list_for_each_entry(child, &bus->children, node)
- pcie_bus_configure_settings(child);
- }
-
- pci_bus_add_devices(bus);
return 0;
}
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 1360db508035..178328d06a32 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -2685,6 +2685,39 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
}
EXPORT_SYMBOL_GPL(pci_create_root_bus);
+int pci_host_probe(struct pci_host_bridge *bridge)
+{
+ struct pci_bus *bus, *child;
+ int ret;
+
+ ret = pci_scan_root_bus_bridge(bridge);
+ if (ret < 0) {
+ dev_err(bridge->dev.parent, "Scanning root bridge failed");
+ return ret;
+ }
+
+ bus = bridge->bus;
+
+ /*
+ * We insert PCI resources into the iomem_resource and
+ * ioport_resource trees in either pci_bus_claim_resources()
+ * or pci_bus_assign_resources().
+ */
+ if (pci_has_flag(PCI_PROBE_ONLY)) {
+ pci_bus_claim_resources(bus);
+ } else {
+ pci_bus_size_bridges(bus);
+ pci_bus_assign_resources(bus);
+
+ list_for_each_entry(child, &bus->children, node)
+ pcie_bus_configure_settings(child);
+ }
+
+ pci_bus_add_devices(bus);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(pci_host_probe);
+
int pci_bus_insert_busn_res(struct pci_bus *b, int bus, int bus_max)
{
struct resource *res = &b->busn_res;
diff --git a/include/linux/pci.h b/include/linux/pci.h
index a1b0672fd38a..0ca261fda900 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -879,6 +879,7 @@ struct pci_bus *pci_scan_bus(int bus, struct pci_ops *ops, void *sysdata);
struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
struct pci_ops *ops, void *sysdata,
struct list_head *resources);
+int pci_host_probe(struct pci_host_bridge *bridge);
int pci_bus_insert_busn_res(struct pci_bus *b, int bus, int busmax);
int pci_bus_update_busn_res_end(struct pci_bus *b, int busmax);
void pci_bus_release_busn_res(struct pci_bus *b);
--
2.11.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v3 4/6] PCI: Add vendor ID for Cadence
2018-01-10 22:47 [PATCH v3 0/6] PCI: Add support to the Cadence PCIe controller Cyrille Pitchen
` (2 preceding siblings ...)
2018-01-10 22:47 ` [PATCH v3 3/6] PCI: Add generic function to probe PCI host controllers Cyrille Pitchen
@ 2018-01-10 22:47 ` Cyrille Pitchen
2018-01-10 22:47 ` [PATCH v3 5/6] dt-bindings: PCI: cadence: Add DT bindings for Cadence PCIe host controller Cyrille Pitchen
2018-01-10 22:47 ` [PATCH v3 6/6] PCI: cadence: Add host driver for Cadence PCIe controller Cyrille Pitchen
5 siblings, 0 replies; 14+ messages in thread
From: Cyrille Pitchen @ 2018-01-10 22:47 UTC (permalink / raw)
To: bhelgaas, kishon, lorenzo.pieralisi, linux-pci
Cc: adouglas, stelford, dgary, kgopi, eandrews, thomas.petazzoni,
sureshp, nsekhar, linux-kernel, robh, devicetree,
Cyrille Pitchen
This patch adds a new PCI vendor ID for Cadence.
Signed-off-by: Cyrille Pitchen <cyrille.pitchen@free-electrons.com>
---
include/linux/pci_ids.h | 2 ++
1 file changed, 2 insertions(+)
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index ab20dc5db423..eb13e84e1fef 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -2381,6 +2381,8 @@
#define PCI_VENDOR_ID_LENOVO 0x17aa
+#define PCI_VENDOR_ID_CDNS 0x17cd
+
#define PCI_VENDOR_ID_ARECA 0x17d3
#define PCI_DEVICE_ID_ARECA_1110 0x1110
#define PCI_DEVICE_ID_ARECA_1120 0x1120
--
2.11.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v3 5/6] dt-bindings: PCI: cadence: Add DT bindings for Cadence PCIe host controller
2018-01-10 22:47 [PATCH v3 0/6] PCI: Add support to the Cadence PCIe controller Cyrille Pitchen
` (3 preceding siblings ...)
2018-01-10 22:47 ` [PATCH v3 4/6] PCI: Add vendor ID for Cadence Cyrille Pitchen
@ 2018-01-10 22:47 ` Cyrille Pitchen
2018-01-10 22:47 ` [PATCH v3 6/6] PCI: cadence: Add host driver for Cadence PCIe controller Cyrille Pitchen
5 siblings, 0 replies; 14+ messages in thread
From: Cyrille Pitchen @ 2018-01-10 22:47 UTC (permalink / raw)
To: bhelgaas, kishon, lorenzo.pieralisi, linux-pci
Cc: adouglas, stelford, dgary, kgopi, eandrews, thomas.petazzoni,
sureshp, nsekhar, linux-kernel, robh, devicetree,
Cyrille Pitchen
From: Scott Telford <stelford@cadence.com>
This patch adds documentation for the DT bindings of the Cadence PCIe
controller when configured in host (Root Complex) mode.
Signed-off-by: Scott Telford <stelford@cadence.com>
Signed-off-by: Cyrille Pitchen <cyrille.pitchen@free-electrons.com>
Reviewed-by: Rob Herring <robh@kernel.org>
---
.../bindings/pci/cdns,cdns-pcie-host.txt | 60 ++++++++++++++++++++++
1 file changed, 60 insertions(+)
create mode 100644 Documentation/devicetree/bindings/pci/cdns,cdns-pcie-host.txt
diff --git a/Documentation/devicetree/bindings/pci/cdns,cdns-pcie-host.txt b/Documentation/devicetree/bindings/pci/cdns,cdns-pcie-host.txt
new file mode 100644
index 000000000000..20a33f38f69d
--- /dev/null
+++ b/Documentation/devicetree/bindings/pci/cdns,cdns-pcie-host.txt
@@ -0,0 +1,60 @@
+* Cadence PCIe host controller
+
+This PCIe controller inherits the base properties defined in
+host-generic-pci.txt.
+
+Required properties:
+- compatible: Should contain "cdns,cdns-pcie-host" to identify the IP used.
+- reg: Should contain the controller register base address, PCIe configuration
+ window base address, and AXI interface region base address respectively.
+- reg-names: Must be "reg", "cfg" and "mem" respectively.
+- #address-cells: Set to <3>
+- #size-cells: Set to <2>
+- device_type: Set to "pci"
+- ranges: Ranges for the PCI memory and I/O regions
+- #interrupt-cells: Set to <1>
+- interrupt-map-mask and interrupt-map: Standard PCI properties to define the
+ mapping of the PCIe interface to interrupt numbers.
+
+Optional properties:
+- cdns,max-outbound-regions: Set to maximum number of outbound regions
+ (default 32)
+- cdns,no-bar-match-nbits: Set into the no BAR match register to configure the
+ number of least significant bits kept during inbound (PCIe -> AXI) address
+ translations (default 32)
+- vendor-id: The PCI vendor ID (16 bits, default is design dependent)
+- device-id: The PCI device ID (16 bits, default is design dependent)
+
+Example:
+
+pcie@fb000000 {
+ compatible = "cdns,cdns-pcie-host";
+ device_type = "pci";
+ #address-cells = <3>;
+ #size-cells = <2>;
+ bus-range = <0x0 0xff>;
+ linux,pci-domain = <0>;
+ cdns,max-outbound-regions = <16>;
+ cdns,no-bar-match-nbits = <32>;
+ vendor-id = /bits/ 16 <0x17cd>;
+ device-id = /bits/ 16 <0x0200>;
+
+ reg = <0x0 0xfb000000 0x0 0x01000000>,
+ <0x0 0x41000000 0x0 0x00001000>,
+ <0x0 0x40000000 0x0 0x04000000>;
+ reg-names = "reg", "cfg", "mem";
+
+ ranges = <0x02000000 0x0 0x42000000 0x0 0x42000000 0x0 0x1000000>,
+ <0x01000000 0x0 0x43000000 0x0 0x43000000 0x0 0x0010000>;
+
+ #interrupt-cells = <0x1>;
+
+ interrupt-map = <0x0 0x0 0x0 0x1 &gic 0x0 0x0 0x0 14 0x1
+ 0x0 0x0 0x0 0x2 &gic 0x0 0x0 0x0 15 0x1
+ 0x0 0x0 0x0 0x3 &gic 0x0 0x0 0x0 16 0x1
+ 0x0 0x0 0x0 0x4 &gic 0x0 0x0 0x0 17 0x1>;
+
+ interrupt-map-mask = <0x0 0x0 0x0 0x7>;
+
+ msi-parent = <&its_pci>;
+};
--
2.11.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v3 6/6] PCI: cadence: Add host driver for Cadence PCIe controller
2018-01-10 22:47 [PATCH v3 0/6] PCI: Add support to the Cadence PCIe controller Cyrille Pitchen
` (4 preceding siblings ...)
2018-01-10 22:47 ` [PATCH v3 5/6] dt-bindings: PCI: cadence: Add DT bindings for Cadence PCIe host controller Cyrille Pitchen
@ 2018-01-10 22:47 ` Cyrille Pitchen
2018-01-16 11:16 ` Kishon Vijay Abraham I
2018-01-16 16:07 ` Lorenzo Pieralisi
5 siblings, 2 replies; 14+ messages in thread
From: Cyrille Pitchen @ 2018-01-10 22:47 UTC (permalink / raw)
To: bhelgaas, kishon, lorenzo.pieralisi, linux-pci
Cc: adouglas, stelford, dgary, kgopi, eandrews, thomas.petazzoni,
sureshp, nsekhar, linux-kernel, robh, devicetree,
Cyrille Pitchen
This patch adds support to the Cadence PCIe controller in host mode.
Signed-off-by: Cyrille Pitchen <cyrille.pitchen@free-electrons.com>
---
MAINTAINERS | 7 +
drivers/pci/Kconfig | 1 +
drivers/pci/Makefile | 1 +
drivers/pci/cadence/Kconfig | 16 ++
drivers/pci/cadence/Makefile | 3 +
drivers/pci/cadence/pcie-cadence-host.c | 336 ++++++++++++++++++++++++++++++++
drivers/pci/cadence/pcie-cadence.c | 68 +++++++
drivers/pci/cadence/pcie-cadence.h | 196 +++++++++++++++++++
8 files changed, 628 insertions(+)
create mode 100644 drivers/pci/cadence/Kconfig
create mode 100644 drivers/pci/cadence/Makefile
create mode 100644 drivers/pci/cadence/pcie-cadence-host.c
create mode 100644 drivers/pci/cadence/pcie-cadence.c
create mode 100644 drivers/pci/cadence/pcie-cadence.h
diff --git a/MAINTAINERS b/MAINTAINERS
index 13945646b95d..cc24c74a946e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -10402,6 +10402,13 @@ S: Maintained
F: Documentation/devicetree/bindings/pci/pci-armada8k.txt
F: drivers/pci/dwc/pcie-armada8k.c
+PCI DRIVER FOR CADENCE PCIE IP
+M: Alan Douglas <adouglas@cadence.com>
+L: linux-pci@vger.kernel.org
+S: Maintained
+F: Documentation/devicetree/bindings/pci/cdns,*.txt
+F: drivers/pci/cadence/pcie-cadence*
+
PCI DRIVER FOR FREESCALE LAYERSCAPE
M: Minghuan Lian <minghuan.Lian@freescale.com>
M: Mingkai Hu <mingkai.hu@freescale.com>
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
index 7eeb969ab86a..dee90cc1dcaf 100644
--- a/drivers/pci/Kconfig
+++ b/drivers/pci/Kconfig
@@ -136,6 +136,7 @@ config PCI_HYPERV
PCI devices from a PCI backend to support PCI driver domains.
source "drivers/pci/hotplug/Kconfig"
+source "drivers/pci/cadence/Kconfig"
source "drivers/pci/dwc/Kconfig"
source "drivers/pci/host/Kconfig"
source "drivers/pci/endpoint/Kconfig"
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
index ddb5aa6640d7..941970936840 100644
--- a/drivers/pci/Makefile
+++ b/drivers/pci/Makefile
@@ -56,5 +56,6 @@ obj-y += switch/
obj-$(CONFIG_PCI_ENDPOINT) += endpoint/
# Endpoint library must be initialized before its users
+obj-$(CONFIG_PCIE_CADENCE) += cadence/
# pcie-hisi.o quirks are needed even without CONFIG_PCIE_DW
obj-y += dwc/
diff --git a/drivers/pci/cadence/Kconfig b/drivers/pci/cadence/Kconfig
new file mode 100644
index 000000000000..0123d384a628
--- /dev/null
+++ b/drivers/pci/cadence/Kconfig
@@ -0,0 +1,16 @@
+menu "Cadence PCIe controllers support"
+
+config PCIE_CADENCE
+ bool
+
+config PCIE_CADENCE_HOST
+ bool "Cadence PCIe host controller"
+ depends on OF
+ select IRQ_DOMAIN
+ select PCIE_CADENCE
+ help
+ Say Y here if you want to support the Cadence PCIe controller in host
+ mode. This PCIe controller may be embedded into many different vendors
+ SoCs.
+
+endmenu
diff --git a/drivers/pci/cadence/Makefile b/drivers/pci/cadence/Makefile
new file mode 100644
index 000000000000..589601a8ff89
--- /dev/null
+++ b/drivers/pci/cadence/Makefile
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0
+obj-$(CONFIG_PCIE_CADENCE) += pcie-cadence.o
+obj-$(CONFIG_PCIE_CADENCE_HOST) += pcie-cadence-host.o
diff --git a/drivers/pci/cadence/pcie-cadence-host.c b/drivers/pci/cadence/pcie-cadence-host.c
new file mode 100644
index 000000000000..26caf8963e3c
--- /dev/null
+++ b/drivers/pci/cadence/pcie-cadence-host.c
@@ -0,0 +1,336 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2017 Cadence
+// Cadence PCIe host controller driver.
+// Author: Cyrille Pitchen <cyrille.pitchen@free-electrons.com>
+
+#include <linux/kernel.h>
+#include <linux/of_address.h>
+#include <linux/of_pci.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+
+#include "pcie-cadence.h"
+
+/**
+ * struct cdns_pcie_rc - private data for this PCIe Root Complex driver
+ * @pcie: Cadence PCIe controller
+ * @dev: pointer to PCIe device
+ * @cfg_res: start/end offsets in the physical system memory to map PCI
+ * configuration space accesses
+ * @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
+ * @max_regions: maximum number of regions supported by the hardware
+ * @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
+ */
+struct cdns_pcie_rc {
+ struct cdns_pcie pcie;
+ struct device *dev;
+ struct resource *cfg_res;
+ struct resource *bus_range;
+ void __iomem *cfg_base;
+ u32 max_regions;
+ u32 no_bar_nbits;
+ u16 vendor_id;
+ u16 device_id;
+};
+
+static 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);
+ struct cdns_pcie *pcie = &rc->pcie;
+ unsigned int busn = bus->number;
+ u32 addr0, desc0;
+
+ if (busn == rc->bus_range->start) {
+ /*
+ * Only the root port (devfn == 0) is connected to this bus.
+ * All other PCI devices are behind some bridge hence on another
+ * bus.
+ */
+ if (devfn)
+ return NULL;
+
+ return pcie->reg_base + (where & 0xfff);
+ }
+
+ /* Update Output registers for AXI region 0. */
+ addr0 = CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_NBITS(12) |
+ CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_DEVFN(devfn) |
+ CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_BUS(busn);
+ cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_PCI_ADDR0(0), addr0);
+
+ /* Configuration Type 0 or Type 1 access. */
+ desc0 = CDNS_PCIE_AT_OB_REGION_DESC0_HARDCODED_RID |
+ CDNS_PCIE_AT_OB_REGION_DESC0_DEVFN(0);
+ /*
+ * The bus number was already set once for all in desc1 by
+ * cdns_pcie_host_init_address_translation().
+ */
+ if (busn == rc->bus_range->start + 1)
+ desc0 |= CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_CONF_TYPE0;
+ else
+ desc0 |= CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_CONF_TYPE1;
+ cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC0(0), desc0);
+
+ return rc->cfg_base + (where & 0xfff);
+}
+
+static struct pci_ops cdns_pcie_host_ops = {
+ .map_bus = cdns_pci_map_bus,
+ .read = pci_generic_config_read,
+ .write = pci_generic_config_write,
+};
+
+static const struct of_device_id cdns_pcie_host_of_match[] = {
+ { .compatible = "cdns,cdns-pcie-host" },
+
+ { },
+};
+
+static int cdns_pcie_host_init_root_port(struct cdns_pcie_rc *rc)
+{
+ struct cdns_pcie *pcie = &rc->pcie;
+ u32 value, ctrl;
+
+ /*
+ * Set the root complex BAR configuration register:
+ * - disable both BAR0 and BAR1.
+ * - enable Prefetchable Memory Base and Limit registers in type 1
+ * config space (64 bits).
+ * - enable IO Base and Limit registers in type 1 config
+ * space (32 bits).
+ */
+ ctrl = CDNS_PCIE_LM_BAR_CFG_CTRL_DISABLED;
+ value = CDNS_PCIE_LM_RC_BAR_CFG_BAR0_CTRL(ctrl) |
+ CDNS_PCIE_LM_RC_BAR_CFG_BAR1_CTRL(ctrl) |
+ CDNS_PCIE_LM_RC_BAR_CFG_PREFETCH_MEM_ENABLE |
+ CDNS_PCIE_LM_RC_BAR_CFG_PREFETCH_MEM_64BITS |
+ CDNS_PCIE_LM_RC_BAR_CFG_IO_ENABLE |
+ CDNS_PCIE_LM_RC_BAR_CFG_IO_32BITS;
+ 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->device_id != 0xffff)
+ cdns_pcie_rp_writew(pcie, PCI_DEVICE_ID, rc->device_id);
+
+ cdns_pcie_rp_writeb(pcie, PCI_CLASS_REVISION, 0);
+ cdns_pcie_rp_writeb(pcie, PCI_CLASS_PROG, 0);
+ cdns_pcie_rp_writew(pcie, PCI_CLASS_DEVICE, PCI_CLASS_BRIDGE_PCI);
+
+ return 0;
+}
+
+static int cdns_pcie_host_init_address_translation(struct cdns_pcie_rc *rc)
+{
+ struct cdns_pcie *pcie = &rc->pcie;
+ struct resource *cfg_res = rc->cfg_res;
+ struct resource *mem_res = pcie->mem_res;
+ struct resource *bus_range = rc->bus_range;
+ struct device *dev = rc->dev;
+ struct device_node *np = dev->of_node;
+ struct of_pci_range_parser parser;
+ struct of_pci_range range;
+ u32 addr0, addr1, desc1;
+ u64 cpu_addr;
+ int r, err;
+
+ /*
+ * Reserve region 0 for PCI configure space accesses:
+ * OB_REGION_PCI_ADDR0 and OB_REGION_DESC0 are updated dynamically by
+ * cdns_pci_map_bus(), other region registers are set here once for all.
+ */
+ addr1 = 0; /* Should be programmed to zero. */
+ desc1 = CDNS_PCIE_AT_OB_REGION_DESC1_BUS(bus_range->start);
+ 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;
+ addr0 = CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS(12) |
+ (lower_32_bits(cpu_addr) & GENMASK(31, 8));
+ addr1 = upper_32_bits(cpu_addr);
+ cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR0(0), addr0);
+ cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR1(0), addr1);
+
+ err = of_pci_range_parser_init(&parser, np);
+ if (err)
+ return err;
+
+ r = 1;
+ for_each_of_pci_range(&parser, &range) {
+ bool is_io;
+
+ if (r >= rc->max_regions)
+ break;
+
+ if ((range.flags & IORESOURCE_TYPE_BITS) == IORESOURCE_MEM)
+ is_io = false;
+ else if ((range.flags & IORESOURCE_TYPE_BITS) == IORESOURCE_IO)
+ is_io = true;
+ else
+ continue;
+
+ cdns_pcie_set_outbound_region(pcie, r, is_io,
+ range.cpu_addr,
+ range.pci_addr,
+ range.size);
+ 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);
+
+ return 0;
+}
+
+static int cdns_pcie_host_init(struct device *dev,
+ struct list_head *resources,
+ struct cdns_pcie_rc *rc)
+{
+ struct resource *bus_range = NULL;
+ int err;
+
+ /* Parse our PCI ranges and request their resources */
+ err = pci_parse_request_of_pci_ranges(dev, resources, &bus_range);
+ if (err)
+ return err;
+
+ rc->bus_range = bus_range;
+ rc->pcie.bus = bus_range->start;
+
+ err = cdns_pcie_host_init_root_port(rc);
+ if (err)
+ goto err_out;
+
+ err = cdns_pcie_host_init_address_translation(rc);
+ if (err)
+ goto err_out;
+
+ return 0;
+
+ err_out:
+ pci_free_resource_list(resources);
+ return err;
+}
+
+static int cdns_pcie_host_probe(struct platform_device *pdev)
+{
+ const char *type;
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct pci_host_bridge *bridge;
+ struct list_head resources;
+ struct cdns_pcie_rc *rc;
+ struct cdns_pcie *pcie;
+ struct resource *res;
+ int ret;
+
+ bridge = devm_pci_alloc_host_bridge(dev, sizeof(*rc));
+ if (!bridge)
+ return -ENOMEM;
+
+ rc = pci_host_bridge_priv(bridge);
+ rc->dev = dev;
+
+ pcie = &rc->pcie;
+ pcie->is_rc = true;
+
+ rc->max_regions = 32;
+ of_property_read_u32(np, "cdns,max-outbound-regions", &rc->max_regions);
+
+ 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_u16(np, "vendor-id", &rc->vendor_id);
+
+ rc->device_id = 0xffff;
+ of_property_read_u16(np, "device-id", &rc->device_id);
+
+ type = of_get_property(np, "device_type", NULL);
+ if (!type || strcmp(type, "pci")) {
+ dev_err(dev, "invalid \"device_type\" %s\n", type);
+ return -EINVAL;
+ }
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "reg");
+ pcie->reg_base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(pcie->reg_base)) {
+ dev_err(dev, "missing \"reg\"\n");
+ return PTR_ERR(pcie->reg_base);
+ }
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cfg");
+ rc->cfg_base = devm_pci_remap_cfg_resource(dev, res);
+ if (IS_ERR(rc->cfg_base)) {
+ dev_err(dev, "missing \"cfg\"\n");
+ return PTR_ERR(rc->cfg_base);
+ }
+ 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;
+
+ 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 = cdns_pcie_host_init(dev, &resources, rc);
+ if (ret)
+ goto err_init;
+
+ list_splice_init(&resources, &bridge->windows);
+ bridge->dev.parent = dev;
+ bridge->busnr = pcie->bus;
+ bridge->ops = &cdns_pcie_host_ops;
+ bridge->map_irq = of_irq_parse_and_map_pci;
+ bridge->swizzle_irq = pci_common_swizzle;
+
+ ret = pci_host_probe(bridge);
+ if (ret < 0)
+ goto err_host_probe;
+
+ return 0;
+
+ err_host_probe:
+ pci_free_resource_list(&resources);
+
+ err_init:
+ pm_runtime_put_sync(dev);
+
+ err_get_sync:
+ pm_runtime_disable(dev);
+
+ return ret;
+}
+
+static struct platform_driver cdns_pcie_host_driver = {
+ .driver = {
+ .name = "cdns-pcie-host",
+ .of_match_table = cdns_pcie_host_of_match,
+ },
+ .probe = cdns_pcie_host_probe,
+};
+builtin_platform_driver(cdns_pcie_host_driver);
diff --git a/drivers/pci/cadence/pcie-cadence.c b/drivers/pci/cadence/pcie-cadence.c
new file mode 100644
index 000000000000..5c76e7f4c5f9
--- /dev/null
+++ b/drivers/pci/cadence/pcie-cadence.c
@@ -0,0 +1,68 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2017 Cadence
+// Cadence PCIe controller driver.
+// Author: Cyrille Pitchen <cyrille.pitchen@free-electrons.com>
+
+#include <linux/kernel.h>
+
+#include "pcie-cadence.h"
+
+void cdns_pcie_set_outbound_region(struct cdns_pcie *pcie, u32 r, bool is_io,
+ u64 cpu_addr, u64 pci_addr, size_t size)
+{
+ /*
+ * roundup_pow_of_two() returns an unsigned long, which is not suited
+ * for 64bit values.
+ */
+ u64 sz = 1ULL << fls64(size - 1);
+ int nbits = ilog2(sz);
+ u32 addr0, addr1, desc0, desc1;
+
+ if (nbits < 8)
+ nbits = 8;
+
+ /* Set the PCI address */
+ addr0 = CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_NBITS(nbits) |
+ (lower_32_bits(pci_addr) & GENMASK(31, 8));
+ addr1 = upper_32_bits(pci_addr);
+
+ cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_PCI_ADDR0(r), addr0);
+ cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_PCI_ADDR1(r), addr1);
+
+ /* Set the PCIe header descriptor */
+ if (is_io)
+ desc0 = CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_IO;
+ else
+ desc0 = CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_MEM;
+ desc1 = 0;
+
+ if (pcie->is_rc) {
+ desc0 |= CDNS_PCIE_AT_OB_REGION_DESC0_HARDCODED_RID |
+ CDNS_PCIE_AT_OB_REGION_DESC0_DEVFN(0);
+ desc1 |= CDNS_PCIE_AT_OB_REGION_DESC1_BUS(pcie->bus);
+ }
+
+ cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC0(r), desc0);
+ cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC1(r), desc1);
+
+ /* Set the CPU address */
+ cpu_addr -= pcie->mem_res->start;
+ addr0 = CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS(nbits) |
+ (lower_32_bits(cpu_addr) & GENMASK(31, 8));
+ addr1 = upper_32_bits(cpu_addr);
+
+ cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR0(r), addr0);
+ cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR1(r), addr1);
+}
+
+void cdns_pcie_reset_outbound_region(struct cdns_pcie *pcie, u32 r)
+{
+ cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_PCI_ADDR0(r), 0);
+ cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_PCI_ADDR1(r), 0);
+
+ cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC0(r), 0);
+ cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC1(r), 0);
+
+ cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR0(r), 0);
+ cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR1(r), 0);
+}
diff --git a/drivers/pci/cadence/pcie-cadence.h b/drivers/pci/cadence/pcie-cadence.h
new file mode 100644
index 000000000000..3a15b4016352
--- /dev/null
+++ b/drivers/pci/cadence/pcie-cadence.h
@@ -0,0 +1,196 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2017 Cadence
+// Cadence PCIe controller driver.
+// Author: Cyrille Pitchen <cyrille.pitchen@free-electrons.com>
+
+#ifndef _PCIE_CADENCE_H
+#define _PCIE_CADENCE_H
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+
+/*
+ * Local Management Registers
+ */
+#define CDNS_PCIE_LM_BASE 0x00100000
+
+/* Vendor ID Register */
+#define CDNS_PCIE_LM_ID (CDNS_PCIE_LM_BASE + 0x0044)
+#define CDNS_PCIE_LM_ID_VENDOR_MASK GENMASK(15, 0)
+#define CDNS_PCIE_LM_ID_VENDOR_SHIFT 0
+#define CDNS_PCIE_LM_ID_VENDOR(vid) \
+ (((vid) << CDNS_PCIE_LM_ID_VENDOR_SHIFT) & CDNS_PCIE_LM_ID_VENDOR_MASK)
+#define CDNS_PCIE_LM_ID_SUBSYS_MASK GENMASK(31, 16)
+#define CDNS_PCIE_LM_ID_SUBSYS_SHIFT 16
+#define CDNS_PCIE_LM_ID_SUBSYS(sub) \
+ (((sub) << CDNS_PCIE_LM_ID_SUBSYS_SHIFT) & CDNS_PCIE_LM_ID_SUBSYS_MASK)
+
+/* Root Port Requestor ID Register */
+#define CDNS_PCIE_LM_RP_RID (CDNS_PCIE_LM_BASE + 0x0228)
+#define CDNS_PCIE_LM_RP_RID_MASK GENMASK(15, 0)
+#define CDNS_PCIE_LM_RP_RID_SHIFT 0
+#define CDNS_PCIE_LM_RP_RID_(rid) \
+ (((rid) << CDNS_PCIE_LM_RP_RID_SHIFT) & CDNS_PCIE_LM_RP_RID_MASK)
+
+/* Root Complex BAR Configuration Register */
+#define CDNS_PCIE_LM_RC_BAR_CFG (CDNS_PCIE_LM_BASE + 0x0300)
+#define CDNS_PCIE_LM_RC_BAR_CFG_BAR0_APERTURE_MASK GENMASK(5, 0)
+#define CDNS_PCIE_LM_RC_BAR_CFG_BAR0_APERTURE(a) \
+ (((a) << 0) & CDNS_PCIE_LM_RC_BAR_CFG_BAR0_APERTURE_MASK)
+#define CDNS_PCIE_LM_RC_BAR_CFG_BAR0_CTRL_MASK GENMASK(8, 6)
+#define CDNS_PCIE_LM_RC_BAR_CFG_BAR0_CTRL(c) \
+ (((c) << 6) & CDNS_PCIE_LM_RC_BAR_CFG_BAR0_CTRL_MASK)
+#define CDNS_PCIE_LM_RC_BAR_CFG_BAR1_APERTURE_MASK GENMASK(13, 9)
+#define CDNS_PCIE_LM_RC_BAR_CFG_BAR1_APERTURE(a) \
+ (((a) << 9) & CDNS_PCIE_LM_RC_BAR_CFG_BAR1_APERTURE_MASK)
+#define CDNS_PCIE_LM_RC_BAR_CFG_BAR1_CTRL_MASK GENMASK(16, 14)
+#define CDNS_PCIE_LM_RC_BAR_CFG_BAR1_CTRL(c) \
+ (((c) << 14) & CDNS_PCIE_LM_RC_BAR_CFG_BAR1_CTRL_MASK)
+#define CDNS_PCIE_LM_RC_BAR_CFG_PREFETCH_MEM_ENABLE BIT(17)
+#define CDNS_PCIE_LM_RC_BAR_CFG_PREFETCH_MEM_32BITS 0
+#define CDNS_PCIE_LM_RC_BAR_CFG_PREFETCH_MEM_64BITS BIT(18)
+#define CDNS_PCIE_LM_RC_BAR_CFG_IO_ENABLE BIT(19)
+#define CDNS_PCIE_LM_RC_BAR_CFG_IO_16BITS 0
+#define CDNS_PCIE_LM_RC_BAR_CFG_IO_32BITS BIT(20)
+#define CDNS_PCIE_LM_RC_BAR_CFG_CHECK_ENABLE BIT(31)
+
+/* BAR control values applicable to both Endpoint Function and Root Complex */
+#define CDNS_PCIE_LM_BAR_CFG_CTRL_DISABLED 0x0
+#define CDNS_PCIE_LM_BAR_CFG_CTRL_IO_32BITS 0x1
+#define CDNS_PCIE_LM_BAR_CFG_CTRL_MEM_32BITS 0x4
+#define CDNS_PCIE_LM_BAR_CFG_CTRL_PREFETCH_MEM_32BITS 0x5
+#define CDNS_PCIE_LM_BAR_CFG_CTRL_MEM_64BITS 0x6
+#define CDNS_PCIE_LM_BAR_CFG_CTRL_PREFETCH_MEM_64BITS 0x7
+
+
+/*
+ * Root Port Registers (PCI configuration space for the root port function)
+ */
+#define CDNS_PCIE_RP_BASE 0x00200000
+
+
+/*
+ * Address Translation Registers
+ */
+#define CDNS_PCIE_AT_BASE 0x00400000
+
+/* Region r Outbound AXI to PCIe Address Translation Register 0 */
+#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0(r) \
+ (CDNS_PCIE_AT_BASE + 0x0000 + ((r) & 0x1f) * 0x0020)
+#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_NBITS_MASK GENMASK(5, 0)
+#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_NBITS(nbits) \
+ (((nbits) - 1) & CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_NBITS_MASK)
+#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_DEVFN_MASK GENMASK(19, 12)
+#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_DEVFN(devfn) \
+ (((devfn) << 12) & CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_DEVFN_MASK)
+#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_BUS_MASK GENMASK(27, 20)
+#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_BUS(bus) \
+ (((bus) << 20) & CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_BUS_MASK)
+
+/* Region r Outbound AXI to PCIe Address Translation Register 1 */
+#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR1(r) \
+ (CDNS_PCIE_AT_BASE + 0x0004 + ((r) & 0x1f) * 0x0020)
+
+/* Region r Outbound PCIe Descriptor Register 0 */
+#define CDNS_PCIE_AT_OB_REGION_DESC0(r) \
+ (CDNS_PCIE_AT_BASE + 0x0008 + ((r) & 0x1f) * 0x0020)
+#define CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_MASK GENMASK(3, 0)
+#define CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_MEM 0x2
+#define CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_IO 0x6
+#define CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_CONF_TYPE0 0xa
+#define CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_CONF_TYPE1 0xb
+#define CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_NORMAL_MSG 0xc
+#define CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_VENDOR_MSG 0xd
+/* Bit 23 MUST be set in RC mode. */
+#define CDNS_PCIE_AT_OB_REGION_DESC0_HARDCODED_RID BIT(23)
+#define CDNS_PCIE_AT_OB_REGION_DESC0_DEVFN_MASK GENMASK(31, 24)
+#define CDNS_PCIE_AT_OB_REGION_DESC0_DEVFN(devfn) \
+ (((devfn) << 24) & CDNS_PCIE_AT_OB_REGION_DESC0_DEVFN_MASK)
+
+/* Region r Outbound PCIe Descriptor Register 1 */
+#define CDNS_PCIE_AT_OB_REGION_DESC1(r) \
+ (CDNS_PCIE_AT_BASE + 0x000c + ((r) & 0x1f) * 0x0020)
+#define CDNS_PCIE_AT_OB_REGION_DESC1_BUS_MASK GENMASK(7, 0)
+#define CDNS_PCIE_AT_OB_REGION_DESC1_BUS(bus) \
+ ((bus) & CDNS_PCIE_AT_OB_REGION_DESC1_BUS_MASK)
+
+/* Region r AXI Region Base Address Register 0 */
+#define CDNS_PCIE_AT_OB_REGION_CPU_ADDR0(r) \
+ (CDNS_PCIE_AT_BASE + 0x0018 + ((r) & 0x1f) * 0x0020)
+#define CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS_MASK GENMASK(5, 0)
+#define CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS(nbits) \
+ (((nbits) - 1) & CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS_MASK)
+
+/* Region r AXI Region Base Address Register 1 */
+#define CDNS_PCIE_AT_OB_REGION_CPU_ADDR1(r) \
+ (CDNS_PCIE_AT_BASE + 0x001c + ((r) & 0x1f) * 0x0020)
+
+/* Root Port BAR Inbound PCIe to AXI Address Translation Register */
+#define CDNS_PCIE_AT_IB_RP_BAR_ADDR0(bar) \
+ (CDNS_PCIE_AT_BASE + 0x0800 + (bar) * 0x0008)
+#define CDNS_PCIE_AT_IB_RP_BAR_ADDR0_NBITS_MASK GENMASK(5, 0)
+#define CDNS_PCIE_AT_IB_RP_BAR_ADDR0_NBITS(nbits) \
+ (((nbits) - 1) & CDNS_PCIE_AT_IB_RP_BAR_ADDR0_NBITS_MASK)
+#define CDNS_PCIE_AT_IB_RP_BAR_ADDR1(bar) \
+ (CDNS_PCIE_AT_BASE + 0x0804 + (bar) * 0x0008)
+
+enum cdns_pcie_rp_bar {
+ RP_BAR0,
+ RP_BAR1,
+ RP_NO_BAR
+};
+
+/**
+ * struct cdns_pcie - private data for Cadence PCIe controller drivers
+ * @reg_base: IO mapped register base
+ * @mem_res: start/end offsets in the physical system memory to map PCI accesses
+ * @is_rc: tell whether the PCIe controller mode is Root Complex or Endpoint.
+ * @bus: In Root Complex mode, the bus number
+ */
+struct cdns_pcie {
+ void __iomem *reg_base;
+ struct resource *mem_res;
+ bool is_rc;
+ u8 bus;
+};
+
+/* Register access */
+static inline void cdns_pcie_writeb(struct cdns_pcie *pcie, u32 reg, u8 value)
+{
+ writeb(value, pcie->reg_base + reg);
+}
+
+static inline void cdns_pcie_writew(struct cdns_pcie *pcie, u32 reg, u16 value)
+{
+ writew(value, pcie->reg_base + reg);
+}
+
+static inline void cdns_pcie_writel(struct cdns_pcie *pcie, u32 reg, u32 value)
+{
+ writel(value, pcie->reg_base + reg);
+}
+
+static inline u32 cdns_pcie_readl(struct cdns_pcie *pcie, u32 reg)
+{
+ return readl(pcie->reg_base + reg);
+}
+
+/* Root Port register access */
+static inline void cdns_pcie_rp_writeb(struct cdns_pcie *pcie,
+ u32 reg, u8 value)
+{
+ writeb(value, pcie->reg_base + CDNS_PCIE_RP_BASE + reg);
+}
+
+static inline void cdns_pcie_rp_writew(struct cdns_pcie *pcie,
+ u32 reg, u16 value)
+{
+ writew(value, pcie->reg_base + CDNS_PCIE_RP_BASE + reg);
+}
+
+void cdns_pcie_set_outbound_region(struct cdns_pcie *pcie, u32 r, bool is_io,
+ u64 cpu_addr, u64 pci_addr, size_t size);
+
+void cdns_pcie_reset_outbound_region(struct cdns_pcie *pcie, u32 r);
+
+#endif /* _PCIE_CADENCE_H */
--
2.11.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCH v3 6/6] PCI: cadence: Add host driver for Cadence PCIe controller
2018-01-10 22:47 ` [PATCH v3 6/6] PCI: cadence: Add host driver for Cadence PCIe controller Cyrille Pitchen
@ 2018-01-16 11:16 ` Kishon Vijay Abraham I
[not found] ` <e3d88d5b-e770-d2e5-20b2-62551d5f4f8f-l0cyMroinI0@public.gmane.org>
2018-01-16 16:07 ` Lorenzo Pieralisi
1 sibling, 1 reply; 14+ messages in thread
From: Kishon Vijay Abraham I @ 2018-01-16 11:16 UTC (permalink / raw)
To: Cyrille Pitchen, bhelgaas, lorenzo.pieralisi, linux-pci
Cc: adouglas, stelford, dgary, kgopi, eandrews, thomas.petazzoni,
sureshp, nsekhar, linux-kernel, robh, devicetree
Hi Cyrille,
On Thursday 11 January 2018 04:17 AM, Cyrille Pitchen wrote:
> This patch adds support to the Cadence PCIe controller in host mode.
>
> Signed-off-by: Cyrille Pitchen <cyrille.pitchen@free-electrons.com>
> ---
> MAINTAINERS | 7 +
> drivers/pci/Kconfig | 1 +
> drivers/pci/Makefile | 1 +
> drivers/pci/cadence/Kconfig | 16 ++
> drivers/pci/cadence/Makefile | 3 +
> drivers/pci/cadence/pcie-cadence-host.c | 336 ++++++++++++++++++++++++++++++++
> drivers/pci/cadence/pcie-cadence.c | 68 +++++++
> drivers/pci/cadence/pcie-cadence.h | 196 +++++++++++++++++++
> 8 files changed, 628 insertions(+)
> create mode 100644 drivers/pci/cadence/Kconfig
> create mode 100644 drivers/pci/cadence/Makefile
> create mode 100644 drivers/pci/cadence/pcie-cadence-host.c
> create mode 100644 drivers/pci/cadence/pcie-cadence.c
> create mode 100644 drivers/pci/cadence/pcie-cadence.h
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 13945646b95d..cc24c74a946e 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -10402,6 +10402,13 @@ S: Maintained
> F: Documentation/devicetree/bindings/pci/pci-armada8k.txt
> F: drivers/pci/dwc/pcie-armada8k.c
>
> +PCI DRIVER FOR CADENCE PCIE IP
> +M: Alan Douglas <adouglas@cadence.com>
> +L: linux-pci@vger.kernel.org
> +S: Maintained
> +F: Documentation/devicetree/bindings/pci/cdns,*.txt
> +F: drivers/pci/cadence/pcie-cadence*
> +
> PCI DRIVER FOR FREESCALE LAYERSCAPE
> M: Minghuan Lian <minghuan.Lian@freescale.com>
> M: Mingkai Hu <mingkai.hu@freescale.com>
> diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
> index 7eeb969ab86a..dee90cc1dcaf 100644
> --- a/drivers/pci/Kconfig
> +++ b/drivers/pci/Kconfig
> @@ -136,6 +136,7 @@ config PCI_HYPERV
> PCI devices from a PCI backend to support PCI driver domains.
>
> source "drivers/pci/hotplug/Kconfig"
> +source "drivers/pci/cadence/Kconfig"
> source "drivers/pci/dwc/Kconfig"
> source "drivers/pci/host/Kconfig"
> source "drivers/pci/endpoint/Kconfig"
> diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
> index ddb5aa6640d7..941970936840 100644
> --- a/drivers/pci/Makefile
> +++ b/drivers/pci/Makefile
> @@ -56,5 +56,6 @@ obj-y += switch/
> obj-$(CONFIG_PCI_ENDPOINT) += endpoint/
>
> # Endpoint library must be initialized before its users
> +obj-$(CONFIG_PCIE_CADENCE) += cadence/
> # pcie-hisi.o quirks are needed even without CONFIG_PCIE_DW
> obj-y += dwc/
> diff --git a/drivers/pci/cadence/Kconfig b/drivers/pci/cadence/Kconfig
> new file mode 100644
> index 000000000000..0123d384a628
> --- /dev/null
> +++ b/drivers/pci/cadence/Kconfig
> @@ -0,0 +1,16 @@
> +menu "Cadence PCIe controllers support"
> +
> +config PCIE_CADENCE
> + bool
> +
> +config PCIE_CADENCE_HOST
> + bool "Cadence PCIe host controller"
> + depends on OF
> + select IRQ_DOMAIN
> + select PCIE_CADENCE
> + help
> + Say Y here if you want to support the Cadence PCIe controller in host
> + mode. This PCIe controller may be embedded into many different vendors
> + SoCs.
> +
> +endmenu
> diff --git a/drivers/pci/cadence/Makefile b/drivers/pci/cadence/Makefile
> new file mode 100644
> index 000000000000..589601a8ff89
> --- /dev/null
> +++ b/drivers/pci/cadence/Makefile
> @@ -0,0 +1,3 @@
> +# SPDX-License-Identifier: GPL-2.0
> +obj-$(CONFIG_PCIE_CADENCE) += pcie-cadence.o
> +obj-$(CONFIG_PCIE_CADENCE_HOST) += pcie-cadence-host.o
> diff --git a/drivers/pci/cadence/pcie-cadence-host.c b/drivers/pci/cadence/pcie-cadence-host.c
> new file mode 100644
> index 000000000000..26caf8963e3c
> --- /dev/null
> +++ b/drivers/pci/cadence/pcie-cadence-host.c
> @@ -0,0 +1,336 @@
> +// SPDX-License-Identifier: GPL-2.0
> +// Copyright (c) 2017 Cadence
> +// Cadence PCIe host controller driver.
> +// Author: Cyrille Pitchen <cyrille.pitchen@free-electrons.com>
> +
> +#include <linux/kernel.h>
> +#include <linux/of_address.h>
> +#include <linux/of_pci.h>
> +#include <linux/platform_device.h>
> +#include <linux/pm_runtime.h>
> +
> +#include "pcie-cadence.h"
> +
> +/**
> + * struct cdns_pcie_rc - private data for this PCIe Root Complex driver
> + * @pcie: Cadence PCIe controller
> + * @dev: pointer to PCIe device
> + * @cfg_res: start/end offsets in the physical system memory to map PCI
> + * configuration space accesses
> + * @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
> + * @max_regions: maximum number of regions supported by the hardware
> + * @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
> + */
> +struct cdns_pcie_rc {
> + struct cdns_pcie pcie;
> + struct device *dev;
> + struct resource *cfg_res;
> + struct resource *bus_range;
> + void __iomem *cfg_base;
> + u32 max_regions;
> + u32 no_bar_nbits;
> + u16 vendor_id;
> + u16 device_id;
> +};
> +
> +static 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);
> + struct cdns_pcie *pcie = &rc->pcie;
> + unsigned int busn = bus->number;
> + u32 addr0, desc0;
> +
> + if (busn == rc->bus_range->start) {
> + /*
> + * Only the root port (devfn == 0) is connected to this bus.
> + * All other PCI devices are behind some bridge hence on another
> + * bus.
> + */
> + if (devfn)
> + return NULL;
> +
> + return pcie->reg_base + (where & 0xfff);
> + }
> +
> + /* Update Output registers for AXI region 0. */
> + addr0 = CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_NBITS(12) |
> + CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_DEVFN(devfn) |
> + CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_BUS(busn);
> + cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_PCI_ADDR0(0), addr0);
> +
> + /* Configuration Type 0 or Type 1 access. */
> + desc0 = CDNS_PCIE_AT_OB_REGION_DESC0_HARDCODED_RID |
> + CDNS_PCIE_AT_OB_REGION_DESC0_DEVFN(0);
> + /*
> + * The bus number was already set once for all in desc1 by
> + * cdns_pcie_host_init_address_translation().
> + */
> + if (busn == rc->bus_range->start + 1)
> + desc0 |= CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_CONF_TYPE0;
> + else
> + desc0 |= CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_CONF_TYPE1;
> + cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC0(0), desc0);
> +
> + return rc->cfg_base + (where & 0xfff);
> +}
> +
> +static struct pci_ops cdns_pcie_host_ops = {
> + .map_bus = cdns_pci_map_bus,
> + .read = pci_generic_config_read,
> + .write = pci_generic_config_write,
> +};
> +
> +static const struct of_device_id cdns_pcie_host_of_match[] = {
> + { .compatible = "cdns,cdns-pcie-host" },
> +
> + { },
> +};
> +
> +static int cdns_pcie_host_init_root_port(struct cdns_pcie_rc *rc)
> +{
> + struct cdns_pcie *pcie = &rc->pcie;
> + u32 value, ctrl;
> +
> + /*
> + * Set the root complex BAR configuration register:
> + * - disable both BAR0 and BAR1.
> + * - enable Prefetchable Memory Base and Limit registers in type 1
> + * config space (64 bits).
> + * - enable IO Base and Limit registers in type 1 config
> + * space (32 bits).
> + */
> + ctrl = CDNS_PCIE_LM_BAR_CFG_CTRL_DISABLED;
> + value = CDNS_PCIE_LM_RC_BAR_CFG_BAR0_CTRL(ctrl) |
> + CDNS_PCIE_LM_RC_BAR_CFG_BAR1_CTRL(ctrl) |
> + CDNS_PCIE_LM_RC_BAR_CFG_PREFETCH_MEM_ENABLE |
> + CDNS_PCIE_LM_RC_BAR_CFG_PREFETCH_MEM_64BITS |
> + CDNS_PCIE_LM_RC_BAR_CFG_IO_ENABLE |
> + CDNS_PCIE_LM_RC_BAR_CFG_IO_32BITS;
> + 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->device_id != 0xffff)
> + cdns_pcie_rp_writew(pcie, PCI_DEVICE_ID, rc->device_id);
> +
> + cdns_pcie_rp_writeb(pcie, PCI_CLASS_REVISION, 0);
> + cdns_pcie_rp_writeb(pcie, PCI_CLASS_PROG, 0);
> + cdns_pcie_rp_writew(pcie, PCI_CLASS_DEVICE, PCI_CLASS_BRIDGE_PCI);
> +
> + return 0;
> +}
> +
> +static int cdns_pcie_host_init_address_translation(struct cdns_pcie_rc *rc)
> +{
> + struct cdns_pcie *pcie = &rc->pcie;
> + struct resource *cfg_res = rc->cfg_res;
> + struct resource *mem_res = pcie->mem_res;
> + struct resource *bus_range = rc->bus_range;
> + struct device *dev = rc->dev;
> + struct device_node *np = dev->of_node;
> + struct of_pci_range_parser parser;
> + struct of_pci_range range;
> + u32 addr0, addr1, desc1;
> + u64 cpu_addr;
> + int r, err;
> +
> + /*
> + * Reserve region 0 for PCI configure space accesses:
> + * OB_REGION_PCI_ADDR0 and OB_REGION_DESC0 are updated dynamically by
> + * cdns_pci_map_bus(), other region registers are set here once for all.
> + */
> + addr1 = 0; /* Should be programmed to zero. */
> + desc1 = CDNS_PCIE_AT_OB_REGION_DESC1_BUS(bus_range->start);
> + 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;
> + addr0 = CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS(12) |
> + (lower_32_bits(cpu_addr) & GENMASK(31, 8));
> + addr1 = upper_32_bits(cpu_addr);
> + cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR0(0), addr0);
> + cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR1(0), addr1);
> +
> + err = of_pci_range_parser_init(&parser, np);
> + if (err)
> + return err;
> +
> + r = 1;
> + for_each_of_pci_range(&parser, &range) {
> + bool is_io;
> +
> + if (r >= rc->max_regions)
> + break;
> +
> + if ((range.flags & IORESOURCE_TYPE_BITS) == IORESOURCE_MEM)
> + is_io = false;
> + else if ((range.flags & IORESOURCE_TYPE_BITS) == IORESOURCE_IO)
> + is_io = true;
> + else
> + continue;
> +
> + cdns_pcie_set_outbound_region(pcie, r, is_io,
> + range.cpu_addr,
> + range.pci_addr,
> + range.size);
> + 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);
> +
> + return 0;
> +}
> +
> +static int cdns_pcie_host_init(struct device *dev,
> + struct list_head *resources,
> + struct cdns_pcie_rc *rc)
> +{
> + struct resource *bus_range = NULL;
> + int err;
> +
> + /* Parse our PCI ranges and request their resources */
> + err = pci_parse_request_of_pci_ranges(dev, resources, &bus_range);
> + if (err)
> + return err;
> +
> + rc->bus_range = bus_range;
> + rc->pcie.bus = bus_range->start;
> +
> + err = cdns_pcie_host_init_root_port(rc);
> + if (err)
> + goto err_out;
> +
> + err = cdns_pcie_host_init_address_translation(rc);
> + if (err)
> + goto err_out;
> +
> + return 0;
> +
> + err_out:
> + pci_free_resource_list(resources);
> + return err;
> +}
> +
> +static int cdns_pcie_host_probe(struct platform_device *pdev)
> +{
> + const char *type;
> + struct device *dev = &pdev->dev;
> + struct device_node *np = dev->of_node;
> + struct pci_host_bridge *bridge;
> + struct list_head resources;
> + struct cdns_pcie_rc *rc;
> + struct cdns_pcie *pcie;
> + struct resource *res;
> + int ret;
> +
> + bridge = devm_pci_alloc_host_bridge(dev, sizeof(*rc));
> + if (!bridge)
> + return -ENOMEM;
> +
> + rc = pci_host_bridge_priv(bridge);
> + rc->dev = dev;
> +
> + pcie = &rc->pcie;
> + pcie->is_rc = true;
> +
> + rc->max_regions = 32;
> + of_property_read_u32(np, "cdns,max-outbound-regions", &rc->max_regions);
> +
> + 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_u16(np, "vendor-id", &rc->vendor_id);
> +
> + rc->device_id = 0xffff;
> + of_property_read_u16(np, "device-id", &rc->device_id);
> +
> + type = of_get_property(np, "device_type", NULL);
> + if (!type || strcmp(type, "pci")) {
> + dev_err(dev, "invalid \"device_type\" %s\n", type);
> + return -EINVAL;
> + }
> +
> + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "reg");
> + pcie->reg_base = devm_ioremap_resource(dev, res);
> + if (IS_ERR(pcie->reg_base)) {
> + dev_err(dev, "missing \"reg\"\n");
> + return PTR_ERR(pcie->reg_base);
> + }
> +
> + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cfg");
> + rc->cfg_base = devm_pci_remap_cfg_resource(dev, res);
> + if (IS_ERR(rc->cfg_base)) {
> + dev_err(dev, "missing \"cfg\"\n");
> + return PTR_ERR(rc->cfg_base);
> + }
> + 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;
> +
> + 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 = cdns_pcie_host_init(dev, &resources, rc);
> + if (ret)
> + goto err_init;
> +
> + list_splice_init(&resources, &bridge->windows);
> + bridge->dev.parent = dev;
> + bridge->busnr = pcie->bus;
> + bridge->ops = &cdns_pcie_host_ops;
> + bridge->map_irq = of_irq_parse_and_map_pci;
> + bridge->swizzle_irq = pci_common_swizzle;
> +
> + ret = pci_host_probe(bridge);
> + if (ret < 0)
> + goto err_host_probe;
> +
> + return 0;
> +
> + err_host_probe:
> + pci_free_resource_list(&resources);
> +
> + err_init:
> + pm_runtime_put_sync(dev);
> +
> + err_get_sync:
> + pm_runtime_disable(dev);
> +
> + return ret;
> +}
> +
> +static struct platform_driver cdns_pcie_host_driver = {
> + .driver = {
> + .name = "cdns-pcie-host",
> + .of_match_table = cdns_pcie_host_of_match,
> + },
> + .probe = cdns_pcie_host_probe,
> +};
In the case of DWC, designware core is modeled as a library which has API's to
be invoked by various platform specific glue drivers.
But with the cadence approach we'll have two separate drivers: the cadence core
driver and the platform specific glue drivers. Is this approach chosen for a
specific reason?
Thanks
Kishon
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v3 6/6] PCI: cadence: Add host driver for Cadence PCIe controller
[not found] ` <e3d88d5b-e770-d2e5-20b2-62551d5f4f8f-l0cyMroinI0@public.gmane.org>
@ 2018-01-16 15:09 ` Lorenzo Pieralisi
2018-01-18 23:13 ` Cyrille Pitchen
1 sibling, 0 replies; 14+ messages in thread
From: Lorenzo Pieralisi @ 2018-01-16 15:09 UTC (permalink / raw)
To: Kishon Vijay Abraham I
Cc: Cyrille Pitchen, bhelgaas-hpIqsD4AKlfQT0dZR+AlfA,
linux-pci-u79uwXL29TY76Z2rM5mHXA,
adouglas-vna1KIf7WgpBDgjK7y7TUQ, stelford-vna1KIf7WgpBDgjK7y7TUQ,
dgary-vna1KIf7WgpBDgjK7y7TUQ, kgopi-vna1KIf7WgpBDgjK7y7TUQ,
eandrews-vna1KIf7WgpBDgjK7y7TUQ,
thomas.petazzoni-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
sureshp-vna1KIf7WgpBDgjK7y7TUQ, nsekhar-l0cyMroinI0,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, robh-DgEjT+Ai2ygdnm+yROfE0A,
devicetree-u79uwXL29TY76Z2rM5mHXA
On Tue, Jan 16, 2018 at 04:46:12PM +0530, Kishon Vijay Abraham I wrote:
[...]
> > +static struct platform_driver cdns_pcie_host_driver = {
> > + .driver = {
> > + .name = "cdns-pcie-host",
> > + .of_match_table = cdns_pcie_host_of_match,
> > + },
> > + .probe = cdns_pcie_host_probe,
> > +};
>
> In the case of DWC, designware core is modeled as a library which has
> API's to be invoked by various platform specific glue drivers.
>
> But with the cadence approach we'll have two separate drivers: the
> cadence core driver and the platform specific glue drivers. Is this
> approach chosen for a specific reason?
That's a fair point but I do not think that's a concern at the moment.
If/when other platform drivers are built around the generic IP we just
have to refactor this driver and turn into a core library + a PCI host
bridge driver like dwc does, at the moment I do not necessarily see the
reason for splitting them.
Cyrille ?
Thanks,
Lorenzo
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v3 3/6] PCI: Add generic function to probe PCI host controllers
2018-01-10 22:47 ` [PATCH v3 3/6] PCI: Add generic function to probe PCI host controllers Cyrille Pitchen
@ 2018-01-16 15:25 ` Lorenzo Pieralisi
2018-01-18 22:58 ` Cyrille Pitchen
0 siblings, 1 reply; 14+ messages in thread
From: Lorenzo Pieralisi @ 2018-01-16 15:25 UTC (permalink / raw)
To: Cyrille Pitchen
Cc: bhelgaas, kishon, linux-pci, adouglas, stelford, dgary, kgopi,
eandrews, thomas.petazzoni, sureshp, nsekhar, linux-kernel, robh,
devicetree
On Wed, Jan 10, 2018 at 11:47:32PM +0100, Cyrille Pitchen wrote:
> This patchs moves generic source code from
> drivers/pci/host/pci-host-common.c into drivers/pci/probe.c.
>
> Indeed the extracted lines of code were duplicated by many host
> controller drivers. Regrouping them into a generic function gives a
> change to properly share this code without introducing a useless
> dependency to PCI_HOST_COMMON, which selects PCI_ECAM when not needed by
> most host controller drivers.
>
> We also add a missing call of pci_free_resource_list() from
> pci_host_common_probe() when probing fails, as done inside gen_pci_init()
I have to ask you to split this change into another patch.
First add the missing pci_free_resource_list() then add this patch.
Do you have time to respin quickly ? I would like to merge this
series for v4.16.
Thanks,
Lorenzo
> when this later function fails.
>
> Signed-off-by: Cyrille Pitchen <cyrille.pitchen@free-electrons.com>
> ---
> drivers/pci/host/pci-host-common.c | 25 +++----------------------
> drivers/pci/probe.c | 33 +++++++++++++++++++++++++++++++++
> include/linux/pci.h | 1 +
> 3 files changed, 37 insertions(+), 22 deletions(-)
>
> diff --git a/drivers/pci/host/pci-host-common.c b/drivers/pci/host/pci-host-common.c
> index a613ea310e76..df25b4a4edaf 100644
> --- a/drivers/pci/host/pci-host-common.c
> +++ b/drivers/pci/host/pci-host-common.c
> @@ -72,7 +72,6 @@ int pci_host_common_probe(struct platform_device *pdev,
> const char *type;
> struct device *dev = &pdev->dev;
> struct device_node *np = dev->of_node;
> - struct pci_bus *bus, *child;
> struct pci_host_bridge *bridge;
> struct pci_config_window *cfg;
> struct list_head resources;
> @@ -107,29 +106,11 @@ int pci_host_common_probe(struct platform_device *pdev,
> bridge->map_irq = of_irq_parse_and_map_pci;
> bridge->swizzle_irq = pci_common_swizzle;
>
> - ret = pci_scan_root_bus_bridge(bridge);
> - if (ret < 0) {
> - dev_err(dev, "Scanning root bridge failed");
> + ret = pci_host_probe(bridge);
> + if (ret) {
> + pci_free_resource_list(&resources);
> return ret;
> }
>
> - bus = bridge->bus;
> -
> - /*
> - * We insert PCI resources into the iomem_resource and
> - * ioport_resource trees in either pci_bus_claim_resources()
> - * or pci_bus_assign_resources().
> - */
> - if (pci_has_flag(PCI_PROBE_ONLY)) {
> - pci_bus_claim_resources(bus);
> - } else {
> - pci_bus_size_bridges(bus);
> - pci_bus_assign_resources(bus);
> -
> - list_for_each_entry(child, &bus->children, node)
> - pcie_bus_configure_settings(child);
> - }
> -
> - pci_bus_add_devices(bus);
> return 0;
> }
> diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
> index 1360db508035..178328d06a32 100644
> --- a/drivers/pci/probe.c
> +++ b/drivers/pci/probe.c
> @@ -2685,6 +2685,39 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
> }
> EXPORT_SYMBOL_GPL(pci_create_root_bus);
>
> +int pci_host_probe(struct pci_host_bridge *bridge)
> +{
> + struct pci_bus *bus, *child;
> + int ret;
> +
> + ret = pci_scan_root_bus_bridge(bridge);
> + if (ret < 0) {
> + dev_err(bridge->dev.parent, "Scanning root bridge failed");
> + return ret;
> + }
> +
> + bus = bridge->bus;
> +
> + /*
> + * We insert PCI resources into the iomem_resource and
> + * ioport_resource trees in either pci_bus_claim_resources()
> + * or pci_bus_assign_resources().
> + */
> + if (pci_has_flag(PCI_PROBE_ONLY)) {
> + pci_bus_claim_resources(bus);
> + } else {
> + pci_bus_size_bridges(bus);
> + pci_bus_assign_resources(bus);
> +
> + list_for_each_entry(child, &bus->children, node)
> + pcie_bus_configure_settings(child);
> + }
> +
> + pci_bus_add_devices(bus);
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(pci_host_probe);
> +
> int pci_bus_insert_busn_res(struct pci_bus *b, int bus, int bus_max)
> {
> struct resource *res = &b->busn_res;
> diff --git a/include/linux/pci.h b/include/linux/pci.h
> index a1b0672fd38a..0ca261fda900 100644
> --- a/include/linux/pci.h
> +++ b/include/linux/pci.h
> @@ -879,6 +879,7 @@ struct pci_bus *pci_scan_bus(int bus, struct pci_ops *ops, void *sysdata);
> struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
> struct pci_ops *ops, void *sysdata,
> struct list_head *resources);
> +int pci_host_probe(struct pci_host_bridge *bridge);
> int pci_bus_insert_busn_res(struct pci_bus *b, int bus, int busmax);
> int pci_bus_update_busn_res_end(struct pci_bus *b, int busmax);
> void pci_bus_release_busn_res(struct pci_bus *b);
> --
> 2.11.0
>
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v3 6/6] PCI: cadence: Add host driver for Cadence PCIe controller
2018-01-10 22:47 ` [PATCH v3 6/6] PCI: cadence: Add host driver for Cadence PCIe controller Cyrille Pitchen
2018-01-16 11:16 ` Kishon Vijay Abraham I
@ 2018-01-16 16:07 ` Lorenzo Pieralisi
[not found] ` <20180116160733.GA3644-4tUPXFaYRHv6sAKXYmQ0tx/iLCjYCKR+VpNB7YpNyf8@public.gmane.org>
1 sibling, 1 reply; 14+ messages in thread
From: Lorenzo Pieralisi @ 2018-01-16 16:07 UTC (permalink / raw)
To: Cyrille Pitchen
Cc: bhelgaas, kishon, linux-pci, adouglas, stelford, dgary, kgopi,
eandrews, thomas.petazzoni, sureshp, nsekhar, linux-kernel, robh,
devicetree
On Wed, Jan 10, 2018 at 11:47:35PM +0100, Cyrille Pitchen wrote:
> This patch adds support to the Cadence PCIe controller in host mode.
>
> Signed-off-by: Cyrille Pitchen <cyrille.pitchen@free-electrons.com>
> ---
> MAINTAINERS | 7 +
> drivers/pci/Kconfig | 1 +
> drivers/pci/Makefile | 1 +
> drivers/pci/cadence/Kconfig | 16 ++
> drivers/pci/cadence/Makefile | 3 +
> drivers/pci/cadence/pcie-cadence-host.c | 336 ++++++++++++++++++++++++++++++++
> drivers/pci/cadence/pcie-cadence.c | 68 +++++++
> drivers/pci/cadence/pcie-cadence.h | 196 +++++++++++++++++++
[...]
> +void cdns_pcie_reset_outbound_region(struct cdns_pcie *pcie, u32 r)
> +{
> + cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_PCI_ADDR0(r), 0);
> + cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_PCI_ADDR1(r), 0);
> +
> + cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC0(r), 0);
> + cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC1(r), 0);
> +
> + cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR0(r), 0);
> + cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR1(r), 0);
> +}
Unused function, please remove it.
> diff --git a/drivers/pci/cadence/pcie-cadence.h b/drivers/pci/cadence/pcie-cadence.h
> new file mode 100644
> index 000000000000..3a15b4016352
> --- /dev/null
> +++ b/drivers/pci/cadence/pcie-cadence.h
> @@ -0,0 +1,196 @@
> +// SPDX-License-Identifier: GPL-2.0
> +// Copyright (c) 2017 Cadence
> +// Cadence PCIe controller driver.
> +// Author: Cyrille Pitchen <cyrille.pitchen@free-electrons.com>
> +
> +#ifndef _PCIE_CADENCE_H
> +#define _PCIE_CADENCE_H
> +
> +#include <linux/kernel.h>
> +#include <linux/pci.h>
> +
> +/*
> + * Local Management Registers
> + */
> +#define CDNS_PCIE_LM_BASE 0x00100000
> +
> +/* Vendor ID Register */
> +#define CDNS_PCIE_LM_ID (CDNS_PCIE_LM_BASE + 0x0044)
> +#define CDNS_PCIE_LM_ID_VENDOR_MASK GENMASK(15, 0)
> +#define CDNS_PCIE_LM_ID_VENDOR_SHIFT 0
> +#define CDNS_PCIE_LM_ID_VENDOR(vid) \
> + (((vid) << CDNS_PCIE_LM_ID_VENDOR_SHIFT) & CDNS_PCIE_LM_ID_VENDOR_MASK)
> +#define CDNS_PCIE_LM_ID_SUBSYS_MASK GENMASK(31, 16)
> +#define CDNS_PCIE_LM_ID_SUBSYS_SHIFT 16
> +#define CDNS_PCIE_LM_ID_SUBSYS(sub) \
> + (((sub) << CDNS_PCIE_LM_ID_SUBSYS_SHIFT) & CDNS_PCIE_LM_ID_SUBSYS_MASK)
> +
> +/* Root Port Requestor ID Register */
> +#define CDNS_PCIE_LM_RP_RID (CDNS_PCIE_LM_BASE + 0x0228)
> +#define CDNS_PCIE_LM_RP_RID_MASK GENMASK(15, 0)
> +#define CDNS_PCIE_LM_RP_RID_SHIFT 0
> +#define CDNS_PCIE_LM_RP_RID_(rid) \
> + (((rid) << CDNS_PCIE_LM_RP_RID_SHIFT) & CDNS_PCIE_LM_RP_RID_MASK)
> +
> +/* Root Complex BAR Configuration Register */
> +#define CDNS_PCIE_LM_RC_BAR_CFG (CDNS_PCIE_LM_BASE + 0x0300)
> +#define CDNS_PCIE_LM_RC_BAR_CFG_BAR0_APERTURE_MASK GENMASK(5, 0)
> +#define CDNS_PCIE_LM_RC_BAR_CFG_BAR0_APERTURE(a) \
> + (((a) << 0) & CDNS_PCIE_LM_RC_BAR_CFG_BAR0_APERTURE_MASK)
> +#define CDNS_PCIE_LM_RC_BAR_CFG_BAR0_CTRL_MASK GENMASK(8, 6)
> +#define CDNS_PCIE_LM_RC_BAR_CFG_BAR0_CTRL(c) \
> + (((c) << 6) & CDNS_PCIE_LM_RC_BAR_CFG_BAR0_CTRL_MASK)
> +#define CDNS_PCIE_LM_RC_BAR_CFG_BAR1_APERTURE_MASK GENMASK(13, 9)
> +#define CDNS_PCIE_LM_RC_BAR_CFG_BAR1_APERTURE(a) \
> + (((a) << 9) & CDNS_PCIE_LM_RC_BAR_CFG_BAR1_APERTURE_MASK)
> +#define CDNS_PCIE_LM_RC_BAR_CFG_BAR1_CTRL_MASK GENMASK(16, 14)
> +#define CDNS_PCIE_LM_RC_BAR_CFG_BAR1_CTRL(c) \
> + (((c) << 14) & CDNS_PCIE_LM_RC_BAR_CFG_BAR1_CTRL_MASK)
> +#define CDNS_PCIE_LM_RC_BAR_CFG_PREFETCH_MEM_ENABLE BIT(17)
> +#define CDNS_PCIE_LM_RC_BAR_CFG_PREFETCH_MEM_32BITS 0
> +#define CDNS_PCIE_LM_RC_BAR_CFG_PREFETCH_MEM_64BITS BIT(18)
> +#define CDNS_PCIE_LM_RC_BAR_CFG_IO_ENABLE BIT(19)
> +#define CDNS_PCIE_LM_RC_BAR_CFG_IO_16BITS 0
> +#define CDNS_PCIE_LM_RC_BAR_CFG_IO_32BITS BIT(20)
> +#define CDNS_PCIE_LM_RC_BAR_CFG_CHECK_ENABLE BIT(31)
> +
> +/* BAR control values applicable to both Endpoint Function and Root Complex */
> +#define CDNS_PCIE_LM_BAR_CFG_CTRL_DISABLED 0x0
> +#define CDNS_PCIE_LM_BAR_CFG_CTRL_IO_32BITS 0x1
> +#define CDNS_PCIE_LM_BAR_CFG_CTRL_MEM_32BITS 0x4
> +#define CDNS_PCIE_LM_BAR_CFG_CTRL_PREFETCH_MEM_32BITS 0x5
> +#define CDNS_PCIE_LM_BAR_CFG_CTRL_MEM_64BITS 0x6
> +#define CDNS_PCIE_LM_BAR_CFG_CTRL_PREFETCH_MEM_64BITS 0x7
> +
> +
> +/*
> + * Root Port Registers (PCI configuration space for the root port function)
> + */
> +#define CDNS_PCIE_RP_BASE 0x00200000
> +
> +
> +/*
> + * Address Translation Registers
> + */
> +#define CDNS_PCIE_AT_BASE 0x00400000
> +
> +/* Region r Outbound AXI to PCIe Address Translation Register 0 */
> +#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0(r) \
> + (CDNS_PCIE_AT_BASE + 0x0000 + ((r) & 0x1f) * 0x0020)
> +#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_NBITS_MASK GENMASK(5, 0)
> +#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_NBITS(nbits) \
> + (((nbits) - 1) & CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_NBITS_MASK)
> +#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_DEVFN_MASK GENMASK(19, 12)
> +#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_DEVFN(devfn) \
> + (((devfn) << 12) & CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_DEVFN_MASK)
> +#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_BUS_MASK GENMASK(27, 20)
> +#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_BUS(bus) \
> + (((bus) << 20) & CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_BUS_MASK)
> +
> +/* Region r Outbound AXI to PCIe Address Translation Register 1 */
> +#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR1(r) \
> + (CDNS_PCIE_AT_BASE + 0x0004 + ((r) & 0x1f) * 0x0020)
> +
> +/* Region r Outbound PCIe Descriptor Register 0 */
> +#define CDNS_PCIE_AT_OB_REGION_DESC0(r) \
> + (CDNS_PCIE_AT_BASE + 0x0008 + ((r) & 0x1f) * 0x0020)
> +#define CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_MASK GENMASK(3, 0)
> +#define CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_MEM 0x2
> +#define CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_IO 0x6
> +#define CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_CONF_TYPE0 0xa
> +#define CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_CONF_TYPE1 0xb
> +#define CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_NORMAL_MSG 0xc
> +#define CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_VENDOR_MSG 0xd
> +/* Bit 23 MUST be set in RC mode. */
> +#define CDNS_PCIE_AT_OB_REGION_DESC0_HARDCODED_RID BIT(23)
> +#define CDNS_PCIE_AT_OB_REGION_DESC0_DEVFN_MASK GENMASK(31, 24)
> +#define CDNS_PCIE_AT_OB_REGION_DESC0_DEVFN(devfn) \
> + (((devfn) << 24) & CDNS_PCIE_AT_OB_REGION_DESC0_DEVFN_MASK)
> +
> +/* Region r Outbound PCIe Descriptor Register 1 */
> +#define CDNS_PCIE_AT_OB_REGION_DESC1(r) \
> + (CDNS_PCIE_AT_BASE + 0x000c + ((r) & 0x1f) * 0x0020)
> +#define CDNS_PCIE_AT_OB_REGION_DESC1_BUS_MASK GENMASK(7, 0)
> +#define CDNS_PCIE_AT_OB_REGION_DESC1_BUS(bus) \
> + ((bus) & CDNS_PCIE_AT_OB_REGION_DESC1_BUS_MASK)
> +
> +/* Region r AXI Region Base Address Register 0 */
> +#define CDNS_PCIE_AT_OB_REGION_CPU_ADDR0(r) \
> + (CDNS_PCIE_AT_BASE + 0x0018 + ((r) & 0x1f) * 0x0020)
> +#define CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS_MASK GENMASK(5, 0)
> +#define CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS(nbits) \
> + (((nbits) - 1) & CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS_MASK)
> +
> +/* Region r AXI Region Base Address Register 1 */
> +#define CDNS_PCIE_AT_OB_REGION_CPU_ADDR1(r) \
> + (CDNS_PCIE_AT_BASE + 0x001c + ((r) & 0x1f) * 0x0020)
> +
> +/* Root Port BAR Inbound PCIe to AXI Address Translation Register */
> +#define CDNS_PCIE_AT_IB_RP_BAR_ADDR0(bar) \
> + (CDNS_PCIE_AT_BASE + 0x0800 + (bar) * 0x0008)
> +#define CDNS_PCIE_AT_IB_RP_BAR_ADDR0_NBITS_MASK GENMASK(5, 0)
> +#define CDNS_PCIE_AT_IB_RP_BAR_ADDR0_NBITS(nbits) \
> + (((nbits) - 1) & CDNS_PCIE_AT_IB_RP_BAR_ADDR0_NBITS_MASK)
> +#define CDNS_PCIE_AT_IB_RP_BAR_ADDR1(bar) \
> + (CDNS_PCIE_AT_BASE + 0x0804 + (bar) * 0x0008)
> +
> +enum cdns_pcie_rp_bar {
> + RP_BAR0,
> + RP_BAR1,
> + RP_NO_BAR
> +};
> +
> +/**
> + * struct cdns_pcie - private data for Cadence PCIe controller drivers
> + * @reg_base: IO mapped register base
> + * @mem_res: start/end offsets in the physical system memory to map PCI accesses
> + * @is_rc: tell whether the PCIe controller mode is Root Complex or Endpoint.
> + * @bus: In Root Complex mode, the bus number
> + */
> +struct cdns_pcie {
> + void __iomem *reg_base;
> + struct resource *mem_res;
> + bool is_rc;
> + u8 bus;
> +};
> +
> +/* Register access */
> +static inline void cdns_pcie_writeb(struct cdns_pcie *pcie, u32 reg, u8 value)
> +{
> + writeb(value, pcie->reg_base + reg);
> +}
> +
> +static inline void cdns_pcie_writew(struct cdns_pcie *pcie, u32 reg, u16 value)
> +{
> + writew(value, pcie->reg_base + reg);
> +}
> +
> +static inline void cdns_pcie_writel(struct cdns_pcie *pcie, u32 reg, u32 value)
> +{
> + writel(value, pcie->reg_base + reg);
> +}
> +
> +static inline u32 cdns_pcie_readl(struct cdns_pcie *pcie, u32 reg)
> +{
> + return readl(pcie->reg_base + reg);
> +}
> +
> +/* Root Port register access */
> +static inline void cdns_pcie_rp_writeb(struct cdns_pcie *pcie,
> + u32 reg, u8 value)
> +{
> + writeb(value, pcie->reg_base + CDNS_PCIE_RP_BASE + reg);
> +}
> +
> +static inline void cdns_pcie_rp_writew(struct cdns_pcie *pcie,
> + u32 reg, u16 value)
> +{
> + writew(value, pcie->reg_base + CDNS_PCIE_RP_BASE + reg);
> +}
> +
> +void cdns_pcie_set_outbound_region(struct cdns_pcie *pcie, u32 r, bool is_io,
> + u64 cpu_addr, u64 pci_addr, size_t size);
> +
> +void cdns_pcie_reset_outbound_region(struct cdns_pcie *pcie, u32 r);
Ditto. I understand it is hard to untangle code that was written with
both EP and host bridge support in mind but, as I state below every
patch has to make sense on its own.
> +
> +#endif /* _PCIE_CADENCE_H */
Technically speaking, this 3-file (.c .h) split is not necessary and can
turn out unnecessary churn if we never merge the endpoint code -
actually you would not even need a special cadence directory, just a
host bridge driver file.
Bottom line, as you know: every patch has to be self contained.
It is already quite late -rc, I understand that changes this late
are error prone so I will accept that this file splitting is necessary
for "future" patches - if you manage to squash changes into a file I'd
appreciate though, it does not make sense to export functions that are
used in just one compilation unit (and some that are not used at all).
Thanks,
Lorenzo
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v3 3/6] PCI: Add generic function to probe PCI host controllers
2018-01-16 15:25 ` Lorenzo Pieralisi
@ 2018-01-18 22:58 ` Cyrille Pitchen
0 siblings, 0 replies; 14+ messages in thread
From: Cyrille Pitchen @ 2018-01-18 22:58 UTC (permalink / raw)
To: Lorenzo Pieralisi
Cc: bhelgaas-hpIqsD4AKlfQT0dZR+AlfA, kishon-l0cyMroinI0,
linux-pci-u79uwXL29TY76Z2rM5mHXA,
adouglas-vna1KIf7WgpBDgjK7y7TUQ, stelford-vna1KIf7WgpBDgjK7y7TUQ,
dgary-vna1KIf7WgpBDgjK7y7TUQ, kgopi-vna1KIf7WgpBDgjK7y7TUQ,
eandrews-vna1KIf7WgpBDgjK7y7TUQ,
thomas.petazzoni-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
sureshp-vna1KIf7WgpBDgjK7y7TUQ, nsekhar-l0cyMroinI0,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, robh-DgEjT+Ai2ygdnm+yROfE0A,
devicetree-u79uwXL29TY76Z2rM5mHXA
Hi Lorenzo,
Le 16/01/2018 à 16:25, Lorenzo Pieralisi a écrit :
> On Wed, Jan 10, 2018 at 11:47:32PM +0100, Cyrille Pitchen wrote:
>> This patchs moves generic source code from
>> drivers/pci/host/pci-host-common.c into drivers/pci/probe.c.
>>
>> Indeed the extracted lines of code were duplicated by many host
>> controller drivers. Regrouping them into a generic function gives a
>> change to properly share this code without introducing a useless
>> dependency to PCI_HOST_COMMON, which selects PCI_ECAM when not needed by
>> most host controller drivers.
>>
>> We also add a missing call of pci_free_resource_list() from
>> pci_host_common_probe() when probing fails, as done inside gen_pci_init()
> I have to ask you to split this change into another patch.
>
> First add the missing pci_free_resource_list() then add this patch.
>
> Do you have time to respin quickly ? I would like to merge this
> series for v4.16.
>
Sorry, I've been a little bit busy. I've just done it and submit v4.
patch 3 from v3 split into patches 3 and 4 in v4.
Best regards,
Cyrille
> Thanks,
> Lorenzo
>
>> when this later function fails.
>>
>> Signed-off-by: Cyrille Pitchen <cyrille.pitchen-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
>> ---
>> drivers/pci/host/pci-host-common.c | 25 +++----------------------
>> drivers/pci/probe.c | 33 +++++++++++++++++++++++++++++++++
>> include/linux/pci.h | 1 +
>> 3 files changed, 37 insertions(+), 22 deletions(-)
>>
>> diff --git a/drivers/pci/host/pci-host-common.c b/drivers/pci/host/pci-host-common.c
>> index a613ea310e76..df25b4a4edaf 100644
>> --- a/drivers/pci/host/pci-host-common.c
>> +++ b/drivers/pci/host/pci-host-common.c
>> @@ -72,7 +72,6 @@ int pci_host_common_probe(struct platform_device *pdev,
>> const char *type;
>> struct device *dev = &pdev->dev;
>> struct device_node *np = dev->of_node;
>> - struct pci_bus *bus, *child;
>> struct pci_host_bridge *bridge;
>> struct pci_config_window *cfg;
>> struct list_head resources;
>> @@ -107,29 +106,11 @@ int pci_host_common_probe(struct platform_device *pdev,
>> bridge->map_irq = of_irq_parse_and_map_pci;
>> bridge->swizzle_irq = pci_common_swizzle;
>>
>> - ret = pci_scan_root_bus_bridge(bridge);
>> - if (ret < 0) {
>> - dev_err(dev, "Scanning root bridge failed");
>> + ret = pci_host_probe(bridge);
>> + if (ret) {
>> + pci_free_resource_list(&resources);
>> return ret;
>> }
>>
>> - bus = bridge->bus;
>> -
>> - /*
>> - * We insert PCI resources into the iomem_resource and
>> - * ioport_resource trees in either pci_bus_claim_resources()
>> - * or pci_bus_assign_resources().
>> - */
>> - if (pci_has_flag(PCI_PROBE_ONLY)) {
>> - pci_bus_claim_resources(bus);
>> - } else {
>> - pci_bus_size_bridges(bus);
>> - pci_bus_assign_resources(bus);
>> -
>> - list_for_each_entry(child, &bus->children, node)
>> - pcie_bus_configure_settings(child);
>> - }
>> -
>> - pci_bus_add_devices(bus);
>> return 0;
>> }
>> diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
>> index 1360db508035..178328d06a32 100644
>> --- a/drivers/pci/probe.c
>> +++ b/drivers/pci/probe.c
>> @@ -2685,6 +2685,39 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
>> }
>> EXPORT_SYMBOL_GPL(pci_create_root_bus);
>>
>> +int pci_host_probe(struct pci_host_bridge *bridge)
>> +{
>> + struct pci_bus *bus, *child;
>> + int ret;
>> +
>> + ret = pci_scan_root_bus_bridge(bridge);
>> + if (ret < 0) {
>> + dev_err(bridge->dev.parent, "Scanning root bridge failed");
>> + return ret;
>> + }
>> +
>> + bus = bridge->bus;
>> +
>> + /*
>> + * We insert PCI resources into the iomem_resource and
>> + * ioport_resource trees in either pci_bus_claim_resources()
>> + * or pci_bus_assign_resources().
>> + */
>> + if (pci_has_flag(PCI_PROBE_ONLY)) {
>> + pci_bus_claim_resources(bus);
>> + } else {
>> + pci_bus_size_bridges(bus);
>> + pci_bus_assign_resources(bus);
>> +
>> + list_for_each_entry(child, &bus->children, node)
>> + pcie_bus_configure_settings(child);
>> + }
>> +
>> + pci_bus_add_devices(bus);
>> + return 0;
>> +}
>> +EXPORT_SYMBOL_GPL(pci_host_probe);
>> +
>> int pci_bus_insert_busn_res(struct pci_bus *b, int bus, int bus_max)
>> {
>> struct resource *res = &b->busn_res;
>> diff --git a/include/linux/pci.h b/include/linux/pci.h
>> index a1b0672fd38a..0ca261fda900 100644
>> --- a/include/linux/pci.h
>> +++ b/include/linux/pci.h
>> @@ -879,6 +879,7 @@ struct pci_bus *pci_scan_bus(int bus, struct pci_ops *ops, void *sysdata);
>> struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
>> struct pci_ops *ops, void *sysdata,
>> struct list_head *resources);
>> +int pci_host_probe(struct pci_host_bridge *bridge);
>> int pci_bus_insert_busn_res(struct pci_bus *b, int bus, int busmax);
>> int pci_bus_update_busn_res_end(struct pci_bus *b, int busmax);
>> void pci_bus_release_busn_res(struct pci_bus *b);
>> --
>> 2.11.0
>>
>
--
Cyrille Pitchen, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v3 6/6] PCI: cadence: Add host driver for Cadence PCIe controller
[not found] ` <e3d88d5b-e770-d2e5-20b2-62551d5f4f8f-l0cyMroinI0@public.gmane.org>
2018-01-16 15:09 ` Lorenzo Pieralisi
@ 2018-01-18 23:13 ` Cyrille Pitchen
1 sibling, 0 replies; 14+ messages in thread
From: Cyrille Pitchen @ 2018-01-18 23:13 UTC (permalink / raw)
To: Kishon Vijay Abraham I, bhelgaas-hpIqsD4AKlfQT0dZR+AlfA,
lorenzo.pieralisi-5wv7dgnIgG8, linux-pci-u79uwXL29TY76Z2rM5mHXA
Cc: adouglas-vna1KIf7WgpBDgjK7y7TUQ, stelford-vna1KIf7WgpBDgjK7y7TUQ,
dgary-vna1KIf7WgpBDgjK7y7TUQ, kgopi-vna1KIf7WgpBDgjK7y7TUQ,
eandrews-vna1KIf7WgpBDgjK7y7TUQ,
thomas.petazzoni-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
sureshp-vna1KIf7WgpBDgjK7y7TUQ, nsekhar-l0cyMroinI0,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, robh-DgEjT+Ai2ygdnm+yROfE0A,
devicetree-u79uwXL29TY76Z2rM5mHXA
Hi Kishon,
Le 16/01/2018 à 12:16, Kishon Vijay Abraham I a écrit :
> Hi Cyrille,
>
> On Thursday 11 January 2018 04:17 AM, Cyrille Pitchen wrote:
>> This patch adds support to the Cadence PCIe controller in host mode.
>>
>> Signed-off-by: Cyrille Pitchen <cyrille.pitchen-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
>> ---
>> MAINTAINERS | 7 +
>> drivers/pci/Kconfig | 1 +
>> drivers/pci/Makefile | 1 +
>> drivers/pci/cadence/Kconfig | 16 ++
>> drivers/pci/cadence/Makefile | 3 +
>> drivers/pci/cadence/pcie-cadence-host.c | 336 ++++++++++++++++++++++++++++++++
>> drivers/pci/cadence/pcie-cadence.c | 68 +++++++
>> drivers/pci/cadence/pcie-cadence.h | 196 +++++++++++++++++++
>> 8 files changed, 628 insertions(+)
>> create mode 100644 drivers/pci/cadence/Kconfig
>> create mode 100644 drivers/pci/cadence/Makefile
>> create mode 100644 drivers/pci/cadence/pcie-cadence-host.c
>> create mode 100644 drivers/pci/cadence/pcie-cadence.c
>> create mode 100644 drivers/pci/cadence/pcie-cadence.h
>>
>> diff --git a/MAINTAINERS b/MAINTAINERS
>> index 13945646b95d..cc24c74a946e 100644
>> --- a/MAINTAINERS
>> +++ b/MAINTAINERS
>> @@ -10402,6 +10402,13 @@ S: Maintained
>> F: Documentation/devicetree/bindings/pci/pci-armada8k.txt
>> F: drivers/pci/dwc/pcie-armada8k.c
>>
>> +PCI DRIVER FOR CADENCE PCIE IP
>> +M: Alan Douglas <adouglas-vna1KIf7WgpBDgjK7y7TUQ@public.gmane.org>
>> +L: linux-pci-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
>> +S: Maintained
>> +F: Documentation/devicetree/bindings/pci/cdns,*.txt
>> +F: drivers/pci/cadence/pcie-cadence*
>> +
>> PCI DRIVER FOR FREESCALE LAYERSCAPE
>> M: Minghuan Lian <minghuan.Lian-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
>> M: Mingkai Hu <mingkai.hu-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
>> diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
>> index 7eeb969ab86a..dee90cc1dcaf 100644
>> --- a/drivers/pci/Kconfig
>> +++ b/drivers/pci/Kconfig
>> @@ -136,6 +136,7 @@ config PCI_HYPERV
>> PCI devices from a PCI backend to support PCI driver domains.
>>
>> source "drivers/pci/hotplug/Kconfig"
>> +source "drivers/pci/cadence/Kconfig"
>> source "drivers/pci/dwc/Kconfig"
>> source "drivers/pci/host/Kconfig"
>> source "drivers/pci/endpoint/Kconfig"
>> diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
>> index ddb5aa6640d7..941970936840 100644
>> --- a/drivers/pci/Makefile
>> +++ b/drivers/pci/Makefile
>> @@ -56,5 +56,6 @@ obj-y += switch/
>> obj-$(CONFIG_PCI_ENDPOINT) += endpoint/
>>
>> # Endpoint library must be initialized before its users
>> +obj-$(CONFIG_PCIE_CADENCE) += cadence/
>> # pcie-hisi.o quirks are needed even without CONFIG_PCIE_DW
>> obj-y += dwc/
>> diff --git a/drivers/pci/cadence/Kconfig b/drivers/pci/cadence/Kconfig
>> new file mode 100644
>> index 000000000000..0123d384a628
>> --- /dev/null
>> +++ b/drivers/pci/cadence/Kconfig
>> @@ -0,0 +1,16 @@
>> +menu "Cadence PCIe controllers support"
>> +
>> +config PCIE_CADENCE
>> + bool
>> +
>> +config PCIE_CADENCE_HOST
>> + bool "Cadence PCIe host controller"
>> + depends on OF
>> + select IRQ_DOMAIN
>> + select PCIE_CADENCE
>> + help
>> + Say Y here if you want to support the Cadence PCIe controller in host
>> + mode. This PCIe controller may be embedded into many different vendors
>> + SoCs.
>> +
>> +endmenu
>> diff --git a/drivers/pci/cadence/Makefile b/drivers/pci/cadence/Makefile
>> new file mode 100644
>> index 000000000000..589601a8ff89
>> --- /dev/null
>> +++ b/drivers/pci/cadence/Makefile
>> @@ -0,0 +1,3 @@
>> +# SPDX-License-Identifier: GPL-2.0
>> +obj-$(CONFIG_PCIE_CADENCE) += pcie-cadence.o
>> +obj-$(CONFIG_PCIE_CADENCE_HOST) += pcie-cadence-host.o
>> diff --git a/drivers/pci/cadence/pcie-cadence-host.c b/drivers/pci/cadence/pcie-cadence-host.c
>> new file mode 100644
>> index 000000000000..26caf8963e3c
>> --- /dev/null
>> +++ b/drivers/pci/cadence/pcie-cadence-host.c
>> @@ -0,0 +1,336 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +// Copyright (c) 2017 Cadence
>> +// Cadence PCIe host controller driver.
>> +// Author: Cyrille Pitchen <cyrille.pitchen-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
>> +
>> +#include <linux/kernel.h>
>> +#include <linux/of_address.h>
>> +#include <linux/of_pci.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/pm_runtime.h>
>> +
>> +#include "pcie-cadence.h"
>> +
>> +/**
>> + * struct cdns_pcie_rc - private data for this PCIe Root Complex driver
>> + * @pcie: Cadence PCIe controller
>> + * @dev: pointer to PCIe device
>> + * @cfg_res: start/end offsets in the physical system memory to map PCI
>> + * configuration space accesses
>> + * @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
>> + * @max_regions: maximum number of regions supported by the hardware
>> + * @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
>> + */
>> +struct cdns_pcie_rc {
>> + struct cdns_pcie pcie;
>> + struct device *dev;
>> + struct resource *cfg_res;
>> + struct resource *bus_range;
>> + void __iomem *cfg_base;
>> + u32 max_regions;
>> + u32 no_bar_nbits;
>> + u16 vendor_id;
>> + u16 device_id;
>> +};
>> +
>> +static 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);
>> + struct cdns_pcie *pcie = &rc->pcie;
>> + unsigned int busn = bus->number;
>> + u32 addr0, desc0;
>> +
>> + if (busn == rc->bus_range->start) {
>> + /*
>> + * Only the root port (devfn == 0) is connected to this bus.
>> + * All other PCI devices are behind some bridge hence on another
>> + * bus.
>> + */
>> + if (devfn)
>> + return NULL;
>> +
>> + return pcie->reg_base + (where & 0xfff);
>> + }
>> +
>> + /* Update Output registers for AXI region 0. */
>> + addr0 = CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_NBITS(12) |
>> + CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_DEVFN(devfn) |
>> + CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_BUS(busn);
>> + cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_PCI_ADDR0(0), addr0);
>> +
>> + /* Configuration Type 0 or Type 1 access. */
>> + desc0 = CDNS_PCIE_AT_OB_REGION_DESC0_HARDCODED_RID |
>> + CDNS_PCIE_AT_OB_REGION_DESC0_DEVFN(0);
>> + /*
>> + * The bus number was already set once for all in desc1 by
>> + * cdns_pcie_host_init_address_translation().
>> + */
>> + if (busn == rc->bus_range->start + 1)
>> + desc0 |= CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_CONF_TYPE0;
>> + else
>> + desc0 |= CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_CONF_TYPE1;
>> + cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC0(0), desc0);
>> +
>> + return rc->cfg_base + (where & 0xfff);
>> +}
>> +
>> +static struct pci_ops cdns_pcie_host_ops = {
>> + .map_bus = cdns_pci_map_bus,
>> + .read = pci_generic_config_read,
>> + .write = pci_generic_config_write,
>> +};
>> +
>> +static const struct of_device_id cdns_pcie_host_of_match[] = {
>> + { .compatible = "cdns,cdns-pcie-host" },
>> +
>> + { },
>> +};
>> +
>> +static int cdns_pcie_host_init_root_port(struct cdns_pcie_rc *rc)
>> +{
>> + struct cdns_pcie *pcie = &rc->pcie;
>> + u32 value, ctrl;
>> +
>> + /*
>> + * Set the root complex BAR configuration register:
>> + * - disable both BAR0 and BAR1.
>> + * - enable Prefetchable Memory Base and Limit registers in type 1
>> + * config space (64 bits).
>> + * - enable IO Base and Limit registers in type 1 config
>> + * space (32 bits).
>> + */
>> + ctrl = CDNS_PCIE_LM_BAR_CFG_CTRL_DISABLED;
>> + value = CDNS_PCIE_LM_RC_BAR_CFG_BAR0_CTRL(ctrl) |
>> + CDNS_PCIE_LM_RC_BAR_CFG_BAR1_CTRL(ctrl) |
>> + CDNS_PCIE_LM_RC_BAR_CFG_PREFETCH_MEM_ENABLE |
>> + CDNS_PCIE_LM_RC_BAR_CFG_PREFETCH_MEM_64BITS |
>> + CDNS_PCIE_LM_RC_BAR_CFG_IO_ENABLE |
>> + CDNS_PCIE_LM_RC_BAR_CFG_IO_32BITS;
>> + 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->device_id != 0xffff)
>> + cdns_pcie_rp_writew(pcie, PCI_DEVICE_ID, rc->device_id);
>> +
>> + cdns_pcie_rp_writeb(pcie, PCI_CLASS_REVISION, 0);
>> + cdns_pcie_rp_writeb(pcie, PCI_CLASS_PROG, 0);
>> + cdns_pcie_rp_writew(pcie, PCI_CLASS_DEVICE, PCI_CLASS_BRIDGE_PCI);
>> +
>> + return 0;
>> +}
>> +
>> +static int cdns_pcie_host_init_address_translation(struct cdns_pcie_rc *rc)
>> +{
>> + struct cdns_pcie *pcie = &rc->pcie;
>> + struct resource *cfg_res = rc->cfg_res;
>> + struct resource *mem_res = pcie->mem_res;
>> + struct resource *bus_range = rc->bus_range;
>> + struct device *dev = rc->dev;
>> + struct device_node *np = dev->of_node;
>> + struct of_pci_range_parser parser;
>> + struct of_pci_range range;
>> + u32 addr0, addr1, desc1;
>> + u64 cpu_addr;
>> + int r, err;
>> +
>> + /*
>> + * Reserve region 0 for PCI configure space accesses:
>> + * OB_REGION_PCI_ADDR0 and OB_REGION_DESC0 are updated dynamically by
>> + * cdns_pci_map_bus(), other region registers are set here once for all.
>> + */
>> + addr1 = 0; /* Should be programmed to zero. */
>> + desc1 = CDNS_PCIE_AT_OB_REGION_DESC1_BUS(bus_range->start);
>> + 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;
>> + addr0 = CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS(12) |
>> + (lower_32_bits(cpu_addr) & GENMASK(31, 8));
>> + addr1 = upper_32_bits(cpu_addr);
>> + cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR0(0), addr0);
>> + cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR1(0), addr1);
>> +
>> + err = of_pci_range_parser_init(&parser, np);
>> + if (err)
>> + return err;
>> +
>> + r = 1;
>> + for_each_of_pci_range(&parser, &range) {
>> + bool is_io;
>> +
>> + if (r >= rc->max_regions)
>> + break;
>> +
>> + if ((range.flags & IORESOURCE_TYPE_BITS) == IORESOURCE_MEM)
>> + is_io = false;
>> + else if ((range.flags & IORESOURCE_TYPE_BITS) == IORESOURCE_IO)
>> + is_io = true;
>> + else
>> + continue;
>> +
>> + cdns_pcie_set_outbound_region(pcie, r, is_io,
>> + range.cpu_addr,
>> + range.pci_addr,
>> + range.size);
>> + 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);
>> +
>> + return 0;
>> +}
>> +
>> +static int cdns_pcie_host_init(struct device *dev,
>> + struct list_head *resources,
>> + struct cdns_pcie_rc *rc)
>> +{
>> + struct resource *bus_range = NULL;
>> + int err;
>> +
>> + /* Parse our PCI ranges and request their resources */
>> + err = pci_parse_request_of_pci_ranges(dev, resources, &bus_range);
>> + if (err)
>> + return err;
>> +
>> + rc->bus_range = bus_range;
>> + rc->pcie.bus = bus_range->start;
>> +
>> + err = cdns_pcie_host_init_root_port(rc);
>> + if (err)
>> + goto err_out;
>> +
>> + err = cdns_pcie_host_init_address_translation(rc);
>> + if (err)
>> + goto err_out;
>> +
>> + return 0;
>> +
>> + err_out:
>> + pci_free_resource_list(resources);
>> + return err;
>> +}
>> +
>> +static int cdns_pcie_host_probe(struct platform_device *pdev)
>> +{
>> + const char *type;
>> + struct device *dev = &pdev->dev;
>> + struct device_node *np = dev->of_node;
>> + struct pci_host_bridge *bridge;
>> + struct list_head resources;
>> + struct cdns_pcie_rc *rc;
>> + struct cdns_pcie *pcie;
>> + struct resource *res;
>> + int ret;
>> +
>> + bridge = devm_pci_alloc_host_bridge(dev, sizeof(*rc));
>> + if (!bridge)
>> + return -ENOMEM;
>> +
>> + rc = pci_host_bridge_priv(bridge);
>> + rc->dev = dev;
>> +
>> + pcie = &rc->pcie;
>> + pcie->is_rc = true;
>> +
>> + rc->max_regions = 32;
>> + of_property_read_u32(np, "cdns,max-outbound-regions", &rc->max_regions);
>> +
>> + 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_u16(np, "vendor-id", &rc->vendor_id);
>> +
>> + rc->device_id = 0xffff;
>> + of_property_read_u16(np, "device-id", &rc->device_id);
>> +
>> + type = of_get_property(np, "device_type", NULL);
>> + if (!type || strcmp(type, "pci")) {
>> + dev_err(dev, "invalid \"device_type\" %s\n", type);
>> + return -EINVAL;
>> + }
>> +
>> + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "reg");
>> + pcie->reg_base = devm_ioremap_resource(dev, res);
>> + if (IS_ERR(pcie->reg_base)) {
>> + dev_err(dev, "missing \"reg\"\n");
>> + return PTR_ERR(pcie->reg_base);
>> + }
>> +
>> + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cfg");
>> + rc->cfg_base = devm_pci_remap_cfg_resource(dev, res);
>> + if (IS_ERR(rc->cfg_base)) {
>> + dev_err(dev, "missing \"cfg\"\n");
>> + return PTR_ERR(rc->cfg_base);
>> + }
>> + 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;
>> +
>> + 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 = cdns_pcie_host_init(dev, &resources, rc);
>> + if (ret)
>> + goto err_init;
>> +
>> + list_splice_init(&resources, &bridge->windows);
>> + bridge->dev.parent = dev;
>> + bridge->busnr = pcie->bus;
>> + bridge->ops = &cdns_pcie_host_ops;
>> + bridge->map_irq = of_irq_parse_and_map_pci;
>> + bridge->swizzle_irq = pci_common_swizzle;
>> +
>> + ret = pci_host_probe(bridge);
>> + if (ret < 0)
>> + goto err_host_probe;
>> +
>> + return 0;
>> +
>> + err_host_probe:
>> + pci_free_resource_list(&resources);
>> +
>> + err_init:
>> + pm_runtime_put_sync(dev);
>> +
>> + err_get_sync:
>> + pm_runtime_disable(dev);
>> +
>> + return ret;
>> +}
>> +
>> +static struct platform_driver cdns_pcie_host_driver = {
>> + .driver = {
>> + .name = "cdns-pcie-host",
>> + .of_match_table = cdns_pcie_host_of_match,
>> + },
>> + .probe = cdns_pcie_host_probe,
>> +};
>
> In the case of DWC, designware core is modeled as a library which has API's to
> be invoked by various platform specific glue drivers.
>
> But with the cadence approach we'll have two separate drivers: the cadence core
> driver and the platform specific glue drivers. Is this approach chosen for a
> specific reason?
I don't know yet how many chips will integrate the Cadence PCIe controller
or what customizations would be required. I thought we may have a chance to
handle all the variants with different 'compatible' DT values and their
associated .data in the 'struct of_device_id', or maybe with some
additional DT properties but still the single pcie-cadence-host.c file to
drive all host flavors.
Also I was thinking about regrouping all endpoint flavors in
pcie-cadence-enpoint.c.
I can't figure out yet whether it would be enough.
Best regards,
Cyrille
>
> Thanks
> Kishon
>
--
Cyrille Pitchen, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v3 6/6] PCI: cadence: Add host driver for Cadence PCIe controller
[not found] ` <20180116160733.GA3644-4tUPXFaYRHv6sAKXYmQ0tx/iLCjYCKR+VpNB7YpNyf8@public.gmane.org>
@ 2018-01-18 23:23 ` Cyrille Pitchen
0 siblings, 0 replies; 14+ messages in thread
From: Cyrille Pitchen @ 2018-01-18 23:23 UTC (permalink / raw)
To: Lorenzo Pieralisi
Cc: bhelgaas-hpIqsD4AKlfQT0dZR+AlfA, kishon-l0cyMroinI0,
linux-pci-u79uwXL29TY76Z2rM5mHXA,
adouglas-vna1KIf7WgpBDgjK7y7TUQ, stelford-vna1KIf7WgpBDgjK7y7TUQ,
dgary-vna1KIf7WgpBDgjK7y7TUQ, kgopi-vna1KIf7WgpBDgjK7y7TUQ,
eandrews-vna1KIf7WgpBDgjK7y7TUQ,
thomas.petazzoni-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
sureshp-vna1KIf7WgpBDgjK7y7TUQ, nsekhar-l0cyMroinI0,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, robh-DgEjT+Ai2ygdnm+yROfE0A,
devicetree-u79uwXL29TY76Z2rM5mHXA
Hi Lorenzo
Le 16/01/2018 à 17:07, Lorenzo Pieralisi a écrit :
> On Wed, Jan 10, 2018 at 11:47:35PM +0100, Cyrille Pitchen wrote:
>> This patch adds support to the Cadence PCIe controller in host mode.
>>
>> Signed-off-by: Cyrille Pitchen <cyrille.pitchen-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
>> ---
>> MAINTAINERS | 7 +
>> drivers/pci/Kconfig | 1 +
>> drivers/pci/Makefile | 1 +
>> drivers/pci/cadence/Kconfig | 16 ++
>> drivers/pci/cadence/Makefile | 3 +
>> drivers/pci/cadence/pcie-cadence-host.c | 336 ++++++++++++++++++++++++++++++++
>> drivers/pci/cadence/pcie-cadence.c | 68 +++++++
>> drivers/pci/cadence/pcie-cadence.h | 196 +++++++++++++++++++
>
> [...]
>
>> +void cdns_pcie_reset_outbound_region(struct cdns_pcie *pcie, u32 r)
>> +{
>> + cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_PCI_ADDR0(r), 0);
>> + cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_PCI_ADDR1(r), 0);
>> +
>> + cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC0(r), 0);
>> + cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC1(r), 0);
>> +
>> + cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR0(r), 0);
>> + cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR1(r), 0);
>> +}
>
> Unused function, please remove it.
done in v4.
>
>> diff --git a/drivers/pci/cadence/pcie-cadence.h b/drivers/pci/cadence/pcie-cadence.h
>> new file mode 100644
>> index 000000000000..3a15b4016352
>> --- /dev/null
>> +++ b/drivers/pci/cadence/pcie-cadence.h
>> @@ -0,0 +1,196 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +// Copyright (c) 2017 Cadence
>> +// Cadence PCIe controller driver.
>> +// Author: Cyrille Pitchen <cyrille.pitchen-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
>> +
>> +#ifndef _PCIE_CADENCE_H
>> +#define _PCIE_CADENCE_H
>> +
>> +#include <linux/kernel.h>
>> +#include <linux/pci.h>
>> +
>> +/*
>> + * Local Management Registers
>> + */
>> +#define CDNS_PCIE_LM_BASE 0x00100000
>> +
>> +/* Vendor ID Register */
>> +#define CDNS_PCIE_LM_ID (CDNS_PCIE_LM_BASE + 0x0044)
>> +#define CDNS_PCIE_LM_ID_VENDOR_MASK GENMASK(15, 0)
>> +#define CDNS_PCIE_LM_ID_VENDOR_SHIFT 0
>> +#define CDNS_PCIE_LM_ID_VENDOR(vid) \
>> + (((vid) << CDNS_PCIE_LM_ID_VENDOR_SHIFT) & CDNS_PCIE_LM_ID_VENDOR_MASK)
>> +#define CDNS_PCIE_LM_ID_SUBSYS_MASK GENMASK(31, 16)
>> +#define CDNS_PCIE_LM_ID_SUBSYS_SHIFT 16
>> +#define CDNS_PCIE_LM_ID_SUBSYS(sub) \
>> + (((sub) << CDNS_PCIE_LM_ID_SUBSYS_SHIFT) & CDNS_PCIE_LM_ID_SUBSYS_MASK)
>> +
>> +/* Root Port Requestor ID Register */
>> +#define CDNS_PCIE_LM_RP_RID (CDNS_PCIE_LM_BASE + 0x0228)
>> +#define CDNS_PCIE_LM_RP_RID_MASK GENMASK(15, 0)
>> +#define CDNS_PCIE_LM_RP_RID_SHIFT 0
>> +#define CDNS_PCIE_LM_RP_RID_(rid) \
>> + (((rid) << CDNS_PCIE_LM_RP_RID_SHIFT) & CDNS_PCIE_LM_RP_RID_MASK)
>> +
>> +/* Root Complex BAR Configuration Register */
>> +#define CDNS_PCIE_LM_RC_BAR_CFG (CDNS_PCIE_LM_BASE + 0x0300)
>> +#define CDNS_PCIE_LM_RC_BAR_CFG_BAR0_APERTURE_MASK GENMASK(5, 0)
>> +#define CDNS_PCIE_LM_RC_BAR_CFG_BAR0_APERTURE(a) \
>> + (((a) << 0) & CDNS_PCIE_LM_RC_BAR_CFG_BAR0_APERTURE_MASK)
>> +#define CDNS_PCIE_LM_RC_BAR_CFG_BAR0_CTRL_MASK GENMASK(8, 6)
>> +#define CDNS_PCIE_LM_RC_BAR_CFG_BAR0_CTRL(c) \
>> + (((c) << 6) & CDNS_PCIE_LM_RC_BAR_CFG_BAR0_CTRL_MASK)
>> +#define CDNS_PCIE_LM_RC_BAR_CFG_BAR1_APERTURE_MASK GENMASK(13, 9)
>> +#define CDNS_PCIE_LM_RC_BAR_CFG_BAR1_APERTURE(a) \
>> + (((a) << 9) & CDNS_PCIE_LM_RC_BAR_CFG_BAR1_APERTURE_MASK)
>> +#define CDNS_PCIE_LM_RC_BAR_CFG_BAR1_CTRL_MASK GENMASK(16, 14)
>> +#define CDNS_PCIE_LM_RC_BAR_CFG_BAR1_CTRL(c) \
>> + (((c) << 14) & CDNS_PCIE_LM_RC_BAR_CFG_BAR1_CTRL_MASK)
>> +#define CDNS_PCIE_LM_RC_BAR_CFG_PREFETCH_MEM_ENABLE BIT(17)
>> +#define CDNS_PCIE_LM_RC_BAR_CFG_PREFETCH_MEM_32BITS 0
>> +#define CDNS_PCIE_LM_RC_BAR_CFG_PREFETCH_MEM_64BITS BIT(18)
>> +#define CDNS_PCIE_LM_RC_BAR_CFG_IO_ENABLE BIT(19)
>> +#define CDNS_PCIE_LM_RC_BAR_CFG_IO_16BITS 0
>> +#define CDNS_PCIE_LM_RC_BAR_CFG_IO_32BITS BIT(20)
>> +#define CDNS_PCIE_LM_RC_BAR_CFG_CHECK_ENABLE BIT(31)
>> +
>> +/* BAR control values applicable to both Endpoint Function and Root Complex */
>> +#define CDNS_PCIE_LM_BAR_CFG_CTRL_DISABLED 0x0
>> +#define CDNS_PCIE_LM_BAR_CFG_CTRL_IO_32BITS 0x1
>> +#define CDNS_PCIE_LM_BAR_CFG_CTRL_MEM_32BITS 0x4
>> +#define CDNS_PCIE_LM_BAR_CFG_CTRL_PREFETCH_MEM_32BITS 0x5
>> +#define CDNS_PCIE_LM_BAR_CFG_CTRL_MEM_64BITS 0x6
>> +#define CDNS_PCIE_LM_BAR_CFG_CTRL_PREFETCH_MEM_64BITS 0x7
>> +
>> +
>> +/*
>> + * Root Port Registers (PCI configuration space for the root port function)
>> + */
>> +#define CDNS_PCIE_RP_BASE 0x00200000
>> +
>> +
>> +/*
>> + * Address Translation Registers
>> + */
>> +#define CDNS_PCIE_AT_BASE 0x00400000
>> +
>> +/* Region r Outbound AXI to PCIe Address Translation Register 0 */
>> +#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0(r) \
>> + (CDNS_PCIE_AT_BASE + 0x0000 + ((r) & 0x1f) * 0x0020)
>> +#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_NBITS_MASK GENMASK(5, 0)
>> +#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_NBITS(nbits) \
>> + (((nbits) - 1) & CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_NBITS_MASK)
>> +#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_DEVFN_MASK GENMASK(19, 12)
>> +#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_DEVFN(devfn) \
>> + (((devfn) << 12) & CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_DEVFN_MASK)
>> +#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_BUS_MASK GENMASK(27, 20)
>> +#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_BUS(bus) \
>> + (((bus) << 20) & CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_BUS_MASK)
>> +
>> +/* Region r Outbound AXI to PCIe Address Translation Register 1 */
>> +#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR1(r) \
>> + (CDNS_PCIE_AT_BASE + 0x0004 + ((r) & 0x1f) * 0x0020)
>> +
>> +/* Region r Outbound PCIe Descriptor Register 0 */
>> +#define CDNS_PCIE_AT_OB_REGION_DESC0(r) \
>> + (CDNS_PCIE_AT_BASE + 0x0008 + ((r) & 0x1f) * 0x0020)
>> +#define CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_MASK GENMASK(3, 0)
>> +#define CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_MEM 0x2
>> +#define CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_IO 0x6
>> +#define CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_CONF_TYPE0 0xa
>> +#define CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_CONF_TYPE1 0xb
>> +#define CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_NORMAL_MSG 0xc
>> +#define CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_VENDOR_MSG 0xd
>> +/* Bit 23 MUST be set in RC mode. */
>> +#define CDNS_PCIE_AT_OB_REGION_DESC0_HARDCODED_RID BIT(23)
>> +#define CDNS_PCIE_AT_OB_REGION_DESC0_DEVFN_MASK GENMASK(31, 24)
>> +#define CDNS_PCIE_AT_OB_REGION_DESC0_DEVFN(devfn) \
>> + (((devfn) << 24) & CDNS_PCIE_AT_OB_REGION_DESC0_DEVFN_MASK)
>> +
>> +/* Region r Outbound PCIe Descriptor Register 1 */
>> +#define CDNS_PCIE_AT_OB_REGION_DESC1(r) \
>> + (CDNS_PCIE_AT_BASE + 0x000c + ((r) & 0x1f) * 0x0020)
>> +#define CDNS_PCIE_AT_OB_REGION_DESC1_BUS_MASK GENMASK(7, 0)
>> +#define CDNS_PCIE_AT_OB_REGION_DESC1_BUS(bus) \
>> + ((bus) & CDNS_PCIE_AT_OB_REGION_DESC1_BUS_MASK)
>> +
>> +/* Region r AXI Region Base Address Register 0 */
>> +#define CDNS_PCIE_AT_OB_REGION_CPU_ADDR0(r) \
>> + (CDNS_PCIE_AT_BASE + 0x0018 + ((r) & 0x1f) * 0x0020)
>> +#define CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS_MASK GENMASK(5, 0)
>> +#define CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS(nbits) \
>> + (((nbits) - 1) & CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS_MASK)
>> +
>> +/* Region r AXI Region Base Address Register 1 */
>> +#define CDNS_PCIE_AT_OB_REGION_CPU_ADDR1(r) \
>> + (CDNS_PCIE_AT_BASE + 0x001c + ((r) & 0x1f) * 0x0020)
>> +
>> +/* Root Port BAR Inbound PCIe to AXI Address Translation Register */
>> +#define CDNS_PCIE_AT_IB_RP_BAR_ADDR0(bar) \
>> + (CDNS_PCIE_AT_BASE + 0x0800 + (bar) * 0x0008)
>> +#define CDNS_PCIE_AT_IB_RP_BAR_ADDR0_NBITS_MASK GENMASK(5, 0)
>> +#define CDNS_PCIE_AT_IB_RP_BAR_ADDR0_NBITS(nbits) \
>> + (((nbits) - 1) & CDNS_PCIE_AT_IB_RP_BAR_ADDR0_NBITS_MASK)
>> +#define CDNS_PCIE_AT_IB_RP_BAR_ADDR1(bar) \
>> + (CDNS_PCIE_AT_BASE + 0x0804 + (bar) * 0x0008)
>> +
>> +enum cdns_pcie_rp_bar {
>> + RP_BAR0,
>> + RP_BAR1,
>> + RP_NO_BAR
>> +};
>> +
>> +/**
>> + * struct cdns_pcie - private data for Cadence PCIe controller drivers
>> + * @reg_base: IO mapped register base
>> + * @mem_res: start/end offsets in the physical system memory to map PCI accesses
>> + * @is_rc: tell whether the PCIe controller mode is Root Complex or Endpoint.
>> + * @bus: In Root Complex mode, the bus number
>> + */
>> +struct cdns_pcie {
>> + void __iomem *reg_base;
>> + struct resource *mem_res;
>> + bool is_rc;
>> + u8 bus;
>> +};
>> +
>> +/* Register access */
>> +static inline void cdns_pcie_writeb(struct cdns_pcie *pcie, u32 reg, u8 value)
>> +{
>> + writeb(value, pcie->reg_base + reg);
>> +}
>> +
>> +static inline void cdns_pcie_writew(struct cdns_pcie *pcie, u32 reg, u16 value)
>> +{
>> + writew(value, pcie->reg_base + reg);
>> +}
>> +
>> +static inline void cdns_pcie_writel(struct cdns_pcie *pcie, u32 reg, u32 value)
>> +{
>> + writel(value, pcie->reg_base + reg);
>> +}
>> +
>> +static inline u32 cdns_pcie_readl(struct cdns_pcie *pcie, u32 reg)
>> +{
>> + return readl(pcie->reg_base + reg);
>> +}
>> +
>> +/* Root Port register access */
>> +static inline void cdns_pcie_rp_writeb(struct cdns_pcie *pcie,
>> + u32 reg, u8 value)
>> +{
>> + writeb(value, pcie->reg_base + CDNS_PCIE_RP_BASE + reg);
>> +}
>> +
>> +static inline void cdns_pcie_rp_writew(struct cdns_pcie *pcie,
>> + u32 reg, u16 value)
>> +{
>> + writew(value, pcie->reg_base + CDNS_PCIE_RP_BASE + reg);
>> +}
>> +
>> +void cdns_pcie_set_outbound_region(struct cdns_pcie *pcie, u32 r, bool is_io,
>> + u64 cpu_addr, u64 pci_addr, size_t size);
>> +
>> +void cdns_pcie_reset_outbound_region(struct cdns_pcie *pcie, u32 r);
>
> Ditto. I understand it is hard to untangle code that was written with
> both EP and host bridge support in mind but, as I state below every
> patch has to make sense on its own.
done in v4.
>
>> +
>> +#endif /* _PCIE_CADENCE_H */
>
> Technically speaking, this 3-file (.c .h) split is not necessary and can
> turn out unnecessary churn if we never merge the endpoint code -
> actually you would not even need a special cadence directory, just a
> host bridge driver file.
>
> Bottom line, as you know: every patch has to be self contained.
>
> It is already quite late -rc, I understand that changes this late
> are error prone so I will accept that this file splitting is necessary
> for "future" patches - if you manage to squash changes into a file I'd
> appreciate though, it does not make sense to export functions that are
> used in just one compilation unit (and some that are not used at all).
Sorry, I didn't have time to squash the 3 files into a single one. I
can do it in v5 if you think it's better. I plan to work on the endpoint
driver with multi-functions this week-end, hence I hope I will be able
to add this driver back in v5.
I've just been sending v4 anyway so at least you will have former patch 3
from v3 split into new patches 3 and 4 in v4 as you requested.
So if you want to merge at least the new generic patches [1 - 4] for v4.16,
they are available :)
Best regards,
Cyrille
>
> Thanks,
> Lorenzo
>
--
Cyrille Pitchen, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 14+ messages in thread
end of thread, other threads:[~2018-01-18 23:23 UTC | newest]
Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-01-10 22:47 [PATCH v3 0/6] PCI: Add support to the Cadence PCIe controller Cyrille Pitchen
2018-01-10 22:47 ` [PATCH v3 1/6] PCI: Regroup all PCI related entries into drivers/pci/Makefile Cyrille Pitchen
[not found] ` <cover.1515621150.git.cyrille.pitchen-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
2018-01-10 22:47 ` [PATCH v3 2/6] PCI: OF: Add generic function to parse and allocate PCI resources Cyrille Pitchen
2018-01-10 22:47 ` [PATCH v3 3/6] PCI: Add generic function to probe PCI host controllers Cyrille Pitchen
2018-01-16 15:25 ` Lorenzo Pieralisi
2018-01-18 22:58 ` Cyrille Pitchen
2018-01-10 22:47 ` [PATCH v3 4/6] PCI: Add vendor ID for Cadence Cyrille Pitchen
2018-01-10 22:47 ` [PATCH v3 5/6] dt-bindings: PCI: cadence: Add DT bindings for Cadence PCIe host controller Cyrille Pitchen
2018-01-10 22:47 ` [PATCH v3 6/6] PCI: cadence: Add host driver for Cadence PCIe controller Cyrille Pitchen
2018-01-16 11:16 ` Kishon Vijay Abraham I
[not found] ` <e3d88d5b-e770-d2e5-20b2-62551d5f4f8f-l0cyMroinI0@public.gmane.org>
2018-01-16 15:09 ` Lorenzo Pieralisi
2018-01-18 23:13 ` Cyrille Pitchen
2018-01-16 16:07 ` Lorenzo Pieralisi
[not found] ` <20180116160733.GA3644-4tUPXFaYRHv6sAKXYmQ0tx/iLCjYCKR+VpNB7YpNyf8@public.gmane.org>
2018-01-18 23:23 ` Cyrille Pitchen
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).