All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/16] PCI: dwc: Add dma-ranges/YAML-schema/Baikal-T1 support
@ 2022-03-24  1:37 Serge Semin
  2022-03-24  1:37   ` Serge Semin
                   ` (15 more replies)
  0 siblings, 16 replies; 40+ messages in thread
From: Serge Semin @ 2022-03-24  1:37 UTC (permalink / raw)
  To: Jingoo Han, Gustavo Pimentel, Bjorn Helgaas
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Lorenzo Pieralisi, Rob Herring, Krzysztof Wilczyński,
	Frank Li, Manivannan Sadhasivam, Rob Herring, linux-pci,
	devicetree, linux-kernel

This patchset is a third one in the series created in the framework of
my Baikal-T1 PCIe/eDMA-related work:

[1: In-progress] clk: Baikal-T1 DDR/PCIe resets and some xGMAC fixes
Link: --submitted--
[2: In-progress] PCI: dwc: Various fixes and cleanups
Link: --submitted--
[3: In-progress] PCI: dwc: Add dma-ranges/YAML-schema/Baikal-T1 support
Link: --you are looking at it--
[4: Stalling]    dmaengine: dw-edma: Add RP/EP local DMA controllers support
Link: --being submitted afterwards--

Note it is very recommended to merge the patchsets in the same order as
they are listed in the set above in order to have them applied smoothly.
Nothing prevents them from being reviewed synchronously though.

This series is about adding new features to the DW PCIe Host/End-point
driver. First of all we start from splitting up the DT-bindings into
common properties schema and generic DW PCIe bindings definition. It's
done to support the generic DW PCIe Host/End-point available platforms
with adding a common YAML-schema to be reused by the platform-specific DW
PCIe bindings. @Rob could you please take a look at that patch? I've got a
problem with dt_bindings_check-ing the schema which is likely caused by
the dt-schema parser misbehaviour. After that we suggest to add a more
verbose link-up log message. Really printing link generation and width
would be much more informative than just "link up". Then a series of
IP-core version-related patches go, like using a native FourCC version
representation, adding the IP-core auto-detection, adding better
structured IP-core version/type interface. After that the
platform-specific host de-initialization method is introduced. A series of
iATU optimizations, cleanups and new features goes afterwards. In
particular we suggest to drop some redundant enumerations, add iATU
regions size detection procedure and then use the regions parameters to
verify the requested by the platform iATU ranges/dma-ranges settings.
After that the dma-ranges property support is added for the DW PCIe Host
controllers. Then a structured set of the DW PCIe RP/EP specific clocks
and resets names/IDs is introduced so to be re-used by the generic and new
platforms. Note it is fully coherent with the DW PCIe controller manuals
(see the patch log for details). Also note the patch doesn't affect the
already available DW PCIe platform-specific code since it would be too
risky for my to do the corresponding conversion, but the maintainers are
welcome to do that. Finally at the series closure we introduce the
Baikal-T1 PCIe interface support, which uses all the recently added
features including the set of the generic clocks and resets names.

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
Cc: Alexey Malahov <Alexey.Malahov@baikalelectronics.ru>
Cc: Pavel Parkhomenko <Pavel.Parkhomenko@baikalelectronics.ru>
Cc: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Cc: Rob Herring <robh@kernel.org>
Cc: "Krzysztof Wilczyński" <kw@linux.com>
Cc: Frank Li <Frank.Li@nxp.com>
Cc: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
Cc: Rob Herring <robh+dt@kernel.org>
Cc: linux-pci@vger.kernel.org
Cc: devicetree@vger.kernel.org
Cc: linux-kernel@vger.kernel.org

Serge Semin (16):
  dt-bindings: PCI: dwc: Define generic and native DT bindings
  dt-bindings: PCI: dwc: Add Baikal-T1 PCIe Root Port bindings
  PCI: dwc: Add more verbose link-up message
  PCI: dwc: Convert to using native IP-core versions representation
  PCI: dwc: Add IP-core version detection procedure
  PCI: dwc: Introduce Synopsys IP-core versions/types interface
  PCI: dwc: Add host de-initialization callback
  PCI: dwc: Drop inbound iATU types enumeration - dw_pcie_as_type
  PCI: dwc: Simplify in/outbound iATU setup methods
  PCI: dwc: Drop iATU regions enumeration - dw_pcie_region_type
  PCI: dwc: Add iATU regions size detection procedure
  PCI: dwc: Verify in/out regions against iATU constraints
  PCI: dwc: Check iATU in/outbound ranges setup methods status
  PCI: dwc: Introduce dma-ranges property support for RC-host
  PCI: dwc: Introduce generic platform clocks and resets sets
  PCI: dwc: Add Baikal-T1 PCIe controller support

 .../bindings/pci/baikal,bt1-pcie.yaml         | 148 ++++
 .../bindings/pci/fsl,imx6q-pcie.yaml          |   5 +-
 .../bindings/pci/hisilicon,kirin-pcie.yaml    |   4 +-
 .../bindings/pci/sifive,fu740-pcie.yaml       |   4 +-
 .../bindings/pci/snps,dw-pcie-common.yaml     | 298 ++++++++
 .../bindings/pci/snps,dw-pcie-ep.yaml         | 143 ++--
 .../devicetree/bindings/pci/snps,dw-pcie.yaml | 189 ++++--
 .../bindings/pci/toshiba,visconti-pcie.yaml   |   2 +-
 drivers/pci/controller/dwc/Kconfig            |   9 +
 drivers/pci/controller/dwc/Makefile           |   1 +
 drivers/pci/controller/dwc/pci-keystone.c     |  12 +-
 drivers/pci/controller/dwc/pcie-bt1.c         | 638 ++++++++++++++++++
 .../pci/controller/dwc/pcie-designware-ep.c   |  36 +-
 .../pci/controller/dwc/pcie-designware-host.c | 198 ++++--
 drivers/pci/controller/dwc/pcie-designware.c  | 465 ++++++-------
 drivers/pci/controller/dwc/pcie-designware.h  | 200 ++++--
 drivers/pci/controller/dwc/pcie-intel-gw.c    |  10 +-
 drivers/pci/controller/dwc/pcie-tegra194.c    |   2 +-
 18 files changed, 1857 insertions(+), 507 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/pci/baikal,bt1-pcie.yaml
 create mode 100644 Documentation/devicetree/bindings/pci/snps,dw-pcie-common.yaml
 create mode 100644 drivers/pci/controller/dwc/pcie-bt1.c

-- 
2.35.1


^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH 01/16] dt-bindings: PCI: dwc: Define generic and native DT bindings
  2022-03-24  1:37 [PATCH 00/16] PCI: dwc: Add dma-ranges/YAML-schema/Baikal-T1 support Serge Semin
  2022-03-24  1:37   ` Serge Semin
@ 2022-03-24  1:37   ` Serge Semin
  2022-03-24  1:37 ` [PATCH 03/16] PCI: dwc: Add more verbose link-up message Serge Semin
                     ` (13 subsequent siblings)
  15 siblings, 0 replies; 40+ messages in thread
From: Serge Semin @ 2022-03-24  1:37 UTC (permalink / raw)
  To: Jingoo Han, Gustavo Pimentel, Bjorn Helgaas, Richard Zhu,
	Lucas Stach, Rob Herring, Shawn Guo, Sascha Hauer,
	Pengutronix Kernel Team, Fabio Estevam, NXP Linux Team,
	Xiaowei Song, Binghui Wang, Paul Walmsley, Greentime Hu,
	Palmer Dabbelt, Nobuhiro Iwamatsu
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Lorenzo Pieralisi, Rob Herring, Krzysztof Wilczyński,
	Frank Li, Manivannan Sadhasivam, linux-pci, devicetree,
	linux-kernel, linux-arm-kernel, linux-riscv

Currently both DW PCIe Root Port and End-point DT bindings are too generic
to be used as a descriptive set the device properties. Yes, it's very handy
to have them that way so the DT-schemas could be used to evaluate as many
DW PCIe-related DT-nodes as possible. But at the same time they don't
provide well defined DW PCIe RP/EP DT interface description thus leaving
too much flexibility for the new platforms, no encouraging the developers
to preserve a compatible interface.

Instead of currently implemented approach we suggest to be more
restrictive and yet preserve some level of flexibility in the DW PCIe
DT-bindings description. The device tree DT-schema is split up into
three parts: a common YAML-schema applicable for both DWC Root Port and
End-point controller configs, DWC PCIe Root Port-specific YAML-schema
and DWC PCIe End-point-specific YAML-schema, where
1) pci/snps,dw-pcie-common.yaml - The common DT-schema describes the most
generic constraints of the "reg", "interrupts", "clocks", "resets" and
"phys" properties together with a set of common for both device types
PCIe/AXI bus properties like a maximum number of lanes or a maximum link
speed, number of inbound and outbound iATU windows. In addition to that a
set of schema definitions declared under the "$defs" property with "reg",
"interrupt", "clock" and "reset" names common for DWC PCIe Root Port and
End-point devices. They can be used by the successive DT-schemas in case
they are supposed to be compatible with the generic DWC PCIe controller
DT-bindings.
2) pci/snps,dw-pcie.yaml, pci/snps,dw-pcie-ep.yaml - generic DW PCIe Root
Port and End-point DT-bindings which aside with the device-specific
properties set also contain more restrictive constraints. All new DW PCIe
platforms are supposed to be compatible with one of these bindings by
using "allOf: " property and additionally defining their own constraints
to close up the DT-bindings set.

So to speak in case if a DW PCIe-based device for some reason has too many
specific properties or it's bindings have already been defined in a
non-generic way, it's DT-schema is supposed to include 1) YAML-file and
provide its own constraints. Otherwise the ready-to-use bindings from 2)
should be utilized. There only two DT-schemas compatible with 2) at the
moment are samsung,axynos-pcie.yaml and intel-gw-pcie.yaml. The
rest of the DW PCIe-related DT-schemas are supposed to use more generic
DW PCIe DT-bindings - pci/snps,dw-pcie-common.yaml.

Note the provided here generic properties and their possible values are
derived from the DW PCIe RC/EP hardware manuals and from the interface
implemented in the driver. The DT-bindings schemas are created to be as
full as possible with detailed properties/names description for the
easier interface comprehension and new platforms bindings development.

Also note since there are no generic DT-nodes can be found in the kernel
dts-es which would have a pure "snps,dw-pcie" compatible string, these
DT-bindings have been created to not be selected by default for
evaluation. They are supposed to be used by the new vendor-specific
DT-schemas to at least stop adding new bindings for the same set of DWC
PCIe signals or properties.

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>

---

Rob, if you comment the "select: false" line out you'll get a lot of "'*'
is not of type 'array'" errors on the dt_bindings_check command execution.
I have spend tons of time trying to figure out what was wrong, but still
failed to find out a solution. For some reason the "$ref"-ed schemas
defined under the "$defs" basic property are considered by the parser as
defining an array. No matter whether I specified the "type: string"
keyword or not, as long as there is "enum" or "oneOf" keyword used in the
"*-names" property definition in "$defs" it's considered as describing an
array thus causing the errors like:

>  DTC     Documentation/devicetree/bindings/pci/snps,dw-pcie.example.dt.yaml
>  CHECK   Documentation/devicetree/bindings/pci/snps,dw-pcie.example.dt.yaml
> /.../snps,dw-pcie.example.dt.yaml: pcie@1f052000: reg-names:0: 'oneOf' conditional failed, one must be fixed:
>        'dbi' is not of type 'array'
>        From schema: /.../snps,dw-pcie.yaml
> /.../snps,dw-pcie.example.dt.yaml: pcie@1f052000: reg-names:1: 'oneOf' conditional failed, one must be fixed:
>         'config' is not of type 'array'
>         From schema: /.../snps,dw-pcie.yaml
> /.../snps,dw-pcie.example.dt.yaml: pcie@1f052000: interrupt-names:0: 'anyOf' conditional failed, one must be fixed:
>         /.../snps,dw-pcie.example.dt.yaml: pcie@1f052000: interrupt-names:0: 'oneOf' conditional failed, one must be fixed:
>                 'msi' is not of type 'array'
>         /../snps,dw-pcie.example.dt.yaml: pcie@1f052000: interrupt-names:0: 'oneOf' conditional failed, one must be fixed:
>                 'msi' is not of type 'array'
>         From schema: /.../snps,dw-pcie.yaml

As soon as I manually moved the same "$defs"-schemas into the places they
are referenced to, the errors disappeared and the DT-schemas validation
worked as expected by the semantics.

As I see it there must be some bug in the parser, otherwise I am out of
ideas how to implement the suggested in this patch design pattern. Rob,
could you take a look at the DT-schemas and help me out with debugging the
problem described above?
---
 .../bindings/pci/fsl,imx6q-pcie.yaml          |   5 +-
 .../bindings/pci/hisilicon,kirin-pcie.yaml    |   4 +-
 .../bindings/pci/sifive,fu740-pcie.yaml       |   4 +-
 .../bindings/pci/snps,dw-pcie-common.yaml     | 298 ++++++++++++++++++
 .../bindings/pci/snps,dw-pcie-ep.yaml         | 143 ++++++---
 .../devicetree/bindings/pci/snps,dw-pcie.yaml | 189 +++++++----
 .../bindings/pci/toshiba,visconti-pcie.yaml   |   2 +-
 7 files changed, 524 insertions(+), 121 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/pci/snps,dw-pcie-common.yaml

diff --git a/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.yaml b/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.yaml
index 643a6333b07b..ccb5cfdf869f 100644
--- a/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.yaml
+++ b/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.yaml
@@ -12,10 +12,11 @@ maintainers:
 
 description: |+
   This PCIe host controller is based on the Synopsys DesignWare PCIe IP
-  and thus inherits all the common properties defined in snps,dw-pcie.yaml.
+  and thus inherits all the common properties defined in
+  snps,dw-pcie-common.yaml.
 
 allOf:
-  - $ref: /schemas/pci/snps,dw-pcie.yaml#
+  - $ref: /schemas/pci/snps,dw-pcie-common.yaml#
 
 properties:
   compatible:
diff --git a/Documentation/devicetree/bindings/pci/hisilicon,kirin-pcie.yaml b/Documentation/devicetree/bindings/pci/hisilicon,kirin-pcie.yaml
index c9f04999c9cf..879d9ec41cb7 100644
--- a/Documentation/devicetree/bindings/pci/hisilicon,kirin-pcie.yaml
+++ b/Documentation/devicetree/bindings/pci/hisilicon,kirin-pcie.yaml
@@ -14,10 +14,10 @@ description: |
   Kirin PCIe host controller is based on the Synopsys DesignWare PCI core.
   It shares common functions with the PCIe DesignWare core driver and
   inherits common properties defined in
-  Documentation/devicetree/bindings/pci/snps,dw-pcie.yaml.
+  Documentation/devicetree/bindings/pci/snps,dw-pcie-common.yaml.
 
 allOf:
-  - $ref: /schemas/pci/snps,dw-pcie.yaml#
+  - $ref: /schemas/pci/snps,dw-pcie-common.yaml#
 
 properties:
   compatible:
diff --git a/Documentation/devicetree/bindings/pci/sifive,fu740-pcie.yaml b/Documentation/devicetree/bindings/pci/sifive,fu740-pcie.yaml
index 392f0ab488c2..437614257935 100644
--- a/Documentation/devicetree/bindings/pci/sifive,fu740-pcie.yaml
+++ b/Documentation/devicetree/bindings/pci/sifive,fu740-pcie.yaml
@@ -10,14 +10,14 @@ description: |+
   SiFive FU740 PCIe host controller is based on the Synopsys DesignWare
   PCI core. It shares common features with the PCIe DesignWare core and
   inherits common properties defined in
-  Documentation/devicetree/bindings/pci/snps,dw-pcie.yaml.
+  Documentation/devicetree/bindings/pci/snps,dw-pcie-common.yaml.
 
 maintainers:
   - Paul Walmsley <paul.walmsley@sifive.com>
   - Greentime Hu <greentime.hu@sifive.com>
 
 allOf:
-  - $ref: /schemas/pci/snps,dw-pcie.yaml#
+  - $ref: /schemas/pci/snps,dw-pcie-common.yaml#
 
 properties:
   compatible:
diff --git a/Documentation/devicetree/bindings/pci/snps,dw-pcie-common.yaml b/Documentation/devicetree/bindings/pci/snps,dw-pcie-common.yaml
new file mode 100644
index 000000000000..27fe1f5c450f
--- /dev/null
+++ b/Documentation/devicetree/bindings/pci/snps,dw-pcie-common.yaml
@@ -0,0 +1,298 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pci/snps,dw-pcie-common.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Synopsys DWC PCIe RP/EP controller
+
+maintainers:
+  - Jingoo Han <jingoohan1@gmail.com>
+  - Gustavo Pimentel <gustavo.pimentel@synopsys.com>
+
+properties:
+  reg:
+    description:
+      DWC PCIe CSR space is normally accessed over the dedicated Data Bus
+      Interface - DBI. In accordance with the reference manual the register
+      configuration space belongs to the Configuration-Dependent Module (CDM)
+      and is split up into several sub-parts Standard PCIe configuration
+      space, Port Logic Registers (PL), Shadow Config-space Registers,
+      iATU/eDMA registers. The particular sub-space is selected by the
+      CDM/ELBI (dbi_cs) and CS2 (dbi_cs2) signals (selector bits). Such
+      configuration provides a flexible interface for the system engineers to
+      either map the particular space at a desired MMIO address or just leave
+      them in a contiguous memory space if pure Native or AXI Bridge DBI access
+      is selected. Note the PCIe CFG-space, PL and Shadow registers are
+      specific to each activated function, while the rest of the sub-spaces
+      are common for all of them (if there are more than one).
+    minItems: 2
+    maxItems: 6
+
+  interrupts:
+    description:
+      There are two main sub-blocks which are normally capable of
+      generating interrupts. It's System Information Interface and MSI
+      interface. While the former one has some common for the Host and
+      End-point controllers IRQ-signals, the later interface is obviously
+      Root Complex specific since it's responsible for the incoming MSI
+      messages signalling. The System Information IRQ signals are mainly
+      responsible for reporting the generic PCIe hierarchy and Root
+      Complex events like VPD IO request, general AER, PME, Hot-plug, link
+      bandwidth change, link equalization request, INTx asserted/deasserted
+      Message detection, embedded DMA Tx/Rx/Error.
+    minItems: 1
+    maxItems: 26
+
+  clocks:
+    description:
+      DWC PCIe reference manual explicitly defines a set of the clocks required
+      to get the controller working correctly. In general all of them can
+      be divided into two groups':' application and core clocks. Note the
+      platforms may have some of the clock sources unspecified in case if the
+      corresponding domains are fed up from a common clock source.
+    minItems: 1
+    maxItems: 7
+
+  resets:
+    description:
+      DWC PCIe reference manual explicitly defines a set of the reset
+      signals required to be de-asserted to properly activate the controller
+      sub-parts. All of these signals can be divided into two sub-groups':'
+      application and core resets with respect to the main sub-domains they
+      are supposed to reset. Note the platforms may have some of these signals
+      unspecified in case if they are automatically handled or aggregated into
+      a comprehensive control module.
+    minItems: 1
+    maxItems: 10
+
+  reset-gpio:
+    deprecated: true
+    description:
+      Reference to the GPIO-controlled PERST# signal. It is used to reset all
+      the peripheral devices available on the PCIe bus.
+    maxItems: 1
+
+  reset-gpios:
+    description:
+      Reference to the GPIO-controlled PERST# signal. It is used to reset all
+      the peripheral devices available on the PCIe bus.
+    maxItems: 1
+
+  phys:
+    description:
+      There can be up to number of possible lanes PHYs specified.
+      Obviously each specified PHY is supposed to be able to work in the
+      PCIe mode with a speed implied by the DWC PCIe controller it is
+      attached to.
+    minItems: 1
+    maxItems: 16
+
+  phy-names:
+    minItems: 1
+    maxItems: 16
+    items:
+      pattern: '^pcie([0-9]+|-?phy)?$'
+
+  num-lanes:
+    maximum: 16
+
+  max-link-speed:
+    maximum: 4
+
+  num-ob-windows:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    deprecated: true
+    description:
+      Number of outbound address translation windows. This parameter can be
+      auto-detected based on the iATU memory writability. So there is no
+      point in having a dedicated DT-property for it.
+    maximum: 256
+
+  num-ib-windows:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    deprecated: true
+    description:
+      Number of inbound address translation windows. In the same way as
+      for the outbound AT windows, this parameter can be auto-detected based
+      on the iATU memory writability. There is no point having a dedicated
+      DT-property for it either.
+    maximum: 256
+
+  num-viewport:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    deprecated: true
+    description:
+      Number of outbound view ports configured in hardware. It's the same as
+      the number of outbound AT windows.
+    maximum: 256
+
+  snps,enable-cdm-check:
+    $ref: /schemas/types.yaml#/definitions/flag
+    description:
+      Enable automatic checking of CDM (Configuration Dependent Module)
+      registers for data corruption. CDM registers include standard PCIe
+      configuration space registers, Port Logic registers, DMA and iATU
+      registers. This feature has been available since DWC PCIe v4.80a.
+
+additionalProperties: true
+
+$defs:
+  reg-names:
+    description:
+      CSR space names common for the DWC PCIe Root Port and End-point
+      controllers.
+    oneOf:
+      - description:
+          Basic DWC PCIe controller configuration-space accessible over
+          the DBI interface. This memory space is either activated with
+          the CDM/ELBI = 0 and CS2 = 0 or is a contiguous memory region
+          with all spaces. Note iATU/eDMA CSRs are indirectly accessible
+          via the PL viewports on the DWC PCIe controllers older than
+          v4.80a.
+        const: dbi
+      - description:
+          Shadow DWC PCIe config-space registers. This space is selected
+          by setting CDM/ELBI = 0 and CS2 = 1. This is an intermix of
+          the PCI-SIG PCIe CFG-space with the shadow registers for some
+          PCI Header space, PCI Standard and Extended Structures. It's
+          mainly relevant for the end-point controller configuration,
+          but still there are some shadow registers available for the
+          Root Port mode too.
+        const: dbi2
+      - description:
+          External Local Bus registers. It's an application-dependent
+          registers normally defined by the platform engineers, which
+          are selected by setting CDM/ELBI = 1 and CS2 = 0.
+        enum: [ elbi, appl, app ]
+      - description:
+          iATU/eDMA registers common for all device functions. It's an
+          unrolled memory space with the internal Address Translation
+          Unit and Enhanced DMA, which is selected by setting CDM/ELBI = 1
+          and CS2 = 1. For IP-core releases prior v4.80a, these registers
+          have been programmed via an indirect addressing scheme using a
+          set of viewport CSRs mapped into the PL space. Note iATU is
+          normally mapped to the 0x0 address of this region, while eDMA
+          is available at 0x80000 base address.
+        enum: [ atu, atu_dma ]
+      - description:
+          Outbound iATU-available memory-region which usage scenario
+          depends on the DWC PCIe controller being either Root Port or
+          End-point. If it's Root Port then the register space shall
+          have the "config" name and it will be used to access the
+          peripheral PCIe devices configuration space. If it's PCIe
+          end-point controller, then the region shall be named as
+          "addr_space" and it will be used to generate various traffic
+          on the PCIe bus hierarchy. It's usage scenario depends on the
+          end-point functionality, for instance it can be used to create
+          MSI(X) messages.
+        enum: [ config, addr_space ]
+      - description:
+          PHY/PCS configuration registers. Some platforms can have the
+          PCS and PHY CSRs accessible over a dedicated memory mapped
+          region, but mainly these registers are indirectly accessible
+          either by means of the embedded PHY viewport schema or by some
+          platform-specific method.
+        enum: [ link, phy ]
+
+  interrupt-names:
+    description:
+      IRQ signal names common for the DWC PCIe Root Port and End-point
+      controllers.
+    oneOf:
+      - description:
+          Controller request to read or write virtual product data
+          from/to the VPD capability registers.
+        const: vpd
+      - description:
+          Link Equalization Request flag is set in the Link Status 2
+          register (applicable if the corresponding IRQ is enabled in
+          the Link Control 3 register).
+        const: l_eq
+      - description:
+          Indicates that the eDMA Tx/Rx transfer is complete or that an
+          error has occurred on the corresponding channel. eDMA can have
+          eight Tx (Write) and Rx (Read) eDMA channels thus supporting up
+          to 16 IRQ signals all together. Write eDMA channels shall go
+          first in the ordered row as per default edma_int[*] bus setup.
+        pattern: '^dma([0-9]|1[0-5])?$'
+      - description:
+          PCIe protocol correctable error or a Data Path protection
+          correctable error is detected by the automotive/safety
+          feature.
+        const: sft_ce
+      - description:
+          Indicates that the internal safety mechanism detected and
+          uncorrectable error.
+        const: sft_ue
+
+  clock-names:
+    description:
+      Reference clock names common for the DWC PCIe Root Port and End-point
+      controllers.
+    anyOf:
+      - description:
+          Data Bus Interface (DBI) clock. Clock signal for the AXI-bus
+          interface of the Configuration-Dependent Module, which is
+          basically the set of the controller CSRs.
+        enum: [ dbi, pcie ]
+      - description:
+          Application AXI-bus Master interface clock. Basically this is
+          a clock for the controller DMA interface (PCI-to-CPU).
+        enum: [ mstr, pcie_bus ]
+      - description:
+          Application AXI-bus Slave interface clock. This is a clock for
+          the CPU-to-PCI memory IO interface.
+        enum: [ slv, pcie_bus ]
+      - description:
+          Controller Core-PCS PIPE interface clock. It's normally
+          supplied by an external PCS-PHY.
+        const: pipe
+      - description:
+          Controller Primary clock. It's assumed that all controller input
+          signals (except resets) are synchronous to this clock.
+        const: core
+      - description:
+          Auxiliary clock for the controller PMC domain. The controller
+          partitioning implies having some parts to operate with this
+          clock in some power management states.
+        const: aux
+      - description:
+          Generic reference clock. In case if there are several
+          interfaces fed up with a common clock source it's advisable to
+          define it with this name (for instance pipe, core and aux can
+          be connected to a single source of the periodic signal).
+        const: ref
+      - description:
+          Clock for the PHY registers interface. Originally this is
+          a PHY-viewport-based interface, but some platform may have
+          specifically designed one.
+        const: phy_reg
+
+  reset-names:
+    description:
+      Reset signal names common for the DWC PCIe Root Port and End-point
+      controllers.
+    anyOf:
+      - description: Data Bus Interface (DBI) domain reset
+        const: dbi
+      - description: AXI-bus Master interface reset
+        const: mstr
+      - description: AXI-bus Slave interface reset
+        const: slv
+      - description: Controller Non-sticky CSR flags reset
+        const: non-sticky
+      - description: Controller sticky CSR flags reset
+        const: sticky
+      - description: PIPE-interface (Core-PCS) logic reset
+        const: pipe
+      - description:
+          Controller primary reset (resets everything except PMC module)
+        const: core
+      - description: PCS/PHY block reset
+        const: phy
+      - description: PMC hot reset signal
+        const: hot
+      - description: Cold reset signal
+        const: pwr
+...
diff --git a/Documentation/devicetree/bindings/pci/snps,dw-pcie-ep.yaml b/Documentation/devicetree/bindings/pci/snps,dw-pcie-ep.yaml
index e59059ab5be0..c3bbe90264dc 100644
--- a/Documentation/devicetree/bindings/pci/snps,dw-pcie-ep.yaml
+++ b/Documentation/devicetree/bindings/pci/snps,dw-pcie-ep.yaml
@@ -13,74 +13,115 @@ maintainers:
 description: |
   Synopsys DesignWare PCIe host controller endpoint
 
+# Please create a separate DT-schema for the particular DWC PCIe End-point
+# controller and make sure it's assigned with the vendor-specific
+# compatible string together with the generic Synopsys DWC PCIe strings so
+# the bindings would be successfully evaluated against this schema.
+select: false
+
 allOf:
   - $ref: /schemas/pci/pci-ep.yaml#
+  - $ref: snps,dw-pcie-common.yaml#
 
 properties:
   compatible:
-    anyOf:
-      - {}
-      - const: snps,dw-pcie-ep
+    contains:
+      oneOf:
+        - description:
+            DWC PCIe End-point controller (IP-core version is explicitly
+            specified in the additional compatible string)
+          items:
+            - pattern: '^snps,dw-pcie-ep-[0-9]+\.[0-9]+a?$'
+            - const: snps,dw-pcie-ep
+        - description:
+            DWC PCIe End-point controller (IP-core version is either unknown
+            or can be read from the PCIe version register of the PL reg-space)
+          const: snps,dw-pcie-ep
 
   reg:
-    description: |
-      It should contain Data Bus Interface (dbi) and config registers for all
-      versions.
-      For designware core version >= 4.80, it may contain ATU address space.
-    minItems: 2
-    maxItems: 4
+    description:
+      DBI, DBI2 reg-spaces and outbound memory window are required for the
+      normal controller functioning. iATU memory IO region is also required
+      if the space is unrolled (IP-core version >= 4.80a).
+    minItems: 3
+    maxItems: 5
 
   reg-names:
-    minItems: 2
-    maxItems: 4
+    minItems: 3
+    maxItems: 5
     items:
-      enum: [dbi, dbi2, config, atu, addr_space, link, atu_dma, appl]
-
-  reset-gpio:
-    description: GPIO pin number of PERST# signal
-    maxItems: 1
-    deprecated: true
-
-  reset-gpios:
-    description: GPIO controlled connection to PERST# signal
-    maxItems: 1
-
-  snps,enable-cdm-check:
-    type: boolean
-    description: |
-      This is a boolean property and if present enables
-      automatic checking of CDM (Configuration Dependent Module) registers
-      for data corruption. CDM registers include standard PCIe configuration
-      space registers, Port Logic registers, DMA and iATU (internal Address
-      Translation Unit) registers.
-
-  num-ib-windows:
-    description: number of inbound address translation windows
-    maxItems: 1
-    deprecated: true
-
-  num-ob-windows:
-    description: number of outbound address translation windows
-    maxItems: 1
-    deprecated: true
+      $ref: snps,dw-pcie-common.yaml#/$defs/reg-names
+    allOf:
+      - contains:
+          const: dbi
+      - contains:
+          const: dbi2
+      - contains:
+          const: addr_space
+
+  interrupts:
+    description:
+      There is no mandatory IRQ signals for the normal controller functioning,
+      but in addition to the native set the platforms may have a link- or
+      PM-related IRQs specified.
+    minItems: 1
+    maxItems: 20
+
+  interrupt-names:
+    minItems: 1
+    maxItems: 20
+    items:
+      $ref: snps,dw-pcie-common.yaml#/$defs/interrupt-names
+
+  clocks:
+    minItems: 1
+    maxItems: 7
+
+  clock-names:
+    minItems: 1
+    maxItems: 7
+    items:
+      $ref: snps,dw-pcie-common.yaml#/$defs/clock-names
+
+  resets:
+    minItems: 1
+    maxItems: 10
+
+  reset-names:
+    minItems: 1
+    maxItems: 10
+    items:
+      $ref: snps,dw-pcie-common.yaml#/$defs/reset-names
+
+  max-functions:
+    maximum: 32
 
 required:
+  - compatible
   - reg
   - reg-names
-  - compatible
 
 additionalProperties: true
 
 examples:
   - |
-    bus {
-      #address-cells = <1>;
-      #size-cells = <1>;
-      pcie-ep@dfd00000 {
-        compatible = "snps,dw-pcie-ep";
-        reg = <0xdfc00000 0x0001000>, /* IP registers 1 */
-              <0xdfc01000 0x0001000>, /* IP registers 2 */
-              <0xd0000000 0x2000000>; /* Configuration space */
-        reg-names = "dbi", "dbi2", "addr_space";
-      };
+    pcie-ep@1f052000 {
+      compatible = "vendor,soc-pcie", "snps,dw-pcie-ep-4.60a", "snps,dw-pcie-ep";
+      reg = <0x66000000 0x1000>, <0x66010000 0x10000>, <0x67000000 0x400000>;
+      reg-names = "dbi", "dbi2", "addr_space";
+
+      clocks = <&sys_clk 12>, <&sys_clk 24>;
+      clock-names = "dbi", "ref";
+
+      resets = <&sys_rst 12>, <&sys_rst 24>;
+      reset-names = "dbi", "phy";
+
+      phys = <&pcie_phy>;
+      phy-names = "pcie-phy";
+
+      num-lanes = <4>;
+      max-link-speed = <4>;
+      num-ib-windows = <16>;
+      num-ob-windows = <16>;
     };
+...
diff --git a/Documentation/devicetree/bindings/pci/snps,dw-pcie.yaml b/Documentation/devicetree/bindings/pci/snps,dw-pcie.yaml
index a5345c494744..6c397ae3c71a 100644
--- a/Documentation/devicetree/bindings/pci/snps,dw-pcie.yaml
+++ b/Documentation/devicetree/bindings/pci/snps,dw-pcie.yaml
@@ -13,20 +13,36 @@ maintainers:
 description: |
   Synopsys DesignWare PCIe host controller
 
+# Please create a separate DT-schema for the particular DWC PCIe Root Port
+# controller and make sure it's assigned with the vendor-specific
+# compatible string together with the generic Synopsys DWC PCIe strings so
+# the bindings would be successfully evaluated against this schema.
+select: false
+
 allOf:
   - $ref: /schemas/pci/pci-bus.yaml#
+  - $ref: snps,dw-pcie-common.yaml#
 
 properties:
   compatible:
-    anyOf:
-      - {}
-      - const: snps,dw-pcie
+    contains:
+      oneOf:
+        - description:
+            DWC PCIe Root Port controller (IP-core version is explicitly
+            specified in the additional compatible string)
+          items:
+            - pattern: '^snps,dw-pcie-[0-9]+\.[0-9]+a?$'
+            - const: snps,dw-pcie
+        - description:
+            DWC PCIe Root Port controller (IP-core version is either unknown
+            or can be read from the PCIe version register of the PL reg-space)
+          const: snps,dw-pcie
 
   reg:
-    description: |
-      It should contain Data Bus Interface (dbi) and config registers for all
-      versions.
-      For designware core version >= 4.80, it may contain ATU address space.
+    description:
+      At least DBI reg-space and peripheral devices CFG-space outbound window
+      are required for the normal controller work. iATU memory IO region is
+      also required if the space is unrolled (IP-core version >= 4.80a).
     minItems: 2
     maxItems: 5
 
@@ -34,69 +50,116 @@ properties:
     minItems: 2
     maxItems: 5
     items:
-      enum: [ dbi, dbi2, config, atu, app, elbi, mgmt, ctrl, parf, cfg, link,
-              ulreg, smu, mpu, apb, phy ]
-
-  num-lanes:
-    description: |
-      number of lanes to use (this property should be specified unless
-      the link is brought already up in firmware)
-    maximum: 16
-
-  reset-gpio:
-    description: GPIO pin number of PERST# signal
-    maxItems: 1
-    deprecated: true
-
-  reset-gpios:
-    description: GPIO controlled connection to PERST# signal
-    maxItems: 1
-
-  interrupts: true
-
-  interrupt-names: true
-
-  clocks: true
-
-  snps,enable-cdm-check:
-    type: boolean
-    description: |
-      This is a boolean property and if present enables
-      automatic checking of CDM (Configuration Dependent Module) registers
-      for data corruption. CDM registers include standard PCIe configuration
-      space registers, Port Logic registers, DMA and iATU (internal Address
-      Translation Unit) registers.
+      $ref: snps,dw-pcie-common.yaml#/$defs/reg-names
+    allOf:
+      - contains:
+          const: dbi
+      - contains:
+          const: config
+
+  interrupts:
+    description:
+      At least MSI interrupt signal is supposed to be specified for
+      the DWC PCIe host controller.
+    minItems: 1
+    maxItems: 26
+
+  interrupt-names:
+    minItems: 1
+    maxItems: 26
+    items:
+      anyOf:
+        - $ref: snps,dw-pcie-common.yaml#/$defs/interrupt-names
+        - $ref: '#/$defs/interrupt-names'
+    allOf:
+      - contains:
+          const: msi
+
+  clocks:
+    minItems: 1
+    maxItems: 7
+
+  clock-names:
+    minItems: 1
+    maxItems: 7
+    items:
+      $ref: snps,dw-pcie-common.yaml#/$defs/clock-names
 
-  num-viewport:
-    description: |
-      number of view ports configured in hardware. If a platform
-      does not specify it, the driver autodetects it.
-    deprecated: true
+  resets:
+    minItems: 1
+    maxItems: 10
 
-additionalProperties: true
+  reset-names:
+    minItems: 1
+    maxItems: 10
+    items:
+      $ref: snps,dw-pcie-common.yaml#/$defs/reset-names
 
 required:
+  - compatible
   - reg
   - reg-names
-  - compatible
+  - interrupts
+  - interrupt-names
+
+additionalProperties: true
+
+$defs:
+  interrupt-names:
+    description:
+      DWC PCIe Root Port/Complex specific IRQ signal names.
+    oneOf:
+      - description:
+          DSP AXI MSI Interrupt detected. It gets de-asserted when there is
+          no more MSI interrupt pending. The interrupt is relevant to the
+          iMSI-RX - Integrated MSI Receiver (AXI bridge).
+        const: msi
+      - description:
+          Error condition detected and a bit is set in the Root Error Status
+          register of the AER capability. It's asserted when the RC
+          internally generated an error or an error message is received by
+          the RC.
+        const: aer
+      - description:
+          PME message is received by the port. That means having the PME
+          status bit set in the Root Status register (the event is
+          supposed to be unmasked in the Root Control register).
+        const: pme
+      - description:
+          Hot-plug event is detected. That is a bit has been set in the
+          Slot Status register and the corresponding event is enabled in
+          the Slot Control register.
+        const: hp
+      - description:
+          Link Autonomous Bandwidth Status flag has been set in the Link
+          Status register (the event is supposed to be unmasked in the
+          Link Control register).
+        const: bw_au
+      - description:
+          Bandwidth Management Status flag has been set in the Link
+          Status register (the event is supposed to be unmasked in the
+          Link Control register).
+        const: bw_mg
 
 examples:
   - |
-    bus {
-      #address-cells = <1>;
-      #size-cells = <1>;
-      pcie@dfc00000 {
-        device_type = "pci";
-        compatible = "snps,dw-pcie";
-        reg = <0xdfc00000 0x0001000>, /* IP registers */
-              <0xd0000000 0x0002000>; /* Configuration space */
-        reg-names = "dbi", "config";
-        #address-cells = <3>;
-        #size-cells = <2>;
-        ranges = <0x81000000 0 0x00000000 0xde000000 0 0x00010000>,
-                 <0x82000000 0 0xd0400000 0xd0400000 0 0x0d000000>;
-        interrupts = <25>, <24>;
-        #interrupt-cells = <1>;
-        num-lanes = <1>;
-      };
+    pcie@1f052000 {
+      compatible = "vendor,soc-pcie", "snps,dw-pcie-4.60a", "snps,dw-pcie";
+      device_type = "pci";
+      reg = <0x1f052000 0x1000>, <0x1bdbf000 0x1000>;
+      reg-names = "dbi", "config";
+      #address-cells = <3>;
+      #size-cells = <2>;
+      ranges = <0x81000000 0 0x00000000 0x1bdb0000 0 0x00008000>,
+               <0x82000000 0 0x20000000 0x08000000 0 0x13db0000>;
+      bus-range = <0x0 0xff>;
+
+      interrupts = <0 80 4>;
+      interrupt-names = "msi";
+
+      reset-gpios = <&port0 0 1>;
+
+      num-lanes = <4>;
+      max-link-speed = <3>;
     };
+...
diff --git a/Documentation/devicetree/bindings/pci/toshiba,visconti-pcie.yaml b/Documentation/devicetree/bindings/pci/toshiba,visconti-pcie.yaml
index 30b6396d83c8..f0a3c436c6d1 100644
--- a/Documentation/devicetree/bindings/pci/toshiba,visconti-pcie.yaml
+++ b/Documentation/devicetree/bindings/pci/toshiba,visconti-pcie.yaml
@@ -13,7 +13,7 @@ description:
   Toshiba Visconti5 SoC PCIe host controller is based on the Synopsys DesignWare PCIe IP.
 
 allOf:
-  - $ref: /schemas/pci/snps,dw-pcie.yaml#
+  - $ref: /schemas/pci/snps,dw-pcie-common.yaml#
 
 properties:
   compatible:
-- 
2.35.1


_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv

^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 01/16] dt-bindings: PCI: dwc: Define generic and native DT bindings
@ 2022-03-24  1:37   ` Serge Semin
  0 siblings, 0 replies; 40+ messages in thread
From: Serge Semin @ 2022-03-24  1:37 UTC (permalink / raw)
  To: Jingoo Han, Gustavo Pimentel, Bjorn Helgaas, Richard Zhu,
	Lucas Stach, Rob Herring, Shawn Guo, Sascha Hauer,
	Pengutronix Kernel Team, Fabio Estevam, NXP Linux Team,
	Xiaowei Song, Binghui Wang, Paul Walmsley, Greentime Hu,
	Palmer Dabbelt, Nobuhiro Iwamatsu
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Lorenzo Pieralisi, Rob Herring, Krzysztof Wilczyński,
	Frank Li, Manivannan Sadhasivam, linux-pci, devicetree,
	linux-kernel, linux-arm-kernel, linux-riscv

Currently both DW PCIe Root Port and End-point DT bindings are too generic
to be used as a descriptive set the device properties. Yes, it's very handy
to have them that way so the DT-schemas could be used to evaluate as many
DW PCIe-related DT-nodes as possible. But at the same time they don't
provide well defined DW PCIe RP/EP DT interface description thus leaving
too much flexibility for the new platforms, no encouraging the developers
to preserve a compatible interface.

Instead of currently implemented approach we suggest to be more
restrictive and yet preserve some level of flexibility in the DW PCIe
DT-bindings description. The device tree DT-schema is split up into
three parts: a common YAML-schema applicable for both DWC Root Port and
End-point controller configs, DWC PCIe Root Port-specific YAML-schema
and DWC PCIe End-point-specific YAML-schema, where
1) pci/snps,dw-pcie-common.yaml - The common DT-schema describes the most
generic constraints of the "reg", "interrupts", "clocks", "resets" and
"phys" properties together with a set of common for both device types
PCIe/AXI bus properties like a maximum number of lanes or a maximum link
speed, number of inbound and outbound iATU windows. In addition to that a
set of schema definitions declared under the "$defs" property with "reg",
"interrupt", "clock" and "reset" names common for DWC PCIe Root Port and
End-point devices. They can be used by the successive DT-schemas in case
they are supposed to be compatible with the generic DWC PCIe controller
DT-bindings.
2) pci/snps,dw-pcie.yaml, pci/snps,dw-pcie-ep.yaml - generic DW PCIe Root
Port and End-point DT-bindings which aside with the device-specific
properties set also contain more restrictive constraints. All new DW PCIe
platforms are supposed to be compatible with one of these bindings by
using "allOf: " property and additionally defining their own constraints
to close up the DT-bindings set.

So to speak in case if a DW PCIe-based device for some reason has too many
specific properties or it's bindings have already been defined in a
non-generic way, it's DT-schema is supposed to include 1) YAML-file and
provide its own constraints. Otherwise the ready-to-use bindings from 2)
should be utilized. There only two DT-schemas compatible with 2) at the
moment are samsung,axynos-pcie.yaml and intel-gw-pcie.yaml. The
rest of the DW PCIe-related DT-schemas are supposed to use more generic
DW PCIe DT-bindings - pci/snps,dw-pcie-common.yaml.

Note the provided here generic properties and their possible values are
derived from the DW PCIe RC/EP hardware manuals and from the interface
implemented in the driver. The DT-bindings schemas are created to be as
full as possible with detailed properties/names description for the
easier interface comprehension and new platforms bindings development.

Also note since there are no generic DT-nodes can be found in the kernel
dts-es which would have a pure "snps,dw-pcie" compatible string, these
DT-bindings have been created to not be selected by default for
evaluation. They are supposed to be used by the new vendor-specific
DT-schemas to at least stop adding new bindings for the same set of DWC
PCIe signals or properties.

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>

---

Rob, if you comment the "select: false" line out you'll get a lot of "'*'
is not of type 'array'" errors on the dt_bindings_check command execution.
I have spend tons of time trying to figure out what was wrong, but still
failed to find out a solution. For some reason the "$ref"-ed schemas
defined under the "$defs" basic property are considered by the parser as
defining an array. No matter whether I specified the "type: string"
keyword or not, as long as there is "enum" or "oneOf" keyword used in the
"*-names" property definition in "$defs" it's considered as describing an
array thus causing the errors like:

>  DTC     Documentation/devicetree/bindings/pci/snps,dw-pcie.example.dt.yaml
>  CHECK   Documentation/devicetree/bindings/pci/snps,dw-pcie.example.dt.yaml
> /.../snps,dw-pcie.example.dt.yaml: pcie@1f052000: reg-names:0: 'oneOf' conditional failed, one must be fixed:
>        'dbi' is not of type 'array'
>        From schema: /.../snps,dw-pcie.yaml
> /.../snps,dw-pcie.example.dt.yaml: pcie@1f052000: reg-names:1: 'oneOf' conditional failed, one must be fixed:
>         'config' is not of type 'array'
>         From schema: /.../snps,dw-pcie.yaml
> /.../snps,dw-pcie.example.dt.yaml: pcie@1f052000: interrupt-names:0: 'anyOf' conditional failed, one must be fixed:
>         /.../snps,dw-pcie.example.dt.yaml: pcie@1f052000: interrupt-names:0: 'oneOf' conditional failed, one must be fixed:
>                 'msi' is not of type 'array'
>         /../snps,dw-pcie.example.dt.yaml: pcie@1f052000: interrupt-names:0: 'oneOf' conditional failed, one must be fixed:
>                 'msi' is not of type 'array'
>         From schema: /.../snps,dw-pcie.yaml

As soon as I manually moved the same "$defs"-schemas into the places they
are referenced to, the errors disappeared and the DT-schemas validation
worked as expected by the semantics.

As I see it there must be some bug in the parser, otherwise I am out of
ideas how to implement the suggested in this patch design pattern. Rob,
could you take a look at the DT-schemas and help me out with debugging the
problem described above?
---
 .../bindings/pci/fsl,imx6q-pcie.yaml          |   5 +-
 .../bindings/pci/hisilicon,kirin-pcie.yaml    |   4 +-
 .../bindings/pci/sifive,fu740-pcie.yaml       |   4 +-
 .../bindings/pci/snps,dw-pcie-common.yaml     | 298 ++++++++++++++++++
 .../bindings/pci/snps,dw-pcie-ep.yaml         | 143 ++++++---
 .../devicetree/bindings/pci/snps,dw-pcie.yaml | 189 +++++++----
 .../bindings/pci/toshiba,visconti-pcie.yaml   |   2 +-
 7 files changed, 524 insertions(+), 121 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/pci/snps,dw-pcie-common.yaml

diff --git a/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.yaml b/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.yaml
index 643a6333b07b..ccb5cfdf869f 100644
--- a/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.yaml
+++ b/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.yaml
@@ -12,10 +12,11 @@ maintainers:
 
 description: |+
   This PCIe host controller is based on the Synopsys DesignWare PCIe IP
-  and thus inherits all the common properties defined in snps,dw-pcie.yaml.
+  and thus inherits all the common properties defined in
+  snps,dw-pcie-common.yaml.
 
 allOf:
-  - $ref: /schemas/pci/snps,dw-pcie.yaml#
+  - $ref: /schemas/pci/snps,dw-pcie-common.yaml#
 
 properties:
   compatible:
diff --git a/Documentation/devicetree/bindings/pci/hisilicon,kirin-pcie.yaml b/Documentation/devicetree/bindings/pci/hisilicon,kirin-pcie.yaml
index c9f04999c9cf..879d9ec41cb7 100644
--- a/Documentation/devicetree/bindings/pci/hisilicon,kirin-pcie.yaml
+++ b/Documentation/devicetree/bindings/pci/hisilicon,kirin-pcie.yaml
@@ -14,10 +14,10 @@ description: |
   Kirin PCIe host controller is based on the Synopsys DesignWare PCI core.
   It shares common functions with the PCIe DesignWare core driver and
   inherits common properties defined in
-  Documentation/devicetree/bindings/pci/snps,dw-pcie.yaml.
+  Documentation/devicetree/bindings/pci/snps,dw-pcie-common.yaml.
 
 allOf:
-  - $ref: /schemas/pci/snps,dw-pcie.yaml#
+  - $ref: /schemas/pci/snps,dw-pcie-common.yaml#
 
 properties:
   compatible:
diff --git a/Documentation/devicetree/bindings/pci/sifive,fu740-pcie.yaml b/Documentation/devicetree/bindings/pci/sifive,fu740-pcie.yaml
index 392f0ab488c2..437614257935 100644
--- a/Documentation/devicetree/bindings/pci/sifive,fu740-pcie.yaml
+++ b/Documentation/devicetree/bindings/pci/sifive,fu740-pcie.yaml
@@ -10,14 +10,14 @@ description: |+
   SiFive FU740 PCIe host controller is based on the Synopsys DesignWare
   PCI core. It shares common features with the PCIe DesignWare core and
   inherits common properties defined in
-  Documentation/devicetree/bindings/pci/snps,dw-pcie.yaml.
+  Documentation/devicetree/bindings/pci/snps,dw-pcie-common.yaml.
 
 maintainers:
   - Paul Walmsley <paul.walmsley@sifive.com>
   - Greentime Hu <greentime.hu@sifive.com>
 
 allOf:
-  - $ref: /schemas/pci/snps,dw-pcie.yaml#
+  - $ref: /schemas/pci/snps,dw-pcie-common.yaml#
 
 properties:
   compatible:
diff --git a/Documentation/devicetree/bindings/pci/snps,dw-pcie-common.yaml b/Documentation/devicetree/bindings/pci/snps,dw-pcie-common.yaml
new file mode 100644
index 000000000000..27fe1f5c450f
--- /dev/null
+++ b/Documentation/devicetree/bindings/pci/snps,dw-pcie-common.yaml
@@ -0,0 +1,298 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pci/snps,dw-pcie-common.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Synopsys DWC PCIe RP/EP controller
+
+maintainers:
+  - Jingoo Han <jingoohan1@gmail.com>
+  - Gustavo Pimentel <gustavo.pimentel@synopsys.com>
+
+properties:
+  reg:
+    description:
+      DWC PCIe CSR space is normally accessed over the dedicated Data Bus
+      Interface - DBI. In accordance with the reference manual the register
+      configuration space belongs to the Configuration-Dependent Module (CDM)
+      and is split up into several sub-parts Standard PCIe configuration
+      space, Port Logic Registers (PL), Shadow Config-space Registers,
+      iATU/eDMA registers. The particular sub-space is selected by the
+      CDM/ELBI (dbi_cs) and CS2 (dbi_cs2) signals (selector bits). Such
+      configuration provides a flexible interface for the system engineers to
+      either map the particular space at a desired MMIO address or just leave
+      them in a contiguous memory space if pure Native or AXI Bridge DBI access
+      is selected. Note the PCIe CFG-space, PL and Shadow registers are
+      specific to each activated function, while the rest of the sub-spaces
+      are common for all of them (if there are more than one).
+    minItems: 2
+    maxItems: 6
+
+  interrupts:
+    description:
+      There are two main sub-blocks which are normally capable of
+      generating interrupts. It's System Information Interface and MSI
+      interface. While the former one has some common for the Host and
+      End-point controllers IRQ-signals, the later interface is obviously
+      Root Complex specific since it's responsible for the incoming MSI
+      messages signalling. The System Information IRQ signals are mainly
+      responsible for reporting the generic PCIe hierarchy and Root
+      Complex events like VPD IO request, general AER, PME, Hot-plug, link
+      bandwidth change, link equalization request, INTx asserted/deasserted
+      Message detection, embedded DMA Tx/Rx/Error.
+    minItems: 1
+    maxItems: 26
+
+  clocks:
+    description:
+      DWC PCIe reference manual explicitly defines a set of the clocks required
+      to get the controller working correctly. In general all of them can
+      be divided into two groups':' application and core clocks. Note the
+      platforms may have some of the clock sources unspecified in case if the
+      corresponding domains are fed up from a common clock source.
+    minItems: 1
+    maxItems: 7
+
+  resets:
+    description:
+      DWC PCIe reference manual explicitly defines a set of the reset
+      signals required to be de-asserted to properly activate the controller
+      sub-parts. All of these signals can be divided into two sub-groups':'
+      application and core resets with respect to the main sub-domains they
+      are supposed to reset. Note the platforms may have some of these signals
+      unspecified in case if they are automatically handled or aggregated into
+      a comprehensive control module.
+    minItems: 1
+    maxItems: 10
+
+  reset-gpio:
+    deprecated: true
+    description:
+      Reference to the GPIO-controlled PERST# signal. It is used to reset all
+      the peripheral devices available on the PCIe bus.
+    maxItems: 1
+
+  reset-gpios:
+    description:
+      Reference to the GPIO-controlled PERST# signal. It is used to reset all
+      the peripheral devices available on the PCIe bus.
+    maxItems: 1
+
+  phys:
+    description:
+      There can be up to number of possible lanes PHYs specified.
+      Obviously each specified PHY is supposed to be able to work in the
+      PCIe mode with a speed implied by the DWC PCIe controller it is
+      attached to.
+    minItems: 1
+    maxItems: 16
+
+  phy-names:
+    minItems: 1
+    maxItems: 16
+    items:
+      pattern: '^pcie([0-9]+|-?phy)?$'
+
+  num-lanes:
+    maximum: 16
+
+  max-link-speed:
+    maximum: 4
+
+  num-ob-windows:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    deprecated: true
+    description:
+      Number of outbound address translation windows. This parameter can be
+      auto-detected based on the iATU memory writability. So there is no
+      point in having a dedicated DT-property for it.
+    maximum: 256
+
+  num-ib-windows:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    deprecated: true
+    description:
+      Number of inbound address translation windows. In the same way as
+      for the outbound AT windows, this parameter can be auto-detected based
+      on the iATU memory writability. There is no point having a dedicated
+      DT-property for it either.
+    maximum: 256
+
+  num-viewport:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    deprecated: true
+    description:
+      Number of outbound view ports configured in hardware. It's the same as
+      the number of outbound AT windows.
+    maximum: 256
+
+  snps,enable-cdm-check:
+    $ref: /schemas/types.yaml#/definitions/flag
+    description:
+      Enable automatic checking of CDM (Configuration Dependent Module)
+      registers for data corruption. CDM registers include standard PCIe
+      configuration space registers, Port Logic registers, DMA and iATU
+      registers. This feature has been available since DWC PCIe v4.80a.
+
+additionalProperties: true
+
+$defs:
+  reg-names:
+    description:
+      CSR space names common for the DWC PCIe Root Port and End-point
+      controllers.
+    oneOf:
+      - description:
+          Basic DWC PCIe controller configuration-space accessible over
+          the DBI interface. This memory space is either activated with
+          the CDM/ELBI = 0 and CS2 = 0 or is a contiguous memory region
+          with all spaces. Note iATU/eDMA CSRs are indirectly accessible
+          via the PL viewports on the DWC PCIe controllers older than
+          v4.80a.
+        const: dbi
+      - description:
+          Shadow DWC PCIe config-space registers. This space is selected
+          by setting CDM/ELBI = 0 and CS2 = 1. This is an intermix of
+          the PCI-SIG PCIe CFG-space with the shadow registers for some
+          PCI Header space, PCI Standard and Extended Structures. It's
+          mainly relevant for the end-point controller configuration,
+          but still there are some shadow registers available for the
+          Root Port mode too.
+        const: dbi2
+      - description:
+          External Local Bus registers. It's an application-dependent
+          registers normally defined by the platform engineers, which
+          are selected by setting CDM/ELBI = 1 and CS2 = 0.
+        enum: [ elbi, appl, app ]
+      - description:
+          iATU/eDMA registers common for all device functions. It's an
+          unrolled memory space with the internal Address Translation
+          Unit and Enhanced DMA, which is selected by setting CDM/ELBI = 1
+          and CS2 = 1. For IP-core releases prior v4.80a, these registers
+          have been programmed via an indirect addressing scheme using a
+          set of viewport CSRs mapped into the PL space. Note iATU is
+          normally mapped to the 0x0 address of this region, while eDMA
+          is available at 0x80000 base address.
+        enum: [ atu, atu_dma ]
+      - description:
+          Outbound iATU-available memory-region which usage scenario
+          depends on the DWC PCIe controller being either Root Port or
+          End-point. If it's Root Port then the register space shall
+          have the "config" name and it will be used to access the
+          peripheral PCIe devices configuration space. If it's PCIe
+          end-point controller, then the region shall be named as
+          "addr_space" and it will be used to generate various traffic
+          on the PCIe bus hierarchy. It's usage scenario depends on the
+          end-point functionality, for instance it can be used to create
+          MSI(X) messages.
+        enum: [ config, addr_space ]
+      - description:
+          PHY/PCS configuration registers. Some platforms can have the
+          PCS and PHY CSRs accessible over a dedicated memory mapped
+          region, but mainly these registers are indirectly accessible
+          either by means of the embedded PHY viewport schema or by some
+          platform-specific method.
+        enum: [ link, phy ]
+
+  interrupt-names:
+    description:
+      IRQ signal names common for the DWC PCIe Root Port and End-point
+      controllers.
+    oneOf:
+      - description:
+          Controller request to read or write virtual product data
+          from/to the VPD capability registers.
+        const: vpd
+      - description:
+          Link Equalization Request flag is set in the Link Status 2
+          register (applicable if the corresponding IRQ is enabled in
+          the Link Control 3 register).
+        const: l_eq
+      - description:
+          Indicates that the eDMA Tx/Rx transfer is complete or that an
+          error has occurred on the corresponding channel. eDMA can have
+          eight Tx (Write) and Rx (Read) eDMA channels thus supporting up
+          to 16 IRQ signals all together. Write eDMA channels shall go
+          first in the ordered row as per default edma_int[*] bus setup.
+        pattern: '^dma([0-9]|1[0-5])?$'
+      - description:
+          PCIe protocol correctable error or a Data Path protection
+          correctable error is detected by the automotive/safety
+          feature.
+        const: sft_ce
+      - description:
+          Indicates that the internal safety mechanism detected and
+          uncorrectable error.
+        const: sft_ue
+
+  clock-names:
+    description:
+      Reference clock names common for the DWC PCIe Root Port and End-point
+      controllers.
+    anyOf:
+      - description:
+          Data Bus Interface (DBI) clock. Clock signal for the AXI-bus
+          interface of the Configuration-Dependent Module, which is
+          basically the set of the controller CSRs.
+        enum: [ dbi, pcie ]
+      - description:
+          Application AXI-bus Master interface clock. Basically this is
+          a clock for the controller DMA interface (PCI-to-CPU).
+        enum: [ mstr, pcie_bus ]
+      - description:
+          Application AXI-bus Slave interface clock. This is a clock for
+          the CPU-to-PCI memory IO interface.
+        enum: [ slv, pcie_bus ]
+      - description:
+          Controller Core-PCS PIPE interface clock. It's normally
+          supplied by an external PCS-PHY.
+        const: pipe
+      - description:
+          Controller Primary clock. It's assumed that all controller input
+          signals (except resets) are synchronous to this clock.
+        const: core
+      - description:
+          Auxiliary clock for the controller PMC domain. The controller
+          partitioning implies having some parts to operate with this
+          clock in some power management states.
+        const: aux
+      - description:
+          Generic reference clock. In case if there are several
+          interfaces fed up with a common clock source it's advisable to
+          define it with this name (for instance pipe, core and aux can
+          be connected to a single source of the periodic signal).
+        const: ref
+      - description:
+          Clock for the PHY registers interface. Originally this is
+          a PHY-viewport-based interface, but some platform may have
+          specifically designed one.
+        const: phy_reg
+
+  reset-names:
+    description:
+      Reset signal names common for the DWC PCIe Root Port and End-point
+      controllers.
+    anyOf:
+      - description: Data Bus Interface (DBI) domain reset
+        const: dbi
+      - description: AXI-bus Master interface reset
+        const: mstr
+      - description: AXI-bus Slave interface reset
+        const: slv
+      - description: Controller Non-sticky CSR flags reset
+        const: non-sticky
+      - description: Controller sticky CSR flags reset
+        const: sticky
+      - description: PIPE-interface (Core-PCS) logic reset
+        const: pipe
+      - description:
+          Controller primary reset (resets everything except PMC module)
+        const: core
+      - description: PCS/PHY block reset
+        const: phy
+      - description: PMC hot reset signal
+        const: hot
+      - description: Cold reset signal
+        const: pwr
+...
diff --git a/Documentation/devicetree/bindings/pci/snps,dw-pcie-ep.yaml b/Documentation/devicetree/bindings/pci/snps,dw-pcie-ep.yaml
index e59059ab5be0..c3bbe90264dc 100644
--- a/Documentation/devicetree/bindings/pci/snps,dw-pcie-ep.yaml
+++ b/Documentation/devicetree/bindings/pci/snps,dw-pcie-ep.yaml
@@ -13,74 +13,115 @@ maintainers:
 description: |
   Synopsys DesignWare PCIe host controller endpoint
 
+# Please create a separate DT-schema for the particular DWC PCIe End-point
+# controller and make sure it's assigned with the vendor-specific
+# compatible string together with the generic Synopsys DWC PCIe strings so
+# the bindings would be successfully evaluated against this schema.
+select: false
+
 allOf:
   - $ref: /schemas/pci/pci-ep.yaml#
+  - $ref: snps,dw-pcie-common.yaml#
 
 properties:
   compatible:
-    anyOf:
-      - {}
-      - const: snps,dw-pcie-ep
+    contains:
+      oneOf:
+        - description:
+            DWC PCIe End-point controller (IP-core version is explicitly
+            specified in the additional compatible string)
+          items:
+            - pattern: '^snps,dw-pcie-ep-[0-9]+\.[0-9]+a?$'
+            - const: snps,dw-pcie-ep
+        - description:
+            DWC PCIe End-point controller (IP-core version is either unknown
+            or can be read from the PCIe version register of the PL reg-space)
+          const: snps,dw-pcie-ep
 
   reg:
-    description: |
-      It should contain Data Bus Interface (dbi) and config registers for all
-      versions.
-      For designware core version >= 4.80, it may contain ATU address space.
-    minItems: 2
-    maxItems: 4
+    description:
+      DBI, DBI2 reg-spaces and outbound memory window are required for the
+      normal controller functioning. iATU memory IO region is also required
+      if the space is unrolled (IP-core version >= 4.80a).
+    minItems: 3
+    maxItems: 5
 
   reg-names:
-    minItems: 2
-    maxItems: 4
+    minItems: 3
+    maxItems: 5
     items:
-      enum: [dbi, dbi2, config, atu, addr_space, link, atu_dma, appl]
-
-  reset-gpio:
-    description: GPIO pin number of PERST# signal
-    maxItems: 1
-    deprecated: true
-
-  reset-gpios:
-    description: GPIO controlled connection to PERST# signal
-    maxItems: 1
-
-  snps,enable-cdm-check:
-    type: boolean
-    description: |
-      This is a boolean property and if present enables
-      automatic checking of CDM (Configuration Dependent Module) registers
-      for data corruption. CDM registers include standard PCIe configuration
-      space registers, Port Logic registers, DMA and iATU (internal Address
-      Translation Unit) registers.
-
-  num-ib-windows:
-    description: number of inbound address translation windows
-    maxItems: 1
-    deprecated: true
-
-  num-ob-windows:
-    description: number of outbound address translation windows
-    maxItems: 1
-    deprecated: true
+      $ref: snps,dw-pcie-common.yaml#/$defs/reg-names
+    allOf:
+      - contains:
+          const: dbi
+      - contains:
+          const: dbi2
+      - contains:
+          const: addr_space
+
+  interrupts:
+    description:
+      There is no mandatory IRQ signals for the normal controller functioning,
+      but in addition to the native set the platforms may have a link- or
+      PM-related IRQs specified.
+    minItems: 1
+    maxItems: 20
+
+  interrupt-names:
+    minItems: 1
+    maxItems: 20
+    items:
+      $ref: snps,dw-pcie-common.yaml#/$defs/interrupt-names
+
+  clocks:
+    minItems: 1
+    maxItems: 7
+
+  clock-names:
+    minItems: 1
+    maxItems: 7
+    items:
+      $ref: snps,dw-pcie-common.yaml#/$defs/clock-names
+
+  resets:
+    minItems: 1
+    maxItems: 10
+
+  reset-names:
+    minItems: 1
+    maxItems: 10
+    items:
+      $ref: snps,dw-pcie-common.yaml#/$defs/reset-names
+
+  max-functions:
+    maximum: 32
 
 required:
+  - compatible
   - reg
   - reg-names
-  - compatible
 
 additionalProperties: true
 
 examples:
   - |
-    bus {
-      #address-cells = <1>;
-      #size-cells = <1>;
-      pcie-ep@dfd00000 {
-        compatible = "snps,dw-pcie-ep";
-        reg = <0xdfc00000 0x0001000>, /* IP registers 1 */
-              <0xdfc01000 0x0001000>, /* IP registers 2 */
-              <0xd0000000 0x2000000>; /* Configuration space */
-        reg-names = "dbi", "dbi2", "addr_space";
-      };
+    pcie-ep@1f052000 {
+      compatible = "vendor,soc-pcie", "snps,dw-pcie-ep-4.60a", "snps,dw-pcie-ep";
+      reg = <0x66000000 0x1000>, <0x66010000 0x10000>, <0x67000000 0x400000>;
+      reg-names = "dbi", "dbi2", "addr_space";
+
+      clocks = <&sys_clk 12>, <&sys_clk 24>;
+      clock-names = "dbi", "ref";
+
+      resets = <&sys_rst 12>, <&sys_rst 24>;
+      reset-names = "dbi", "phy";
+
+      phys = <&pcie_phy>;
+      phy-names = "pcie-phy";
+
+      num-lanes = <4>;
+      max-link-speed = <4>;
+      num-ib-windows = <16>;
+      num-ob-windows = <16>;
     };
+...
diff --git a/Documentation/devicetree/bindings/pci/snps,dw-pcie.yaml b/Documentation/devicetree/bindings/pci/snps,dw-pcie.yaml
index a5345c494744..6c397ae3c71a 100644
--- a/Documentation/devicetree/bindings/pci/snps,dw-pcie.yaml
+++ b/Documentation/devicetree/bindings/pci/snps,dw-pcie.yaml
@@ -13,20 +13,36 @@ maintainers:
 description: |
   Synopsys DesignWare PCIe host controller
 
+# Please create a separate DT-schema for the particular DWC PCIe Root Port
+# controller and make sure it's assigned with the vendor-specific
+# compatible string together with the generic Synopsys DWC PCIe strings so
+# the bindings would be successfully evaluated against this schema.
+select: false
+
 allOf:
   - $ref: /schemas/pci/pci-bus.yaml#
+  - $ref: snps,dw-pcie-common.yaml#
 
 properties:
   compatible:
-    anyOf:
-      - {}
-      - const: snps,dw-pcie
+    contains:
+      oneOf:
+        - description:
+            DWC PCIe Root Port controller (IP-core version is explicitly
+            specified in the additional compatible string)
+          items:
+            - pattern: '^snps,dw-pcie-[0-9]+\.[0-9]+a?$'
+            - const: snps,dw-pcie
+        - description:
+            DWC PCIe Root Port controller (IP-core version is either unknown
+            or can be read from the PCIe version register of the PL reg-space)
+          const: snps,dw-pcie
 
   reg:
-    description: |
-      It should contain Data Bus Interface (dbi) and config registers for all
-      versions.
-      For designware core version >= 4.80, it may contain ATU address space.
+    description:
+      At least DBI reg-space and peripheral devices CFG-space outbound window
+      are required for the normal controller work. iATU memory IO region is
+      also required if the space is unrolled (IP-core version >= 4.80a).
     minItems: 2
     maxItems: 5
 
@@ -34,69 +50,116 @@ properties:
     minItems: 2
     maxItems: 5
     items:
-      enum: [ dbi, dbi2, config, atu, app, elbi, mgmt, ctrl, parf, cfg, link,
-              ulreg, smu, mpu, apb, phy ]
-
-  num-lanes:
-    description: |
-      number of lanes to use (this property should be specified unless
-      the link is brought already up in firmware)
-    maximum: 16
-
-  reset-gpio:
-    description: GPIO pin number of PERST# signal
-    maxItems: 1
-    deprecated: true
-
-  reset-gpios:
-    description: GPIO controlled connection to PERST# signal
-    maxItems: 1
-
-  interrupts: true
-
-  interrupt-names: true
-
-  clocks: true
-
-  snps,enable-cdm-check:
-    type: boolean
-    description: |
-      This is a boolean property and if present enables
-      automatic checking of CDM (Configuration Dependent Module) registers
-      for data corruption. CDM registers include standard PCIe configuration
-      space registers, Port Logic registers, DMA and iATU (internal Address
-      Translation Unit) registers.
+      $ref: snps,dw-pcie-common.yaml#/$defs/reg-names
+    allOf:
+      - contains:
+          const: dbi
+      - contains:
+          const: config
+
+  interrupts:
+    description:
+      At least MSI interrupt signal is supposed to be specified for
+      the DWC PCIe host controller.
+    minItems: 1
+    maxItems: 26
+
+  interrupt-names:
+    minItems: 1
+    maxItems: 26
+    items:
+      anyOf:
+        - $ref: snps,dw-pcie-common.yaml#/$defs/interrupt-names
+        - $ref: '#/$defs/interrupt-names'
+    allOf:
+      - contains:
+          const: msi
+
+  clocks:
+    minItems: 1
+    maxItems: 7
+
+  clock-names:
+    minItems: 1
+    maxItems: 7
+    items:
+      $ref: snps,dw-pcie-common.yaml#/$defs/clock-names
 
-  num-viewport:
-    description: |
-      number of view ports configured in hardware. If a platform
-      does not specify it, the driver autodetects it.
-    deprecated: true
+  resets:
+    minItems: 1
+    maxItems: 10
 
-additionalProperties: true
+  reset-names:
+    minItems: 1
+    maxItems: 10
+    items:
+      $ref: snps,dw-pcie-common.yaml#/$defs/reset-names
 
 required:
+  - compatible
   - reg
   - reg-names
-  - compatible
+  - interrupts
+  - interrupt-names
+
+additionalProperties: true
+
+$defs:
+  interrupt-names:
+    description:
+      DWC PCIe Root Port/Complex specific IRQ signal names.
+    oneOf:
+      - description:
+          DSP AXI MSI Interrupt detected. It gets de-asserted when there is
+          no more MSI interrupt pending. The interrupt is relevant to the
+          iMSI-RX - Integrated MSI Receiver (AXI bridge).
+        const: msi
+      - description:
+          Error condition detected and a bit is set in the Root Error Status
+          register of the AER capability. It's asserted when the RC
+          internally generated an error or an error message is received by
+          the RC.
+        const: aer
+      - description:
+          PME message is received by the port. That means having the PME
+          status bit set in the Root Status register (the event is
+          supposed to be unmasked in the Root Control register).
+        const: pme
+      - description:
+          Hot-plug event is detected. That is a bit has been set in the
+          Slot Status register and the corresponding event is enabled in
+          the Slot Control register.
+        const: hp
+      - description:
+          Link Autonomous Bandwidth Status flag has been set in the Link
+          Status register (the event is supposed to be unmasked in the
+          Link Control register).
+        const: bw_au
+      - description:
+          Bandwidth Management Status flag has been set in the Link
+          Status register (the event is supposed to be unmasked in the
+          Link Control register).
+        const: bw_mg
 
 examples:
   - |
-    bus {
-      #address-cells = <1>;
-      #size-cells = <1>;
-      pcie@dfc00000 {
-        device_type = "pci";
-        compatible = "snps,dw-pcie";
-        reg = <0xdfc00000 0x0001000>, /* IP registers */
-              <0xd0000000 0x0002000>; /* Configuration space */
-        reg-names = "dbi", "config";
-        #address-cells = <3>;
-        #size-cells = <2>;
-        ranges = <0x81000000 0 0x00000000 0xde000000 0 0x00010000>,
-                 <0x82000000 0 0xd0400000 0xd0400000 0 0x0d000000>;
-        interrupts = <25>, <24>;
-        #interrupt-cells = <1>;
-        num-lanes = <1>;
-      };
+    pcie@1f052000 {
+      compatible = "vendor,soc-pcie", "snps,dw-pcie-4.60a", "snps,dw-pcie";
+      device_type = "pci";
+      reg = <0x1f052000 0x1000>, <0x1bdbf000 0x1000>;
+      reg-names = "dbi", "config";
+      #address-cells = <3>;
+      #size-cells = <2>;
+      ranges = <0x81000000 0 0x00000000 0x1bdb0000 0 0x00008000>,
+               <0x82000000 0 0x20000000 0x08000000 0 0x13db0000>;
+      bus-range = <0x0 0xff>;
+
+      interrupts = <0 80 4>;
+      interrupt-names = "msi";
+
+      reset-gpios = <&port0 0 1>;
+
+      num-lanes = <4>;
+      max-link-speed = <3>;
     };
+...
diff --git a/Documentation/devicetree/bindings/pci/toshiba,visconti-pcie.yaml b/Documentation/devicetree/bindings/pci/toshiba,visconti-pcie.yaml
index 30b6396d83c8..f0a3c436c6d1 100644
--- a/Documentation/devicetree/bindings/pci/toshiba,visconti-pcie.yaml
+++ b/Documentation/devicetree/bindings/pci/toshiba,visconti-pcie.yaml
@@ -13,7 +13,7 @@ description:
   Toshiba Visconti5 SoC PCIe host controller is based on the Synopsys DesignWare PCIe IP.
 
 allOf:
-  - $ref: /schemas/pci/snps,dw-pcie.yaml#
+  - $ref: /schemas/pci/snps,dw-pcie-common.yaml#
 
 properties:
   compatible:
-- 
2.35.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 01/16] dt-bindings: PCI: dwc: Define generic and native DT bindings
@ 2022-03-24  1:37   ` Serge Semin
  0 siblings, 0 replies; 40+ messages in thread
From: Serge Semin @ 2022-03-24  1:37 UTC (permalink / raw)
  To: Jingoo Han, Gustavo Pimentel, Bjorn Helgaas, Richard Zhu,
	Lucas Stach, Rob Herring, Shawn Guo, Sascha Hauer,
	Pengutronix Kernel Team, Fabio Estevam, NXP Linux Team,
	Xiaowei Song, Binghui Wang, Paul Walmsley, Greentime Hu,
	Palmer Dabbelt, Nobuhiro Iwamatsu
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Lorenzo Pieralisi, Rob Herring, Krzysztof Wilczyński,
	Frank Li, Manivannan Sadhasivam, linux-pci, devicetree,
	linux-kernel, linux-arm-kernel, linux-riscv

Currently both DW PCIe Root Port and End-point DT bindings are too generic
to be used as a descriptive set the device properties. Yes, it's very handy
to have them that way so the DT-schemas could be used to evaluate as many
DW PCIe-related DT-nodes as possible. But at the same time they don't
provide well defined DW PCIe RP/EP DT interface description thus leaving
too much flexibility for the new platforms, no encouraging the developers
to preserve a compatible interface.

Instead of currently implemented approach we suggest to be more
restrictive and yet preserve some level of flexibility in the DW PCIe
DT-bindings description. The device tree DT-schema is split up into
three parts: a common YAML-schema applicable for both DWC Root Port and
End-point controller configs, DWC PCIe Root Port-specific YAML-schema
and DWC PCIe End-point-specific YAML-schema, where
1) pci/snps,dw-pcie-common.yaml - The common DT-schema describes the most
generic constraints of the "reg", "interrupts", "clocks", "resets" and
"phys" properties together with a set of common for both device types
PCIe/AXI bus properties like a maximum number of lanes or a maximum link
speed, number of inbound and outbound iATU windows. In addition to that a
set of schema definitions declared under the "$defs" property with "reg",
"interrupt", "clock" and "reset" names common for DWC PCIe Root Port and
End-point devices. They can be used by the successive DT-schemas in case
they are supposed to be compatible with the generic DWC PCIe controller
DT-bindings.
2) pci/snps,dw-pcie.yaml, pci/snps,dw-pcie-ep.yaml - generic DW PCIe Root
Port and End-point DT-bindings which aside with the device-specific
properties set also contain more restrictive constraints. All new DW PCIe
platforms are supposed to be compatible with one of these bindings by
using "allOf: " property and additionally defining their own constraints
to close up the DT-bindings set.

So to speak in case if a DW PCIe-based device for some reason has too many
specific properties or it's bindings have already been defined in a
non-generic way, it's DT-schema is supposed to include 1) YAML-file and
provide its own constraints. Otherwise the ready-to-use bindings from 2)
should be utilized. There only two DT-schemas compatible with 2) at the
moment are samsung,axynos-pcie.yaml and intel-gw-pcie.yaml. The
rest of the DW PCIe-related DT-schemas are supposed to use more generic
DW PCIe DT-bindings - pci/snps,dw-pcie-common.yaml.

Note the provided here generic properties and their possible values are
derived from the DW PCIe RC/EP hardware manuals and from the interface
implemented in the driver. The DT-bindings schemas are created to be as
full as possible with detailed properties/names description for the
easier interface comprehension and new platforms bindings development.

Also note since there are no generic DT-nodes can be found in the kernel
dts-es which would have a pure "snps,dw-pcie" compatible string, these
DT-bindings have been created to not be selected by default for
evaluation. They are supposed to be used by the new vendor-specific
DT-schemas to at least stop adding new bindings for the same set of DWC
PCIe signals or properties.

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>

---

Rob, if you comment the "select: false" line out you'll get a lot of "'*'
is not of type 'array'" errors on the dt_bindings_check command execution.
I have spend tons of time trying to figure out what was wrong, but still
failed to find out a solution. For some reason the "$ref"-ed schemas
defined under the "$defs" basic property are considered by the parser as
defining an array. No matter whether I specified the "type: string"
keyword or not, as long as there is "enum" or "oneOf" keyword used in the
"*-names" property definition in "$defs" it's considered as describing an
array thus causing the errors like:

>  DTC     Documentation/devicetree/bindings/pci/snps,dw-pcie.example.dt.yaml
>  CHECK   Documentation/devicetree/bindings/pci/snps,dw-pcie.example.dt.yaml
> /.../snps,dw-pcie.example.dt.yaml: pcie@1f052000: reg-names:0: 'oneOf' conditional failed, one must be fixed:
>        'dbi' is not of type 'array'
>        From schema: /.../snps,dw-pcie.yaml
> /.../snps,dw-pcie.example.dt.yaml: pcie@1f052000: reg-names:1: 'oneOf' conditional failed, one must be fixed:
>         'config' is not of type 'array'
>         From schema: /.../snps,dw-pcie.yaml
> /.../snps,dw-pcie.example.dt.yaml: pcie@1f052000: interrupt-names:0: 'anyOf' conditional failed, one must be fixed:
>         /.../snps,dw-pcie.example.dt.yaml: pcie@1f052000: interrupt-names:0: 'oneOf' conditional failed, one must be fixed:
>                 'msi' is not of type 'array'
>         /../snps,dw-pcie.example.dt.yaml: pcie@1f052000: interrupt-names:0: 'oneOf' conditional failed, one must be fixed:
>                 'msi' is not of type 'array'
>         From schema: /.../snps,dw-pcie.yaml

As soon as I manually moved the same "$defs"-schemas into the places they
are referenced to, the errors disappeared and the DT-schemas validation
worked as expected by the semantics.

As I see it there must be some bug in the parser, otherwise I am out of
ideas how to implement the suggested in this patch design pattern. Rob,
could you take a look at the DT-schemas and help me out with debugging the
problem described above?
---
 .../bindings/pci/fsl,imx6q-pcie.yaml          |   5 +-
 .../bindings/pci/hisilicon,kirin-pcie.yaml    |   4 +-
 .../bindings/pci/sifive,fu740-pcie.yaml       |   4 +-
 .../bindings/pci/snps,dw-pcie-common.yaml     | 298 ++++++++++++++++++
 .../bindings/pci/snps,dw-pcie-ep.yaml         | 143 ++++++---
 .../devicetree/bindings/pci/snps,dw-pcie.yaml | 189 +++++++----
 .../bindings/pci/toshiba,visconti-pcie.yaml   |   2 +-
 7 files changed, 524 insertions(+), 121 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/pci/snps,dw-pcie-common.yaml

diff --git a/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.yaml b/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.yaml
index 643a6333b07b..ccb5cfdf869f 100644
--- a/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.yaml
+++ b/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.yaml
@@ -12,10 +12,11 @@ maintainers:
 
 description: |+
   This PCIe host controller is based on the Synopsys DesignWare PCIe IP
-  and thus inherits all the common properties defined in snps,dw-pcie.yaml.
+  and thus inherits all the common properties defined in
+  snps,dw-pcie-common.yaml.
 
 allOf:
-  - $ref: /schemas/pci/snps,dw-pcie.yaml#
+  - $ref: /schemas/pci/snps,dw-pcie-common.yaml#
 
 properties:
   compatible:
diff --git a/Documentation/devicetree/bindings/pci/hisilicon,kirin-pcie.yaml b/Documentation/devicetree/bindings/pci/hisilicon,kirin-pcie.yaml
index c9f04999c9cf..879d9ec41cb7 100644
--- a/Documentation/devicetree/bindings/pci/hisilicon,kirin-pcie.yaml
+++ b/Documentation/devicetree/bindings/pci/hisilicon,kirin-pcie.yaml
@@ -14,10 +14,10 @@ description: |
   Kirin PCIe host controller is based on the Synopsys DesignWare PCI core.
   It shares common functions with the PCIe DesignWare core driver and
   inherits common properties defined in
-  Documentation/devicetree/bindings/pci/snps,dw-pcie.yaml.
+  Documentation/devicetree/bindings/pci/snps,dw-pcie-common.yaml.
 
 allOf:
-  - $ref: /schemas/pci/snps,dw-pcie.yaml#
+  - $ref: /schemas/pci/snps,dw-pcie-common.yaml#
 
 properties:
   compatible:
diff --git a/Documentation/devicetree/bindings/pci/sifive,fu740-pcie.yaml b/Documentation/devicetree/bindings/pci/sifive,fu740-pcie.yaml
index 392f0ab488c2..437614257935 100644
--- a/Documentation/devicetree/bindings/pci/sifive,fu740-pcie.yaml
+++ b/Documentation/devicetree/bindings/pci/sifive,fu740-pcie.yaml
@@ -10,14 +10,14 @@ description: |+
   SiFive FU740 PCIe host controller is based on the Synopsys DesignWare
   PCI core. It shares common features with the PCIe DesignWare core and
   inherits common properties defined in
-  Documentation/devicetree/bindings/pci/snps,dw-pcie.yaml.
+  Documentation/devicetree/bindings/pci/snps,dw-pcie-common.yaml.
 
 maintainers:
   - Paul Walmsley <paul.walmsley@sifive.com>
   - Greentime Hu <greentime.hu@sifive.com>
 
 allOf:
-  - $ref: /schemas/pci/snps,dw-pcie.yaml#
+  - $ref: /schemas/pci/snps,dw-pcie-common.yaml#
 
 properties:
   compatible:
diff --git a/Documentation/devicetree/bindings/pci/snps,dw-pcie-common.yaml b/Documentation/devicetree/bindings/pci/snps,dw-pcie-common.yaml
new file mode 100644
index 000000000000..27fe1f5c450f
--- /dev/null
+++ b/Documentation/devicetree/bindings/pci/snps,dw-pcie-common.yaml
@@ -0,0 +1,298 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pci/snps,dw-pcie-common.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Synopsys DWC PCIe RP/EP controller
+
+maintainers:
+  - Jingoo Han <jingoohan1@gmail.com>
+  - Gustavo Pimentel <gustavo.pimentel@synopsys.com>
+
+properties:
+  reg:
+    description:
+      DWC PCIe CSR space is normally accessed over the dedicated Data Bus
+      Interface - DBI. In accordance with the reference manual the register
+      configuration space belongs to the Configuration-Dependent Module (CDM)
+      and is split up into several sub-parts Standard PCIe configuration
+      space, Port Logic Registers (PL), Shadow Config-space Registers,
+      iATU/eDMA registers. The particular sub-space is selected by the
+      CDM/ELBI (dbi_cs) and CS2 (dbi_cs2) signals (selector bits). Such
+      configuration provides a flexible interface for the system engineers to
+      either map the particular space at a desired MMIO address or just leave
+      them in a contiguous memory space if pure Native or AXI Bridge DBI access
+      is selected. Note the PCIe CFG-space, PL and Shadow registers are
+      specific to each activated function, while the rest of the sub-spaces
+      are common for all of them (if there are more than one).
+    minItems: 2
+    maxItems: 6
+
+  interrupts:
+    description:
+      There are two main sub-blocks which are normally capable of
+      generating interrupts. It's System Information Interface and MSI
+      interface. While the former one has some common for the Host and
+      End-point controllers IRQ-signals, the later interface is obviously
+      Root Complex specific since it's responsible for the incoming MSI
+      messages signalling. The System Information IRQ signals are mainly
+      responsible for reporting the generic PCIe hierarchy and Root
+      Complex events like VPD IO request, general AER, PME, Hot-plug, link
+      bandwidth change, link equalization request, INTx asserted/deasserted
+      Message detection, embedded DMA Tx/Rx/Error.
+    minItems: 1
+    maxItems: 26
+
+  clocks:
+    description:
+      DWC PCIe reference manual explicitly defines a set of the clocks required
+      to get the controller working correctly. In general all of them can
+      be divided into two groups':' application and core clocks. Note the
+      platforms may have some of the clock sources unspecified in case if the
+      corresponding domains are fed up from a common clock source.
+    minItems: 1
+    maxItems: 7
+
+  resets:
+    description:
+      DWC PCIe reference manual explicitly defines a set of the reset
+      signals required to be de-asserted to properly activate the controller
+      sub-parts. All of these signals can be divided into two sub-groups':'
+      application and core resets with respect to the main sub-domains they
+      are supposed to reset. Note the platforms may have some of these signals
+      unspecified in case if they are automatically handled or aggregated into
+      a comprehensive control module.
+    minItems: 1
+    maxItems: 10
+
+  reset-gpio:
+    deprecated: true
+    description:
+      Reference to the GPIO-controlled PERST# signal. It is used to reset all
+      the peripheral devices available on the PCIe bus.
+    maxItems: 1
+
+  reset-gpios:
+    description:
+      Reference to the GPIO-controlled PERST# signal. It is used to reset all
+      the peripheral devices available on the PCIe bus.
+    maxItems: 1
+
+  phys:
+    description:
+      There can be up to number of possible lanes PHYs specified.
+      Obviously each specified PHY is supposed to be able to work in the
+      PCIe mode with a speed implied by the DWC PCIe controller it is
+      attached to.
+    minItems: 1
+    maxItems: 16
+
+  phy-names:
+    minItems: 1
+    maxItems: 16
+    items:
+      pattern: '^pcie([0-9]+|-?phy)?$'
+
+  num-lanes:
+    maximum: 16
+
+  max-link-speed:
+    maximum: 4
+
+  num-ob-windows:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    deprecated: true
+    description:
+      Number of outbound address translation windows. This parameter can be
+      auto-detected based on the iATU memory writability. So there is no
+      point in having a dedicated DT-property for it.
+    maximum: 256
+
+  num-ib-windows:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    deprecated: true
+    description:
+      Number of inbound address translation windows. In the same way as
+      for the outbound AT windows, this parameter can be auto-detected based
+      on the iATU memory writability. There is no point having a dedicated
+      DT-property for it either.
+    maximum: 256
+
+  num-viewport:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    deprecated: true
+    description:
+      Number of outbound view ports configured in hardware. It's the same as
+      the number of outbound AT windows.
+    maximum: 256
+
+  snps,enable-cdm-check:
+    $ref: /schemas/types.yaml#/definitions/flag
+    description:
+      Enable automatic checking of CDM (Configuration Dependent Module)
+      registers for data corruption. CDM registers include standard PCIe
+      configuration space registers, Port Logic registers, DMA and iATU
+      registers. This feature has been available since DWC PCIe v4.80a.
+
+additionalProperties: true
+
+$defs:
+  reg-names:
+    description:
+      CSR space names common for the DWC PCIe Root Port and End-point
+      controllers.
+    oneOf:
+      - description:
+          Basic DWC PCIe controller configuration-space accessible over
+          the DBI interface. This memory space is either activated with
+          the CDM/ELBI = 0 and CS2 = 0 or is a contiguous memory region
+          with all spaces. Note iATU/eDMA CSRs are indirectly accessible
+          via the PL viewports on the DWC PCIe controllers older than
+          v4.80a.
+        const: dbi
+      - description:
+          Shadow DWC PCIe config-space registers. This space is selected
+          by setting CDM/ELBI = 0 and CS2 = 1. This is an intermix of
+          the PCI-SIG PCIe CFG-space with the shadow registers for some
+          PCI Header space, PCI Standard and Extended Structures. It's
+          mainly relevant for the end-point controller configuration,
+          but still there are some shadow registers available for the
+          Root Port mode too.
+        const: dbi2
+      - description:
+          External Local Bus registers. It's an application-dependent
+          registers normally defined by the platform engineers, which
+          are selected by setting CDM/ELBI = 1 and CS2 = 0.
+        enum: [ elbi, appl, app ]
+      - description:
+          iATU/eDMA registers common for all device functions. It's an
+          unrolled memory space with the internal Address Translation
+          Unit and Enhanced DMA, which is selected by setting CDM/ELBI = 1
+          and CS2 = 1. For IP-core releases prior v4.80a, these registers
+          have been programmed via an indirect addressing scheme using a
+          set of viewport CSRs mapped into the PL space. Note iATU is
+          normally mapped to the 0x0 address of this region, while eDMA
+          is available at 0x80000 base address.
+        enum: [ atu, atu_dma ]
+      - description:
+          Outbound iATU-available memory-region which usage scenario
+          depends on the DWC PCIe controller being either Root Port or
+          End-point. If it's Root Port then the register space shall
+          have the "config" name and it will be used to access the
+          peripheral PCIe devices configuration space. If it's PCIe
+          end-point controller, then the region shall be named as
+          "addr_space" and it will be used to generate various traffic
+          on the PCIe bus hierarchy. It's usage scenario depends on the
+          end-point functionality, for instance it can be used to create
+          MSI(X) messages.
+        enum: [ config, addr_space ]
+      - description:
+          PHY/PCS configuration registers. Some platforms can have the
+          PCS and PHY CSRs accessible over a dedicated memory mapped
+          region, but mainly these registers are indirectly accessible
+          either by means of the embedded PHY viewport schema or by some
+          platform-specific method.
+        enum: [ link, phy ]
+
+  interrupt-names:
+    description:
+      IRQ signal names common for the DWC PCIe Root Port and End-point
+      controllers.
+    oneOf:
+      - description:
+          Controller request to read or write virtual product data
+          from/to the VPD capability registers.
+        const: vpd
+      - description:
+          Link Equalization Request flag is set in the Link Status 2
+          register (applicable if the corresponding IRQ is enabled in
+          the Link Control 3 register).
+        const: l_eq
+      - description:
+          Indicates that the eDMA Tx/Rx transfer is complete or that an
+          error has occurred on the corresponding channel. eDMA can have
+          eight Tx (Write) and Rx (Read) eDMA channels thus supporting up
+          to 16 IRQ signals all together. Write eDMA channels shall go
+          first in the ordered row as per default edma_int[*] bus setup.
+        pattern: '^dma([0-9]|1[0-5])?$'
+      - description:
+          PCIe protocol correctable error or a Data Path protection
+          correctable error is detected by the automotive/safety
+          feature.
+        const: sft_ce
+      - description:
+          Indicates that the internal safety mechanism detected and
+          uncorrectable error.
+        const: sft_ue
+
+  clock-names:
+    description:
+      Reference clock names common for the DWC PCIe Root Port and End-point
+      controllers.
+    anyOf:
+      - description:
+          Data Bus Interface (DBI) clock. Clock signal for the AXI-bus
+          interface of the Configuration-Dependent Module, which is
+          basically the set of the controller CSRs.
+        enum: [ dbi, pcie ]
+      - description:
+          Application AXI-bus Master interface clock. Basically this is
+          a clock for the controller DMA interface (PCI-to-CPU).
+        enum: [ mstr, pcie_bus ]
+      - description:
+          Application AXI-bus Slave interface clock. This is a clock for
+          the CPU-to-PCI memory IO interface.
+        enum: [ slv, pcie_bus ]
+      - description:
+          Controller Core-PCS PIPE interface clock. It's normally
+          supplied by an external PCS-PHY.
+        const: pipe
+      - description:
+          Controller Primary clock. It's assumed that all controller input
+          signals (except resets) are synchronous to this clock.
+        const: core
+      - description:
+          Auxiliary clock for the controller PMC domain. The controller
+          partitioning implies having some parts to operate with this
+          clock in some power management states.
+        const: aux
+      - description:
+          Generic reference clock. In case if there are several
+          interfaces fed up with a common clock source it's advisable to
+          define it with this name (for instance pipe, core and aux can
+          be connected to a single source of the periodic signal).
+        const: ref
+      - description:
+          Clock for the PHY registers interface. Originally this is
+          a PHY-viewport-based interface, but some platform may have
+          specifically designed one.
+        const: phy_reg
+
+  reset-names:
+    description:
+      Reset signal names common for the DWC PCIe Root Port and End-point
+      controllers.
+    anyOf:
+      - description: Data Bus Interface (DBI) domain reset
+        const: dbi
+      - description: AXI-bus Master interface reset
+        const: mstr
+      - description: AXI-bus Slave interface reset
+        const: slv
+      - description: Controller Non-sticky CSR flags reset
+        const: non-sticky
+      - description: Controller sticky CSR flags reset
+        const: sticky
+      - description: PIPE-interface (Core-PCS) logic reset
+        const: pipe
+      - description:
+          Controller primary reset (resets everything except PMC module)
+        const: core
+      - description: PCS/PHY block reset
+        const: phy
+      - description: PMC hot reset signal
+        const: hot
+      - description: Cold reset signal
+        const: pwr
+...
diff --git a/Documentation/devicetree/bindings/pci/snps,dw-pcie-ep.yaml b/Documentation/devicetree/bindings/pci/snps,dw-pcie-ep.yaml
index e59059ab5be0..c3bbe90264dc 100644
--- a/Documentation/devicetree/bindings/pci/snps,dw-pcie-ep.yaml
+++ b/Documentation/devicetree/bindings/pci/snps,dw-pcie-ep.yaml
@@ -13,74 +13,115 @@ maintainers:
 description: |
   Synopsys DesignWare PCIe host controller endpoint
 
+# Please create a separate DT-schema for the particular DWC PCIe End-point
+# controller and make sure it's assigned with the vendor-specific
+# compatible string together with the generic Synopsys DWC PCIe strings so
+# the bindings would be successfully evaluated against this schema.
+select: false
+
 allOf:
   - $ref: /schemas/pci/pci-ep.yaml#
+  - $ref: snps,dw-pcie-common.yaml#
 
 properties:
   compatible:
-    anyOf:
-      - {}
-      - const: snps,dw-pcie-ep
+    contains:
+      oneOf:
+        - description:
+            DWC PCIe End-point controller (IP-core version is explicitly
+            specified in the additional compatible string)
+          items:
+            - pattern: '^snps,dw-pcie-ep-[0-9]+\.[0-9]+a?$'
+            - const: snps,dw-pcie-ep
+        - description:
+            DWC PCIe End-point controller (IP-core version is either unknown
+            or can be read from the PCIe version register of the PL reg-space)
+          const: snps,dw-pcie-ep
 
   reg:
-    description: |
-      It should contain Data Bus Interface (dbi) and config registers for all
-      versions.
-      For designware core version >= 4.80, it may contain ATU address space.
-    minItems: 2
-    maxItems: 4
+    description:
+      DBI, DBI2 reg-spaces and outbound memory window are required for the
+      normal controller functioning. iATU memory IO region is also required
+      if the space is unrolled (IP-core version >= 4.80a).
+    minItems: 3
+    maxItems: 5
 
   reg-names:
-    minItems: 2
-    maxItems: 4
+    minItems: 3
+    maxItems: 5
     items:
-      enum: [dbi, dbi2, config, atu, addr_space, link, atu_dma, appl]
-
-  reset-gpio:
-    description: GPIO pin number of PERST# signal
-    maxItems: 1
-    deprecated: true
-
-  reset-gpios:
-    description: GPIO controlled connection to PERST# signal
-    maxItems: 1
-
-  snps,enable-cdm-check:
-    type: boolean
-    description: |
-      This is a boolean property and if present enables
-      automatic checking of CDM (Configuration Dependent Module) registers
-      for data corruption. CDM registers include standard PCIe configuration
-      space registers, Port Logic registers, DMA and iATU (internal Address
-      Translation Unit) registers.
-
-  num-ib-windows:
-    description: number of inbound address translation windows
-    maxItems: 1
-    deprecated: true
-
-  num-ob-windows:
-    description: number of outbound address translation windows
-    maxItems: 1
-    deprecated: true
+      $ref: snps,dw-pcie-common.yaml#/$defs/reg-names
+    allOf:
+      - contains:
+          const: dbi
+      - contains:
+          const: dbi2
+      - contains:
+          const: addr_space
+
+  interrupts:
+    description:
+      There is no mandatory IRQ signals for the normal controller functioning,
+      but in addition to the native set the platforms may have a link- or
+      PM-related IRQs specified.
+    minItems: 1
+    maxItems: 20
+
+  interrupt-names:
+    minItems: 1
+    maxItems: 20
+    items:
+      $ref: snps,dw-pcie-common.yaml#/$defs/interrupt-names
+
+  clocks:
+    minItems: 1
+    maxItems: 7
+
+  clock-names:
+    minItems: 1
+    maxItems: 7
+    items:
+      $ref: snps,dw-pcie-common.yaml#/$defs/clock-names
+
+  resets:
+    minItems: 1
+    maxItems: 10
+
+  reset-names:
+    minItems: 1
+    maxItems: 10
+    items:
+      $ref: snps,dw-pcie-common.yaml#/$defs/reset-names
+
+  max-functions:
+    maximum: 32
 
 required:
+  - compatible
   - reg
   - reg-names
-  - compatible
 
 additionalProperties: true
 
 examples:
   - |
-    bus {
-      #address-cells = <1>;
-      #size-cells = <1>;
-      pcie-ep@dfd00000 {
-        compatible = "snps,dw-pcie-ep";
-        reg = <0xdfc00000 0x0001000>, /* IP registers 1 */
-              <0xdfc01000 0x0001000>, /* IP registers 2 */
-              <0xd0000000 0x2000000>; /* Configuration space */
-        reg-names = "dbi", "dbi2", "addr_space";
-      };
+    pcie-ep@1f052000 {
+      compatible = "vendor,soc-pcie", "snps,dw-pcie-ep-4.60a", "snps,dw-pcie-ep";
+      reg = <0x66000000 0x1000>, <0x66010000 0x10000>, <0x67000000 0x400000>;
+      reg-names = "dbi", "dbi2", "addr_space";
+
+      clocks = <&sys_clk 12>, <&sys_clk 24>;
+      clock-names = "dbi", "ref";
+
+      resets = <&sys_rst 12>, <&sys_rst 24>;
+      reset-names = "dbi", "phy";
+
+      phys = <&pcie_phy>;
+      phy-names = "pcie-phy";
+
+      num-lanes = <4>;
+      max-link-speed = <4>;
+      num-ib-windows = <16>;
+      num-ob-windows = <16>;
     };
+...
diff --git a/Documentation/devicetree/bindings/pci/snps,dw-pcie.yaml b/Documentation/devicetree/bindings/pci/snps,dw-pcie.yaml
index a5345c494744..6c397ae3c71a 100644
--- a/Documentation/devicetree/bindings/pci/snps,dw-pcie.yaml
+++ b/Documentation/devicetree/bindings/pci/snps,dw-pcie.yaml
@@ -13,20 +13,36 @@ maintainers:
 description: |
   Synopsys DesignWare PCIe host controller
 
+# Please create a separate DT-schema for the particular DWC PCIe Root Port
+# controller and make sure it's assigned with the vendor-specific
+# compatible string together with the generic Synopsys DWC PCIe strings so
+# the bindings would be successfully evaluated against this schema.
+select: false
+
 allOf:
   - $ref: /schemas/pci/pci-bus.yaml#
+  - $ref: snps,dw-pcie-common.yaml#
 
 properties:
   compatible:
-    anyOf:
-      - {}
-      - const: snps,dw-pcie
+    contains:
+      oneOf:
+        - description:
+            DWC PCIe Root Port controller (IP-core version is explicitly
+            specified in the additional compatible string)
+          items:
+            - pattern: '^snps,dw-pcie-[0-9]+\.[0-9]+a?$'
+            - const: snps,dw-pcie
+        - description:
+            DWC PCIe Root Port controller (IP-core version is either unknown
+            or can be read from the PCIe version register of the PL reg-space)
+          const: snps,dw-pcie
 
   reg:
-    description: |
-      It should contain Data Bus Interface (dbi) and config registers for all
-      versions.
-      For designware core version >= 4.80, it may contain ATU address space.
+    description:
+      At least DBI reg-space and peripheral devices CFG-space outbound window
+      are required for the normal controller work. iATU memory IO region is
+      also required if the space is unrolled (IP-core version >= 4.80a).
     minItems: 2
     maxItems: 5
 
@@ -34,69 +50,116 @@ properties:
     minItems: 2
     maxItems: 5
     items:
-      enum: [ dbi, dbi2, config, atu, app, elbi, mgmt, ctrl, parf, cfg, link,
-              ulreg, smu, mpu, apb, phy ]
-
-  num-lanes:
-    description: |
-      number of lanes to use (this property should be specified unless
-      the link is brought already up in firmware)
-    maximum: 16
-
-  reset-gpio:
-    description: GPIO pin number of PERST# signal
-    maxItems: 1
-    deprecated: true
-
-  reset-gpios:
-    description: GPIO controlled connection to PERST# signal
-    maxItems: 1
-
-  interrupts: true
-
-  interrupt-names: true
-
-  clocks: true
-
-  snps,enable-cdm-check:
-    type: boolean
-    description: |
-      This is a boolean property and if present enables
-      automatic checking of CDM (Configuration Dependent Module) registers
-      for data corruption. CDM registers include standard PCIe configuration
-      space registers, Port Logic registers, DMA and iATU (internal Address
-      Translation Unit) registers.
+      $ref: snps,dw-pcie-common.yaml#/$defs/reg-names
+    allOf:
+      - contains:
+          const: dbi
+      - contains:
+          const: config
+
+  interrupts:
+    description:
+      At least MSI interrupt signal is supposed to be specified for
+      the DWC PCIe host controller.
+    minItems: 1
+    maxItems: 26
+
+  interrupt-names:
+    minItems: 1
+    maxItems: 26
+    items:
+      anyOf:
+        - $ref: snps,dw-pcie-common.yaml#/$defs/interrupt-names
+        - $ref: '#/$defs/interrupt-names'
+    allOf:
+      - contains:
+          const: msi
+
+  clocks:
+    minItems: 1
+    maxItems: 7
+
+  clock-names:
+    minItems: 1
+    maxItems: 7
+    items:
+      $ref: snps,dw-pcie-common.yaml#/$defs/clock-names
 
-  num-viewport:
-    description: |
-      number of view ports configured in hardware. If a platform
-      does not specify it, the driver autodetects it.
-    deprecated: true
+  resets:
+    minItems: 1
+    maxItems: 10
 
-additionalProperties: true
+  reset-names:
+    minItems: 1
+    maxItems: 10
+    items:
+      $ref: snps,dw-pcie-common.yaml#/$defs/reset-names
 
 required:
+  - compatible
   - reg
   - reg-names
-  - compatible
+  - interrupts
+  - interrupt-names
+
+additionalProperties: true
+
+$defs:
+  interrupt-names:
+    description:
+      DWC PCIe Root Port/Complex specific IRQ signal names.
+    oneOf:
+      - description:
+          DSP AXI MSI Interrupt detected. It gets de-asserted when there is
+          no more MSI interrupt pending. The interrupt is relevant to the
+          iMSI-RX - Integrated MSI Receiver (AXI bridge).
+        const: msi
+      - description:
+          Error condition detected and a bit is set in the Root Error Status
+          register of the AER capability. It's asserted when the RC
+          internally generated an error or an error message is received by
+          the RC.
+        const: aer
+      - description:
+          PME message is received by the port. That means having the PME
+          status bit set in the Root Status register (the event is
+          supposed to be unmasked in the Root Control register).
+        const: pme
+      - description:
+          Hot-plug event is detected. That is a bit has been set in the
+          Slot Status register and the corresponding event is enabled in
+          the Slot Control register.
+        const: hp
+      - description:
+          Link Autonomous Bandwidth Status flag has been set in the Link
+          Status register (the event is supposed to be unmasked in the
+          Link Control register).
+        const: bw_au
+      - description:
+          Bandwidth Management Status flag has been set in the Link
+          Status register (the event is supposed to be unmasked in the
+          Link Control register).
+        const: bw_mg
 
 examples:
   - |
-    bus {
-      #address-cells = <1>;
-      #size-cells = <1>;
-      pcie@dfc00000 {
-        device_type = "pci";
-        compatible = "snps,dw-pcie";
-        reg = <0xdfc00000 0x0001000>, /* IP registers */
-              <0xd0000000 0x0002000>; /* Configuration space */
-        reg-names = "dbi", "config";
-        #address-cells = <3>;
-        #size-cells = <2>;
-        ranges = <0x81000000 0 0x00000000 0xde000000 0 0x00010000>,
-                 <0x82000000 0 0xd0400000 0xd0400000 0 0x0d000000>;
-        interrupts = <25>, <24>;
-        #interrupt-cells = <1>;
-        num-lanes = <1>;
-      };
+    pcie@1f052000 {
+      compatible = "vendor,soc-pcie", "snps,dw-pcie-4.60a", "snps,dw-pcie";
+      device_type = "pci";
+      reg = <0x1f052000 0x1000>, <0x1bdbf000 0x1000>;
+      reg-names = "dbi", "config";
+      #address-cells = <3>;
+      #size-cells = <2>;
+      ranges = <0x81000000 0 0x00000000 0x1bdb0000 0 0x00008000>,
+               <0x82000000 0 0x20000000 0x08000000 0 0x13db0000>;
+      bus-range = <0x0 0xff>;
+
+      interrupts = <0 80 4>;
+      interrupt-names = "msi";
+
+      reset-gpios = <&port0 0 1>;
+
+      num-lanes = <4>;
+      max-link-speed = <3>;
     };
+...
diff --git a/Documentation/devicetree/bindings/pci/toshiba,visconti-pcie.yaml b/Documentation/devicetree/bindings/pci/toshiba,visconti-pcie.yaml
index 30b6396d83c8..f0a3c436c6d1 100644
--- a/Documentation/devicetree/bindings/pci/toshiba,visconti-pcie.yaml
+++ b/Documentation/devicetree/bindings/pci/toshiba,visconti-pcie.yaml
@@ -13,7 +13,7 @@ description:
   Toshiba Visconti5 SoC PCIe host controller is based on the Synopsys DesignWare PCIe IP.
 
 allOf:
-  - $ref: /schemas/pci/snps,dw-pcie.yaml#
+  - $ref: /schemas/pci/snps,dw-pcie-common.yaml#
 
 properties:
   compatible:
-- 
2.35.1


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 02/16] dt-bindings: PCI: dwc: Add Baikal-T1 PCIe Root Port bindings
  2022-03-24  1:37 [PATCH 00/16] PCI: dwc: Add dma-ranges/YAML-schema/Baikal-T1 support Serge Semin
  2022-03-24  1:37   ` Serge Semin
@ 2022-03-24  1:37 ` Serge Semin
  2022-03-28 23:20   ` Rob Herring
  2022-03-24  1:37 ` [PATCH 03/16] PCI: dwc: Add more verbose link-up message Serge Semin
                   ` (13 subsequent siblings)
  15 siblings, 1 reply; 40+ messages in thread
From: Serge Semin @ 2022-03-24  1:37 UTC (permalink / raw)
  To: Jingoo Han, Gustavo Pimentel, Bjorn Helgaas, Rob Herring, Serge Semin
  Cc: Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Lorenzo Pieralisi, Rob Herring, Krzysztof Wilczyński,
	Frank Li, Manivannan Sadhasivam, linux-pci, devicetree,
	linux-kernel

Baikal-T1 SoC is equipped with DWC PCIe v4.60a Root Port controller, which
link can be trained to work on up to Gen.3 speed over up to x4 lanes. The
controller is supposed to be fed up with four clock sources: DBI
peripheral clock, AXI application Tx/Rx clocks and external PHY/core
reference clock generating the 100MHz signal. In addition to that the
platform provide a way to reset each part of the controller:
sticky/non-sticky bits, host controller core, PIPE interface, PCS/PHY and
Hot/Power reset signal. The Root Port controller is equipped with multiple
IRQ lines like MSI, system AER, PME, HP, Bandwidth change, Link
equalization request and eDMA ones. The registers space is accessed over
the DBI interface. There can be no more than four inbound or outbound iATU
windows configured.

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>

---

Rob, this DT-bindings most likely will fail the dt_bindings_check
evaluations with the "'*' is not of type 'array'" errors for the same
reason described in the previous patch. Let's discuss the problem there.
---
 .../bindings/pci/baikal,bt1-pcie.yaml         | 148 ++++++++++++++++++
 1 file changed, 148 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/pci/baikal,bt1-pcie.yaml

diff --git a/Documentation/devicetree/bindings/pci/baikal,bt1-pcie.yaml b/Documentation/devicetree/bindings/pci/baikal,bt1-pcie.yaml
new file mode 100644
index 000000000000..f34438330a86
--- /dev/null
+++ b/Documentation/devicetree/bindings/pci/baikal,bt1-pcie.yaml
@@ -0,0 +1,148 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pci/baikal,bt1-pcie.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Baikal-T1 PCIe Root Port Controller
+
+maintainers:
+  - Serge Semin <fancer.lancer@gmail.com>
+
+description: |
+  Embedded into Baikal-T1 SoC Root Complex controller. It's based on the
+  DWC RC PCIe v4.60a IP-core, which is configured to have just a single Root
+  Port function and is capable of establishing the link up to Gen.3 speed
+  on x4 lanes. It doesn't have embedded clock and reset control module, so
+  the proper interface initialization is supposed to be performed by software.
+
+allOf:
+  - $ref: /schemas/pci/pci-bus.yaml#
+  - $ref: snps,dw-pcie.yaml#
+
+properties:
+  compatible:
+    contains:
+      const: baikal,bt1-pcie
+
+  reg:
+    description:
+      DBI, DBI2 and at least 4KB outbound iATU-capable region are available.
+    maxItems: 3
+
+  reg-names:
+    minItems: 3
+    maxItems: 3
+    items:
+      enum: [ dbi, dbi2, config ]
+
+  interrupts:
+    description:
+      MSI, AER, PME, Hot-plug, Link Bandwidth Management, Link Equalization
+      request and eight Read/Write eDMA IRQ lines are available.
+    maxItems: 14
+
+  interrupt-names:
+    minItems: 14
+    maxItems: 14
+    items:
+      oneOf:
+        - pattern: '^dma[0-7]$'
+        - enum: [ msi, aer, pme, hp, bw_mg, l_eq ]
+
+  clocks:
+    description:
+      DBI (attached to the APB bus), AXI-bus master and slave interfaces
+      are fed up by the dedicated application clocks. A common reference
+      clock signal is supposed to be attached to the corresponding Ref-pad
+      of the SoC. It will be redistributed amongst the controller core
+      sub-modules (pipe, core, aux, etc).
+    minItems: 4
+    maxItems: 4
+
+  clock-names:
+    minItems: 4
+    maxItems: 4
+    items:
+      enum: [ dbi, mstr, slv, ref ]
+
+  resets:
+    description:
+      A comprehensive controller reset logic is supposed to be implemented
+      by software, so almost all the possible application and core reset
+      signals are exposed via the system CCU module.
+    minItems: 9
+    maxItems: 9
+
+  reset-names:
+    minItems: 9
+    maxItems: 9
+    items:
+      enum: [ mstr, slv, pwr, hot, phy, core, pipe, sticky, non-sticky ]
+
+  syscon:
+    $ref: /schemas/types.yaml#/definitions/phandle
+    description:
+      Phandle to the Baikal-T1 System Controller DT node. It's required to
+      access some additional PM, Reset-related and LTSSM signals.
+
+  num-lanes:
+    maximum: 4
+
+  max-link-speed:
+    maximum: 3
+
+  num-ob-windows:
+    const: 4
+
+  num-ib-windows:
+    const: 4
+
+required:
+  - compatible
+  - reg
+  - reg-names
+  - interrupts
+  - interrupt-names
+  - clocks
+  - clock-names
+  - resets
+  - reset-names
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    pcie@1f052000 {
+      compatible = "baikal,bt1-pcie", "snps,dw-pcie-4.60a", "snps,dw-pcie";
+      device_type = "pci";
+      reg = <0x1f052000 0x1000>, <0x1f053000 0x1000>, <0x1bdbf000 0x1000>;
+      reg-names = "dbi", "dbi2", "config";
+      #address-cells = <3>;
+      #size-cells = <2>;
+      ranges = <0x81000000 0 0x00000000 0x1bdb0000 0 0x00008000>,
+               <0x82000000 0 0x20000000 0x08000000 0 0x13db0000>;
+      bus-range = <0x0 0xff>;
+
+      interrupts = <0 80 4>, <0 81 4>, <0 82 4>, <0 83 4>,
+                   <0 84 4>, <0 85 4>, <0 86 4>, <0 87 4>,
+                   <0 88 4>, <0 89 4>, <0 90 4>, <0 91 4>,
+                   <0 92 4>, <0 93 4>;
+      interrupt-names = "dma0", "dma1", "dma2", "dma3", "dma4", "dma5", "dma6",
+                        "dma7", "msi", "aer", "pme", "hp", "bw_mg", "l_eq";
+
+      clocks = <&ccu_sys 1>, <&ccu_axi 6>, <&ccu_axi 7>, <&clk_pcie>;
+      clock-names = "dbi", "mstr", "slv", "ref";
+
+      resets = <&ccu_axi 6>, <&ccu_axi 7>, <&ccu_sys 7>, <&ccu_sys 10>,
+               <&ccu_sys 4>, <&ccu_sys 6>, <&ccu_sys 5>, <&ccu_sys 8>,
+               <&ccu_sys 9>;
+      reset-names = "mstr", "slv", "pwr", "hot", "phy", "core", "pipe",
+                    "sticky", "non-sticky";
+
+      reset-gpios = <&port0 0 1>;
+
+      num-lanes = <4>;
+      max-link-speed = <3>;
+    };
+...
-- 
2.35.1


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 03/16] PCI: dwc: Add more verbose link-up message
  2022-03-24  1:37 [PATCH 00/16] PCI: dwc: Add dma-ranges/YAML-schema/Baikal-T1 support Serge Semin
  2022-03-24  1:37   ` Serge Semin
  2022-03-24  1:37 ` [PATCH 02/16] dt-bindings: PCI: dwc: Add Baikal-T1 PCIe Root Port bindings Serge Semin
@ 2022-03-24  1:37 ` Serge Semin
  2022-03-28 23:31   ` Joe Perches
  2022-03-29 14:47   ` Rob Herring
  2022-03-24  1:37 ` [PATCH 04/16] PCI: dwc: Convert to using native IP-core versions representation Serge Semin
                   ` (12 subsequent siblings)
  15 siblings, 2 replies; 40+ messages in thread
From: Serge Semin @ 2022-03-24  1:37 UTC (permalink / raw)
  To: Jingoo Han, Gustavo Pimentel, Bjorn Helgaas, Lorenzo Pieralisi,
	Rob Herring, Krzysztof Wilczyński
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Frank Li, Manivannan Sadhasivam, Rob Herring, linux-pci,
	devicetree, linux-kernel

Printing just "link up" isn't that much informative especially when it
comes to working with the PCI Express bus. Even if the link is up, due to
multiple reasons the bus performance can degrade to slower speeds or to
narrower width than both Root Port and its partner is capable of. In that
case it would be handy to know the link specifications as early as
possible. So let's add a more verbose message to the busy-wait link-state
method, which will contain the link speed generation and the PCIe bus
width in case if the link up state is discovered. Otherwise an error will
be printed to the system log.

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 drivers/pci/controller/dwc/pcie-designware.c | 22 +++++++++++++++-----
 1 file changed, 17 insertions(+), 5 deletions(-)

diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c
index 6e81264fdfb4..f1693e25afcb 100644
--- a/drivers/pci/controller/dwc/pcie-designware.c
+++ b/drivers/pci/controller/dwc/pcie-designware.c
@@ -528,14 +528,26 @@ int dw_pcie_wait_for_link(struct dw_pcie *pci)
 
 	/* Check if the link is up or not */
 	for (retries = 0; retries < LINK_WAIT_MAX_RETRIES; retries++) {
-		if (dw_pcie_link_up(pci)) {
-			dev_info(pci->dev, "Link up\n");
-			return 0;
-		}
+		if (dw_pcie_link_up(pci))
+			break;
+
 		usleep_range(LINK_WAIT_USLEEP_MIN, LINK_WAIT_USLEEP_MAX);
 	}
 
-	dev_info(pci->dev, "Phy link never came up\n");
+	if (retries < LINK_WAIT_MAX_RETRIES) {
+		u32 offset, val;
+
+		offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
+		val = dw_pcie_readw_dbi(pci, offset + PCI_EXP_LNKSTA);
+
+		dev_info(pci->dev, "PCIe Gen.%u x%u link up\n",
+			 FIELD_GET(PCI_EXP_LNKSTA_CLS, val),
+			 FIELD_GET(PCI_EXP_LNKSTA_NLW, val));
+
+		return 0;
+	}
+
+	dev_err(pci->dev, "Phy link never came up\n");
 
 	return -ETIMEDOUT;
 }
-- 
2.35.1


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 04/16] PCI: dwc: Convert to using native IP-core versions representation
  2022-03-24  1:37 [PATCH 00/16] PCI: dwc: Add dma-ranges/YAML-schema/Baikal-T1 support Serge Semin
                   ` (2 preceding siblings ...)
  2022-03-24  1:37 ` [PATCH 03/16] PCI: dwc: Add more verbose link-up message Serge Semin
@ 2022-03-24  1:37 ` Serge Semin
  2022-03-29 15:00   ` Rob Herring
  2022-03-24  1:37 ` [PATCH 05/16] PCI: dwc: Add IP-core version detection procedure Serge Semin
                   ` (11 subsequent siblings)
  15 siblings, 1 reply; 40+ messages in thread
From: Serge Semin @ 2022-03-24  1:37 UTC (permalink / raw)
  To: Jingoo Han, Gustavo Pimentel, Bjorn Helgaas, Lorenzo Pieralisi,
	Rob Herring, Krzysztof Wilczyński, Rahul Tanwar,
	Thierry Reding, Jonathan Hunter
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Frank Li, Manivannan Sadhasivam, Rob Herring, linux-pci,
	devicetree, linux-kernel, linux-tegra

Since DWC PCIe v4.70a the controller version can be read from the
PORT_LOGIC.PCIE_VERSION_OFF register. Version is represented in the FourCC
format [1]. It's standard versioning approach for the Synopsys DWC
IP-cores. Moreover some of the DWC kernel drivers already make use of it
to fixup version-dependent functionality (See DWC USB3, Stmicro STMMAC or
recent DW SPI driver). In order to preserve the standard version
representation and prevent the data conversion back and forth, we suggest
to preserve the native version representation in the DWC PCIe driver too
in the same way as it has already been done in the rest of the DWC
drivers. IP-core version reading from the CSR will be introduced in the
next commit together with a simple macro-based API to use it.

[1] https://en.wikipedia.org/wiki/FourCC

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 drivers/pci/controller/dwc/pci-keystone.c    | 12 ++++++------
 drivers/pci/controller/dwc/pcie-designware.c |  8 ++++----
 drivers/pci/controller/dwc/pcie-designware.h | 10 +++++++++-
 drivers/pci/controller/dwc/pcie-intel-gw.c   |  4 ++--
 drivers/pci/controller/dwc/pcie-tegra194.c   |  2 +-
 5 files changed, 22 insertions(+), 14 deletions(-)

diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c
index 1c2ee4e13f1c..ec65355dd29b 100644
--- a/drivers/pci/controller/dwc/pci-keystone.c
+++ b/drivers/pci/controller/dwc/pci-keystone.c
@@ -109,7 +109,7 @@ struct ks_pcie_of_data {
 	enum dw_pcie_device_mode mode;
 	const struct dw_pcie_host_ops *host_ops;
 	const struct dw_pcie_ep_ops *ep_ops;
-	unsigned int version;
+	u32 version;
 };
 
 struct keystone_pcie {
@@ -1069,19 +1069,19 @@ static int ks_pcie_am654_set_mode(struct device *dev,
 
 static const struct ks_pcie_of_data ks_pcie_rc_of_data = {
 	.host_ops = &ks_pcie_host_ops,
-	.version = 0x365A,
+	.version = DW_PCIE_VER_365A,
 };
 
 static const struct ks_pcie_of_data ks_pcie_am654_rc_of_data = {
 	.host_ops = &ks_pcie_am654_host_ops,
 	.mode = DW_PCIE_RC_TYPE,
-	.version = 0x490A,
+	.version = DW_PCIE_VER_490A,
 };
 
 static const struct ks_pcie_of_data ks_pcie_am654_ep_of_data = {
 	.ep_ops = &ks_pcie_am654_ep_ops,
 	.mode = DW_PCIE_EP_TYPE,
-	.version = 0x490A,
+	.version = DW_PCIE_VER_490A,
 };
 
 static const struct of_device_id ks_pcie_of_match[] = {
@@ -1114,12 +1114,12 @@ static int __init ks_pcie_probe(struct platform_device *pdev)
 	struct device_link **link;
 	struct gpio_desc *gpiod;
 	struct resource *res;
-	unsigned int version;
 	void __iomem *base;
 	u32 num_viewport;
 	struct phy **phy;
 	u32 num_lanes;
 	char name[10];
+	u32 version;
 	int ret;
 	int irq;
 	int i;
@@ -1233,7 +1233,7 @@ static int __init ks_pcie_probe(struct platform_device *pdev)
 		goto err_get_sync;
 	}
 
-	if (pci->version >= 0x480A)
+	if (pci->version >= DW_PCIE_VER_480A)
 		ret = ks_pcie_am654_set_mode(dev, mode);
 	else
 		ret = ks_pcie_set_mode(dev);
diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c
index f1693e25afcb..c21373c6cb51 100644
--- a/drivers/pci/controller/dwc/pcie-designware.c
+++ b/drivers/pci/controller/dwc/pcie-designware.c
@@ -289,7 +289,7 @@ static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, u8 func_no,
 	val = type | PCIE_ATU_FUNC_NUM(func_no);
 	if (upper_32_bits(limit_addr) > upper_32_bits(cpu_addr))
 		val |= PCIE_ATU_INCREASE_REGION_SIZE;
-	if (pci->version == 0x490A)
+	if (pci->version == DW_PCIE_VER_490A)
 		val = dw_pcie_enable_ecrc(val);
 	dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1, val);
 	dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL2,
@@ -336,7 +336,7 @@ static void __dw_pcie_prog_outbound_atu(struct dw_pcie *pci, u8 func_no,
 			   upper_32_bits(cpu_addr));
 	dw_pcie_writel_dbi(pci, PCIE_ATU_LIMIT,
 			   lower_32_bits(limit_addr));
-	if (pci->version >= 0x460A)
+	if (pci->version >= DW_PCIE_VER_460A)
 		dw_pcie_writel_dbi(pci, PCIE_ATU_UPPER_LIMIT,
 				   upper_32_bits(limit_addr));
 	dw_pcie_writel_dbi(pci, PCIE_ATU_LOWER_TARGET,
@@ -345,9 +345,9 @@ static void __dw_pcie_prog_outbound_atu(struct dw_pcie *pci, u8 func_no,
 			   upper_32_bits(pci_addr));
 	val = type | PCIE_ATU_FUNC_NUM(func_no);
 	if (upper_32_bits(limit_addr) > upper_32_bits(cpu_addr) &&
-	    pci->version >= 0x460A)
+	    pci->version >= DW_PCIE_VER_460A)
 		val |= PCIE_ATU_INCREASE_REGION_SIZE;
-	if (pci->version == 0x490A)
+	if (pci->version == DW_PCIE_VER_490A)
 		val = dw_pcie_enable_ecrc(val);
 	dw_pcie_writel_dbi(pci, PCIE_ATU_CR1, val);
 	dw_pcie_writel_dbi(pci, PCIE_ATU_CR2, PCIE_ATU_ENABLE);
diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
index 7d6e9b7576be..5be43c662176 100644
--- a/drivers/pci/controller/dwc/pcie-designware.h
+++ b/drivers/pci/controller/dwc/pcie-designware.h
@@ -20,6 +20,14 @@
 #include <linux/pci-epc.h>
 #include <linux/pci-epf.h>
 
+/* DWC PCIe IP-core versions (native support since v4.70a) */
+#define DW_PCIE_VER_365A		0x3336352a
+#define DW_PCIE_VER_460A		0x3436302a
+#define DW_PCIE_VER_470A		0x3437302a
+#define DW_PCIE_VER_480A		0x3438302a
+#define DW_PCIE_VER_490A		0x3439302a
+#define DW_PCIE_VER_520A		0x3532302a
+
 /* Parameters for the waiting for link up routine */
 #define LINK_WAIT_MAX_RETRIES		10
 #define LINK_WAIT_USLEEP_MIN		90000
@@ -269,7 +277,7 @@ struct dw_pcie {
 	struct pcie_port	pp;
 	struct dw_pcie_ep	ep;
 	const struct dw_pcie_ops *ops;
-	unsigned int		version;
+	u32			version;
 	int			num_lanes;
 	int			link_gen;
 	u8			n_fts[2];
diff --git a/drivers/pci/controller/dwc/pcie-intel-gw.c b/drivers/pci/controller/dwc/pcie-intel-gw.c
index 5ba144924ff8..786af2ba379f 100644
--- a/drivers/pci/controller/dwc/pcie-intel-gw.c
+++ b/drivers/pci/controller/dwc/pcie-intel-gw.c
@@ -59,7 +59,7 @@
 #define RESET_INTERVAL_MS		100
 
 struct intel_pcie_soc {
-	unsigned int	pcie_ver;
+	u32	pcie_ver;
 };
 
 struct intel_pcie {
@@ -395,7 +395,7 @@ static const struct dw_pcie_host_ops intel_pcie_dw_ops = {
 };
 
 static const struct intel_pcie_soc pcie_data = {
-	.pcie_ver =		0x520A,
+	.pcie_ver =		DW_PCIE_VER_520A,
 };
 
 static int intel_pcie_probe(struct platform_device *pdev)
diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c
index b1b5f836a806..6f1330ed63e5 100644
--- a/drivers/pci/controller/dwc/pcie-tegra194.c
+++ b/drivers/pci/controller/dwc/pcie-tegra194.c
@@ -1981,7 +1981,7 @@ static int tegra194_pcie_probe(struct platform_device *pdev)
 	pci->ops = &tegra_dw_pcie_ops;
 	pci->n_fts[0] = N_FTS_VAL;
 	pci->n_fts[1] = FTS_VAL;
-	pci->version = 0x490A;
+	pci->version = DW_PCIE_VER_490A;
 
 	pp = &pci->pp;
 	pp->num_vectors = MAX_MSI_IRQS;
-- 
2.35.1


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 05/16] PCI: dwc: Add IP-core version detection procedure
  2022-03-24  1:37 [PATCH 00/16] PCI: dwc: Add dma-ranges/YAML-schema/Baikal-T1 support Serge Semin
                   ` (3 preceding siblings ...)
  2022-03-24  1:37 ` [PATCH 04/16] PCI: dwc: Convert to using native IP-core versions representation Serge Semin
@ 2022-03-24  1:37 ` Serge Semin
  2022-03-29 15:08   ` Rob Herring
  2022-03-24  1:37 ` [PATCH 06/16] PCI: dwc: Introduce Synopsys IP-core versions/types interface Serge Semin
                   ` (10 subsequent siblings)
  15 siblings, 1 reply; 40+ messages in thread
From: Serge Semin @ 2022-03-24  1:37 UTC (permalink / raw)
  To: Jingoo Han, Gustavo Pimentel, Bjorn Helgaas, Lorenzo Pieralisi,
	Rob Herring, Krzysztof Wilczyński
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Frank Li, Manivannan Sadhasivam, Rob Herring, linux-pci,
	devicetree, linux-kernel

Since DWC PCIe v4.70a the controller version and version type can be read
from the PORT_LOGIC.PCIE_VERSION_OFF and PORT_LOGIC.PCIE_VERSION_TYPE_OFF
registers respectively. Seeing the generic code has got version-dependent
parts let's use these registers to find out the controller version.  The
detection procedure is executed for both RC and EP modes right after the
platform-specific initialization. We can't do that earlier since the
glue-drivers can perform the DBI-related setups there including the bus
reference clocks activation, without which the CSRs just can't be read.

Note the CSRs content is zero on the older DWC PCIe controller. In that
case we have no choice but to rely on the platform setup.

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 .../pci/controller/dwc/pcie-designware-ep.c   |  2 ++
 .../pci/controller/dwc/pcie-designware-host.c |  2 ++
 drivers/pci/controller/dwc/pcie-designware.c  | 24 +++++++++++++++++++
 drivers/pci/controller/dwc/pcie-designware.h  |  6 +++++
 4 files changed, 34 insertions(+)

diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c
index 7c9315fffe24..3b981d13cca9 100644
--- a/drivers/pci/controller/dwc/pcie-designware-ep.c
+++ b/drivers/pci/controller/dwc/pcie-designware-ep.c
@@ -645,6 +645,8 @@ int dw_pcie_ep_init_complete(struct dw_pcie_ep *ep)
 	u32 reg;
 	int i;
 
+	dw_pcie_version_detect(pci);
+
 	hdr_type = dw_pcie_readb_dbi(pci, PCI_HEADER_TYPE) &
 		   PCI_HEADER_TYPE_MASK;
 	if (hdr_type != PCI_HEADER_TYPE_NORMAL) {
diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c
index 8364ea234e88..8f0d473ff770 100644
--- a/drivers/pci/controller/dwc/pcie-designware-host.c
+++ b/drivers/pci/controller/dwc/pcie-designware-host.c
@@ -398,6 +398,8 @@ int dw_pcie_host_init(struct pcie_port *pp)
 		}
 	}
 
+	dw_pcie_version_detect(pci);
+
 	dw_pcie_iatu_detect(pci);
 
 	dw_pcie_setup_rc(pp);
diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c
index c21373c6cb51..49c494d82042 100644
--- a/drivers/pci/controller/dwc/pcie-designware.c
+++ b/drivers/pci/controller/dwc/pcie-designware.c
@@ -16,6 +16,30 @@
 #include "../../pci.h"
 #include "pcie-designware.h"
 
+void dw_pcie_version_detect(struct dw_pcie *pci)
+{
+	u32 ver;
+
+	/* The content of the CSR is zero on DWC PCIe older than v4.70a */
+	ver = dw_pcie_readl_dbi(pci, PCIE_VERSION_NUMBER);
+	if (!ver)
+		return;
+
+	if (pci->version && pci->version != ver)
+		dev_warn(pci->dev, "Versions don't match (%08x != %08x)\n",
+			 pci->version, ver);
+	else
+		pci->version = ver;
+
+	ver = dw_pcie_readl_dbi(pci, PCIE_VERSION_TYPE);
+
+	if (pci->type && pci->type != ver)
+		dev_warn(pci->dev, "Types don't match (%08x != %08x)\n",
+			 pci->type, ver);
+	else
+		pci->type = ver;
+}
+
 /*
  * These interfaces resemble the pci_find_*capability() interfaces, but these
  * are for configuring host controllers, which are bridges *to* PCI devices but
diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
index 5be43c662176..f70cbdedf5a3 100644
--- a/drivers/pci/controller/dwc/pcie-designware.h
+++ b/drivers/pci/controller/dwc/pcie-designware.h
@@ -85,6 +85,9 @@
 #define PCIE_PORT_MULTI_LANE_CTRL	0x8C0
 #define PORT_MLTI_UPCFG_SUPPORT		BIT(7)
 
+#define PCIE_VERSION_NUMBER		0x8F8
+#define PCIE_VERSION_TYPE		0x8FC
+
 #define PCIE_ATU_VIEWPORT		0x900
 #define PCIE_ATU_REGION_INBOUND		BIT(31)
 #define PCIE_ATU_REGION_OUTBOUND	0
@@ -278,6 +281,7 @@ struct dw_pcie {
 	struct dw_pcie_ep	ep;
 	const struct dw_pcie_ops *ops;
 	u32			version;
+	u32			type;
 	int			num_lanes;
 	int			link_gen;
 	u8			n_fts[2];
@@ -290,6 +294,8 @@ struct dw_pcie {
 #define to_dw_pcie_from_ep(endpoint)   \
 		container_of((endpoint), struct dw_pcie, ep)
 
+void dw_pcie_version_detect(struct dw_pcie *pci);
+
 u8 dw_pcie_find_capability(struct dw_pcie *pci, u8 cap);
 u16 dw_pcie_find_ext_capability(struct dw_pcie *pci, u8 cap);
 
-- 
2.35.1


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 06/16] PCI: dwc: Introduce Synopsys IP-core versions/types interface
  2022-03-24  1:37 [PATCH 00/16] PCI: dwc: Add dma-ranges/YAML-schema/Baikal-T1 support Serge Semin
                   ` (4 preceding siblings ...)
  2022-03-24  1:37 ` [PATCH 05/16] PCI: dwc: Add IP-core version detection procedure Serge Semin
@ 2022-03-24  1:37 ` Serge Semin
  2022-03-24  1:37 ` [PATCH 07/16] PCI: dwc: Add host de-initialization callback Serge Semin
                   ` (9 subsequent siblings)
  15 siblings, 0 replies; 40+ messages in thread
From: Serge Semin @ 2022-03-24  1:37 UTC (permalink / raw)
  To: Jingoo Han, Gustavo Pimentel, Bjorn Helgaas, Lorenzo Pieralisi,
	Rob Herring, Krzysztof Wilczyński
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Frank Li, Manivannan Sadhasivam, Rob Herring, linux-pci,
	devicetree, linux-kernel

Instead of manual DW PCIe data version field comparison let's use a handy
macro-based interface in order to shorten out the statements, simplify the
corresponding parts, improve the code readability and maintainability in
perspective when more complex version-based dependencies need to
implemented. Similar approaches have already been implemented in the DWC
USB3 and DW SPI drivers (though with some IP-core evolution specifics).

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 drivers/pci/controller/dwc/pci-keystone.c    |  2 +-
 drivers/pci/controller/dwc/pcie-designware.c |  8 ++++----
 drivers/pci/controller/dwc/pcie-designware.h | 15 +++++++++++++++
 3 files changed, 20 insertions(+), 5 deletions(-)

diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c
index ec65355dd29b..8fbebeb923b8 100644
--- a/drivers/pci/controller/dwc/pci-keystone.c
+++ b/drivers/pci/controller/dwc/pci-keystone.c
@@ -1233,7 +1233,7 @@ static int __init ks_pcie_probe(struct platform_device *pdev)
 		goto err_get_sync;
 	}
 
-	if (pci->version >= DW_PCIE_VER_480A)
+	if (dw_pcie_ver_is_ge(pci, 480A))
 		ret = ks_pcie_am654_set_mode(dev, mode);
 	else
 		ret = ks_pcie_set_mode(dev);
diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c
index 49c494d82042..d5ce19625769 100644
--- a/drivers/pci/controller/dwc/pcie-designware.c
+++ b/drivers/pci/controller/dwc/pcie-designware.c
@@ -313,7 +313,7 @@ static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, u8 func_no,
 	val = type | PCIE_ATU_FUNC_NUM(func_no);
 	if (upper_32_bits(limit_addr) > upper_32_bits(cpu_addr))
 		val |= PCIE_ATU_INCREASE_REGION_SIZE;
-	if (pci->version == DW_PCIE_VER_490A)
+	if (dw_pcie_ver_is(pci, 490A))
 		val = dw_pcie_enable_ecrc(val);
 	dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1, val);
 	dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL2,
@@ -360,7 +360,7 @@ static void __dw_pcie_prog_outbound_atu(struct dw_pcie *pci, u8 func_no,
 			   upper_32_bits(cpu_addr));
 	dw_pcie_writel_dbi(pci, PCIE_ATU_LIMIT,
 			   lower_32_bits(limit_addr));
-	if (pci->version >= DW_PCIE_VER_460A)
+	if (dw_pcie_ver_is_ge(pci, 460A))
 		dw_pcie_writel_dbi(pci, PCIE_ATU_UPPER_LIMIT,
 				   upper_32_bits(limit_addr));
 	dw_pcie_writel_dbi(pci, PCIE_ATU_LOWER_TARGET,
@@ -369,9 +369,9 @@ static void __dw_pcie_prog_outbound_atu(struct dw_pcie *pci, u8 func_no,
 			   upper_32_bits(pci_addr));
 	val = type | PCIE_ATU_FUNC_NUM(func_no);
 	if (upper_32_bits(limit_addr) > upper_32_bits(cpu_addr) &&
-	    pci->version >= DW_PCIE_VER_460A)
+	    dw_pcie_ver_is_ge(pci, 460A))
 		val |= PCIE_ATU_INCREASE_REGION_SIZE;
-	if (pci->version == DW_PCIE_VER_490A)
+	if (dw_pcie_ver_is(pci, 490A))
 		val = dw_pcie_enable_ecrc(val);
 	dw_pcie_writel_dbi(pci, PCIE_ATU_CR1, val);
 	dw_pcie_writel_dbi(pci, PCIE_ATU_CR2, PCIE_ATU_ENABLE);
diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
index f70cbdedf5a3..1868773ecb91 100644
--- a/drivers/pci/controller/dwc/pcie-designware.h
+++ b/drivers/pci/controller/dwc/pcie-designware.h
@@ -28,6 +28,21 @@
 #define DW_PCIE_VER_490A		0x3439302a
 #define DW_PCIE_VER_520A		0x3532302a
 
+#define __dw_pcie_ver_cmp(_pci, _ver, _op) \
+	((_pci)->version _op DW_PCIE_VER_ ## _ver)
+
+#define dw_pcie_ver_is(_pci, _ver) __dw_pcie_ver_cmp(_pci, _ver, ==)
+
+#define dw_pcie_ver_is_ge(_pci, _ver) __dw_pcie_ver_cmp(_pci, _ver, >=)
+
+#define dw_pcie_ver_type_is(_pci, _ver, _type) \
+	(__dw_pcie_ver_cmp(_pci, _ver, ==) && \
+	 __dw_pcie_ver_cmp(_pci, TYPE_ ## _type, ==))
+
+#define dw_pcie_ver_type_is_ge(_pci, _ver, _type) \
+	(__dw_pcie_ver_cmp(_pci, _ver, ==) && \
+	 __dw_pcie_ver_cmp(_pci, TYPE_ ## _type, >=))
+
 /* Parameters for the waiting for link up routine */
 #define LINK_WAIT_MAX_RETRIES		10
 #define LINK_WAIT_USLEEP_MIN		90000
-- 
2.35.1


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 07/16] PCI: dwc: Add host de-initialization callback
  2022-03-24  1:37 [PATCH 00/16] PCI: dwc: Add dma-ranges/YAML-schema/Baikal-T1 support Serge Semin
                   ` (5 preceding siblings ...)
  2022-03-24  1:37 ` [PATCH 06/16] PCI: dwc: Introduce Synopsys IP-core versions/types interface Serge Semin
@ 2022-03-24  1:37 ` Serge Semin
  2022-03-24  1:37 ` [PATCH 08/16] PCI: dwc: Drop inbound iATU types enumeration - dw_pcie_as_type Serge Semin
                   ` (8 subsequent siblings)
  15 siblings, 0 replies; 40+ messages in thread
From: Serge Semin @ 2022-03-24  1:37 UTC (permalink / raw)
  To: Jingoo Han, Gustavo Pimentel, Bjorn Helgaas, Lorenzo Pieralisi,
	Rob Herring, Krzysztof Wilczyński
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Frank Li, Manivannan Sadhasivam, Rob Herring, linux-pci,
	devicetree, linux-kernel

Seeing the platform-specific DW PCIe host-initialization is performed from
within the generic dw_pcie_host_init() method by means of the dedicated
dw_pcie_ops.host_init() callback, there must be declared an antagonist
which would perform the corresponding cleanups. Let's add such callback
then. It will be called in the dw_pcie_host_deinit() method and in the
cleanup-on-error path in the dw_pcie_host_init() function.

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 .../pci/controller/dwc/pcie-designware-host.c | 21 ++++++++++++++-----
 drivers/pci/controller/dwc/pcie-designware.h  |  1 +
 2 files changed, 17 insertions(+), 5 deletions(-)

diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c
index 8f0d473ff770..602cf4fe502b 100644
--- a/drivers/pci/controller/dwc/pcie-designware-host.c
+++ b/drivers/pci/controller/dwc/pcie-designware-host.c
@@ -354,20 +354,23 @@ int dw_pcie_host_init(struct pcie_port *pp)
 			pp->num_vectors = MSI_DEF_NUM_VECTORS;
 		} else if (pp->num_vectors > MAX_MSI_IRQS) {
 			dev_err(dev, "Invalid number of vectors\n");
-			return -EINVAL;
+			ret = -EINVAL;
+			goto err_host_deinit;
 		}
 
 		if (pp->ops->msi_host_init) {
 			ret = pp->ops->msi_host_init(pp);
 			if (ret < 0)
-				return ret;
+				goto err_host_deinit;
 		} else if (pp->has_msi_ctrl) {
 			if (!pp->msi_irq) {
 				pp->msi_irq = platform_get_irq_byname_optional(pdev, "msi");
 				if (pp->msi_irq < 0) {
 					pp->msi_irq = platform_get_irq(pdev, 0);
-					if (pp->msi_irq < 0)
-						return pp->msi_irq;
+					if (pp->msi_irq < 0) {
+						ret = pp->msi_irq;
+						goto err_host_deinit;
+					}
 				}
 			}
 
@@ -375,7 +378,7 @@ int dw_pcie_host_init(struct pcie_port *pp)
 
 			ret = dw_pcie_allocate_domains(pp);
 			if (ret)
-				return ret;
+				goto err_host_deinit;
 
 			if (pp->msi_irq > 0)
 				irq_set_chained_handler_and_data(pp->msi_irq,
@@ -428,6 +431,11 @@ int dw_pcie_host_init(struct pcie_port *pp)
 err_free_msi:
 	if (pp->has_msi_ctrl)
 		dw_pcie_free_msi(pp);
+
+err_host_deinit:
+	if (pp->ops->host_deinit)
+		pp->ops->host_deinit(pp);
+
 	return ret;
 }
 EXPORT_SYMBOL_GPL(dw_pcie_host_init);
@@ -444,6 +452,9 @@ void dw_pcie_host_deinit(struct pcie_port *pp)
 
 	if (pp->has_msi_ctrl)
 		dw_pcie_free_msi(pp);
+
+	if (pp->ops->host_deinit)
+		pp->ops->host_deinit(pp);
 }
 EXPORT_SYMBOL_GPL(dw_pcie_host_deinit);
 
diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
index 1868773ecb91..bca1d3e83636 100644
--- a/drivers/pci/controller/dwc/pcie-designware.h
+++ b/drivers/pci/controller/dwc/pcie-designware.h
@@ -200,6 +200,7 @@ enum dw_pcie_device_mode {
 
 struct dw_pcie_host_ops {
 	int (*host_init)(struct pcie_port *pp);
+	void (*host_deinit)(struct pcie_port *pp);
 	int (*msi_host_init)(struct pcie_port *pp);
 };
 
-- 
2.35.1


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 08/16] PCI: dwc: Drop inbound iATU types enumeration - dw_pcie_as_type
  2022-03-24  1:37 [PATCH 00/16] PCI: dwc: Add dma-ranges/YAML-schema/Baikal-T1 support Serge Semin
                   ` (6 preceding siblings ...)
  2022-03-24  1:37 ` [PATCH 07/16] PCI: dwc: Add host de-initialization callback Serge Semin
@ 2022-03-24  1:37 ` Serge Semin
  2022-03-29 15:16   ` Rob Herring
  2022-03-24  1:37 ` [PATCH 09/16] PCI: dwc: Simplify in/outbound iATU setup methods Serge Semin
                   ` (7 subsequent siblings)
  15 siblings, 1 reply; 40+ messages in thread
From: Serge Semin @ 2022-03-24  1:37 UTC (permalink / raw)
  To: Jingoo Han, Gustavo Pimentel, Bjorn Helgaas, Lorenzo Pieralisi,
	Rob Herring, Krzysztof Wilczyński
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Frank Li, Manivannan Sadhasivam, Rob Herring, linux-pci,
	devicetree, linux-kernel

There is no point in having an enumeration declared in the driver for the
PCIe end-point. First of all it's redundant since the driver already has a
set of macro declared which describe the available in/out iATU types, thus
having an addition abstraction just needlessly complicates the code.
Secondly checking the passed iATU type for validity within a single driver
is pointless since the driver is supposed to be consistent by its nature.
Finally the outbound iATU type isn't encoded by the denoted enumeration,
thus giving a false impression that the in and out iATU types are
unrelated while they are the same. So to speak let's drop the redundant
dw_pcie_as_type enumeration replacing it with the direct iATU type usage.

While at it, since we are touching the iATU inbound regions config methods
anyway, let's fix the arguments order so the type would be followed by the
address-related parameters. Thus the inbound and outbound iATU setup
methods will look alike. That shall improve the code readability a bit.

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 .../pci/controller/dwc/pcie-designware-ep.c   | 21 +++++------
 drivers/pci/controller/dwc/pcie-designware.c  | 35 +++----------------
 drivers/pci/controller/dwc/pcie-designware.h  |  9 +----
 3 files changed, 15 insertions(+), 50 deletions(-)

diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c
index 3b981d13cca9..3bd9026071e8 100644
--- a/drivers/pci/controller/dwc/pcie-designware-ep.c
+++ b/drivers/pci/controller/dwc/pcie-designware-ep.c
@@ -154,9 +154,8 @@ static int dw_pcie_ep_write_header(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
 	return 0;
 }
 
-static int dw_pcie_ep_inbound_atu(struct dw_pcie_ep *ep, u8 func_no,
-				  enum pci_barno bar, dma_addr_t cpu_addr,
-				  enum dw_pcie_as_type as_type)
+static int dw_pcie_ep_inbound_atu(struct dw_pcie_ep *ep, u8 func_no, int type,
+				  dma_addr_t cpu_addr, enum pci_barno bar)
 {
 	int ret;
 	u32 free_win;
@@ -168,8 +167,8 @@ static int dw_pcie_ep_inbound_atu(struct dw_pcie_ep *ep, u8 func_no,
 		return -EINVAL;
 	}
 
-	ret = dw_pcie_prog_inbound_atu(pci, func_no, free_win, bar, cpu_addr,
-				       as_type);
+	ret = dw_pcie_prog_inbound_atu(pci, func_no, free_win, type,
+				       cpu_addr, bar);
 	if (ret < 0) {
 		dev_err(pci->dev, "Failed to program IB window\n");
 		return ret;
@@ -221,27 +220,25 @@ static void dw_pcie_ep_clear_bar(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
 static int dw_pcie_ep_set_bar(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
 			      struct pci_epf_bar *epf_bar)
 {
-	int ret;
 	struct dw_pcie_ep *ep = epc_get_drvdata(epc);
 	struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
 	enum pci_barno bar = epf_bar->barno;
 	size_t size = epf_bar->size;
 	int flags = epf_bar->flags;
-	enum dw_pcie_as_type as_type;
-	u32 reg;
 	unsigned int func_offset = 0;
+	int ret, type;
+	u32 reg;
 
 	func_offset = dw_pcie_ep_func_select(ep, func_no);
 
 	reg = PCI_BASE_ADDRESS_0 + (4 * bar) + func_offset;
 
 	if (!(flags & PCI_BASE_ADDRESS_SPACE))
-		as_type = DW_PCIE_AS_MEM;
+		type = PCIE_ATU_TYPE_MEM;
 	else
-		as_type = DW_PCIE_AS_IO;
+		type = PCIE_ATU_TYPE_IO;
 
-	ret = dw_pcie_ep_inbound_atu(ep, func_no, bar,
-				     epf_bar->phys_addr, as_type);
+	ret = dw_pcie_ep_inbound_atu(ep, func_no, type, epf_bar->phys_addr, bar);
 	if (ret)
 		return ret;
 
diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c
index d5ce19625769..b983128584ff 100644
--- a/drivers/pci/controller/dwc/pcie-designware.c
+++ b/drivers/pci/controller/dwc/pcie-designware.c
@@ -421,10 +421,9 @@ static void dw_pcie_writel_ib_unroll(struct dw_pcie *pci, u32 index, u32 reg,
 }
 
 static int dw_pcie_prog_inbound_atu_unroll(struct dw_pcie *pci, u8 func_no,
-					   int index, int bar, u64 cpu_addr,
-					   enum dw_pcie_as_type as_type)
+					   int index, int type,
+					   u64 cpu_addr, u8 bar)
 {
-	int type;
 	u32 retries, val;
 
 	dw_pcie_writel_ib_unroll(pci, index, PCIE_ATU_UNR_LOWER_TARGET,
@@ -432,17 +431,6 @@ static int dw_pcie_prog_inbound_atu_unroll(struct dw_pcie *pci, u8 func_no,
 	dw_pcie_writel_ib_unroll(pci, index, PCIE_ATU_UNR_UPPER_TARGET,
 				 upper_32_bits(cpu_addr));
 
-	switch (as_type) {
-	case DW_PCIE_AS_MEM:
-		type = PCIE_ATU_TYPE_MEM;
-		break;
-	case DW_PCIE_AS_IO:
-		type = PCIE_ATU_TYPE_IO;
-		break;
-	default:
-		return -EINVAL;
-	}
-
 	dw_pcie_writel_ib_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1, type |
 				 PCIE_ATU_FUNC_NUM(func_no));
 	dw_pcie_writel_ib_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL2,
@@ -468,32 +456,19 @@ static int dw_pcie_prog_inbound_atu_unroll(struct dw_pcie *pci, u8 func_no,
 }
 
 int dw_pcie_prog_inbound_atu(struct dw_pcie *pci, u8 func_no, int index,
-			     int bar, u64 cpu_addr,
-			     enum dw_pcie_as_type as_type)
+			     int type, u64 cpu_addr, u8 bar)
 {
-	int type;
 	u32 retries, val;
 
 	if (pci->iatu_unroll_enabled)
-		return dw_pcie_prog_inbound_atu_unroll(pci, func_no, index, bar,
-						       cpu_addr, as_type);
+		return dw_pcie_prog_inbound_atu_unroll(pci, func_no, index, type,
+						       cpu_addr, bar);
 
 	dw_pcie_writel_dbi(pci, PCIE_ATU_VIEWPORT, PCIE_ATU_REGION_INBOUND |
 			   index);
 	dw_pcie_writel_dbi(pci, PCIE_ATU_LOWER_TARGET, lower_32_bits(cpu_addr));
 	dw_pcie_writel_dbi(pci, PCIE_ATU_UPPER_TARGET, upper_32_bits(cpu_addr));
 
-	switch (as_type) {
-	case DW_PCIE_AS_MEM:
-		type = PCIE_ATU_TYPE_MEM;
-		break;
-	case DW_PCIE_AS_IO:
-		type = PCIE_ATU_TYPE_IO;
-		break;
-	default:
-		return -EINVAL;
-	}
-
 	dw_pcie_writel_dbi(pci, PCIE_ATU_CR1, type |
 			   PCIE_ATU_FUNC_NUM(func_no));
 	dw_pcie_writel_dbi(pci, PCIE_ATU_CR2, PCIE_ATU_ENABLE |
diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
index bca1d3e83636..449c5ad92edc 100644
--- a/drivers/pci/controller/dwc/pcie-designware.h
+++ b/drivers/pci/controller/dwc/pcie-designware.h
@@ -227,12 +227,6 @@ struct pcie_port {
 	DECLARE_BITMAP(msi_irq_in_use, MAX_MSI_IRQS);
 };
 
-enum dw_pcie_as_type {
-	DW_PCIE_AS_UNKNOWN,
-	DW_PCIE_AS_MEM,
-	DW_PCIE_AS_IO,
-};
-
 struct dw_pcie_ep_ops {
 	void	(*ep_init)(struct dw_pcie_ep *ep);
 	int	(*raise_irq)(struct dw_pcie_ep *ep, u8 func_no,
@@ -331,8 +325,7 @@ void dw_pcie_prog_ep_outbound_atu(struct dw_pcie *pci, u8 func_no, int index,
 				  int type, u64 cpu_addr, u64 pci_addr,
 				  u64 size);
 int dw_pcie_prog_inbound_atu(struct dw_pcie *pci, u8 func_no, int index,
-			     int bar, u64 cpu_addr,
-			     enum dw_pcie_as_type as_type);
+			     int type, u64 cpu_addr, u8 bar);
 void dw_pcie_disable_atu(struct dw_pcie *pci, int index,
 			 enum dw_pcie_region_type type);
 void dw_pcie_setup(struct dw_pcie *pci);
-- 
2.35.1


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 09/16] PCI: dwc: Simplify in/outbound iATU setup methods
  2022-03-24  1:37 [PATCH 00/16] PCI: dwc: Add dma-ranges/YAML-schema/Baikal-T1 support Serge Semin
                   ` (7 preceding siblings ...)
  2022-03-24  1:37 ` [PATCH 08/16] PCI: dwc: Drop inbound iATU types enumeration - dw_pcie_as_type Serge Semin
@ 2022-03-24  1:37 ` Serge Semin
  2022-03-29 15:28   ` Rob Herring
  2022-03-24  1:37 ` [PATCH 10/16] PCI: dwc: Drop iATU regions enumeration - dw_pcie_region_type Serge Semin
                   ` (6 subsequent siblings)
  15 siblings, 1 reply; 40+ messages in thread
From: Serge Semin @ 2022-03-24  1:37 UTC (permalink / raw)
  To: Jingoo Han, Gustavo Pimentel, Bjorn Helgaas, Lorenzo Pieralisi,
	Rob Herring, Krzysztof Wilczyński
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Frank Li, Manivannan Sadhasivam, Rob Herring, linux-pci,
	devicetree, linux-kernel

From maintainability and scalability points of view it has been wrong to
use different iATU inbound and outbound regions accessors for the viewport
and unrolled versions of the iATU CSRs mapping. Seeing the particular iATU
region-wise registers layout is almost fully compatible for different
IP-core versions, there were no much points in splitting the code up that
way since it was possible to implement a common windows setup methods for
both viewport and unrolled iATU CSRs spaces. While what we can observe in
the current driver implementation of these methods, is a lot of code
duplication, which consequently worsen the code readability,
maintainability and scalability. Note the current implementation is a bit
more performant than the one suggested in this commit since it implies
having less MMIO accesses. But the gain just doesn't worth having the
denoted difficulties especially seeing the iATU setup methods are mainly
called on the DW PCIe controller and peripheral devices initialization
stage.

Here we suggest to move the iATU viewport and unrolled CSR access
specifics in the dw_pcie_readl_atu() and dw_pcie_writel_atu() method, and
convert the dw_pcie_prog_outbound_atu() and
dw_pcie_prog_{ep_}inbound_atu() functions to being generic instead of
having a different methods for each viewport and unrolled types of iATU
CSRs mapping. Nothing complex really. First of all the dw_pcie_readl_atu()
and dw_pcie_writel_atu() are converted to accept relative iATU CSRs
address together with the iATU region direction (inbound or outbound) and
region index. If DW PCIe controller doesn't have the unrolled iATU CSRs
space, then the accessors will need to activate a iATU viewport based on
the specified direction and index, otherwise a base address for the
corresponding region CSRs will be calculated by means of the
PCIE_ATU_UNROLL_BASE() macro. The CSRs macro have been modified in
accordance with that logic in the pcie-designware.h header file.

The rest of the changes in this commit just concern converting the iATU
in-/out-bound setup methods and iATU regions detection procedure to be
compatible with the new accessors semantics. As a result we've dropped the
no more required dw_pcie_prog_outbound_atu_unroll(),
dw_pcie_prog_inbound_atu_unroll() and dw_pcie_iatu_detect_regions_unroll()
methods.

Note aside with the denoted code improvements, there is an additional
positive side effect of this change. If at some point an atomic iATU
configs setup procedure is required, it will be possible to be done with
no much effort just by adding the synchronization into the
dw_pcie_readl_atu() and dw_pcie_writel_atu() accessors.

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 drivers/pci/controller/dwc/pcie-designware.c | 301 ++++++-------------
 drivers/pci/controller/dwc/pcie-designware.h |  50 ++-
 2 files changed, 112 insertions(+), 239 deletions(-)

diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c
index b983128584ff..f1aa6e2e85fe 100644
--- a/drivers/pci/controller/dwc/pcie-designware.c
+++ b/drivers/pci/controller/dwc/pcie-designware.c
@@ -205,48 +205,67 @@ void dw_pcie_write_dbi2(struct dw_pcie *pci, u32 reg, size_t size, u32 val)
 		dev_err(pci->dev, "write DBI address failed\n");
 }
 
-static u32 dw_pcie_readl_atu(struct dw_pcie *pci, u32 reg)
+static u32 dw_pcie_readl_atu(struct dw_pcie *pci, u32 dir, u32 region, u32 reg)
 {
+	void __iomem *base;
 	int ret;
 	u32 val;
 
+	if (pci->iatu_unroll_enabled) {
+		base = pci->atu_base;
+		reg = reg + PCIE_ATU_UNROLL_BASE(dir, region);
+	} else {
+		base = pci->dbi_base;
+		reg = reg + PCIE_ATU_VIEWPORT_BASE;
+
+		dw_pcie_writel_dbi(pci, PCIE_ATU_VIEWPORT, dir | region);
+	}
+
 	if (pci->ops && pci->ops->read_dbi)
-		return pci->ops->read_dbi(pci, pci->atu_base, reg, 4);
+		return pci->ops->read_dbi(pci, base, reg, 4);
 
-	ret = dw_pcie_read(pci->atu_base + reg, 4, &val);
+	ret = dw_pcie_read(base + reg, 4, &val);
 	if (ret)
 		dev_err(pci->dev, "Read ATU address failed\n");
 
 	return val;
 }
 
-static void dw_pcie_writel_atu(struct dw_pcie *pci, u32 reg, u32 val)
+static void dw_pcie_writel_atu(struct dw_pcie *pci, u32 dir, u32 region,
+			       u32 reg, u32 val)
 {
+	void __iomem *base;
 	int ret;
 
+	if (pci->iatu_unroll_enabled) {
+		base = pci->atu_base;
+		reg = reg + PCIE_ATU_UNROLL_BASE(dir, region);
+	} else {
+		base = pci->dbi_base;
+		reg = reg + PCIE_ATU_VIEWPORT_BASE;
+
+		dw_pcie_writel_dbi(pci, PCIE_ATU_VIEWPORT, dir | region);
+	}
+
 	if (pci->ops && pci->ops->write_dbi) {
-		pci->ops->write_dbi(pci, pci->atu_base, reg, 4, val);
+		pci->ops->write_dbi(pci, base, reg, 4, val);
 		return;
 	}
 
-	ret = dw_pcie_write(pci->atu_base + reg, 4, val);
+	ret = dw_pcie_write(base + reg, 4, val);
 	if (ret)
 		dev_err(pci->dev, "Write ATU address failed\n");
 }
 
-static u32 dw_pcie_readl_ob_unroll(struct dw_pcie *pci, u32 index, u32 reg)
+static inline u32 dw_pcie_readl_atu_ob(struct dw_pcie *pci, u32 region, u32 reg)
 {
-	u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index);
-
-	return dw_pcie_readl_atu(pci, offset + reg);
+	return dw_pcie_readl_atu(pci, PCIE_ATU_REGION_DIR_OB, region, reg);
 }
 
-static void dw_pcie_writel_ob_unroll(struct dw_pcie *pci, u32 index, u32 reg,
-				     u32 val)
+static inline void dw_pcie_writel_atu_ob(struct dw_pcie *pci, u32 region, u32 reg,
+					 u32 val)
 {
-	u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index);
-
-	dw_pcie_writel_atu(pci, offset + reg, val);
+	dw_pcie_writel_atu(pci, PCIE_ATU_REGION_DIR_OB, region, reg, val);
 }
 
 static inline u32 dw_pcie_enable_ecrc(u32 val)
@@ -290,50 +309,6 @@ static inline u32 dw_pcie_enable_ecrc(u32 val)
 	return val | PCIE_ATU_TD;
 }
 
-static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, u8 func_no,
-					     int index, int type,
-					     u64 cpu_addr, u64 pci_addr,
-					     u64 size)
-{
-	u32 retries, val;
-	u64 limit_addr = cpu_addr + size - 1;
-
-	dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LOWER_BASE,
-				 lower_32_bits(cpu_addr));
-	dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_BASE,
-				 upper_32_bits(cpu_addr));
-	dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LOWER_LIMIT,
-				 lower_32_bits(limit_addr));
-	dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_LIMIT,
-				 upper_32_bits(limit_addr));
-	dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LOWER_TARGET,
-				 lower_32_bits(pci_addr));
-	dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_TARGET,
-				 upper_32_bits(pci_addr));
-	val = type | PCIE_ATU_FUNC_NUM(func_no);
-	if (upper_32_bits(limit_addr) > upper_32_bits(cpu_addr))
-		val |= PCIE_ATU_INCREASE_REGION_SIZE;
-	if (dw_pcie_ver_is(pci, 490A))
-		val = dw_pcie_enable_ecrc(val);
-	dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1, val);
-	dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL2,
-				 PCIE_ATU_ENABLE);
-
-	/*
-	 * Make sure ATU enable takes effect before any subsequent config
-	 * and I/O accesses.
-	 */
-	for (retries = 0; retries < LINK_WAIT_MAX_IATU_RETRIES; retries++) {
-		val = dw_pcie_readl_ob_unroll(pci, index,
-					      PCIE_ATU_UNR_REGION_CTRL2);
-		if (val & PCIE_ATU_ENABLE)
-			return;
-
-		mdelay(LINK_WAIT_IATU);
-	}
-	dev_err(pci->dev, "Outbound iATU is not being enabled\n");
-}
-
 static void __dw_pcie_prog_outbound_atu(struct dw_pcie *pci, u8 func_no,
 					int index, int type, u64 cpu_addr,
 					u64 pci_addr, u64 size)
@@ -344,49 +319,46 @@ static void __dw_pcie_prog_outbound_atu(struct dw_pcie *pci, u8 func_no,
 	if (pci->ops && pci->ops->cpu_addr_fixup)
 		cpu_addr = pci->ops->cpu_addr_fixup(pci, cpu_addr);
 
-	if (pci->iatu_unroll_enabled) {
-		dw_pcie_prog_outbound_atu_unroll(pci, func_no, index, type,
-						 cpu_addr, pci_addr, size);
-		return;
-	}
-
 	limit_addr = cpu_addr + size - 1;
 
-	dw_pcie_writel_dbi(pci, PCIE_ATU_VIEWPORT,
-			   PCIE_ATU_REGION_OUTBOUND | index);
-	dw_pcie_writel_dbi(pci, PCIE_ATU_LOWER_BASE,
-			   lower_32_bits(cpu_addr));
-	dw_pcie_writel_dbi(pci, PCIE_ATU_UPPER_BASE,
-			   upper_32_bits(cpu_addr));
-	dw_pcie_writel_dbi(pci, PCIE_ATU_LIMIT,
-			   lower_32_bits(limit_addr));
+	dw_pcie_writel_atu_ob(pci, index, PCIE_ATU_LOWER_BASE,
+			      lower_32_bits(cpu_addr));
+	dw_pcie_writel_atu_ob(pci, index, PCIE_ATU_UPPER_BASE,
+			      upper_32_bits(cpu_addr));
+
+	dw_pcie_writel_atu_ob(pci, index, PCIE_ATU_LIMIT,
+			      lower_32_bits(limit_addr));
 	if (dw_pcie_ver_is_ge(pci, 460A))
-		dw_pcie_writel_dbi(pci, PCIE_ATU_UPPER_LIMIT,
-				   upper_32_bits(limit_addr));
-	dw_pcie_writel_dbi(pci, PCIE_ATU_LOWER_TARGET,
-			   lower_32_bits(pci_addr));
-	dw_pcie_writel_dbi(pci, PCIE_ATU_UPPER_TARGET,
-			   upper_32_bits(pci_addr));
+		dw_pcie_writel_atu_ob(pci, index, PCIE_ATU_UPPER_LIMIT,
+				      upper_32_bits(limit_addr));
+
+	dw_pcie_writel_atu_ob(pci, index, PCIE_ATU_LOWER_TARGET,
+			      lower_32_bits(pci_addr));
+	dw_pcie_writel_atu_ob(pci, index, PCIE_ATU_UPPER_TARGET,
+			      upper_32_bits(pci_addr));
+
 	val = type | PCIE_ATU_FUNC_NUM(func_no);
 	if (upper_32_bits(limit_addr) > upper_32_bits(cpu_addr) &&
 	    dw_pcie_ver_is_ge(pci, 460A))
 		val |= PCIE_ATU_INCREASE_REGION_SIZE;
 	if (dw_pcie_ver_is(pci, 490A))
 		val = dw_pcie_enable_ecrc(val);
-	dw_pcie_writel_dbi(pci, PCIE_ATU_CR1, val);
-	dw_pcie_writel_dbi(pci, PCIE_ATU_CR2, PCIE_ATU_ENABLE);
+	dw_pcie_writel_atu_ob(pci, index, PCIE_ATU_REGION_CTRL1, val);
+
+	dw_pcie_writel_atu_ob(pci, index, PCIE_ATU_REGION_CTRL2, PCIE_ATU_ENABLE);
 
 	/*
 	 * Make sure ATU enable takes effect before any subsequent config
 	 * and I/O accesses.
 	 */
 	for (retries = 0; retries < LINK_WAIT_MAX_IATU_RETRIES; retries++) {
-		val = dw_pcie_readl_dbi(pci, PCIE_ATU_CR2);
+		val = dw_pcie_readl_atu_ob(pci, index, PCIE_ATU_REGION_CTRL2);
 		if (val & PCIE_ATU_ENABLE)
 			return;
 
 		mdelay(LINK_WAIT_IATU);
 	}
+
 	dev_err(pci->dev, "Outbound iATU is not being enabled\n");
 }
 
@@ -405,54 +377,15 @@ void dw_pcie_prog_ep_outbound_atu(struct dw_pcie *pci, u8 func_no, int index,
 				    cpu_addr, pci_addr, size);
 }
 
-static u32 dw_pcie_readl_ib_unroll(struct dw_pcie *pci, u32 index, u32 reg)
-{
-	u32 offset = PCIE_GET_ATU_INB_UNR_REG_OFFSET(index);
-
-	return dw_pcie_readl_atu(pci, offset + reg);
-}
-
-static void dw_pcie_writel_ib_unroll(struct dw_pcie *pci, u32 index, u32 reg,
-				     u32 val)
+static inline u32 dw_pcie_readl_atu_ib(struct dw_pcie *pci, u32 region, u32 reg)
 {
-	u32 offset = PCIE_GET_ATU_INB_UNR_REG_OFFSET(index);
-
-	dw_pcie_writel_atu(pci, offset + reg, val);
+	return dw_pcie_readl_atu(pci, PCIE_ATU_REGION_DIR_IB, region, reg);
 }
 
-static int dw_pcie_prog_inbound_atu_unroll(struct dw_pcie *pci, u8 func_no,
-					   int index, int type,
-					   u64 cpu_addr, u8 bar)
+static inline void dw_pcie_writel_atu_ib(struct dw_pcie *pci, u32 region, u32 reg,
+					 u32 val)
 {
-	u32 retries, val;
-
-	dw_pcie_writel_ib_unroll(pci, index, PCIE_ATU_UNR_LOWER_TARGET,
-				 lower_32_bits(cpu_addr));
-	dw_pcie_writel_ib_unroll(pci, index, PCIE_ATU_UNR_UPPER_TARGET,
-				 upper_32_bits(cpu_addr));
-
-	dw_pcie_writel_ib_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1, type |
-				 PCIE_ATU_FUNC_NUM(func_no));
-	dw_pcie_writel_ib_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL2,
-				 PCIE_ATU_FUNC_NUM_MATCH_EN |
-				 PCIE_ATU_ENABLE |
-				 PCIE_ATU_BAR_MODE_ENABLE | (bar << 8));
-
-	/*
-	 * Make sure ATU enable takes effect before any subsequent config
-	 * and I/O accesses.
-	 */
-	for (retries = 0; retries < LINK_WAIT_MAX_IATU_RETRIES; retries++) {
-		val = dw_pcie_readl_ib_unroll(pci, index,
-					      PCIE_ATU_UNR_REGION_CTRL2);
-		if (val & PCIE_ATU_ENABLE)
-			return 0;
-
-		mdelay(LINK_WAIT_IATU);
-	}
-	dev_err(pci->dev, "Inbound iATU is not being enabled\n");
-
-	return -EBUSY;
+	dw_pcie_writel_atu(pci, PCIE_ATU_REGION_DIR_IB, region, reg, val);
 }
 
 int dw_pcie_prog_inbound_atu(struct dw_pcie *pci, u8 func_no, int index,
@@ -460,65 +393,51 @@ int dw_pcie_prog_inbound_atu(struct dw_pcie *pci, u8 func_no, int index,
 {
 	u32 retries, val;
 
-	if (pci->iatu_unroll_enabled)
-		return dw_pcie_prog_inbound_atu_unroll(pci, func_no, index, type,
-						       cpu_addr, bar);
-
-	dw_pcie_writel_dbi(pci, PCIE_ATU_VIEWPORT, PCIE_ATU_REGION_INBOUND |
-			   index);
-	dw_pcie_writel_dbi(pci, PCIE_ATU_LOWER_TARGET, lower_32_bits(cpu_addr));
-	dw_pcie_writel_dbi(pci, PCIE_ATU_UPPER_TARGET, upper_32_bits(cpu_addr));
+	dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_LOWER_TARGET,
+			      lower_32_bits(cpu_addr));
+	dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_UPPER_TARGET,
+			      upper_32_bits(cpu_addr));
 
-	dw_pcie_writel_dbi(pci, PCIE_ATU_CR1, type |
-			   PCIE_ATU_FUNC_NUM(func_no));
-	dw_pcie_writel_dbi(pci, PCIE_ATU_CR2, PCIE_ATU_ENABLE |
-			   PCIE_ATU_FUNC_NUM_MATCH_EN |
-			   PCIE_ATU_BAR_MODE_ENABLE | (bar << 8));
+	dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_REGION_CTRL1, type |
+			      PCIE_ATU_FUNC_NUM(func_no));
+	dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_REGION_CTRL2,
+			      PCIE_ATU_ENABLE | PCIE_ATU_FUNC_NUM_MATCH_EN |
+			      PCIE_ATU_BAR_MODE_ENABLE | (bar << 8));
 
 	/*
 	 * Make sure ATU enable takes effect before any subsequent config
 	 * and I/O accesses.
 	 */
 	for (retries = 0; retries < LINK_WAIT_MAX_IATU_RETRIES; retries++) {
-		val = dw_pcie_readl_dbi(pci, PCIE_ATU_CR2);
+		val = dw_pcie_readl_atu_ib(pci, index, PCIE_ATU_REGION_CTRL2);
 		if (val & PCIE_ATU_ENABLE)
 			return 0;
 
 		mdelay(LINK_WAIT_IATU);
 	}
+
 	dev_err(pci->dev, "Inbound iATU is not being enabled\n");
 
-	return -EBUSY;
+	return -ETIMEDOUT;
 }
 
 void dw_pcie_disable_atu(struct dw_pcie *pci, int index,
 			 enum dw_pcie_region_type type)
 {
-	int region;
+	u32 dir;
 
 	switch (type) {
 	case DW_PCIE_REGION_INBOUND:
-		region = PCIE_ATU_REGION_INBOUND;
+		dir = PCIE_ATU_REGION_DIR_IB;
 		break;
 	case DW_PCIE_REGION_OUTBOUND:
-		region = PCIE_ATU_REGION_OUTBOUND;
+		dir = PCIE_ATU_REGION_DIR_OB;
 		break;
 	default:
 		return;
 	}
 
-	if (pci->iatu_unroll_enabled) {
-		if (region == PCIE_ATU_REGION_INBOUND) {
-			dw_pcie_writel_ib_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL2,
-						 ~(u32)PCIE_ATU_ENABLE);
-		} else {
-			dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL2,
-						 ~(u32)PCIE_ATU_ENABLE);
-		}
-	} else {
-		dw_pcie_writel_dbi(pci, PCIE_ATU_VIEWPORT, region | index);
-		dw_pcie_writel_dbi(pci, PCIE_ATU_CR2, ~(u32)PCIE_ATU_ENABLE);
-	}
+	dw_pcie_writel_atu(pci, dir, index, PCIE_ATU_REGION_CTRL2, 0);
 }
 
 int dw_pcie_wait_for_link(struct dw_pcie *pci)
@@ -622,63 +541,29 @@ static bool dw_pcie_iatu_unroll_enabled(struct dw_pcie *pci)
 	return false;
 }
 
-static void dw_pcie_iatu_detect_regions_unroll(struct dw_pcie *pci)
-{
-	int max_region, i, ob = 0, ib = 0;
-	u32 val;
-
-	max_region = min((int)pci->atu_size / 512, 256);
-
-	for (i = 0; i < max_region; i++) {
-		dw_pcie_writel_ob_unroll(pci, i, PCIE_ATU_UNR_LOWER_TARGET,
-					0x11110000);
-
-		val = dw_pcie_readl_ob_unroll(pci, i, PCIE_ATU_UNR_LOWER_TARGET);
-		if (val == 0x11110000)
-			ob++;
-		else
-			break;
-	}
-
-	for (i = 0; i < max_region; i++) {
-		dw_pcie_writel_ib_unroll(pci, i, PCIE_ATU_UNR_LOWER_TARGET,
-					0x11110000);
-
-		val = dw_pcie_readl_ib_unroll(pci, i, PCIE_ATU_UNR_LOWER_TARGET);
-		if (val == 0x11110000)
-			ib++;
-		else
-			break;
-	}
-	pci->num_ib_windows = ib;
-	pci->num_ob_windows = ob;
-}
-
 static void dw_pcie_iatu_detect_regions(struct dw_pcie *pci)
 {
-	int max_region, i, ob = 0, ib = 0;
+	int max_region, ob, ib;
 	u32 val;
 
-	dw_pcie_writel_dbi(pci, PCIE_ATU_VIEWPORT, 0xFF);
-	max_region = dw_pcie_readl_dbi(pci, PCIE_ATU_VIEWPORT) + 1;
+	if (pci->iatu_unroll_enabled) {
+		max_region = min((int)pci->atu_size / 512, 256);
+	} else {
+		dw_pcie_writel_dbi(pci, PCIE_ATU_VIEWPORT, 0xFF);
+		max_region = dw_pcie_readl_dbi(pci, PCIE_ATU_VIEWPORT) + 1;
+	}
 
-	for (i = 0; i < max_region; i++) {
-		dw_pcie_writel_dbi(pci, PCIE_ATU_VIEWPORT, PCIE_ATU_REGION_OUTBOUND | i);
-		dw_pcie_writel_dbi(pci, PCIE_ATU_LOWER_TARGET, 0x11110000);
-		val = dw_pcie_readl_dbi(pci, PCIE_ATU_LOWER_TARGET);
-		if (val == 0x11110000)
-			ob++;
-		else
+	for (ob = 0; ob < max_region; ob++) {
+		dw_pcie_writel_atu_ob(pci, ob, PCIE_ATU_LOWER_TARGET, 0x11110000);
+		val = dw_pcie_readl_atu_ob(pci, ob, PCIE_ATU_LOWER_TARGET);
+		if (val != 0x11110000)
 			break;
 	}
 
-	for (i = 0; i < max_region; i++) {
-		dw_pcie_writel_dbi(pci, PCIE_ATU_VIEWPORT, PCIE_ATU_REGION_INBOUND | i);
-		dw_pcie_writel_dbi(pci, PCIE_ATU_LOWER_TARGET, 0x11110000);
-		val = dw_pcie_readl_dbi(pci, PCIE_ATU_LOWER_TARGET);
-		if (val == 0x11110000)
-			ib++;
-		else
+	for (ib = 0; ib < max_region; ib++) {
+		dw_pcie_writel_atu_ib(pci, ib, PCIE_ATU_LOWER_TARGET, 0x11110000);
+		val = dw_pcie_readl_atu_ib(pci, ib, PCIE_ATU_LOWER_TARGET);
+		if (val != 0x11110000)
 			break;
 	}
 
@@ -707,12 +592,10 @@ void dw_pcie_iatu_detect(struct dw_pcie *pci)
 		if (!pci->atu_size)
 			/* Pick a minimal default, enough for 8 in and 8 out windows */
 			pci->atu_size = SZ_4K;
-
-		dw_pcie_iatu_detect_regions_unroll(pci);
-	} else {
-		dw_pcie_iatu_detect_regions(pci);
 	}
 
+	dw_pcie_iatu_detect_regions(pci);
+
 	dev_info(pci->dev, "iATU unroll: %s\n", pci->iatu_unroll_enabled ?
 		"enabled" : "disabled");
 
diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
index 449c5ad92edc..6adf0c957c3b 100644
--- a/drivers/pci/controller/dwc/pcie-designware.h
+++ b/drivers/pci/controller/dwc/pcie-designware.h
@@ -103,10 +103,20 @@
 #define PCIE_VERSION_NUMBER		0x8F8
 #define PCIE_VERSION_TYPE		0x8FC
 
+/*
+ * iATU inbound and outbound windows CSRs. Before the IP-core v4.80a each
+ * iATU region CSRs had been indirectly accessible by means of the dedicated
+ * viewport selector. The iATU/eDMA CSRs space was re-designed in DWC PCIe
+ * v4.80a in a way so the viewport was unrolled into the directly accessible
+ * iATU/eDMA CSRs space.
+ */
 #define PCIE_ATU_VIEWPORT		0x900
-#define PCIE_ATU_REGION_INBOUND		BIT(31)
-#define PCIE_ATU_REGION_OUTBOUND	0
-#define PCIE_ATU_CR1			0x904
+#define PCIE_ATU_REGION_DIR_IB		BIT(31)
+#define PCIE_ATU_REGION_DIR_OB		0
+#define PCIE_ATU_VIEWPORT_BASE		0x904
+#define PCIE_ATU_UNROLL_BASE(dir, region) \
+	(((region) << 9) | ((dir == PCIE_ATU_REGION_DIR_IB) ? BIT(8) : 0))
+#define PCIE_ATU_REGION_CTRL1		0x000
 #define PCIE_ATU_INCREASE_REGION_SIZE	BIT(13)
 #define PCIE_ATU_TYPE_MEM		0x0
 #define PCIE_ATU_TYPE_IO		0x2
@@ -114,19 +124,19 @@
 #define PCIE_ATU_TYPE_CFG1		0x5
 #define PCIE_ATU_TD			BIT(8)
 #define PCIE_ATU_FUNC_NUM(pf)           ((pf) << 20)
-#define PCIE_ATU_CR2			0x908
+#define PCIE_ATU_REGION_CTRL2		0x004
 #define PCIE_ATU_ENABLE			BIT(31)
 #define PCIE_ATU_BAR_MODE_ENABLE	BIT(30)
 #define PCIE_ATU_FUNC_NUM_MATCH_EN      BIT(19)
-#define PCIE_ATU_LOWER_BASE		0x90C
-#define PCIE_ATU_UPPER_BASE		0x910
-#define PCIE_ATU_LIMIT			0x914
-#define PCIE_ATU_LOWER_TARGET		0x918
+#define PCIE_ATU_LOWER_BASE		0x008
+#define PCIE_ATU_UPPER_BASE		0x00C
+#define PCIE_ATU_LIMIT			0x010
+#define PCIE_ATU_LOWER_TARGET		0x014
 #define PCIE_ATU_BUS(x)			FIELD_PREP(GENMASK(31, 24), x)
 #define PCIE_ATU_DEV(x)			FIELD_PREP(GENMASK(23, 19), x)
 #define PCIE_ATU_FUNC(x)		FIELD_PREP(GENMASK(18, 16), x)
-#define PCIE_ATU_UPPER_TARGET		0x91C
-#define PCIE_ATU_UPPER_LIMIT		0x924
+#define PCIE_ATU_UPPER_TARGET		0x018
+#define PCIE_ATU_UPPER_LIMIT		0x020
 
 #define PCIE_MISC_CONTROL_1_OFF		0x8BC
 #define PCIE_DBI_RO_WR_EN		BIT(0)
@@ -143,19 +153,6 @@
 
 #define PCIE_PL_CHK_REG_ERR_ADDR			0xB28
 
-/*
- * iATU Unroll-specific register definitions
- * From 4.80 core version the address translation will be made by unroll
- */
-#define PCIE_ATU_UNR_REGION_CTRL1	0x00
-#define PCIE_ATU_UNR_REGION_CTRL2	0x04
-#define PCIE_ATU_UNR_LOWER_BASE		0x08
-#define PCIE_ATU_UNR_UPPER_BASE		0x0C
-#define PCIE_ATU_UNR_LOWER_LIMIT	0x10
-#define PCIE_ATU_UNR_LOWER_TARGET	0x14
-#define PCIE_ATU_UNR_UPPER_TARGET	0x18
-#define PCIE_ATU_UNR_UPPER_LIMIT	0x20
-
 /*
  * The default address offset between dbi_base and atu_base. Root controller
  * drivers are not required to initialize atu_base if the offset matches this
@@ -164,13 +161,6 @@
  */
 #define DEFAULT_DBI_ATU_OFFSET (0x3 << 20)
 
-/* Register address builder */
-#define PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(region) \
-		((region) << 9)
-
-#define PCIE_GET_ATU_INB_UNR_REG_OFFSET(region) \
-		(((region) << 9) | BIT(8))
-
 #define MAX_MSI_IRQS			256
 #define MAX_MSI_IRQS_PER_CTRL		32
 #define MAX_MSI_CTRLS			(MAX_MSI_IRQS / MAX_MSI_IRQS_PER_CTRL)
-- 
2.35.1


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 10/16] PCI: dwc: Drop iATU regions enumeration - dw_pcie_region_type
  2022-03-24  1:37 [PATCH 00/16] PCI: dwc: Add dma-ranges/YAML-schema/Baikal-T1 support Serge Semin
                   ` (8 preceding siblings ...)
  2022-03-24  1:37 ` [PATCH 09/16] PCI: dwc: Simplify in/outbound iATU setup methods Serge Semin
@ 2022-03-24  1:37 ` Serge Semin
  2022-03-29 15:31   ` Rob Herring
  2022-03-24  1:37 ` [PATCH 11/16] PCI: dwc: Add iATU regions size detection procedure Serge Semin
                   ` (5 subsequent siblings)
  15 siblings, 1 reply; 40+ messages in thread
From: Serge Semin @ 2022-03-24  1:37 UTC (permalink / raw)
  To: Jingoo Han, Gustavo Pimentel, Bjorn Helgaas, Lorenzo Pieralisi,
	Rob Herring, Krzysztof Wilczyński
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Frank Li, Manivannan Sadhasivam, Rob Herring, linux-pci,
	devicetree, linux-kernel

There is no point in having the dw_pcie_region_type enumeration for almost
the same reasons as it was stated for dw_pcie_as_type. First of all it's
redundant since the driver already has a set of macro declared which
describe the possible inbound and outbound iATU regions. Having an
addition abstraction just needlessly complicates the code. Secondly
checking the region index passed to the dw_pcie_disable_atu() method for
validity is pointless since the erroneous situation will be just
ignored in the current code implementation. So to speak let's drop the
redundant dw_pcie_region_type enumeration replacing it with the direct
iATU direction macro usage.

While at it we suggest to convert the dw_pcie_disable_atu() method to
being more consistent with the dw_pcie_readl_atu{_ib}() and
dw_pcie_readl_atu{_ob}() functions by having the direction parameter
specified ahead of the region index. Thus the code will be a little bit
more pleasant to read.

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 drivers/pci/controller/dwc/pcie-designware-ep.c  |  4 ++--
 .../pci/controller/dwc/pcie-designware-host.c    |  2 +-
 drivers/pci/controller/dwc/pcie-designware.c     | 16 +---------------
 drivers/pci/controller/dwc/pcie-designware.h     |  9 +--------
 4 files changed, 5 insertions(+), 26 deletions(-)

diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c
index 3bd9026071e8..83ceba84b79d 100644
--- a/drivers/pci/controller/dwc/pcie-designware-ep.c
+++ b/drivers/pci/controller/dwc/pcie-designware-ep.c
@@ -212,7 +212,7 @@ static void dw_pcie_ep_clear_bar(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
 
 	__dw_pcie_ep_reset_bar(pci, func_no, bar, epf_bar->flags);
 
-	dw_pcie_disable_atu(pci, atu_index, DW_PCIE_REGION_INBOUND);
+	dw_pcie_disable_atu(pci, PCIE_ATU_REGION_DIR_IB, atu_index);
 	clear_bit(atu_index, ep->ib_window_map);
 	ep->epf_bar[bar] = NULL;
 }
@@ -286,7 +286,7 @@ static void dw_pcie_ep_unmap_addr(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
 	if (ret < 0)
 		return;
 
-	dw_pcie_disable_atu(pci, atu_index, DW_PCIE_REGION_OUTBOUND);
+	dw_pcie_disable_atu(pci, PCIE_ATU_REGION_DIR_OB, atu_index);
 	clear_bit(atu_index, ep->ob_window_map);
 }
 
diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c
index 602cf4fe502b..e9aa3d8539d8 100644
--- a/drivers/pci/controller/dwc/pcie-designware-host.c
+++ b/drivers/pci/controller/dwc/pcie-designware-host.c
@@ -644,7 +644,7 @@ void dw_pcie_setup_rc(struct pcie_port *pp)
 		 * multiple matches
 		 */
 		for (i = 0; i < pci->num_ob_windows; i++)
-			dw_pcie_disable_atu(pci, i, DW_PCIE_REGION_OUTBOUND);
+			dw_pcie_disable_atu(pci, PCIE_ATU_REGION_DIR_OB, i);
 
 		/* Get last memory resource entry */
 		resource_list_for_each_entry(entry, &pp->bridge->windows) {
diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c
index f1aa6e2e85fe..ce360986609f 100644
--- a/drivers/pci/controller/dwc/pcie-designware.c
+++ b/drivers/pci/controller/dwc/pcie-designware.c
@@ -421,22 +421,8 @@ int dw_pcie_prog_inbound_atu(struct dw_pcie *pci, u8 func_no, int index,
 	return -ETIMEDOUT;
 }
 
-void dw_pcie_disable_atu(struct dw_pcie *pci, int index,
-			 enum dw_pcie_region_type type)
+void dw_pcie_disable_atu(struct dw_pcie *pci, u32 dir, int index)
 {
-	u32 dir;
-
-	switch (type) {
-	case DW_PCIE_REGION_INBOUND:
-		dir = PCIE_ATU_REGION_DIR_IB;
-		break;
-	case DW_PCIE_REGION_OUTBOUND:
-		dir = PCIE_ATU_REGION_DIR_OB;
-		break;
-	default:
-		return;
-	}
-
 	dw_pcie_writel_atu(pci, dir, index, PCIE_ATU_REGION_CTRL2, 0);
 }
 
diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
index 6adf0c957c3b..203f9dfb9048 100644
--- a/drivers/pci/controller/dwc/pcie-designware.h
+++ b/drivers/pci/controller/dwc/pcie-designware.h
@@ -175,12 +175,6 @@ struct pcie_port;
 struct dw_pcie;
 struct dw_pcie_ep;
 
-enum dw_pcie_region_type {
-	DW_PCIE_REGION_UNKNOWN,
-	DW_PCIE_REGION_INBOUND,
-	DW_PCIE_REGION_OUTBOUND,
-};
-
 enum dw_pcie_device_mode {
 	DW_PCIE_UNKNOWN_TYPE,
 	DW_PCIE_EP_TYPE,
@@ -316,8 +310,7 @@ void dw_pcie_prog_ep_outbound_atu(struct dw_pcie *pci, u8 func_no, int index,
 				  u64 size);
 int dw_pcie_prog_inbound_atu(struct dw_pcie *pci, u8 func_no, int index,
 			     int type, u64 cpu_addr, u8 bar);
-void dw_pcie_disable_atu(struct dw_pcie *pci, int index,
-			 enum dw_pcie_region_type type);
+void dw_pcie_disable_atu(struct dw_pcie *pci, u32 dir, int index);
 void dw_pcie_setup(struct dw_pcie *pci);
 void dw_pcie_iatu_detect(struct dw_pcie *pci);
 
-- 
2.35.1


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 11/16] PCI: dwc: Add iATU regions size detection procedure
  2022-03-24  1:37 [PATCH 00/16] PCI: dwc: Add dma-ranges/YAML-schema/Baikal-T1 support Serge Semin
                   ` (9 preceding siblings ...)
  2022-03-24  1:37 ` [PATCH 10/16] PCI: dwc: Drop iATU regions enumeration - dw_pcie_region_type Serge Semin
@ 2022-03-24  1:37 ` Serge Semin
  2022-03-24  1:37 ` [PATCH 12/16] PCI: dwc: Verify in/out regions against iATU constraints Serge Semin
                   ` (4 subsequent siblings)
  15 siblings, 0 replies; 40+ messages in thread
From: Serge Semin @ 2022-03-24  1:37 UTC (permalink / raw)
  To: Jingoo Han, Gustavo Pimentel, Bjorn Helgaas, Lorenzo Pieralisi,
	Rob Herring, Krzysztof Wilczyński
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Frank Li, Manivannan Sadhasivam, Rob Herring, linux-pci,
	devicetree, linux-kernel

Depending on the DWC PCIe RC/EP/DM IP-core configuration parameters the
controllers can be equipped not only with various number of inbound and
outbound iATU windows, but with varied regions settings like alignment
(which is also the minimum window size), minimum and maximum sizes. So to
speak if internal ATU is enabled for the denoted IP-cores then the former
settings will be defined by the CX_ATU_MIN_REGION_SIZE parameter while the
later one will be determined by the CX_ATU_MAX_REGION_SIZE configuration
parameter. Anyway having these parameters used in the driver will help to
verify whether the requested inbound or outbound memory mappings can be
fully created. Currently the driver doesn't perform any corresponding
checking.

Note 1. The extended iATU regions have been supported since DWC PCIe
v4.60a. There is no need in testing the upper limit register availability
for the older cores.

Note 2. The regions alignment is determined with using the fls() method
since the lower four bits of the ATU Limit register can be occupied with
the Circular Buffer Increment setting, which can be initialized with
zeros.

The (dma-)ranges verification will be added a bit later in one of the next
commits.

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 drivers/pci/controller/dwc/pcie-designware.c | 33 +++++++++++++++++---
 drivers/pci/controller/dwc/pcie-designware.h |  2 ++
 2 files changed, 31 insertions(+), 4 deletions(-)

diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c
index ce360986609f..c218b1fe4dad 100644
--- a/drivers/pci/controller/dwc/pcie-designware.c
+++ b/drivers/pci/controller/dwc/pcie-designware.c
@@ -8,9 +8,11 @@
  * Author: Jingoo Han <jg1.han@samsung.com>
  */
 
+#include <linux/bitops.h>
 #include <linux/delay.h>
 #include <linux/of.h>
 #include <linux/of_platform.h>
+#include <linux/sizes.h>
 #include <linux/types.h>
 
 #include "../../pci.h"
@@ -530,7 +532,8 @@ static bool dw_pcie_iatu_unroll_enabled(struct dw_pcie *pci)
 static void dw_pcie_iatu_detect_regions(struct dw_pcie *pci)
 {
 	int max_region, ob, ib;
-	u32 val;
+	u32 val, min, dir;
+	u64 max;
 
 	if (pci->iatu_unroll_enabled) {
 		max_region = min((int)pci->atu_size / 512, 256);
@@ -553,8 +556,29 @@ static void dw_pcie_iatu_detect_regions(struct dw_pcie *pci)
 			break;
 	}
 
-	pci->num_ib_windows = ib;
+	if (ob) {
+		dir = PCIE_ATU_REGION_DIR_OB;
+	} else if (ib) {
+		dir = PCIE_ATU_REGION_DIR_IB;
+	} else {
+		dev_err(pci->dev, "No iATU regions found\n");
+		return;
+	}
+
+	dw_pcie_writel_atu(pci, dir, 0, PCIE_ATU_LIMIT, 0x0);
+	min = dw_pcie_readl_atu(pci, dir, 0, PCIE_ATU_LIMIT);
+
+	if (dw_pcie_ver_is_ge(pci, 460A)) {
+		dw_pcie_writel_atu(pci, dir, 0, PCIE_ATU_UPPER_LIMIT, 0xFFFFFFFF);
+		max = dw_pcie_readl_atu(pci, dir, 0, PCIE_ATU_UPPER_LIMIT);
+	} else {
+		max = 0;
+	}
+
 	pci->num_ob_windows = ob;
+	pci->num_ib_windows = ib;
+	pci->region_align = 1 << fls(min);
+	pci->region_limit = (max << 32) | (SZ_4G - 1);
 }
 
 void dw_pcie_iatu_detect(struct dw_pcie *pci)
@@ -585,8 +609,9 @@ void dw_pcie_iatu_detect(struct dw_pcie *pci)
 	dev_info(pci->dev, "iATU unroll: %s\n", pci->iatu_unroll_enabled ?
 		"enabled" : "disabled");
 
-	dev_info(pci->dev, "Detected iATU regions: %u outbound, %u inbound\n",
-		 pci->num_ob_windows, pci->num_ib_windows);
+	dev_info(pci->dev, "iATU regions: %u ob, %u ib, align %uK, limit %lluG\n",
+		 pci->num_ob_windows, pci->num_ib_windows,
+		 pci->region_align / SZ_1K, (pci->region_limit + 1) / SZ_1G);
 }
 
 void dw_pcie_setup(struct dw_pcie *pci)
diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
index 203f9dfb9048..8b601a6a6090 100644
--- a/drivers/pci/controller/dwc/pcie-designware.h
+++ b/drivers/pci/controller/dwc/pcie-designware.h
@@ -271,6 +271,8 @@ struct dw_pcie {
 	size_t			atu_size;
 	u32			num_ib_windows;
 	u32			num_ob_windows;
+	u32			region_align;
+	u64			region_limit;
 	struct pcie_port	pp;
 	struct dw_pcie_ep	ep;
 	const struct dw_pcie_ops *ops;
-- 
2.35.1


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 12/16] PCI: dwc: Verify in/out regions against iATU constraints
  2022-03-24  1:37 [PATCH 00/16] PCI: dwc: Add dma-ranges/YAML-schema/Baikal-T1 support Serge Semin
                   ` (10 preceding siblings ...)
  2022-03-24  1:37 ` [PATCH 11/16] PCI: dwc: Add iATU regions size detection procedure Serge Semin
@ 2022-03-24  1:37 ` Serge Semin
  2022-03-24  1:37 ` [PATCH 13/16] PCI: dwc: Check iATU in/outbound ranges setup methods status Serge Semin
                   ` (3 subsequent siblings)
  15 siblings, 0 replies; 40+ messages in thread
From: Serge Semin @ 2022-03-24  1:37 UTC (permalink / raw)
  To: Jingoo Han, Gustavo Pimentel, Bjorn Helgaas, Lorenzo Pieralisi,
	Rob Herring, Krzysztof Wilczyński
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Frank Li, Manivannan Sadhasivam, Rob Herring, linux-pci,
	devicetree, linux-kernel

Since the DWC PCIe driver private data now contains the iATU inbound and
outbound regions constraints info like alignment, minimum and maximum
limits, we can use them to make the in- and outbound iATU regions setup
methods more strict to the ranges a callee tries to specify.  That will
give us the safer dw_pcie_prog_outbound_atu(),
dw_pcie_prog_ep_outbound_atu() and dw_pcie_prog_inbound_atu() functions.

First of all let's update the outbound ATU entries setup methods to
returning the operation status. The methods will fail either in case if
the range is failed to be activated or the passed region doesn't fulfill
iATU constraints. Secondly the passed to the
dw_pcie_prog_{ep_}outbound_atu() methods region-related parameters are
verified against the detected iATU regions constraints. In particular the
region limit address must not overflow the lower/upper limit CSR RW-fields
otherwise the specified range will be just silently clamped. That
verification will also protect the code from having u64 type overflow.
Secondly let's make sure base address (CPU-address), target address
(PCI-address) and size are properly aligned. Unaligned ranges will be
silently aligned down (addresses) and up (limit) on writing the values to
the corresponding registers, which in it turn may lead to unpredictable
results like ranges virtual overlap. Finally the CPU-address alignment
needs to be verified in the dw_pcie_prog_inbound_atu() method too as the
DWC PCIe RC/EP registers manual demands seeing the lower bits of the in-
and outbound iATU base address are always zeros.

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 drivers/pci/controller/dwc/pcie-designware.c | 39 +++++++++++++-------
 drivers/pci/controller/dwc/pcie-designware.h | 10 ++---
 2 files changed, 30 insertions(+), 19 deletions(-)

diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c
index c218b1fe4dad..2a7f23a2045c 100644
--- a/drivers/pci/controller/dwc/pcie-designware.c
+++ b/drivers/pci/controller/dwc/pcie-designware.c
@@ -8,6 +8,7 @@
  * Author: Jingoo Han <jg1.han@samsung.com>
  */
 
+#include <linux/align.h>
 #include <linux/bitops.h>
 #include <linux/delay.h>
 #include <linux/of.h>
@@ -311,9 +312,9 @@ static inline u32 dw_pcie_enable_ecrc(u32 val)
 	return val | PCIE_ATU_TD;
 }
 
-static void __dw_pcie_prog_outbound_atu(struct dw_pcie *pci, u8 func_no,
-					int index, int type, u64 cpu_addr,
-					u64 pci_addr, u64 size)
+static int __dw_pcie_prog_outbound_atu(struct dw_pcie *pci, u8 func_no,
+				       int index, int type, u64 cpu_addr,
+				       u64 pci_addr, u64 size)
 {
 	u32 retries, val;
 	u64 limit_addr;
@@ -323,6 +324,13 @@ static void __dw_pcie_prog_outbound_atu(struct dw_pcie *pci, u8 func_no,
 
 	limit_addr = cpu_addr + size - 1;
 
+	if ((limit_addr & ~pci->region_limit) != (cpu_addr & ~pci->region_limit) ||
+	    !IS_ALIGNED(cpu_addr, pci->region_align) ||
+	    !IS_ALIGNED(pci_addr, pci->region_align) ||
+	    !IS_ALIGNED(size, pci->region_align) || !size) {
+		return -EINVAL;
+	}
+
 	dw_pcie_writel_atu_ob(pci, index, PCIE_ATU_LOWER_BASE,
 			      lower_32_bits(cpu_addr));
 	dw_pcie_writel_atu_ob(pci, index, PCIE_ATU_UPPER_BASE,
@@ -356,27 +364,29 @@ static void __dw_pcie_prog_outbound_atu(struct dw_pcie *pci, u8 func_no,
 	for (retries = 0; retries < LINK_WAIT_MAX_IATU_RETRIES; retries++) {
 		val = dw_pcie_readl_atu_ob(pci, index, PCIE_ATU_REGION_CTRL2);
 		if (val & PCIE_ATU_ENABLE)
-			return;
+			return 0;
 
 		mdelay(LINK_WAIT_IATU);
 	}
 
 	dev_err(pci->dev, "Outbound iATU is not being enabled\n");
+
+	return -ETIMEDOUT;
 }
 
-void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index, int type,
-			       u64 cpu_addr, u64 pci_addr, u64 size)
+int dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index, int type,
+			      u64 cpu_addr, u64 pci_addr, u64 size)
 {
-	__dw_pcie_prog_outbound_atu(pci, 0, index, type,
-				    cpu_addr, pci_addr, size);
+	return __dw_pcie_prog_outbound_atu(pci, 0, index, type,
+					   cpu_addr, pci_addr, size);
 }
 
-void dw_pcie_prog_ep_outbound_atu(struct dw_pcie *pci, u8 func_no, int index,
-				  int type, u64 cpu_addr, u64 pci_addr,
-				  u64 size)
+int dw_pcie_prog_ep_outbound_atu(struct dw_pcie *pci, u8 func_no, int index,
+				 int type, u64 cpu_addr, u64 pci_addr,
+				 u64 size)
 {
-	__dw_pcie_prog_outbound_atu(pci, func_no, index, type,
-				    cpu_addr, pci_addr, size);
+	return __dw_pcie_prog_outbound_atu(pci, func_no, index, type,
+					   cpu_addr, pci_addr, size);
 }
 
 static inline u32 dw_pcie_readl_atu_ib(struct dw_pcie *pci, u32 region, u32 reg)
@@ -395,6 +405,9 @@ int dw_pcie_prog_inbound_atu(struct dw_pcie *pci, u8 func_no, int index,
 {
 	u32 retries, val;
 
+	if (!IS_ALIGNED(cpu_addr, pci->region_align))
+		return -EINVAL;
+
 	dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_LOWER_TARGET,
 			      lower_32_bits(cpu_addr));
 	dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_UPPER_TARGET,
diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
index 8b601a6a6090..bcda63393390 100644
--- a/drivers/pci/controller/dwc/pcie-designware.h
+++ b/drivers/pci/controller/dwc/pcie-designware.h
@@ -304,12 +304,10 @@ void dw_pcie_write_dbi2(struct dw_pcie *pci, u32 reg, size_t size, u32 val);
 int dw_pcie_link_up(struct dw_pcie *pci);
 void dw_pcie_upconfig_setup(struct dw_pcie *pci);
 int dw_pcie_wait_for_link(struct dw_pcie *pci);
-void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index,
-			       int type, u64 cpu_addr, u64 pci_addr,
-			       u64 size);
-void dw_pcie_prog_ep_outbound_atu(struct dw_pcie *pci, u8 func_no, int index,
-				  int type, u64 cpu_addr, u64 pci_addr,
-				  u64 size);
+int dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index, int type,
+			      u64 cpu_addr, u64 pci_addr, u64 size);
+int dw_pcie_prog_ep_outbound_atu(struct dw_pcie *pci, u8 func_no, int index,
+				 int type, u64 cpu_addr, u64 pci_addr, u64 size);
 int dw_pcie_prog_inbound_atu(struct dw_pcie *pci, u8 func_no, int index,
 			     int type, u64 cpu_addr, u8 bar);
 void dw_pcie_disable_atu(struct dw_pcie *pci, u32 dir, int index);
-- 
2.35.1


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 13/16] PCI: dwc: Check iATU in/outbound ranges setup methods status
  2022-03-24  1:37 [PATCH 00/16] PCI: dwc: Add dma-ranges/YAML-schema/Baikal-T1 support Serge Semin
                   ` (11 preceding siblings ...)
  2022-03-24  1:37 ` [PATCH 12/16] PCI: dwc: Verify in/out regions against iATU constraints Serge Semin
@ 2022-03-24  1:37 ` Serge Semin
  2022-03-24  1:37 ` [PATCH 14/16] PCI: dwc: Introduce dma-ranges property support for RC-host Serge Semin
                   ` (2 subsequent siblings)
  15 siblings, 0 replies; 40+ messages in thread
From: Serge Semin @ 2022-03-24  1:37 UTC (permalink / raw)
  To: Jingoo Han, Gustavo Pimentel, Bjorn Helgaas, Lorenzo Pieralisi,
	Rob Herring, Krzysztof Wilczyński, Rahul Tanwar
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Frank Li, Manivannan Sadhasivam, Rob Herring, linux-pci,
	devicetree, linux-kernel

Let's make the DWC PCIe RC/EP safer and more verbose for the invalid or
failed inbound and outbound iATU windows setups. Needless to say that
silently ignoring iATU regions setup errors may cause unpredictable
errors. For instance if for some reason a cfg or IO window fails to be
activated, then any CFG/IO requested won't reach target PCIe devices and
the corresponding accessors will return platform-specific random values.

First of all we need to convert dw_pcie_ep_outbound_atu() method to check
whether the specified outbound iATU range is successfully setup. That
method is called by the pci_epc_ops.map_addr callback. Thus we'll make the
EP-specific CPU->PCIe memory mappings saver.

Secondly since the iATU outbound range programming method now returns the
operation status, it will be handy to take that status into account in the
pci_ops.{map_bus,read,write} methods. Thus any failed mapping will be
immediately noticeable by the PCIe CFG operations requesters.

Finally we need to convert the dw_pcie_setup_rc() method to returning the
operation status, since the iATU outbound ranges setup procedure may now
fail. It will be especially handy in case if the DW PCIe RC DT-node has
invalid/unsupported (dma-)ranges property. Note since the suggested
modification causes having too wide code indentation, it is reasonable
from maintainability and readability points of view to move the outbound
ranges setup procedure in the separate function.

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 .../pci/controller/dwc/pcie-designware-ep.c   |   9 +-
 .../pci/controller/dwc/pcie-designware-host.c | 149 ++++++++++++------
 drivers/pci/controller/dwc/pcie-designware.h  |   5 +-
 drivers/pci/controller/dwc/pcie-intel-gw.c    |   6 +-
 4 files changed, 112 insertions(+), 57 deletions(-)

diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c
index 83ceba84b79d..47ed9256b87c 100644
--- a/drivers/pci/controller/dwc/pcie-designware-ep.c
+++ b/drivers/pci/controller/dwc/pcie-designware-ep.c
@@ -184,8 +184,9 @@ static int dw_pcie_ep_outbound_atu(struct dw_pcie_ep *ep, u8 func_no,
 				   phys_addr_t phys_addr,
 				   u64 pci_addr, size_t size)
 {
-	u32 free_win;
 	struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
+	u32 free_win;
+	int ret;
 
 	free_win = find_first_zero_bit(ep->ob_window_map, pci->num_ob_windows);
 	if (free_win >= pci->num_ob_windows) {
@@ -193,8 +194,10 @@ static int dw_pcie_ep_outbound_atu(struct dw_pcie_ep *ep, u8 func_no,
 		return -EINVAL;
 	}
 
-	dw_pcie_prog_ep_outbound_atu(pci, func_no, free_win, PCIE_ATU_TYPE_MEM,
-				     phys_addr, pci_addr, size);
+	ret = dw_pcie_prog_ep_outbound_atu(pci, func_no, free_win, PCIE_ATU_TYPE_MEM,
+					   phys_addr, pci_addr, size);
+	if (ret)
+		return ret;
 
 	set_bit(free_win, ep->ob_window_map);
 	ep->outbound_addr[free_win] = phys_addr;
diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c
index e9aa3d8539d8..41c673c31940 100644
--- a/drivers/pci/controller/dwc/pcie-designware-host.c
+++ b/drivers/pci/controller/dwc/pcie-designware-host.c
@@ -405,7 +405,9 @@ int dw_pcie_host_init(struct pcie_port *pp)
 
 	dw_pcie_iatu_detect(pci);
 
-	dw_pcie_setup_rc(pp);
+	ret = dw_pcie_setup_rc(pp);
+	if (ret)
+		goto err_free_msi;
 
 	if (!dw_pcie_link_up(pci) && pci->ops && pci->ops->start_link) {
 		ret = pci->ops->start_link(pci);
@@ -461,10 +463,10 @@ EXPORT_SYMBOL_GPL(dw_pcie_host_deinit);
 static void __iomem *dw_pcie_other_conf_map_bus(struct pci_bus *bus,
 						unsigned int devfn, int where)
 {
-	int type;
-	u32 busdev;
 	struct pcie_port *pp = bus->sysdata;
 	struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+	int type, ret;
+	u32 busdev;
 
 	/*
 	 * Checking whether the link is up here is a last line of defense
@@ -485,8 +487,10 @@ static void __iomem *dw_pcie_other_conf_map_bus(struct pci_bus *bus,
 	else
 		type = PCIE_ATU_TYPE_CFG1;
 
-
-	dw_pcie_prog_outbound_atu(pci, 0, type, pp->cfg0_base, busdev, pp->cfg0_size);
+	ret = dw_pcie_prog_outbound_atu(pci, 0, type, pp->cfg0_base, busdev,
+					pp->cfg0_size);
+	if (ret)
+		return NULL;
 
 	return pp->va_cfg0_base + where;
 }
@@ -499,12 +503,18 @@ static int dw_pcie_rd_other_conf(struct pci_bus *bus, unsigned int devfn,
 	struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
 
 	ret = pci_generic_config_read(bus, devfn, where, size, val);
+	if (ret != PCIBIOS_SUCCESSFUL)
+		return ret;
 
-	if (!ret && pci->io_cfg_atu_shared)
-		dw_pcie_prog_outbound_atu(pci, 0, PCIE_ATU_TYPE_IO, pp->io_base,
-					  pp->io_bus_addr, pp->io_size);
+	if (pci->io_cfg_atu_shared) {
+		ret = dw_pcie_prog_outbound_atu(pci, 0, PCIE_ATU_TYPE_IO,
+						pp->io_base, pp->io_bus_addr,
+						pp->io_size);
+		if (ret)
+			return PCIBIOS_SET_FAILED;
+	}
 
-	return ret;
+	return PCIBIOS_SUCCESSFUL;
 }
 
 static int dw_pcie_wr_other_conf(struct pci_bus *bus, unsigned int devfn,
@@ -515,12 +525,18 @@ static int dw_pcie_wr_other_conf(struct pci_bus *bus, unsigned int devfn,
 	struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
 
 	ret = pci_generic_config_write(bus, devfn, where, size, val);
+	if (ret != PCIBIOS_SUCCESSFUL)
+		return ret;
 
-	if (!ret && pci->io_cfg_atu_shared)
-		dw_pcie_prog_outbound_atu(pci, 0, PCIE_ATU_TYPE_IO, pp->io_base,
-					  pp->io_bus_addr, pp->io_size);
+	if (pci->io_cfg_atu_shared) {
+		ret = dw_pcie_prog_outbound_atu(pci, 0, PCIE_ATU_TYPE_IO,
+						pp->io_base, pp->io_bus_addr,
+						pp->io_size);
+		if (ret)
+			return PCIBIOS_SET_FAILED;
+	}
 
-	return ret;
+	return PCIBIOS_SUCCESSFUL;
 }
 
 static struct pci_ops dw_child_pcie_ops = {
@@ -577,10 +593,72 @@ static struct pci_ops dw_pcie_ops = {
 	.write = dw_pcie_wr_own_conf,
 };
 
-void dw_pcie_setup_rc(struct pcie_port *pp)
+static int dw_pcie_iatu_setup(struct pcie_port *pp)
+{
+	struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+	struct resource_entry *entry;
+	int i, ret;
+
+	/* Note the very first outbound ATU is used for CFG IOs */
+	if (!pci->num_ob_windows) {
+		dev_err(pci->dev, "No outbound iATU found\n");
+		return -EINVAL;
+	}
+
+	/*
+	 * Ensure all outbound windows are disabled before proceeding with
+	 * the MEM/IO ranges setups.
+	 */
+	for (i = 0; i < pci->num_ob_windows; i++)
+		dw_pcie_disable_atu(pci, PCIE_ATU_REGION_DIR_OB, i);
+
+	i = 0;
+	resource_list_for_each_entry(entry, &pp->bridge->windows) {
+		if (resource_type(entry->res) != IORESOURCE_MEM)
+			continue;
+
+		if (pci->num_ob_windows <= ++i)
+			break;
+
+		ret = dw_pcie_prog_outbound_atu(pci, i, PCIE_ATU_TYPE_MEM,
+						entry->res->start,
+						entry->res->start - entry->offset,
+						resource_size(entry->res));
+		if (ret) {
+			dev_err(pci->dev, "Failed to set MEM range %pr\n",
+				entry->res);
+			return ret;
+		}
+	}
+
+	if (pp->io_size) {
+		if (pci->num_ob_windows > ++i) {
+			ret = dw_pcie_prog_outbound_atu(pci, i, PCIE_ATU_TYPE_IO,
+							pp->io_base,
+							pp->io_bus_addr,
+							pp->io_size);
+			if (ret) {
+				dev_err(pci->dev, "Failed to set IO range %pr\n",
+					entry->res);
+				return ret;
+			}
+		} else {
+			pci->io_cfg_atu_shared = true;
+		}
+	}
+
+	if (pci->num_ob_windows <= i)
+		dev_warn(pci->dev, "Resources exceed number of ATU entries (%d)\n",
+			 pci->num_ob_windows);
+
+	return 0;
+}
+
+int dw_pcie_setup_rc(struct pcie_port *pp)
 {
-	u32 val, ctrl, num_ctrls;
 	struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+	u32 val, ctrl, num_ctrls;
+	int ret;
 
 	/*
 	 * Enable DBI read-only registers for writing/updating configuration.
@@ -636,42 +714,9 @@ void dw_pcie_setup_rc(struct pcie_port *pp)
 	 * ATU, so we should not program the ATU here.
 	 */
 	if (pp->bridge->child_ops == &dw_child_pcie_ops) {
-		int i, atu_idx = 0;
-		struct resource_entry *entry;
-
-		/*
-		 * Ensure all outbound windows are disabled so there are
-		 * multiple matches
-		 */
-		for (i = 0; i < pci->num_ob_windows; i++)
-			dw_pcie_disable_atu(pci, PCIE_ATU_REGION_DIR_OB, i);
-
-		/* Get last memory resource entry */
-		resource_list_for_each_entry(entry, &pp->bridge->windows) {
-			if (resource_type(entry->res) != IORESOURCE_MEM)
-				continue;
-
-			if (pci->num_ob_windows <= ++atu_idx)
-				break;
-
-			dw_pcie_prog_outbound_atu(pci, atu_idx,
-						  PCIE_ATU_TYPE_MEM, entry->res->start,
-						  entry->res->start - entry->offset,
-						  resource_size(entry->res));
-		}
-
-		if (pp->io_size) {
-			if (pci->num_ob_windows > ++atu_idx)
-				dw_pcie_prog_outbound_atu(pci, atu_idx,
-							  PCIE_ATU_TYPE_IO, pp->io_base,
-							  pp->io_bus_addr, pp->io_size);
-			else
-				pci->io_cfg_atu_shared = true;
-		}
-
-		if (pci->num_ob_windows <= atu_idx)
-			dev_warn(pci->dev, "Resources exceed number of ATU entries (%d)\n",
-				 pci->num_ob_windows);
+		ret = dw_pcie_iatu_setup(pp);
+		if (ret)
+			return ret;
 	}
 
 	dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_0, 0);
@@ -684,5 +729,7 @@ void dw_pcie_setup_rc(struct pcie_port *pp)
 	dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, val);
 
 	dw_pcie_dbi_ro_wr_dis(pci);
+
+	return 0;
 }
 EXPORT_SYMBOL_GPL(dw_pcie_setup_rc);
diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
index bcda63393390..15fce8fd33df 100644
--- a/drivers/pci/controller/dwc/pcie-designware.h
+++ b/drivers/pci/controller/dwc/pcie-designware.h
@@ -373,7 +373,7 @@ static inline void dw_pcie_dbi_ro_wr_dis(struct dw_pcie *pci)
 
 #ifdef CONFIG_PCIE_DW_HOST
 irqreturn_t dw_handle_msi_irq(struct pcie_port *pp);
-void dw_pcie_setup_rc(struct pcie_port *pp);
+int dw_pcie_setup_rc(struct pcie_port *pp);
 int dw_pcie_host_init(struct pcie_port *pp);
 void dw_pcie_host_deinit(struct pcie_port *pp);
 int dw_pcie_allocate_domains(struct pcie_port *pp);
@@ -385,8 +385,9 @@ static inline irqreturn_t dw_handle_msi_irq(struct pcie_port *pp)
 	return IRQ_NONE;
 }
 
-static inline void dw_pcie_setup_rc(struct pcie_port *pp)
+static inline int dw_pcie_setup_rc(struct pcie_port *pp)
 {
+	return 0;
 }
 
 static inline int dw_pcie_host_init(struct pcie_port *pp)
diff --git a/drivers/pci/controller/dwc/pcie-intel-gw.c b/drivers/pci/controller/dwc/pcie-intel-gw.c
index 786af2ba379f..c3bafaa803de 100644
--- a/drivers/pci/controller/dwc/pcie-intel-gw.c
+++ b/drivers/pci/controller/dwc/pcie-intel-gw.c
@@ -306,7 +306,11 @@ static int intel_pcie_host_setup(struct intel_pcie *pcie)
 	intel_pcie_ltssm_disable(pcie);
 	intel_pcie_link_setup(pcie);
 	intel_pcie_init_n_fts(pci);
-	dw_pcie_setup_rc(&pci->pp);
+
+	ret = dw_pcie_setup_rc(&pci->pp);
+	if (ret)
+		goto app_init_err;
+
 	dw_pcie_upconfig_setup(pci);
 
 	intel_pcie_device_rst_deassert(pcie);
-- 
2.35.1


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 14/16] PCI: dwc: Introduce dma-ranges property support for RC-host
  2022-03-24  1:37 [PATCH 00/16] PCI: dwc: Add dma-ranges/YAML-schema/Baikal-T1 support Serge Semin
                   ` (12 preceding siblings ...)
  2022-03-24  1:37 ` [PATCH 13/16] PCI: dwc: Check iATU in/outbound ranges setup methods status Serge Semin
@ 2022-03-24  1:37 ` Serge Semin
  2022-03-24  1:37 ` [PATCH 15/16] PCI: dwc: Introduce generic platform clocks and resets sets Serge Semin
  2022-03-24  1:37 ` [PATCH 16/16] PCI: dwc: Add Baikal-T1 PCIe controller support Serge Semin
  15 siblings, 0 replies; 40+ messages in thread
From: Serge Semin @ 2022-03-24  1:37 UTC (permalink / raw)
  To: Jingoo Han, Gustavo Pimentel, Bjorn Helgaas, Lorenzo Pieralisi,
	Rob Herring, Krzysztof Wilczyński
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Frank Li, Manivannan Sadhasivam, Rob Herring, linux-pci,
	devicetree, linux-kernel

In accordance with the generic PCIe Root Port DT-bindings the "dma-ranges"
property has the same format as the "ranges" property. The only difference
is in their semantics. The "dma-ranges" property describes the PCIe-to-CPU
memory mapping in opposite to the CPU-to-PCIe mapping of the "ranges"
property. Even though the DW PCIe controllers are normally equipped with
internal Address Translation Unit which inbound and outbound tables can be
used to implement both properties semantics, it was surprise for me to
discover that the host-related part of the DW PCIe driver currently
supports the "ranges" property only while the "dma-ranges" windows are
just ignored. Having the "dma-ranges" supported in the driver would be
very handy for the platforms, that don't tolerate the 1:1 CPU-PCIe memory
mapping and require customized the PCIe memory layout. So let's fix that
by introducing the "dma-ranges" property support.

First of all we suggest to rename the dw_pcie_prog_inbound_atu() method to
dw_pcie_prog_ep_inbound_atu() and create a new version of the
dw_pcie_prog_inbound_atu() function. Thus we'll have two methods for RC
and EP controllers respectively in the same way as it has been developed
for the outbound ATU setup methods.

Secondly aside with the memory window index and type the new
dw_pcie_prog_inbound_atu() function will accept CPU address, PCIe address
and size as its arguments. These parameters define the PCIe and CPU memory
ranges which will be used to setup the respective inbound ATU mapping. The
passed parameters need to be verified against the ATU ranges constraints
in the same way as it is done for the outbound ranges.

Finally the DMA-ranges detected for the PCIe controller need to be
converted into the inbound ATU entries during the host controller
initialization procedure. It will be done in the framework of the
dw_pcie_iatu_setup() method. Note before setting the inbound ranges up we
need to disable all the inbound ATU entries in order to prevent unexpected
PCIe TLPs translations defined by some third party software like
bootloader.

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 .../pci/controller/dwc/pcie-designware-ep.c   |  4 +-
 .../pci/controller/dwc/pcie-designware-host.c | 32 ++++++++++-
 drivers/pci/controller/dwc/pcie-designware.c  | 57 ++++++++++++++++++-
 drivers/pci/controller/dwc/pcie-designware.h  |  6 +-
 4 files changed, 90 insertions(+), 9 deletions(-)

diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c
index 47ed9256b87c..23401f17e8f0 100644
--- a/drivers/pci/controller/dwc/pcie-designware-ep.c
+++ b/drivers/pci/controller/dwc/pcie-designware-ep.c
@@ -167,8 +167,8 @@ static int dw_pcie_ep_inbound_atu(struct dw_pcie_ep *ep, u8 func_no, int type,
 		return -EINVAL;
 	}
 
-	ret = dw_pcie_prog_inbound_atu(pci, func_no, free_win, type,
-				       cpu_addr, bar);
+	ret = dw_pcie_prog_ep_inbound_atu(pci, func_no, free_win, type,
+					  cpu_addr, bar);
 	if (ret < 0) {
 		dev_err(pci->dev, "Failed to program IB window\n");
 		return ret;
diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c
index 41c673c31940..715a13b90e43 100644
--- a/drivers/pci/controller/dwc/pcie-designware-host.c
+++ b/drivers/pci/controller/dwc/pcie-designware-host.c
@@ -606,12 +606,15 @@ static int dw_pcie_iatu_setup(struct pcie_port *pp)
 	}
 
 	/*
-	 * Ensure all outbound windows are disabled before proceeding with
-	 * the MEM/IO ranges setups.
+	 * Ensure all out/inbound windows are disabled before proceeding with
+	 * the MEM/IO (dma-)ranges setups.
 	 */
 	for (i = 0; i < pci->num_ob_windows; i++)
 		dw_pcie_disable_atu(pci, PCIE_ATU_REGION_DIR_OB, i);
 
+	for (i = 0; i < pci->num_ib_windows; i++)
+		dw_pcie_disable_atu(pci, PCIE_ATU_REGION_DIR_IB, i);
+
 	i = 0;
 	resource_list_for_each_entry(entry, &pp->bridge->windows) {
 		if (resource_type(entry->res) != IORESOURCE_MEM)
@@ -648,9 +651,32 @@ static int dw_pcie_iatu_setup(struct pcie_port *pp)
 	}
 
 	if (pci->num_ob_windows <= i)
-		dev_warn(pci->dev, "Resources exceed number of ATU entries (%d)\n",
+		dev_warn(pci->dev, "Ranges exceed outbound iATU size (%d)\n",
 			 pci->num_ob_windows);
 
+	i = 0;
+	resource_list_for_each_entry(entry, &pp->bridge->dma_ranges) {
+		if (resource_type(entry->res) != IORESOURCE_MEM)
+			continue;
+
+		if (pci->num_ib_windows <= i)
+			break;
+
+		ret = dw_pcie_prog_inbound_atu(pci, i++, PCIE_ATU_TYPE_MEM,
+					       entry->res->start,
+					       entry->res->start - entry->offset,
+					       resource_size(entry->res));
+		if (ret) {
+			dev_err(pci->dev, "Failed to set DMA range %pr\n",
+				entry->res);
+			return ret;
+		}
+	}
+
+	if (pci->num_ib_windows <= i)
+		dev_warn(pci->dev, "Dma-ranges exceed inbound iATU size (%u)\n",
+			 pci->num_ib_windows);
+
 	return 0;
 }
 
diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c
index 2a7f23a2045c..4a95a7b112e9 100644
--- a/drivers/pci/controller/dwc/pcie-designware.c
+++ b/drivers/pci/controller/dwc/pcie-designware.c
@@ -400,8 +400,61 @@ static inline void dw_pcie_writel_atu_ib(struct dw_pcie *pci, u32 region, u32 re
 	dw_pcie_writel_atu(pci, PCIE_ATU_REGION_DIR_IB, region, reg, val);
 }
 
-int dw_pcie_prog_inbound_atu(struct dw_pcie *pci, u8 func_no, int index,
-			     int type, u64 cpu_addr, u8 bar)
+int dw_pcie_prog_inbound_atu(struct dw_pcie *pci, int index, int type,
+			     u64 cpu_addr, u64 pci_addr, u64 size)
+{
+	u64 limit_addr = pci_addr + size - 1;
+	u32 retries, val;
+
+	if ((limit_addr & ~pci->region_limit) != (pci_addr & ~pci->region_limit) ||
+	    !IS_ALIGNED(cpu_addr, pci->region_align) ||
+	    !IS_ALIGNED(pci_addr, pci->region_align) ||
+	    !IS_ALIGNED(size, pci->region_align) || !size) {
+		return -EINVAL;
+	}
+
+	dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_LOWER_BASE,
+			      lower_32_bits(pci_addr));
+	dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_UPPER_BASE,
+			      upper_32_bits(pci_addr));
+
+	dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_LIMIT,
+			      lower_32_bits(limit_addr));
+	if (dw_pcie_ver_is_ge(pci, 460A))
+		dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_UPPER_LIMIT,
+				      upper_32_bits(limit_addr));
+
+	dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_LOWER_TARGET,
+			      lower_32_bits(cpu_addr));
+	dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_UPPER_TARGET,
+			      upper_32_bits(cpu_addr));
+
+	val = type;
+	if (upper_32_bits(limit_addr) > upper_32_bits(pci_addr) &&
+	    dw_pcie_ver_is_ge(pci, 460A))
+		val |= PCIE_ATU_INCREASE_REGION_SIZE;
+	dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_REGION_CTRL1, val);
+	dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_REGION_CTRL2, PCIE_ATU_ENABLE);
+
+	/*
+	 * Make sure ATU enable takes effect before any subsequent config
+	 * and I/O accesses.
+	 */
+	for (retries = 0; retries < LINK_WAIT_MAX_IATU_RETRIES; retries++) {
+		val = dw_pcie_readl_atu_ib(pci, index, PCIE_ATU_REGION_CTRL2);
+		if (val & PCIE_ATU_ENABLE)
+			return 0;
+
+		mdelay(LINK_WAIT_IATU);
+	}
+
+	dev_err(pci->dev, "Inbound iATU is not being enabled\n");
+
+	return -ETIMEDOUT;
+}
+
+int dw_pcie_prog_ep_inbound_atu(struct dw_pcie *pci, u8 func_no, int index,
+				int type, u64 cpu_addr, u8 bar)
 {
 	u32 retries, val;
 
diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
index 15fce8fd33df..ade854217332 100644
--- a/drivers/pci/controller/dwc/pcie-designware.h
+++ b/drivers/pci/controller/dwc/pcie-designware.h
@@ -308,8 +308,10 @@ int dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index, int type,
 			      u64 cpu_addr, u64 pci_addr, u64 size);
 int dw_pcie_prog_ep_outbound_atu(struct dw_pcie *pci, u8 func_no, int index,
 				 int type, u64 cpu_addr, u64 pci_addr, u64 size);
-int dw_pcie_prog_inbound_atu(struct dw_pcie *pci, u8 func_no, int index,
-			     int type, u64 cpu_addr, u8 bar);
+int dw_pcie_prog_inbound_atu(struct dw_pcie *pci, int index, int type,
+			     u64 cpu_addr, u64 pci_addr, u64 size);
+int dw_pcie_prog_ep_inbound_atu(struct dw_pcie *pci, u8 func_no, int index,
+				int type, u64 cpu_addr, u8 bar);
 void dw_pcie_disable_atu(struct dw_pcie *pci, u32 dir, int index);
 void dw_pcie_setup(struct dw_pcie *pci);
 void dw_pcie_iatu_detect(struct dw_pcie *pci);
-- 
2.35.1


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 15/16] PCI: dwc: Introduce generic platform clocks and resets sets
  2022-03-24  1:37 [PATCH 00/16] PCI: dwc: Add dma-ranges/YAML-schema/Baikal-T1 support Serge Semin
                   ` (13 preceding siblings ...)
  2022-03-24  1:37 ` [PATCH 14/16] PCI: dwc: Introduce dma-ranges property support for RC-host Serge Semin
@ 2022-03-24  1:37 ` Serge Semin
  2022-03-24  1:37 ` [PATCH 16/16] PCI: dwc: Add Baikal-T1 PCIe controller support Serge Semin
  15 siblings, 0 replies; 40+ messages in thread
From: Serge Semin @ 2022-03-24  1:37 UTC (permalink / raw)
  To: Jingoo Han, Gustavo Pimentel, Bjorn Helgaas, Lorenzo Pieralisi,
	Rob Herring, Krzysztof Wilczyński
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Frank Li, Manivannan Sadhasivam, Rob Herring, linux-pci,
	devicetree, linux-kernel

Currently almost each platform driver uses its own resets and clocks
naming in order to get the corresponding descriptors. It makes the code
harder to maintain and comprehend especially seeing the DWC PCIe core main
resets and clocks signals set hasn't changed much for about at least one
major IP-core release. So in order to organize things around these signals
we suggest to create a generic interface for them in accordance with the
naming introduced in the DWC PCIe IP-core reference manual:

Clocks:
- DBI - data bus interface clock (on some DWC PCIe platforms it's
  referred as "pclk", "pcie", "sys", "ahb", "cfg", "iface", "gio", "reg",
  "pcie_apb_sys");
- MSTR - AXI-bus master interface clock (some DWC PCIe glue drivers refer
  to this clock as "port", "bus", "pcie_bus",
  "bus_master/master_bus/axi_m", "pcie_aclk");
- SLV - AXI-bus slave interface clock (also called as "port", "bus",
  "pcie_bus", "bus_slave/slave_bus/axi_s", "pcie_aclk",
  "pcie_inbound_axi");
- PIPE - Core-PCS PIPE interface clock coming from external PHY (it's
  normally named by the platform drivers as just "pipe")
- CORE - primary clock of the controller (none of the platform drivers
  declare such a clock but in accordance with the ref. manual the devices
  may have it separately specified);
- AUX - Auxiliary PMC domain clock (it is named by some platforms as
  "pcie_aux" and just "aux")
- REF - Generic reference clock (it is a generic clock source, which can
  be used as a signal source for multiple interfaces, some platforms call
  it as "ref", "general", "pcie_phy", "pcie_phy_ref").

Application resets:
- DBI - Data-bus interface reset (it's CSR interface clock and is normally
  called as "apb" though technically it's not APB but DWC PCIe-specific
  interface);
  apb, sys,
- MSTR -AXI-bus master reset (some platforms call it as "port", "apps",
  "bus", "axi_m");
- SLV - ABI-bus slave reset (some platforms call it as "port", "apps",
  "bus", "axi_s").

Core resets:
- NON_STICKY - Non-sticky CSR flags reset;
- STICKY - sticky CSR flags reset;
- PIPE - PIPE-interface (Core-PCS) logic reset (some platforms call it
  just "pipe");
- CORE - controller primary reset (resets everything except PMC module,
  some platforms refer to this signal as "soft", "pci");
- PHY - PCS/PHY block reset (strictly speaking it is normally connected to
  the out of the external block, but the reference manual says it must be
  available for the PMC working correctly, some existing platforms call it
  as "pciephy", "phy", "link");
- HOT - PMC hot reset signal (also called as sleep");
- PWR - cold reset signal (can be referred as "pwr", "turnoff").

As you can see each platform uses it's own naming for basically the same
set of the signals. In the framework of this commit we suggest to add a
set of the clocks and signals identifiers and corresponding names for each
denoted entity. The platforms will be able to use them to define local
mapping tables between the generic identifiers and the available set of
the clocks and resets. The tables can be then utilized to create the
corresponding bulk-arrays, which in its turn can be passed to the
clock/reset-bulk API methods to easily get/enable/disable/put,
get/reset/assert/deassert/put all the handlers at once or, if it's
required, manipulate with the handlers individually.

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 drivers/pci/controller/dwc/pcie-designware.h | 79 ++++++++++++++++++++
 1 file changed, 79 insertions(+)

diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
index ade854217332..11c52d2eaf79 100644
--- a/drivers/pci/controller/dwc/pcie-designware.h
+++ b/drivers/pci/controller/dwc/pcie-designware.h
@@ -182,6 +182,35 @@ enum dw_pcie_device_mode {
 	DW_PCIE_RC_TYPE,
 };
 
+enum dw_pcie_clk {
+	DW_PCIE_DBI_CLK,
+	DW_PCIE_MSTR_CLK,
+	DW_PCIE_SLV_CLK,
+	DW_PCIE_PIPE_CLK,
+	DW_PCIE_CORE_CLK,
+	DW_PCIE_AUX_CLK,
+	DW_PCIE_REF_CLK,
+	DW_PCIE_NUM_CLKS
+};
+
+enum dw_pcie_app_rst {
+	DW_PCIE_DBI_RST,
+	DW_PCIE_MSTR_RST,
+	DW_PCIE_SLV_RST,
+	DW_PCIE_NUM_APP_RSTS
+};
+
+enum dw_pcie_core_rst {
+	DW_PCIE_NON_STICKY_RST,
+	DW_PCIE_STICKY_RST,
+	DW_PCIE_CORE_RST,
+	DW_PCIE_PIPE_RST,
+	DW_PCIE_PHY_RST,
+	DW_PCIE_HOT_RST,
+	DW_PCIE_PWR_RST,
+	DW_PCIE_NUM_CORE_RSTS
+};
+
 struct dw_pcie_host_ops {
 	int (*host_init)(struct pcie_port *pp);
 	void (*host_deinit)(struct pcie_port *pp);
@@ -373,6 +402,56 @@ static inline void dw_pcie_dbi_ro_wr_dis(struct dw_pcie *pci)
 	dw_pcie_writel_dbi(pci, reg, val);
 }
 
+static inline const char *dw_pcie_clk_name(enum dw_pcie_clk id)
+{
+	static const char *names[DW_PCIE_NUM_CLKS] = {
+		[DW_PCIE_DBI_CLK] = "dbi",
+		[DW_PCIE_MSTR_CLK] = "mstr",
+		[DW_PCIE_SLV_CLK] = "slv",
+		[DW_PCIE_PIPE_CLK] = "pipe",
+		[DW_PCIE_CORE_CLK] = "core",
+		[DW_PCIE_AUX_CLK] = "aux",
+		[DW_PCIE_REF_CLK] = "ref",
+	};
+
+	if (id >= DW_PCIE_NUM_CLKS)
+		return NULL;
+
+	return names[id];
+}
+
+static inline const char *dw_pcie_app_rst_name(enum dw_pcie_app_rst id)
+{
+	static const char *names[DW_PCIE_NUM_APP_RSTS] = {
+		[DW_PCIE_DBI_RST] = "dbi",
+		[DW_PCIE_MSTR_RST] = "mstr",
+		[DW_PCIE_SLV_RST] = "slv",
+	};
+
+	if (id >= DW_PCIE_NUM_APP_RSTS)
+		return NULL;
+
+	return names[id];
+}
+
+static inline const char *dw_pcie_core_rst_name(enum dw_pcie_core_rst id)
+{
+	static const char *names[DW_PCIE_NUM_CORE_RSTS] = {
+		[DW_PCIE_NON_STICKY_RST] = "non-sticky",
+		[DW_PCIE_STICKY_RST] = "sticky",
+		[DW_PCIE_CORE_RST] = "core",
+		[DW_PCIE_PIPE_RST] = "pipe",
+		[DW_PCIE_PHY_RST] = "phy",
+		[DW_PCIE_HOT_RST] = "hot",
+		[DW_PCIE_PWR_RST] = "pwr",
+	};
+
+	if (id >= DW_PCIE_NUM_CORE_RSTS)
+		return NULL;
+
+	return names[id];
+}
+
 #ifdef CONFIG_PCIE_DW_HOST
 irqreturn_t dw_handle_msi_irq(struct pcie_port *pp);
 int dw_pcie_setup_rc(struct pcie_port *pp);
-- 
2.35.1


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 16/16] PCI: dwc: Add Baikal-T1 PCIe controller support
  2022-03-24  1:37 [PATCH 00/16] PCI: dwc: Add dma-ranges/YAML-schema/Baikal-T1 support Serge Semin
                   ` (14 preceding siblings ...)
  2022-03-24  1:37 ` [PATCH 15/16] PCI: dwc: Introduce generic platform clocks and resets sets Serge Semin
@ 2022-03-24  1:37 ` Serge Semin
  15 siblings, 0 replies; 40+ messages in thread
From: Serge Semin @ 2022-03-24  1:37 UTC (permalink / raw)
  To: Jingoo Han, Gustavo Pimentel, Bjorn Helgaas, Lorenzo Pieralisi,
	Rob Herring, Krzysztof Wilczyński
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Frank Li, Manivannan Sadhasivam, Rob Herring, linux-pci,
	devicetree, linux-kernel

Baikal-T1 SoC is equipped with DWC PCIe v4.60a host controller. It can be
trained to work up to Gen.3 speed over up to x4 lanes. The host controller
is attached to the DW PCIe 3.0 PCS via the PIPE-4 interface, which in its
turn is connected to the DWC 10G PHY. The whole system is supposed to be
fed up with four clock sources: DBI peripheral clock, AXI application
clocks and external PHY/core reference clock generating the 100MHz signal.
In addition to that the platform provide a way to reset each part of the
controller: sticky/non-sticky bits, host controller core, PIPE interface,
PCS/PHY and Hot/Power reset signal. The driver also provides a way to
handle the GPIO-based PERST# signal.

Note due to the Baikal-T1 MMIO peculiarity we have to implement the DBI
interface accessors which make sure the IO is dword-aligned.

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 drivers/pci/controller/dwc/Kconfig    |   9 +
 drivers/pci/controller/dwc/Makefile   |   1 +
 drivers/pci/controller/dwc/pcie-bt1.c | 638 ++++++++++++++++++++++++++
 3 files changed, 648 insertions(+)
 create mode 100644 drivers/pci/controller/dwc/pcie-bt1.c

diff --git a/drivers/pci/controller/dwc/Kconfig b/drivers/pci/controller/dwc/Kconfig
index 62ce3abf0f19..771b8b146623 100644
--- a/drivers/pci/controller/dwc/Kconfig
+++ b/drivers/pci/controller/dwc/Kconfig
@@ -222,6 +222,15 @@ config PCIE_ARTPEC6_EP
 	  Enables support for the PCIe controller in the ARTPEC-6 SoC to work in
 	  endpoint mode. This uses the DesignWare core.
 
+config PCIE_BT1
+	tristate "Baikal-T1 PCIe controller"
+	depends on MIPS_BAIKAL_T1 || COMPILE_TEST
+	depends on PCI_MSI_IRQ_DOMAIN
+	select PCIE_DW_HOST
+	help
+	  Enables support for the PCIe controller in the Baikal-T1 SoC to work
+	  in host mode. It's based on the Synopsys DWC PCIe v4.60a IP-core.
+
 config PCIE_ROCKCHIP_DW_HOST
 	bool "Rockchip DesignWare PCIe controller"
 	select PCIE_DW
diff --git a/drivers/pci/controller/dwc/Makefile b/drivers/pci/controller/dwc/Makefile
index 8ba7b67f5e50..bf5c311875a1 100644
--- a/drivers/pci/controller/dwc/Makefile
+++ b/drivers/pci/controller/dwc/Makefile
@@ -3,6 +3,7 @@ obj-$(CONFIG_PCIE_DW) += pcie-designware.o
 obj-$(CONFIG_PCIE_DW_HOST) += pcie-designware-host.o
 obj-$(CONFIG_PCIE_DW_EP) += pcie-designware-ep.o
 obj-$(CONFIG_PCIE_DW_PLAT) += pcie-designware-plat.o
+obj-$(CONFIG_PCIE_BT1) += pcie-bt1.o
 obj-$(CONFIG_PCI_DRA7XX) += pci-dra7xx.o
 obj-$(CONFIG_PCI_EXYNOS) += pci-exynos.o
 obj-$(CONFIG_PCIE_FU740) += pcie-fu740.o
diff --git a/drivers/pci/controller/dwc/pcie-bt1.c b/drivers/pci/controller/dwc/pcie-bt1.c
new file mode 100644
index 000000000000..8cb6a9b3e39d
--- /dev/null
+++ b/drivers/pci/controller/dwc/pcie-bt1.c
@@ -0,0 +1,638 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2021 BAIKAL ELECTRONICS, JSC
+ *
+ * Authors:
+ *   Vadim Vlasov <Vadim.Vlasov@baikalelectronics.ru>
+ *   Serge Semin <Sergey.Semin@baikalelectronics.ru>
+ *
+ * Baikal-T1 PCIe controller driver
+ */
+
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+#include <linux/types.h>
+
+#include "pcie-designware.h"
+
+/* Baikal-T1 System CCU control registers */
+#define BT1_CCU_PCIE_CLKC			0x140
+#define BT1_CCU_PCIE_REQ_PCS_CLK		BIT(16)
+#define BT1_CCU_PCIE_REQ_MAC_CLK		BIT(17)
+#define BT1_CCU_PCIE_REQ_PIPE_CLK		BIT(18)
+
+#define BT1_CCU_PCIE_RSTC			0x144
+#define BT1_CCU_PCIE_REQ_LINK_RST		BIT(13)
+#define BT1_CCU_PCIE_REQ_SMLH_RST		BIT(14)
+#define BT1_CCU_PCIE_REQ_PHY_RST		BIT(16)
+#define BT1_CCU_PCIE_REQ_CORE_RST		BIT(24)
+#define BT1_CCU_PCIE_REQ_STICKY_RST		BIT(26)
+#define BT1_CCU_PCIE_REQ_NSTICKY_RST		BIT(27)
+
+#define BT1_CCU_PCIE_PMSC			0x148
+#define BT1_CCU_PCIE_LTSSM_STATE_MASK		GENMASK(5, 0)
+#define BT1_CCU_PCIE_LTSSM_DET_QUIET		0x00
+#define BT1_CCU_PCIE_LTSSM_DET_ACT		0x01
+#define BT1_CCU_PCIE_LTSSM_POLL_ACT		0x02
+#define BT1_CCU_PCIE_LTSSM_POLL_COMP		0x03
+#define BT1_CCU_PCIE_LTSSM_POLL_CONF		0x04
+#define BT1_CCU_PCIE_LTSSM_PRE_DET_QUIET	0x05
+#define BT1_CCU_PCIE_LTSSM_DET_WAIT		0x06
+#define BT1_CCU_PCIE_LTSSM_CFG_LNKWD_START	0x07
+#define BT1_CCU_PCIE_LTSSM_CFG_LNKWD_ACEPT	0x08
+#define BT1_CCU_PCIE_LTSSM_CFG_LNNUM_WAIT	0x09
+#define BT1_CCU_PCIE_LTSSM_CFG_LNNUM_ACEPT	0x0a
+#define BT1_CCU_PCIE_LTSSM_CFG_COMPLETE		0x0b
+#define BT1_CCU_PCIE_LTSSM_CFG_IDLE		0x0c
+#define BT1_CCU_PCIE_LTSSM_RCVR_LOCK		0x0d
+#define BT1_CCU_PCIE_LTSSM_RCVR_SPEED		0x0e
+#define BT1_CCU_PCIE_LTSSM_RCVR_RCVRCFG		0x0f
+#define BT1_CCU_PCIE_LTSSM_RCVR_IDLE		0x10
+#define BT1_CCU_PCIE_LTSSM_L0			0x11
+#define BT1_CCU_PCIE_LTSSM_L0S			0x12
+#define BT1_CCU_PCIE_LTSSM_L123_SEND_IDLE	0x13
+#define BT1_CCU_PCIE_LTSSM_L1_IDLE		0x14
+#define BT1_CCU_PCIE_LTSSM_L2_IDLE		0x15
+#define BT1_CCU_PCIE_LTSSM_L2_WAKE		0x16
+#define BT1_CCU_PCIE_LTSSM_DIS_ENTRY		0x17
+#define BT1_CCU_PCIE_LTSSM_DIS_IDLE		0x18
+#define BT1_CCU_PCIE_LTSSM_DISABLE		0x19
+#define BT1_CCU_PCIE_LTSSM_LPBK_ENTRY		0x1a
+#define BT1_CCU_PCIE_LTSSM_LPBK_ACTIVE		0x1b
+#define BT1_CCU_PCIE_LTSSM_LPBK_EXIT		0x1c
+#define BT1_CCU_PCIE_LTSSM_LPBK_EXIT_TOUT	0x1d
+#define BT1_CCU_PCIE_LTSSM_HOT_RST_ENTRY	0x1e
+#define BT1_CCU_PCIE_LTSSM_HOT_RST		0x1f
+#define BT1_CCU_PCIE_LTSSM_RCVR_EQ0		0x20
+#define BT1_CCU_PCIE_LTSSM_RCVR_EQ1		0x21
+#define BT1_CCU_PCIE_LTSSM_RCVR_EQ2		0x22
+#define BT1_CCU_PCIE_LTSSM_RCVR_EQ3		0x23
+#define BT1_CCU_PCIE_SMLH_LINKUP		BIT(6)
+#define BT1_CCU_PCIE_RDLH_LINKUP		BIT(7)
+#define BT1_CCU_PCIE_PM_LINKSTATE_L0S		BIT(8)
+#define BT1_CCU_PCIE_PM_LINKSTATE_L1		BIT(9)
+#define BT1_CCU_PCIE_PM_LINKSTATE_L2		BIT(10)
+#define BT1_CCU_PCIE_L1_PENDING			BIT(12)
+#define BT1_CCU_PCIE_REQ_EXIT_L1		BIT(14)
+#define BT1_CCU_PCIE_LTSSM_RCVR_EQ		BIT(15)
+#define BT1_CCU_PCIE_PM_DSTAT_MASK		GENMASK(18, 16)
+#define BT1_CCU_PCIE_PM_PME_EN			BIT(20)
+#define BT1_CCU_PCIE_PM_PME_STATUS		BIT(21)
+#define BT1_CCU_PCIE_AUX_PM_EN			BIT(22)
+#define BT1_CCU_PCIE_AUX_PWR_DET		BIT(23)
+#define BT1_CCU_PCIE_WAKE_DET			BIT(24)
+#define BT1_CCU_PCIE_TURNOFF_REQ		BIT(30)
+#define BT1_CCU_PCIE_TURNOFF_ACK		BIT(31)
+
+#define BT1_CCU_PCIE_GENC			0x14c
+#define BT1_CCU_PCIE_LTSSM_EN			BIT(1)
+#define BT1_CCU_PCIE_DBI2_MODE			BIT(2)
+#define BT1_CCU_PCIE_MGMT_EN			BIT(3)
+#define BT1_CCU_PCIE_RXLANE_FLIP_EN		BIT(16)
+#define BT1_CCU_PCIE_TXLANE_FLIP_EN		BIT(17)
+#define BT1_CCU_PCIE_SLV_XFER_PEND		BIT(24)
+#define BT1_CCU_PCIE_RCV_XFER_PEND		BIT(25)
+#define BT1_CCU_PCIE_DBI_XFER_PEND		BIT(26)
+#define BT1_CCU_PCIE_DMA_XFER_PEND		BIT(27)
+
+#define BT1_CCU_PCIE_LTSSM_LINKUP(_pmsc) \
+({ \
+	int __state = FIELD_GET(BT1_CCU_PCIE_LTSSM_STATE_MASK, _pmsc); \
+	__state >= BT1_CCU_PCIE_LTSSM_L0 && __state <= BT1_CCU_PCIE_LTSSM_L2_WAKE; \
+})
+
+/* Baikal-T1 PCIe specific control registers */
+#define BT1_PCIE_AXI2MGM_LANENUM		0xd04
+#define BT1_PCIE_AXI2MGM_LANESEL_MASK		GENMASK(3, 0)
+
+#define BT1_PCIE_AXI2MGM_ADDRCTL		0xd08
+#define BT1_PCIE_AXI2MGM_PHYREG_ADDR_MASK	GENMASK(20, 0)
+#define BT1_PCIE_AXI2MGM_READ_FLAG		BIT(29)
+#define BT1_PCIE_AXI2MGM_DONE			BIT(30)
+#define BT1_PCIE_AXI2MGM_BUSY			BIT(31)
+
+#define BT1_PCIE_AXI2MGM_WRITEDATA		0xd0c
+#define BT1_PCIE_AXI2MGM_WDATA			GENMASK(15, 0)
+
+#define BT1_PCIE_AXI2MGM_READDATA		0xd10
+#define BT1_PCIE_AXI2MGM_RDATA			GENMASK(15, 0)
+
+/* General Baikal-T1 PCIe interface resources */
+#define BT1_PCIE_NUM_CLKS			ARRAY_SIZE(bt1_pcie_clks)
+#define BT1_PCIE_NUM_APP_RSTS			ARRAY_SIZE(bt1_pcie_app_rsts)
+#define BT1_PCIE_NUM_CORE_RSTS			ARRAY_SIZE(bt1_pcie_core_rsts)
+
+enum bt1_pcie_core_rst {
+	BT1_PCIE_NON_STICKY_RST,
+	BT1_PCIE_STICKY_RST,
+	BT1_PCIE_CORE_RST,
+	BT1_PCIE_PIPE_RST,
+	BT1_PCIE_PHY_RST,
+	BT1_PCIE_HOT_RST,
+	BT1_PCIE_PWR_RST,
+};
+
+static const enum dw_pcie_clk bt1_pcie_clks[] = {
+	DW_PCIE_DBI_CLK, DW_PCIE_MSTR_CLK, DW_PCIE_SLV_CLK, DW_PCIE_REF_CLK
+};
+
+static const enum dw_pcie_app_rst bt1_pcie_app_rsts[] = {
+	DW_PCIE_MSTR_RST, DW_PCIE_SLV_RST
+};
+
+static const enum dw_pcie_core_rst bt1_pcie_core_rsts[] = {
+	[BT1_PCIE_NON_STICKY_RST] = DW_PCIE_NON_STICKY_RST,
+	[BT1_PCIE_STICKY_RST] = DW_PCIE_STICKY_RST,
+	[BT1_PCIE_CORE_RST] = DW_PCIE_CORE_RST,
+	[BT1_PCIE_PIPE_RST] = DW_PCIE_PIPE_RST,
+	[BT1_PCIE_PHY_RST] = DW_PCIE_PHY_RST,
+	[BT1_PCIE_HOT_RST] = DW_PCIE_HOT_RST,
+	[BT1_PCIE_PWR_RST] = DW_PCIE_PWR_RST,
+};
+
+struct bt1_pcie {
+	struct dw_pcie dw;
+	struct platform_device *pdev;
+	struct regmap *sys_regs;
+
+	struct clk_bulk_data clks[BT1_PCIE_NUM_CLKS];
+	struct reset_control_bulk_data app_rsts[BT1_PCIE_NUM_APP_RSTS];
+	struct reset_control_bulk_data core_rsts[BT1_PCIE_NUM_CORE_RSTS];
+	struct gpio_desc *pe_rst;
+};
+#define to_bt1_pcie(_dw) container_of(_dw, struct bt1_pcie, dw)
+
+/*
+ * Baikal-T1 MMIO space must be read/written by the dword-aligned
+ * instructions. Note the methods are optimized to have the dword operations
+ * performed with minimum overhead as the most frequently used ones.
+ */
+static int bt1_pcie_read_mmio(void __iomem *addr, int size, u32 *val)
+{
+	unsigned int ofs = (uintptr_t)addr & 0x3;
+
+	if (!IS_ALIGNED((uintptr_t)addr, size))
+		return PCIBIOS_BAD_REGISTER_NUMBER;
+
+	*val = readl(addr - ofs) >> ofs * BITS_PER_BYTE;
+	if (size == 4) {
+		return PCIBIOS_SUCCESSFUL;
+	} else if (size == 2) {
+		*val &= 0xffff;
+		return PCIBIOS_SUCCESSFUL;
+	} else if (size == 1) {
+		*val &= 0xff;
+		return PCIBIOS_SUCCESSFUL;
+	}
+
+	return PCIBIOS_BAD_REGISTER_NUMBER;
+}
+
+static int bt1_pcie_write_mmio(void __iomem *addr, int size, u32 val)
+{
+	unsigned int ofs = (uintptr_t)addr & 0x3;
+	u32 tmp, mask;
+
+	if (!IS_ALIGNED((uintptr_t)addr, size))
+		return PCIBIOS_BAD_REGISTER_NUMBER;
+
+	if (size == 4) {
+		writel(val, addr);
+		return PCIBIOS_SUCCESSFUL;
+	} else if (size == 2 || size == 1) {
+		mask = GENMASK(size * BITS_PER_BYTE - 1, 0);
+		tmp = readl(addr - ofs) & ~(mask << ofs * BITS_PER_BYTE);
+		tmp |= (val & mask) << ofs * BITS_PER_BYTE;
+		writel(tmp, addr - ofs);
+		return PCIBIOS_SUCCESSFUL;
+	}
+
+	return PCIBIOS_BAD_REGISTER_NUMBER;
+}
+
+static u32 bt1_pcie_read_dbi(struct dw_pcie *pci, void __iomem *base, u32 reg,
+			     size_t size)
+{
+	int ret;
+	u32 val;
+
+	ret = bt1_pcie_read_mmio(base + reg, size, &val);
+	if (ret != PCIBIOS_SUCCESSFUL) {
+		dev_err(pci->dev, "Read DBI address failed\n");
+		return ~0U;
+	}
+
+	return val;
+}
+
+static void bt1_pcie_write_dbi(struct dw_pcie *pci, void __iomem *base, u32 reg,
+			       size_t size, u32 val)
+{
+	int ret;
+
+	ret = bt1_pcie_write_mmio(base + reg, size, val);
+	if (ret != PCIBIOS_SUCCESSFUL)
+		dev_err(pci->dev, "Write DBI address failed\n");
+}
+
+static void bt1_pcie_write_dbi2(struct dw_pcie *pci, void __iomem *base, u32 reg,
+				size_t size, u32 val)
+{
+	struct bt1_pcie *btpci = to_bt1_pcie(pci);
+	int ret;
+
+	regmap_update_bits(btpci->sys_regs, BT1_CCU_PCIE_GENC,
+			   BT1_CCU_PCIE_DBI2_MODE, BT1_CCU_PCIE_DBI2_MODE);
+
+	ret = bt1_pcie_write_mmio(base + reg, size, val);
+	if (ret != PCIBIOS_SUCCESSFUL)
+		dev_err(pci->dev, "Write DBI2 address failed\n");
+
+	regmap_update_bits(btpci->sys_regs, BT1_CCU_PCIE_GENC,
+			   BT1_CCU_PCIE_DBI2_MODE, 0);
+}
+
+static int bt1_pcie_start_ltssm(struct dw_pcie *pci)
+{
+	struct bt1_pcie *btpci = to_bt1_pcie(pci);
+	u32 val;
+	int ret;
+
+	/*
+	 * Enable LTSSM and make sure it was able to establish both PHY and
+	 * data links. This procedure shall work fine to reach 2.5 GT/s speed.
+	 */
+	regmap_update_bits(btpci->sys_regs, BT1_CCU_PCIE_GENC,
+			   BT1_CCU_PCIE_LTSSM_EN, BT1_CCU_PCIE_LTSSM_EN);
+
+	ret = regmap_read_poll_timeout(btpci->sys_regs, BT1_CCU_PCIE_PMSC, val,
+				       (val & BT1_CCU_PCIE_SMLH_LINKUP),
+				       1000, 1000000);
+	if (ret) {
+		dev_err(pci->dev, "LTSSM failed to set PHY link up\n");
+		return ret;
+	}
+
+	ret = regmap_read_poll_timeout(btpci->sys_regs, BT1_CCU_PCIE_PMSC, val,
+				       (val & BT1_CCU_PCIE_RDLH_LINKUP),
+				       1000, 1000000);
+	if (ret) {
+		dev_err(pci->dev, "LTSSM failed to set data link up\n");
+		return ret;
+	}
+
+	/*
+	 * Activate direct speed change after the link is established in an
+	 * attempt to reach a higher bus performance (up to Gen.3 - 8.0 GT/s).
+	 * This is required at least to get 8.0 GT/s speed.
+	 */
+	val = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL);
+	val |= PORT_LOGIC_SPEED_CHANGE;
+	dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, val);
+
+	ret = regmap_read_poll_timeout(btpci->sys_regs, BT1_CCU_PCIE_PMSC, val,
+				       BT1_CCU_PCIE_LTSSM_LINKUP(val),
+				       1000, 1000000);
+	if (ret)
+		dev_err(pci->dev, "LTSSM failed to get into L0 state\n");
+
+	return ret;
+}
+
+static void bt1_pcie_stop_ltssm(struct dw_pcie *pci)
+{
+	struct bt1_pcie *btpci = to_bt1_pcie(pci);
+
+	regmap_update_bits(btpci->sys_regs, BT1_CCU_PCIE_GENC,
+			   BT1_CCU_PCIE_LTSSM_EN, 0);
+}
+
+struct dw_pcie_ops bt1_pcie_dw_ops = {
+	.read_dbi = bt1_pcie_read_dbi,
+	.write_dbi = bt1_pcie_write_dbi,
+	.write_dbi2 = bt1_pcie_write_dbi2,
+	.start_link = bt1_pcie_start_ltssm,
+	.stop_link = bt1_pcie_stop_ltssm,
+};
+
+static int bt1_pcie_get_res(struct bt1_pcie *btpci)
+{
+	struct device *dev = btpci->dw.dev;
+	int ret;
+
+	/* AXI-interface is configured with 64-bit address bus width */
+	ret = dma_coerce_mask_and_coherent(&btpci->dw.pp.bridge->dev,
+					   DMA_BIT_MASK(64));
+	if (ret) {
+		ret = dma_set_mask_and_coherent(&btpci->dw.pp.bridge->dev,
+						DMA_BIT_MASK(32));
+		if (ret)
+			return ret;
+	}
+
+	/* These CSRs are in MMIO so we won't check the regmap-methods status */
+	btpci->sys_regs = syscon_regmap_lookup_by_phandle(dev->of_node, "syscon");
+	if (IS_ERR(btpci->sys_regs))
+		return dev_err_probe(dev, PTR_ERR(btpci->sys_regs),
+				     "Failed to get syscon\n");
+
+	ret = devm_clk_bulk_get(dev, BT1_PCIE_NUM_CLKS, btpci->clks);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to get clocks\n");
+
+	ret = devm_reset_control_bulk_get_exclusive(dev, BT1_PCIE_NUM_APP_RSTS,
+						    btpci->app_rsts);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to get app resets\n");
+
+	ret = devm_reset_control_bulk_get_exclusive(dev, BT1_PCIE_NUM_CORE_RSTS,
+						    btpci->core_rsts);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to get core resets\n");
+
+	btpci->pe_rst = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
+	if (IS_ERR(btpci->pe_rst))
+		return dev_err_probe(dev, PTR_ERR(btpci->pe_rst),
+				     "Failed to get PERST#\n");
+
+	return 0;
+}
+
+static void bt1_pcie_full_stop_bus(struct bt1_pcie *btpci, bool init)
+{
+	struct device *dev = btpci->dw.dev;
+	int ret;
+
+	/* Disable LTSSM for sure */
+	regmap_update_bits(btpci->sys_regs, BT1_CCU_PCIE_GENC,
+			   BT1_CCU_PCIE_LTSSM_EN, 0);
+
+	/*
+	 * Application reset controls are trigger-based so de-assert the core
+	 * resets only.
+	 */
+	ret = reset_control_bulk_assert(BT1_PCIE_NUM_CORE_RSTS, btpci->core_rsts);
+	if (ret)
+		dev_err(dev, "Failed to assert core resets\n");
+
+	/*
+	 * Clocks are disabled by default at least in accordance with the clk
+	 * enable counter value on init stage.
+	 */
+	if (!init)
+		clk_bulk_disable_unprepare(BT1_PCIE_NUM_CLKS, btpci->clks);
+
+	/* The peripheral devices are unavailable anyway so reset them too */
+	gpiod_set_value_cansleep(btpci->pe_rst, 1);
+
+	/* Make sure the reset is settled */
+	usleep_range(1, 10);
+}
+
+/*
+ * Implements the cold reset procedure in accordance with the reference manual
+ * and available PM signals.
+ */
+static int bt1_pcie_cold_start_bus(struct bt1_pcie *btpci)
+{
+	struct device *dev = btpci->dw.dev;
+	u32 val;
+	int ret;
+
+	/* First get out of the Power/Hot reset state */
+	ret = reset_control_deassert(btpci->core_rsts[BT1_PCIE_PWR_RST].rstc);
+	if (ret) {
+		dev_err(dev, "Failed to deassert PHY reset\n");
+		return ret;
+	}
+
+	ret = reset_control_deassert(btpci->core_rsts[BT1_PCIE_HOT_RST].rstc);
+	if (ret) {
+		dev_err(dev, "Failed to deassert hot reset\n");
+		goto err_assert_pwr_rst;
+	}
+
+	/* Wait for the PM-core to stop requesting the PHY reset */
+	ret = regmap_read_poll_timeout(btpci->sys_regs, BT1_CCU_PCIE_RSTC, val,
+				       !(val & BT1_CCU_PCIE_REQ_PHY_RST), 1, 1000);
+	if (ret) {
+		dev_err(dev, "Timed out waiting for PM to stop PHY resetting\n");
+		goto err_assert_hot_rst;
+	}
+
+	ret = reset_control_deassert(btpci->core_rsts[BT1_PCIE_PHY_RST].rstc);
+	if (ret) {
+		dev_err(dev, "Failed to deassert PHY reset\n");
+		goto err_assert_hot_rst;
+	}
+
+	/* Clocks can be now enabled, but the ref one is crucial at this stage */
+	ret = clk_bulk_prepare_enable(BT1_PCIE_NUM_CLKS, btpci->clks);
+	if (ret) {
+		dev_err(dev, "Failed to enable ref clocks\n");
+		goto err_assert_phy_rst;
+	}
+
+	/* Wait for the PM to stop requesting the controller core reset */
+	ret = regmap_read_poll_timeout(btpci->sys_regs, BT1_CCU_PCIE_RSTC, val,
+				       !(val & BT1_CCU_PCIE_REQ_CORE_RST), 1, 1000);
+	if (ret) {
+		dev_err(dev, "Timed out waiting for PM to stop core resetting\n");
+		goto err_clk_disable;
+	}
+
+	/* PCS-PIPE interface and controller core can be now activated */
+	ret = reset_control_deassert(btpci->core_rsts[BT1_PCIE_PIPE_RST].rstc);
+	if (ret) {
+		dev_err(dev, "Failed to deassert PIPE reset\n");
+		goto err_clk_disable;
+	}
+
+	ret = reset_control_deassert(btpci->core_rsts[BT1_PCIE_CORE_RST].rstc);
+	if (ret) {
+		dev_err(dev, "Failed to deassert core reset\n");
+		goto err_assert_pipe_rst;
+	}
+
+	/* It's recommended to reset the core and application logic together */
+	ret = reset_control_bulk_reset(BT1_PCIE_NUM_APP_RSTS, btpci->app_rsts);
+	if (ret) {
+		dev_err(dev, "Failed to reset app domain\n");
+		goto err_assert_core_rst;
+	}
+
+	/* Sticky/Non-sticky CSR flags can be now unreset too */
+	ret = reset_control_deassert(btpci->core_rsts[BT1_PCIE_STICKY_RST].rstc);
+	if (ret) {
+		dev_err(dev, "Failed to deassert sticky reset\n");
+		goto err_assert_core_rst;
+	}
+
+	ret = reset_control_deassert(btpci->core_rsts[BT1_PCIE_NON_STICKY_RST].rstc);
+	if (ret) {
+		dev_err(dev, "Failed to deassert non-sticky reset\n");
+		goto err_assert_sticky_rst;
+	}
+
+	/* Activate the PCIe bus peripheral devices */
+	gpiod_set_value_cansleep(btpci->pe_rst, 0);
+
+	/* Make sure the state is settled (LTSSM is still disabled though) */
+	usleep_range(1, 10);
+
+	return 0;
+
+err_assert_sticky_rst:
+	reset_control_assert(btpci->core_rsts[BT1_PCIE_STICKY_RST].rstc);
+
+err_assert_core_rst:
+	reset_control_assert(btpci->core_rsts[BT1_PCIE_CORE_RST].rstc);
+
+err_assert_pipe_rst:
+	reset_control_assert(btpci->core_rsts[BT1_PCIE_PIPE_RST].rstc);
+
+err_clk_disable:
+	clk_bulk_disable_unprepare(BT1_PCIE_NUM_CLKS, btpci->clks);
+
+err_assert_phy_rst:
+	reset_control_assert(btpci->core_rsts[BT1_PCIE_PHY_RST].rstc);
+
+err_assert_hot_rst:
+	reset_control_assert(btpci->core_rsts[BT1_PCIE_HOT_RST].rstc);
+
+err_assert_pwr_rst:
+	reset_control_assert(btpci->core_rsts[BT1_PCIE_PWR_RST].rstc);
+
+	return ret;
+}
+
+static int bt1_pcie_host_init(struct pcie_port *pp)
+{
+	struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+	struct bt1_pcie *btpci = to_bt1_pcie(pci);
+	int ret;
+
+	ret = bt1_pcie_get_res(btpci);
+	if (ret)
+		return ret;
+
+	bt1_pcie_full_stop_bus(btpci, true);
+
+	return bt1_pcie_cold_start_bus(btpci);
+}
+
+static void bt1_pcie_host_deinit(struct pcie_port *pp)
+{
+	struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+	struct bt1_pcie *btpci = to_bt1_pcie(pci);
+
+	bt1_pcie_full_stop_bus(btpci, false);
+}
+
+struct dw_pcie_host_ops bt1_pcie_host_ops = {
+	.host_init = bt1_pcie_host_init,
+	.host_deinit = bt1_pcie_host_deinit,
+};
+
+static struct bt1_pcie *bt1_pcie_create_data(struct platform_device *pdev)
+{
+	struct bt1_pcie *btpci;
+	int i;
+
+	btpci = devm_kzalloc(&pdev->dev, sizeof(*btpci), GFP_KERNEL);
+	if (!btpci)
+		return ERR_PTR(-ENOMEM);
+
+	btpci->pdev = pdev;
+
+	for (i = 0; i < BT1_PCIE_NUM_CLKS; ++i)
+		btpci->clks[i].id = dw_pcie_clk_name(bt1_pcie_clks[i]);
+
+	for (i = 0; i < BT1_PCIE_NUM_APP_RSTS; ++i)
+		btpci->app_rsts[i].id = dw_pcie_app_rst_name(bt1_pcie_app_rsts[i]);
+
+	for (i = 0; i < BT1_PCIE_NUM_CORE_RSTS; ++i)
+		btpci->core_rsts[i].id = dw_pcie_core_rst_name(bt1_pcie_core_rsts[i]);
+
+	platform_set_drvdata(pdev, btpci);
+
+	return btpci;
+}
+
+static int bt1_pcie_add_dw_port(struct bt1_pcie *btpci)
+{
+	struct device *dev = &btpci->pdev->dev;
+	int ret;
+
+	ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64));
+	if (ret)
+		return ret;
+
+	btpci->dw.version = DW_PCIE_VER_460A;
+	btpci->dw.dev = dev;
+	btpci->dw.ops = &bt1_pcie_dw_ops;
+
+	btpci->dw.pp.num_vectors = MAX_MSI_IRQS;
+	btpci->dw.pp.ops = &bt1_pcie_host_ops;
+
+	ret = dw_pcie_host_init(&btpci->dw.pp);
+	if (ret)
+		dev_err_probe(dev, ret, "Failed to initialize DWC PCIe host\n");
+
+	return ret;
+}
+
+static void bt1_pcie_del_dw_port(struct bt1_pcie *btpci)
+{
+	dw_pcie_host_deinit(&btpci->dw.pp);
+}
+
+static int bt1_pcie_probe(struct platform_device *pdev)
+{
+	struct bt1_pcie *btpci;
+
+	btpci = bt1_pcie_create_data(pdev);
+	if (IS_ERR(btpci))
+		return PTR_ERR(btpci);
+
+	return bt1_pcie_add_dw_port(btpci);
+}
+
+static int bt1_pcie_remove(struct platform_device *pdev)
+{
+	struct bt1_pcie *btpci = platform_get_drvdata(pdev);
+
+	bt1_pcie_del_dw_port(btpci);
+
+	return 0;
+}
+
+static const struct of_device_id bt1_pcie_of_match[] = {
+	{ .compatible = "baikal,bt1-pcie" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, bt1_pcie_of_match);
+
+static struct platform_driver bt1_pcie_driver = {
+	.probe = bt1_pcie_probe,
+	.remove = bt1_pcie_remove,
+	.driver = {
+		.name	= "bt1-pcie",
+		.of_match_table = bt1_pcie_of_match,
+	},
+};
+module_platform_driver(bt1_pcie_driver);
+
+MODULE_AUTHOR("Serge Semin <Sergey.Semin@baikalelectronics.ru>");
+MODULE_DESCRIPTION("Baikal-T1 PCIe driver");
+MODULE_LICENSE("GPL v2");
-- 
2.35.1


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* Re: [PATCH 01/16] dt-bindings: PCI: dwc: Define generic and native DT bindings
  2022-03-24  1:37   ` Serge Semin
  (?)
@ 2022-03-28 20:46     ` Rob Herring
  -1 siblings, 0 replies; 40+ messages in thread
From: Rob Herring @ 2022-03-28 20:46 UTC (permalink / raw)
  To: Serge Semin
  Cc: Jingoo Han, Gustavo Pimentel, Bjorn Helgaas, Richard Zhu,
	Lucas Stach, Shawn Guo, Sascha Hauer, Pengutronix Kernel Team,
	Fabio Estevam, NXP Linux Team, Xiaowei Song, Binghui Wang,
	Paul Walmsley, Greentime Hu, Palmer Dabbelt, Nobuhiro Iwamatsu,
	Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Lorenzo Pieralisi, Krzysztof Wilczyński, Frank Li,
	Manivannan Sadhasivam, linux-pci, devicetree, linux-kernel,
	linux-arm-kernel, linux-riscv

On Thu, Mar 24, 2022 at 04:37:19AM +0300, Serge Semin wrote:
> Currently both DW PCIe Root Port and End-point DT bindings are too generic
> to be used as a descriptive set the device properties. Yes, it's very handy
> to have them that way so the DT-schemas could be used to evaluate as many
> DW PCIe-related DT-nodes as possible. But at the same time they don't
> provide well defined DW PCIe RP/EP DT interface description thus leaving
> too much flexibility for the new platforms, no encouraging the developers
> to preserve a compatible interface.
> 
> Instead of currently implemented approach we suggest to be more
> restrictive and yet preserve some level of flexibility in the DW PCIe
> DT-bindings description. The device tree DT-schema is split up into
> three parts: a common YAML-schema applicable for both DWC Root Port and
> End-point controller configs, DWC PCIe Root Port-specific YAML-schema
> and DWC PCIe End-point-specific YAML-schema, where
> 1) pci/snps,dw-pcie-common.yaml - The common DT-schema describes the most
> generic constraints of the "reg", "interrupts", "clocks", "resets" and
> "phys" properties together with a set of common for both device types
> PCIe/AXI bus properties like a maximum number of lanes or a maximum link
> speed, number of inbound and outbound iATU windows. In addition to that a
> set of schema definitions declared under the "$defs" property with "reg",
> "interrupt", "clock" and "reset" names common for DWC PCIe Root Port and
> End-point devices. They can be used by the successive DT-schemas in case
> they are supposed to be compatible with the generic DWC PCIe controller
> DT-bindings.
> 2) pci/snps,dw-pcie.yaml, pci/snps,dw-pcie-ep.yaml - generic DW PCIe Root
> Port and End-point DT-bindings which aside with the device-specific
> properties set also contain more restrictive constraints. All new DW PCIe
> platforms are supposed to be compatible with one of these bindings by
> using "allOf: " property and additionally defining their own constraints
> to close up the DT-bindings set.
> 
> So to speak in case if a DW PCIe-based device for some reason has too many
> specific properties or it's bindings have already been defined in a
> non-generic way, it's DT-schema is supposed to include 1) YAML-file and
> provide its own constraints. Otherwise the ready-to-use bindings from 2)
> should be utilized. There only two DT-schemas compatible with 2) at the
> moment are samsung,axynos-pcie.yaml and intel-gw-pcie.yaml. The
> rest of the DW PCIe-related DT-schemas are supposed to use more generic
> DW PCIe DT-bindings - pci/snps,dw-pcie-common.yaml.
> 
> Note the provided here generic properties and their possible values are
> derived from the DW PCIe RC/EP hardware manuals and from the interface
> implemented in the driver. The DT-bindings schemas are created to be as
> full as possible with detailed properties/names description for the
> easier interface comprehension and new platforms bindings development.
> 
> Also note since there are no generic DT-nodes can be found in the kernel
> dts-es which would have a pure "snps,dw-pcie" compatible string, these
> DT-bindings have been created to not be selected by default for
> evaluation. They are supposed to be used by the new vendor-specific
> DT-schemas to at least stop adding new bindings for the same set of DWC
> PCIe signals or properties.
> 
> Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> 
> ---
> 
> Rob, if you comment the "select: false" line out you'll get a lot of "'*'
> is not of type 'array'" errors on the dt_bindings_check command execution.
> I have spend tons of time trying to figure out what was wrong, but still
> failed to find out a solution. For some reason the "$ref"-ed schemas
> defined under the "$defs" basic property are considered by the parser as
> defining an array. No matter whether I specified the "type: string"
> keyword or not, as long as there is "enum" or "oneOf" keyword used in the
> "*-names" property definition in "$defs" it's considered as describing an
> array thus causing the errors like:

As-is, there were lots of errors...

> 
> >  DTC     Documentation/devicetree/bindings/pci/snps,dw-pcie.example.dt.yaml
> >  CHECK   Documentation/devicetree/bindings/pci/snps,dw-pcie.example.dt.yaml
> > /.../snps,dw-pcie.example.dt.yaml: pcie@1f052000: reg-names:0: 'oneOf' conditional failed, one must be fixed:
> >        'dbi' is not of type 'array'
> >        From schema: /.../snps,dw-pcie.yaml
> > /.../snps,dw-pcie.example.dt.yaml: pcie@1f052000: reg-names:1: 'oneOf' conditional failed, one must be fixed:
> >         'config' is not of type 'array'
> >         From schema: /.../snps,dw-pcie.yaml
> > /.../snps,dw-pcie.example.dt.yaml: pcie@1f052000: interrupt-names:0: 'anyOf' conditional failed, one must be fixed:
> >         /.../snps,dw-pcie.example.dt.yaml: pcie@1f052000: interrupt-names:0: 'oneOf' conditional failed, one must be fixed:
> >                 'msi' is not of type 'array'
> >         /../snps,dw-pcie.example.dt.yaml: pcie@1f052000: interrupt-names:0: 'oneOf' conditional failed, one must be fixed:
> >                 'msi' is not of type 'array'
> >         From schema: /.../snps,dw-pcie.yaml
> 
> As soon as I manually moved the same "$defs"-schemas into the places they
> are referenced to, the errors disappeared and the DT-schemas validation
> worked as expected by the semantics.
> 
> As I see it there must be some bug in the parser, otherwise I am out of
> ideas how to implement the suggested in this patch design pattern. Rob,
> could you take a look at the DT-schemas and help me out with debugging the
> problem described above?

There is at least an error in your schema, details latter on.

It could be an issue in the fixups which in general convert 
schemas for strings to string arrays and scalars/arrays to matrix. You 
have to look at processed-schema.json to debug it.

The other thing is 'oneOf' errors can be confusing in terms of error 
messages because the tooling doesn't really know which entry had the 
least error. Like the type was right, but some secondary constraint 
failed (as what's secondary is not expressed in any way).

I would debug it further, but I don't really like the end result. I 
think it's too hard to follow. For the most part, we avoid $refs at the 
property level across different schema files with the big exception 
being types.yaml. $defs are also used sparingly. The challenge is that 
json-schema by default will be silent on schemas misformed in lots of 
ways. Our meta-schema adds a lot of constraints which limits what the 
schemas can look like and ensures schemas are valid. It also allows me 
to define new constraints rather than repeat the same review comment 
over and over.

> ---
>  .../bindings/pci/fsl,imx6q-pcie.yaml          |   5 +-
>  .../bindings/pci/hisilicon,kirin-pcie.yaml    |   4 +-
>  .../bindings/pci/sifive,fu740-pcie.yaml       |   4 +-
>  .../bindings/pci/snps,dw-pcie-common.yaml     | 298 ++++++++++++++++++
>  .../bindings/pci/snps,dw-pcie-ep.yaml         | 143 ++++++---
>  .../devicetree/bindings/pci/snps,dw-pcie.yaml | 189 +++++++----
>  .../bindings/pci/toshiba,visconti-pcie.yaml   |   2 +-
>  7 files changed, 524 insertions(+), 121 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/pci/snps,dw-pcie-common.yaml


> diff --git a/Documentation/devicetree/bindings/pci/snps,dw-pcie-common.yaml b/Documentation/devicetree/bindings/pci/snps,dw-pcie-common.yaml
> new file mode 100644
> index 000000000000..27fe1f5c450f
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/pci/snps,dw-pcie-common.yaml
> @@ -0,0 +1,298 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/pci/snps,dw-pcie-common.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Synopsys DWC PCIe RP/EP controller
> +
> +maintainers:
> +  - Jingoo Han <jingoohan1@gmail.com>
> +  - Gustavo Pimentel <gustavo.pimentel@synopsys.com>
> +
> +properties:
> +  reg:
> +    description:
> +      DWC PCIe CSR space is normally accessed over the dedicated Data Bus
> +      Interface - DBI. In accordance with the reference manual the register
> +      configuration space belongs to the Configuration-Dependent Module (CDM)
> +      and is split up into several sub-parts Standard PCIe configuration
> +      space, Port Logic Registers (PL), Shadow Config-space Registers,
> +      iATU/eDMA registers. The particular sub-space is selected by the
> +      CDM/ELBI (dbi_cs) and CS2 (dbi_cs2) signals (selector bits). Such
> +      configuration provides a flexible interface for the system engineers to
> +      either map the particular space at a desired MMIO address or just leave
> +      them in a contiguous memory space if pure Native or AXI Bridge DBI access
> +      is selected. Note the PCIe CFG-space, PL and Shadow registers are
> +      specific to each activated function, while the rest of the sub-spaces
> +      are common for all of them (if there are more than one).
> +    minItems: 2
> +    maxItems: 6
> +
> +  interrupts:
> +    description:
> +      There are two main sub-blocks which are normally capable of
> +      generating interrupts. It's System Information Interface and MSI
> +      interface. While the former one has some common for the Host and
> +      End-point controllers IRQ-signals, the later interface is obviously
> +      Root Complex specific since it's responsible for the incoming MSI
> +      messages signalling. The System Information IRQ signals are mainly
> +      responsible for reporting the generic PCIe hierarchy and Root
> +      Complex events like VPD IO request, general AER, PME, Hot-plug, link
> +      bandwidth change, link equalization request, INTx asserted/deasserted
> +      Message detection, embedded DMA Tx/Rx/Error.
> +    minItems: 1
> +    maxItems: 26
> +
> +  clocks:
> +    description:
> +      DWC PCIe reference manual explicitly defines a set of the clocks required
> +      to get the controller working correctly. In general all of them can
> +      be divided into two groups':' application and core clocks. Note the
> +      platforms may have some of the clock sources unspecified in case if the
> +      corresponding domains are fed up from a common clock source.
> +    minItems: 1
> +    maxItems: 7
> +
> +  resets:
> +    description:
> +      DWC PCIe reference manual explicitly defines a set of the reset
> +      signals required to be de-asserted to properly activate the controller
> +      sub-parts. All of these signals can be divided into two sub-groups':'
> +      application and core resets with respect to the main sub-domains they
> +      are supposed to reset. Note the platforms may have some of these signals
> +      unspecified in case if they are automatically handled or aggregated into
> +      a comprehensive control module.
> +    minItems: 1
> +    maxItems: 10
> +
> +  reset-gpio:
> +    deprecated: true
> +    description:
> +      Reference to the GPIO-controlled PERST# signal. It is used to reset all
> +      the peripheral devices available on the PCIe bus.
> +    maxItems: 1
> +
> +  reset-gpios:
> +    description:
> +      Reference to the GPIO-controlled PERST# signal. It is used to reset all
> +      the peripheral devices available on the PCIe bus.
> +    maxItems: 1
> +
> +  phys:
> +    description:
> +      There can be up to number of possible lanes PHYs specified.
> +      Obviously each specified PHY is supposed to be able to work in the
> +      PCIe mode with a speed implied by the DWC PCIe controller it is
> +      attached to.
> +    minItems: 1
> +    maxItems: 16
> +
> +  phy-names:
> +    minItems: 1
> +    maxItems: 16
> +    items:
> +      pattern: '^pcie([0-9]+|-?phy)?$'
> +
> +  num-lanes:
> +    maximum: 16
> +
> +  max-link-speed:
> +    maximum: 4
> +
> +  num-ob-windows:
> +    $ref: /schemas/types.yaml#/definitions/uint32
> +    deprecated: true
> +    description:
> +      Number of outbound address translation windows. This parameter can be
> +      auto-detected based on the iATU memory writability. So there is no
> +      point in having a dedicated DT-property for it.
> +    maximum: 256
> +
> +  num-ib-windows:
> +    $ref: /schemas/types.yaml#/definitions/uint32
> +    deprecated: true
> +    description:
> +      Number of inbound address translation windows. In the same way as
> +      for the outbound AT windows, this parameter can be auto-detected based
> +      on the iATU memory writability. There is no point having a dedicated
> +      DT-property for it either.
> +    maximum: 256
> +
> +  num-viewport:
> +    $ref: /schemas/types.yaml#/definitions/uint32
> +    deprecated: true
> +    description:
> +      Number of outbound view ports configured in hardware. It's the same as
> +      the number of outbound AT windows.
> +    maximum: 256
> +
> +  snps,enable-cdm-check:
> +    $ref: /schemas/types.yaml#/definitions/flag
> +    description:
> +      Enable automatic checking of CDM (Configuration Dependent Module)
> +      registers for data corruption. CDM registers include standard PCIe
> +      configuration space registers, Port Logic registers, DMA and iATU
> +      registers. This feature has been available since DWC PCIe v4.80a.
> +
> +additionalProperties: true
> +
> +$defs:
> +  reg-names:
> +    description:
> +      CSR space names common for the DWC PCIe Root Port and End-point
> +      controllers.
> +    oneOf:
> +      - description:
> +          Basic DWC PCIe controller configuration-space accessible over
> +          the DBI interface. This memory space is either activated with
> +          the CDM/ELBI = 0 and CS2 = 0 or is a contiguous memory region
> +          with all spaces. Note iATU/eDMA CSRs are indirectly accessible
> +          via the PL viewports on the DWC PCIe controllers older than
> +          v4.80a.
> +        const: dbi

This passes only for 'reg-names = "dbi";'

> +      - description:
> +          Shadow DWC PCIe config-space registers. This space is selected
> +          by setting CDM/ELBI = 0 and CS2 = 1. This is an intermix of
> +          the PCI-SIG PCIe CFG-space with the shadow registers for some
> +          PCI Header space, PCI Standard and Extended Structures. It's
> +          mainly relevant for the end-point controller configuration,
> +          but still there are some shadow registers available for the
> +          Root Port mode too.
> +        const: dbi2

This passes only for 'reg-names = "dbi2";'

> +      - description:
> +          External Local Bus registers. It's an application-dependent
> +          registers normally defined by the platform engineers, which
> +          are selected by setting CDM/ELBI = 1 and CS2 = 0.
> +        enum: [ elbi, appl, app ]

This passes only for 'reg-names = "elbi", "appl", "app";'

See the problem? Replacing the 'oneOf' above with 'items' is what you 
want. But then the schema will not allow any missing entries either. 
DBI2 is optional for example. There is no way in json-schema to define a 
list of ordered values(string) once and say some entries are optional 
which I think is what you are trying to do here.

> +      - description:
> +          iATU/eDMA registers common for all device functions. It's an
> +          unrolled memory space with the internal Address Translation
> +          Unit and Enhanced DMA, which is selected by setting CDM/ELBI = 1
> +          and CS2 = 1. For IP-core releases prior v4.80a, these registers
> +          have been programmed via an indirect addressing scheme using a
> +          set of viewport CSRs mapped into the PL space. Note iATU is
> +          normally mapped to the 0x0 address of this region, while eDMA
> +          is available at 0x80000 base address.
> +        enum: [ atu, atu_dma ]
> +      - description:
> +          Outbound iATU-available memory-region which usage scenario
> +          depends on the DWC PCIe controller being either Root Port or
> +          End-point. If it's Root Port then the register space shall
> +          have the "config" name and it will be used to access the
> +          peripheral PCIe devices configuration space. If it's PCIe
> +          end-point controller, then the region shall be named as
> +          "addr_space" and it will be used to generate various traffic
> +          on the PCIe bus hierarchy. It's usage scenario depends on the
> +          end-point functionality, for instance it can be used to create
> +          MSI(X) messages.
> +        enum: [ config, addr_space ]

So 'addr_space' is now valid for host mode?

(Really, for DW blocks with iATU, this should have been the whole memory 
space and the driver could size the config space itself. (IOW, the 
config region is configuration rather than h/w description.)

> +      - description:
> +          PHY/PCS configuration registers. Some platforms can have the
> +          PCS and PHY CSRs accessible over a dedicated memory mapped
> +          region, but mainly these registers are indirectly accessible
> +          either by means of the embedded PHY viewport schema or by some
> +          platform-specific method.
> +        enum: [ link, phy ]

These should not be in any new users as the phy should be separate.

> +
> +  interrupt-names:
> +    description:
> +      IRQ signal names common for the DWC PCIe Root Port and End-point
> +      controllers.
> +    oneOf:
> +      - description:
> +          Controller request to read or write virtual product data
> +          from/to the VPD capability registers.
> +        const: vpd
> +      - description:
> +          Link Equalization Request flag is set in the Link Status 2
> +          register (applicable if the corresponding IRQ is enabled in
> +          the Link Control 3 register).
> +        const: l_eq
> +      - description:
> +          Indicates that the eDMA Tx/Rx transfer is complete or that an
> +          error has occurred on the corresponding channel. eDMA can have
> +          eight Tx (Write) and Rx (Read) eDMA channels thus supporting up
> +          to 16 IRQ signals all together. Write eDMA channels shall go
> +          first in the ordered row as per default edma_int[*] bus setup.
> +        pattern: '^dma([0-9]|1[0-5])?$'
> +      - description:
> +          PCIe protocol correctable error or a Data Path protection
> +          correctable error is detected by the automotive/safety
> +          feature.
> +        const: sft_ce
> +      - description:
> +          Indicates that the internal safety mechanism detected and
> +          uncorrectable error.
> +        const: sft_ue

This says there is only a single interrupt entry. Same for the other 
$defs.

Rob

_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 01/16] dt-bindings: PCI: dwc: Define generic and native DT bindings
@ 2022-03-28 20:46     ` Rob Herring
  0 siblings, 0 replies; 40+ messages in thread
From: Rob Herring @ 2022-03-28 20:46 UTC (permalink / raw)
  To: Serge Semin
  Cc: Jingoo Han, Gustavo Pimentel, Bjorn Helgaas, Richard Zhu,
	Lucas Stach, Shawn Guo, Sascha Hauer, Pengutronix Kernel Team,
	Fabio Estevam, NXP Linux Team, Xiaowei Song, Binghui Wang,
	Paul Walmsley, Greentime Hu, Palmer Dabbelt, Nobuhiro Iwamatsu,
	Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Lorenzo Pieralisi, Krzysztof Wilczyński, Frank Li,
	Manivannan Sadhasivam, linux-pci, devicetree, linux-kernel,
	linux-arm-kernel, linux-riscv

On Thu, Mar 24, 2022 at 04:37:19AM +0300, Serge Semin wrote:
> Currently both DW PCIe Root Port and End-point DT bindings are too generic
> to be used as a descriptive set the device properties. Yes, it's very handy
> to have them that way so the DT-schemas could be used to evaluate as many
> DW PCIe-related DT-nodes as possible. But at the same time they don't
> provide well defined DW PCIe RP/EP DT interface description thus leaving
> too much flexibility for the new platforms, no encouraging the developers
> to preserve a compatible interface.
> 
> Instead of currently implemented approach we suggest to be more
> restrictive and yet preserve some level of flexibility in the DW PCIe
> DT-bindings description. The device tree DT-schema is split up into
> three parts: a common YAML-schema applicable for both DWC Root Port and
> End-point controller configs, DWC PCIe Root Port-specific YAML-schema
> and DWC PCIe End-point-specific YAML-schema, where
> 1) pci/snps,dw-pcie-common.yaml - The common DT-schema describes the most
> generic constraints of the "reg", "interrupts", "clocks", "resets" and
> "phys" properties together with a set of common for both device types
> PCIe/AXI bus properties like a maximum number of lanes or a maximum link
> speed, number of inbound and outbound iATU windows. In addition to that a
> set of schema definitions declared under the "$defs" property with "reg",
> "interrupt", "clock" and "reset" names common for DWC PCIe Root Port and
> End-point devices. They can be used by the successive DT-schemas in case
> they are supposed to be compatible with the generic DWC PCIe controller
> DT-bindings.
> 2) pci/snps,dw-pcie.yaml, pci/snps,dw-pcie-ep.yaml - generic DW PCIe Root
> Port and End-point DT-bindings which aside with the device-specific
> properties set also contain more restrictive constraints. All new DW PCIe
> platforms are supposed to be compatible with one of these bindings by
> using "allOf: " property and additionally defining their own constraints
> to close up the DT-bindings set.
> 
> So to speak in case if a DW PCIe-based device for some reason has too many
> specific properties or it's bindings have already been defined in a
> non-generic way, it's DT-schema is supposed to include 1) YAML-file and
> provide its own constraints. Otherwise the ready-to-use bindings from 2)
> should be utilized. There only two DT-schemas compatible with 2) at the
> moment are samsung,axynos-pcie.yaml and intel-gw-pcie.yaml. The
> rest of the DW PCIe-related DT-schemas are supposed to use more generic
> DW PCIe DT-bindings - pci/snps,dw-pcie-common.yaml.
> 
> Note the provided here generic properties and their possible values are
> derived from the DW PCIe RC/EP hardware manuals and from the interface
> implemented in the driver. The DT-bindings schemas are created to be as
> full as possible with detailed properties/names description for the
> easier interface comprehension and new platforms bindings development.
> 
> Also note since there are no generic DT-nodes can be found in the kernel
> dts-es which would have a pure "snps,dw-pcie" compatible string, these
> DT-bindings have been created to not be selected by default for
> evaluation. They are supposed to be used by the new vendor-specific
> DT-schemas to at least stop adding new bindings for the same set of DWC
> PCIe signals or properties.
> 
> Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> 
> ---
> 
> Rob, if you comment the "select: false" line out you'll get a lot of "'*'
> is not of type 'array'" errors on the dt_bindings_check command execution.
> I have spend tons of time trying to figure out what was wrong, but still
> failed to find out a solution. For some reason the "$ref"-ed schemas
> defined under the "$defs" basic property are considered by the parser as
> defining an array. No matter whether I specified the "type: string"
> keyword or not, as long as there is "enum" or "oneOf" keyword used in the
> "*-names" property definition in "$defs" it's considered as describing an
> array thus causing the errors like:

As-is, there were lots of errors...

> 
> >  DTC     Documentation/devicetree/bindings/pci/snps,dw-pcie.example.dt.yaml
> >  CHECK   Documentation/devicetree/bindings/pci/snps,dw-pcie.example.dt.yaml
> > /.../snps,dw-pcie.example.dt.yaml: pcie@1f052000: reg-names:0: 'oneOf' conditional failed, one must be fixed:
> >        'dbi' is not of type 'array'
> >        From schema: /.../snps,dw-pcie.yaml
> > /.../snps,dw-pcie.example.dt.yaml: pcie@1f052000: reg-names:1: 'oneOf' conditional failed, one must be fixed:
> >         'config' is not of type 'array'
> >         From schema: /.../snps,dw-pcie.yaml
> > /.../snps,dw-pcie.example.dt.yaml: pcie@1f052000: interrupt-names:0: 'anyOf' conditional failed, one must be fixed:
> >         /.../snps,dw-pcie.example.dt.yaml: pcie@1f052000: interrupt-names:0: 'oneOf' conditional failed, one must be fixed:
> >                 'msi' is not of type 'array'
> >         /../snps,dw-pcie.example.dt.yaml: pcie@1f052000: interrupt-names:0: 'oneOf' conditional failed, one must be fixed:
> >                 'msi' is not of type 'array'
> >         From schema: /.../snps,dw-pcie.yaml
> 
> As soon as I manually moved the same "$defs"-schemas into the places they
> are referenced to, the errors disappeared and the DT-schemas validation
> worked as expected by the semantics.
> 
> As I see it there must be some bug in the parser, otherwise I am out of
> ideas how to implement the suggested in this patch design pattern. Rob,
> could you take a look at the DT-schemas and help me out with debugging the
> problem described above?

There is at least an error in your schema, details latter on.

It could be an issue in the fixups which in general convert 
schemas for strings to string arrays and scalars/arrays to matrix. You 
have to look at processed-schema.json to debug it.

The other thing is 'oneOf' errors can be confusing in terms of error 
messages because the tooling doesn't really know which entry had the 
least error. Like the type was right, but some secondary constraint 
failed (as what's secondary is not expressed in any way).

I would debug it further, but I don't really like the end result. I 
think it's too hard to follow. For the most part, we avoid $refs at the 
property level across different schema files with the big exception 
being types.yaml. $defs are also used sparingly. The challenge is that 
json-schema by default will be silent on schemas misformed in lots of 
ways. Our meta-schema adds a lot of constraints which limits what the 
schemas can look like and ensures schemas are valid. It also allows me 
to define new constraints rather than repeat the same review comment 
over and over.

> ---
>  .../bindings/pci/fsl,imx6q-pcie.yaml          |   5 +-
>  .../bindings/pci/hisilicon,kirin-pcie.yaml    |   4 +-
>  .../bindings/pci/sifive,fu740-pcie.yaml       |   4 +-
>  .../bindings/pci/snps,dw-pcie-common.yaml     | 298 ++++++++++++++++++
>  .../bindings/pci/snps,dw-pcie-ep.yaml         | 143 ++++++---
>  .../devicetree/bindings/pci/snps,dw-pcie.yaml | 189 +++++++----
>  .../bindings/pci/toshiba,visconti-pcie.yaml   |   2 +-
>  7 files changed, 524 insertions(+), 121 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/pci/snps,dw-pcie-common.yaml


> diff --git a/Documentation/devicetree/bindings/pci/snps,dw-pcie-common.yaml b/Documentation/devicetree/bindings/pci/snps,dw-pcie-common.yaml
> new file mode 100644
> index 000000000000..27fe1f5c450f
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/pci/snps,dw-pcie-common.yaml
> @@ -0,0 +1,298 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/pci/snps,dw-pcie-common.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Synopsys DWC PCIe RP/EP controller
> +
> +maintainers:
> +  - Jingoo Han <jingoohan1@gmail.com>
> +  - Gustavo Pimentel <gustavo.pimentel@synopsys.com>
> +
> +properties:
> +  reg:
> +    description:
> +      DWC PCIe CSR space is normally accessed over the dedicated Data Bus
> +      Interface - DBI. In accordance with the reference manual the register
> +      configuration space belongs to the Configuration-Dependent Module (CDM)
> +      and is split up into several sub-parts Standard PCIe configuration
> +      space, Port Logic Registers (PL), Shadow Config-space Registers,
> +      iATU/eDMA registers. The particular sub-space is selected by the
> +      CDM/ELBI (dbi_cs) and CS2 (dbi_cs2) signals (selector bits). Such
> +      configuration provides a flexible interface for the system engineers to
> +      either map the particular space at a desired MMIO address or just leave
> +      them in a contiguous memory space if pure Native or AXI Bridge DBI access
> +      is selected. Note the PCIe CFG-space, PL and Shadow registers are
> +      specific to each activated function, while the rest of the sub-spaces
> +      are common for all of them (if there are more than one).
> +    minItems: 2
> +    maxItems: 6
> +
> +  interrupts:
> +    description:
> +      There are two main sub-blocks which are normally capable of
> +      generating interrupts. It's System Information Interface and MSI
> +      interface. While the former one has some common for the Host and
> +      End-point controllers IRQ-signals, the later interface is obviously
> +      Root Complex specific since it's responsible for the incoming MSI
> +      messages signalling. The System Information IRQ signals are mainly
> +      responsible for reporting the generic PCIe hierarchy and Root
> +      Complex events like VPD IO request, general AER, PME, Hot-plug, link
> +      bandwidth change, link equalization request, INTx asserted/deasserted
> +      Message detection, embedded DMA Tx/Rx/Error.
> +    minItems: 1
> +    maxItems: 26
> +
> +  clocks:
> +    description:
> +      DWC PCIe reference manual explicitly defines a set of the clocks required
> +      to get the controller working correctly. In general all of them can
> +      be divided into two groups':' application and core clocks. Note the
> +      platforms may have some of the clock sources unspecified in case if the
> +      corresponding domains are fed up from a common clock source.
> +    minItems: 1
> +    maxItems: 7
> +
> +  resets:
> +    description:
> +      DWC PCIe reference manual explicitly defines a set of the reset
> +      signals required to be de-asserted to properly activate the controller
> +      sub-parts. All of these signals can be divided into two sub-groups':'
> +      application and core resets with respect to the main sub-domains they
> +      are supposed to reset. Note the platforms may have some of these signals
> +      unspecified in case if they are automatically handled or aggregated into
> +      a comprehensive control module.
> +    minItems: 1
> +    maxItems: 10
> +
> +  reset-gpio:
> +    deprecated: true
> +    description:
> +      Reference to the GPIO-controlled PERST# signal. It is used to reset all
> +      the peripheral devices available on the PCIe bus.
> +    maxItems: 1
> +
> +  reset-gpios:
> +    description:
> +      Reference to the GPIO-controlled PERST# signal. It is used to reset all
> +      the peripheral devices available on the PCIe bus.
> +    maxItems: 1
> +
> +  phys:
> +    description:
> +      There can be up to number of possible lanes PHYs specified.
> +      Obviously each specified PHY is supposed to be able to work in the
> +      PCIe mode with a speed implied by the DWC PCIe controller it is
> +      attached to.
> +    minItems: 1
> +    maxItems: 16
> +
> +  phy-names:
> +    minItems: 1
> +    maxItems: 16
> +    items:
> +      pattern: '^pcie([0-9]+|-?phy)?$'
> +
> +  num-lanes:
> +    maximum: 16
> +
> +  max-link-speed:
> +    maximum: 4
> +
> +  num-ob-windows:
> +    $ref: /schemas/types.yaml#/definitions/uint32
> +    deprecated: true
> +    description:
> +      Number of outbound address translation windows. This parameter can be
> +      auto-detected based on the iATU memory writability. So there is no
> +      point in having a dedicated DT-property for it.
> +    maximum: 256
> +
> +  num-ib-windows:
> +    $ref: /schemas/types.yaml#/definitions/uint32
> +    deprecated: true
> +    description:
> +      Number of inbound address translation windows. In the same way as
> +      for the outbound AT windows, this parameter can be auto-detected based
> +      on the iATU memory writability. There is no point having a dedicated
> +      DT-property for it either.
> +    maximum: 256
> +
> +  num-viewport:
> +    $ref: /schemas/types.yaml#/definitions/uint32
> +    deprecated: true
> +    description:
> +      Number of outbound view ports configured in hardware. It's the same as
> +      the number of outbound AT windows.
> +    maximum: 256
> +
> +  snps,enable-cdm-check:
> +    $ref: /schemas/types.yaml#/definitions/flag
> +    description:
> +      Enable automatic checking of CDM (Configuration Dependent Module)
> +      registers for data corruption. CDM registers include standard PCIe
> +      configuration space registers, Port Logic registers, DMA and iATU
> +      registers. This feature has been available since DWC PCIe v4.80a.
> +
> +additionalProperties: true
> +
> +$defs:
> +  reg-names:
> +    description:
> +      CSR space names common for the DWC PCIe Root Port and End-point
> +      controllers.
> +    oneOf:
> +      - description:
> +          Basic DWC PCIe controller configuration-space accessible over
> +          the DBI interface. This memory space is either activated with
> +          the CDM/ELBI = 0 and CS2 = 0 or is a contiguous memory region
> +          with all spaces. Note iATU/eDMA CSRs are indirectly accessible
> +          via the PL viewports on the DWC PCIe controllers older than
> +          v4.80a.
> +        const: dbi

This passes only for 'reg-names = "dbi";'

> +      - description:
> +          Shadow DWC PCIe config-space registers. This space is selected
> +          by setting CDM/ELBI = 0 and CS2 = 1. This is an intermix of
> +          the PCI-SIG PCIe CFG-space with the shadow registers for some
> +          PCI Header space, PCI Standard and Extended Structures. It's
> +          mainly relevant for the end-point controller configuration,
> +          but still there are some shadow registers available for the
> +          Root Port mode too.
> +        const: dbi2

This passes only for 'reg-names = "dbi2";'

> +      - description:
> +          External Local Bus registers. It's an application-dependent
> +          registers normally defined by the platform engineers, which
> +          are selected by setting CDM/ELBI = 1 and CS2 = 0.
> +        enum: [ elbi, appl, app ]

This passes only for 'reg-names = "elbi", "appl", "app";'

See the problem? Replacing the 'oneOf' above with 'items' is what you 
want. But then the schema will not allow any missing entries either. 
DBI2 is optional for example. There is no way in json-schema to define a 
list of ordered values(string) once and say some entries are optional 
which I think is what you are trying to do here.

> +      - description:
> +          iATU/eDMA registers common for all device functions. It's an
> +          unrolled memory space with the internal Address Translation
> +          Unit and Enhanced DMA, which is selected by setting CDM/ELBI = 1
> +          and CS2 = 1. For IP-core releases prior v4.80a, these registers
> +          have been programmed via an indirect addressing scheme using a
> +          set of viewport CSRs mapped into the PL space. Note iATU is
> +          normally mapped to the 0x0 address of this region, while eDMA
> +          is available at 0x80000 base address.
> +        enum: [ atu, atu_dma ]
> +      - description:
> +          Outbound iATU-available memory-region which usage scenario
> +          depends on the DWC PCIe controller being either Root Port or
> +          End-point. If it's Root Port then the register space shall
> +          have the "config" name and it will be used to access the
> +          peripheral PCIe devices configuration space. If it's PCIe
> +          end-point controller, then the region shall be named as
> +          "addr_space" and it will be used to generate various traffic
> +          on the PCIe bus hierarchy. It's usage scenario depends on the
> +          end-point functionality, for instance it can be used to create
> +          MSI(X) messages.
> +        enum: [ config, addr_space ]

So 'addr_space' is now valid for host mode?

(Really, for DW blocks with iATU, this should have been the whole memory 
space and the driver could size the config space itself. (IOW, the 
config region is configuration rather than h/w description.)

> +      - description:
> +          PHY/PCS configuration registers. Some platforms can have the
> +          PCS and PHY CSRs accessible over a dedicated memory mapped
> +          region, but mainly these registers are indirectly accessible
> +          either by means of the embedded PHY viewport schema or by some
> +          platform-specific method.
> +        enum: [ link, phy ]

These should not be in any new users as the phy should be separate.

> +
> +  interrupt-names:
> +    description:
> +      IRQ signal names common for the DWC PCIe Root Port and End-point
> +      controllers.
> +    oneOf:
> +      - description:
> +          Controller request to read or write virtual product data
> +          from/to the VPD capability registers.
> +        const: vpd
> +      - description:
> +          Link Equalization Request flag is set in the Link Status 2
> +          register (applicable if the corresponding IRQ is enabled in
> +          the Link Control 3 register).
> +        const: l_eq
> +      - description:
> +          Indicates that the eDMA Tx/Rx transfer is complete or that an
> +          error has occurred on the corresponding channel. eDMA can have
> +          eight Tx (Write) and Rx (Read) eDMA channels thus supporting up
> +          to 16 IRQ signals all together. Write eDMA channels shall go
> +          first in the ordered row as per default edma_int[*] bus setup.
> +        pattern: '^dma([0-9]|1[0-5])?$'
> +      - description:
> +          PCIe protocol correctable error or a Data Path protection
> +          correctable error is detected by the automotive/safety
> +          feature.
> +        const: sft_ce
> +      - description:
> +          Indicates that the internal safety mechanism detected and
> +          uncorrectable error.
> +        const: sft_ue

This says there is only a single interrupt entry. Same for the other 
$defs.

Rob

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 01/16] dt-bindings: PCI: dwc: Define generic and native DT bindings
@ 2022-03-28 20:46     ` Rob Herring
  0 siblings, 0 replies; 40+ messages in thread
From: Rob Herring @ 2022-03-28 20:46 UTC (permalink / raw)
  To: Serge Semin
  Cc: Jingoo Han, Gustavo Pimentel, Bjorn Helgaas, Richard Zhu,
	Lucas Stach, Shawn Guo, Sascha Hauer, Pengutronix Kernel Team,
	Fabio Estevam, NXP Linux Team, Xiaowei Song, Binghui Wang,
	Paul Walmsley, Greentime Hu, Palmer Dabbelt, Nobuhiro Iwamatsu,
	Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Lorenzo Pieralisi, Krzysztof Wilczyński, Frank Li,
	Manivannan Sadhasivam, linux-pci, devicetree, linux-kernel,
	linux-arm-kernel, linux-riscv

On Thu, Mar 24, 2022 at 04:37:19AM +0300, Serge Semin wrote:
> Currently both DW PCIe Root Port and End-point DT bindings are too generic
> to be used as a descriptive set the device properties. Yes, it's very handy
> to have them that way so the DT-schemas could be used to evaluate as many
> DW PCIe-related DT-nodes as possible. But at the same time they don't
> provide well defined DW PCIe RP/EP DT interface description thus leaving
> too much flexibility for the new platforms, no encouraging the developers
> to preserve a compatible interface.
> 
> Instead of currently implemented approach we suggest to be more
> restrictive and yet preserve some level of flexibility in the DW PCIe
> DT-bindings description. The device tree DT-schema is split up into
> three parts: a common YAML-schema applicable for both DWC Root Port and
> End-point controller configs, DWC PCIe Root Port-specific YAML-schema
> and DWC PCIe End-point-specific YAML-schema, where
> 1) pci/snps,dw-pcie-common.yaml - The common DT-schema describes the most
> generic constraints of the "reg", "interrupts", "clocks", "resets" and
> "phys" properties together with a set of common for both device types
> PCIe/AXI bus properties like a maximum number of lanes or a maximum link
> speed, number of inbound and outbound iATU windows. In addition to that a
> set of schema definitions declared under the "$defs" property with "reg",
> "interrupt", "clock" and "reset" names common for DWC PCIe Root Port and
> End-point devices. They can be used by the successive DT-schemas in case
> they are supposed to be compatible with the generic DWC PCIe controller
> DT-bindings.
> 2) pci/snps,dw-pcie.yaml, pci/snps,dw-pcie-ep.yaml - generic DW PCIe Root
> Port and End-point DT-bindings which aside with the device-specific
> properties set also contain more restrictive constraints. All new DW PCIe
> platforms are supposed to be compatible with one of these bindings by
> using "allOf: " property and additionally defining their own constraints
> to close up the DT-bindings set.
> 
> So to speak in case if a DW PCIe-based device for some reason has too many
> specific properties or it's bindings have already been defined in a
> non-generic way, it's DT-schema is supposed to include 1) YAML-file and
> provide its own constraints. Otherwise the ready-to-use bindings from 2)
> should be utilized. There only two DT-schemas compatible with 2) at the
> moment are samsung,axynos-pcie.yaml and intel-gw-pcie.yaml. The
> rest of the DW PCIe-related DT-schemas are supposed to use more generic
> DW PCIe DT-bindings - pci/snps,dw-pcie-common.yaml.
> 
> Note the provided here generic properties and their possible values are
> derived from the DW PCIe RC/EP hardware manuals and from the interface
> implemented in the driver. The DT-bindings schemas are created to be as
> full as possible with detailed properties/names description for the
> easier interface comprehension and new platforms bindings development.
> 
> Also note since there are no generic DT-nodes can be found in the kernel
> dts-es which would have a pure "snps,dw-pcie" compatible string, these
> DT-bindings have been created to not be selected by default for
> evaluation. They are supposed to be used by the new vendor-specific
> DT-schemas to at least stop adding new bindings for the same set of DWC
> PCIe signals or properties.
> 
> Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> 
> ---
> 
> Rob, if you comment the "select: false" line out you'll get a lot of "'*'
> is not of type 'array'" errors on the dt_bindings_check command execution.
> I have spend tons of time trying to figure out what was wrong, but still
> failed to find out a solution. For some reason the "$ref"-ed schemas
> defined under the "$defs" basic property are considered by the parser as
> defining an array. No matter whether I specified the "type: string"
> keyword or not, as long as there is "enum" or "oneOf" keyword used in the
> "*-names" property definition in "$defs" it's considered as describing an
> array thus causing the errors like:

As-is, there were lots of errors...

> 
> >  DTC     Documentation/devicetree/bindings/pci/snps,dw-pcie.example.dt.yaml
> >  CHECK   Documentation/devicetree/bindings/pci/snps,dw-pcie.example.dt.yaml
> > /.../snps,dw-pcie.example.dt.yaml: pcie@1f052000: reg-names:0: 'oneOf' conditional failed, one must be fixed:
> >        'dbi' is not of type 'array'
> >        From schema: /.../snps,dw-pcie.yaml
> > /.../snps,dw-pcie.example.dt.yaml: pcie@1f052000: reg-names:1: 'oneOf' conditional failed, one must be fixed:
> >         'config' is not of type 'array'
> >         From schema: /.../snps,dw-pcie.yaml
> > /.../snps,dw-pcie.example.dt.yaml: pcie@1f052000: interrupt-names:0: 'anyOf' conditional failed, one must be fixed:
> >         /.../snps,dw-pcie.example.dt.yaml: pcie@1f052000: interrupt-names:0: 'oneOf' conditional failed, one must be fixed:
> >                 'msi' is not of type 'array'
> >         /../snps,dw-pcie.example.dt.yaml: pcie@1f052000: interrupt-names:0: 'oneOf' conditional failed, one must be fixed:
> >                 'msi' is not of type 'array'
> >         From schema: /.../snps,dw-pcie.yaml
> 
> As soon as I manually moved the same "$defs"-schemas into the places they
> are referenced to, the errors disappeared and the DT-schemas validation
> worked as expected by the semantics.
> 
> As I see it there must be some bug in the parser, otherwise I am out of
> ideas how to implement the suggested in this patch design pattern. Rob,
> could you take a look at the DT-schemas and help me out with debugging the
> problem described above?

There is at least an error in your schema, details latter on.

It could be an issue in the fixups which in general convert 
schemas for strings to string arrays and scalars/arrays to matrix. You 
have to look at processed-schema.json to debug it.

The other thing is 'oneOf' errors can be confusing in terms of error 
messages because the tooling doesn't really know which entry had the 
least error. Like the type was right, but some secondary constraint 
failed (as what's secondary is not expressed in any way).

I would debug it further, but I don't really like the end result. I 
think it's too hard to follow. For the most part, we avoid $refs at the 
property level across different schema files with the big exception 
being types.yaml. $defs are also used sparingly. The challenge is that 
json-schema by default will be silent on schemas misformed in lots of 
ways. Our meta-schema adds a lot of constraints which limits what the 
schemas can look like and ensures schemas are valid. It also allows me 
to define new constraints rather than repeat the same review comment 
over and over.

> ---
>  .../bindings/pci/fsl,imx6q-pcie.yaml          |   5 +-
>  .../bindings/pci/hisilicon,kirin-pcie.yaml    |   4 +-
>  .../bindings/pci/sifive,fu740-pcie.yaml       |   4 +-
>  .../bindings/pci/snps,dw-pcie-common.yaml     | 298 ++++++++++++++++++
>  .../bindings/pci/snps,dw-pcie-ep.yaml         | 143 ++++++---
>  .../devicetree/bindings/pci/snps,dw-pcie.yaml | 189 +++++++----
>  .../bindings/pci/toshiba,visconti-pcie.yaml   |   2 +-
>  7 files changed, 524 insertions(+), 121 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/pci/snps,dw-pcie-common.yaml


> diff --git a/Documentation/devicetree/bindings/pci/snps,dw-pcie-common.yaml b/Documentation/devicetree/bindings/pci/snps,dw-pcie-common.yaml
> new file mode 100644
> index 000000000000..27fe1f5c450f
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/pci/snps,dw-pcie-common.yaml
> @@ -0,0 +1,298 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/pci/snps,dw-pcie-common.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Synopsys DWC PCIe RP/EP controller
> +
> +maintainers:
> +  - Jingoo Han <jingoohan1@gmail.com>
> +  - Gustavo Pimentel <gustavo.pimentel@synopsys.com>
> +
> +properties:
> +  reg:
> +    description:
> +      DWC PCIe CSR space is normally accessed over the dedicated Data Bus
> +      Interface - DBI. In accordance with the reference manual the register
> +      configuration space belongs to the Configuration-Dependent Module (CDM)
> +      and is split up into several sub-parts Standard PCIe configuration
> +      space, Port Logic Registers (PL), Shadow Config-space Registers,
> +      iATU/eDMA registers. The particular sub-space is selected by the
> +      CDM/ELBI (dbi_cs) and CS2 (dbi_cs2) signals (selector bits). Such
> +      configuration provides a flexible interface for the system engineers to
> +      either map the particular space at a desired MMIO address or just leave
> +      them in a contiguous memory space if pure Native or AXI Bridge DBI access
> +      is selected. Note the PCIe CFG-space, PL and Shadow registers are
> +      specific to each activated function, while the rest of the sub-spaces
> +      are common for all of them (if there are more than one).
> +    minItems: 2
> +    maxItems: 6
> +
> +  interrupts:
> +    description:
> +      There are two main sub-blocks which are normally capable of
> +      generating interrupts. It's System Information Interface and MSI
> +      interface. While the former one has some common for the Host and
> +      End-point controllers IRQ-signals, the later interface is obviously
> +      Root Complex specific since it's responsible for the incoming MSI
> +      messages signalling. The System Information IRQ signals are mainly
> +      responsible for reporting the generic PCIe hierarchy and Root
> +      Complex events like VPD IO request, general AER, PME, Hot-plug, link
> +      bandwidth change, link equalization request, INTx asserted/deasserted
> +      Message detection, embedded DMA Tx/Rx/Error.
> +    minItems: 1
> +    maxItems: 26
> +
> +  clocks:
> +    description:
> +      DWC PCIe reference manual explicitly defines a set of the clocks required
> +      to get the controller working correctly. In general all of them can
> +      be divided into two groups':' application and core clocks. Note the
> +      platforms may have some of the clock sources unspecified in case if the
> +      corresponding domains are fed up from a common clock source.
> +    minItems: 1
> +    maxItems: 7
> +
> +  resets:
> +    description:
> +      DWC PCIe reference manual explicitly defines a set of the reset
> +      signals required to be de-asserted to properly activate the controller
> +      sub-parts. All of these signals can be divided into two sub-groups':'
> +      application and core resets with respect to the main sub-domains they
> +      are supposed to reset. Note the platforms may have some of these signals
> +      unspecified in case if they are automatically handled or aggregated into
> +      a comprehensive control module.
> +    minItems: 1
> +    maxItems: 10
> +
> +  reset-gpio:
> +    deprecated: true
> +    description:
> +      Reference to the GPIO-controlled PERST# signal. It is used to reset all
> +      the peripheral devices available on the PCIe bus.
> +    maxItems: 1
> +
> +  reset-gpios:
> +    description:
> +      Reference to the GPIO-controlled PERST# signal. It is used to reset all
> +      the peripheral devices available on the PCIe bus.
> +    maxItems: 1
> +
> +  phys:
> +    description:
> +      There can be up to number of possible lanes PHYs specified.
> +      Obviously each specified PHY is supposed to be able to work in the
> +      PCIe mode with a speed implied by the DWC PCIe controller it is
> +      attached to.
> +    minItems: 1
> +    maxItems: 16
> +
> +  phy-names:
> +    minItems: 1
> +    maxItems: 16
> +    items:
> +      pattern: '^pcie([0-9]+|-?phy)?$'
> +
> +  num-lanes:
> +    maximum: 16
> +
> +  max-link-speed:
> +    maximum: 4
> +
> +  num-ob-windows:
> +    $ref: /schemas/types.yaml#/definitions/uint32
> +    deprecated: true
> +    description:
> +      Number of outbound address translation windows. This parameter can be
> +      auto-detected based on the iATU memory writability. So there is no
> +      point in having a dedicated DT-property for it.
> +    maximum: 256
> +
> +  num-ib-windows:
> +    $ref: /schemas/types.yaml#/definitions/uint32
> +    deprecated: true
> +    description:
> +      Number of inbound address translation windows. In the same way as
> +      for the outbound AT windows, this parameter can be auto-detected based
> +      on the iATU memory writability. There is no point having a dedicated
> +      DT-property for it either.
> +    maximum: 256
> +
> +  num-viewport:
> +    $ref: /schemas/types.yaml#/definitions/uint32
> +    deprecated: true
> +    description:
> +      Number of outbound view ports configured in hardware. It's the same as
> +      the number of outbound AT windows.
> +    maximum: 256
> +
> +  snps,enable-cdm-check:
> +    $ref: /schemas/types.yaml#/definitions/flag
> +    description:
> +      Enable automatic checking of CDM (Configuration Dependent Module)
> +      registers for data corruption. CDM registers include standard PCIe
> +      configuration space registers, Port Logic registers, DMA and iATU
> +      registers. This feature has been available since DWC PCIe v4.80a.
> +
> +additionalProperties: true
> +
> +$defs:
> +  reg-names:
> +    description:
> +      CSR space names common for the DWC PCIe Root Port and End-point
> +      controllers.
> +    oneOf:
> +      - description:
> +          Basic DWC PCIe controller configuration-space accessible over
> +          the DBI interface. This memory space is either activated with
> +          the CDM/ELBI = 0 and CS2 = 0 or is a contiguous memory region
> +          with all spaces. Note iATU/eDMA CSRs are indirectly accessible
> +          via the PL viewports on the DWC PCIe controllers older than
> +          v4.80a.
> +        const: dbi

This passes only for 'reg-names = "dbi";'

> +      - description:
> +          Shadow DWC PCIe config-space registers. This space is selected
> +          by setting CDM/ELBI = 0 and CS2 = 1. This is an intermix of
> +          the PCI-SIG PCIe CFG-space with the shadow registers for some
> +          PCI Header space, PCI Standard and Extended Structures. It's
> +          mainly relevant for the end-point controller configuration,
> +          but still there are some shadow registers available for the
> +          Root Port mode too.
> +        const: dbi2

This passes only for 'reg-names = "dbi2";'

> +      - description:
> +          External Local Bus registers. It's an application-dependent
> +          registers normally defined by the platform engineers, which
> +          are selected by setting CDM/ELBI = 1 and CS2 = 0.
> +        enum: [ elbi, appl, app ]

This passes only for 'reg-names = "elbi", "appl", "app";'

See the problem? Replacing the 'oneOf' above with 'items' is what you 
want. But then the schema will not allow any missing entries either. 
DBI2 is optional for example. There is no way in json-schema to define a 
list of ordered values(string) once and say some entries are optional 
which I think is what you are trying to do here.

> +      - description:
> +          iATU/eDMA registers common for all device functions. It's an
> +          unrolled memory space with the internal Address Translation
> +          Unit and Enhanced DMA, which is selected by setting CDM/ELBI = 1
> +          and CS2 = 1. For IP-core releases prior v4.80a, these registers
> +          have been programmed via an indirect addressing scheme using a
> +          set of viewport CSRs mapped into the PL space. Note iATU is
> +          normally mapped to the 0x0 address of this region, while eDMA
> +          is available at 0x80000 base address.
> +        enum: [ atu, atu_dma ]
> +      - description:
> +          Outbound iATU-available memory-region which usage scenario
> +          depends on the DWC PCIe controller being either Root Port or
> +          End-point. If it's Root Port then the register space shall
> +          have the "config" name and it will be used to access the
> +          peripheral PCIe devices configuration space. If it's PCIe
> +          end-point controller, then the region shall be named as
> +          "addr_space" and it will be used to generate various traffic
> +          on the PCIe bus hierarchy. It's usage scenario depends on the
> +          end-point functionality, for instance it can be used to create
> +          MSI(X) messages.
> +        enum: [ config, addr_space ]

So 'addr_space' is now valid for host mode?

(Really, for DW blocks with iATU, this should have been the whole memory 
space and the driver could size the config space itself. (IOW, the 
config region is configuration rather than h/w description.)

> +      - description:
> +          PHY/PCS configuration registers. Some platforms can have the
> +          PCS and PHY CSRs accessible over a dedicated memory mapped
> +          region, but mainly these registers are indirectly accessible
> +          either by means of the embedded PHY viewport schema or by some
> +          platform-specific method.
> +        enum: [ link, phy ]

These should not be in any new users as the phy should be separate.

> +
> +  interrupt-names:
> +    description:
> +      IRQ signal names common for the DWC PCIe Root Port and End-point
> +      controllers.
> +    oneOf:
> +      - description:
> +          Controller request to read or write virtual product data
> +          from/to the VPD capability registers.
> +        const: vpd
> +      - description:
> +          Link Equalization Request flag is set in the Link Status 2
> +          register (applicable if the corresponding IRQ is enabled in
> +          the Link Control 3 register).
> +        const: l_eq
> +      - description:
> +          Indicates that the eDMA Tx/Rx transfer is complete or that an
> +          error has occurred on the corresponding channel. eDMA can have
> +          eight Tx (Write) and Rx (Read) eDMA channels thus supporting up
> +          to 16 IRQ signals all together. Write eDMA channels shall go
> +          first in the ordered row as per default edma_int[*] bus setup.
> +        pattern: '^dma([0-9]|1[0-5])?$'
> +      - description:
> +          PCIe protocol correctable error or a Data Path protection
> +          correctable error is detected by the automotive/safety
> +          feature.
> +        const: sft_ce
> +      - description:
> +          Indicates that the internal safety mechanism detected and
> +          uncorrectable error.
> +        const: sft_ue

This says there is only a single interrupt entry. Same for the other 
$defs.

Rob

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 02/16] dt-bindings: PCI: dwc: Add Baikal-T1 PCIe Root Port bindings
  2022-03-24  1:37 ` [PATCH 02/16] dt-bindings: PCI: dwc: Add Baikal-T1 PCIe Root Port bindings Serge Semin
@ 2022-03-28 23:20   ` Rob Herring
  2022-04-15 20:22     ` Serge Semin
  0 siblings, 1 reply; 40+ messages in thread
From: Rob Herring @ 2022-03-28 23:20 UTC (permalink / raw)
  To: Serge Semin
  Cc: Jingoo Han, Gustavo Pimentel, Bjorn Helgaas, Serge Semin,
	Alexey Malahov, Pavel Parkhomenko, Lorenzo Pieralisi,
	Krzysztof Wilczyński, Frank Li, Manivannan Sadhasivam,
	linux-pci, devicetree, linux-kernel

On Thu, Mar 24, 2022 at 04:37:20AM +0300, Serge Semin wrote:
> Baikal-T1 SoC is equipped with DWC PCIe v4.60a Root Port controller, which
> link can be trained to work on up to Gen.3 speed over up to x4 lanes. The
> controller is supposed to be fed up with four clock sources: DBI
> peripheral clock, AXI application Tx/Rx clocks and external PHY/core
> reference clock generating the 100MHz signal. In addition to that the
> platform provide a way to reset each part of the controller:
> sticky/non-sticky bits, host controller core, PIPE interface, PCS/PHY and
> Hot/Power reset signal. The Root Port controller is equipped with multiple
> IRQ lines like MSI, system AER, PME, HP, Bandwidth change, Link
> equalization request and eDMA ones. The registers space is accessed over
> the DBI interface. There can be no more than four inbound or outbound iATU
> windows configured.
> 
> Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> 
> ---
> 
> Rob, this DT-bindings most likely will fail the dt_bindings_check
> evaluations with the "'*' is not of type 'array'" errors for the same
> reason described in the previous patch. Let's discuss the problem there.
> ---
>  .../bindings/pci/baikal,bt1-pcie.yaml         | 148 ++++++++++++++++++
>  1 file changed, 148 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/pci/baikal,bt1-pcie.yaml
> 
> diff --git a/Documentation/devicetree/bindings/pci/baikal,bt1-pcie.yaml b/Documentation/devicetree/bindings/pci/baikal,bt1-pcie.yaml
> new file mode 100644
> index 000000000000..f34438330a86
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/pci/baikal,bt1-pcie.yaml
> @@ -0,0 +1,148 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/pci/baikal,bt1-pcie.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Baikal-T1 PCIe Root Port Controller
> +
> +maintainers:
> +  - Serge Semin <fancer.lancer@gmail.com>
> +
> +description: |
> +  Embedded into Baikal-T1 SoC Root Complex controller. It's based on the
> +  DWC RC PCIe v4.60a IP-core, which is configured to have just a single Root
> +  Port function and is capable of establishing the link up to Gen.3 speed
> +  on x4 lanes. It doesn't have embedded clock and reset control module, so
> +  the proper interface initialization is supposed to be performed by software.
> +
> +allOf:
> +  - $ref: /schemas/pci/pci-bus.yaml#
> +  - $ref: snps,dw-pcie.yaml#
> +
> +properties:
> +  compatible:
> +    contains:
> +      const: baikal,bt1-pcie
> +
> +  reg:
> +    description:
> +      DBI, DBI2 and at least 4KB outbound iATU-capable region are available.

outbound iATU-capable region? While configured with iATU, it's just 
config space from a binding standpoint.

It's a bit more precise to do this:

items:
  - description: DBI...
  - description: DBI2...
  - ...


> +    maxItems: 3

And then drop this.

> +
> +  reg-names:
> +    minItems: 3
> +    maxItems: 3
> +    items:
> +      enum: [ dbi, dbi2, config ]

To enforce the order:

items:
  - const: dbi
  - const: dbi2
  - const: config

> +
> +  interrupts:
> +    description:
> +      MSI, AER, PME, Hot-plug, Link Bandwidth Management, Link Equalization
> +      request and eight Read/Write eDMA IRQ lines are available.
> +    maxItems: 14
> +
> +  interrupt-names:
> +    minItems: 14
> +    maxItems: 14
> +    items:
> +      oneOf:
> +        - pattern: '^dma[0-7]$'
> +        - enum: [ msi, aer, pme, hp, bw_mg, l_eq ]

Can't you define the order?

> +
> +  clocks:
> +    description:
> +      DBI (attached to the APB bus), AXI-bus master and slave interfaces
> +      are fed up by the dedicated application clocks. A common reference
> +      clock signal is supposed to be attached to the corresponding Ref-pad
> +      of the SoC. It will be redistributed amongst the controller core
> +      sub-modules (pipe, core, aux, etc).
> +    minItems: 4
> +    maxItems: 4
> +
> +  clock-names:
> +    minItems: 4
> +    maxItems: 4
> +    items:
> +      enum: [ dbi, mstr, slv, ref ]
> +
> +  resets:
> +    description:
> +      A comprehensive controller reset logic is supposed to be implemented
> +      by software, so almost all the possible application and core reset
> +      signals are exposed via the system CCU module.
> +    minItems: 9
> +    maxItems: 9
> +
> +  reset-names:
> +    minItems: 9
> +    maxItems: 9
> +    items:
> +      enum: [ mstr, slv, pwr, hot, phy, core, pipe, sticky, non-sticky ]

Again, define the order.

> +
> +  syscon:

Needs a vendor prefix.

> +    $ref: /schemas/types.yaml#/definitions/phandle
> +    description:
> +      Phandle to the Baikal-T1 System Controller DT node. It's required to
> +      access some additional PM, Reset-related and LTSSM signals.
> +
> +  num-lanes:
> +    maximum: 4
> +
> +  max-link-speed:
> +    maximum: 3
> +

> +  num-ob-windows:
> +    const: 4
> +
> +  num-ib-windows:
> +    const: 4

These are deprecated. The driver probes for how many now.

> +
> +required:
> +  - compatible
> +  - reg
> +  - reg-names
> +  - interrupts
> +  - interrupt-names
> +  - clocks
> +  - clock-names
> +  - resets
> +  - reset-names
> +
> +unevaluatedProperties: false
> +
> +examples:
> +  - |
> +    pcie@1f052000 {
> +      compatible = "baikal,bt1-pcie", "snps,dw-pcie-4.60a", "snps,dw-pcie";
> +      device_type = "pci";
> +      reg = <0x1f052000 0x1000>, <0x1f053000 0x1000>, <0x1bdbf000 0x1000>;
> +      reg-names = "dbi", "dbi2", "config";
> +      #address-cells = <3>;
> +      #size-cells = <2>;
> +      ranges = <0x81000000 0 0x00000000 0x1bdb0000 0 0x00008000>,
> +               <0x82000000 0 0x20000000 0x08000000 0 0x13db0000>;
> +      bus-range = <0x0 0xff>;
> +
> +      interrupts = <0 80 4>, <0 81 4>, <0 82 4>, <0 83 4>,
> +                   <0 84 4>, <0 85 4>, <0 86 4>, <0 87 4>,
> +                   <0 88 4>, <0 89 4>, <0 90 4>, <0 91 4>,
> +                   <0 92 4>, <0 93 4>;
> +      interrupt-names = "dma0", "dma1", "dma2", "dma3", "dma4", "dma5", "dma6",
> +                        "dma7", "msi", "aer", "pme", "hp", "bw_mg", "l_eq";
> +
> +      clocks = <&ccu_sys 1>, <&ccu_axi 6>, <&ccu_axi 7>, <&clk_pcie>;
> +      clock-names = "dbi", "mstr", "slv", "ref";
> +
> +      resets = <&ccu_axi 6>, <&ccu_axi 7>, <&ccu_sys 7>, <&ccu_sys 10>,
> +               <&ccu_sys 4>, <&ccu_sys 6>, <&ccu_sys 5>, <&ccu_sys 8>,
> +               <&ccu_sys 9>;
> +      reset-names = "mstr", "slv", "pwr", "hot", "phy", "core", "pipe",
> +                    "sticky", "non-sticky";
> +
> +      reset-gpios = <&port0 0 1>;
> +
> +      num-lanes = <4>;
> +      max-link-speed = <3>;
> +    };
> +...
> -- 
> 2.35.1
> 
> 

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 03/16] PCI: dwc: Add more verbose link-up message
  2022-03-24  1:37 ` [PATCH 03/16] PCI: dwc: Add more verbose link-up message Serge Semin
@ 2022-03-28 23:31   ` Joe Perches
  2022-04-16  8:01     ` Serge Semin
  2022-03-29 14:47   ` Rob Herring
  1 sibling, 1 reply; 40+ messages in thread
From: Joe Perches @ 2022-03-28 23:31 UTC (permalink / raw)
  To: Serge Semin, Jingoo Han, Gustavo Pimentel, Bjorn Helgaas,
	Lorenzo Pieralisi, Rob Herring, Krzysztof Wilczyński
  Cc: Serge Semin, Alexey Malahov, Pavel Parkhomenko, Frank Li,
	Manivannan Sadhasivam, Rob Herring, linux-pci, devicetree,
	linux-kernel

On Thu, 2022-03-24 at 04:37 +0300, Serge Semin wrote:
> Printing just "link up" isn't that much informative especially when it
> comes to working with the PCI Express bus. Even if the link is up, due to
> multiple reasons the bus performance can degrade to slower speeds or to
> narrower width than both Root Port and its partner is capable of. In that
> case it would be handy to know the link specifications as early as
> possible. So let's add a more verbose message to the busy-wait link-state
> method, which will contain the link speed generation and the PCIe bus
> width in case if the link up state is discovered. Otherwise an error will
> be printed to the system log.
> 
> Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> ---
>  drivers/pci/controller/dwc/pcie-designware.c | 22 +++++++++++++++-----
>  1 file changed, 17 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c
[]
> @@ -528,14 +528,26 @@ int dw_pcie_wait_for_link(struct dw_pcie *pci)
>  
>  	/* Check if the link is up or not */
>  	for (retries = 0; retries < LINK_WAIT_MAX_RETRIES; retries++) {
> -		if (dw_pcie_link_up(pci)) {
> -			dev_info(pci->dev, "Link up\n");
> -			return 0;
> -		}
> +		if (dw_pcie_link_up(pci))
> +			break;
> +
>  		usleep_range(LINK_WAIT_USLEEP_MIN, LINK_WAIT_USLEEP_MAX);
>  	}
>  
> -	dev_info(pci->dev, "Phy link never came up\n");
> +	if (retries < LINK_WAIT_MAX_RETRIES) {
> +		u32 offset, val;
> +
> +		offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
> +		val = dw_pcie_readw_dbi(pci, offset + PCI_EXP_LNKSTA);
> +
> +		dev_info(pci->dev, "PCIe Gen.%u x%u link up\n",
> +			 FIELD_GET(PCI_EXP_LNKSTA_CLS, val),
> +			 FIELD_GET(PCI_EXP_LNKSTA_NLW, val));
> +
> +		return 0;
> +	}
> +
> +	dev_err(pci->dev, "Phy link never came up\n");
>  
>  	return -ETIMEDOUT;
>  }

IMO: it's generally bette to test the error condition and unindent
the typical return.

	if (retries >= LINK_WAIT_MAX_RETRIES) {
		dev_err(pci->dev, "Phy link never came up\n");
		return -ETIMEDOUT;
	}

	offset = ...
	val = ...
	dev_info(...)

	return 0;
}


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 03/16] PCI: dwc: Add more verbose link-up message
  2022-03-24  1:37 ` [PATCH 03/16] PCI: dwc: Add more verbose link-up message Serge Semin
  2022-03-28 23:31   ` Joe Perches
@ 2022-03-29 14:47   ` Rob Herring
  2022-04-17 10:10     ` Serge Semin
  1 sibling, 1 reply; 40+ messages in thread
From: Rob Herring @ 2022-03-29 14:47 UTC (permalink / raw)
  To: Serge Semin
  Cc: Jingoo Han, Gustavo Pimentel, Bjorn Helgaas, Lorenzo Pieralisi,
	Krzysztof Wilczyński, Serge Semin, Alexey Malahov,
	Pavel Parkhomenko, Frank Li, Manivannan Sadhasivam, linux-pci,
	devicetree, linux-kernel

On Thu, Mar 24, 2022 at 04:37:21AM +0300, Serge Semin wrote:
> Printing just "link up" isn't that much informative especially when it
> comes to working with the PCI Express bus. Even if the link is up, due to
> multiple reasons the bus performance can degrade to slower speeds or to
> narrower width than both Root Port and its partner is capable of. In that
> case it would be handy to know the link specifications as early as
> possible. So let's add a more verbose message to the busy-wait link-state
> method, which will contain the link speed generation and the PCIe bus
> width in case if the link up state is discovered. Otherwise an error will
> be printed to the system log.
> 
> Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> ---
>  drivers/pci/controller/dwc/pcie-designware.c | 22 +++++++++++++++-----
>  1 file changed, 17 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c
> index 6e81264fdfb4..f1693e25afcb 100644
> --- a/drivers/pci/controller/dwc/pcie-designware.c
> +++ b/drivers/pci/controller/dwc/pcie-designware.c
> @@ -528,14 +528,26 @@ int dw_pcie_wait_for_link(struct dw_pcie *pci)
>  
>  	/* Check if the link is up or not */
>  	for (retries = 0; retries < LINK_WAIT_MAX_RETRIES; retries++) {
> -		if (dw_pcie_link_up(pci)) {
> -			dev_info(pci->dev, "Link up\n");
> -			return 0;
> -		}
> +		if (dw_pcie_link_up(pci))
> +			break;
> +
>  		usleep_range(LINK_WAIT_USLEEP_MIN, LINK_WAIT_USLEEP_MAX);
>  	}
>  
> -	dev_info(pci->dev, "Phy link never came up\n");
> +	if (retries < LINK_WAIT_MAX_RETRIES) {
> +		u32 offset, val;
> +
> +		offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
> +		val = dw_pcie_readw_dbi(pci, offset + PCI_EXP_LNKSTA);
> +
> +		dev_info(pci->dev, "PCIe Gen.%u x%u link up\n",
> +			 FIELD_GET(PCI_EXP_LNKSTA_CLS, val),
> +			 FIELD_GET(PCI_EXP_LNKSTA_NLW, val));

Given these are standard registers can we do this in the core code? The 
main issue I think is that the config space accessors don't work until 
you create the bus struct. That still should be early enough.

I think it is possible some implementations don't report the link state 
in these registers. Maybe we don't really need to care.

Rob

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 04/16] PCI: dwc: Convert to using native IP-core versions representation
  2022-03-24  1:37 ` [PATCH 04/16] PCI: dwc: Convert to using native IP-core versions representation Serge Semin
@ 2022-03-29 15:00   ` Rob Herring
  2022-04-17 14:42     ` Serge Semin
  0 siblings, 1 reply; 40+ messages in thread
From: Rob Herring @ 2022-03-29 15:00 UTC (permalink / raw)
  To: Serge Semin
  Cc: Jingoo Han, Gustavo Pimentel, Bjorn Helgaas, Lorenzo Pieralisi,
	Krzysztof Wilczyński, Rahul Tanwar, Thierry Reding,
	Jonathan Hunter, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Frank Li, Manivannan Sadhasivam, linux-pci, devicetree,
	linux-kernel, linux-tegra

On Thu, Mar 24, 2022 at 04:37:22AM +0300, Serge Semin wrote:
> Since DWC PCIe v4.70a the controller version can be read from the
> PORT_LOGIC.PCIE_VERSION_OFF register. Version is represented in the FourCC
> format [1]. It's standard versioning approach for the Synopsys DWC
> IP-cores. Moreover some of the DWC kernel drivers already make use of it
> to fixup version-dependent functionality (See DWC USB3, Stmicro STMMAC or
> recent DW SPI driver). In order to preserve the standard version
> representation and prevent the data conversion back and forth, we suggest
> to preserve the native version representation in the DWC PCIe driver too
> in the same way as it has already been done in the rest of the DWC
> drivers. IP-core version reading from the CSR will be introduced in the
> next commit together with a simple macro-based API to use it.
> 
> [1] https://en.wikipedia.org/wiki/FourCC
> 
> Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> ---
>  drivers/pci/controller/dwc/pci-keystone.c    | 12 ++++++------
>  drivers/pci/controller/dwc/pcie-designware.c |  8 ++++----
>  drivers/pci/controller/dwc/pcie-designware.h | 10 +++++++++-
>  drivers/pci/controller/dwc/pcie-intel-gw.c   |  4 ++--
>  drivers/pci/controller/dwc/pcie-tegra194.c   |  2 +-
>  5 files changed, 22 insertions(+), 14 deletions(-)
> 
> diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c
> index 1c2ee4e13f1c..ec65355dd29b 100644
> --- a/drivers/pci/controller/dwc/pci-keystone.c
> +++ b/drivers/pci/controller/dwc/pci-keystone.c
> @@ -109,7 +109,7 @@ struct ks_pcie_of_data {
>  	enum dw_pcie_device_mode mode;
>  	const struct dw_pcie_host_ops *host_ops;
>  	const struct dw_pcie_ep_ops *ep_ops;
> -	unsigned int version;
> +	u32 version;
>  };
>  
>  struct keystone_pcie {
> @@ -1069,19 +1069,19 @@ static int ks_pcie_am654_set_mode(struct device *dev,
>  
>  static const struct ks_pcie_of_data ks_pcie_rc_of_data = {
>  	.host_ops = &ks_pcie_host_ops,
> -	.version = 0x365A,
> +	.version = DW_PCIE_VER_365A,
>  };
>  
>  static const struct ks_pcie_of_data ks_pcie_am654_rc_of_data = {
>  	.host_ops = &ks_pcie_am654_host_ops,
>  	.mode = DW_PCIE_RC_TYPE,
> -	.version = 0x490A,
> +	.version = DW_PCIE_VER_490A,

This version should be readable, so get rid of hardcoding it here.

>  };
>  
>  static const struct ks_pcie_of_data ks_pcie_am654_ep_of_data = {
>  	.ep_ops = &ks_pcie_am654_ep_ops,
>  	.mode = DW_PCIE_EP_TYPE,
> -	.version = 0x490A,
> +	.version = DW_PCIE_VER_490A,
>  };
>  
>  static const struct of_device_id ks_pcie_of_match[] = {
> @@ -1114,12 +1114,12 @@ static int __init ks_pcie_probe(struct platform_device *pdev)
>  	struct device_link **link;
>  	struct gpio_desc *gpiod;
>  	struct resource *res;
> -	unsigned int version;
>  	void __iomem *base;
>  	u32 num_viewport;
>  	struct phy **phy;
>  	u32 num_lanes;
>  	char name[10];
> +	u32 version;
>  	int ret;
>  	int irq;
>  	int i;
> @@ -1233,7 +1233,7 @@ static int __init ks_pcie_probe(struct platform_device *pdev)
>  		goto err_get_sync;
>  	}
>  
> -	if (pci->version >= 0x480A)
> +	if (pci->version >= DW_PCIE_VER_480A)
>  		ret = ks_pcie_am654_set_mode(dev, mode);
>  	else
>  		ret = ks_pcie_set_mode(dev);
> diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c
> index f1693e25afcb..c21373c6cb51 100644
> --- a/drivers/pci/controller/dwc/pcie-designware.c
> +++ b/drivers/pci/controller/dwc/pcie-designware.c
> @@ -289,7 +289,7 @@ static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, u8 func_no,
>  	val = type | PCIE_ATU_FUNC_NUM(func_no);
>  	if (upper_32_bits(limit_addr) > upper_32_bits(cpu_addr))
>  		val |= PCIE_ATU_INCREASE_REGION_SIZE;
> -	if (pci->version == 0x490A)
> +	if (pci->version == DW_PCIE_VER_490A)
>  		val = dw_pcie_enable_ecrc(val);
>  	dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1, val);
>  	dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL2,
> @@ -336,7 +336,7 @@ static void __dw_pcie_prog_outbound_atu(struct dw_pcie *pci, u8 func_no,
>  			   upper_32_bits(cpu_addr));
>  	dw_pcie_writel_dbi(pci, PCIE_ATU_LIMIT,
>  			   lower_32_bits(limit_addr));
> -	if (pci->version >= 0x460A)
> +	if (pci->version >= DW_PCIE_VER_460A)
>  		dw_pcie_writel_dbi(pci, PCIE_ATU_UPPER_LIMIT,
>  				   upper_32_bits(limit_addr));
>  	dw_pcie_writel_dbi(pci, PCIE_ATU_LOWER_TARGET,
> @@ -345,9 +345,9 @@ static void __dw_pcie_prog_outbound_atu(struct dw_pcie *pci, u8 func_no,
>  			   upper_32_bits(pci_addr));
>  	val = type | PCIE_ATU_FUNC_NUM(func_no);
>  	if (upper_32_bits(limit_addr) > upper_32_bits(cpu_addr) &&
> -	    pci->version >= 0x460A)
> +	    pci->version >= DW_PCIE_VER_460A)
>  		val |= PCIE_ATU_INCREASE_REGION_SIZE;
> -	if (pci->version == 0x490A)
> +	if (pci->version == DW_PCIE_VER_490A)
>  		val = dw_pcie_enable_ecrc(val);
>  	dw_pcie_writel_dbi(pci, PCIE_ATU_CR1, val);
>  	dw_pcie_writel_dbi(pci, PCIE_ATU_CR2, PCIE_ATU_ENABLE);
> diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
> index 7d6e9b7576be..5be43c662176 100644
> --- a/drivers/pci/controller/dwc/pcie-designware.h
> +++ b/drivers/pci/controller/dwc/pcie-designware.h
> @@ -20,6 +20,14 @@
>  #include <linux/pci-epc.h>
>  #include <linux/pci-epf.h>
>  
> +/* DWC PCIe IP-core versions (native support since v4.70a) */
> +#define DW_PCIE_VER_365A		0x3336352a
> +#define DW_PCIE_VER_460A		0x3436302a
> +#define DW_PCIE_VER_470A		0x3437302a
> +#define DW_PCIE_VER_480A		0x3438302a
> +#define DW_PCIE_VER_490A		0x3439302a
> +#define DW_PCIE_VER_520A		0x3532302a

Create a macro to form these so we can do:

DW_PCIE_VER('5', '2', '0', 'A')

> +
>  /* Parameters for the waiting for link up routine */
>  #define LINK_WAIT_MAX_RETRIES		10
>  #define LINK_WAIT_USLEEP_MIN		90000
> @@ -269,7 +277,7 @@ struct dw_pcie {
>  	struct pcie_port	pp;
>  	struct dw_pcie_ep	ep;
>  	const struct dw_pcie_ops *ops;
> -	unsigned int		version;
> +	u32			version;
>  	int			num_lanes;
>  	int			link_gen;
>  	u8			n_fts[2];
> diff --git a/drivers/pci/controller/dwc/pcie-intel-gw.c b/drivers/pci/controller/dwc/pcie-intel-gw.c
> index 5ba144924ff8..786af2ba379f 100644
> --- a/drivers/pci/controller/dwc/pcie-intel-gw.c
> +++ b/drivers/pci/controller/dwc/pcie-intel-gw.c
> @@ -59,7 +59,7 @@
>  #define RESET_INTERVAL_MS		100
>  
>  struct intel_pcie_soc {
> -	unsigned int	pcie_ver;
> +	u32	pcie_ver;
>  };
>  
>  struct intel_pcie {
> @@ -395,7 +395,7 @@ static const struct dw_pcie_host_ops intel_pcie_dw_ops = {
>  };
>  
>  static const struct intel_pcie_soc pcie_data = {
> -	.pcie_ver =		0x520A,
> +	.pcie_ver =		DW_PCIE_VER_520A,
>  };
>  
>  static int intel_pcie_probe(struct platform_device *pdev)
> diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c
> index b1b5f836a806..6f1330ed63e5 100644
> --- a/drivers/pci/controller/dwc/pcie-tegra194.c
> +++ b/drivers/pci/controller/dwc/pcie-tegra194.c
> @@ -1981,7 +1981,7 @@ static int tegra194_pcie_probe(struct platform_device *pdev)
>  	pci->ops = &tegra_dw_pcie_ops;
>  	pci->n_fts[0] = N_FTS_VAL;
>  	pci->n_fts[1] = FTS_VAL;
> -	pci->version = 0x490A;
> +	pci->version = DW_PCIE_VER_490A;
>  
>  	pp = &pci->pp;
>  	pp->num_vectors = MAX_MSI_IRQS;
> -- 
> 2.35.1
> 

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 05/16] PCI: dwc: Add IP-core version detection procedure
  2022-03-24  1:37 ` [PATCH 05/16] PCI: dwc: Add IP-core version detection procedure Serge Semin
@ 2022-03-29 15:08   ` Rob Herring
  2022-04-17 15:13     ` Serge Semin
  0 siblings, 1 reply; 40+ messages in thread
From: Rob Herring @ 2022-03-29 15:08 UTC (permalink / raw)
  To: Serge Semin
  Cc: Jingoo Han, Gustavo Pimentel, Bjorn Helgaas, Lorenzo Pieralisi,
	Krzysztof Wilczyński, Serge Semin, Alexey Malahov,
	Pavel Parkhomenko, Frank Li, Manivannan Sadhasivam, linux-pci,
	devicetree, linux-kernel

On Thu, Mar 24, 2022 at 04:37:23AM +0300, Serge Semin wrote:
> Since DWC PCIe v4.70a the controller version and version type can be read
> from the PORT_LOGIC.PCIE_VERSION_OFF and PORT_LOGIC.PCIE_VERSION_TYPE_OFF
> registers respectively. Seeing the generic code has got version-dependent
> parts let's use these registers to find out the controller version.  The
> detection procedure is executed for both RC and EP modes right after the
> platform-specific initialization. We can't do that earlier since the
> glue-drivers can perform the DBI-related setups there including the bus
> reference clocks activation, without which the CSRs just can't be read.
> 
> Note the CSRs content is zero on the older DWC PCIe controller. In that
> case we have no choice but to rely on the platform setup.
> 
> Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> ---
>  .../pci/controller/dwc/pcie-designware-ep.c   |  2 ++
>  .../pci/controller/dwc/pcie-designware-host.c |  2 ++
>  drivers/pci/controller/dwc/pcie-designware.c  | 24 +++++++++++++++++++
>  drivers/pci/controller/dwc/pcie-designware.h  |  6 +++++
>  4 files changed, 34 insertions(+)
> 
> diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c
> index 7c9315fffe24..3b981d13cca9 100644
> --- a/drivers/pci/controller/dwc/pcie-designware-ep.c
> +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c
> @@ -645,6 +645,8 @@ int dw_pcie_ep_init_complete(struct dw_pcie_ep *ep)
>  	u32 reg;
>  	int i;
>  
> +	dw_pcie_version_detect(pci);
> +
>  	hdr_type = dw_pcie_readb_dbi(pci, PCI_HEADER_TYPE) &
>  		   PCI_HEADER_TYPE_MASK;
>  	if (hdr_type != PCI_HEADER_TYPE_NORMAL) {
> diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c
> index 8364ea234e88..8f0d473ff770 100644
> --- a/drivers/pci/controller/dwc/pcie-designware-host.c
> +++ b/drivers/pci/controller/dwc/pcie-designware-host.c
> @@ -398,6 +398,8 @@ int dw_pcie_host_init(struct pcie_port *pp)
>  		}
>  	}
>  
> +	dw_pcie_version_detect(pci);
> +
>  	dw_pcie_iatu_detect(pci);
>  
>  	dw_pcie_setup_rc(pp);
> diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c
> index c21373c6cb51..49c494d82042 100644
> --- a/drivers/pci/controller/dwc/pcie-designware.c
> +++ b/drivers/pci/controller/dwc/pcie-designware.c
> @@ -16,6 +16,30 @@
>  #include "../../pci.h"
>  #include "pcie-designware.h"
>  
> +void dw_pcie_version_detect(struct dw_pcie *pci)
> +{
> +	u32 ver;
> +
> +	/* The content of the CSR is zero on DWC PCIe older than v4.70a */
> +	ver = dw_pcie_readl_dbi(pci, PCIE_VERSION_NUMBER);
> +	if (!ver)
> +		return;
> +
> +	if (pci->version && pci->version != ver)
> +		dev_warn(pci->dev, "Versions don't match (%08x != %08x)\n",
> +			 pci->version, ver);

Trust the h/w is correct until we have a known case where it isn't. Just 
read the h/w reg if pci->version is zero.

I would suspect as-is this will give some warnings. No doubt there is 
some platform with multiple revs of Si that didn't change their version 
in the driver. Or the author just guessed on the version that picked the 
right paths in the driver.

Rob

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 08/16] PCI: dwc: Drop inbound iATU types enumeration - dw_pcie_as_type
  2022-03-24  1:37 ` [PATCH 08/16] PCI: dwc: Drop inbound iATU types enumeration - dw_pcie_as_type Serge Semin
@ 2022-03-29 15:16   ` Rob Herring
  0 siblings, 0 replies; 40+ messages in thread
From: Rob Herring @ 2022-03-29 15:16 UTC (permalink / raw)
  To: Serge Semin
  Cc: Jingoo Han, Gustavo Pimentel, Bjorn Helgaas, Lorenzo Pieralisi,
	Krzysztof Wilczyński, Serge Semin, Alexey Malahov,
	Pavel Parkhomenko, Frank Li, Manivannan Sadhasivam, linux-pci,
	devicetree, linux-kernel

On Thu, Mar 24, 2022 at 04:37:26AM +0300, Serge Semin wrote:
> There is no point in having an enumeration declared in the driver for the
> PCIe end-point. First of all it's redundant since the driver already has a
> set of macro declared which describe the available in/out iATU types, thus
> having an addition abstraction just needlessly complicates the code.
> Secondly checking the passed iATU type for validity within a single driver
> is pointless since the driver is supposed to be consistent by its nature.
> Finally the outbound iATU type isn't encoded by the denoted enumeration,
> thus giving a false impression that the in and out iATU types are
> unrelated while they are the same. So to speak let's drop the redundant
> dw_pcie_as_type enumeration replacing it with the direct iATU type usage.
> 
> While at it, since we are touching the iATU inbound regions config methods
> anyway, let's fix the arguments order so the type would be followed by the
> address-related parameters. Thus the inbound and outbound iATU setup
> methods will look alike. That shall improve the code readability a bit.
> 
> Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> ---
>  .../pci/controller/dwc/pcie-designware-ep.c   | 21 +++++------
>  drivers/pci/controller/dwc/pcie-designware.c  | 35 +++----------------
>  drivers/pci/controller/dwc/pcie-designware.h  |  9 +----
>  3 files changed, 15 insertions(+), 50 deletions(-)

Reviewed-by: Rob Herring <robh@kernel.org>

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 09/16] PCI: dwc: Simplify in/outbound iATU setup methods
  2022-03-24  1:37 ` [PATCH 09/16] PCI: dwc: Simplify in/outbound iATU setup methods Serge Semin
@ 2022-03-29 15:28   ` Rob Herring
  2022-04-17 20:08     ` Serge Semin
  0 siblings, 1 reply; 40+ messages in thread
From: Rob Herring @ 2022-03-29 15:28 UTC (permalink / raw)
  To: Serge Semin
  Cc: Jingoo Han, Gustavo Pimentel, Bjorn Helgaas, Lorenzo Pieralisi,
	Krzysztof Wilczyński, Serge Semin, Alexey Malahov,
	Pavel Parkhomenko, Frank Li, Manivannan Sadhasivam, linux-pci,
	devicetree, linux-kernel

On Thu, Mar 24, 2022 at 04:37:27AM +0300, Serge Semin wrote:
> From maintainability and scalability points of view it has been wrong to
> use different iATU inbound and outbound regions accessors for the viewport
> and unrolled versions of the iATU CSRs mapping. Seeing the particular iATU
> region-wise registers layout is almost fully compatible for different
> IP-core versions, there were no much points in splitting the code up that
> way since it was possible to implement a common windows setup methods for
> both viewport and unrolled iATU CSRs spaces. While what we can observe in
> the current driver implementation of these methods, is a lot of code
> duplication, which consequently worsen the code readability,
> maintainability and scalability. Note the current implementation is a bit
> more performant than the one suggested in this commit since it implies
> having less MMIO accesses. But the gain just doesn't worth having the
> denoted difficulties especially seeing the iATU setup methods are mainly
> called on the DW PCIe controller and peripheral devices initialization
> stage.
> 
> Here we suggest to move the iATU viewport and unrolled CSR access
> specifics in the dw_pcie_readl_atu() and dw_pcie_writel_atu() method, and
> convert the dw_pcie_prog_outbound_atu() and
> dw_pcie_prog_{ep_}inbound_atu() functions to being generic instead of
> having a different methods for each viewport and unrolled types of iATU
> CSRs mapping. Nothing complex really. First of all the dw_pcie_readl_atu()
> and dw_pcie_writel_atu() are converted to accept relative iATU CSRs
> address together with the iATU region direction (inbound or outbound) and
> region index. If DW PCIe controller doesn't have the unrolled iATU CSRs
> space, then the accessors will need to activate a iATU viewport based on
> the specified direction and index, otherwise a base address for the
> corresponding region CSRs will be calculated by means of the
> PCIE_ATU_UNROLL_BASE() macro. The CSRs macro have been modified in
> accordance with that logic in the pcie-designware.h header file.
> 
> The rest of the changes in this commit just concern converting the iATU
> in-/out-bound setup methods and iATU regions detection procedure to be
> compatible with the new accessors semantics. As a result we've dropped the
> no more required dw_pcie_prog_outbound_atu_unroll(),
> dw_pcie_prog_inbound_atu_unroll() and dw_pcie_iatu_detect_regions_unroll()
> methods.
> 
> Note aside with the denoted code improvements, there is an additional
> positive side effect of this change. If at some point an atomic iATU
> configs setup procedure is required, it will be possible to be done with
> no much effort just by adding the synchronization into the
> dw_pcie_readl_atu() and dw_pcie_writel_atu() accessors.
> 
> Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> ---
>  drivers/pci/controller/dwc/pcie-designware.c | 301 ++++++-------------
>  drivers/pci/controller/dwc/pcie-designware.h |  50 ++-
>  2 files changed, 112 insertions(+), 239 deletions(-)

Nice diffstat. I didn't really like how this was implemented either.

I'm guessing you tested the unrolled case only? IIRC, QEMU has the older 
interface. I can also throw this at kernel-ci if needed. There's a few 
platforms with DWC that get tested.

> 
> diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c
> index b983128584ff..f1aa6e2e85fe 100644
> --- a/drivers/pci/controller/dwc/pcie-designware.c
> +++ b/drivers/pci/controller/dwc/pcie-designware.c
> @@ -205,48 +205,67 @@ void dw_pcie_write_dbi2(struct dw_pcie *pci, u32 reg, size_t size, u32 val)
>  		dev_err(pci->dev, "write DBI address failed\n");
>  }
>  
> -static u32 dw_pcie_readl_atu(struct dw_pcie *pci, u32 reg)
> +static u32 dw_pcie_readl_atu(struct dw_pcie *pci, u32 dir, u32 region, u32 reg)
>  {
> +	void __iomem *base;
>  	int ret;
>  	u32 val;
>  
> +	if (pci->iatu_unroll_enabled) {
> +		base = pci->atu_base;
> +		reg = reg + PCIE_ATU_UNROLL_BASE(dir, region);
> +	} else {
> +		base = pci->dbi_base;
> +		reg = reg + PCIE_ATU_VIEWPORT_BASE;
> +
> +		dw_pcie_writel_dbi(pci, PCIE_ATU_VIEWPORT, dir | region);
> +	}
> +
>  	if (pci->ops && pci->ops->read_dbi)
> -		return pci->ops->read_dbi(pci, pci->atu_base, reg, 4);
> +		return pci->ops->read_dbi(pci, base, reg, 4);
>  
> -	ret = dw_pcie_read(pci->atu_base + reg, 4, &val);
> +	ret = dw_pcie_read(base + reg, 4, &val);
>  	if (ret)
>  		dev_err(pci->dev, "Read ATU address failed\n");
>  
>  	return val;
>  }
>  
> -static void dw_pcie_writel_atu(struct dw_pcie *pci, u32 reg, u32 val)
> +static void dw_pcie_writel_atu(struct dw_pcie *pci, u32 dir, u32 region,
> +			       u32 reg, u32 val)
>  {
> +	void __iomem *base;
>  	int ret;
>  
> +	if (pci->iatu_unroll_enabled) {
> +		base = pci->atu_base;
> +		reg = reg + PCIE_ATU_UNROLL_BASE(dir, region);
> +	} else {
> +		base = pci->dbi_base;
> +		reg = reg + PCIE_ATU_VIEWPORT_BASE;
> +
> +		dw_pcie_writel_dbi(pci, PCIE_ATU_VIEWPORT, dir | region);
> +	}

You have this same sequence twice. Make it a helper function.

> +
>  	if (pci->ops && pci->ops->write_dbi) {
> -		pci->ops->write_dbi(pci, pci->atu_base, reg, 4, val);
> +		pci->ops->write_dbi(pci, base, reg, 4, val);
>  		return;
>  	}
>  
> -	ret = dw_pcie_write(pci->atu_base + reg, 4, val);
> +	ret = dw_pcie_write(base + reg, 4, val);
>  	if (ret)
>  		dev_err(pci->dev, "Write ATU address failed\n");
>  }
>  
> -static u32 dw_pcie_readl_ob_unroll(struct dw_pcie *pci, u32 index, u32 reg)
> +static inline u32 dw_pcie_readl_atu_ob(struct dw_pcie *pci, u32 region, u32 reg)
>  {
> -	u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index);
> -
> -	return dw_pcie_readl_atu(pci, offset + reg);
> +	return dw_pcie_readl_atu(pci, PCIE_ATU_REGION_DIR_OB, region, reg);
>  }
>  
> -static void dw_pcie_writel_ob_unroll(struct dw_pcie *pci, u32 index, u32 reg,
> -				     u32 val)
> +static inline void dw_pcie_writel_atu_ob(struct dw_pcie *pci, u32 region, u32 reg,
> +					 u32 val)
>  {
> -	u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index);
> -
> -	dw_pcie_writel_atu(pci, offset + reg, val);
> +	dw_pcie_writel_atu(pci, PCIE_ATU_REGION_DIR_OB, region, reg, val);
>  }
>  
>  static inline u32 dw_pcie_enable_ecrc(u32 val)
> @@ -290,50 +309,6 @@ static inline u32 dw_pcie_enable_ecrc(u32 val)
>  	return val | PCIE_ATU_TD;
>  }
>  
> -static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, u8 func_no,
> -					     int index, int type,
> -					     u64 cpu_addr, u64 pci_addr,
> -					     u64 size)
> -{
> -	u32 retries, val;
> -	u64 limit_addr = cpu_addr + size - 1;
> -
> -	dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LOWER_BASE,
> -				 lower_32_bits(cpu_addr));
> -	dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_BASE,
> -				 upper_32_bits(cpu_addr));
> -	dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LOWER_LIMIT,
> -				 lower_32_bits(limit_addr));
> -	dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_LIMIT,
> -				 upper_32_bits(limit_addr));
> -	dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LOWER_TARGET,
> -				 lower_32_bits(pci_addr));
> -	dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_TARGET,
> -				 upper_32_bits(pci_addr));
> -	val = type | PCIE_ATU_FUNC_NUM(func_no);
> -	if (upper_32_bits(limit_addr) > upper_32_bits(cpu_addr))
> -		val |= PCIE_ATU_INCREASE_REGION_SIZE;
> -	if (dw_pcie_ver_is(pci, 490A))
> -		val = dw_pcie_enable_ecrc(val);
> -	dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1, val);
> -	dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL2,
> -				 PCIE_ATU_ENABLE);
> -
> -	/*
> -	 * Make sure ATU enable takes effect before any subsequent config
> -	 * and I/O accesses.
> -	 */
> -	for (retries = 0; retries < LINK_WAIT_MAX_IATU_RETRIES; retries++) {
> -		val = dw_pcie_readl_ob_unroll(pci, index,
> -					      PCIE_ATU_UNR_REGION_CTRL2);
> -		if (val & PCIE_ATU_ENABLE)
> -			return;
> -
> -		mdelay(LINK_WAIT_IATU);
> -	}
> -	dev_err(pci->dev, "Outbound iATU is not being enabled\n");
> -}
> -
>  static void __dw_pcie_prog_outbound_atu(struct dw_pcie *pci, u8 func_no,
>  					int index, int type, u64 cpu_addr,
>  					u64 pci_addr, u64 size)
> @@ -344,49 +319,46 @@ static void __dw_pcie_prog_outbound_atu(struct dw_pcie *pci, u8 func_no,
>  	if (pci->ops && pci->ops->cpu_addr_fixup)
>  		cpu_addr = pci->ops->cpu_addr_fixup(pci, cpu_addr);
>  
> -	if (pci->iatu_unroll_enabled) {
> -		dw_pcie_prog_outbound_atu_unroll(pci, func_no, index, type,
> -						 cpu_addr, pci_addr, size);
> -		return;
> -	}
> -
>  	limit_addr = cpu_addr + size - 1;
>  
> -	dw_pcie_writel_dbi(pci, PCIE_ATU_VIEWPORT,
> -			   PCIE_ATU_REGION_OUTBOUND | index);
> -	dw_pcie_writel_dbi(pci, PCIE_ATU_LOWER_BASE,
> -			   lower_32_bits(cpu_addr));
> -	dw_pcie_writel_dbi(pci, PCIE_ATU_UPPER_BASE,
> -			   upper_32_bits(cpu_addr));
> -	dw_pcie_writel_dbi(pci, PCIE_ATU_LIMIT,
> -			   lower_32_bits(limit_addr));
> +	dw_pcie_writel_atu_ob(pci, index, PCIE_ATU_LOWER_BASE,
> +			      lower_32_bits(cpu_addr));
> +	dw_pcie_writel_atu_ob(pci, index, PCIE_ATU_UPPER_BASE,
> +			      upper_32_bits(cpu_addr));
> +
> +	dw_pcie_writel_atu_ob(pci, index, PCIE_ATU_LIMIT,
> +			      lower_32_bits(limit_addr));
>  	if (dw_pcie_ver_is_ge(pci, 460A))
> -		dw_pcie_writel_dbi(pci, PCIE_ATU_UPPER_LIMIT,
> -				   upper_32_bits(limit_addr));
> -	dw_pcie_writel_dbi(pci, PCIE_ATU_LOWER_TARGET,
> -			   lower_32_bits(pci_addr));
> -	dw_pcie_writel_dbi(pci, PCIE_ATU_UPPER_TARGET,
> -			   upper_32_bits(pci_addr));
> +		dw_pcie_writel_atu_ob(pci, index, PCIE_ATU_UPPER_LIMIT,
> +				      upper_32_bits(limit_addr));
> +
> +	dw_pcie_writel_atu_ob(pci, index, PCIE_ATU_LOWER_TARGET,
> +			      lower_32_bits(pci_addr));
> +	dw_pcie_writel_atu_ob(pci, index, PCIE_ATU_UPPER_TARGET,
> +			      upper_32_bits(pci_addr));
> +
>  	val = type | PCIE_ATU_FUNC_NUM(func_no);
>  	if (upper_32_bits(limit_addr) > upper_32_bits(cpu_addr) &&
>  	    dw_pcie_ver_is_ge(pci, 460A))
>  		val |= PCIE_ATU_INCREASE_REGION_SIZE;
>  	if (dw_pcie_ver_is(pci, 490A))
>  		val = dw_pcie_enable_ecrc(val);
> -	dw_pcie_writel_dbi(pci, PCIE_ATU_CR1, val);
> -	dw_pcie_writel_dbi(pci, PCIE_ATU_CR2, PCIE_ATU_ENABLE);
> +	dw_pcie_writel_atu_ob(pci, index, PCIE_ATU_REGION_CTRL1, val);
> +
> +	dw_pcie_writel_atu_ob(pci, index, PCIE_ATU_REGION_CTRL2, PCIE_ATU_ENABLE);
>  
>  	/*
>  	 * Make sure ATU enable takes effect before any subsequent config
>  	 * and I/O accesses.
>  	 */
>  	for (retries = 0; retries < LINK_WAIT_MAX_IATU_RETRIES; retries++) {
> -		val = dw_pcie_readl_dbi(pci, PCIE_ATU_CR2);
> +		val = dw_pcie_readl_atu_ob(pci, index, PCIE_ATU_REGION_CTRL2);
>  		if (val & PCIE_ATU_ENABLE)
>  			return;
>  
>  		mdelay(LINK_WAIT_IATU);
>  	}
> +
>  	dev_err(pci->dev, "Outbound iATU is not being enabled\n");
>  }
>  
> @@ -405,54 +377,15 @@ void dw_pcie_prog_ep_outbound_atu(struct dw_pcie *pci, u8 func_no, int index,
>  				    cpu_addr, pci_addr, size);
>  }
>  
> -static u32 dw_pcie_readl_ib_unroll(struct dw_pcie *pci, u32 index, u32 reg)
> -{
> -	u32 offset = PCIE_GET_ATU_INB_UNR_REG_OFFSET(index);
> -
> -	return dw_pcie_readl_atu(pci, offset + reg);
> -}
> -
> -static void dw_pcie_writel_ib_unroll(struct dw_pcie *pci, u32 index, u32 reg,
> -				     u32 val)
> +static inline u32 dw_pcie_readl_atu_ib(struct dw_pcie *pci, u32 region, u32 reg)
>  {
> -	u32 offset = PCIE_GET_ATU_INB_UNR_REG_OFFSET(index);
> -
> -	dw_pcie_writel_atu(pci, offset + reg, val);
> +	return dw_pcie_readl_atu(pci, PCIE_ATU_REGION_DIR_IB, region, reg);
>  }
>  
> -static int dw_pcie_prog_inbound_atu_unroll(struct dw_pcie *pci, u8 func_no,
> -					   int index, int type,
> -					   u64 cpu_addr, u8 bar)
> +static inline void dw_pcie_writel_atu_ib(struct dw_pcie *pci, u32 region, u32 reg,
> +					 u32 val)
>  {
> -	u32 retries, val;
> -
> -	dw_pcie_writel_ib_unroll(pci, index, PCIE_ATU_UNR_LOWER_TARGET,
> -				 lower_32_bits(cpu_addr));
> -	dw_pcie_writel_ib_unroll(pci, index, PCIE_ATU_UNR_UPPER_TARGET,
> -				 upper_32_bits(cpu_addr));
> -
> -	dw_pcie_writel_ib_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1, type |
> -				 PCIE_ATU_FUNC_NUM(func_no));
> -	dw_pcie_writel_ib_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL2,
> -				 PCIE_ATU_FUNC_NUM_MATCH_EN |
> -				 PCIE_ATU_ENABLE |
> -				 PCIE_ATU_BAR_MODE_ENABLE | (bar << 8));
> -
> -	/*
> -	 * Make sure ATU enable takes effect before any subsequent config
> -	 * and I/O accesses.
> -	 */
> -	for (retries = 0; retries < LINK_WAIT_MAX_IATU_RETRIES; retries++) {
> -		val = dw_pcie_readl_ib_unroll(pci, index,
> -					      PCIE_ATU_UNR_REGION_CTRL2);
> -		if (val & PCIE_ATU_ENABLE)
> -			return 0;
> -
> -		mdelay(LINK_WAIT_IATU);
> -	}
> -	dev_err(pci->dev, "Inbound iATU is not being enabled\n");
> -
> -	return -EBUSY;
> +	dw_pcie_writel_atu(pci, PCIE_ATU_REGION_DIR_IB, region, reg, val);
>  }
>  
>  int dw_pcie_prog_inbound_atu(struct dw_pcie *pci, u8 func_no, int index,
> @@ -460,65 +393,51 @@ int dw_pcie_prog_inbound_atu(struct dw_pcie *pci, u8 func_no, int index,
>  {
>  	u32 retries, val;
>  
> -	if (pci->iatu_unroll_enabled)
> -		return dw_pcie_prog_inbound_atu_unroll(pci, func_no, index, type,
> -						       cpu_addr, bar);
> -
> -	dw_pcie_writel_dbi(pci, PCIE_ATU_VIEWPORT, PCIE_ATU_REGION_INBOUND |
> -			   index);
> -	dw_pcie_writel_dbi(pci, PCIE_ATU_LOWER_TARGET, lower_32_bits(cpu_addr));
> -	dw_pcie_writel_dbi(pci, PCIE_ATU_UPPER_TARGET, upper_32_bits(cpu_addr));
> +	dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_LOWER_TARGET,
> +			      lower_32_bits(cpu_addr));
> +	dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_UPPER_TARGET,
> +			      upper_32_bits(cpu_addr));
>  
> -	dw_pcie_writel_dbi(pci, PCIE_ATU_CR1, type |
> -			   PCIE_ATU_FUNC_NUM(func_no));
> -	dw_pcie_writel_dbi(pci, PCIE_ATU_CR2, PCIE_ATU_ENABLE |
> -			   PCIE_ATU_FUNC_NUM_MATCH_EN |
> -			   PCIE_ATU_BAR_MODE_ENABLE | (bar << 8));
> +	dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_REGION_CTRL1, type |
> +			      PCIE_ATU_FUNC_NUM(func_no));
> +	dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_REGION_CTRL2,
> +			      PCIE_ATU_ENABLE | PCIE_ATU_FUNC_NUM_MATCH_EN |
> +			      PCIE_ATU_BAR_MODE_ENABLE | (bar << 8));
>  
>  	/*
>  	 * Make sure ATU enable takes effect before any subsequent config
>  	 * and I/O accesses.
>  	 */
>  	for (retries = 0; retries < LINK_WAIT_MAX_IATU_RETRIES; retries++) {
> -		val = dw_pcie_readl_dbi(pci, PCIE_ATU_CR2);
> +		val = dw_pcie_readl_atu_ib(pci, index, PCIE_ATU_REGION_CTRL2);
>  		if (val & PCIE_ATU_ENABLE)
>  			return 0;
>  
>  		mdelay(LINK_WAIT_IATU);
>  	}
> +
>  	dev_err(pci->dev, "Inbound iATU is not being enabled\n");
>  
> -	return -EBUSY;
> +	return -ETIMEDOUT;
>  }
>  
>  void dw_pcie_disable_atu(struct dw_pcie *pci, int index,
>  			 enum dw_pcie_region_type type)
>  {
> -	int region;
> +	u32 dir;
>  
>  	switch (type) {
>  	case DW_PCIE_REGION_INBOUND:
> -		region = PCIE_ATU_REGION_INBOUND;
> +		dir = PCIE_ATU_REGION_DIR_IB;

Is this the same double definition with the enum?

>  		break;
>  	case DW_PCIE_REGION_OUTBOUND:
> -		region = PCIE_ATU_REGION_OUTBOUND;
> +		dir = PCIE_ATU_REGION_DIR_OB;
>  		break;
>  	default:
>  		return;
>  	}
>  
> -	if (pci->iatu_unroll_enabled) {
> -		if (region == PCIE_ATU_REGION_INBOUND) {
> -			dw_pcie_writel_ib_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL2,
> -						 ~(u32)PCIE_ATU_ENABLE);
> -		} else {
> -			dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL2,
> -						 ~(u32)PCIE_ATU_ENABLE);
> -		}
> -	} else {
> -		dw_pcie_writel_dbi(pci, PCIE_ATU_VIEWPORT, region | index);
> -		dw_pcie_writel_dbi(pci, PCIE_ATU_CR2, ~(u32)PCIE_ATU_ENABLE);
> -	}
> +	dw_pcie_writel_atu(pci, dir, index, PCIE_ATU_REGION_CTRL2, 0);
>  }
>  
>  int dw_pcie_wait_for_link(struct dw_pcie *pci)
> @@ -622,63 +541,29 @@ static bool dw_pcie_iatu_unroll_enabled(struct dw_pcie *pci)
>  	return false;
>  }
>  
> -static void dw_pcie_iatu_detect_regions_unroll(struct dw_pcie *pci)
> -{
> -	int max_region, i, ob = 0, ib = 0;
> -	u32 val;
> -
> -	max_region = min((int)pci->atu_size / 512, 256);
> -
> -	for (i = 0; i < max_region; i++) {
> -		dw_pcie_writel_ob_unroll(pci, i, PCIE_ATU_UNR_LOWER_TARGET,
> -					0x11110000);
> -
> -		val = dw_pcie_readl_ob_unroll(pci, i, PCIE_ATU_UNR_LOWER_TARGET);
> -		if (val == 0x11110000)
> -			ob++;
> -		else
> -			break;
> -	}
> -
> -	for (i = 0; i < max_region; i++) {
> -		dw_pcie_writel_ib_unroll(pci, i, PCIE_ATU_UNR_LOWER_TARGET,
> -					0x11110000);
> -
> -		val = dw_pcie_readl_ib_unroll(pci, i, PCIE_ATU_UNR_LOWER_TARGET);
> -		if (val == 0x11110000)
> -			ib++;
> -		else
> -			break;
> -	}
> -	pci->num_ib_windows = ib;
> -	pci->num_ob_windows = ob;
> -}
> -
>  static void dw_pcie_iatu_detect_regions(struct dw_pcie *pci)
>  {
> -	int max_region, i, ob = 0, ib = 0;
> +	int max_region, ob, ib;
>  	u32 val;
>  
> -	dw_pcie_writel_dbi(pci, PCIE_ATU_VIEWPORT, 0xFF);
> -	max_region = dw_pcie_readl_dbi(pci, PCIE_ATU_VIEWPORT) + 1;
> +	if (pci->iatu_unroll_enabled) {
> +		max_region = min((int)pci->atu_size / 512, 256);
> +	} else {
> +		dw_pcie_writel_dbi(pci, PCIE_ATU_VIEWPORT, 0xFF);
> +		max_region = dw_pcie_readl_dbi(pci, PCIE_ATU_VIEWPORT) + 1;
> +	}
>  
> -	for (i = 0; i < max_region; i++) {
> -		dw_pcie_writel_dbi(pci, PCIE_ATU_VIEWPORT, PCIE_ATU_REGION_OUTBOUND | i);
> -		dw_pcie_writel_dbi(pci, PCIE_ATU_LOWER_TARGET, 0x11110000);
> -		val = dw_pcie_readl_dbi(pci, PCIE_ATU_LOWER_TARGET);
> -		if (val == 0x11110000)
> -			ob++;
> -		else
> +	for (ob = 0; ob < max_region; ob++) {
> +		dw_pcie_writel_atu_ob(pci, ob, PCIE_ATU_LOWER_TARGET, 0x11110000);
> +		val = dw_pcie_readl_atu_ob(pci, ob, PCIE_ATU_LOWER_TARGET);
> +		if (val != 0x11110000)
>  			break;
>  	}
>  
> -	for (i = 0; i < max_region; i++) {
> -		dw_pcie_writel_dbi(pci, PCIE_ATU_VIEWPORT, PCIE_ATU_REGION_INBOUND | i);
> -		dw_pcie_writel_dbi(pci, PCIE_ATU_LOWER_TARGET, 0x11110000);
> -		val = dw_pcie_readl_dbi(pci, PCIE_ATU_LOWER_TARGET);
> -		if (val == 0x11110000)
> -			ib++;
> -		else
> +	for (ib = 0; ib < max_region; ib++) {
> +		dw_pcie_writel_atu_ib(pci, ib, PCIE_ATU_LOWER_TARGET, 0x11110000);
> +		val = dw_pcie_readl_atu_ib(pci, ib, PCIE_ATU_LOWER_TARGET);
> +		if (val != 0x11110000)
>  			break;
>  	}
>  
> @@ -707,12 +592,10 @@ void dw_pcie_iatu_detect(struct dw_pcie *pci)
>  		if (!pci->atu_size)
>  			/* Pick a minimal default, enough for 8 in and 8 out windows */
>  			pci->atu_size = SZ_4K;
> -
> -		dw_pcie_iatu_detect_regions_unroll(pci);
> -	} else {
> -		dw_pcie_iatu_detect_regions(pci);
>  	}
>  
> +	dw_pcie_iatu_detect_regions(pci);
> +
>  	dev_info(pci->dev, "iATU unroll: %s\n", pci->iatu_unroll_enabled ?
>  		"enabled" : "disabled");
>  
> diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
> index 449c5ad92edc..6adf0c957c3b 100644
> --- a/drivers/pci/controller/dwc/pcie-designware.h
> +++ b/drivers/pci/controller/dwc/pcie-designware.h
> @@ -103,10 +103,20 @@
>  #define PCIE_VERSION_NUMBER		0x8F8
>  #define PCIE_VERSION_TYPE		0x8FC
>  
> +/*
> + * iATU inbound and outbound windows CSRs. Before the IP-core v4.80a each
> + * iATU region CSRs had been indirectly accessible by means of the dedicated
> + * viewport selector. The iATU/eDMA CSRs space was re-designed in DWC PCIe
> + * v4.80a in a way so the viewport was unrolled into the directly accessible
> + * iATU/eDMA CSRs space.

IIRC, I think it is configurable in later versions. There was some 
discussion when I did the detection.

> + */
>  #define PCIE_ATU_VIEWPORT		0x900
> -#define PCIE_ATU_REGION_INBOUND		BIT(31)
> -#define PCIE_ATU_REGION_OUTBOUND	0
> -#define PCIE_ATU_CR1			0x904
> +#define PCIE_ATU_REGION_DIR_IB		BIT(31)
> +#define PCIE_ATU_REGION_DIR_OB		0
> +#define PCIE_ATU_VIEWPORT_BASE		0x904
> +#define PCIE_ATU_UNROLL_BASE(dir, region) \
> +	(((region) << 9) | ((dir == PCIE_ATU_REGION_DIR_IB) ? BIT(8) : 0))
> +#define PCIE_ATU_REGION_CTRL1		0x000
>  #define PCIE_ATU_INCREASE_REGION_SIZE	BIT(13)
>  #define PCIE_ATU_TYPE_MEM		0x0
>  #define PCIE_ATU_TYPE_IO		0x2
> @@ -114,19 +124,19 @@
>  #define PCIE_ATU_TYPE_CFG1		0x5
>  #define PCIE_ATU_TD			BIT(8)
>  #define PCIE_ATU_FUNC_NUM(pf)           ((pf) << 20)
> -#define PCIE_ATU_CR2			0x908
> +#define PCIE_ATU_REGION_CTRL2		0x004
>  #define PCIE_ATU_ENABLE			BIT(31)
>  #define PCIE_ATU_BAR_MODE_ENABLE	BIT(30)
>  #define PCIE_ATU_FUNC_NUM_MATCH_EN      BIT(19)
> -#define PCIE_ATU_LOWER_BASE		0x90C
> -#define PCIE_ATU_UPPER_BASE		0x910
> -#define PCIE_ATU_LIMIT			0x914
> -#define PCIE_ATU_LOWER_TARGET		0x918
> +#define PCIE_ATU_LOWER_BASE		0x008
> +#define PCIE_ATU_UPPER_BASE		0x00C
> +#define PCIE_ATU_LIMIT			0x010
> +#define PCIE_ATU_LOWER_TARGET		0x014
>  #define PCIE_ATU_BUS(x)			FIELD_PREP(GENMASK(31, 24), x)
>  #define PCIE_ATU_DEV(x)			FIELD_PREP(GENMASK(23, 19), x)
>  #define PCIE_ATU_FUNC(x)		FIELD_PREP(GENMASK(18, 16), x)
> -#define PCIE_ATU_UPPER_TARGET		0x91C
> -#define PCIE_ATU_UPPER_LIMIT		0x924
> +#define PCIE_ATU_UPPER_TARGET		0x018
> +#define PCIE_ATU_UPPER_LIMIT		0x020
>  
>  #define PCIE_MISC_CONTROL_1_OFF		0x8BC
>  #define PCIE_DBI_RO_WR_EN		BIT(0)
> @@ -143,19 +153,6 @@
>  
>  #define PCIE_PL_CHK_REG_ERR_ADDR			0xB28
>  
> -/*
> - * iATU Unroll-specific register definitions
> - * From 4.80 core version the address translation will be made by unroll
> - */
> -#define PCIE_ATU_UNR_REGION_CTRL1	0x00
> -#define PCIE_ATU_UNR_REGION_CTRL2	0x04
> -#define PCIE_ATU_UNR_LOWER_BASE		0x08
> -#define PCIE_ATU_UNR_UPPER_BASE		0x0C
> -#define PCIE_ATU_UNR_LOWER_LIMIT	0x10
> -#define PCIE_ATU_UNR_LOWER_TARGET	0x14
> -#define PCIE_ATU_UNR_UPPER_TARGET	0x18
> -#define PCIE_ATU_UNR_UPPER_LIMIT	0x20
> -
>  /*
>   * The default address offset between dbi_base and atu_base. Root controller
>   * drivers are not required to initialize atu_base if the offset matches this
> @@ -164,13 +161,6 @@
>   */
>  #define DEFAULT_DBI_ATU_OFFSET (0x3 << 20)
>  
> -/* Register address builder */
> -#define PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(region) \
> -		((region) << 9)
> -
> -#define PCIE_GET_ATU_INB_UNR_REG_OFFSET(region) \
> -		(((region) << 9) | BIT(8))
> -
>  #define MAX_MSI_IRQS			256
>  #define MAX_MSI_IRQS_PER_CTRL		32
>  #define MAX_MSI_CTRLS			(MAX_MSI_IRQS / MAX_MSI_IRQS_PER_CTRL)
> -- 
> 2.35.1
> 

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 10/16] PCI: dwc: Drop iATU regions enumeration - dw_pcie_region_type
  2022-03-24  1:37 ` [PATCH 10/16] PCI: dwc: Drop iATU regions enumeration - dw_pcie_region_type Serge Semin
@ 2022-03-29 15:31   ` Rob Herring
  2022-04-17 17:52     ` Serge Semin
  0 siblings, 1 reply; 40+ messages in thread
From: Rob Herring @ 2022-03-29 15:31 UTC (permalink / raw)
  To: Serge Semin
  Cc: Jingoo Han, Gustavo Pimentel, Bjorn Helgaas, Lorenzo Pieralisi,
	Krzysztof Wilczyński, Serge Semin, Alexey Malahov,
	Pavel Parkhomenko, Frank Li, Manivannan Sadhasivam, linux-pci,
	devicetree, linux-kernel

On Thu, Mar 24, 2022 at 04:37:28AM +0300, Serge Semin wrote:
> There is no point in having the dw_pcie_region_type enumeration for almost
> the same reasons as it was stated for dw_pcie_as_type. First of all it's
> redundant since the driver already has a set of macro declared which
> describe the possible inbound and outbound iATU regions. Having an
> addition abstraction just needlessly complicates the code. Secondly
> checking the region index passed to the dw_pcie_disable_atu() method for
> validity is pointless since the erroneous situation will be just
> ignored in the current code implementation. So to speak let's drop the
> redundant dw_pcie_region_type enumeration replacing it with the direct
> iATU direction macro usage.
> 
> While at it we suggest to convert the dw_pcie_disable_atu() method to
> being more consistent with the dw_pcie_readl_atu{_ib}() and
> dw_pcie_readl_atu{_ob}() functions by having the direction parameter
> specified ahead of the region index. Thus the code will be a little bit
> more pleasant to read.
> 
> Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> ---
>  drivers/pci/controller/dwc/pcie-designware-ep.c  |  4 ++--
>  .../pci/controller/dwc/pcie-designware-host.c    |  2 +-
>  drivers/pci/controller/dwc/pcie-designware.c     | 16 +---------------
>  drivers/pci/controller/dwc/pcie-designware.h     |  9 +--------
>  4 files changed, 5 insertions(+), 26 deletions(-)

This answers my question. I would have expected this to come before the 
previous patch, but if it's easier to do it this way it's fine.

Reviewed-by: Rob Herring <robh@kernel.org>

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 01/16] dt-bindings: PCI: dwc: Define generic and native DT bindings
  2022-03-28 20:46     ` Rob Herring
  (?)
@ 2022-04-15 16:14       ` Serge Semin
  -1 siblings, 0 replies; 40+ messages in thread
From: Serge Semin @ 2022-04-15 16:14 UTC (permalink / raw)
  To: Rob Herring
  Cc: Serge Semin, Jingoo Han, Gustavo Pimentel, Bjorn Helgaas,
	Richard Zhu, Lucas Stach, Shawn Guo, Sascha Hauer,
	Pengutronix Kernel Team, Fabio Estevam, NXP Linux Team,
	Xiaowei Song, Binghui Wang, Paul Walmsley, Greentime Hu,
	Palmer Dabbelt, Nobuhiro Iwamatsu, Alexey Malahov,
	Pavel Parkhomenko, Lorenzo Pieralisi, Krzysztof Wilczyński,
	Frank Li, Manivannan Sadhasivam, linux-pci, devicetree,
	linux-kernel, linux-arm-kernel, linux-riscv

Hello Rob,

On Mon, Mar 28, 2022 at 03:46:04PM -0500, Rob Herring wrote:
> On Thu, Mar 24, 2022 at 04:37:19AM +0300, Serge Semin wrote:
> > Currently both DW PCIe Root Port and End-point DT bindings are too generic
> > to be used as a descriptive set the device properties. Yes, it's very handy
> > to have them that way so the DT-schemas could be used to evaluate as many
> > DW PCIe-related DT-nodes as possible. But at the same time they don't
> > provide well defined DW PCIe RP/EP DT interface description thus leaving
> > too much flexibility for the new platforms, no encouraging the developers
> > to preserve a compatible interface.
> > 
> > Instead of currently implemented approach we suggest to be more
> > restrictive and yet preserve some level of flexibility in the DW PCIe
> > DT-bindings description. The device tree DT-schema is split up into
> > three parts: a common YAML-schema applicable for both DWC Root Port and
> > End-point controller configs, DWC PCIe Root Port-specific YAML-schema
> > and DWC PCIe End-point-specific YAML-schema, where
> > 1) pci/snps,dw-pcie-common.yaml - The common DT-schema describes the most
> > generic constraints of the "reg", "interrupts", "clocks", "resets" and
> > "phys" properties together with a set of common for both device types
> > PCIe/AXI bus properties like a maximum number of lanes or a maximum link
> > speed, number of inbound and outbound iATU windows. In addition to that a
> > set of schema definitions declared under the "$defs" property with "reg",
> > "interrupt", "clock" and "reset" names common for DWC PCIe Root Port and
> > End-point devices. They can be used by the successive DT-schemas in case
> > they are supposed to be compatible with the generic DWC PCIe controller
> > DT-bindings.
> > 2) pci/snps,dw-pcie.yaml, pci/snps,dw-pcie-ep.yaml - generic DW PCIe Root
> > Port and End-point DT-bindings which aside with the device-specific
> > properties set also contain more restrictive constraints. All new DW PCIe
> > platforms are supposed to be compatible with one of these bindings by
> > using "allOf: " property and additionally defining their own constraints
> > to close up the DT-bindings set.
> > 
> > So to speak in case if a DW PCIe-based device for some reason has too many
> > specific properties or it's bindings have already been defined in a
> > non-generic way, it's DT-schema is supposed to include 1) YAML-file and
> > provide its own constraints. Otherwise the ready-to-use bindings from 2)
> > should be utilized. There only two DT-schemas compatible with 2) at the
> > moment are samsung,axynos-pcie.yaml and intel-gw-pcie.yaml. The
> > rest of the DW PCIe-related DT-schemas are supposed to use more generic
> > DW PCIe DT-bindings - pci/snps,dw-pcie-common.yaml.
> > 
> > Note the provided here generic properties and their possible values are
> > derived from the DW PCIe RC/EP hardware manuals and from the interface
> > implemented in the driver. The DT-bindings schemas are created to be as
> > full as possible with detailed properties/names description for the
> > easier interface comprehension and new platforms bindings development.
> > 
> > Also note since there are no generic DT-nodes can be found in the kernel
> > dts-es which would have a pure "snps,dw-pcie" compatible string, these
> > DT-bindings have been created to not be selected by default for
> > evaluation. They are supposed to be used by the new vendor-specific
> > DT-schemas to at least stop adding new bindings for the same set of DWC
> > PCIe signals or properties.
> > 
> > Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> > 
> > ---
> > 
> > Rob, if you comment the "select: false" line out you'll get a lot of "'*'
> > is not of type 'array'" errors on the dt_bindings_check command execution.
> > I have spend tons of time trying to figure out what was wrong, but still
> > failed to find out a solution. For some reason the "$ref"-ed schemas
> > defined under the "$defs" basic property are considered by the parser as
> > defining an array. No matter whether I specified the "type: string"
> > keyword or not, as long as there is "enum" or "oneOf" keyword used in the
> > "*-names" property definition in "$defs" it's considered as describing an
> > array thus causing the errors like:
> 
> As-is, there were lots of errors...
> 
> > 
> > >  DTC     Documentation/devicetree/bindings/pci/snps,dw-pcie.example.dt.yaml
> > >  CHECK   Documentation/devicetree/bindings/pci/snps,dw-pcie.example.dt.yaml
> > > /.../snps,dw-pcie.example.dt.yaml: pcie@1f052000: reg-names:0: 'oneOf' conditional failed, one must be fixed:
> > >        'dbi' is not of type 'array'
> > >        From schema: /.../snps,dw-pcie.yaml
> > > /.../snps,dw-pcie.example.dt.yaml: pcie@1f052000: reg-names:1: 'oneOf' conditional failed, one must be fixed:
> > >         'config' is not of type 'array'
> > >         From schema: /.../snps,dw-pcie.yaml
> > > /.../snps,dw-pcie.example.dt.yaml: pcie@1f052000: interrupt-names:0: 'anyOf' conditional failed, one must be fixed:
> > >         /.../snps,dw-pcie.example.dt.yaml: pcie@1f052000: interrupt-names:0: 'oneOf' conditional failed, one must be fixed:
> > >                 'msi' is not of type 'array'
> > >         /../snps,dw-pcie.example.dt.yaml: pcie@1f052000: interrupt-names:0: 'oneOf' conditional failed, one must be fixed:
> > >                 'msi' is not of type 'array'
> > >         From schema: /.../snps,dw-pcie.yaml
> > 
> > As soon as I manually moved the same "$defs"-schemas into the places they
> > are referenced to, the errors disappeared and the DT-schemas validation
> > worked as expected by the semantics.
> > 
> > As I see it there must be some bug in the parser, otherwise I am out of
> > ideas how to implement the suggested in this patch design pattern. Rob,
> > could you take a look at the DT-schemas and help me out with debugging the
> > problem described above?
> 

> There is at least an error in your schema, details latter on.

It depends on the schema usage. Please see my next comments for the
detailed explanation what I am trying to achieve here and why it would
be very useful.

> 
> It could be an issue in the fixups which in general convert 
> schemas for strings to string arrays and scalars/arrays to matrix. You 
> have to look at processed-schema.json to debug it.
> 
> The other thing is 'oneOf' errors can be confusing in terms of error 
> messages because the tooling doesn't really know which entry had the 
> least error. Like the type was right, but some secondary constraint 
> failed (as what's secondary is not expressed in any way).
> 
> I would debug it further, but I don't really like the end result. I 
> think it's too hard to follow. For the most part, we avoid $refs at the 
> property level across different schema files with the big exception 
> being types.yaml. $defs are also used sparingly. The challenge is that 
> json-schema by default will be silent on schemas misformed in lots of 
> ways. Our meta-schema adds a lot of constraints which limits what the 
> schemas can look like and ensures schemas are valid. It also allows me 
> to define new constraints rather than repeat the same review comment 
> over and over.

I see your point, but in this case I suppose an exception would gain
good benefits too. Here is why.

As I said in the patch log the main idea of this modification was to
create a common schema for the DW PCIe compatible controllers which would
be more restrictive than the existing one but more descriptive and yet
extendable if required. So using $refs was the best method for such
case.

In the framework of this patch aside with a set of the generic DW PCIe
properties, I tried to implement the schemas for the string array with
a pre-defined set values. These schemas can be used to set the
constraints on the device-specific bindings or can be omitted if
either the bindings have already been defined in a different way or
the device is incompatible with the generic bindings for some reason.
Please see the schemas defined in the pci/snps,dw-pcie-common.yaml
file.

As you can see mainly the snps,dw-pcie-common.yaml schema contains the
normal properties descriptions like 'reg', 'clocks', 'interrupts',
'resets', etc. The only peculiarity is the sub-properties defined under
the "$defs" property. See, they aren't used in that file, but are
referenced in the snps,dw-pcie-ep.yaml and snps,dw-pcie.yaml schemas in
order to create the corresponding string arrays constraints. See my
next comments for the further explanation.

> 
> > ---
> >  .../bindings/pci/fsl,imx6q-pcie.yaml          |   5 +-
> >  .../bindings/pci/hisilicon,kirin-pcie.yaml    |   4 +-
> >  .../bindings/pci/sifive,fu740-pcie.yaml       |   4 +-
> >  .../bindings/pci/snps,dw-pcie-common.yaml     | 298 ++++++++++++++++++
> >  .../bindings/pci/snps,dw-pcie-ep.yaml         | 143 ++++++---
> >  .../devicetree/bindings/pci/snps,dw-pcie.yaml | 189 +++++++----
> >  .../bindings/pci/toshiba,visconti-pcie.yaml   |   2 +-
> >  7 files changed, 524 insertions(+), 121 deletions(-)
> >  create mode 100644 Documentation/devicetree/bindings/pci/snps,dw-pcie-common.yaml
> 
> 
> > diff --git a/Documentation/devicetree/bindings/pci/snps,dw-pcie-common.yaml b/Documentation/devicetree/bindings/pci/snps,dw-pcie-common.yaml
> > new file mode 100644
> > index 000000000000..27fe1f5c450f
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/pci/snps,dw-pcie-common.yaml
> > @@ -0,0 +1,298 @@
> > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> > +%YAML 1.2
> > +---
> > +$id: http://devicetree.org/schemas/pci/snps,dw-pcie-common.yaml#
> > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > +
> > +title: Synopsys DWC PCIe RP/EP controller
> > +
> > +maintainers:
> > +  - Jingoo Han <jingoohan1@gmail.com>
> > +  - Gustavo Pimentel <gustavo.pimentel@synopsys.com>
> > +
> > +properties:
> > +  reg:
> > +    description:
> > +      DWC PCIe CSR space is normally accessed over the dedicated Data Bus
> > +      Interface - DBI. In accordance with the reference manual the register
> > +      configuration space belongs to the Configuration-Dependent Module (CDM)
> > +      and is split up into several sub-parts Standard PCIe configuration
> > +      space, Port Logic Registers (PL), Shadow Config-space Registers,
> > +      iATU/eDMA registers. The particular sub-space is selected by the
> > +      CDM/ELBI (dbi_cs) and CS2 (dbi_cs2) signals (selector bits). Such
> > +      configuration provides a flexible interface for the system engineers to
> > +      either map the particular space at a desired MMIO address or just leave
> > +      them in a contiguous memory space if pure Native or AXI Bridge DBI access
> > +      is selected. Note the PCIe CFG-space, PL and Shadow registers are
> > +      specific to each activated function, while the rest of the sub-spaces
> > +      are common for all of them (if there are more than one).
> > +    minItems: 2
> > +    maxItems: 6
> > +
> > +  interrupts:
> > +    description:
> > +      There are two main sub-blocks which are normally capable of
> > +      generating interrupts. It's System Information Interface and MSI
> > +      interface. While the former one has some common for the Host and
> > +      End-point controllers IRQ-signals, the later interface is obviously
> > +      Root Complex specific since it's responsible for the incoming MSI
> > +      messages signalling. The System Information IRQ signals are mainly
> > +      responsible for reporting the generic PCIe hierarchy and Root
> > +      Complex events like VPD IO request, general AER, PME, Hot-plug, link
> > +      bandwidth change, link equalization request, INTx asserted/deasserted
> > +      Message detection, embedded DMA Tx/Rx/Error.
> > +    minItems: 1
> > +    maxItems: 26
> > +
> > +  clocks:
> > +    description:
> > +      DWC PCIe reference manual explicitly defines a set of the clocks required
> > +      to get the controller working correctly. In general all of them can
> > +      be divided into two groups':' application and core clocks. Note the
> > +      platforms may have some of the clock sources unspecified in case if the
> > +      corresponding domains are fed up from a common clock source.
> > +    minItems: 1
> > +    maxItems: 7
> > +
> > +  resets:
> > +    description:
> > +      DWC PCIe reference manual explicitly defines a set of the reset
> > +      signals required to be de-asserted to properly activate the controller
> > +      sub-parts. All of these signals can be divided into two sub-groups':'
> > +      application and core resets with respect to the main sub-domains they
> > +      are supposed to reset. Note the platforms may have some of these signals
> > +      unspecified in case if they are automatically handled or aggregated into
> > +      a comprehensive control module.
> > +    minItems: 1
> > +    maxItems: 10
> > +
> > +  reset-gpio:
> > +    deprecated: true
> > +    description:
> > +      Reference to the GPIO-controlled PERST# signal. It is used to reset all
> > +      the peripheral devices available on the PCIe bus.
> > +    maxItems: 1
> > +
> > +  reset-gpios:
> > +    description:
> > +      Reference to the GPIO-controlled PERST# signal. It is used to reset all
> > +      the peripheral devices available on the PCIe bus.
> > +    maxItems: 1
> > +
> > +  phys:
> > +    description:
> > +      There can be up to number of possible lanes PHYs specified.
> > +      Obviously each specified PHY is supposed to be able to work in the
> > +      PCIe mode with a speed implied by the DWC PCIe controller it is
> > +      attached to.
> > +    minItems: 1
> > +    maxItems: 16
> > +
> > +  phy-names:
> > +    minItems: 1
> > +    maxItems: 16
> > +    items:
> > +      pattern: '^pcie([0-9]+|-?phy)?$'
> > +
> > +  num-lanes:
> > +    maximum: 16
> > +
> > +  max-link-speed:
> > +    maximum: 4
> > +
> > +  num-ob-windows:
> > +    $ref: /schemas/types.yaml#/definitions/uint32
> > +    deprecated: true
> > +    description:
> > +      Number of outbound address translation windows. This parameter can be
> > +      auto-detected based on the iATU memory writability. So there is no
> > +      point in having a dedicated DT-property for it.
> > +    maximum: 256
> > +
> > +  num-ib-windows:
> > +    $ref: /schemas/types.yaml#/definitions/uint32
> > +    deprecated: true
> > +    description:
> > +      Number of inbound address translation windows. In the same way as
> > +      for the outbound AT windows, this parameter can be auto-detected based
> > +      on the iATU memory writability. There is no point having a dedicated
> > +      DT-property for it either.
> > +    maximum: 256
> > +
> > +  num-viewport:
> > +    $ref: /schemas/types.yaml#/definitions/uint32
> > +    deprecated: true
> > +    description:
> > +      Number of outbound view ports configured in hardware. It's the same as
> > +      the number of outbound AT windows.
> > +    maximum: 256
> > +
> > +  snps,enable-cdm-check:
> > +    $ref: /schemas/types.yaml#/definitions/flag
> > +    description:
> > +      Enable automatic checking of CDM (Configuration Dependent Module)
> > +      registers for data corruption. CDM registers include standard PCIe
> > +      configuration space registers, Port Logic registers, DMA and iATU
> > +      registers. This feature has been available since DWC PCIe v4.80a.
> > +
> > +additionalProperties: true
> > +
> > +$defs:
> > +  reg-names:
> > +    description:
> > +      CSR space names common for the DWC PCIe Root Port and End-point
> > +      controllers.
> > +    oneOf:
> > +      - description:
> > +          Basic DWC PCIe controller configuration-space accessible over
> > +          the DBI interface. This memory space is either activated with
> > +          the CDM/ELBI = 0 and CS2 = 0 or is a contiguous memory region
> > +          with all spaces. Note iATU/eDMA CSRs are indirectly accessible
> > +          via the PL viewports on the DWC PCIe controllers older than
> > +          v4.80a.
> > +        const: dbi
> 

> This passes only for 'reg-names = "dbi";'

No, if the defined here "reg-names" schema is correctly referenced. See my
next comments.

> 
> > +      - description:
> > +          Shadow DWC PCIe config-space registers. This space is selected
> > +          by setting CDM/ELBI = 0 and CS2 = 1. This is an intermix of
> > +          the PCI-SIG PCIe CFG-space with the shadow registers for some
> > +          PCI Header space, PCI Standard and Extended Structures. It's
> > +          mainly relevant for the end-point controller configuration,
> > +          but still there are some shadow registers available for the
> > +          Root Port mode too.
> > +        const: dbi2
> 

> This passes only for 'reg-names = "dbi2";'

ditto

> 
> > +      - description:
> > +          External Local Bus registers. It's an application-dependent
> > +          registers normally defined by the platform engineers, which
> > +          are selected by setting CDM/ELBI = 1 and CS2 = 0.
> > +        enum: [ elbi, appl, app ]
> 

> This passes only for 'reg-names = "elbi", "appl", "app";'
> 
> See the problem? Replacing the 'oneOf' above with 'items' is what you 
> want. But then the schema will not allow any missing entries either. 
> DBI2 is optional for example. There is no way in json-schema to define a 
> list of ordered values(string) once and say some entries are optional 
> which I think is what you are trying to do here.

Please see the way the "$defs: *-names" properties are referenced in
the framework of this patch. My idea was to define a set of strings in
the "$defs: *-names" properties here. Then re-use that set to define
the device-specific constraints. That's why I've intentionally used
'oneOf'-based composition so the properties could be used to set a
constraints on !each! item of the corresponding strings array, but not
on the whole array as you suggest by replacing 'oneOf' with 'items'.
BTW the ordering can be defined in the corresponding schemas if it's
required. 

As an example please see the json schema of the generic DWC
PCIe End-point reg-names property I am trying to achieve here:
https://www.jsonschemavalidator.net/s/eGV3M3gK

As you can see it makes sure the reg-names array contains at least
the "dbi", "dbi2" and "addr_space" strings and may also have the
optional CSR names if it's specific to the corresponding platform.

If you need the ordered set of the strings then the next schema
can be used:
https://www.jsonschemavalidator.net/s/53KKrXV9

Regarding the ordering. As I see it, it isn't something what we need
in the modern bindings in the reference to the "*-names" properties
since the new drivers mainly rely on getting the CSR maps, interrupts,
clocks and resets by their names rather than a position in the 'reg'
phandles array. The CSRs order isn't something what hardware defines
either. Moreover tons of the DT source files don't really have the
reg-names, clock-names, etc properties initialized with some strict
order. So if we want the schema to be applicable for the already
created DT sources the ordering constraints need to be avoided.

Getting back to the patch. As I said in the patch log, alas I failed
to reproduce the described schema in the DT bindings due to the
denoted error. Seeing the JSON-schema examples are working and so does
the DT-schema parser if I manually move the "$defs: *-names" schemas
content in the place of the references, there must be some problem
with the parser. That's why I asked your help with debugging.

> 
> > +      - description:
> > +          iATU/eDMA registers common for all device functions. It's an
> > +          unrolled memory space with the internal Address Translation
> > +          Unit and Enhanced DMA, which is selected by setting CDM/ELBI = 1
> > +          and CS2 = 1. For IP-core releases prior v4.80a, these registers
> > +          have been programmed via an indirect addressing scheme using a
> > +          set of viewport CSRs mapped into the PL space. Note iATU is
> > +          normally mapped to the 0x0 address of this region, while eDMA
> > +          is available at 0x80000 base address.
> > +        enum: [ atu, atu_dma ]
> > +      - description:
> > +          Outbound iATU-available memory-region which usage scenario
> > +          depends on the DWC PCIe controller being either Root Port or
> > +          End-point. If it's Root Port then the register space shall
> > +          have the "config" name and it will be used to access the
> > +          peripheral PCIe devices configuration space. If it's PCIe
> > +          end-point controller, then the region shall be named as
> > +          "addr_space" and it will be used to generate various traffic
> > +          on the PCIe bus hierarchy. It's usage scenario depends on the
> > +          end-point functionality, for instance it can be used to create
> > +          MSI(X) messages.
> > +        enum: [ config, addr_space ]
> 

> So 'addr_space' is now valid for host mode?

Well, in general this reg-space is supposed to be of the same memory
space type - outbound iATU sub-region - for both Host and End-point
controller, but the names are different for them. Anyway basically you
are right, the schemas referencing this property will permit having
both reg names. I can split this property up into two: "$defs:
host-reg-names" and "$defs: ep-reg-names" and use the new schemas in
the Host and EP reg-names property constraints respectively. What do
you think?

> 
> (Really, for DW blocks with iATU, this should have been the whole memory 
> space and the driver could size the config space itself. (IOW, the 
> config region is configuration rather than h/w description.)

I am fully agree with you but the addr/config-space reg-bindings have
already been defined that way. It is implemented in the DWC PCIe driver
and many DT files rely on having that bindings implemented. So alas
nothing we can do about it.

> 
> > +      - description:
> > +          PHY/PCS configuration registers. Some platforms can have the
> > +          PCS and PHY CSRs accessible over a dedicated memory mapped
> > +          region, but mainly these registers are indirectly accessible
> > +          either by means of the embedded PHY viewport schema or by some
> > +          platform-specific method.
> > +        enum: [ link, phy ]
> 

> These should not be in any new users as the phy should be separate.

I agree, but these names have already been referenced in some glue
drivers so does the DW PCIe Host/EP manual have the PHY/PCS CSRs IO
interface described. Thus we have to have them described here for the
sake of compatibility.

> 
> > +
> > +  interrupt-names:
> > +    description:
> > +      IRQ signal names common for the DWC PCIe Root Port and End-point
> > +      controllers.
> > +    oneOf:
> > +      - description:
> > +          Controller request to read or write virtual product data
> > +          from/to the VPD capability registers.
> > +        const: vpd
> > +      - description:
> > +          Link Equalization Request flag is set in the Link Status 2
> > +          register (applicable if the corresponding IRQ is enabled in
> > +          the Link Control 3 register).
> > +        const: l_eq
> > +      - description:
> > +          Indicates that the eDMA Tx/Rx transfer is complete or that an
> > +          error has occurred on the corresponding channel. eDMA can have
> > +          eight Tx (Write) and Rx (Read) eDMA channels thus supporting up
> > +          to 16 IRQ signals all together. Write eDMA channels shall go
> > +          first in the ordered row as per default edma_int[*] bus setup.
> > +        pattern: '^dma([0-9]|1[0-5])?$'
> > +      - description:
> > +          PCIe protocol correctable error or a Data Path protection
> > +          correctable error is detected by the automotive/safety
> > +          feature.
> > +        const: sft_ce
> > +      - description:
> > +          Indicates that the internal safety mechanism detected and
> > +          uncorrectable error.
> > +        const: sft_ue
> 

> This says there is only a single interrupt entry. Same for the other 
> $defs.

No, this property is supposed to be considered as applicable to each
"interrupt-names" item, not for the whole array. Please see my comments
before.

-Sergey

> 
> Rob

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 01/16] dt-bindings: PCI: dwc: Define generic and native DT bindings
@ 2022-04-15 16:14       ` Serge Semin
  0 siblings, 0 replies; 40+ messages in thread
From: Serge Semin @ 2022-04-15 16:14 UTC (permalink / raw)
  To: Rob Herring
  Cc: Serge Semin, Jingoo Han, Gustavo Pimentel, Bjorn Helgaas,
	Richard Zhu, Lucas Stach, Shawn Guo, Sascha Hauer,
	Pengutronix Kernel Team, Fabio Estevam, NXP Linux Team,
	Xiaowei Song, Binghui Wang, Paul Walmsley, Greentime Hu,
	Palmer Dabbelt, Nobuhiro Iwamatsu, Alexey Malahov,
	Pavel Parkhomenko, Lorenzo Pieralisi, Krzysztof Wilczyński,
	Frank Li, Manivannan Sadhasivam, linux-pci, devicetree,
	linux-kernel, linux-arm-kernel, linux-riscv

Hello Rob,

On Mon, Mar 28, 2022 at 03:46:04PM -0500, Rob Herring wrote:
> On Thu, Mar 24, 2022 at 04:37:19AM +0300, Serge Semin wrote:
> > Currently both DW PCIe Root Port and End-point DT bindings are too generic
> > to be used as a descriptive set the device properties. Yes, it's very handy
> > to have them that way so the DT-schemas could be used to evaluate as many
> > DW PCIe-related DT-nodes as possible. But at the same time they don't
> > provide well defined DW PCIe RP/EP DT interface description thus leaving
> > too much flexibility for the new platforms, no encouraging the developers
> > to preserve a compatible interface.
> > 
> > Instead of currently implemented approach we suggest to be more
> > restrictive and yet preserve some level of flexibility in the DW PCIe
> > DT-bindings description. The device tree DT-schema is split up into
> > three parts: a common YAML-schema applicable for both DWC Root Port and
> > End-point controller configs, DWC PCIe Root Port-specific YAML-schema
> > and DWC PCIe End-point-specific YAML-schema, where
> > 1) pci/snps,dw-pcie-common.yaml - The common DT-schema describes the most
> > generic constraints of the "reg", "interrupts", "clocks", "resets" and
> > "phys" properties together with a set of common for both device types
> > PCIe/AXI bus properties like a maximum number of lanes or a maximum link
> > speed, number of inbound and outbound iATU windows. In addition to that a
> > set of schema definitions declared under the "$defs" property with "reg",
> > "interrupt", "clock" and "reset" names common for DWC PCIe Root Port and
> > End-point devices. They can be used by the successive DT-schemas in case
> > they are supposed to be compatible with the generic DWC PCIe controller
> > DT-bindings.
> > 2) pci/snps,dw-pcie.yaml, pci/snps,dw-pcie-ep.yaml - generic DW PCIe Root
> > Port and End-point DT-bindings which aside with the device-specific
> > properties set also contain more restrictive constraints. All new DW PCIe
> > platforms are supposed to be compatible with one of these bindings by
> > using "allOf: " property and additionally defining their own constraints
> > to close up the DT-bindings set.
> > 
> > So to speak in case if a DW PCIe-based device for some reason has too many
> > specific properties or it's bindings have already been defined in a
> > non-generic way, it's DT-schema is supposed to include 1) YAML-file and
> > provide its own constraints. Otherwise the ready-to-use bindings from 2)
> > should be utilized. There only two DT-schemas compatible with 2) at the
> > moment are samsung,axynos-pcie.yaml and intel-gw-pcie.yaml. The
> > rest of the DW PCIe-related DT-schemas are supposed to use more generic
> > DW PCIe DT-bindings - pci/snps,dw-pcie-common.yaml.
> > 
> > Note the provided here generic properties and their possible values are
> > derived from the DW PCIe RC/EP hardware manuals and from the interface
> > implemented in the driver. The DT-bindings schemas are created to be as
> > full as possible with detailed properties/names description for the
> > easier interface comprehension and new platforms bindings development.
> > 
> > Also note since there are no generic DT-nodes can be found in the kernel
> > dts-es which would have a pure "snps,dw-pcie" compatible string, these
> > DT-bindings have been created to not be selected by default for
> > evaluation. They are supposed to be used by the new vendor-specific
> > DT-schemas to at least stop adding new bindings for the same set of DWC
> > PCIe signals or properties.
> > 
> > Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> > 
> > ---
> > 
> > Rob, if you comment the "select: false" line out you'll get a lot of "'*'
> > is not of type 'array'" errors on the dt_bindings_check command execution.
> > I have spend tons of time trying to figure out what was wrong, but still
> > failed to find out a solution. For some reason the "$ref"-ed schemas
> > defined under the "$defs" basic property are considered by the parser as
> > defining an array. No matter whether I specified the "type: string"
> > keyword or not, as long as there is "enum" or "oneOf" keyword used in the
> > "*-names" property definition in "$defs" it's considered as describing an
> > array thus causing the errors like:
> 
> As-is, there were lots of errors...
> 
> > 
> > >  DTC     Documentation/devicetree/bindings/pci/snps,dw-pcie.example.dt.yaml
> > >  CHECK   Documentation/devicetree/bindings/pci/snps,dw-pcie.example.dt.yaml
> > > /.../snps,dw-pcie.example.dt.yaml: pcie@1f052000: reg-names:0: 'oneOf' conditional failed, one must be fixed:
> > >        'dbi' is not of type 'array'
> > >        From schema: /.../snps,dw-pcie.yaml
> > > /.../snps,dw-pcie.example.dt.yaml: pcie@1f052000: reg-names:1: 'oneOf' conditional failed, one must be fixed:
> > >         'config' is not of type 'array'
> > >         From schema: /.../snps,dw-pcie.yaml
> > > /.../snps,dw-pcie.example.dt.yaml: pcie@1f052000: interrupt-names:0: 'anyOf' conditional failed, one must be fixed:
> > >         /.../snps,dw-pcie.example.dt.yaml: pcie@1f052000: interrupt-names:0: 'oneOf' conditional failed, one must be fixed:
> > >                 'msi' is not of type 'array'
> > >         /../snps,dw-pcie.example.dt.yaml: pcie@1f052000: interrupt-names:0: 'oneOf' conditional failed, one must be fixed:
> > >                 'msi' is not of type 'array'
> > >         From schema: /.../snps,dw-pcie.yaml
> > 
> > As soon as I manually moved the same "$defs"-schemas into the places they
> > are referenced to, the errors disappeared and the DT-schemas validation
> > worked as expected by the semantics.
> > 
> > As I see it there must be some bug in the parser, otherwise I am out of
> > ideas how to implement the suggested in this patch design pattern. Rob,
> > could you take a look at the DT-schemas and help me out with debugging the
> > problem described above?
> 

> There is at least an error in your schema, details latter on.

It depends on the schema usage. Please see my next comments for the
detailed explanation what I am trying to achieve here and why it would
be very useful.

> 
> It could be an issue in the fixups which in general convert 
> schemas for strings to string arrays and scalars/arrays to matrix. You 
> have to look at processed-schema.json to debug it.
> 
> The other thing is 'oneOf' errors can be confusing in terms of error 
> messages because the tooling doesn't really know which entry had the 
> least error. Like the type was right, but some secondary constraint 
> failed (as what's secondary is not expressed in any way).
> 
> I would debug it further, but I don't really like the end result. I 
> think it's too hard to follow. For the most part, we avoid $refs at the 
> property level across different schema files with the big exception 
> being types.yaml. $defs are also used sparingly. The challenge is that 
> json-schema by default will be silent on schemas misformed in lots of 
> ways. Our meta-schema adds a lot of constraints which limits what the 
> schemas can look like and ensures schemas are valid. It also allows me 
> to define new constraints rather than repeat the same review comment 
> over and over.

I see your point, but in this case I suppose an exception would gain
good benefits too. Here is why.

As I said in the patch log the main idea of this modification was to
create a common schema for the DW PCIe compatible controllers which would
be more restrictive than the existing one but more descriptive and yet
extendable if required. So using $refs was the best method for such
case.

In the framework of this patch aside with a set of the generic DW PCIe
properties, I tried to implement the schemas for the string array with
a pre-defined set values. These schemas can be used to set the
constraints on the device-specific bindings or can be omitted if
either the bindings have already been defined in a different way or
the device is incompatible with the generic bindings for some reason.
Please see the schemas defined in the pci/snps,dw-pcie-common.yaml
file.

As you can see mainly the snps,dw-pcie-common.yaml schema contains the
normal properties descriptions like 'reg', 'clocks', 'interrupts',
'resets', etc. The only peculiarity is the sub-properties defined under
the "$defs" property. See, they aren't used in that file, but are
referenced in the snps,dw-pcie-ep.yaml and snps,dw-pcie.yaml schemas in
order to create the corresponding string arrays constraints. See my
next comments for the further explanation.

> 
> > ---
> >  .../bindings/pci/fsl,imx6q-pcie.yaml          |   5 +-
> >  .../bindings/pci/hisilicon,kirin-pcie.yaml    |   4 +-
> >  .../bindings/pci/sifive,fu740-pcie.yaml       |   4 +-
> >  .../bindings/pci/snps,dw-pcie-common.yaml     | 298 ++++++++++++++++++
> >  .../bindings/pci/snps,dw-pcie-ep.yaml         | 143 ++++++---
> >  .../devicetree/bindings/pci/snps,dw-pcie.yaml | 189 +++++++----
> >  .../bindings/pci/toshiba,visconti-pcie.yaml   |   2 +-
> >  7 files changed, 524 insertions(+), 121 deletions(-)
> >  create mode 100644 Documentation/devicetree/bindings/pci/snps,dw-pcie-common.yaml
> 
> 
> > diff --git a/Documentation/devicetree/bindings/pci/snps,dw-pcie-common.yaml b/Documentation/devicetree/bindings/pci/snps,dw-pcie-common.yaml
> > new file mode 100644
> > index 000000000000..27fe1f5c450f
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/pci/snps,dw-pcie-common.yaml
> > @@ -0,0 +1,298 @@
> > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> > +%YAML 1.2
> > +---
> > +$id: http://devicetree.org/schemas/pci/snps,dw-pcie-common.yaml#
> > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > +
> > +title: Synopsys DWC PCIe RP/EP controller
> > +
> > +maintainers:
> > +  - Jingoo Han <jingoohan1@gmail.com>
> > +  - Gustavo Pimentel <gustavo.pimentel@synopsys.com>
> > +
> > +properties:
> > +  reg:
> > +    description:
> > +      DWC PCIe CSR space is normally accessed over the dedicated Data Bus
> > +      Interface - DBI. In accordance with the reference manual the register
> > +      configuration space belongs to the Configuration-Dependent Module (CDM)
> > +      and is split up into several sub-parts Standard PCIe configuration
> > +      space, Port Logic Registers (PL), Shadow Config-space Registers,
> > +      iATU/eDMA registers. The particular sub-space is selected by the
> > +      CDM/ELBI (dbi_cs) and CS2 (dbi_cs2) signals (selector bits). Such
> > +      configuration provides a flexible interface for the system engineers to
> > +      either map the particular space at a desired MMIO address or just leave
> > +      them in a contiguous memory space if pure Native or AXI Bridge DBI access
> > +      is selected. Note the PCIe CFG-space, PL and Shadow registers are
> > +      specific to each activated function, while the rest of the sub-spaces
> > +      are common for all of them (if there are more than one).
> > +    minItems: 2
> > +    maxItems: 6
> > +
> > +  interrupts:
> > +    description:
> > +      There are two main sub-blocks which are normally capable of
> > +      generating interrupts. It's System Information Interface and MSI
> > +      interface. While the former one has some common for the Host and
> > +      End-point controllers IRQ-signals, the later interface is obviously
> > +      Root Complex specific since it's responsible for the incoming MSI
> > +      messages signalling. The System Information IRQ signals are mainly
> > +      responsible for reporting the generic PCIe hierarchy and Root
> > +      Complex events like VPD IO request, general AER, PME, Hot-plug, link
> > +      bandwidth change, link equalization request, INTx asserted/deasserted
> > +      Message detection, embedded DMA Tx/Rx/Error.
> > +    minItems: 1
> > +    maxItems: 26
> > +
> > +  clocks:
> > +    description:
> > +      DWC PCIe reference manual explicitly defines a set of the clocks required
> > +      to get the controller working correctly. In general all of them can
> > +      be divided into two groups':' application and core clocks. Note the
> > +      platforms may have some of the clock sources unspecified in case if the
> > +      corresponding domains are fed up from a common clock source.
> > +    minItems: 1
> > +    maxItems: 7
> > +
> > +  resets:
> > +    description:
> > +      DWC PCIe reference manual explicitly defines a set of the reset
> > +      signals required to be de-asserted to properly activate the controller
> > +      sub-parts. All of these signals can be divided into two sub-groups':'
> > +      application and core resets with respect to the main sub-domains they
> > +      are supposed to reset. Note the platforms may have some of these signals
> > +      unspecified in case if they are automatically handled or aggregated into
> > +      a comprehensive control module.
> > +    minItems: 1
> > +    maxItems: 10
> > +
> > +  reset-gpio:
> > +    deprecated: true
> > +    description:
> > +      Reference to the GPIO-controlled PERST# signal. It is used to reset all
> > +      the peripheral devices available on the PCIe bus.
> > +    maxItems: 1
> > +
> > +  reset-gpios:
> > +    description:
> > +      Reference to the GPIO-controlled PERST# signal. It is used to reset all
> > +      the peripheral devices available on the PCIe bus.
> > +    maxItems: 1
> > +
> > +  phys:
> > +    description:
> > +      There can be up to number of possible lanes PHYs specified.
> > +      Obviously each specified PHY is supposed to be able to work in the
> > +      PCIe mode with a speed implied by the DWC PCIe controller it is
> > +      attached to.
> > +    minItems: 1
> > +    maxItems: 16
> > +
> > +  phy-names:
> > +    minItems: 1
> > +    maxItems: 16
> > +    items:
> > +      pattern: '^pcie([0-9]+|-?phy)?$'
> > +
> > +  num-lanes:
> > +    maximum: 16
> > +
> > +  max-link-speed:
> > +    maximum: 4
> > +
> > +  num-ob-windows:
> > +    $ref: /schemas/types.yaml#/definitions/uint32
> > +    deprecated: true
> > +    description:
> > +      Number of outbound address translation windows. This parameter can be
> > +      auto-detected based on the iATU memory writability. So there is no
> > +      point in having a dedicated DT-property for it.
> > +    maximum: 256
> > +
> > +  num-ib-windows:
> > +    $ref: /schemas/types.yaml#/definitions/uint32
> > +    deprecated: true
> > +    description:
> > +      Number of inbound address translation windows. In the same way as
> > +      for the outbound AT windows, this parameter can be auto-detected based
> > +      on the iATU memory writability. There is no point having a dedicated
> > +      DT-property for it either.
> > +    maximum: 256
> > +
> > +  num-viewport:
> > +    $ref: /schemas/types.yaml#/definitions/uint32
> > +    deprecated: true
> > +    description:
> > +      Number of outbound view ports configured in hardware. It's the same as
> > +      the number of outbound AT windows.
> > +    maximum: 256
> > +
> > +  snps,enable-cdm-check:
> > +    $ref: /schemas/types.yaml#/definitions/flag
> > +    description:
> > +      Enable automatic checking of CDM (Configuration Dependent Module)
> > +      registers for data corruption. CDM registers include standard PCIe
> > +      configuration space registers, Port Logic registers, DMA and iATU
> > +      registers. This feature has been available since DWC PCIe v4.80a.
> > +
> > +additionalProperties: true
> > +
> > +$defs:
> > +  reg-names:
> > +    description:
> > +      CSR space names common for the DWC PCIe Root Port and End-point
> > +      controllers.
> > +    oneOf:
> > +      - description:
> > +          Basic DWC PCIe controller configuration-space accessible over
> > +          the DBI interface. This memory space is either activated with
> > +          the CDM/ELBI = 0 and CS2 = 0 or is a contiguous memory region
> > +          with all spaces. Note iATU/eDMA CSRs are indirectly accessible
> > +          via the PL viewports on the DWC PCIe controllers older than
> > +          v4.80a.
> > +        const: dbi
> 

> This passes only for 'reg-names = "dbi";'

No, if the defined here "reg-names" schema is correctly referenced. See my
next comments.

> 
> > +      - description:
> > +          Shadow DWC PCIe config-space registers. This space is selected
> > +          by setting CDM/ELBI = 0 and CS2 = 1. This is an intermix of
> > +          the PCI-SIG PCIe CFG-space with the shadow registers for some
> > +          PCI Header space, PCI Standard and Extended Structures. It's
> > +          mainly relevant for the end-point controller configuration,
> > +          but still there are some shadow registers available for the
> > +          Root Port mode too.
> > +        const: dbi2
> 

> This passes only for 'reg-names = "dbi2";'

ditto

> 
> > +      - description:
> > +          External Local Bus registers. It's an application-dependent
> > +          registers normally defined by the platform engineers, which
> > +          are selected by setting CDM/ELBI = 1 and CS2 = 0.
> > +        enum: [ elbi, appl, app ]
> 

> This passes only for 'reg-names = "elbi", "appl", "app";'
> 
> See the problem? Replacing the 'oneOf' above with 'items' is what you 
> want. But then the schema will not allow any missing entries either. 
> DBI2 is optional for example. There is no way in json-schema to define a 
> list of ordered values(string) once and say some entries are optional 
> which I think is what you are trying to do here.

Please see the way the "$defs: *-names" properties are referenced in
the framework of this patch. My idea was to define a set of strings in
the "$defs: *-names" properties here. Then re-use that set to define
the device-specific constraints. That's why I've intentionally used
'oneOf'-based composition so the properties could be used to set a
constraints on !each! item of the corresponding strings array, but not
on the whole array as you suggest by replacing 'oneOf' with 'items'.
BTW the ordering can be defined in the corresponding schemas if it's
required. 

As an example please see the json schema of the generic DWC
PCIe End-point reg-names property I am trying to achieve here:
https://www.jsonschemavalidator.net/s/eGV3M3gK

As you can see it makes sure the reg-names array contains at least
the "dbi", "dbi2" and "addr_space" strings and may also have the
optional CSR names if it's specific to the corresponding platform.

If you need the ordered set of the strings then the next schema
can be used:
https://www.jsonschemavalidator.net/s/53KKrXV9

Regarding the ordering. As I see it, it isn't something what we need
in the modern bindings in the reference to the "*-names" properties
since the new drivers mainly rely on getting the CSR maps, interrupts,
clocks and resets by their names rather than a position in the 'reg'
phandles array. The CSRs order isn't something what hardware defines
either. Moreover tons of the DT source files don't really have the
reg-names, clock-names, etc properties initialized with some strict
order. So if we want the schema to be applicable for the already
created DT sources the ordering constraints need to be avoided.

Getting back to the patch. As I said in the patch log, alas I failed
to reproduce the described schema in the DT bindings due to the
denoted error. Seeing the JSON-schema examples are working and so does
the DT-schema parser if I manually move the "$defs: *-names" schemas
content in the place of the references, there must be some problem
with the parser. That's why I asked your help with debugging.

> 
> > +      - description:
> > +          iATU/eDMA registers common for all device functions. It's an
> > +          unrolled memory space with the internal Address Translation
> > +          Unit and Enhanced DMA, which is selected by setting CDM/ELBI = 1
> > +          and CS2 = 1. For IP-core releases prior v4.80a, these registers
> > +          have been programmed via an indirect addressing scheme using a
> > +          set of viewport CSRs mapped into the PL space. Note iATU is
> > +          normally mapped to the 0x0 address of this region, while eDMA
> > +          is available at 0x80000 base address.
> > +        enum: [ atu, atu_dma ]
> > +      - description:
> > +          Outbound iATU-available memory-region which usage scenario
> > +          depends on the DWC PCIe controller being either Root Port or
> > +          End-point. If it's Root Port then the register space shall
> > +          have the "config" name and it will be used to access the
> > +          peripheral PCIe devices configuration space. If it's PCIe
> > +          end-point controller, then the region shall be named as
> > +          "addr_space" and it will be used to generate various traffic
> > +          on the PCIe bus hierarchy. It's usage scenario depends on the
> > +          end-point functionality, for instance it can be used to create
> > +          MSI(X) messages.
> > +        enum: [ config, addr_space ]
> 

> So 'addr_space' is now valid for host mode?

Well, in general this reg-space is supposed to be of the same memory
space type - outbound iATU sub-region - for both Host and End-point
controller, but the names are different for them. Anyway basically you
are right, the schemas referencing this property will permit having
both reg names. I can split this property up into two: "$defs:
host-reg-names" and "$defs: ep-reg-names" and use the new schemas in
the Host and EP reg-names property constraints respectively. What do
you think?

> 
> (Really, for DW blocks with iATU, this should have been the whole memory 
> space and the driver could size the config space itself. (IOW, the 
> config region is configuration rather than h/w description.)

I am fully agree with you but the addr/config-space reg-bindings have
already been defined that way. It is implemented in the DWC PCIe driver
and many DT files rely on having that bindings implemented. So alas
nothing we can do about it.

> 
> > +      - description:
> > +          PHY/PCS configuration registers. Some platforms can have the
> > +          PCS and PHY CSRs accessible over a dedicated memory mapped
> > +          region, but mainly these registers are indirectly accessible
> > +          either by means of the embedded PHY viewport schema or by some
> > +          platform-specific method.
> > +        enum: [ link, phy ]
> 

> These should not be in any new users as the phy should be separate.

I agree, but these names have already been referenced in some glue
drivers so does the DW PCIe Host/EP manual have the PHY/PCS CSRs IO
interface described. Thus we have to have them described here for the
sake of compatibility.

> 
> > +
> > +  interrupt-names:
> > +    description:
> > +      IRQ signal names common for the DWC PCIe Root Port and End-point
> > +      controllers.
> > +    oneOf:
> > +      - description:
> > +          Controller request to read or write virtual product data
> > +          from/to the VPD capability registers.
> > +        const: vpd
> > +      - description:
> > +          Link Equalization Request flag is set in the Link Status 2
> > +          register (applicable if the corresponding IRQ is enabled in
> > +          the Link Control 3 register).
> > +        const: l_eq
> > +      - description:
> > +          Indicates that the eDMA Tx/Rx transfer is complete or that an
> > +          error has occurred on the corresponding channel. eDMA can have
> > +          eight Tx (Write) and Rx (Read) eDMA channels thus supporting up
> > +          to 16 IRQ signals all together. Write eDMA channels shall go
> > +          first in the ordered row as per default edma_int[*] bus setup.
> > +        pattern: '^dma([0-9]|1[0-5])?$'
> > +      - description:
> > +          PCIe protocol correctable error or a Data Path protection
> > +          correctable error is detected by the automotive/safety
> > +          feature.
> > +        const: sft_ce
> > +      - description:
> > +          Indicates that the internal safety mechanism detected and
> > +          uncorrectable error.
> > +        const: sft_ue
> 

> This says there is only a single interrupt entry. Same for the other 
> $defs.

No, this property is supposed to be considered as applicable to each
"interrupt-names" item, not for the whole array. Please see my comments
before.

-Sergey

> 
> Rob

_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 01/16] dt-bindings: PCI: dwc: Define generic and native DT bindings
@ 2022-04-15 16:14       ` Serge Semin
  0 siblings, 0 replies; 40+ messages in thread
From: Serge Semin @ 2022-04-15 16:14 UTC (permalink / raw)
  To: Rob Herring
  Cc: Serge Semin, Jingoo Han, Gustavo Pimentel, Bjorn Helgaas,
	Richard Zhu, Lucas Stach, Shawn Guo, Sascha Hauer,
	Pengutronix Kernel Team, Fabio Estevam, NXP Linux Team,
	Xiaowei Song, Binghui Wang, Paul Walmsley, Greentime Hu,
	Palmer Dabbelt, Nobuhiro Iwamatsu, Alexey Malahov,
	Pavel Parkhomenko, Lorenzo Pieralisi, Krzysztof Wilczyński,
	Frank Li, Manivannan Sadhasivam, linux-pci, devicetree,
	linux-kernel, linux-arm-kernel, linux-riscv

Hello Rob,

On Mon, Mar 28, 2022 at 03:46:04PM -0500, Rob Herring wrote:
> On Thu, Mar 24, 2022 at 04:37:19AM +0300, Serge Semin wrote:
> > Currently both DW PCIe Root Port and End-point DT bindings are too generic
> > to be used as a descriptive set the device properties. Yes, it's very handy
> > to have them that way so the DT-schemas could be used to evaluate as many
> > DW PCIe-related DT-nodes as possible. But at the same time they don't
> > provide well defined DW PCIe RP/EP DT interface description thus leaving
> > too much flexibility for the new platforms, no encouraging the developers
> > to preserve a compatible interface.
> > 
> > Instead of currently implemented approach we suggest to be more
> > restrictive and yet preserve some level of flexibility in the DW PCIe
> > DT-bindings description. The device tree DT-schema is split up into
> > three parts: a common YAML-schema applicable for both DWC Root Port and
> > End-point controller configs, DWC PCIe Root Port-specific YAML-schema
> > and DWC PCIe End-point-specific YAML-schema, where
> > 1) pci/snps,dw-pcie-common.yaml - The common DT-schema describes the most
> > generic constraints of the "reg", "interrupts", "clocks", "resets" and
> > "phys" properties together with a set of common for both device types
> > PCIe/AXI bus properties like a maximum number of lanes or a maximum link
> > speed, number of inbound and outbound iATU windows. In addition to that a
> > set of schema definitions declared under the "$defs" property with "reg",
> > "interrupt", "clock" and "reset" names common for DWC PCIe Root Port and
> > End-point devices. They can be used by the successive DT-schemas in case
> > they are supposed to be compatible with the generic DWC PCIe controller
> > DT-bindings.
> > 2) pci/snps,dw-pcie.yaml, pci/snps,dw-pcie-ep.yaml - generic DW PCIe Root
> > Port and End-point DT-bindings which aside with the device-specific
> > properties set also contain more restrictive constraints. All new DW PCIe
> > platforms are supposed to be compatible with one of these bindings by
> > using "allOf: " property and additionally defining their own constraints
> > to close up the DT-bindings set.
> > 
> > So to speak in case if a DW PCIe-based device for some reason has too many
> > specific properties or it's bindings have already been defined in a
> > non-generic way, it's DT-schema is supposed to include 1) YAML-file and
> > provide its own constraints. Otherwise the ready-to-use bindings from 2)
> > should be utilized. There only two DT-schemas compatible with 2) at the
> > moment are samsung,axynos-pcie.yaml and intel-gw-pcie.yaml. The
> > rest of the DW PCIe-related DT-schemas are supposed to use more generic
> > DW PCIe DT-bindings - pci/snps,dw-pcie-common.yaml.
> > 
> > Note the provided here generic properties and their possible values are
> > derived from the DW PCIe RC/EP hardware manuals and from the interface
> > implemented in the driver. The DT-bindings schemas are created to be as
> > full as possible with detailed properties/names description for the
> > easier interface comprehension and new platforms bindings development.
> > 
> > Also note since there are no generic DT-nodes can be found in the kernel
> > dts-es which would have a pure "snps,dw-pcie" compatible string, these
> > DT-bindings have been created to not be selected by default for
> > evaluation. They are supposed to be used by the new vendor-specific
> > DT-schemas to at least stop adding new bindings for the same set of DWC
> > PCIe signals or properties.
> > 
> > Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> > 
> > ---
> > 
> > Rob, if you comment the "select: false" line out you'll get a lot of "'*'
> > is not of type 'array'" errors on the dt_bindings_check command execution.
> > I have spend tons of time trying to figure out what was wrong, but still
> > failed to find out a solution. For some reason the "$ref"-ed schemas
> > defined under the "$defs" basic property are considered by the parser as
> > defining an array. No matter whether I specified the "type: string"
> > keyword or not, as long as there is "enum" or "oneOf" keyword used in the
> > "*-names" property definition in "$defs" it's considered as describing an
> > array thus causing the errors like:
> 
> As-is, there were lots of errors...
> 
> > 
> > >  DTC     Documentation/devicetree/bindings/pci/snps,dw-pcie.example.dt.yaml
> > >  CHECK   Documentation/devicetree/bindings/pci/snps,dw-pcie.example.dt.yaml
> > > /.../snps,dw-pcie.example.dt.yaml: pcie@1f052000: reg-names:0: 'oneOf' conditional failed, one must be fixed:
> > >        'dbi' is not of type 'array'
> > >        From schema: /.../snps,dw-pcie.yaml
> > > /.../snps,dw-pcie.example.dt.yaml: pcie@1f052000: reg-names:1: 'oneOf' conditional failed, one must be fixed:
> > >         'config' is not of type 'array'
> > >         From schema: /.../snps,dw-pcie.yaml
> > > /.../snps,dw-pcie.example.dt.yaml: pcie@1f052000: interrupt-names:0: 'anyOf' conditional failed, one must be fixed:
> > >         /.../snps,dw-pcie.example.dt.yaml: pcie@1f052000: interrupt-names:0: 'oneOf' conditional failed, one must be fixed:
> > >                 'msi' is not of type 'array'
> > >         /../snps,dw-pcie.example.dt.yaml: pcie@1f052000: interrupt-names:0: 'oneOf' conditional failed, one must be fixed:
> > >                 'msi' is not of type 'array'
> > >         From schema: /.../snps,dw-pcie.yaml
> > 
> > As soon as I manually moved the same "$defs"-schemas into the places they
> > are referenced to, the errors disappeared and the DT-schemas validation
> > worked as expected by the semantics.
> > 
> > As I see it there must be some bug in the parser, otherwise I am out of
> > ideas how to implement the suggested in this patch design pattern. Rob,
> > could you take a look at the DT-schemas and help me out with debugging the
> > problem described above?
> 

> There is at least an error in your schema, details latter on.

It depends on the schema usage. Please see my next comments for the
detailed explanation what I am trying to achieve here and why it would
be very useful.

> 
> It could be an issue in the fixups which in general convert 
> schemas for strings to string arrays and scalars/arrays to matrix. You 
> have to look at processed-schema.json to debug it.
> 
> The other thing is 'oneOf' errors can be confusing in terms of error 
> messages because the tooling doesn't really know which entry had the 
> least error. Like the type was right, but some secondary constraint 
> failed (as what's secondary is not expressed in any way).
> 
> I would debug it further, but I don't really like the end result. I 
> think it's too hard to follow. For the most part, we avoid $refs at the 
> property level across different schema files with the big exception 
> being types.yaml. $defs are also used sparingly. The challenge is that 
> json-schema by default will be silent on schemas misformed in lots of 
> ways. Our meta-schema adds a lot of constraints which limits what the 
> schemas can look like and ensures schemas are valid. It also allows me 
> to define new constraints rather than repeat the same review comment 
> over and over.

I see your point, but in this case I suppose an exception would gain
good benefits too. Here is why.

As I said in the patch log the main idea of this modification was to
create a common schema for the DW PCIe compatible controllers which would
be more restrictive than the existing one but more descriptive and yet
extendable if required. So using $refs was the best method for such
case.

In the framework of this patch aside with a set of the generic DW PCIe
properties, I tried to implement the schemas for the string array with
a pre-defined set values. These schemas can be used to set the
constraints on the device-specific bindings or can be omitted if
either the bindings have already been defined in a different way or
the device is incompatible with the generic bindings for some reason.
Please see the schemas defined in the pci/snps,dw-pcie-common.yaml
file.

As you can see mainly the snps,dw-pcie-common.yaml schema contains the
normal properties descriptions like 'reg', 'clocks', 'interrupts',
'resets', etc. The only peculiarity is the sub-properties defined under
the "$defs" property. See, they aren't used in that file, but are
referenced in the snps,dw-pcie-ep.yaml and snps,dw-pcie.yaml schemas in
order to create the corresponding string arrays constraints. See my
next comments for the further explanation.

> 
> > ---
> >  .../bindings/pci/fsl,imx6q-pcie.yaml          |   5 +-
> >  .../bindings/pci/hisilicon,kirin-pcie.yaml    |   4 +-
> >  .../bindings/pci/sifive,fu740-pcie.yaml       |   4 +-
> >  .../bindings/pci/snps,dw-pcie-common.yaml     | 298 ++++++++++++++++++
> >  .../bindings/pci/snps,dw-pcie-ep.yaml         | 143 ++++++---
> >  .../devicetree/bindings/pci/snps,dw-pcie.yaml | 189 +++++++----
> >  .../bindings/pci/toshiba,visconti-pcie.yaml   |   2 +-
> >  7 files changed, 524 insertions(+), 121 deletions(-)
> >  create mode 100644 Documentation/devicetree/bindings/pci/snps,dw-pcie-common.yaml
> 
> 
> > diff --git a/Documentation/devicetree/bindings/pci/snps,dw-pcie-common.yaml b/Documentation/devicetree/bindings/pci/snps,dw-pcie-common.yaml
> > new file mode 100644
> > index 000000000000..27fe1f5c450f
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/pci/snps,dw-pcie-common.yaml
> > @@ -0,0 +1,298 @@
> > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> > +%YAML 1.2
> > +---
> > +$id: http://devicetree.org/schemas/pci/snps,dw-pcie-common.yaml#
> > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > +
> > +title: Synopsys DWC PCIe RP/EP controller
> > +
> > +maintainers:
> > +  - Jingoo Han <jingoohan1@gmail.com>
> > +  - Gustavo Pimentel <gustavo.pimentel@synopsys.com>
> > +
> > +properties:
> > +  reg:
> > +    description:
> > +      DWC PCIe CSR space is normally accessed over the dedicated Data Bus
> > +      Interface - DBI. In accordance with the reference manual the register
> > +      configuration space belongs to the Configuration-Dependent Module (CDM)
> > +      and is split up into several sub-parts Standard PCIe configuration
> > +      space, Port Logic Registers (PL), Shadow Config-space Registers,
> > +      iATU/eDMA registers. The particular sub-space is selected by the
> > +      CDM/ELBI (dbi_cs) and CS2 (dbi_cs2) signals (selector bits). Such
> > +      configuration provides a flexible interface for the system engineers to
> > +      either map the particular space at a desired MMIO address or just leave
> > +      them in a contiguous memory space if pure Native or AXI Bridge DBI access
> > +      is selected. Note the PCIe CFG-space, PL and Shadow registers are
> > +      specific to each activated function, while the rest of the sub-spaces
> > +      are common for all of them (if there are more than one).
> > +    minItems: 2
> > +    maxItems: 6
> > +
> > +  interrupts:
> > +    description:
> > +      There are two main sub-blocks which are normally capable of
> > +      generating interrupts. It's System Information Interface and MSI
> > +      interface. While the former one has some common for the Host and
> > +      End-point controllers IRQ-signals, the later interface is obviously
> > +      Root Complex specific since it's responsible for the incoming MSI
> > +      messages signalling. The System Information IRQ signals are mainly
> > +      responsible for reporting the generic PCIe hierarchy and Root
> > +      Complex events like VPD IO request, general AER, PME, Hot-plug, link
> > +      bandwidth change, link equalization request, INTx asserted/deasserted
> > +      Message detection, embedded DMA Tx/Rx/Error.
> > +    minItems: 1
> > +    maxItems: 26
> > +
> > +  clocks:
> > +    description:
> > +      DWC PCIe reference manual explicitly defines a set of the clocks required
> > +      to get the controller working correctly. In general all of them can
> > +      be divided into two groups':' application and core clocks. Note the
> > +      platforms may have some of the clock sources unspecified in case if the
> > +      corresponding domains are fed up from a common clock source.
> > +    minItems: 1
> > +    maxItems: 7
> > +
> > +  resets:
> > +    description:
> > +      DWC PCIe reference manual explicitly defines a set of the reset
> > +      signals required to be de-asserted to properly activate the controller
> > +      sub-parts. All of these signals can be divided into two sub-groups':'
> > +      application and core resets with respect to the main sub-domains they
> > +      are supposed to reset. Note the platforms may have some of these signals
> > +      unspecified in case if they are automatically handled or aggregated into
> > +      a comprehensive control module.
> > +    minItems: 1
> > +    maxItems: 10
> > +
> > +  reset-gpio:
> > +    deprecated: true
> > +    description:
> > +      Reference to the GPIO-controlled PERST# signal. It is used to reset all
> > +      the peripheral devices available on the PCIe bus.
> > +    maxItems: 1
> > +
> > +  reset-gpios:
> > +    description:
> > +      Reference to the GPIO-controlled PERST# signal. It is used to reset all
> > +      the peripheral devices available on the PCIe bus.
> > +    maxItems: 1
> > +
> > +  phys:
> > +    description:
> > +      There can be up to number of possible lanes PHYs specified.
> > +      Obviously each specified PHY is supposed to be able to work in the
> > +      PCIe mode with a speed implied by the DWC PCIe controller it is
> > +      attached to.
> > +    minItems: 1
> > +    maxItems: 16
> > +
> > +  phy-names:
> > +    minItems: 1
> > +    maxItems: 16
> > +    items:
> > +      pattern: '^pcie([0-9]+|-?phy)?$'
> > +
> > +  num-lanes:
> > +    maximum: 16
> > +
> > +  max-link-speed:
> > +    maximum: 4
> > +
> > +  num-ob-windows:
> > +    $ref: /schemas/types.yaml#/definitions/uint32
> > +    deprecated: true
> > +    description:
> > +      Number of outbound address translation windows. This parameter can be
> > +      auto-detected based on the iATU memory writability. So there is no
> > +      point in having a dedicated DT-property for it.
> > +    maximum: 256
> > +
> > +  num-ib-windows:
> > +    $ref: /schemas/types.yaml#/definitions/uint32
> > +    deprecated: true
> > +    description:
> > +      Number of inbound address translation windows. In the same way as
> > +      for the outbound AT windows, this parameter can be auto-detected based
> > +      on the iATU memory writability. There is no point having a dedicated
> > +      DT-property for it either.
> > +    maximum: 256
> > +
> > +  num-viewport:
> > +    $ref: /schemas/types.yaml#/definitions/uint32
> > +    deprecated: true
> > +    description:
> > +      Number of outbound view ports configured in hardware. It's the same as
> > +      the number of outbound AT windows.
> > +    maximum: 256
> > +
> > +  snps,enable-cdm-check:
> > +    $ref: /schemas/types.yaml#/definitions/flag
> > +    description:
> > +      Enable automatic checking of CDM (Configuration Dependent Module)
> > +      registers for data corruption. CDM registers include standard PCIe
> > +      configuration space registers, Port Logic registers, DMA and iATU
> > +      registers. This feature has been available since DWC PCIe v4.80a.
> > +
> > +additionalProperties: true
> > +
> > +$defs:
> > +  reg-names:
> > +    description:
> > +      CSR space names common for the DWC PCIe Root Port and End-point
> > +      controllers.
> > +    oneOf:
> > +      - description:
> > +          Basic DWC PCIe controller configuration-space accessible over
> > +          the DBI interface. This memory space is either activated with
> > +          the CDM/ELBI = 0 and CS2 = 0 or is a contiguous memory region
> > +          with all spaces. Note iATU/eDMA CSRs are indirectly accessible
> > +          via the PL viewports on the DWC PCIe controllers older than
> > +          v4.80a.
> > +        const: dbi
> 

> This passes only for 'reg-names = "dbi";'

No, if the defined here "reg-names" schema is correctly referenced. See my
next comments.

> 
> > +      - description:
> > +          Shadow DWC PCIe config-space registers. This space is selected
> > +          by setting CDM/ELBI = 0 and CS2 = 1. This is an intermix of
> > +          the PCI-SIG PCIe CFG-space with the shadow registers for some
> > +          PCI Header space, PCI Standard and Extended Structures. It's
> > +          mainly relevant for the end-point controller configuration,
> > +          but still there are some shadow registers available for the
> > +          Root Port mode too.
> > +        const: dbi2
> 

> This passes only for 'reg-names = "dbi2";'

ditto

> 
> > +      - description:
> > +          External Local Bus registers. It's an application-dependent
> > +          registers normally defined by the platform engineers, which
> > +          are selected by setting CDM/ELBI = 1 and CS2 = 0.
> > +        enum: [ elbi, appl, app ]
> 

> This passes only for 'reg-names = "elbi", "appl", "app";'
> 
> See the problem? Replacing the 'oneOf' above with 'items' is what you 
> want. But then the schema will not allow any missing entries either. 
> DBI2 is optional for example. There is no way in json-schema to define a 
> list of ordered values(string) once and say some entries are optional 
> which I think is what you are trying to do here.

Please see the way the "$defs: *-names" properties are referenced in
the framework of this patch. My idea was to define a set of strings in
the "$defs: *-names" properties here. Then re-use that set to define
the device-specific constraints. That's why I've intentionally used
'oneOf'-based composition so the properties could be used to set a
constraints on !each! item of the corresponding strings array, but not
on the whole array as you suggest by replacing 'oneOf' with 'items'.
BTW the ordering can be defined in the corresponding schemas if it's
required. 

As an example please see the json schema of the generic DWC
PCIe End-point reg-names property I am trying to achieve here:
https://www.jsonschemavalidator.net/s/eGV3M3gK

As you can see it makes sure the reg-names array contains at least
the "dbi", "dbi2" and "addr_space" strings and may also have the
optional CSR names if it's specific to the corresponding platform.

If you need the ordered set of the strings then the next schema
can be used:
https://www.jsonschemavalidator.net/s/53KKrXV9

Regarding the ordering. As I see it, it isn't something what we need
in the modern bindings in the reference to the "*-names" properties
since the new drivers mainly rely on getting the CSR maps, interrupts,
clocks and resets by their names rather than a position in the 'reg'
phandles array. The CSRs order isn't something what hardware defines
either. Moreover tons of the DT source files don't really have the
reg-names, clock-names, etc properties initialized with some strict
order. So if we want the schema to be applicable for the already
created DT sources the ordering constraints need to be avoided.

Getting back to the patch. As I said in the patch log, alas I failed
to reproduce the described schema in the DT bindings due to the
denoted error. Seeing the JSON-schema examples are working and so does
the DT-schema parser if I manually move the "$defs: *-names" schemas
content in the place of the references, there must be some problem
with the parser. That's why I asked your help with debugging.

> 
> > +      - description:
> > +          iATU/eDMA registers common for all device functions. It's an
> > +          unrolled memory space with the internal Address Translation
> > +          Unit and Enhanced DMA, which is selected by setting CDM/ELBI = 1
> > +          and CS2 = 1. For IP-core releases prior v4.80a, these registers
> > +          have been programmed via an indirect addressing scheme using a
> > +          set of viewport CSRs mapped into the PL space. Note iATU is
> > +          normally mapped to the 0x0 address of this region, while eDMA
> > +          is available at 0x80000 base address.
> > +        enum: [ atu, atu_dma ]
> > +      - description:
> > +          Outbound iATU-available memory-region which usage scenario
> > +          depends on the DWC PCIe controller being either Root Port or
> > +          End-point. If it's Root Port then the register space shall
> > +          have the "config" name and it will be used to access the
> > +          peripheral PCIe devices configuration space. If it's PCIe
> > +          end-point controller, then the region shall be named as
> > +          "addr_space" and it will be used to generate various traffic
> > +          on the PCIe bus hierarchy. It's usage scenario depends on the
> > +          end-point functionality, for instance it can be used to create
> > +          MSI(X) messages.
> > +        enum: [ config, addr_space ]
> 

> So 'addr_space' is now valid for host mode?

Well, in general this reg-space is supposed to be of the same memory
space type - outbound iATU sub-region - for both Host and End-point
controller, but the names are different for them. Anyway basically you
are right, the schemas referencing this property will permit having
both reg names. I can split this property up into two: "$defs:
host-reg-names" and "$defs: ep-reg-names" and use the new schemas in
the Host and EP reg-names property constraints respectively. What do
you think?

> 
> (Really, for DW blocks with iATU, this should have been the whole memory 
> space and the driver could size the config space itself. (IOW, the 
> config region is configuration rather than h/w description.)

I am fully agree with you but the addr/config-space reg-bindings have
already been defined that way. It is implemented in the DWC PCIe driver
and many DT files rely on having that bindings implemented. So alas
nothing we can do about it.

> 
> > +      - description:
> > +          PHY/PCS configuration registers. Some platforms can have the
> > +          PCS and PHY CSRs accessible over a dedicated memory mapped
> > +          region, but mainly these registers are indirectly accessible
> > +          either by means of the embedded PHY viewport schema or by some
> > +          platform-specific method.
> > +        enum: [ link, phy ]
> 

> These should not be in any new users as the phy should be separate.

I agree, but these names have already been referenced in some glue
drivers so does the DW PCIe Host/EP manual have the PHY/PCS CSRs IO
interface described. Thus we have to have them described here for the
sake of compatibility.

> 
> > +
> > +  interrupt-names:
> > +    description:
> > +      IRQ signal names common for the DWC PCIe Root Port and End-point
> > +      controllers.
> > +    oneOf:
> > +      - description:
> > +          Controller request to read or write virtual product data
> > +          from/to the VPD capability registers.
> > +        const: vpd
> > +      - description:
> > +          Link Equalization Request flag is set in the Link Status 2
> > +          register (applicable if the corresponding IRQ is enabled in
> > +          the Link Control 3 register).
> > +        const: l_eq
> > +      - description:
> > +          Indicates that the eDMA Tx/Rx transfer is complete or that an
> > +          error has occurred on the corresponding channel. eDMA can have
> > +          eight Tx (Write) and Rx (Read) eDMA channels thus supporting up
> > +          to 16 IRQ signals all together. Write eDMA channels shall go
> > +          first in the ordered row as per default edma_int[*] bus setup.
> > +        pattern: '^dma([0-9]|1[0-5])?$'
> > +      - description:
> > +          PCIe protocol correctable error or a Data Path protection
> > +          correctable error is detected by the automotive/safety
> > +          feature.
> > +        const: sft_ce
> > +      - description:
> > +          Indicates that the internal safety mechanism detected and
> > +          uncorrectable error.
> > +        const: sft_ue
> 

> This says there is only a single interrupt entry. Same for the other 
> $defs.

No, this property is supposed to be considered as applicable to each
"interrupt-names" item, not for the whole array. Please see my comments
before.

-Sergey

> 
> Rob

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 02/16] dt-bindings: PCI: dwc: Add Baikal-T1 PCIe Root Port bindings
  2022-03-28 23:20   ` Rob Herring
@ 2022-04-15 20:22     ` Serge Semin
  0 siblings, 0 replies; 40+ messages in thread
From: Serge Semin @ 2022-04-15 20:22 UTC (permalink / raw)
  To: Rob Herring
  Cc: Serge Semin, Jingoo Han, Gustavo Pimentel, Bjorn Helgaas,
	Alexey Malahov, Pavel Parkhomenko, Lorenzo Pieralisi,
	Krzysztof Wilczyński, Frank Li, Manivannan Sadhasivam,
	linux-pci, devicetree, linux-kernel

On Mon, Mar 28, 2022 at 06:20:03PM -0500, Rob Herring wrote:
> On Thu, Mar 24, 2022 at 04:37:20AM +0300, Serge Semin wrote:
> > Baikal-T1 SoC is equipped with DWC PCIe v4.60a Root Port controller, which
> > link can be trained to work on up to Gen.3 speed over up to x4 lanes. The
> > controller is supposed to be fed up with four clock sources: DBI
> > peripheral clock, AXI application Tx/Rx clocks and external PHY/core
> > reference clock generating the 100MHz signal. In addition to that the
> > platform provide a way to reset each part of the controller:
> > sticky/non-sticky bits, host controller core, PIPE interface, PCS/PHY and
> > Hot/Power reset signal. The Root Port controller is equipped with multiple
> > IRQ lines like MSI, system AER, PME, HP, Bandwidth change, Link
> > equalization request and eDMA ones. The registers space is accessed over
> > the DBI interface. There can be no more than four inbound or outbound iATU
> > windows configured.
> > 
> > Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> > 
> > ---
> > 
> > Rob, this DT-bindings most likely will fail the dt_bindings_check
> > evaluations with the "'*' is not of type 'array'" errors for the same
> > reason described in the previous patch. Let's discuss the problem there.
> > ---
> >  .../bindings/pci/baikal,bt1-pcie.yaml         | 148 ++++++++++++++++++
> >  1 file changed, 148 insertions(+)
> >  create mode 100644 Documentation/devicetree/bindings/pci/baikal,bt1-pcie.yaml
> > 
> > diff --git a/Documentation/devicetree/bindings/pci/baikal,bt1-pcie.yaml b/Documentation/devicetree/bindings/pci/baikal,bt1-pcie.yaml
> > new file mode 100644
> > index 000000000000..f34438330a86
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/pci/baikal,bt1-pcie.yaml
> > @@ -0,0 +1,148 @@
> > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> > +%YAML 1.2
> > +---
> > +$id: http://devicetree.org/schemas/pci/baikal,bt1-pcie.yaml#
> > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > +
> > +title: Baikal-T1 PCIe Root Port Controller
> > +
> > +maintainers:
> > +  - Serge Semin <fancer.lancer@gmail.com>
> > +
> > +description: |
> > +  Embedded into Baikal-T1 SoC Root Complex controller. It's based on the
> > +  DWC RC PCIe v4.60a IP-core, which is configured to have just a single Root
> > +  Port function and is capable of establishing the link up to Gen.3 speed
> > +  on x4 lanes. It doesn't have embedded clock and reset control module, so
> > +  the proper interface initialization is supposed to be performed by software.
> > +
> > +allOf:
> > +  - $ref: /schemas/pci/pci-bus.yaml#
> > +  - $ref: snps,dw-pcie.yaml#
> > +
> > +properties:
> > +  compatible:
> > +    contains:
> > +      const: baikal,bt1-pcie
> > +
> > +  reg:
> > +    description:
> > +      DBI, DBI2 and at least 4KB outbound iATU-capable region are available.
> 

> outbound iATU-capable region? While configured with iATU, it's just 
> config space from a binding standpoint.

In this particular device the config-space is supposed to be mapped
over the outbound iATU region. It's a MMIO region mapped to the Source
side of the outbound iATU interface.

> 
> It's a bit more precise to do this:
> 
> items:
>   - description: DBI...
>   - description: DBI2...
>   - ...

I know, but I prefer using the reg-names property for that, while
having the 'reg' property with minItems/maxItems constraints specified.
In this case the reg property would be left unordered.

> 
> 
> > +    maxItems: 3
> 
> And then drop this.
> 
> > +
> > +  reg-names:
> > +    minItems: 3
> > +    maxItems: 3
> > +    items:
> > +      enum: [ dbi, dbi2, config ]
> 

> To enforce the order:
> 
> items:
>   - const: dbi
>   - const: dbi2
>   - const: config

Could you please explain why do you always suggest to define the ordered
X/X-names properties group? I just don't see much benefits in such
approach except that it's a bit more readable and one line shorter.

> 
> > +
> > +  interrupts:
> > +    description:
> > +      MSI, AER, PME, Hot-plug, Link Bandwidth Management, Link Equalization
> > +      request and eight Read/Write eDMA IRQ lines are available.
> > +    maxItems: 14
> > +
> > +  interrupt-names:
> > +    minItems: 14
> > +    maxItems: 14
> > +    items:
> > +      oneOf:
> > +        - pattern: '^dma[0-7]$'
> > +        - enum: [ msi, aer, pme, hp, bw_mg, l_eq ]
> 

> Can't you define the order?

Please, see my question in the previous comment.

> 
> > +
> > +  clocks:
> > +    description:
> > +      DBI (attached to the APB bus), AXI-bus master and slave interfaces
> > +      are fed up by the dedicated application clocks. A common reference
> > +      clock signal is supposed to be attached to the corresponding Ref-pad
> > +      of the SoC. It will be redistributed amongst the controller core
> > +      sub-modules (pipe, core, aux, etc).
> > +    minItems: 4
> > +    maxItems: 4
> > +
> > +  clock-names:
> > +    minItems: 4
> > +    maxItems: 4
> > +    items:
> > +      enum: [ dbi, mstr, slv, ref ]
> > +
> > +  resets:
> > +    description:
> > +      A comprehensive controller reset logic is supposed to be implemented
> > +      by software, so almost all the possible application and core reset
> > +      signals are exposed via the system CCU module.
> > +    minItems: 9
> > +    maxItems: 9
> > +
> > +  reset-names:
> > +    minItems: 9
> > +    maxItems: 9
> > +    items:
> > +      enum: [ mstr, slv, pwr, hot, phy, core, pipe, sticky, non-sticky ]
> 

> Again, define the order.

Could you tell me why it's better than unordered property? Really I
don't see good reason enough to define more constraints than required.

> 
> > +
> > +  syscon:
> 

> Needs a vendor prefix.

Ok.

> 
> > +    $ref: /schemas/types.yaml#/definitions/phandle
> > +    description:
> > +      Phandle to the Baikal-T1 System Controller DT node. It's required to
> > +      access some additional PM, Reset-related and LTSSM signals.
> > +
> > +  num-lanes:
> > +    maximum: 4
> > +
> > +  max-link-speed:
> > +    maximum: 3
> > +
> 
> > +  num-ob-windows:
> > +    const: 4
> > +
> > +  num-ib-windows:
> > +    const: 4
> 

> These are deprecated. The driver probes for how many now.

I know that they are deprecated. But they are deprecated on the DT
node level, not in the DT schema. Here by explicitly defining these
properties I signify that there are four in- and outbound iATU
windows. Doesn't that better describe our hardware?

-Sergey

> 
> > +
> > +required:
> > +  - compatible
> > +  - reg
> > +  - reg-names
> > +  - interrupts
> > +  - interrupt-names
> > +  - clocks
> > +  - clock-names
> > +  - resets
> > +  - reset-names
> > +
> > +unevaluatedProperties: false
> > +
> > +examples:
> > +  - |
> > +    pcie@1f052000 {
> > +      compatible = "baikal,bt1-pcie", "snps,dw-pcie-4.60a", "snps,dw-pcie";
> > +      device_type = "pci";
> > +      reg = <0x1f052000 0x1000>, <0x1f053000 0x1000>, <0x1bdbf000 0x1000>;
> > +      reg-names = "dbi", "dbi2", "config";
> > +      #address-cells = <3>;
> > +      #size-cells = <2>;
> > +      ranges = <0x81000000 0 0x00000000 0x1bdb0000 0 0x00008000>,
> > +               <0x82000000 0 0x20000000 0x08000000 0 0x13db0000>;
> > +      bus-range = <0x0 0xff>;
> > +
> > +      interrupts = <0 80 4>, <0 81 4>, <0 82 4>, <0 83 4>,
> > +                   <0 84 4>, <0 85 4>, <0 86 4>, <0 87 4>,
> > +                   <0 88 4>, <0 89 4>, <0 90 4>, <0 91 4>,
> > +                   <0 92 4>, <0 93 4>;
> > +      interrupt-names = "dma0", "dma1", "dma2", "dma3", "dma4", "dma5", "dma6",
> > +                        "dma7", "msi", "aer", "pme", "hp", "bw_mg", "l_eq";
> > +
> > +      clocks = <&ccu_sys 1>, <&ccu_axi 6>, <&ccu_axi 7>, <&clk_pcie>;
> > +      clock-names = "dbi", "mstr", "slv", "ref";
> > +
> > +      resets = <&ccu_axi 6>, <&ccu_axi 7>, <&ccu_sys 7>, <&ccu_sys 10>,
> > +               <&ccu_sys 4>, <&ccu_sys 6>, <&ccu_sys 5>, <&ccu_sys 8>,
> > +               <&ccu_sys 9>;
> > +      reset-names = "mstr", "slv", "pwr", "hot", "phy", "core", "pipe",
> > +                    "sticky", "non-sticky";
> > +
> > +      reset-gpios = <&port0 0 1>;
> > +
> > +      num-lanes = <4>;
> > +      max-link-speed = <3>;
> > +    };
> > +...
> > -- 
> > 2.35.1
> > 
> > 

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 03/16] PCI: dwc: Add more verbose link-up message
  2022-03-28 23:31   ` Joe Perches
@ 2022-04-16  8:01     ` Serge Semin
  0 siblings, 0 replies; 40+ messages in thread
From: Serge Semin @ 2022-04-16  8:01 UTC (permalink / raw)
  To: Joe Perches
  Cc: Serge Semin, Jingoo Han, Gustavo Pimentel, Bjorn Helgaas,
	Lorenzo Pieralisi, Rob Herring, Krzysztof Wilczyński,
	Alexey Malahov, Pavel Parkhomenko, Frank Li,
	Manivannan Sadhasivam, Rob Herring, linux-pci, devicetree,
	linux-kernel

On Mon, Mar 28, 2022 at 04:31:53PM -0700, Joe Perches wrote:
> On Thu, 2022-03-24 at 04:37 +0300, Serge Semin wrote:
> > Printing just "link up" isn't that much informative especially when it
> > comes to working with the PCI Express bus. Even if the link is up, due to
> > multiple reasons the bus performance can degrade to slower speeds or to
> > narrower width than both Root Port and its partner is capable of. In that
> > case it would be handy to know the link specifications as early as
> > possible. So let's add a more verbose message to the busy-wait link-state
> > method, which will contain the link speed generation and the PCIe bus
> > width in case if the link up state is discovered. Otherwise an error will
> > be printed to the system log.
> > 
> > Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> > ---
> >  drivers/pci/controller/dwc/pcie-designware.c | 22 +++++++++++++++-----
> >  1 file changed, 17 insertions(+), 5 deletions(-)
> > 
> > diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c
> []
> > @@ -528,14 +528,26 @@ int dw_pcie_wait_for_link(struct dw_pcie *pci)
> >  
> >  	/* Check if the link is up or not */
> >  	for (retries = 0; retries < LINK_WAIT_MAX_RETRIES; retries++) {
> > -		if (dw_pcie_link_up(pci)) {
> > -			dev_info(pci->dev, "Link up\n");
> > -			return 0;
> > -		}
> > +		if (dw_pcie_link_up(pci))
> > +			break;
> > +
> >  		usleep_range(LINK_WAIT_USLEEP_MIN, LINK_WAIT_USLEEP_MAX);
> >  	}
> >  
> > -	dev_info(pci->dev, "Phy link never came up\n");
> > +	if (retries < LINK_WAIT_MAX_RETRIES) {
> > +		u32 offset, val;
> > +
> > +		offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
> > +		val = dw_pcie_readw_dbi(pci, offset + PCI_EXP_LNKSTA);
> > +
> > +		dev_info(pci->dev, "PCIe Gen.%u x%u link up\n",
> > +			 FIELD_GET(PCI_EXP_LNKSTA_CLS, val),
> > +			 FIELD_GET(PCI_EXP_LNKSTA_NLW, val));
> > +
> > +		return 0;
> > +	}
> > +
> > +	dev_err(pci->dev, "Phy link never came up\n");
> >  
> >  	return -ETIMEDOUT;
> >  }
> 

> IMO: it's generally bette to test the error condition and unindent
> the typical return.

Absolutely right. Thanks for noticing that. No idea why I haven't done
the way you said 'cause it seems neater, more maintainable than what I
suggested here.

-Sergey

> 
> 	if (retries >= LINK_WAIT_MAX_RETRIES) {
> 		dev_err(pci->dev, "Phy link never came up\n");
> 		return -ETIMEDOUT;
> 	}
> 
> 	offset = ...
> 	val = ...
> 	dev_info(...)
> 
> 	return 0;
> }
> 

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 03/16] PCI: dwc: Add more verbose link-up message
  2022-03-29 14:47   ` Rob Herring
@ 2022-04-17 10:10     ` Serge Semin
  0 siblings, 0 replies; 40+ messages in thread
From: Serge Semin @ 2022-04-17 10:10 UTC (permalink / raw)
  To: Rob Herring
  Cc: Serge Semin, Jingoo Han, Gustavo Pimentel, Bjorn Helgaas,
	Lorenzo Pieralisi, Krzysztof Wilczyński, Alexey Malahov,
	Pavel Parkhomenko, Frank Li, Manivannan Sadhasivam, linux-pci,
	devicetree, linux-kernel

On Tue, Mar 29, 2022 at 09:47:02AM -0500, Rob Herring wrote:
> On Thu, Mar 24, 2022 at 04:37:21AM +0300, Serge Semin wrote:
> > Printing just "link up" isn't that much informative especially when it
> > comes to working with the PCI Express bus. Even if the link is up, due to
> > multiple reasons the bus performance can degrade to slower speeds or to
> > narrower width than both Root Port and its partner is capable of. In that
> > case it would be handy to know the link specifications as early as
> > possible. So let's add a more verbose message to the busy-wait link-state
> > method, which will contain the link speed generation and the PCIe bus
> > width in case if the link up state is discovered. Otherwise an error will
> > be printed to the system log.
> > 
> > Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> > ---
> >  drivers/pci/controller/dwc/pcie-designware.c | 22 +++++++++++++++-----
> >  1 file changed, 17 insertions(+), 5 deletions(-)
> > 
> > diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c
> > index 6e81264fdfb4..f1693e25afcb 100644
> > --- a/drivers/pci/controller/dwc/pcie-designware.c
> > +++ b/drivers/pci/controller/dwc/pcie-designware.c
> > @@ -528,14 +528,26 @@ int dw_pcie_wait_for_link(struct dw_pcie *pci)
> >  
> >  	/* Check if the link is up or not */
> >  	for (retries = 0; retries < LINK_WAIT_MAX_RETRIES; retries++) {
> > -		if (dw_pcie_link_up(pci)) {
> > -			dev_info(pci->dev, "Link up\n");
> > -			return 0;
> > -		}
> > +		if (dw_pcie_link_up(pci))
> > +			break;
> > +
> >  		usleep_range(LINK_WAIT_USLEEP_MIN, LINK_WAIT_USLEEP_MAX);
> >  	}
> >  
> > -	dev_info(pci->dev, "Phy link never came up\n");
> > +	if (retries < LINK_WAIT_MAX_RETRIES) {
> > +		u32 offset, val;
> > +
> > +		offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
> > +		val = dw_pcie_readw_dbi(pci, offset + PCI_EXP_LNKSTA);
> > +
> > +		dev_info(pci->dev, "PCIe Gen.%u x%u link up\n",
> > +			 FIELD_GET(PCI_EXP_LNKSTA_CLS, val),
> > +			 FIELD_GET(PCI_EXP_LNKSTA_NLW, val));
> 

> Given these are standard registers can we do this in the core code? The 
> main issue I think is that the config space accessors don't work until 
> you create the bus struct. That still should be early enough.

AFAICS there are generic methods in the core code to get and print the
link status. See the __pcie_print_link_status() method implementation.
But as you said they rely on having the bus struct instance created and
properly initialized. It's created in the framework of the PCI Host bridge
registration procedure:
pci_host_probe()
+-> pci_scan_root_bus_bridge()
    +-> pci_register_host_bridge()
        +-> pci_alloc_bus(NULL); 
        +-> ...
As for me it would be more logical to have the PCIe link established
(at least activated) and it' status logged before any of the denoted
actions are made since further initialization rely on the PCIe bus
transfers. Moreover the PCIe host probe procedure doesn't really
perform any link up/down related activity, so there is no logical
place to implement the link state checking except someplace at the
traceback top position, but again the bus struct instance isn't
available at that stage. Of course we could implement an alternative
__pcie_print_HOST_link_status() method, which wouldn't need the bus
struct passed. But that would have required some more modifications
(and may cause some functionality duplication) than fixing a few lines
of code and wasn't a subject of this patchset. As such I decided to
stick with having the local link status logging procedure especially
seeing it's done in the framework of the link-wait method, which is
called right after the DW PCIe LTSSM is activated (at least for the DW
PCIe Host controller).

> 
> I think it is possible some implementations don't report the link state 
> in these registers. Maybe we don't really need to care.

I don't see a way to disable the PCIe capability in the DW PCIe
controllers. So if some implementations lack of these registers
reporting the link state, then either those implementations must have
been broken or they violate the PCIe Base Specification [1]. IMO that
must be considered as abnormal situation and needs to be specifically
handled.

[1] PCI Express® Base Specification Revision 5.0, p. 742.

-Sergey

> 
> Rob

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 04/16] PCI: dwc: Convert to using native IP-core versions representation
  2022-03-29 15:00   ` Rob Herring
@ 2022-04-17 14:42     ` Serge Semin
  0 siblings, 0 replies; 40+ messages in thread
From: Serge Semin @ 2022-04-17 14:42 UTC (permalink / raw)
  To: Rob Herring
  Cc: Serge Semin, Jingoo Han, Gustavo Pimentel, Bjorn Helgaas,
	Lorenzo Pieralisi, Krzysztof Wilczyński, Rahul Tanwar,
	Thierry Reding, Jonathan Hunter, Alexey Malahov,
	Pavel Parkhomenko, Frank Li, Manivannan Sadhasivam, linux-pci,
	devicetree, linux-kernel, linux-tegra

On Tue, Mar 29, 2022 at 10:00:38AM -0500, Rob Herring wrote:
> On Thu, Mar 24, 2022 at 04:37:22AM +0300, Serge Semin wrote:
> > Since DWC PCIe v4.70a the controller version can be read from the
> > PORT_LOGIC.PCIE_VERSION_OFF register. Version is represented in the FourCC
> > format [1]. It's standard versioning approach for the Synopsys DWC
> > IP-cores. Moreover some of the DWC kernel drivers already make use of it
> > to fixup version-dependent functionality (See DWC USB3, Stmicro STMMAC or
> > recent DW SPI driver). In order to preserve the standard version
> > representation and prevent the data conversion back and forth, we suggest
> > to preserve the native version representation in the DWC PCIe driver too
> > in the same way as it has already been done in the rest of the DWC
> > drivers. IP-core version reading from the CSR will be introduced in the
> > next commit together with a simple macro-based API to use it.
> > 
> > [1] https://en.wikipedia.org/wiki/FourCC
> > 
> > Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> > ---
> >  drivers/pci/controller/dwc/pci-keystone.c    | 12 ++++++------
> >  drivers/pci/controller/dwc/pcie-designware.c |  8 ++++----
> >  drivers/pci/controller/dwc/pcie-designware.h | 10 +++++++++-
> >  drivers/pci/controller/dwc/pcie-intel-gw.c   |  4 ++--
> >  drivers/pci/controller/dwc/pcie-tegra194.c   |  2 +-
> >  5 files changed, 22 insertions(+), 14 deletions(-)
> > 
> > diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c
> > index 1c2ee4e13f1c..ec65355dd29b 100644
> > --- a/drivers/pci/controller/dwc/pci-keystone.c
> > +++ b/drivers/pci/controller/dwc/pci-keystone.c
> > @@ -109,7 +109,7 @@ struct ks_pcie_of_data {
> >  	enum dw_pcie_device_mode mode;
> >  	const struct dw_pcie_host_ops *host_ops;
> >  	const struct dw_pcie_ep_ops *ep_ops;
> > -	unsigned int version;
> > +	u32 version;
> >  };
> >  
> >  struct keystone_pcie {
> > @@ -1069,19 +1069,19 @@ static int ks_pcie_am654_set_mode(struct device *dev,
> >  
> >  static const struct ks_pcie_of_data ks_pcie_rc_of_data = {
> >  	.host_ops = &ks_pcie_host_ops,
> > -	.version = 0x365A,
> > +	.version = DW_PCIE_VER_365A,
> >  };
> >  
> >  static const struct ks_pcie_of_data ks_pcie_am654_rc_of_data = {
> >  	.host_ops = &ks_pcie_am654_host_ops,
> >  	.mode = DW_PCIE_RC_TYPE,

> > -	.version = 0x490A,
> > +	.version = DW_PCIE_VER_490A,
> 
> This version should be readable, so get rid of hardcoding it here.

Sorry but what do you mean by 'readable'? Do you mean that since the
version CSR has been available since 4.70a, it is supposed to be read
from the h/w registers for the newer IPs and there is no point in
having that field initialized here? If so do you suggest to drop the
initialization from the both pci-keystone.c:ks_pcie_am654_rc_of_data
and pci-keystone.c:ks_pcie_am654_rc_of_data structure instances? If
so then the same can be done in the pcie-tegra194.c and
pcie-intel-gw.c drivers. Shall I drop it from there too?

Anyway if that's what you mean it needs to be done in a dedicated
patch, not here.

> 
> >  };
> >  
> >  static const struct ks_pcie_of_data ks_pcie_am654_ep_of_data = {
> >  	.ep_ops = &ks_pcie_am654_ep_ops,
> >  	.mode = DW_PCIE_EP_TYPE,
> > -	.version = 0x490A,
> > +	.version = DW_PCIE_VER_490A,
> >  };
> >  
> >  static const struct of_device_id ks_pcie_of_match[] = {
> > @@ -1114,12 +1114,12 @@ static int __init ks_pcie_probe(struct platform_device *pdev)
> >  	struct device_link **link;
> >  	struct gpio_desc *gpiod;
> >  	struct resource *res;
> > -	unsigned int version;
> >  	void __iomem *base;
> >  	u32 num_viewport;
> >  	struct phy **phy;
> >  	u32 num_lanes;
> >  	char name[10];
> > +	u32 version;
> >  	int ret;
> >  	int irq;
> >  	int i;
> > @@ -1233,7 +1233,7 @@ static int __init ks_pcie_probe(struct platform_device *pdev)
> >  		goto err_get_sync;
> >  	}
> >  
> > -	if (pci->version >= 0x480A)
> > +	if (pci->version >= DW_PCIE_VER_480A)
> >  		ret = ks_pcie_am654_set_mode(dev, mode);
> >  	else
> >  		ret = ks_pcie_set_mode(dev);
> > diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c
> > index f1693e25afcb..c21373c6cb51 100644
> > --- a/drivers/pci/controller/dwc/pcie-designware.c
> > +++ b/drivers/pci/controller/dwc/pcie-designware.c
> > @@ -289,7 +289,7 @@ static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, u8 func_no,
> >  	val = type | PCIE_ATU_FUNC_NUM(func_no);
> >  	if (upper_32_bits(limit_addr) > upper_32_bits(cpu_addr))
> >  		val |= PCIE_ATU_INCREASE_REGION_SIZE;
> > -	if (pci->version == 0x490A)
> > +	if (pci->version == DW_PCIE_VER_490A)
> >  		val = dw_pcie_enable_ecrc(val);
> >  	dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1, val);
> >  	dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL2,
> > @@ -336,7 +336,7 @@ static void __dw_pcie_prog_outbound_atu(struct dw_pcie *pci, u8 func_no,
> >  			   upper_32_bits(cpu_addr));
> >  	dw_pcie_writel_dbi(pci, PCIE_ATU_LIMIT,
> >  			   lower_32_bits(limit_addr));
> > -	if (pci->version >= 0x460A)
> > +	if (pci->version >= DW_PCIE_VER_460A)
> >  		dw_pcie_writel_dbi(pci, PCIE_ATU_UPPER_LIMIT,
> >  				   upper_32_bits(limit_addr));
> >  	dw_pcie_writel_dbi(pci, PCIE_ATU_LOWER_TARGET,
> > @@ -345,9 +345,9 @@ static void __dw_pcie_prog_outbound_atu(struct dw_pcie *pci, u8 func_no,
> >  			   upper_32_bits(pci_addr));
> >  	val = type | PCIE_ATU_FUNC_NUM(func_no);
> >  	if (upper_32_bits(limit_addr) > upper_32_bits(cpu_addr) &&
> > -	    pci->version >= 0x460A)
> > +	    pci->version >= DW_PCIE_VER_460A)
> >  		val |= PCIE_ATU_INCREASE_REGION_SIZE;
> > -	if (pci->version == 0x490A)
> > +	if (pci->version == DW_PCIE_VER_490A)
> >  		val = dw_pcie_enable_ecrc(val);
> >  	dw_pcie_writel_dbi(pci, PCIE_ATU_CR1, val);
> >  	dw_pcie_writel_dbi(pci, PCIE_ATU_CR2, PCIE_ATU_ENABLE);
> > diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
> > index 7d6e9b7576be..5be43c662176 100644
> > --- a/drivers/pci/controller/dwc/pcie-designware.h
> > +++ b/drivers/pci/controller/dwc/pcie-designware.h
> > @@ -20,6 +20,14 @@
> >  #include <linux/pci-epc.h>
> >  #include <linux/pci-epf.h>
> >  

> > +/* DWC PCIe IP-core versions (native support since v4.70a) */
> > +#define DW_PCIE_VER_365A		0x3336352a
> > +#define DW_PCIE_VER_460A		0x3436302a
> > +#define DW_PCIE_VER_470A		0x3437302a
> > +#define DW_PCIE_VER_480A		0x3438302a
> > +#define DW_PCIE_VER_490A		0x3439302a
> > +#define DW_PCIE_VER_520A		0x3532302a
> 
> Create a macro to form these so we can do:
> 
> DW_PCIE_VER('5', '2', '0', 'A')

I am ok with that as long as you suggest to use it in the definition
of the macros above. Like this:

+#define DW_PCIE_VER_365A	__DW_PCIE_VER('3', '5', '6', '*')

otherwise if we used the macro suggested by you right in the code or
in the introduced further dw_pcie_ver_is() macros, the version
checking conditional statements turn into the much longer constructions.
I'd rather avoid that. So could you clarify what is the usage scenario
of the macro DW_PCIE_VER() suggested by you?

Please also note that mainly the DW PCIe (USB, SPI, *MAC, etc) FourCC
versions don't contain the letter symbols, but are enclosed with the
'*' symbol (see 0x2a ASCII code). So the 3.65a version isn't encoded
as 0x333635_61_, but as 0x333635_2a_. I don't know a real reasoning of
that, but can guess that the same version value might be used for the
series of releases like 3.65a, 4.65b, 4.65c, etc as some kind of
wildcard. Alas I don't have any non-'a' implementation of the Synopsys
IP-core to check that out.

-Sergey

> 
> > +
> >  /* Parameters for the waiting for link up routine */
> >  #define LINK_WAIT_MAX_RETRIES		10
> >  #define LINK_WAIT_USLEEP_MIN		90000
> > @@ -269,7 +277,7 @@ struct dw_pcie {
> >  	struct pcie_port	pp;
> >  	struct dw_pcie_ep	ep;
> >  	const struct dw_pcie_ops *ops;
> > -	unsigned int		version;
> > +	u32			version;
> >  	int			num_lanes;
> >  	int			link_gen;
> >  	u8			n_fts[2];
> > diff --git a/drivers/pci/controller/dwc/pcie-intel-gw.c b/drivers/pci/controller/dwc/pcie-intel-gw.c
> > index 5ba144924ff8..786af2ba379f 100644
> > --- a/drivers/pci/controller/dwc/pcie-intel-gw.c
> > +++ b/drivers/pci/controller/dwc/pcie-intel-gw.c
> > @@ -59,7 +59,7 @@
> >  #define RESET_INTERVAL_MS		100
> >  
> >  struct intel_pcie_soc {
> > -	unsigned int	pcie_ver;
> > +	u32	pcie_ver;
> >  };
> >  
> >  struct intel_pcie {
> > @@ -395,7 +395,7 @@ static const struct dw_pcie_host_ops intel_pcie_dw_ops = {
> >  };
> >  
> >  static const struct intel_pcie_soc pcie_data = {
> > -	.pcie_ver =		0x520A,
> > +	.pcie_ver =		DW_PCIE_VER_520A,
> >  };
> >  
> >  static int intel_pcie_probe(struct platform_device *pdev)
> > diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c
> > index b1b5f836a806..6f1330ed63e5 100644
> > --- a/drivers/pci/controller/dwc/pcie-tegra194.c
> > +++ b/drivers/pci/controller/dwc/pcie-tegra194.c
> > @@ -1981,7 +1981,7 @@ static int tegra194_pcie_probe(struct platform_device *pdev)
> >  	pci->ops = &tegra_dw_pcie_ops;
> >  	pci->n_fts[0] = N_FTS_VAL;
> >  	pci->n_fts[1] = FTS_VAL;
> > -	pci->version = 0x490A;
> > +	pci->version = DW_PCIE_VER_490A;
> >  
> >  	pp = &pci->pp;
> >  	pp->num_vectors = MAX_MSI_IRQS;
> > -- 
> > 2.35.1
> > 

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 05/16] PCI: dwc: Add IP-core version detection procedure
  2022-03-29 15:08   ` Rob Herring
@ 2022-04-17 15:13     ` Serge Semin
  0 siblings, 0 replies; 40+ messages in thread
From: Serge Semin @ 2022-04-17 15:13 UTC (permalink / raw)
  To: Rob Herring
  Cc: Serge Semin, Jingoo Han, Gustavo Pimentel, Bjorn Helgaas,
	Lorenzo Pieralisi, Krzysztof Wilczyński, Alexey Malahov,
	Pavel Parkhomenko, Frank Li, Manivannan Sadhasivam, linux-pci,
	devicetree, linux-kernel

On Tue, Mar 29, 2022 at 10:08:53AM -0500, Rob Herring wrote:
> On Thu, Mar 24, 2022 at 04:37:23AM +0300, Serge Semin wrote:
> > Since DWC PCIe v4.70a the controller version and version type can be read
> > from the PORT_LOGIC.PCIE_VERSION_OFF and PORT_LOGIC.PCIE_VERSION_TYPE_OFF
> > registers respectively. Seeing the generic code has got version-dependent
> > parts let's use these registers to find out the controller version.  The
> > detection procedure is executed for both RC and EP modes right after the
> > platform-specific initialization. We can't do that earlier since the
> > glue-drivers can perform the DBI-related setups there including the bus
> > reference clocks activation, without which the CSRs just can't be read.
> > 
> > Note the CSRs content is zero on the older DWC PCIe controller. In that
> > case we have no choice but to rely on the platform setup.
> > 
> > Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> > ---
> >  .../pci/controller/dwc/pcie-designware-ep.c   |  2 ++
> >  .../pci/controller/dwc/pcie-designware-host.c |  2 ++
> >  drivers/pci/controller/dwc/pcie-designware.c  | 24 +++++++++++++++++++
> >  drivers/pci/controller/dwc/pcie-designware.h  |  6 +++++
> >  4 files changed, 34 insertions(+)
> > 
> > diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c
> > index 7c9315fffe24..3b981d13cca9 100644
> > --- a/drivers/pci/controller/dwc/pcie-designware-ep.c
> > +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c
> > @@ -645,6 +645,8 @@ int dw_pcie_ep_init_complete(struct dw_pcie_ep *ep)
> >  	u32 reg;
> >  	int i;
> >  
> > +	dw_pcie_version_detect(pci);
> > +
> >  	hdr_type = dw_pcie_readb_dbi(pci, PCI_HEADER_TYPE) &
> >  		   PCI_HEADER_TYPE_MASK;
> >  	if (hdr_type != PCI_HEADER_TYPE_NORMAL) {
> > diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c
> > index 8364ea234e88..8f0d473ff770 100644
> > --- a/drivers/pci/controller/dwc/pcie-designware-host.c
> > +++ b/drivers/pci/controller/dwc/pcie-designware-host.c
> > @@ -398,6 +398,8 @@ int dw_pcie_host_init(struct pcie_port *pp)
> >  		}
> >  	}
> >  
> > +	dw_pcie_version_detect(pci);
> > +
> >  	dw_pcie_iatu_detect(pci);
> >  
> >  	dw_pcie_setup_rc(pp);
> > diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c
> > index c21373c6cb51..49c494d82042 100644
> > --- a/drivers/pci/controller/dwc/pcie-designware.c
> > +++ b/drivers/pci/controller/dwc/pcie-designware.c
> > @@ -16,6 +16,30 @@
> >  #include "../../pci.h"
> >  #include "pcie-designware.h"
> >  
> > +void dw_pcie_version_detect(struct dw_pcie *pci)
> > +{
> > +	u32 ver;
> > +
> > +	/* The content of the CSR is zero on DWC PCIe older than v4.70a */
> > +	ver = dw_pcie_readl_dbi(pci, PCIE_VERSION_NUMBER);
> > +	if (!ver)
> > +		return;
> > +
> > +	if (pci->version && pci->version != ver)
> > +		dev_warn(pci->dev, "Versions don't match (%08x != %08x)\n",
> > +			 pci->version, ver);
> 

> Trust the h/w is correct until we have a known case where it isn't. Just 
> read the h/w reg if pci->version is zero.
> 
> I would suspect as-is this will give some warnings. No doubt there is 
> some platform with multiple revs of Si that didn't change their version 
> in the driver. Or the author just guessed on the version that picked the 
> right paths in the driver.

I'm not sure I fully get it. Could you elaborate what you suggest
here?  Do you suggest for me to drop the warnings and rewrite the
pci->{version, type} fields with the values read from the registers if
these fields were set with zeros?

-Sergey

> 
> Rob

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 10/16] PCI: dwc: Drop iATU regions enumeration - dw_pcie_region_type
  2022-03-29 15:31   ` Rob Herring
@ 2022-04-17 17:52     ` Serge Semin
  0 siblings, 0 replies; 40+ messages in thread
From: Serge Semin @ 2022-04-17 17:52 UTC (permalink / raw)
  To: Rob Herring
  Cc: Serge Semin, Jingoo Han, Gustavo Pimentel, Bjorn Helgaas,
	Lorenzo Pieralisi, Krzysztof Wilczyński, Alexey Malahov,
	Pavel Parkhomenko, Frank Li, Manivannan Sadhasivam, linux-pci,
	devicetree, linux-kernel

On Tue, Mar 29, 2022 at 10:31:18AM -0500, Rob Herring wrote:
> On Thu, Mar 24, 2022 at 04:37:28AM +0300, Serge Semin wrote:
> > There is no point in having the dw_pcie_region_type enumeration for almost
> > the same reasons as it was stated for dw_pcie_as_type. First of all it's
> > redundant since the driver already has a set of macro declared which
> > describe the possible inbound and outbound iATU regions. Having an
> > addition abstraction just needlessly complicates the code. Secondly
> > checking the region index passed to the dw_pcie_disable_atu() method for
> > validity is pointless since the erroneous situation will be just
> > ignored in the current code implementation. So to speak let's drop the
> > redundant dw_pcie_region_type enumeration replacing it with the direct
> > iATU direction macro usage.
> > 
> > While at it we suggest to convert the dw_pcie_disable_atu() method to
> > being more consistent with the dw_pcie_readl_atu{_ib}() and
> > dw_pcie_readl_atu{_ob}() functions by having the direction parameter
> > specified ahead of the region index. Thus the code will be a little bit
> > more pleasant to read.
> > 
> > Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> > ---
> >  drivers/pci/controller/dwc/pcie-designware-ep.c  |  4 ++--
> >  .../pci/controller/dwc/pcie-designware-host.c    |  2 +-
> >  drivers/pci/controller/dwc/pcie-designware.c     | 16 +---------------
> >  drivers/pci/controller/dwc/pcie-designware.h     |  9 +--------
> >  4 files changed, 5 insertions(+), 26 deletions(-)
> 

> This answers my question. I would have expected this to come before the 
> previous patch, but if it's easier to do it this way it's fine.
> 
> Reviewed-by: Rob Herring <robh@kernel.org>

I thought about placing this patch before the previous one, but it
turned a bit easier for me to split the changes in the reverse order.
It has made this patch a bit smaller and more coherent. But seeing you
weren't happy with too many changes in the previous patch I'll do as
you suggest and change the patches order. Since the patch content will
be changed I won't add your reviewed-by tag there on v2. So please
consider re-reviewing it one more time.

-Sergey


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 09/16] PCI: dwc: Simplify in/outbound iATU setup methods
  2022-03-29 15:28   ` Rob Herring
@ 2022-04-17 20:08     ` Serge Semin
  0 siblings, 0 replies; 40+ messages in thread
From: Serge Semin @ 2022-04-17 20:08 UTC (permalink / raw)
  To: Rob Herring
  Cc: Serge Semin, Jingoo Han, Gustavo Pimentel, Bjorn Helgaas,
	Lorenzo Pieralisi, Krzysztof Wilczyński, Alexey Malahov,
	Pavel Parkhomenko, Frank Li, Manivannan Sadhasivam, linux-pci,
	devicetree, linux-kernel

On Tue, Mar 29, 2022 at 10:28:56AM -0500, Rob Herring wrote:
> On Thu, Mar 24, 2022 at 04:37:27AM +0300, Serge Semin wrote:
> > From maintainability and scalability points of view it has been wrong to
> > use different iATU inbound and outbound regions accessors for the viewport
> > and unrolled versions of the iATU CSRs mapping. Seeing the particular iATU
> > region-wise registers layout is almost fully compatible for different
> > IP-core versions, there were no much points in splitting the code up that
> > way since it was possible to implement a common windows setup methods for
> > both viewport and unrolled iATU CSRs spaces. While what we can observe in
> > the current driver implementation of these methods, is a lot of code
> > duplication, which consequently worsen the code readability,
> > maintainability and scalability. Note the current implementation is a bit
> > more performant than the one suggested in this commit since it implies
> > having less MMIO accesses. But the gain just doesn't worth having the
> > denoted difficulties especially seeing the iATU setup methods are mainly
> > called on the DW PCIe controller and peripheral devices initialization
> > stage.
> > 
> > Here we suggest to move the iATU viewport and unrolled CSR access
> > specifics in the dw_pcie_readl_atu() and dw_pcie_writel_atu() method, and
> > convert the dw_pcie_prog_outbound_atu() and
> > dw_pcie_prog_{ep_}inbound_atu() functions to being generic instead of
> > having a different methods for each viewport and unrolled types of iATU
> > CSRs mapping. Nothing complex really. First of all the dw_pcie_readl_atu()
> > and dw_pcie_writel_atu() are converted to accept relative iATU CSRs
> > address together with the iATU region direction (inbound or outbound) and
> > region index. If DW PCIe controller doesn't have the unrolled iATU CSRs
> > space, then the accessors will need to activate a iATU viewport based on
> > the specified direction and index, otherwise a base address for the
> > corresponding region CSRs will be calculated by means of the
> > PCIE_ATU_UNROLL_BASE() macro. The CSRs macro have been modified in
> > accordance with that logic in the pcie-designware.h header file.
> > 
> > The rest of the changes in this commit just concern converting the iATU
> > in-/out-bound setup methods and iATU regions detection procedure to be
> > compatible with the new accessors semantics. As a result we've dropped the
> > no more required dw_pcie_prog_outbound_atu_unroll(),
> > dw_pcie_prog_inbound_atu_unroll() and dw_pcie_iatu_detect_regions_unroll()
> > methods.
> > 
> > Note aside with the denoted code improvements, there is an additional
> > positive side effect of this change. If at some point an atomic iATU
> > configs setup procedure is required, it will be possible to be done with
> > no much effort just by adding the synchronization into the
> > dw_pcie_readl_atu() and dw_pcie_writel_atu() accessors.
> > 
> > Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> > ---
> >  drivers/pci/controller/dwc/pcie-designware.c | 301 ++++++-------------
> >  drivers/pci/controller/dwc/pcie-designware.h |  50 ++-
> >  2 files changed, 112 insertions(+), 239 deletions(-)
> 

> Nice diffstat. I didn't really like how this was implemented either.

Yeah, the change has turned to be a bit bulky. I wouldn't really
bother with it if I didn't need to add the "dma-ranges" support.

> 
> I'm guessing you tested the unrolled case only? IIRC, QEMU has the older 
> interface. I can also throw this at kernel-ci if needed. There's a few 
> platforms with DWC that get tested.

In fact I tested the series on DW PCIe Host v4.60a with the legacy
iATU/eDMA registers mapping (viewport-based). So testing on the modern
controllers with the unrolled iATU/eDMA region would be very welcome.

> 
> > 
> > diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c
> > index b983128584ff..f1aa6e2e85fe 100644
> > --- a/drivers/pci/controller/dwc/pcie-designware.c
> > +++ b/drivers/pci/controller/dwc/pcie-designware.c
> > @@ -205,48 +205,67 @@ void dw_pcie_write_dbi2(struct dw_pcie *pci, u32 reg, size_t size, u32 val)
> >  		dev_err(pci->dev, "write DBI address failed\n");
> >  }
> >  
> > -static u32 dw_pcie_readl_atu(struct dw_pcie *pci, u32 reg)
> > +static u32 dw_pcie_readl_atu(struct dw_pcie *pci, u32 dir, u32 region, u32 reg)
> >  {
> > +	void __iomem *base;
> >  	int ret;
> >  	u32 val;
> >  
> > +	if (pci->iatu_unroll_enabled) {
> > +		base = pci->atu_base;
> > +		reg = reg + PCIE_ATU_UNROLL_BASE(dir, region);
> > +	} else {
> > +		base = pci->dbi_base;
> > +		reg = reg + PCIE_ATU_VIEWPORT_BASE;
> > +
> > +		dw_pcie_writel_dbi(pci, PCIE_ATU_VIEWPORT, dir | region);
> > +	}
> > +
> >  	if (pci->ops && pci->ops->read_dbi)
> > -		return pci->ops->read_dbi(pci, pci->atu_base, reg, 4);
> > +		return pci->ops->read_dbi(pci, base, reg, 4);
> >  
> > -	ret = dw_pcie_read(pci->atu_base + reg, 4, &val);
> > +	ret = dw_pcie_read(base + reg, 4, &val);
> >  	if (ret)
> >  		dev_err(pci->dev, "Read ATU address failed\n");
> >  
> >  	return val;
> >  }
> >  
> > -static void dw_pcie_writel_atu(struct dw_pcie *pci, u32 reg, u32 val)
> > +static void dw_pcie_writel_atu(struct dw_pcie *pci, u32 dir, u32 region,
> > +			       u32 reg, u32 val)
> >  {
> > +	void __iomem *base;
> >  	int ret;
> >  
> > +	if (pci->iatu_unroll_enabled) {
> > +		base = pci->atu_base;
> > +		reg = reg + PCIE_ATU_UNROLL_BASE(dir, region);
> > +	} else {
> > +		base = pci->dbi_base;
> > +		reg = reg + PCIE_ATU_VIEWPORT_BASE;
> > +
> > +		dw_pcie_writel_dbi(pci, PCIE_ATU_VIEWPORT, dir | region);
> > +	}
> 

> You have this same sequence twice. Make it a helper function.

Ok. I'll move this code into a helper function - dw_pcie_select_atu().

> 
> > +
> >  	if (pci->ops && pci->ops->write_dbi) {
> > -		pci->ops->write_dbi(pci, pci->atu_base, reg, 4, val);
> > +		pci->ops->write_dbi(pci, base, reg, 4, val);
> >  		return;
> >  	}
> >  
> > -	ret = dw_pcie_write(pci->atu_base + reg, 4, val);
> > +	ret = dw_pcie_write(base + reg, 4, val);
> >  	if (ret)
> >  		dev_err(pci->dev, "Write ATU address failed\n");
> >  }
> >  
> > -static u32 dw_pcie_readl_ob_unroll(struct dw_pcie *pci, u32 index, u32 reg)
> > +static inline u32 dw_pcie_readl_atu_ob(struct dw_pcie *pci, u32 region, u32 reg)
> >  {
> > -	u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index);
> > -
> > -	return dw_pcie_readl_atu(pci, offset + reg);
> > +	return dw_pcie_readl_atu(pci, PCIE_ATU_REGION_DIR_OB, region, reg);
> >  }
> >  
> > -static void dw_pcie_writel_ob_unroll(struct dw_pcie *pci, u32 index, u32 reg,
> > -				     u32 val)
> > +static inline void dw_pcie_writel_atu_ob(struct dw_pcie *pci, u32 region, u32 reg,
> > +					 u32 val)
> >  {
> > -	u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index);
> > -
> > -	dw_pcie_writel_atu(pci, offset + reg, val);
> > +	dw_pcie_writel_atu(pci, PCIE_ATU_REGION_DIR_OB, region, reg, val);
> >  }
> >  
> >  static inline u32 dw_pcie_enable_ecrc(u32 val)
> > @@ -290,50 +309,6 @@ static inline u32 dw_pcie_enable_ecrc(u32 val)
> >  	return val | PCIE_ATU_TD;
> >  }
> >  
> > -static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, u8 func_no,
> > -					     int index, int type,
> > -					     u64 cpu_addr, u64 pci_addr,
> > -					     u64 size)
> > -{
> > -	u32 retries, val;
> > -	u64 limit_addr = cpu_addr + size - 1;
> > -
> > -	dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LOWER_BASE,
> > -				 lower_32_bits(cpu_addr));
> > -	dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_BASE,
> > -				 upper_32_bits(cpu_addr));
> > -	dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LOWER_LIMIT,
> > -				 lower_32_bits(limit_addr));
> > -	dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_LIMIT,
> > -				 upper_32_bits(limit_addr));
> > -	dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LOWER_TARGET,
> > -				 lower_32_bits(pci_addr));
> > -	dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_TARGET,
> > -				 upper_32_bits(pci_addr));
> > -	val = type | PCIE_ATU_FUNC_NUM(func_no);
> > -	if (upper_32_bits(limit_addr) > upper_32_bits(cpu_addr))
> > -		val |= PCIE_ATU_INCREASE_REGION_SIZE;
> > -	if (dw_pcie_ver_is(pci, 490A))
> > -		val = dw_pcie_enable_ecrc(val);
> > -	dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1, val);
> > -	dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL2,
> > -				 PCIE_ATU_ENABLE);
> > -
> > -	/*
> > -	 * Make sure ATU enable takes effect before any subsequent config
> > -	 * and I/O accesses.
> > -	 */
> > -	for (retries = 0; retries < LINK_WAIT_MAX_IATU_RETRIES; retries++) {
> > -		val = dw_pcie_readl_ob_unroll(pci, index,
> > -					      PCIE_ATU_UNR_REGION_CTRL2);
> > -		if (val & PCIE_ATU_ENABLE)
> > -			return;
> > -
> > -		mdelay(LINK_WAIT_IATU);
> > -	}
> > -	dev_err(pci->dev, "Outbound iATU is not being enabled\n");
> > -}
> > -
> >  static void __dw_pcie_prog_outbound_atu(struct dw_pcie *pci, u8 func_no,
> >  					int index, int type, u64 cpu_addr,
> >  					u64 pci_addr, u64 size)
> > @@ -344,49 +319,46 @@ static void __dw_pcie_prog_outbound_atu(struct dw_pcie *pci, u8 func_no,
> >  	if (pci->ops && pci->ops->cpu_addr_fixup)
> >  		cpu_addr = pci->ops->cpu_addr_fixup(pci, cpu_addr);
> >  
> > -	if (pci->iatu_unroll_enabled) {
> > -		dw_pcie_prog_outbound_atu_unroll(pci, func_no, index, type,
> > -						 cpu_addr, pci_addr, size);
> > -		return;
> > -	}
> > -
> >  	limit_addr = cpu_addr + size - 1;
> >  
> > -	dw_pcie_writel_dbi(pci, PCIE_ATU_VIEWPORT,
> > -			   PCIE_ATU_REGION_OUTBOUND | index);
> > -	dw_pcie_writel_dbi(pci, PCIE_ATU_LOWER_BASE,
> > -			   lower_32_bits(cpu_addr));
> > -	dw_pcie_writel_dbi(pci, PCIE_ATU_UPPER_BASE,
> > -			   upper_32_bits(cpu_addr));
> > -	dw_pcie_writel_dbi(pci, PCIE_ATU_LIMIT,
> > -			   lower_32_bits(limit_addr));
> > +	dw_pcie_writel_atu_ob(pci, index, PCIE_ATU_LOWER_BASE,
> > +			      lower_32_bits(cpu_addr));
> > +	dw_pcie_writel_atu_ob(pci, index, PCIE_ATU_UPPER_BASE,
> > +			      upper_32_bits(cpu_addr));
> > +
> > +	dw_pcie_writel_atu_ob(pci, index, PCIE_ATU_LIMIT,
> > +			      lower_32_bits(limit_addr));
> >  	if (dw_pcie_ver_is_ge(pci, 460A))
> > -		dw_pcie_writel_dbi(pci, PCIE_ATU_UPPER_LIMIT,
> > -				   upper_32_bits(limit_addr));
> > -	dw_pcie_writel_dbi(pci, PCIE_ATU_LOWER_TARGET,
> > -			   lower_32_bits(pci_addr));
> > -	dw_pcie_writel_dbi(pci, PCIE_ATU_UPPER_TARGET,
> > -			   upper_32_bits(pci_addr));
> > +		dw_pcie_writel_atu_ob(pci, index, PCIE_ATU_UPPER_LIMIT,
> > +				      upper_32_bits(limit_addr));
> > +
> > +	dw_pcie_writel_atu_ob(pci, index, PCIE_ATU_LOWER_TARGET,
> > +			      lower_32_bits(pci_addr));
> > +	dw_pcie_writel_atu_ob(pci, index, PCIE_ATU_UPPER_TARGET,
> > +			      upper_32_bits(pci_addr));
> > +
> >  	val = type | PCIE_ATU_FUNC_NUM(func_no);
> >  	if (upper_32_bits(limit_addr) > upper_32_bits(cpu_addr) &&
> >  	    dw_pcie_ver_is_ge(pci, 460A))
> >  		val |= PCIE_ATU_INCREASE_REGION_SIZE;
> >  	if (dw_pcie_ver_is(pci, 490A))
> >  		val = dw_pcie_enable_ecrc(val);
> > -	dw_pcie_writel_dbi(pci, PCIE_ATU_CR1, val);
> > -	dw_pcie_writel_dbi(pci, PCIE_ATU_CR2, PCIE_ATU_ENABLE);
> > +	dw_pcie_writel_atu_ob(pci, index, PCIE_ATU_REGION_CTRL1, val);
> > +
> > +	dw_pcie_writel_atu_ob(pci, index, PCIE_ATU_REGION_CTRL2, PCIE_ATU_ENABLE);
> >  
> >  	/*
> >  	 * Make sure ATU enable takes effect before any subsequent config
> >  	 * and I/O accesses.
> >  	 */
> >  	for (retries = 0; retries < LINK_WAIT_MAX_IATU_RETRIES; retries++) {
> > -		val = dw_pcie_readl_dbi(pci, PCIE_ATU_CR2);
> > +		val = dw_pcie_readl_atu_ob(pci, index, PCIE_ATU_REGION_CTRL2);
> >  		if (val & PCIE_ATU_ENABLE)
> >  			return;
> >  
> >  		mdelay(LINK_WAIT_IATU);
> >  	}
> > +
> >  	dev_err(pci->dev, "Outbound iATU is not being enabled\n");
> >  }
> >  
> > @@ -405,54 +377,15 @@ void dw_pcie_prog_ep_outbound_atu(struct dw_pcie *pci, u8 func_no, int index,
> >  				    cpu_addr, pci_addr, size);
> >  }
> >  
> > -static u32 dw_pcie_readl_ib_unroll(struct dw_pcie *pci, u32 index, u32 reg)
> > -{
> > -	u32 offset = PCIE_GET_ATU_INB_UNR_REG_OFFSET(index);
> > -
> > -	return dw_pcie_readl_atu(pci, offset + reg);
> > -}
> > -
> > -static void dw_pcie_writel_ib_unroll(struct dw_pcie *pci, u32 index, u32 reg,
> > -				     u32 val)
> > +static inline u32 dw_pcie_readl_atu_ib(struct dw_pcie *pci, u32 region, u32 reg)
> >  {
> > -	u32 offset = PCIE_GET_ATU_INB_UNR_REG_OFFSET(index);
> > -
> > -	dw_pcie_writel_atu(pci, offset + reg, val);
> > +	return dw_pcie_readl_atu(pci, PCIE_ATU_REGION_DIR_IB, region, reg);
> >  }
> >  
> > -static int dw_pcie_prog_inbound_atu_unroll(struct dw_pcie *pci, u8 func_no,
> > -					   int index, int type,
> > -					   u64 cpu_addr, u8 bar)
> > +static inline void dw_pcie_writel_atu_ib(struct dw_pcie *pci, u32 region, u32 reg,
> > +					 u32 val)
> >  {
> > -	u32 retries, val;
> > -
> > -	dw_pcie_writel_ib_unroll(pci, index, PCIE_ATU_UNR_LOWER_TARGET,
> > -				 lower_32_bits(cpu_addr));
> > -	dw_pcie_writel_ib_unroll(pci, index, PCIE_ATU_UNR_UPPER_TARGET,
> > -				 upper_32_bits(cpu_addr));
> > -
> > -	dw_pcie_writel_ib_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1, type |
> > -				 PCIE_ATU_FUNC_NUM(func_no));
> > -	dw_pcie_writel_ib_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL2,
> > -				 PCIE_ATU_FUNC_NUM_MATCH_EN |
> > -				 PCIE_ATU_ENABLE |
> > -				 PCIE_ATU_BAR_MODE_ENABLE | (bar << 8));
> > -
> > -	/*
> > -	 * Make sure ATU enable takes effect before any subsequent config
> > -	 * and I/O accesses.
> > -	 */
> > -	for (retries = 0; retries < LINK_WAIT_MAX_IATU_RETRIES; retries++) {
> > -		val = dw_pcie_readl_ib_unroll(pci, index,
> > -					      PCIE_ATU_UNR_REGION_CTRL2);
> > -		if (val & PCIE_ATU_ENABLE)
> > -			return 0;
> > -
> > -		mdelay(LINK_WAIT_IATU);
> > -	}
> > -	dev_err(pci->dev, "Inbound iATU is not being enabled\n");
> > -
> > -	return -EBUSY;
> > +	dw_pcie_writel_atu(pci, PCIE_ATU_REGION_DIR_IB, region, reg, val);
> >  }
> >  
> >  int dw_pcie_prog_inbound_atu(struct dw_pcie *pci, u8 func_no, int index,
> > @@ -460,65 +393,51 @@ int dw_pcie_prog_inbound_atu(struct dw_pcie *pci, u8 func_no, int index,
> >  {
> >  	u32 retries, val;
> >  
> > -	if (pci->iatu_unroll_enabled)
> > -		return dw_pcie_prog_inbound_atu_unroll(pci, func_no, index, type,
> > -						       cpu_addr, bar);
> > -
> > -	dw_pcie_writel_dbi(pci, PCIE_ATU_VIEWPORT, PCIE_ATU_REGION_INBOUND |
> > -			   index);
> > -	dw_pcie_writel_dbi(pci, PCIE_ATU_LOWER_TARGET, lower_32_bits(cpu_addr));
> > -	dw_pcie_writel_dbi(pci, PCIE_ATU_UPPER_TARGET, upper_32_bits(cpu_addr));
> > +	dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_LOWER_TARGET,
> > +			      lower_32_bits(cpu_addr));
> > +	dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_UPPER_TARGET,
> > +			      upper_32_bits(cpu_addr));
> >  
> > -	dw_pcie_writel_dbi(pci, PCIE_ATU_CR1, type |
> > -			   PCIE_ATU_FUNC_NUM(func_no));
> > -	dw_pcie_writel_dbi(pci, PCIE_ATU_CR2, PCIE_ATU_ENABLE |
> > -			   PCIE_ATU_FUNC_NUM_MATCH_EN |
> > -			   PCIE_ATU_BAR_MODE_ENABLE | (bar << 8));
> > +	dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_REGION_CTRL1, type |
> > +			      PCIE_ATU_FUNC_NUM(func_no));
> > +	dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_REGION_CTRL2,
> > +			      PCIE_ATU_ENABLE | PCIE_ATU_FUNC_NUM_MATCH_EN |
> > +			      PCIE_ATU_BAR_MODE_ENABLE | (bar << 8));
> >  
> >  	/*
> >  	 * Make sure ATU enable takes effect before any subsequent config
> >  	 * and I/O accesses.
> >  	 */
> >  	for (retries = 0; retries < LINK_WAIT_MAX_IATU_RETRIES; retries++) {
> > -		val = dw_pcie_readl_dbi(pci, PCIE_ATU_CR2);
> > +		val = dw_pcie_readl_atu_ib(pci, index, PCIE_ATU_REGION_CTRL2);
> >  		if (val & PCIE_ATU_ENABLE)
> >  			return 0;
> >  
> >  		mdelay(LINK_WAIT_IATU);
> >  	}
> > +
> >  	dev_err(pci->dev, "Inbound iATU is not being enabled\n");
> >  
> > -	return -EBUSY;
> > +	return -ETIMEDOUT;
> >  }
> >  
> >  void dw_pcie_disable_atu(struct dw_pcie *pci, int index,
> >  			 enum dw_pcie_region_type type)
> >  {
> > -	int region;
> > +	u32 dir;
> >  
> >  	switch (type) {
> >  	case DW_PCIE_REGION_INBOUND:
> > -		region = PCIE_ATU_REGION_INBOUND;
> > +		dir = PCIE_ATU_REGION_DIR_IB;
> 

> Is this the same double definition with the enum?

Absolutely right. I'll drop it in the next patch of this series. I'll
also move that patch to being applied before this one so to prevent
this question from araising and to simplify this patch a bit.

> 
> >  		break;
> >  	case DW_PCIE_REGION_OUTBOUND:
> > -		region = PCIE_ATU_REGION_OUTBOUND;
> > +		dir = PCIE_ATU_REGION_DIR_OB;
> >  		break;
> >  	default:
> >  		return;
> >  	}
> >  
> > -	if (pci->iatu_unroll_enabled) {
> > -		if (region == PCIE_ATU_REGION_INBOUND) {
> > -			dw_pcie_writel_ib_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL2,
> > -						 ~(u32)PCIE_ATU_ENABLE);
> > -		} else {
> > -			dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL2,
> > -						 ~(u32)PCIE_ATU_ENABLE);
> > -		}
> > -	} else {
> > -		dw_pcie_writel_dbi(pci, PCIE_ATU_VIEWPORT, region | index);
> > -		dw_pcie_writel_dbi(pci, PCIE_ATU_CR2, ~(u32)PCIE_ATU_ENABLE);
> > -	}
> > +	dw_pcie_writel_atu(pci, dir, index, PCIE_ATU_REGION_CTRL2, 0);
> >  }
> >  
> >  int dw_pcie_wait_for_link(struct dw_pcie *pci)
> > @@ -622,63 +541,29 @@ static bool dw_pcie_iatu_unroll_enabled(struct dw_pcie *pci)
> >  	return false;
> >  }
> >  
> > -static void dw_pcie_iatu_detect_regions_unroll(struct dw_pcie *pci)
> > -{
> > -	int max_region, i, ob = 0, ib = 0;
> > -	u32 val;
> > -
> > -	max_region = min((int)pci->atu_size / 512, 256);
> > -
> > -	for (i = 0; i < max_region; i++) {
> > -		dw_pcie_writel_ob_unroll(pci, i, PCIE_ATU_UNR_LOWER_TARGET,
> > -					0x11110000);
> > -
> > -		val = dw_pcie_readl_ob_unroll(pci, i, PCIE_ATU_UNR_LOWER_TARGET);
> > -		if (val == 0x11110000)
> > -			ob++;
> > -		else
> > -			break;
> > -	}
> > -
> > -	for (i = 0; i < max_region; i++) {
> > -		dw_pcie_writel_ib_unroll(pci, i, PCIE_ATU_UNR_LOWER_TARGET,
> > -					0x11110000);
> > -
> > -		val = dw_pcie_readl_ib_unroll(pci, i, PCIE_ATU_UNR_LOWER_TARGET);
> > -		if (val == 0x11110000)
> > -			ib++;
> > -		else
> > -			break;
> > -	}
> > -	pci->num_ib_windows = ib;
> > -	pci->num_ob_windows = ob;
> > -}
> > -
> >  static void dw_pcie_iatu_detect_regions(struct dw_pcie *pci)
> >  {
> > -	int max_region, i, ob = 0, ib = 0;
> > +	int max_region, ob, ib;
> >  	u32 val;
> >  
> > -	dw_pcie_writel_dbi(pci, PCIE_ATU_VIEWPORT, 0xFF);
> > -	max_region = dw_pcie_readl_dbi(pci, PCIE_ATU_VIEWPORT) + 1;
> > +	if (pci->iatu_unroll_enabled) {
> > +		max_region = min((int)pci->atu_size / 512, 256);
> > +	} else {
> > +		dw_pcie_writel_dbi(pci, PCIE_ATU_VIEWPORT, 0xFF);
> > +		max_region = dw_pcie_readl_dbi(pci, PCIE_ATU_VIEWPORT) + 1;
> > +	}
> >  
> > -	for (i = 0; i < max_region; i++) {
> > -		dw_pcie_writel_dbi(pci, PCIE_ATU_VIEWPORT, PCIE_ATU_REGION_OUTBOUND | i);
> > -		dw_pcie_writel_dbi(pci, PCIE_ATU_LOWER_TARGET, 0x11110000);
> > -		val = dw_pcie_readl_dbi(pci, PCIE_ATU_LOWER_TARGET);
> > -		if (val == 0x11110000)
> > -			ob++;
> > -		else
> > +	for (ob = 0; ob < max_region; ob++) {
> > +		dw_pcie_writel_atu_ob(pci, ob, PCIE_ATU_LOWER_TARGET, 0x11110000);
> > +		val = dw_pcie_readl_atu_ob(pci, ob, PCIE_ATU_LOWER_TARGET);
> > +		if (val != 0x11110000)
> >  			break;
> >  	}
> >  
> > -	for (i = 0; i < max_region; i++) {
> > -		dw_pcie_writel_dbi(pci, PCIE_ATU_VIEWPORT, PCIE_ATU_REGION_INBOUND | i);
> > -		dw_pcie_writel_dbi(pci, PCIE_ATU_LOWER_TARGET, 0x11110000);
> > -		val = dw_pcie_readl_dbi(pci, PCIE_ATU_LOWER_TARGET);
> > -		if (val == 0x11110000)
> > -			ib++;
> > -		else
> > +	for (ib = 0; ib < max_region; ib++) {
> > +		dw_pcie_writel_atu_ib(pci, ib, PCIE_ATU_LOWER_TARGET, 0x11110000);
> > +		val = dw_pcie_readl_atu_ib(pci, ib, PCIE_ATU_LOWER_TARGET);
> > +		if (val != 0x11110000)
> >  			break;
> >  	}
> >  
> > @@ -707,12 +592,10 @@ void dw_pcie_iatu_detect(struct dw_pcie *pci)
> >  		if (!pci->atu_size)
> >  			/* Pick a minimal default, enough for 8 in and 8 out windows */
> >  			pci->atu_size = SZ_4K;
> > -
> > -		dw_pcie_iatu_detect_regions_unroll(pci);
> > -	} else {
> > -		dw_pcie_iatu_detect_regions(pci);
> >  	}
> >  
> > +	dw_pcie_iatu_detect_regions(pci);
> > +
> >  	dev_info(pci->dev, "iATU unroll: %s\n", pci->iatu_unroll_enabled ?
> >  		"enabled" : "disabled");
> >  
> > diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
> > index 449c5ad92edc..6adf0c957c3b 100644
> > --- a/drivers/pci/controller/dwc/pcie-designware.h
> > +++ b/drivers/pci/controller/dwc/pcie-designware.h
> > @@ -103,10 +103,20 @@
> >  #define PCIE_VERSION_NUMBER		0x8F8
> >  #define PCIE_VERSION_TYPE		0x8FC
> >  

> > +/*
> > + * iATU inbound and outbound windows CSRs. Before the IP-core v4.80a each
> > + * iATU region CSRs had been indirectly accessible by means of the dedicated
> > + * viewport selector. The iATU/eDMA CSRs space was re-designed in DWC PCIe
> > + * v4.80a in a way so the viewport was unrolled into the directly accessible
> > + * iATU/eDMA CSRs space.
> 
> IIRC, I think it is configurable in later versions. There was some 
> discussion when I did the detection.

There are two internal IP-core parameters which indicate whether the
unrolled eDMA/iATU CSRs mapping is enabled:
CC_UNROLL_EN = (CC_DMA_ENABLE || CX_INTERNAL_ATU_ENABLE) && !AHB_POPULATED
and
CC_UNROLL_ENABLE = ((CC_UNROLL_EN ==0) ? 0: 1)
Normally these parameters shouldn't be manually changed since they
aren't advertised in the list of the configurable IP-core parameters.
But there is a note in the databook (v4.90a, v5.20a, v5.40a) which
suggests to contact the Synopsys support if it's required to enable
the legacy mapping on the later IP-core versions. So basically you are
right. It is configurable, but not in the normal circumstances.
Practically I don't think there is any modern DW PCIe controller
implemented with the legacy eDMA/iATU CSRs mapping since the modern
CPUs/SoC-Interconnects mainly have enough unused IO space for
the unrolled access.

-Sergey

> 
> > + */
> >  #define PCIE_ATU_VIEWPORT		0x900
> > -#define PCIE_ATU_REGION_INBOUND		BIT(31)
> > -#define PCIE_ATU_REGION_OUTBOUND	0
> > -#define PCIE_ATU_CR1			0x904
> > +#define PCIE_ATU_REGION_DIR_IB		BIT(31)
> > +#define PCIE_ATU_REGION_DIR_OB		0
> > +#define PCIE_ATU_VIEWPORT_BASE		0x904
> > +#define PCIE_ATU_UNROLL_BASE(dir, region) \
> > +	(((region) << 9) | ((dir == PCIE_ATU_REGION_DIR_IB) ? BIT(8) : 0))
> > +#define PCIE_ATU_REGION_CTRL1		0x000
> >  #define PCIE_ATU_INCREASE_REGION_SIZE	BIT(13)
> >  #define PCIE_ATU_TYPE_MEM		0x0
> >  #define PCIE_ATU_TYPE_IO		0x2
> > @@ -114,19 +124,19 @@
> >  #define PCIE_ATU_TYPE_CFG1		0x5
> >  #define PCIE_ATU_TD			BIT(8)
> >  #define PCIE_ATU_FUNC_NUM(pf)           ((pf) << 20)
> > -#define PCIE_ATU_CR2			0x908
> > +#define PCIE_ATU_REGION_CTRL2		0x004
> >  #define PCIE_ATU_ENABLE			BIT(31)
> >  #define PCIE_ATU_BAR_MODE_ENABLE	BIT(30)
> >  #define PCIE_ATU_FUNC_NUM_MATCH_EN      BIT(19)
> > -#define PCIE_ATU_LOWER_BASE		0x90C
> > -#define PCIE_ATU_UPPER_BASE		0x910
> > -#define PCIE_ATU_LIMIT			0x914
> > -#define PCIE_ATU_LOWER_TARGET		0x918
> > +#define PCIE_ATU_LOWER_BASE		0x008
> > +#define PCIE_ATU_UPPER_BASE		0x00C
> > +#define PCIE_ATU_LIMIT			0x010
> > +#define PCIE_ATU_LOWER_TARGET		0x014
> >  #define PCIE_ATU_BUS(x)			FIELD_PREP(GENMASK(31, 24), x)
> >  #define PCIE_ATU_DEV(x)			FIELD_PREP(GENMASK(23, 19), x)
> >  #define PCIE_ATU_FUNC(x)		FIELD_PREP(GENMASK(18, 16), x)
> > -#define PCIE_ATU_UPPER_TARGET		0x91C
> > -#define PCIE_ATU_UPPER_LIMIT		0x924
> > +#define PCIE_ATU_UPPER_TARGET		0x018
> > +#define PCIE_ATU_UPPER_LIMIT		0x020
> >  
> >  #define PCIE_MISC_CONTROL_1_OFF		0x8BC
> >  #define PCIE_DBI_RO_WR_EN		BIT(0)
> > @@ -143,19 +153,6 @@
> >  
> >  #define PCIE_PL_CHK_REG_ERR_ADDR			0xB28
> >  
> > -/*
> > - * iATU Unroll-specific register definitions
> > - * From 4.80 core version the address translation will be made by unroll
> > - */
> > -#define PCIE_ATU_UNR_REGION_CTRL1	0x00
> > -#define PCIE_ATU_UNR_REGION_CTRL2	0x04
> > -#define PCIE_ATU_UNR_LOWER_BASE		0x08
> > -#define PCIE_ATU_UNR_UPPER_BASE		0x0C
> > -#define PCIE_ATU_UNR_LOWER_LIMIT	0x10
> > -#define PCIE_ATU_UNR_LOWER_TARGET	0x14
> > -#define PCIE_ATU_UNR_UPPER_TARGET	0x18
> > -#define PCIE_ATU_UNR_UPPER_LIMIT	0x20
> > -
> >  /*
> >   * The default address offset between dbi_base and atu_base. Root controller
> >   * drivers are not required to initialize atu_base if the offset matches this
> > @@ -164,13 +161,6 @@
> >   */
> >  #define DEFAULT_DBI_ATU_OFFSET (0x3 << 20)
> >  
> > -/* Register address builder */
> > -#define PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(region) \
> > -		((region) << 9)
> > -
> > -#define PCIE_GET_ATU_INB_UNR_REG_OFFSET(region) \
> > -		(((region) << 9) | BIT(8))
> > -
> >  #define MAX_MSI_IRQS			256
> >  #define MAX_MSI_IRQS_PER_CTRL		32
> >  #define MAX_MSI_CTRLS			(MAX_MSI_IRQS / MAX_MSI_IRQS_PER_CTRL)
> > -- 
> > 2.35.1
> > 

^ permalink raw reply	[flat|nested] 40+ messages in thread

end of thread, other threads:[~2022-04-17 20:08 UTC | newest]

Thread overview: 40+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-03-24  1:37 [PATCH 00/16] PCI: dwc: Add dma-ranges/YAML-schema/Baikal-T1 support Serge Semin
2022-03-24  1:37 ` [PATCH 01/16] dt-bindings: PCI: dwc: Define generic and native DT bindings Serge Semin
2022-03-24  1:37   ` Serge Semin
2022-03-24  1:37   ` Serge Semin
2022-03-28 20:46   ` Rob Herring
2022-03-28 20:46     ` Rob Herring
2022-03-28 20:46     ` Rob Herring
2022-04-15 16:14     ` Serge Semin
2022-04-15 16:14       ` Serge Semin
2022-04-15 16:14       ` Serge Semin
2022-03-24  1:37 ` [PATCH 02/16] dt-bindings: PCI: dwc: Add Baikal-T1 PCIe Root Port bindings Serge Semin
2022-03-28 23:20   ` Rob Herring
2022-04-15 20:22     ` Serge Semin
2022-03-24  1:37 ` [PATCH 03/16] PCI: dwc: Add more verbose link-up message Serge Semin
2022-03-28 23:31   ` Joe Perches
2022-04-16  8:01     ` Serge Semin
2022-03-29 14:47   ` Rob Herring
2022-04-17 10:10     ` Serge Semin
2022-03-24  1:37 ` [PATCH 04/16] PCI: dwc: Convert to using native IP-core versions representation Serge Semin
2022-03-29 15:00   ` Rob Herring
2022-04-17 14:42     ` Serge Semin
2022-03-24  1:37 ` [PATCH 05/16] PCI: dwc: Add IP-core version detection procedure Serge Semin
2022-03-29 15:08   ` Rob Herring
2022-04-17 15:13     ` Serge Semin
2022-03-24  1:37 ` [PATCH 06/16] PCI: dwc: Introduce Synopsys IP-core versions/types interface Serge Semin
2022-03-24  1:37 ` [PATCH 07/16] PCI: dwc: Add host de-initialization callback Serge Semin
2022-03-24  1:37 ` [PATCH 08/16] PCI: dwc: Drop inbound iATU types enumeration - dw_pcie_as_type Serge Semin
2022-03-29 15:16   ` Rob Herring
2022-03-24  1:37 ` [PATCH 09/16] PCI: dwc: Simplify in/outbound iATU setup methods Serge Semin
2022-03-29 15:28   ` Rob Herring
2022-04-17 20:08     ` Serge Semin
2022-03-24  1:37 ` [PATCH 10/16] PCI: dwc: Drop iATU regions enumeration - dw_pcie_region_type Serge Semin
2022-03-29 15:31   ` Rob Herring
2022-04-17 17:52     ` Serge Semin
2022-03-24  1:37 ` [PATCH 11/16] PCI: dwc: Add iATU regions size detection procedure Serge Semin
2022-03-24  1:37 ` [PATCH 12/16] PCI: dwc: Verify in/out regions against iATU constraints Serge Semin
2022-03-24  1:37 ` [PATCH 13/16] PCI: dwc: Check iATU in/outbound ranges setup methods status Serge Semin
2022-03-24  1:37 ` [PATCH 14/16] PCI: dwc: Introduce dma-ranges property support for RC-host Serge Semin
2022-03-24  1:37 ` [PATCH 15/16] PCI: dwc: Introduce generic platform clocks and resets sets Serge Semin
2022-03-24  1:37 ` [PATCH 16/16] PCI: dwc: Add Baikal-T1 PCIe controller support Serge Semin

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.