提交 489e9fea 编写于 作者: L Linus Torvalds

Merge tag 'pci-v5.11-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci

Pull PCI updates from Bjorn Helgaas:
 "Enumeration:
   - Decode PCIe 64 GT/s link speed (Gustavo Pimentel)
   - Remove unused HAVE_PCI_SET_MWI (Heiner Kallweit)
   - Reduce pci_set_cacheline_size() message to debug level (Heiner
     Kallweit)
   - Fix pci_slot_release() NULL pointer dereference (Jubin Zhong)
   - Unify ECAM constants in native PCI Express drivers (Krzysztof
     Wilczyński)
   - Return u8 from pci_find_capability() and similar (Puranjay Mohan)
   - Return u16 from pci_find_ext_capability() and similar (Bjorn
     Helgaas)
   - Fix ACPI companion lookup for device 0 on the root bus (Rafael J.
     Wysocki)

  Resource management:
   - Keep both device and resource name for config space remaps
     (Alexander Lobakin)
   - Bounds-check command-line resource alignment requests (Bjorn
     Helgaas)
   - Fix overflow in command-line resource alignment requests (Colin Ian
     King)

  Driver binding:
   - Avoid duplicate IDs in driver dynamic IDs list (Zhenzhong Duan)

  Power management:
   - Save/restore Precision Time Measurement Capability for
     suspend/resume (David E. Box)
   - Disable PTM during suspend to save power (David E. Box)
   - Add sysfs attribute for device power state (Maximilian Luz)
   - Rename pci_wakeup_bus() to pci_resume_bus() (Mika Westerberg)
   - Do not generate wakeup event when runtime resuming device (Mika
     Westerberg)
   - Save/restore ASPM L1SS Capability for suspend/resume (Vidya Sagar)

  Virtualization:
   - Mark AMD Raven iGPU ATS as broken in some platforms (Alex Deucher)
   - Add function 1 DMA alias quirk for Marvell 9215 SATA controller
     (Bjorn Helgaas)

  MSI:
   - Disable MSI for Pericom PCIe-USB adapter (Andy Shevchenko)
   - Improve warnings for 32-bit-limited MSI support (Vidya Sagar)

  Error handling:
   - Cache RCEC EA Capability offset in pci_init_capabilities() (Sean V
     Kelley)
   - Rename reset_link() to reset_subordinates() (Sean V Kelley)
   - Write AER Capability only when we control it (Sean V Kelley)
   - Clear AER status only when we control AER (Sean V Kelley)
   - Bind RCEC devices to the Root Port driver (Qiuxu Zhuo)
   - Recover from RCiEP AER errors (Qiuxu Zhuo)
   - Recover from RCEC AER errors (Sean V Kelley)
   - Add pcie_link_rcec() to associate RCiEPs (Sean V Kelley)
   - Add pcie_walk_rcec() to RCEC AER handling (Sean V Kelley)
   - Add pcie_walk_rcec() to RCEC PME handling (Sean V Kelley)
   - Add RCEC AER error injection support (Qiuxu Zhuo)

  Broadcom iProc PCIe controller driver:
   - Fix out-of-bound array accesses (Bharat Gooty)
   - Invalidate correct PAXB inbound windows (Roman Bacik)
   - Enhance PCIe Link information display (Srinath Mannam)

  Cadence PCIe controller driver:
   - Make "cdns,max-outbound-regions" property optional (Kishon Vijay
     Abraham I)

  Intel VMD host bridge driver:
   - Offset client MSI-X vectors (Jon Derrick)
   - Update type of __iomem pointers (Krzysztof Wilczyński)

  NVIDIA Tegra PCIe controller driver:
   - Move "dbi" accesses to post common DWC initialization (Vidya Sagar)
   - Read "dbi" base address to program in application logic (Vidya
     Sagar)
   - Fix ASPM-L1SS advertisement disable code (Vidya Sagar)
   - Set DesignWare IP version (Vidya Sagar)
   - Continue unconfig sequence even if parts fail (Vidya Sagar)
   - Check return value of tegra_pcie_init_controller() (Vidya Sagar)
   - Disable LTSSM during L2 entry (Vidya Sagar)

  Qualcomm PCIe controller driver:
   - Document PCIe bindings for SM8250 SoC (Manivannan Sadhasivam)
   - Add SM8250 SoC support (Manivannan Sadhasivam)
   - Add support for configuring BDF to SID mapping for SM8250
     (Manivannan Sadhasivam)

  Renesas R-Car PCIe controller driver:
   - rcar: Drop unused members from struct rcar_pcie_host (Lad
     Prabhakar)
   - PCI: rcar-pci-host: Document r8a774e1 bindings (Lad Prabhakar)
   - PCI: rcar-pci-host: Convert bindings to json-schema (Yoshihiro
     Shimoda)
   - PCI: rcar-pci-host: Document r8a77965 bindings (Yoshihiro Shimoda)

  Samsung Exynos PCIe controller driver:
   - Rework driver to support Exynos5433 PCIe PHY (Jaehoon Chung)
   - Rework driver to support Exynos5433 variant (Jaehoon Chung)
   - Drop samsung,exynos5440-pcie binding (Marek Szyprowski)
   - Add the samsung,exynos-pcie binding (Marek Szyprowski)
   - Add the samsung,exynos-pcie-phy binding (Marek Szyprowski)

  Synopsys DesignWare PCIe controller driver:
   - Support multiple ATU memory regions (Rob Herring)
   - Move intel-gw ATU offset out of driver match data (Rob Herring)
   - Move "dbi", "dbi2", and "addr_space" resource setup into common
     code (Rob Herring)
   - Remove intel-gw unneeded function wrappers (Rob Herring)
   - Ensure all outbound ATU windows are reset (Rob Herring)
   - Use the common MSI irq_chip in dra7xx (Rob Herring)
   - Drop the .set_num_vectors() host op (Rob Herring)
   - Move MSI interrupt setup into DWC common code (Rob Herring)
   - Rework MSI initialization (Rob Herring)
   - Move link handling into common code (Rob Herring)
   - Move dw_pcie_msi_init() into core (Rob Herring)
   - Move dw_pcie_setup_rc() to DWC common code (Rob Herring)
   - Remove unnecessary wrappers around dw_pcie_host_init() (Rob
     Herring)
   - Drop keystone duplicated 'num-viewport'" (Rob Herring)
   - Move inbound and outbound windows to common struct (Rob Herring)
   - Detect number of iATU windows (Rob Herring)
   - Warn if non-prefetchable memory aperture size is > 32-bit (Vidya
     Sagar)
   - Add support to program ATU for >4GB memory (Vidya Sagar)
   - Set 32-bit DMA mask for MSI target address allocation (Vidya Sagar)

  TI J721E PCIe driver:
   - Fix "ti,syscon-pcie-ctrl" to take argument (Kishon Vijay Abraham I)
   - Add host mode dt-bindings for TI's J7200 SoC (Kishon Vijay Abraham
     I)
   - Add EP mode dt-bindings for TI's J7200 SoC (Kishon Vijay Abraham I)
   - Get offset within "syscon" from "ti,syscon-pcie-ctrl" phandle arg
     (Kishon Vijay Abraham I)

  TI Keystone PCIe controller driver:
   - Enable compile-testing on !ARM (Alex Dewar)"

* tag 'pci-v5.11-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci: (100 commits)
  PCI: Add function 1 DMA alias quirk for Marvell 9215 SATA controller
  PCI/ACPI: Fix companion lookup for device 0 on the root bus
  PCI: Keep both device and resource name for config space remaps
  PCI: xgene: Removed unused ".bus_shift" initialisers from pci-xgene.c
  PCI: vmd: Update type of the __iomem pointers
  PCI: iproc: Convert to use the new ECAM constants
  PCI: thunder-pem: Add constant for custom ".bus_shift" initialiser
  PCI: Unify ECAM constants in native PCI Express drivers
  PCI: Disable PTM during suspend to save power
  PCI/PTM: Save/restore Precision Time Measurement Capability for suspend/resume
  PCI: Mark AMD Raven iGPU ATS as broken in some platforms
  PCI: j721e: Get offset within "syscon" from "ti,syscon-pcie-ctrl" phandle arg
  dt-bindings: PCI: Add EP mode dt-bindings for TI's J7200 SoC
  dt-bindings: PCI: Add host mode dt-bindings for TI's J7200 SoC
  dt-bindings: pci: ti,j721e: Fix "ti,syscon-pcie-ctrl" to take argument
  PCI: dwc: Set 32-bit DMA mask for MSI target address allocation
  PCI: qcom: Add support for configuring BDF to SID mapping for SM8250
  PCI: Reduce pci_set_cacheline_size() message to debug level
  PCI: Remove unused HAVE_PCI_SET_MWI
  PCI: qcom: Add SM8250 SoC support
  ...
...@@ -366,3 +366,12 @@ Contact: Heiner Kallweit <hkallweit1@gmail.com> ...@@ -366,3 +366,12 @@ Contact: Heiner Kallweit <hkallweit1@gmail.com>
Description: If ASPM is supported for an endpoint, these files can be Description: If ASPM is supported for an endpoint, these files can be
used to disable or enable the individual power management used to disable or enable the individual power management
states. Write y/1/on to enable, n/0/off to disable. states. Write y/1/on to enable, n/0/off to disable.
What: /sys/bus/pci/devices/.../power_state
Date: November 2020
Contact: Linux PCI developers <linux-pci@vger.kernel.org>
Description:
This file contains the current PCI power state of the device.
The value comes from the PCI kernel device state and can be one
of: "unknown", "error", "D0", D1", "D2", "D3hot", "D3cold".
The file is read only.
...@@ -20,7 +20,4 @@ properties: ...@@ -20,7 +20,4 @@ properties:
maximum: 32 maximum: 32
default: 32 default: 32
required:
- cdns,max-outbound-regions
additionalProperties: true additionalProperties: true
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
- "qcom,pcie-ipq8074" for ipq8074 - "qcom,pcie-ipq8074" for ipq8074
- "qcom,pcie-qcs404" for qcs404 - "qcom,pcie-qcs404" for qcs404
- "qcom,pcie-sdm845" for sdm845 - "qcom,pcie-sdm845" for sdm845
- "qcom,pcie-sm8250" for sm8250
- reg: - reg:
Usage: required Usage: required
...@@ -27,6 +28,7 @@ ...@@ -27,6 +28,7 @@
- "dbi" DesignWare PCIe registers - "dbi" DesignWare PCIe registers
- "elbi" External local bus interface registers - "elbi" External local bus interface registers
- "config" PCIe configuration space - "config" PCIe configuration space
- "atu" ATU address space (optional)
- device_type: - device_type:
Usage: required Usage: required
...@@ -131,7 +133,7 @@ ...@@ -131,7 +133,7 @@
- "slave_bus" AXI Slave clock - "slave_bus" AXI Slave clock
-clock-names: -clock-names:
Usage: required for sdm845 Usage: required for sdm845 and sm8250
Value type: <stringlist> Value type: <stringlist>
Definition: Should contain the following entries Definition: Should contain the following entries
- "aux" Auxiliary clock - "aux" Auxiliary clock
...@@ -206,7 +208,7 @@ ...@@ -206,7 +208,7 @@
- "ahb" AHB reset - "ahb" AHB reset
- reset-names: - reset-names:
Usage: required for sdm845 Usage: required for sdm845 and sm8250
Value type: <stringlist> Value type: <stringlist>
Definition: Should contain the following entries Definition: Should contain the following entries
- "pci" PCIe core reset - "pci" PCIe core reset
......
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
# Copyright (C) 2020 Renesas Electronics Corp.
%YAML 1.2
---
$id: http://devicetree.org/schemas/pci/rcar-pci-host.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Renesas R-Car PCIe Host
maintainers:
- Marek Vasut <marek.vasut+renesas@gmail.com>
- Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
allOf:
- $ref: pci-bus.yaml#
properties:
compatible:
oneOf:
- items:
- enum:
- renesas,pcie-r8a7742 # RZ/G1H
- renesas,pcie-r8a7743 # RZ/G1M
- renesas,pcie-r8a7744 # RZ/G1N
- renesas,pcie-r8a7790 # R-Car H2
- renesas,pcie-r8a7791 # R-Car M2-W
- renesas,pcie-r8a7793 # R-Car M2-N
- const: renesas,pcie-rcar-gen2 # R-Car Gen2 and RZ/G1
- items:
- enum:
- renesas,pcie-r8a774a1 # RZ/G2M
- renesas,pcie-r8a774b1 # RZ/G2N
- renesas,pcie-r8a774c0 # RZ/G2E
- renesas,pcie-r8a774e1 # RZ/G2H
- renesas,pcie-r8a7795 # R-Car H3
- renesas,pcie-r8a7796 # R-Car M3-W
- renesas,pcie-r8a77961 # R-Car M3-W+
- renesas,pcie-r8a77965 # R-Car M3-N
- renesas,pcie-r8a77980 # R-Car V3H
- renesas,pcie-r8a77990 # R-Car E3
- const: renesas,pcie-rcar-gen3 # R-Car Gen3 and RZ/G2
reg:
maxItems: 1
interrupts:
minItems: 3
maxItems: 3
clocks:
maxItems: 2
clock-names:
items:
- const: pcie
- const: pcie_bus
power-domains:
maxItems: 1
resets:
maxItems: 1
phys:
maxItems: 1
phy-names:
const: pcie
required:
- compatible
- reg
- interrupts
- clocks
- clock-names
- power-domains
- resets
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/clock/r8a7791-cpg-mssr.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/power/r8a7791-sysc.h>
soc {
#address-cells = <2>;
#size-cells = <2>;
pcie: pcie@fe000000 {
compatible = "renesas,pcie-r8a7791", "renesas,pcie-rcar-gen2";
reg = <0 0xfe000000 0 0x80000>;
#address-cells = <3>;
#size-cells = <2>;
bus-range = <0x00 0xff>;
device_type = "pci";
ranges = <0x01000000 0 0x00000000 0 0xfe100000 0 0x00100000>,
<0x02000000 0 0xfe200000 0 0xfe200000 0 0x00200000>,
<0x02000000 0 0x30000000 0 0x30000000 0 0x08000000>,
<0x42000000 0 0x38000000 0 0x38000000 0 0x08000000>;
dma-ranges = <0x42000000 0 0x40000000 0 0x40000000 0 0x40000000>,
<0x42000000 2 0x00000000 2 0x00000000 0 0x40000000>;
interrupts = <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
#interrupt-cells = <1>;
interrupt-map-mask = <0 0 0 0>;
interrupt-map = <0 0 0 0 &gic GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cpg CPG_MOD 319>, <&pcie_bus_clk>;
clock-names = "pcie", "pcie_bus";
power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
resets = <&cpg 319>;
};
};
* Renesas R-Car PCIe interface
Required properties:
compatible: "renesas,pcie-r8a7742" for the R8A7742 SoC;
"renesas,pcie-r8a7743" for the R8A7743 SoC;
"renesas,pcie-r8a7744" for the R8A7744 SoC;
"renesas,pcie-r8a774a1" for the R8A774A1 SoC;
"renesas,pcie-r8a774b1" for the R8A774B1 SoC;
"renesas,pcie-r8a774c0" for the R8A774C0 SoC;
"renesas,pcie-r8a7779" for the R8A7779 SoC;
"renesas,pcie-r8a7790" for the R8A7790 SoC;
"renesas,pcie-r8a7791" for the R8A7791 SoC;
"renesas,pcie-r8a7793" for the R8A7793 SoC;
"renesas,pcie-r8a7795" for the R8A7795 SoC;
"renesas,pcie-r8a7796" for the R8A77960 SoC;
"renesas,pcie-r8a77961" for the R8A77961 SoC;
"renesas,pcie-r8a77980" for the R8A77980 SoC;
"renesas,pcie-r8a77990" for the R8A77990 SoC;
"renesas,pcie-rcar-gen2" for a generic R-Car Gen2 or
RZ/G1 compatible device.
"renesas,pcie-rcar-gen3" for a generic R-Car Gen3 or
RZ/G2 compatible device.
When compatible with the generic version, nodes must list the
SoC-specific version corresponding to the platform first
followed by the generic version.
- reg: base address and length of the PCIe controller registers.
- #address-cells: set to <3>
- #size-cells: set to <2>
- bus-range: PCI bus numbers covered
- device_type: set to "pci"
- ranges: ranges for the PCI memory and I/O regions.
- dma-ranges: ranges for the inbound memory regions.
- interrupts: two interrupt sources for MSI interrupts, followed by interrupt
source for hardware related interrupts (e.g. link speed change).
- #interrupt-cells: set to <1>
- interrupt-map-mask and interrupt-map: standard PCI properties
to define the mapping of the PCIe interface to interrupt numbers.
- clocks: from common clock binding: clock specifiers for the PCIe controller
and PCIe bus clocks.
- clock-names: from common clock binding: should be "pcie" and "pcie_bus".
Optional properties:
- phys: from common PHY binding: PHY phandle and specifier (only make sense
for R-Car gen3 SoCs where the PCIe PHYs have their own register blocks).
- phy-names: from common PHY binding: should be "pcie".
Example:
SoC-specific DT Entry:
pcie: pcie@fe000000 {
compatible = "renesas,pcie-r8a7791", "renesas,pcie-rcar-gen2";
reg = <0 0xfe000000 0 0x80000>;
#address-cells = <3>;
#size-cells = <2>;
bus-range = <0x00 0xff>;
device_type = "pci";
ranges = <0x01000000 0 0x00000000 0 0xfe100000 0 0x00100000
0x02000000 0 0xfe200000 0 0xfe200000 0 0x00200000
0x02000000 0 0x30000000 0 0x30000000 0 0x08000000
0x42000000 0 0x38000000 0 0x38000000 0 0x08000000>;
dma-ranges = <0x42000000 0 0x40000000 0 0x40000000 0 0x40000000
0x42000000 2 0x00000000 2 0x00000000 0 0x40000000>;
interrupts = <0 116 4>, <0 117 4>, <0 118 4>;
#interrupt-cells = <1>;
interrupt-map-mask = <0 0 0 0>;
interrupt-map = <0 0 0 0 &gic 0 116 4>;
clocks = <&mstp3_clks R8A7791_CLK_PCIE>, <&pcie_bus_clk>;
clock-names = "pcie", "pcie_bus";
};
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/pci/samsung,exynos-pcie.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Samsung SoC series PCIe Host Controller Device Tree Bindings
maintainers:
- Marek Szyprowski <m.szyprowski@samsung.com>
- Jaehoon Chung <jh80.chung@samsung.com>
description: |+
Exynos5433 SoC PCIe host controller is based on the Synopsys DesignWare
PCIe IP and thus inherits all the common properties defined in
designware-pcie.txt.
allOf:
- $ref: /schemas/pci/pci-bus.yaml#
properties:
compatible:
const: samsung,exynos5433-pcie
reg:
items:
- description: Data Bus Interface (DBI) registers.
- description: External Local Bus interface (ELBI) registers.
- description: PCIe configuration space region.
reg-names:
items:
- const: dbi
- const: elbi
- const: config
interrupts:
maxItems: 1
clocks:
items:
- description: PCIe bridge clock
- description: PCIe bus clock
clock-names:
items:
- const: pcie
- const: pcie_bus
phys:
maxItems: 1
vdd10-supply:
description:
Phandle to a regulator that provides 1.0V power to the PCIe block.
vdd18-supply:
description:
Phandle to a regulator that provides 1.8V power to the PCIe block.
num-lanes:
const: 1
num-viewport:
const: 3
required:
- reg
- reg-names
- interrupts
- "#address-cells"
- "#size-cells"
- "#interrupt-cells"
- interrupt-map
- interrupt-map-mask
- ranges
- bus-range
- device_type
- num-lanes
- num-viewport
- clocks
- clock-names
- phys
- vdd10-supply
- vdd18-supply
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/clock/exynos5433.h>
pcie: pcie@15700000 {
compatible = "samsung,exynos5433-pcie";
reg = <0x15700000 0x1000>, <0x156b0000 0x1000>, <0x0c000000 0x1000>;
reg-names = "dbi", "elbi", "config";
#address-cells = <3>;
#size-cells = <2>;
#interrupt-cells = <1>;
device_type = "pci";
interrupts = <GIC_SPI 245 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cmu_fsys CLK_PCIE>, <&cmu_fsys CLK_PCLK_PCIE_PHY>;
clock-names = "pcie", "pcie_bus";
phys = <&pcie_phy>;
pinctrl-0 = <&pcie_bus &pcie_wlanen>;
pinctrl-names = "default";
num-lanes = <1>;
num-viewport = <3>;
bus-range = <0x00 0xff>;
ranges = <0x81000000 0 0 0x0c001000 0 0x00010000>,
<0x82000000 0 0x0c011000 0x0c011000 0 0x03feefff>;
vdd10-supply = <&ldo6_reg>;
vdd18-supply = <&ldo7_reg>;
interrupt-map-mask = <0 0 0 0>;
interrupt-map = <0 0 0 0 &gic GIC_SPI 245 IRQ_TYPE_LEVEL_HIGH>;
};
...
* Samsung Exynos 5440 PCIe interface
This PCIe host controller is based on the Synopsys DesignWare PCIe IP
and thus inherits all the common properties defined in designware-pcie.txt.
Required properties:
- compatible: "samsung,exynos5440-pcie"
- reg: base addresses and lengths of the PCIe controller,
- reg-names : First name should be set to "elbi".
And use the "config" instead of getting the configuration address space
from "ranges".
NOTE: When using the "config" property, reg-names must be set.
- interrupts: A list of interrupt outputs for level interrupt,
pulse interrupt, special interrupt.
- phys: From PHY binding. Phandle for the generic PHY.
Refer to Documentation/devicetree/bindings/phy/samsung-phy.txt
For other common properties, refer to
Documentation/devicetree/bindings/pci/designware-pcie.txt
Example:
SoC-specific DT Entry (with using PHY framework):
pcie_phy0: pcie-phy@270000 {
...
reg = <0x270000 0x1000>, <0x271000 0x40>;
reg-names = "phy", "block";
...
};
pcie@290000 {
compatible = "samsung,exynos5440-pcie", "snps,dw-pcie";
reg = <0x290000 0x1000>, <0x40000000 0x1000>;
reg-names = "elbi", "config";
clocks = <&clock 28>, <&clock 27>;
clock-names = "pcie", "pcie_bus";
#address-cells = <3>;
#size-cells = <2>;
device_type = "pci";
phys = <&pcie_phy0>;
ranges = <0x81000000 0 0 0x60001000 0 0x00010000
0x82000000 0 0x60011000 0x60011000 0 0x1ffef000>;
#interrupt-cells = <1>;
interrupt-map-mask = <0 0 0 0>;
interrupt-map = <0 0 0 0 &gic GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>;
num-lanes = <4>;
};
Board-specific DT Entry:
pcie@290000 {
reset-gpio = <&pin_ctrl 5 0>;
};
pcie@2a0000 {
reset-gpio = <&pin_ctrl 22 0>;
};
...@@ -15,8 +15,14 @@ allOf: ...@@ -15,8 +15,14 @@ allOf:
properties: properties:
compatible: compatible:
enum: oneOf:
- ti,j721e-pcie-ep - description: PCIe EP controller in J7200
items:
- const: ti,j7200-pcie-ep
- const: ti,j721e-pcie-ep
- description: PCIe EP controller in J721E
items:
- const: ti,j721e-pcie-ep
reg: reg:
maxItems: 4 maxItems: 4
...@@ -29,9 +35,12 @@ properties: ...@@ -29,9 +35,12 @@ properties:
- const: mem - const: mem
ti,syscon-pcie-ctrl: ti,syscon-pcie-ctrl:
description: Phandle to the SYSCON entry required for configuring PCIe mode $ref: /schemas/types.yaml#/definitions/phandle-array
and link speed. items:
$ref: /schemas/types.yaml#/definitions/phandle - items:
- description: Phandle to the SYSCON entry
- description: pcie_ctrl register offset within SYSCON
description: Specifier for configuring PCIe mode and link speed.
power-domains: power-domains:
maxItems: 1 maxItems: 1
...@@ -57,7 +66,6 @@ required: ...@@ -57,7 +66,6 @@ required:
- power-domains - power-domains
- clocks - clocks
- clock-names - clock-names
- cdns,max-outbound-regions
- dma-coherent - dma-coherent
- max-functions - max-functions
- phys - phys
...@@ -80,13 +88,12 @@ examples: ...@@ -80,13 +88,12 @@ examples:
<0x00 0x0d000000 0x00 0x00800000>, <0x00 0x0d000000 0x00 0x00800000>,
<0x00 0x10000000 0x00 0x08000000>; <0x00 0x10000000 0x00 0x08000000>;
reg-names = "intd_cfg", "user_cfg", "reg", "mem"; reg-names = "intd_cfg", "user_cfg", "reg", "mem";
ti,syscon-pcie-ctrl = <&pcie0_ctrl>; ti,syscon-pcie-ctrl = <&pcie0_ctrl 0x4070>;
max-link-speed = <3>; max-link-speed = <3>;
num-lanes = <2>; num-lanes = <2>;
power-domains = <&k3_pds 239 TI_SCI_PD_EXCLUSIVE>; power-domains = <&k3_pds 239 TI_SCI_PD_EXCLUSIVE>;
clocks = <&k3_clks 239 1>; clocks = <&k3_clks 239 1>;
clock-names = "fck"; clock-names = "fck";
cdns,max-outbound-regions = <16>;
max-functions = /bits/ 8 <6>; max-functions = /bits/ 8 <6>;
dma-coherent; dma-coherent;
phys = <&serdes0_pcie_link>; phys = <&serdes0_pcie_link>;
......
...@@ -15,8 +15,14 @@ allOf: ...@@ -15,8 +15,14 @@ allOf:
properties: properties:
compatible: compatible:
enum: oneOf:
- ti,j721e-pcie-host - description: PCIe controller in J7200
items:
- const: ti,j7200-pcie-host
- const: ti,j721e-pcie-host
- description: PCIe controller in J721E
items:
- const: ti,j721e-pcie-host
reg: reg:
maxItems: 4 maxItems: 4
...@@ -29,9 +35,12 @@ properties: ...@@ -29,9 +35,12 @@ properties:
- const: cfg - const: cfg
ti,syscon-pcie-ctrl: ti,syscon-pcie-ctrl:
description: Phandle to the SYSCON entry required for configuring PCIe mode $ref: /schemas/types.yaml#/definitions/phandle-array
and link speed. items:
$ref: /schemas/types.yaml#/definitions/phandle - items:
- description: Phandle to the SYSCON entry
- description: pcie_ctrl register offset within SYSCON
description: Specifier for configuring PCIe mode and link speed.
power-domains: power-domains:
maxItems: 1 maxItems: 1
...@@ -48,7 +57,11 @@ properties: ...@@ -48,7 +57,11 @@ properties:
const: 0x104c const: 0x104c
device-id: device-id:
const: 0xb00d oneOf:
- items:
- const: 0xb00d
- items:
- const: 0xb00f
msi-map: true msi-map: true
...@@ -90,7 +103,7 @@ examples: ...@@ -90,7 +103,7 @@ examples:
<0x00 0x0d000000 0x00 0x00800000>, <0x00 0x0d000000 0x00 0x00800000>,
<0x00 0x10000000 0x00 0x00001000>; <0x00 0x10000000 0x00 0x00001000>;
reg-names = "intd_cfg", "user_cfg", "reg", "cfg"; reg-names = "intd_cfg", "user_cfg", "reg", "cfg";
ti,syscon-pcie-ctrl = <&pcie0_ctrl>; ti,syscon-pcie-ctrl = <&pcie0_ctrl 0x4070>;
max-link-speed = <3>; max-link-speed = <3>;
num-lanes = <2>; num-lanes = <2>;
power-domains = <&k3_pds 239 TI_SCI_PD_EXCLUSIVE>; power-domains = <&k3_pds 239 TI_SCI_PD_EXCLUSIVE>;
......
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/phy/samsung,exynos-pcie-phy.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Samsung SoC series PCIe PHY Device Tree Bindings
maintainers:
- Marek Szyprowski <m.szyprowski@samsung.com>
- Jaehoon Chung <jh80.chung@samsung.com>
properties:
"#phy-cells":
const: 0
compatible:
const: samsung,exynos5433-pcie-phy
reg:
maxItems: 1
samsung,pmu-syscon:
$ref: '/schemas/types.yaml#/definitions/phandle'
description: phandle for PMU system controller interface, used to
control PMU registers bits for PCIe PHY
samsung,fsys-sysreg:
$ref: '/schemas/types.yaml#/definitions/phandle'
description: phandle for FSYS sysreg interface, used to control
sysreg registers bits for PCIe PHY
required:
- "#phy-cells"
- compatible
- reg
- samsung,pmu-syscon
- samsung,fsys-sysreg
additionalProperties: false
examples:
- |
pcie_phy: pcie-phy@15680000 {
compatible = "samsung,exynos5433-pcie-phy";
reg = <0x15680000 0x1000>;
samsung,pmu-syscon = <&pmu_system_controller>;
samsung,fsys-sysreg = <&syscon_fsys>;
#phy-cells = <0>;
};
...
...@@ -13656,6 +13656,8 @@ M: Kishon Vijay Abraham I <kishon@ti.com> ...@@ -13656,6 +13656,8 @@ M: Kishon Vijay Abraham I <kishon@ti.com>
M: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> M: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
L: linux-pci@vger.kernel.org L: linux-pci@vger.kernel.org
S: Supported S: Supported
F: Documentation/PCI/endpoint/*
F: Documentation/misc-devices/pci-endpoint-test.rst
T: git git://git.kernel.org/pub/scm/linux/kernel/git/kishon/pci-endpoint.git T: git git://git.kernel.org/pub/scm/linux/kernel/git/kishon/pci-endpoint.git
F: drivers/misc/pci_endpoint_test.c F: drivers/misc/pci_endpoint_test.c
F: drivers/pci/endpoint/ F: drivers/pci/endpoint/
......
...@@ -1038,7 +1038,7 @@ static int vga_switcheroo_runtime_resume(struct device *dev) ...@@ -1038,7 +1038,7 @@ static int vga_switcheroo_runtime_resume(struct device *dev)
mutex_lock(&vgasr_mutex); mutex_lock(&vgasr_mutex);
vga_switcheroo_power_switch(pdev, VGA_SWITCHEROO_ON); vga_switcheroo_power_switch(pdev, VGA_SWITCHEROO_ON);
mutex_unlock(&vgasr_mutex); mutex_unlock(&vgasr_mutex);
pci_wakeup_bus(pdev->bus); pci_resume_bus(pdev->bus);
return dev->bus->pm->runtime_resume(dev); return dev->bus->pm->runtime_resume(dev);
} }
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
obj-$(CONFIG_PCI) += access.o bus.o probe.o host-bridge.o \ obj-$(CONFIG_PCI) += access.o bus.o probe.o host-bridge.o \
remove.o pci.o pci-driver.o search.o \ remove.o pci.o pci-driver.o search.o \
pci-sysfs.o rom.o setup-res.o irq.o vpd.o \ pci-sysfs.o rom.o setup-res.o irq.o vpd.o \
setup-bus.o vc.o mmap.o setup-irq.o setup-bus.o vc.o mmap.o setup-irq.o msi.o
obj-$(CONFIG_PCI) += pcie/ obj-$(CONFIG_PCI) += pcie/
...@@ -18,7 +18,6 @@ endif ...@@ -18,7 +18,6 @@ endif
obj-$(CONFIG_OF) += of.o obj-$(CONFIG_OF) += of.o
obj-$(CONFIG_PCI_QUIRKS) += quirks.o obj-$(CONFIG_PCI_QUIRKS) += quirks.o
obj-$(CONFIG_HOTPLUG_PCI) += hotplug/ obj-$(CONFIG_HOTPLUG_PCI) += hotplug/
obj-$(CONFIG_PCI_MSI) += msi.o
obj-$(CONFIG_PCI_ATS) += ats.o obj-$(CONFIG_PCI_ATS) += ats.o
obj-$(CONFIG_PCI_IOV) += iov.o obj-$(CONFIG_PCI_IOV) += iov.o
obj-$(CONFIG_PCI_BRIDGE_EMUL) += pci-bridge-emul.o obj-$(CONFIG_PCI_BRIDGE_EMUL) += pci-bridge-emul.o
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include <linux/irqchip/chained_irq.h> #include <linux/irqchip/chained_irq.h>
#include <linux/irqdomain.h> #include <linux/irqdomain.h>
#include <linux/mfd/syscon.h> #include <linux/mfd/syscon.h>
#include <linux/of.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/of_irq.h> #include <linux/of_irq.h>
#include <linux/pci.h> #include <linux/pci.h>
...@@ -153,7 +154,8 @@ static const struct cdns_pcie_ops j721e_pcie_ops = { ...@@ -153,7 +154,8 @@ static const struct cdns_pcie_ops j721e_pcie_ops = {
.link_up = j721e_pcie_link_up, .link_up = j721e_pcie_link_up,
}; };
static int j721e_pcie_set_mode(struct j721e_pcie *pcie, struct regmap *syscon) static int j721e_pcie_set_mode(struct j721e_pcie *pcie, struct regmap *syscon,
unsigned int offset)
{ {
struct device *dev = pcie->dev; struct device *dev = pcie->dev;
u32 mask = J721E_MODE_RC; u32 mask = J721E_MODE_RC;
...@@ -164,7 +166,7 @@ static int j721e_pcie_set_mode(struct j721e_pcie *pcie, struct regmap *syscon) ...@@ -164,7 +166,7 @@ static int j721e_pcie_set_mode(struct j721e_pcie *pcie, struct regmap *syscon)
if (mode == PCI_MODE_RC) if (mode == PCI_MODE_RC)
val = J721E_MODE_RC; val = J721E_MODE_RC;
ret = regmap_update_bits(syscon, 0, mask, val); ret = regmap_update_bits(syscon, offset, mask, val);
if (ret) if (ret)
dev_err(dev, "failed to set pcie mode\n"); dev_err(dev, "failed to set pcie mode\n");
...@@ -172,7 +174,7 @@ static int j721e_pcie_set_mode(struct j721e_pcie *pcie, struct regmap *syscon) ...@@ -172,7 +174,7 @@ static int j721e_pcie_set_mode(struct j721e_pcie *pcie, struct regmap *syscon)
} }
static int j721e_pcie_set_link_speed(struct j721e_pcie *pcie, static int j721e_pcie_set_link_speed(struct j721e_pcie *pcie,
struct regmap *syscon) struct regmap *syscon, unsigned int offset)
{ {
struct device *dev = pcie->dev; struct device *dev = pcie->dev;
struct device_node *np = dev->of_node; struct device_node *np = dev->of_node;
...@@ -185,7 +187,7 @@ static int j721e_pcie_set_link_speed(struct j721e_pcie *pcie, ...@@ -185,7 +187,7 @@ static int j721e_pcie_set_link_speed(struct j721e_pcie *pcie,
link_speed = 2; link_speed = 2;
val = link_speed - 1; val = link_speed - 1;
ret = regmap_update_bits(syscon, 0, GENERATION_SEL_MASK, val); ret = regmap_update_bits(syscon, offset, GENERATION_SEL_MASK, val);
if (ret) if (ret)
dev_err(dev, "failed to set link speed\n"); dev_err(dev, "failed to set link speed\n");
...@@ -193,7 +195,7 @@ static int j721e_pcie_set_link_speed(struct j721e_pcie *pcie, ...@@ -193,7 +195,7 @@ static int j721e_pcie_set_link_speed(struct j721e_pcie *pcie,
} }
static int j721e_pcie_set_lane_count(struct j721e_pcie *pcie, static int j721e_pcie_set_lane_count(struct j721e_pcie *pcie,
struct regmap *syscon) struct regmap *syscon, unsigned int offset)
{ {
struct device *dev = pcie->dev; struct device *dev = pcie->dev;
u32 lanes = pcie->num_lanes; u32 lanes = pcie->num_lanes;
...@@ -201,7 +203,7 @@ static int j721e_pcie_set_lane_count(struct j721e_pcie *pcie, ...@@ -201,7 +203,7 @@ static int j721e_pcie_set_lane_count(struct j721e_pcie *pcie,
int ret; int ret;
val = LANE_COUNT(lanes - 1); val = LANE_COUNT(lanes - 1);
ret = regmap_update_bits(syscon, 0, LANE_COUNT_MASK, val); ret = regmap_update_bits(syscon, offset, LANE_COUNT_MASK, val);
if (ret) if (ret)
dev_err(dev, "failed to set link count\n"); dev_err(dev, "failed to set link count\n");
...@@ -212,6 +214,8 @@ static int j721e_pcie_ctrl_init(struct j721e_pcie *pcie) ...@@ -212,6 +214,8 @@ static int j721e_pcie_ctrl_init(struct j721e_pcie *pcie)
{ {
struct device *dev = pcie->dev; struct device *dev = pcie->dev;
struct device_node *node = dev->of_node; struct device_node *node = dev->of_node;
struct of_phandle_args args;
unsigned int offset = 0;
struct regmap *syscon; struct regmap *syscon;
int ret; int ret;
...@@ -221,19 +225,25 @@ static int j721e_pcie_ctrl_init(struct j721e_pcie *pcie) ...@@ -221,19 +225,25 @@ static int j721e_pcie_ctrl_init(struct j721e_pcie *pcie)
return PTR_ERR(syscon); return PTR_ERR(syscon);
} }
ret = j721e_pcie_set_mode(pcie, syscon); /* Do not error out to maintain old DT compatibility */
ret = of_parse_phandle_with_fixed_args(node, "ti,syscon-pcie-ctrl", 1,
0, &args);
if (!ret)
offset = args.args[0];
ret = j721e_pcie_set_mode(pcie, syscon, offset);
if (ret < 0) { if (ret < 0) {
dev_err(dev, "Failed to set pci mode\n"); dev_err(dev, "Failed to set pci mode\n");
return ret; return ret;
} }
ret = j721e_pcie_set_link_speed(pcie, syscon); ret = j721e_pcie_set_link_speed(pcie, syscon, offset);
if (ret < 0) { if (ret < 0) {
dev_err(dev, "Failed to set link speed\n"); dev_err(dev, "Failed to set link speed\n");
return ret; return ret;
} }
ret = j721e_pcie_set_lane_count(pcie, syscon); ret = j721e_pcie_set_lane_count(pcie, syscon, offset);
if (ret < 0) { if (ret < 0) {
dev_err(dev, "Failed to set num-lanes\n"); dev_err(dev, "Failed to set num-lanes\n");
return ret; return ret;
......
...@@ -530,12 +530,9 @@ int cdns_pcie_ep_setup(struct cdns_pcie_ep *ep) ...@@ -530,12 +530,9 @@ int cdns_pcie_ep_setup(struct cdns_pcie_ep *ep)
} }
pcie->mem_res = res; pcie->mem_res = res;
ret = of_property_read_u32(np, "cdns,max-outbound-regions", ep->max_regions = CDNS_PCIE_MAX_OB;
&ep->max_regions); of_property_read_u32(np, "cdns,max-outbound-regions", &ep->max_regions);
if (ret < 0) {
dev_err(dev, "missing \"cdns,max-outbound-regions\"\n");
return ret;
}
ep->ob_addr = devm_kcalloc(dev, ep->ob_addr = devm_kcalloc(dev,
ep->max_regions, sizeof(*ep->ob_addr), ep->max_regions, sizeof(*ep->ob_addr),
GFP_KERNEL); GFP_KERNEL);
......
...@@ -197,6 +197,7 @@ enum cdns_pcie_rp_bar { ...@@ -197,6 +197,7 @@ enum cdns_pcie_rp_bar {
}; };
#define CDNS_PCIE_RP_MAX_IB 0x3 #define CDNS_PCIE_RP_MAX_IB 0x3
#define CDNS_PCIE_MAX_OB 32
struct cdns_pcie_rp_ib_bar { struct cdns_pcie_rp_ib_bar {
u64 size; u64 size;
......
...@@ -83,10 +83,15 @@ config PCIE_DW_PLAT_EP ...@@ -83,10 +83,15 @@ config PCIE_DW_PLAT_EP
selected. selected.
config PCI_EXYNOS config PCI_EXYNOS
bool "Samsung Exynos PCIe controller" tristate "Samsung Exynos PCIe controller"
depends on SOC_EXYNOS5440 || COMPILE_TEST depends on ARCH_EXYNOS || COMPILE_TEST
depends on PCI_MSI_IRQ_DOMAIN depends on PCI_MSI_IRQ_DOMAIN
select PCIE_DW_HOST select PCIE_DW_HOST
help
Enables support for the PCIe controller in the Samsung Exynos SoCs
to work in host mode. The PCI controller is based on the DesignWare
hardware and therefore the driver re-uses the DesignWare core
functions to implement the driver.
config PCI_IMX6 config PCI_IMX6
bool "Freescale i.MX6/7/8 PCIe controller" bool "Freescale i.MX6/7/8 PCIe controller"
...@@ -107,7 +112,7 @@ config PCI_KEYSTONE ...@@ -107,7 +112,7 @@ config PCI_KEYSTONE
config PCI_KEYSTONE_HOST config PCI_KEYSTONE_HOST
bool "PCI Keystone Host Mode" bool "PCI Keystone Host Mode"
depends on ARCH_KEYSTONE || ARCH_K3 || ((ARM || ARM64) && COMPILE_TEST) depends on ARCH_KEYSTONE || ARCH_K3 || COMPILE_TEST
depends on PCI_MSI_IRQ_DOMAIN depends on PCI_MSI_IRQ_DOMAIN
select PCIE_DW_HOST select PCIE_DW_HOST
select PCI_KEYSTONE select PCI_KEYSTONE
...@@ -119,7 +124,7 @@ config PCI_KEYSTONE_HOST ...@@ -119,7 +124,7 @@ config PCI_KEYSTONE_HOST
config PCI_KEYSTONE_EP config PCI_KEYSTONE_EP
bool "PCI Keystone Endpoint Mode" bool "PCI Keystone Endpoint Mode"
depends on ARCH_KEYSTONE || ARCH_K3 || ((ARM || ARM64) && COMPILE_TEST) depends on ARCH_KEYSTONE || ARCH_K3 || COMPILE_TEST
depends on PCI_ENDPOINT depends on PCI_ENDPOINT
select PCIE_DW_EP select PCIE_DW_EP
select PCI_KEYSTONE select PCI_KEYSTONE
...@@ -169,6 +174,7 @@ config PCIE_QCOM ...@@ -169,6 +174,7 @@ config PCIE_QCOM
depends on OF && (ARCH_QCOM || COMPILE_TEST) depends on OF && (ARCH_QCOM || COMPILE_TEST)
depends on PCI_MSI_IRQ_DOMAIN depends on PCI_MSI_IRQ_DOMAIN
select PCIE_DW_HOST select PCIE_DW_HOST
select CRC8
help help
Say Y here to enable PCIe controller support on Qualcomm SoCs. The Say Y here to enable PCIe controller support on Qualcomm SoCs. The
PCIe controller uses the DesignWare core plus Qualcomm-specific PCIe controller uses the DesignWare core plus Qualcomm-specific
......
...@@ -181,11 +181,6 @@ static int dra7xx_pcie_host_init(struct pcie_port *pp) ...@@ -181,11 +181,6 @@ static int dra7xx_pcie_host_init(struct pcie_port *pp)
struct dw_pcie *pci = to_dw_pcie_from_pp(pp); struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
struct dra7xx_pcie *dra7xx = to_dra7xx_pcie(pci); struct dra7xx_pcie *dra7xx = to_dra7xx_pcie(pci);
dw_pcie_setup_rc(pp);
dra7xx_pcie_establish_link(pci);
dw_pcie_wait_for_link(pci);
dw_pcie_msi_init(pp);
dra7xx_pcie_enable_interrupts(dra7xx); dra7xx_pcie_enable_interrupts(dra7xx);
return 0; return 0;
...@@ -377,133 +372,8 @@ static int dra7xx_pcie_init_irq_domain(struct pcie_port *pp) ...@@ -377,133 +372,8 @@ static int dra7xx_pcie_init_irq_domain(struct pcie_port *pp)
return 0; return 0;
} }
static void dra7xx_pcie_setup_msi_msg(struct irq_data *d, struct msi_msg *msg)
{
struct pcie_port *pp = irq_data_get_irq_chip_data(d);
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
u64 msi_target;
msi_target = (u64)pp->msi_data;
msg->address_lo = lower_32_bits(msi_target);
msg->address_hi = upper_32_bits(msi_target);
msg->data = d->hwirq;
dev_dbg(pci->dev, "msi#%d address_hi %#x address_lo %#x\n",
(int)d->hwirq, msg->address_hi, msg->address_lo);
}
static int dra7xx_pcie_msi_set_affinity(struct irq_data *d,
const struct cpumask *mask,
bool force)
{
return -EINVAL;
}
static void dra7xx_pcie_bottom_mask(struct irq_data *d)
{
struct pcie_port *pp = irq_data_get_irq_chip_data(d);
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
unsigned int res, bit, ctrl;
unsigned long flags;
raw_spin_lock_irqsave(&pp->lock, flags);
ctrl = d->hwirq / MAX_MSI_IRQS_PER_CTRL;
res = ctrl * MSI_REG_CTRL_BLOCK_SIZE;
bit = d->hwirq % MAX_MSI_IRQS_PER_CTRL;
pp->irq_mask[ctrl] |= BIT(bit);
dw_pcie_writel_dbi(pci, PCIE_MSI_INTR0_MASK + res,
pp->irq_mask[ctrl]);
raw_spin_unlock_irqrestore(&pp->lock, flags);
}
static void dra7xx_pcie_bottom_unmask(struct irq_data *d)
{
struct pcie_port *pp = irq_data_get_irq_chip_data(d);
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
unsigned int res, bit, ctrl;
unsigned long flags;
raw_spin_lock_irqsave(&pp->lock, flags);
ctrl = d->hwirq / MAX_MSI_IRQS_PER_CTRL;
res = ctrl * MSI_REG_CTRL_BLOCK_SIZE;
bit = d->hwirq % MAX_MSI_IRQS_PER_CTRL;
pp->irq_mask[ctrl] &= ~BIT(bit);
dw_pcie_writel_dbi(pci, PCIE_MSI_INTR0_MASK + res,
pp->irq_mask[ctrl]);
raw_spin_unlock_irqrestore(&pp->lock, flags);
}
static void dra7xx_pcie_bottom_ack(struct irq_data *d)
{
struct pcie_port *pp = irq_data_get_irq_chip_data(d);
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
unsigned int res, bit, ctrl;
ctrl = d->hwirq / MAX_MSI_IRQS_PER_CTRL;
res = ctrl * MSI_REG_CTRL_BLOCK_SIZE;
bit = d->hwirq % MAX_MSI_IRQS_PER_CTRL;
dw_pcie_writel_dbi(pci, PCIE_MSI_INTR0_STATUS + res, BIT(bit));
}
static struct irq_chip dra7xx_pci_msi_bottom_irq_chip = {
.name = "DRA7XX-PCI-MSI",
.irq_ack = dra7xx_pcie_bottom_ack,
.irq_compose_msi_msg = dra7xx_pcie_setup_msi_msg,
.irq_set_affinity = dra7xx_pcie_msi_set_affinity,
.irq_mask = dra7xx_pcie_bottom_mask,
.irq_unmask = dra7xx_pcie_bottom_unmask,
};
static int dra7xx_pcie_msi_host_init(struct pcie_port *pp)
{
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
struct device *dev = pci->dev;
u32 ctrl, num_ctrls;
int ret;
pp->msi_irq_chip = &dra7xx_pci_msi_bottom_irq_chip;
num_ctrls = pp->num_vectors / MAX_MSI_IRQS_PER_CTRL;
/* Initialize IRQ Status array */
for (ctrl = 0; ctrl < num_ctrls; ctrl++) {
pp->irq_mask[ctrl] = ~0;
dw_pcie_writel_dbi(pci, PCIE_MSI_INTR0_MASK +
(ctrl * MSI_REG_CTRL_BLOCK_SIZE),
pp->irq_mask[ctrl]);
dw_pcie_writel_dbi(pci, PCIE_MSI_INTR0_ENABLE +
(ctrl * MSI_REG_CTRL_BLOCK_SIZE),
~0);
}
ret = dw_pcie_allocate_domains(pp);
if (ret)
return ret;
pp->msi_data = dma_map_single_attrs(dev, &pp->msi_msg,
sizeof(pp->msi_msg),
DMA_FROM_DEVICE,
DMA_ATTR_SKIP_CPU_SYNC);
ret = dma_mapping_error(dev, pp->msi_data);
if (ret) {
dev_err(dev, "Failed to map MSI data\n");
pp->msi_data = 0;
dw_pcie_free_msi(pp);
}
return ret;
}
static const struct dw_pcie_host_ops dra7xx_pcie_host_ops = { static const struct dw_pcie_host_ops dra7xx_pcie_host_ops = {
.host_init = dra7xx_pcie_host_init, .host_init = dra7xx_pcie_host_init,
.msi_host_init = dra7xx_pcie_msi_host_init,
}; };
static void dra7xx_pcie_ep_init(struct dw_pcie_ep *ep) static void dra7xx_pcie_ep_init(struct dw_pcie_ep *ep)
...@@ -578,7 +448,6 @@ static int __init dra7xx_add_pcie_ep(struct dra7xx_pcie *dra7xx, ...@@ -578,7 +448,6 @@ static int __init dra7xx_add_pcie_ep(struct dra7xx_pcie *dra7xx,
{ {
int ret; int ret;
struct dw_pcie_ep *ep; struct dw_pcie_ep *ep;
struct resource *res;
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct dw_pcie *pci = dra7xx->pci; struct dw_pcie *pci = dra7xx->pci;
...@@ -594,13 +463,6 @@ static int __init dra7xx_add_pcie_ep(struct dra7xx_pcie *dra7xx, ...@@ -594,13 +463,6 @@ static int __init dra7xx_add_pcie_ep(struct dra7xx_pcie *dra7xx,
if (IS_ERR(pci->dbi_base2)) if (IS_ERR(pci->dbi_base2))
return PTR_ERR(pci->dbi_base2); return PTR_ERR(pci->dbi_base2);
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "addr_space");
if (!res)
return -EINVAL;
ep->phys_base = res->start;
ep->addr_size = resource_size(res);
ret = dw_pcie_ep_init(ep); ret = dw_pcie_ep_init(ep);
if (ret) { if (ret) {
dev_err(dev, "failed to initialize endpoint\n"); dev_err(dev, "failed to initialize endpoint\n");
...@@ -622,6 +484,9 @@ static int __init dra7xx_add_pcie_port(struct dra7xx_pcie *dra7xx, ...@@ -622,6 +484,9 @@ static int __init dra7xx_add_pcie_port(struct dra7xx_pcie *dra7xx,
if (pp->irq < 0) if (pp->irq < 0)
return pp->irq; return pp->irq;
/* MSI IRQ is muxed */
pp->msi_irq = -ENODEV;
ret = dra7xx_pcie_init_irq_domain(pp); ret = dra7xx_pcie_init_irq_domain(pp);
if (ret < 0) if (ret < 0)
return ret; return ret;
......
...@@ -2,26 +2,23 @@ ...@@ -2,26 +2,23 @@
/* /*
* PCIe host controller driver for Samsung Exynos SoCs * PCIe host controller driver for Samsung Exynos SoCs
* *
* Copyright (C) 2013 Samsung Electronics Co., Ltd. * Copyright (C) 2013-2020 Samsung Electronics Co., Ltd.
* https://www.samsung.com * https://www.samsung.com
* *
* Author: Jingoo Han <jg1.han@samsung.com> * Author: Jingoo Han <jg1.han@samsung.com>
* Jaehoon Chung <jh80.chung@samsung.com>
*/ */
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/phy/phy.h> #include <linux/phy/phy.h>
#include <linux/resource.h> #include <linux/regulator/consumer.h>
#include <linux/signal.h>
#include <linux/types.h>
#include "pcie-designware.h" #include "pcie-designware.h"
...@@ -37,102 +34,43 @@ ...@@ -37,102 +34,43 @@
#define PCIE_IRQ_SPECIAL 0x008 #define PCIE_IRQ_SPECIAL 0x008
#define PCIE_IRQ_EN_PULSE 0x00c #define PCIE_IRQ_EN_PULSE 0x00c
#define PCIE_IRQ_EN_LEVEL 0x010 #define PCIE_IRQ_EN_LEVEL 0x010
#define IRQ_MSI_ENABLE BIT(2)
#define PCIE_IRQ_EN_SPECIAL 0x014 #define PCIE_IRQ_EN_SPECIAL 0x014
#define PCIE_PWR_RESET 0x018 #define PCIE_SW_WAKE 0x018
#define PCIE_BUS_EN BIT(1)
#define PCIE_CORE_RESET 0x01c #define PCIE_CORE_RESET 0x01c
#define PCIE_CORE_RESET_ENABLE BIT(0) #define PCIE_CORE_RESET_ENABLE BIT(0)
#define PCIE_STICKY_RESET 0x020 #define PCIE_STICKY_RESET 0x020
#define PCIE_NONSTICKY_RESET 0x024 #define PCIE_NONSTICKY_RESET 0x024
#define PCIE_APP_INIT_RESET 0x028 #define PCIE_APP_INIT_RESET 0x028
#define PCIE_APP_LTSSM_ENABLE 0x02c #define PCIE_APP_LTSSM_ENABLE 0x02c
#define PCIE_ELBI_RDLH_LINKUP 0x064 #define PCIE_ELBI_RDLH_LINKUP 0x074
#define PCIE_ELBI_XMLH_LINKUP BIT(4)
#define PCIE_ELBI_LTSSM_ENABLE 0x1 #define PCIE_ELBI_LTSSM_ENABLE 0x1
#define PCIE_ELBI_SLV_AWMISC 0x11c #define PCIE_ELBI_SLV_AWMISC 0x11c
#define PCIE_ELBI_SLV_ARMISC 0x120 #define PCIE_ELBI_SLV_ARMISC 0x120
#define PCIE_ELBI_SLV_DBI_ENABLE BIT(21) #define PCIE_ELBI_SLV_DBI_ENABLE BIT(21)
struct exynos_pcie_mem_res {
void __iomem *elbi_base; /* DT 0th resource: PCIe CTRL */
};
struct exynos_pcie_clk_res {
struct clk *clk;
struct clk *bus_clk;
};
struct exynos_pcie { struct exynos_pcie {
struct dw_pcie *pci; struct dw_pcie pci;
struct exynos_pcie_mem_res *mem_res; void __iomem *elbi_base;
struct exynos_pcie_clk_res *clk_res; struct clk *clk;
const struct exynos_pcie_ops *ops; struct clk *bus_clk;
int reset_gpio;
struct phy *phy; struct phy *phy;
struct regulator_bulk_data supplies[2];
}; };
struct exynos_pcie_ops { static int exynos_pcie_init_clk_resources(struct exynos_pcie *ep)
int (*get_mem_resources)(struct platform_device *pdev,
struct exynos_pcie *ep);
int (*get_clk_resources)(struct exynos_pcie *ep);
int (*init_clk_resources)(struct exynos_pcie *ep);
void (*deinit_clk_resources)(struct exynos_pcie *ep);
};
static int exynos5440_pcie_get_mem_resources(struct platform_device *pdev,
struct exynos_pcie *ep)
{
struct dw_pcie *pci = ep->pci;
struct device *dev = pci->dev;
ep->mem_res = devm_kzalloc(dev, sizeof(*ep->mem_res), GFP_KERNEL);
if (!ep->mem_res)
return -ENOMEM;
ep->mem_res->elbi_base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(ep->mem_res->elbi_base))
return PTR_ERR(ep->mem_res->elbi_base);
return 0;
}
static int exynos5440_pcie_get_clk_resources(struct exynos_pcie *ep)
{ {
struct dw_pcie *pci = ep->pci; struct device *dev = ep->pci.dev;
struct device *dev = pci->dev;
ep->clk_res = devm_kzalloc(dev, sizeof(*ep->clk_res), GFP_KERNEL);
if (!ep->clk_res)
return -ENOMEM;
ep->clk_res->clk = devm_clk_get(dev, "pcie");
if (IS_ERR(ep->clk_res->clk)) {
dev_err(dev, "Failed to get pcie rc clock\n");
return PTR_ERR(ep->clk_res->clk);
}
ep->clk_res->bus_clk = devm_clk_get(dev, "pcie_bus");
if (IS_ERR(ep->clk_res->bus_clk)) {
dev_err(dev, "Failed to get pcie bus clock\n");
return PTR_ERR(ep->clk_res->bus_clk);
}
return 0;
}
static int exynos5440_pcie_init_clk_resources(struct exynos_pcie *ep)
{
struct dw_pcie *pci = ep->pci;
struct device *dev = pci->dev;
int ret; int ret;
ret = clk_prepare_enable(ep->clk_res->clk); ret = clk_prepare_enable(ep->clk);
if (ret) { if (ret) {
dev_err(dev, "cannot enable pcie rc clock"); dev_err(dev, "cannot enable pcie rc clock");
return ret; return ret;
} }
ret = clk_prepare_enable(ep->clk_res->bus_clk); ret = clk_prepare_enable(ep->bus_clk);
if (ret) { if (ret) {
dev_err(dev, "cannot enable pcie bus clock"); dev_err(dev, "cannot enable pcie bus clock");
goto err_bus_clk; goto err_bus_clk;
...@@ -141,24 +79,17 @@ static int exynos5440_pcie_init_clk_resources(struct exynos_pcie *ep) ...@@ -141,24 +79,17 @@ static int exynos5440_pcie_init_clk_resources(struct exynos_pcie *ep)
return 0; return 0;
err_bus_clk: err_bus_clk:
clk_disable_unprepare(ep->clk_res->clk); clk_disable_unprepare(ep->clk);
return ret; return ret;
} }
static void exynos5440_pcie_deinit_clk_resources(struct exynos_pcie *ep) static void exynos_pcie_deinit_clk_resources(struct exynos_pcie *ep)
{ {
clk_disable_unprepare(ep->clk_res->bus_clk); clk_disable_unprepare(ep->bus_clk);
clk_disable_unprepare(ep->clk_res->clk); clk_disable_unprepare(ep->clk);
} }
static const struct exynos_pcie_ops exynos5440_pcie_ops = {
.get_mem_resources = exynos5440_pcie_get_mem_resources,
.get_clk_resources = exynos5440_pcie_get_clk_resources,
.init_clk_resources = exynos5440_pcie_init_clk_resources,
.deinit_clk_resources = exynos5440_pcie_deinit_clk_resources,
};
static void exynos_pcie_writel(void __iomem *base, u32 val, u32 reg) static void exynos_pcie_writel(void __iomem *base, u32 val, u32 reg)
{ {
writel(val, base + reg); writel(val, base + reg);
...@@ -173,115 +104,71 @@ static void exynos_pcie_sideband_dbi_w_mode(struct exynos_pcie *ep, bool on) ...@@ -173,115 +104,71 @@ static void exynos_pcie_sideband_dbi_w_mode(struct exynos_pcie *ep, bool on)
{ {
u32 val; u32 val;
val = exynos_pcie_readl(ep->mem_res->elbi_base, PCIE_ELBI_SLV_AWMISC); val = exynos_pcie_readl(ep->elbi_base, PCIE_ELBI_SLV_AWMISC);
if (on) if (on)
val |= PCIE_ELBI_SLV_DBI_ENABLE; val |= PCIE_ELBI_SLV_DBI_ENABLE;
else else
val &= ~PCIE_ELBI_SLV_DBI_ENABLE; val &= ~PCIE_ELBI_SLV_DBI_ENABLE;
exynos_pcie_writel(ep->mem_res->elbi_base, val, PCIE_ELBI_SLV_AWMISC); exynos_pcie_writel(ep->elbi_base, val, PCIE_ELBI_SLV_AWMISC);
} }
static void exynos_pcie_sideband_dbi_r_mode(struct exynos_pcie *ep, bool on) static void exynos_pcie_sideband_dbi_r_mode(struct exynos_pcie *ep, bool on)
{ {
u32 val; u32 val;
val = exynos_pcie_readl(ep->mem_res->elbi_base, PCIE_ELBI_SLV_ARMISC); val = exynos_pcie_readl(ep->elbi_base, PCIE_ELBI_SLV_ARMISC);
if (on) if (on)
val |= PCIE_ELBI_SLV_DBI_ENABLE; val |= PCIE_ELBI_SLV_DBI_ENABLE;
else else
val &= ~PCIE_ELBI_SLV_DBI_ENABLE; val &= ~PCIE_ELBI_SLV_DBI_ENABLE;
exynos_pcie_writel(ep->mem_res->elbi_base, val, PCIE_ELBI_SLV_ARMISC); exynos_pcie_writel(ep->elbi_base, val, PCIE_ELBI_SLV_ARMISC);
} }
static void exynos_pcie_assert_core_reset(struct exynos_pcie *ep) static void exynos_pcie_assert_core_reset(struct exynos_pcie *ep)
{ {
u32 val; u32 val;
val = exynos_pcie_readl(ep->mem_res->elbi_base, PCIE_CORE_RESET); val = exynos_pcie_readl(ep->elbi_base, PCIE_CORE_RESET);
val &= ~PCIE_CORE_RESET_ENABLE; val &= ~PCIE_CORE_RESET_ENABLE;
exynos_pcie_writel(ep->mem_res->elbi_base, val, PCIE_CORE_RESET); exynos_pcie_writel(ep->elbi_base, val, PCIE_CORE_RESET);
exynos_pcie_writel(ep->mem_res->elbi_base, 0, PCIE_PWR_RESET); exynos_pcie_writel(ep->elbi_base, 0, PCIE_STICKY_RESET);
exynos_pcie_writel(ep->mem_res->elbi_base, 0, PCIE_STICKY_RESET); exynos_pcie_writel(ep->elbi_base, 0, PCIE_NONSTICKY_RESET);
exynos_pcie_writel(ep->mem_res->elbi_base, 0, PCIE_NONSTICKY_RESET);
} }
static void exynos_pcie_deassert_core_reset(struct exynos_pcie *ep) static void exynos_pcie_deassert_core_reset(struct exynos_pcie *ep)
{ {
u32 val; u32 val;
val = exynos_pcie_readl(ep->mem_res->elbi_base, PCIE_CORE_RESET); val = exynos_pcie_readl(ep->elbi_base, PCIE_CORE_RESET);
val |= PCIE_CORE_RESET_ENABLE; val |= PCIE_CORE_RESET_ENABLE;
exynos_pcie_writel(ep->mem_res->elbi_base, val, PCIE_CORE_RESET); exynos_pcie_writel(ep->elbi_base, val, PCIE_CORE_RESET);
exynos_pcie_writel(ep->mem_res->elbi_base, 1, PCIE_STICKY_RESET); exynos_pcie_writel(ep->elbi_base, 1, PCIE_STICKY_RESET);
exynos_pcie_writel(ep->mem_res->elbi_base, 1, PCIE_NONSTICKY_RESET); exynos_pcie_writel(ep->elbi_base, 1, PCIE_NONSTICKY_RESET);
exynos_pcie_writel(ep->mem_res->elbi_base, 1, PCIE_APP_INIT_RESET); exynos_pcie_writel(ep->elbi_base, 1, PCIE_APP_INIT_RESET);
exynos_pcie_writel(ep->mem_res->elbi_base, 0, PCIE_APP_INIT_RESET); exynos_pcie_writel(ep->elbi_base, 0, PCIE_APP_INIT_RESET);
}
static void exynos_pcie_assert_reset(struct exynos_pcie *ep)
{
struct dw_pcie *pci = ep->pci;
struct device *dev = pci->dev;
if (ep->reset_gpio >= 0)
devm_gpio_request_one(dev, ep->reset_gpio,
GPIOF_OUT_INIT_HIGH, "RESET");
} }
static int exynos_pcie_establish_link(struct exynos_pcie *ep) static int exynos_pcie_start_link(struct dw_pcie *pci)
{ {
struct dw_pcie *pci = ep->pci; struct exynos_pcie *ep = to_exynos_pcie(pci);
struct pcie_port *pp = &pci->pp; u32 val;
struct device *dev = pci->dev;
if (dw_pcie_link_up(pci)) {
dev_err(dev, "Link already up\n");
return 0;
}
exynos_pcie_assert_core_reset(ep);
phy_reset(ep->phy);
exynos_pcie_writel(ep->mem_res->elbi_base, 1,
PCIE_PWR_RESET);
phy_power_on(ep->phy); val = exynos_pcie_readl(ep->elbi_base, PCIE_SW_WAKE);
phy_init(ep->phy); val &= ~PCIE_BUS_EN;
exynos_pcie_writel(ep->elbi_base, val, PCIE_SW_WAKE);
exynos_pcie_deassert_core_reset(ep);
dw_pcie_setup_rc(pp);
exynos_pcie_assert_reset(ep);
/* assert LTSSM enable */ /* assert LTSSM enable */
exynos_pcie_writel(ep->mem_res->elbi_base, PCIE_ELBI_LTSSM_ENABLE, exynos_pcie_writel(ep->elbi_base, PCIE_ELBI_LTSSM_ENABLE,
PCIE_APP_LTSSM_ENABLE); PCIE_APP_LTSSM_ENABLE);
return 0;
/* check if the link is up or not */
if (!dw_pcie_wait_for_link(pci))
return 0;
phy_power_off(ep->phy);
return -ETIMEDOUT;
} }
static void exynos_pcie_clear_irq_pulse(struct exynos_pcie *ep) static void exynos_pcie_clear_irq_pulse(struct exynos_pcie *ep)
{ {
u32 val; u32 val = exynos_pcie_readl(ep->elbi_base, PCIE_IRQ_PULSE);
val = exynos_pcie_readl(ep->mem_res->elbi_base, PCIE_IRQ_PULSE); exynos_pcie_writel(ep->elbi_base, val, PCIE_IRQ_PULSE);
exynos_pcie_writel(ep->mem_res->elbi_base, val, PCIE_IRQ_PULSE);
}
static void exynos_pcie_enable_irq_pulse(struct exynos_pcie *ep)
{
u32 val;
/* enable INTX interrupt */
val = IRQ_INTA_ASSERT | IRQ_INTB_ASSERT |
IRQ_INTC_ASSERT | IRQ_INTD_ASSERT;
exynos_pcie_writel(ep->mem_res->elbi_base, val, PCIE_IRQ_EN_PULSE);
} }
static irqreturn_t exynos_pcie_irq_handler(int irq, void *arg) static irqreturn_t exynos_pcie_irq_handler(int irq, void *arg)
...@@ -292,26 +179,14 @@ static irqreturn_t exynos_pcie_irq_handler(int irq, void *arg) ...@@ -292,26 +179,14 @@ static irqreturn_t exynos_pcie_irq_handler(int irq, void *arg)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static void exynos_pcie_msi_init(struct exynos_pcie *ep) static void exynos_pcie_enable_irq_pulse(struct exynos_pcie *ep)
{
struct dw_pcie *pci = ep->pci;
struct pcie_port *pp = &pci->pp;
u32 val;
dw_pcie_msi_init(pp);
/* enable MSI interrupt */
val = exynos_pcie_readl(ep->mem_res->elbi_base, PCIE_IRQ_EN_LEVEL);
val |= IRQ_MSI_ENABLE;
exynos_pcie_writel(ep->mem_res->elbi_base, val, PCIE_IRQ_EN_LEVEL);
}
static void exynos_pcie_enable_interrupts(struct exynos_pcie *ep)
{ {
exynos_pcie_enable_irq_pulse(ep); u32 val = IRQ_INTA_ASSERT | IRQ_INTB_ASSERT |
IRQ_INTC_ASSERT | IRQ_INTD_ASSERT;
if (IS_ENABLED(CONFIG_PCI_MSI)) exynos_pcie_writel(ep->elbi_base, val, PCIE_IRQ_EN_PULSE);
exynos_pcie_msi_init(ep); exynos_pcie_writel(ep->elbi_base, 0, PCIE_IRQ_EN_LEVEL);
exynos_pcie_writel(ep->elbi_base, 0, PCIE_IRQ_EN_SPECIAL);
} }
static u32 exynos_pcie_read_dbi(struct dw_pcie *pci, void __iomem *base, static u32 exynos_pcie_read_dbi(struct dw_pcie *pci, void __iomem *base,
...@@ -370,13 +245,9 @@ static struct pci_ops exynos_pci_ops = { ...@@ -370,13 +245,9 @@ static struct pci_ops exynos_pci_ops = {
static int exynos_pcie_link_up(struct dw_pcie *pci) static int exynos_pcie_link_up(struct dw_pcie *pci)
{ {
struct exynos_pcie *ep = to_exynos_pcie(pci); struct exynos_pcie *ep = to_exynos_pcie(pci);
u32 val; u32 val = exynos_pcie_readl(ep->elbi_base, PCIE_ELBI_RDLH_LINKUP);
val = exynos_pcie_readl(ep->mem_res->elbi_base, PCIE_ELBI_RDLH_LINKUP); return (val & PCIE_ELBI_XMLH_LINKUP);
if (val == PCIE_ELBI_LTSSM_ENABLE)
return 1;
return 0;
} }
static int exynos_pcie_host_init(struct pcie_port *pp) static int exynos_pcie_host_init(struct pcie_port *pp)
...@@ -386,8 +257,14 @@ static int exynos_pcie_host_init(struct pcie_port *pp) ...@@ -386,8 +257,14 @@ static int exynos_pcie_host_init(struct pcie_port *pp)
pp->bridge->ops = &exynos_pci_ops; pp->bridge->ops = &exynos_pci_ops;
exynos_pcie_establish_link(ep); exynos_pcie_assert_core_reset(ep);
exynos_pcie_enable_interrupts(ep);
phy_reset(ep->phy);
phy_power_on(ep->phy);
phy_init(ep->phy);
exynos_pcie_deassert_core_reset(ep);
exynos_pcie_enable_irq_pulse(ep);
return 0; return 0;
} }
...@@ -396,32 +273,27 @@ static const struct dw_pcie_host_ops exynos_pcie_host_ops = { ...@@ -396,32 +273,27 @@ static const struct dw_pcie_host_ops exynos_pcie_host_ops = {
.host_init = exynos_pcie_host_init, .host_init = exynos_pcie_host_init,
}; };
static int __init exynos_add_pcie_port(struct exynos_pcie *ep, static int exynos_add_pcie_port(struct exynos_pcie *ep,
struct platform_device *pdev) struct platform_device *pdev)
{ {
struct dw_pcie *pci = ep->pci; struct dw_pcie *pci = &ep->pci;
struct pcie_port *pp = &pci->pp; struct pcie_port *pp = &pci->pp;
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
int ret; int ret;
pp->irq = platform_get_irq(pdev, 1); pp->irq = platform_get_irq(pdev, 0);
if (pp->irq < 0) if (pp->irq < 0)
return pp->irq; return pp->irq;
ret = devm_request_irq(dev, pp->irq, exynos_pcie_irq_handler, ret = devm_request_irq(dev, pp->irq, exynos_pcie_irq_handler,
IRQF_SHARED, "exynos-pcie", ep); IRQF_SHARED, "exynos-pcie", ep);
if (ret) { if (ret) {
dev_err(dev, "failed to request irq\n"); dev_err(dev, "failed to request irq\n");
return ret; return ret;
} }
if (IS_ENABLED(CONFIG_PCI_MSI)) {
pp->msi_irq = platform_get_irq(pdev, 0);
if (pp->msi_irq < 0)
return pp->msi_irq;
}
pp->ops = &exynos_pcie_host_ops; pp->ops = &exynos_pcie_host_ops;
pp->msi_irq = -ENODEV;
ret = dw_pcie_host_init(pp); ret = dw_pcie_host_init(pp);
if (ret) { if (ret) {
...@@ -436,12 +308,12 @@ static const struct dw_pcie_ops dw_pcie_ops = { ...@@ -436,12 +308,12 @@ static const struct dw_pcie_ops dw_pcie_ops = {
.read_dbi = exynos_pcie_read_dbi, .read_dbi = exynos_pcie_read_dbi,
.write_dbi = exynos_pcie_write_dbi, .write_dbi = exynos_pcie_write_dbi,
.link_up = exynos_pcie_link_up, .link_up = exynos_pcie_link_up,
.start_link = exynos_pcie_start_link,
}; };
static int __init exynos_pcie_probe(struct platform_device *pdev) static int exynos_pcie_probe(struct platform_device *pdev)
{ {
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct dw_pcie *pci;
struct exynos_pcie *ep; struct exynos_pcie *ep;
struct device_node *np = dev->of_node; struct device_node *np = dev->of_node;
int ret; int ret;
...@@ -450,43 +322,45 @@ static int __init exynos_pcie_probe(struct platform_device *pdev) ...@@ -450,43 +322,45 @@ static int __init exynos_pcie_probe(struct platform_device *pdev)
if (!ep) if (!ep)
return -ENOMEM; return -ENOMEM;
pci = devm_kzalloc(dev, sizeof(*pci), GFP_KERNEL); ep->pci.dev = dev;
if (!pci) ep->pci.ops = &dw_pcie_ops;
return -ENOMEM;
pci->dev = dev;
pci->ops = &dw_pcie_ops;
ep->pci = pci;
ep->ops = (const struct exynos_pcie_ops *)
of_device_get_match_data(dev);
ep->reset_gpio = of_get_named_gpio(np, "reset-gpio", 0);
ep->phy = devm_of_phy_get(dev, np, NULL); ep->phy = devm_of_phy_get(dev, np, NULL);
if (IS_ERR(ep->phy)) { if (IS_ERR(ep->phy))
if (PTR_ERR(ep->phy) != -ENODEV) return PTR_ERR(ep->phy);
return PTR_ERR(ep->phy);
ep->phy = NULL; /* External Local Bus interface (ELBI) registers */
} ep->elbi_base = devm_platform_ioremap_resource_byname(pdev, "elbi");
if (IS_ERR(ep->elbi_base))
return PTR_ERR(ep->elbi_base);
if (ep->ops && ep->ops->get_mem_resources) { ep->clk = devm_clk_get(dev, "pcie");
ret = ep->ops->get_mem_resources(pdev, ep); if (IS_ERR(ep->clk)) {
if (ret) dev_err(dev, "Failed to get pcie rc clock\n");
return ret; return PTR_ERR(ep->clk);
} }
if (ep->ops && ep->ops->get_clk_resources && ep->bus_clk = devm_clk_get(dev, "pcie_bus");
ep->ops->init_clk_resources) { if (IS_ERR(ep->bus_clk)) {
ret = ep->ops->get_clk_resources(ep); dev_err(dev, "Failed to get pcie bus clock\n");
if (ret) return PTR_ERR(ep->bus_clk);
return ret;
ret = ep->ops->init_clk_resources(ep);
if (ret)
return ret;
} }
ep->supplies[0].supply = "vdd18";
ep->supplies[1].supply = "vdd10";
ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ep->supplies),
ep->supplies);
if (ret)
return ret;
ret = exynos_pcie_init_clk_resources(ep);
if (ret)
return ret;
ret = regulator_bulk_enable(ARRAY_SIZE(ep->supplies), ep->supplies);
if (ret)
return ret;
platform_set_drvdata(pdev, ep); platform_set_drvdata(pdev, ep);
ret = exynos_add_pcie_port(ep, pdev); ret = exynos_add_pcie_port(ep, pdev);
...@@ -497,9 +371,9 @@ static int __init exynos_pcie_probe(struct platform_device *pdev) ...@@ -497,9 +371,9 @@ static int __init exynos_pcie_probe(struct platform_device *pdev)
fail_probe: fail_probe:
phy_exit(ep->phy); phy_exit(ep->phy);
exynos_pcie_deinit_clk_resources(ep);
regulator_bulk_disable(ARRAY_SIZE(ep->supplies), ep->supplies);
if (ep->ops && ep->ops->deinit_clk_resources)
ep->ops->deinit_clk_resources(ep);
return ret; return ret;
} }
...@@ -507,32 +381,65 @@ static int __exit exynos_pcie_remove(struct platform_device *pdev) ...@@ -507,32 +381,65 @@ static int __exit exynos_pcie_remove(struct platform_device *pdev)
{ {
struct exynos_pcie *ep = platform_get_drvdata(pdev); struct exynos_pcie *ep = platform_get_drvdata(pdev);
if (ep->ops && ep->ops->deinit_clk_resources) dw_pcie_host_deinit(&ep->pci.pp);
ep->ops->deinit_clk_resources(ep); exynos_pcie_assert_core_reset(ep);
phy_power_off(ep->phy);
phy_exit(ep->phy);
exynos_pcie_deinit_clk_resources(ep);
regulator_bulk_disable(ARRAY_SIZE(ep->supplies), ep->supplies);
return 0; return 0;
} }
static int __maybe_unused exynos_pcie_suspend_noirq(struct device *dev)
{
struct exynos_pcie *ep = dev_get_drvdata(dev);
exynos_pcie_assert_core_reset(ep);
phy_power_off(ep->phy);
phy_exit(ep->phy);
regulator_bulk_disable(ARRAY_SIZE(ep->supplies), ep->supplies);
return 0;
}
static int __maybe_unused exynos_pcie_resume_noirq(struct device *dev)
{
struct exynos_pcie *ep = dev_get_drvdata(dev);
struct dw_pcie *pci = &ep->pci;
struct pcie_port *pp = &pci->pp;
int ret;
ret = regulator_bulk_enable(ARRAY_SIZE(ep->supplies), ep->supplies);
if (ret)
return ret;
/* exynos_pcie_host_init controls ep->phy */
exynos_pcie_host_init(pp);
dw_pcie_setup_rc(pp);
exynos_pcie_start_link(pci);
return dw_pcie_wait_for_link(pci);
}
static const struct dev_pm_ops exynos_pcie_pm_ops = {
SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(exynos_pcie_suspend_noirq,
exynos_pcie_resume_noirq)
};
static const struct of_device_id exynos_pcie_of_match[] = { static const struct of_device_id exynos_pcie_of_match[] = {
{ { .compatible = "samsung,exynos5433-pcie", },
.compatible = "samsung,exynos5440-pcie", { },
.data = &exynos5440_pcie_ops
},
{},
}; };
static struct platform_driver exynos_pcie_driver = { static struct platform_driver exynos_pcie_driver = {
.probe = exynos_pcie_probe,
.remove = __exit_p(exynos_pcie_remove), .remove = __exit_p(exynos_pcie_remove),
.driver = { .driver = {
.name = "exynos-pcie", .name = "exynos-pcie",
.of_match_table = exynos_pcie_of_match, .of_match_table = exynos_pcie_of_match,
.pm = &exynos_pcie_pm_ops,
}, },
}; };
module_platform_driver(exynos_pcie_driver);
/* Exynos PCIe driver does not allow module unload */ MODULE_LICENSE("GPL v2");
MODULE_DEVICE_TABLE(of, exynos_pcie_of_match);
static int __init exynos_pcie_init(void)
{
return platform_driver_probe(&exynos_pcie_driver, exynos_pcie_probe);
}
subsys_initcall(exynos_pcie_init);
...@@ -745,9 +745,9 @@ static void imx6_pcie_ltssm_enable(struct device *dev) ...@@ -745,9 +745,9 @@ static void imx6_pcie_ltssm_enable(struct device *dev)
} }
} }
static int imx6_pcie_establish_link(struct imx6_pcie *imx6_pcie) static int imx6_pcie_start_link(struct dw_pcie *pci)
{ {
struct dw_pcie *pci = imx6_pcie->pci; struct imx6_pcie *imx6_pcie = to_imx6_pcie(pci);
struct device *dev = pci->dev; struct device *dev = pci->dev;
u8 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP); u8 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
u32 tmp; u32 tmp;
...@@ -834,9 +834,6 @@ static int imx6_pcie_host_init(struct pcie_port *pp) ...@@ -834,9 +834,6 @@ static int imx6_pcie_host_init(struct pcie_port *pp)
imx6_pcie_init_phy(imx6_pcie); imx6_pcie_init_phy(imx6_pcie);
imx6_pcie_deassert_core_reset(imx6_pcie); imx6_pcie_deassert_core_reset(imx6_pcie);
imx6_setup_phy_mpll(imx6_pcie); imx6_setup_phy_mpll(imx6_pcie);
dw_pcie_setup_rc(pp);
imx6_pcie_establish_link(imx6_pcie);
dw_pcie_msi_init(pp);
return 0; return 0;
} }
...@@ -845,33 +842,8 @@ static const struct dw_pcie_host_ops imx6_pcie_host_ops = { ...@@ -845,33 +842,8 @@ static const struct dw_pcie_host_ops imx6_pcie_host_ops = {
.host_init = imx6_pcie_host_init, .host_init = imx6_pcie_host_init,
}; };
static int imx6_add_pcie_port(struct imx6_pcie *imx6_pcie,
struct platform_device *pdev)
{
struct dw_pcie *pci = imx6_pcie->pci;
struct pcie_port *pp = &pci->pp;
struct device *dev = &pdev->dev;
int ret;
if (IS_ENABLED(CONFIG_PCI_MSI)) {
pp->msi_irq = platform_get_irq_byname(pdev, "msi");
if (pp->msi_irq < 0)
return pp->msi_irq;
}
pp->ops = &imx6_pcie_host_ops;
ret = dw_pcie_host_init(pp);
if (ret) {
dev_err(dev, "failed to initialize host\n");
return ret;
}
return 0;
}
static const struct dw_pcie_ops dw_pcie_ops = { static const struct dw_pcie_ops dw_pcie_ops = {
/* No special ops needed, but pcie-designware still expects this struct */ .start_link = imx6_pcie_start_link,
}; };
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
...@@ -980,7 +952,7 @@ static int imx6_pcie_resume_noirq(struct device *dev) ...@@ -980,7 +952,7 @@ static int imx6_pcie_resume_noirq(struct device *dev)
imx6_pcie_deassert_core_reset(imx6_pcie); imx6_pcie_deassert_core_reset(imx6_pcie);
dw_pcie_setup_rc(pp); dw_pcie_setup_rc(pp);
ret = imx6_pcie_establish_link(imx6_pcie); ret = imx6_pcie_start_link(imx6_pcie->pci);
if (ret < 0) if (ret < 0)
dev_info(dev, "pcie link is down after resume.\n"); dev_info(dev, "pcie link is down after resume.\n");
...@@ -1014,6 +986,7 @@ static int imx6_pcie_probe(struct platform_device *pdev) ...@@ -1014,6 +986,7 @@ static int imx6_pcie_probe(struct platform_device *pdev)
pci->dev = dev; pci->dev = dev;
pci->ops = &dw_pcie_ops; pci->ops = &dw_pcie_ops;
pci->pp.ops = &imx6_pcie_host_ops;
imx6_pcie->pci = pci; imx6_pcie->pci = pci;
imx6_pcie->drvdata = of_device_get_match_data(dev); imx6_pcie->drvdata = of_device_get_match_data(dev);
...@@ -1163,7 +1136,7 @@ static int imx6_pcie_probe(struct platform_device *pdev) ...@@ -1163,7 +1136,7 @@ static int imx6_pcie_probe(struct platform_device *pdev)
if (ret) if (ret)
return ret; return ret;
ret = imx6_add_pcie_port(imx6_pcie, pdev); ret = dw_pcie_host_init(&pci->pp);
if (ret < 0) if (ret < 0)
return ret; return ret;
......
...@@ -121,6 +121,7 @@ struct keystone_pcie { ...@@ -121,6 +121,7 @@ struct keystone_pcie {
int msi_host_irq; int msi_host_irq;
int num_lanes; int num_lanes;
u32 num_viewport;
struct phy **phy; struct phy **phy;
struct device_link **link; struct device_link **link;
struct device_node *msi_intc_np; struct device_node *msi_intc_np;
...@@ -272,14 +273,6 @@ static void ks_pcie_handle_legacy_irq(struct keystone_pcie *ks_pcie, ...@@ -272,14 +273,6 @@ static void ks_pcie_handle_legacy_irq(struct keystone_pcie *ks_pcie,
ks_pcie_app_writel(ks_pcie, IRQ_EOI, offset); ks_pcie_app_writel(ks_pcie, IRQ_EOI, offset);
} }
/*
* Dummy function so that DW core doesn't configure MSI
*/
static int ks_pcie_am654_msi_host_init(struct pcie_port *pp)
{
return 0;
}
static void ks_pcie_enable_error_irq(struct keystone_pcie *ks_pcie) static void ks_pcie_enable_error_irq(struct keystone_pcie *ks_pcie)
{ {
ks_pcie_app_writel(ks_pcie, ERR_IRQ_ENABLE_SET, ERR_IRQ_ALL); ks_pcie_app_writel(ks_pcie, ERR_IRQ_ENABLE_SET, ERR_IRQ_ALL);
...@@ -394,9 +387,9 @@ static void ks_pcie_clear_dbi_mode(struct keystone_pcie *ks_pcie) ...@@ -394,9 +387,9 @@ static void ks_pcie_clear_dbi_mode(struct keystone_pcie *ks_pcie)
static void ks_pcie_setup_rc_app_regs(struct keystone_pcie *ks_pcie) static void ks_pcie_setup_rc_app_regs(struct keystone_pcie *ks_pcie)
{ {
u32 val; u32 val;
u32 num_viewport = ks_pcie->num_viewport;
struct dw_pcie *pci = ks_pcie->pci; struct dw_pcie *pci = ks_pcie->pci;
struct pcie_port *pp = &pci->pp; struct pcie_port *pp = &pci->pp;
u32 num_viewport = pci->num_viewport;
u64 start, end; u64 start, end;
struct resource *mem; struct resource *mem;
int i; int i;
...@@ -519,14 +512,8 @@ static void ks_pcie_stop_link(struct dw_pcie *pci) ...@@ -519,14 +512,8 @@ static void ks_pcie_stop_link(struct dw_pcie *pci)
static int ks_pcie_start_link(struct dw_pcie *pci) static int ks_pcie_start_link(struct dw_pcie *pci)
{ {
struct keystone_pcie *ks_pcie = to_keystone_pcie(pci); struct keystone_pcie *ks_pcie = to_keystone_pcie(pci);
struct device *dev = pci->dev;
u32 val; u32 val;
if (dw_pcie_link_up(pci)) {
dev_dbg(dev, "link is already up\n");
return 0;
}
/* Initiate Link Training */ /* Initiate Link Training */
val = ks_pcie_app_readl(ks_pcie, CMD_STATUS); val = ks_pcie_app_readl(ks_pcie, CMD_STATUS);
ks_pcie_app_writel(ks_pcie, CMD_STATUS, LTSSM_EN_VAL | val); ks_pcie_app_writel(ks_pcie, CMD_STATUS, LTSSM_EN_VAL | val);
...@@ -821,8 +808,6 @@ static int __init ks_pcie_host_init(struct pcie_port *pp) ...@@ -821,8 +808,6 @@ static int __init ks_pcie_host_init(struct pcie_port *pp)
if (ret) if (ret)
return ret; return ret;
dw_pcie_setup_rc(pp);
ks_pcie_stop_link(pci); ks_pcie_stop_link(pci);
ks_pcie_setup_rc_app_regs(ks_pcie); ks_pcie_setup_rc_app_regs(ks_pcie);
writew(PCI_IO_RANGE_TYPE_32 | (PCI_IO_RANGE_TYPE_32 << 8), writew(PCI_IO_RANGE_TYPE_32 | (PCI_IO_RANGE_TYPE_32 << 8),
...@@ -841,9 +826,6 @@ static int __init ks_pcie_host_init(struct pcie_port *pp) ...@@ -841,9 +826,6 @@ static int __init ks_pcie_host_init(struct pcie_port *pp)
"Asynchronous external abort"); "Asynchronous external abort");
#endif #endif
ks_pcie_start_link(pci);
dw_pcie_wait_for_link(pci);
return 0; return 0;
} }
...@@ -854,7 +836,6 @@ static const struct dw_pcie_host_ops ks_pcie_host_ops = { ...@@ -854,7 +836,6 @@ static const struct dw_pcie_host_ops ks_pcie_host_ops = {
static const struct dw_pcie_host_ops ks_pcie_am654_host_ops = { static const struct dw_pcie_host_ops ks_pcie_am654_host_ops = {
.host_init = ks_pcie_host_init, .host_init = ks_pcie_host_init,
.msi_host_init = ks_pcie_am654_msi_host_init,
}; };
static irqreturn_t ks_pcie_err_irq_handler(int irq, void *priv) static irqreturn_t ks_pcie_err_irq_handler(int irq, void *priv)
...@@ -864,23 +845,6 @@ static irqreturn_t ks_pcie_err_irq_handler(int irq, void *priv) ...@@ -864,23 +845,6 @@ static irqreturn_t ks_pcie_err_irq_handler(int irq, void *priv)
return ks_pcie_handle_error_irq(ks_pcie); return ks_pcie_handle_error_irq(ks_pcie);
} }
static int __init ks_pcie_add_pcie_port(struct keystone_pcie *ks_pcie,
struct platform_device *pdev)
{
struct dw_pcie *pci = ks_pcie->pci;
struct pcie_port *pp = &pci->pp;
struct device *dev = &pdev->dev;
int ret;
ret = dw_pcie_host_init(pp);
if (ret) {
dev_err(dev, "failed to initialize host\n");
return ret;
}
return 0;
}
static void ks_pcie_am654_write_dbi2(struct dw_pcie *pci, void __iomem *base, static void ks_pcie_am654_write_dbi2(struct dw_pcie *pci, void __iomem *base,
u32 reg, size_t size, u32 val) u32 reg, size_t size, u32 val)
{ {
...@@ -977,33 +941,6 @@ static const struct dw_pcie_ep_ops ks_pcie_am654_ep_ops = { ...@@ -977,33 +941,6 @@ static const struct dw_pcie_ep_ops ks_pcie_am654_ep_ops = {
.get_features = &ks_pcie_am654_get_features, .get_features = &ks_pcie_am654_get_features,
}; };
static int __init ks_pcie_add_pcie_ep(struct keystone_pcie *ks_pcie,
struct platform_device *pdev)
{
int ret;
struct dw_pcie_ep *ep;
struct resource *res;
struct device *dev = &pdev->dev;
struct dw_pcie *pci = ks_pcie->pci;
ep = &pci->ep;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "addr_space");
if (!res)
return -EINVAL;
ep->phys_base = res->start;
ep->addr_size = resource_size(res);
ret = dw_pcie_ep_init(ep);
if (ret) {
dev_err(dev, "failed to initialize endpoint\n");
return ret;
}
return 0;
}
static void ks_pcie_disable_phy(struct keystone_pcie *ks_pcie) static void ks_pcie_disable_phy(struct keystone_pcie *ks_pcie)
{ {
int num_lanes = ks_pcie->num_lanes; int num_lanes = ks_pcie->num_lanes;
...@@ -1157,6 +1094,7 @@ static int __init ks_pcie_probe(struct platform_device *pdev) ...@@ -1157,6 +1094,7 @@ static int __init ks_pcie_probe(struct platform_device *pdev)
struct resource *res; struct resource *res;
unsigned int version; unsigned int version;
void __iomem *base; void __iomem *base;
u32 num_viewport;
struct phy **phy; struct phy **phy;
u32 num_lanes; u32 num_lanes;
char name[10]; char name[10];
...@@ -1288,6 +1226,12 @@ static int __init ks_pcie_probe(struct platform_device *pdev) ...@@ -1288,6 +1226,12 @@ static int __init ks_pcie_probe(struct platform_device *pdev)
goto err_get_sync; goto err_get_sync;
} }
ret = of_property_read_u32(np, "num-viewport", &num_viewport);
if (ret < 0) {
dev_err(dev, "unable to read *num-viewport* property\n");
goto err_get_sync;
}
/* /*
* "Power Sequencing and Reset Signal Timings" table in * "Power Sequencing and Reset Signal Timings" table in
* PCI EXPRESS CARD ELECTROMECHANICAL SPECIFICATION, REV. 2.0 * PCI EXPRESS CARD ELECTROMECHANICAL SPECIFICATION, REV. 2.0
...@@ -1301,8 +1245,9 @@ static int __init ks_pcie_probe(struct platform_device *pdev) ...@@ -1301,8 +1245,9 @@ static int __init ks_pcie_probe(struct platform_device *pdev)
gpiod_set_value_cansleep(gpiod, 1); gpiod_set_value_cansleep(gpiod, 1);
} }
ks_pcie->num_viewport = num_viewport;
pci->pp.ops = host_ops; pci->pp.ops = host_ops;
ret = ks_pcie_add_pcie_port(ks_pcie, pdev); ret = dw_pcie_host_init(&pci->pp);
if (ret < 0) if (ret < 0)
goto err_get_sync; goto err_get_sync;
break; break;
...@@ -1313,7 +1258,7 @@ static int __init ks_pcie_probe(struct platform_device *pdev) ...@@ -1313,7 +1258,7 @@ static int __init ks_pcie_probe(struct platform_device *pdev)
} }
pci->ep.ops = ep_ops; pci->ep.ops = ep_ops;
ret = ks_pcie_add_pcie_ep(ks_pcie, pdev); ret = dw_pcie_ep_init(&pci->ep);
if (ret < 0) if (ret < 0)
goto err_get_sync; goto err_get_sync;
break; break;
......
...@@ -18,8 +18,6 @@ ...@@ -18,8 +18,6 @@
#include "pcie-designware.h" #include "pcie-designware.h"
#define PCIE_DBI2_OFFSET 0x1000 /* DBI2 base address*/
#define to_ls_pcie_ep(x) dev_get_drvdata((x)->dev) #define to_ls_pcie_ep(x) dev_get_drvdata((x)->dev)
struct ls_pcie_ep_drvdata { struct ls_pcie_ep_drvdata {
...@@ -124,34 +122,6 @@ static const struct of_device_id ls_pcie_ep_of_match[] = { ...@@ -124,34 +122,6 @@ static const struct of_device_id ls_pcie_ep_of_match[] = {
{ }, { },
}; };
static int __init ls_add_pcie_ep(struct ls_pcie_ep *pcie,
struct platform_device *pdev)
{
struct dw_pcie *pci = pcie->pci;
struct device *dev = pci->dev;
struct dw_pcie_ep *ep;
struct resource *res;
int ret;
ep = &pci->ep;
ep->ops = pcie->drvdata->ops;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "addr_space");
if (!res)
return -EINVAL;
ep->phys_base = res->start;
ep->addr_size = resource_size(res);
ret = dw_pcie_ep_init(ep);
if (ret) {
dev_err(dev, "failed to initialize endpoint\n");
return ret;
}
return 0;
}
static int __init ls_pcie_ep_probe(struct platform_device *pdev) static int __init ls_pcie_ep_probe(struct platform_device *pdev)
{ {
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
...@@ -159,7 +129,6 @@ static int __init ls_pcie_ep_probe(struct platform_device *pdev) ...@@ -159,7 +129,6 @@ static int __init ls_pcie_ep_probe(struct platform_device *pdev)
struct ls_pcie_ep *pcie; struct ls_pcie_ep *pcie;
struct pci_epc_features *ls_epc; struct pci_epc_features *ls_epc;
struct resource *dbi_base; struct resource *dbi_base;
int ret;
pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL); pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL);
if (!pcie) if (!pcie)
...@@ -188,13 +157,11 @@ static int __init ls_pcie_ep_probe(struct platform_device *pdev) ...@@ -188,13 +157,11 @@ static int __init ls_pcie_ep_probe(struct platform_device *pdev)
if (IS_ERR(pci->dbi_base)) if (IS_ERR(pci->dbi_base))
return PTR_ERR(pci->dbi_base); return PTR_ERR(pci->dbi_base);
pci->dbi_base2 = pci->dbi_base + PCIE_DBI2_OFFSET; pci->ep.ops = &ls_pcie_ep_ops;
platform_set_drvdata(pdev, pcie); platform_set_drvdata(pdev, pcie);
ret = ls_add_pcie_ep(pcie, pdev); return dw_pcie_ep_init(&pci->ep);
return ret;
} }
static struct platform_driver ls_pcie_ep_driver = { static struct platform_driver ls_pcie_ep_driver = {
......
...@@ -83,14 +83,6 @@ static void ls_pcie_drop_msg_tlp(struct ls_pcie *pcie) ...@@ -83,14 +83,6 @@ static void ls_pcie_drop_msg_tlp(struct ls_pcie *pcie)
iowrite32(val, pci->dbi_base + PCIE_STRFMR1); iowrite32(val, pci->dbi_base + PCIE_STRFMR1);
} }
static void ls_pcie_disable_outbound_atus(struct ls_pcie *pcie)
{
int i;
for (i = 0; i < PCIE_IATU_NUM; i++)
dw_pcie_disable_atu(pcie->pci, i, DW_PCIE_REGION_OUTBOUND);
}
static int ls1021_pcie_link_up(struct dw_pcie *pci) static int ls1021_pcie_link_up(struct dw_pcie *pci)
{ {
u32 state; u32 state;
...@@ -136,12 +128,6 @@ static int ls_pcie_host_init(struct pcie_port *pp) ...@@ -136,12 +128,6 @@ static int ls_pcie_host_init(struct pcie_port *pp)
struct dw_pcie *pci = to_dw_pcie_from_pp(pp); struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
struct ls_pcie *pcie = to_ls_pcie(pci); struct ls_pcie *pcie = to_ls_pcie(pci);
/*
* Disable outbound windows configured by the bootloader to avoid
* one transaction hitting multiple outbound windows.
* dw_pcie_setup_rc() will reconfigure the outbound windows.
*/
ls_pcie_disable_outbound_atus(pcie);
ls_pcie_fix_error_response(pcie); ls_pcie_fix_error_response(pcie);
dw_pcie_dbi_ro_wr_en(pci); dw_pcie_dbi_ro_wr_en(pci);
...@@ -150,8 +136,6 @@ static int ls_pcie_host_init(struct pcie_port *pp) ...@@ -150,8 +136,6 @@ static int ls_pcie_host_init(struct pcie_port *pp)
ls_pcie_drop_msg_tlp(pcie); ls_pcie_drop_msg_tlp(pcie);
dw_pcie_setup_rc(pp);
return 0; return 0;
} }
...@@ -182,37 +166,12 @@ static int ls1021_pcie_host_init(struct pcie_port *pp) ...@@ -182,37 +166,12 @@ static int ls1021_pcie_host_init(struct pcie_port *pp)
return ls_pcie_host_init(pp); return ls_pcie_host_init(pp);
} }
static int ls_pcie_msi_host_init(struct pcie_port *pp)
{
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
struct device *dev = pci->dev;
struct device_node *np = dev->of_node;
struct device_node *msi_node;
/*
* The MSI domain is set by the generic of_msi_configure(). This
* .msi_host_init() function keeps us from doing the default MSI
* domain setup in dw_pcie_host_init() and also enforces the
* requirement that "msi-parent" exists.
*/
msi_node = of_parse_phandle(np, "msi-parent", 0);
if (!msi_node) {
dev_err(dev, "failed to find msi-parent\n");
return -EINVAL;
}
of_node_put(msi_node);
return 0;
}
static const struct dw_pcie_host_ops ls1021_pcie_host_ops = { static const struct dw_pcie_host_ops ls1021_pcie_host_ops = {
.host_init = ls1021_pcie_host_init, .host_init = ls1021_pcie_host_init,
.msi_host_init = ls_pcie_msi_host_init,
}; };
static const struct dw_pcie_host_ops ls_pcie_host_ops = { static const struct dw_pcie_host_ops ls_pcie_host_ops = {
.host_init = ls_pcie_host_init, .host_init = ls_pcie_host_init,
.msi_host_init = ls_pcie_msi_host_init,
}; };
static const struct dw_pcie_ops dw_ls1021_pcie_ops = { static const struct dw_pcie_ops dw_ls1021_pcie_ops = {
...@@ -273,31 +232,12 @@ static const struct of_device_id ls_pcie_of_match[] = { ...@@ -273,31 +232,12 @@ static const struct of_device_id ls_pcie_of_match[] = {
{ }, { },
}; };
static int __init ls_add_pcie_port(struct ls_pcie *pcie)
{
struct dw_pcie *pci = pcie->pci;
struct pcie_port *pp = &pci->pp;
struct device *dev = pci->dev;
int ret;
pp->ops = pcie->drvdata->ops;
ret = dw_pcie_host_init(pp);
if (ret) {
dev_err(dev, "failed to initialize host\n");
return ret;
}
return 0;
}
static int __init ls_pcie_probe(struct platform_device *pdev) static int __init ls_pcie_probe(struct platform_device *pdev)
{ {
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct dw_pcie *pci; struct dw_pcie *pci;
struct ls_pcie *pcie; struct ls_pcie *pcie;
struct resource *dbi_base; struct resource *dbi_base;
int ret;
pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL); pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL);
if (!pcie) if (!pcie)
...@@ -311,6 +251,7 @@ static int __init ls_pcie_probe(struct platform_device *pdev) ...@@ -311,6 +251,7 @@ static int __init ls_pcie_probe(struct platform_device *pdev)
pci->dev = dev; pci->dev = dev;
pci->ops = pcie->drvdata->dw_pcie_ops; pci->ops = pcie->drvdata->dw_pcie_ops;
pci->pp.ops = pcie->drvdata->ops;
pcie->pci = pci; pcie->pci = pci;
...@@ -326,11 +267,7 @@ static int __init ls_pcie_probe(struct platform_device *pdev) ...@@ -326,11 +267,7 @@ static int __init ls_pcie_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, pcie); platform_set_drvdata(pdev, pcie);
ret = ls_add_pcie_port(pcie); return dw_pcie_host_init(&pci->pp);
if (ret < 0)
return ret;
return 0;
} }
static struct platform_driver ls_pcie_driver = { static struct platform_driver ls_pcie_driver = {
......
...@@ -231,7 +231,7 @@ static void meson_pcie_assert_reset(struct meson_pcie *mp) ...@@ -231,7 +231,7 @@ static void meson_pcie_assert_reset(struct meson_pcie *mp)
gpiod_set_value_cansleep(mp->reset_gpio, 0); gpiod_set_value_cansleep(mp->reset_gpio, 0);
} }
static void meson_pcie_init_dw(struct meson_pcie *mp) static void meson_pcie_ltssm_enable(struct meson_pcie *mp)
{ {
u32 val; u32 val;
...@@ -289,20 +289,14 @@ static void meson_set_max_rd_req_size(struct meson_pcie *mp, int size) ...@@ -289,20 +289,14 @@ static void meson_set_max_rd_req_size(struct meson_pcie *mp, int size)
dw_pcie_writel_dbi(pci, offset + PCI_EXP_DEVCTL, val); dw_pcie_writel_dbi(pci, offset + PCI_EXP_DEVCTL, val);
} }
static int meson_pcie_establish_link(struct meson_pcie *mp) static int meson_pcie_start_link(struct dw_pcie *pci)
{ {
struct dw_pcie *pci = &mp->pci; struct meson_pcie *mp = to_meson_pcie(pci);
struct pcie_port *pp = &pci->pp;
meson_pcie_init_dw(mp);
meson_set_max_payload(mp, MAX_PAYLOAD_SIZE);
meson_set_max_rd_req_size(mp, MAX_READ_REQ_SIZE);
dw_pcie_setup_rc(pp);
meson_pcie_ltssm_enable(mp);
meson_pcie_assert_reset(mp); meson_pcie_assert_reset(mp);
return dw_pcie_wait_for_link(pci); return 0;
} }
static int meson_pcie_rd_own_conf(struct pci_bus *bus, u32 devfn, static int meson_pcie_rd_own_conf(struct pci_bus *bus, u32 devfn,
...@@ -380,15 +374,11 @@ static int meson_pcie_host_init(struct pcie_port *pp) ...@@ -380,15 +374,11 @@ static int meson_pcie_host_init(struct pcie_port *pp)
{ {
struct dw_pcie *pci = to_dw_pcie_from_pp(pp); struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
struct meson_pcie *mp = to_meson_pcie(pci); struct meson_pcie *mp = to_meson_pcie(pci);
int ret;
pp->bridge->ops = &meson_pci_ops; pp->bridge->ops = &meson_pci_ops;
ret = meson_pcie_establish_link(mp); meson_set_max_payload(mp, MAX_PAYLOAD_SIZE);
if (ret) meson_set_max_rd_req_size(mp, MAX_READ_REQ_SIZE);
return ret;
dw_pcie_msi_init(pp);
return 0; return 0;
} }
...@@ -397,33 +387,9 @@ static const struct dw_pcie_host_ops meson_pcie_host_ops = { ...@@ -397,33 +387,9 @@ static const struct dw_pcie_host_ops meson_pcie_host_ops = {
.host_init = meson_pcie_host_init, .host_init = meson_pcie_host_init,
}; };
static int meson_add_pcie_port(struct meson_pcie *mp,
struct platform_device *pdev)
{
struct dw_pcie *pci = &mp->pci;
struct pcie_port *pp = &pci->pp;
struct device *dev = &pdev->dev;
int ret;
if (IS_ENABLED(CONFIG_PCI_MSI)) {
pp->msi_irq = platform_get_irq(pdev, 0);
if (pp->msi_irq < 0)
return pp->msi_irq;
}
pp->ops = &meson_pcie_host_ops;
ret = dw_pcie_host_init(pp);
if (ret) {
dev_err(dev, "failed to initialize host\n");
return ret;
}
return 0;
}
static const struct dw_pcie_ops dw_pcie_ops = { static const struct dw_pcie_ops dw_pcie_ops = {
.link_up = meson_pcie_link_up, .link_up = meson_pcie_link_up,
.start_link = meson_pcie_start_link,
}; };
static int meson_pcie_probe(struct platform_device *pdev) static int meson_pcie_probe(struct platform_device *pdev)
...@@ -440,6 +406,7 @@ static int meson_pcie_probe(struct platform_device *pdev) ...@@ -440,6 +406,7 @@ static int meson_pcie_probe(struct platform_device *pdev)
pci = &mp->pci; pci = &mp->pci;
pci->dev = dev; pci->dev = dev;
pci->ops = &dw_pcie_ops; pci->ops = &dw_pcie_ops;
pci->pp.ops = &meson_pcie_host_ops;
pci->num_lanes = 1; pci->num_lanes = 1;
mp->phy = devm_phy_get(dev, "pcie"); mp->phy = devm_phy_get(dev, "pcie");
...@@ -486,7 +453,7 @@ static int meson_pcie_probe(struct platform_device *pdev) ...@@ -486,7 +453,7 @@ static int meson_pcie_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, mp); platform_set_drvdata(pdev, mp);
ret = meson_add_pcie_port(mp, pdev); ret = dw_pcie_host_init(&pci->pp);
if (ret < 0) { if (ret < 0) {
dev_err(dev, "Add PCIe port failed, %d\n", ret); dev_err(dev, "Add PCIe port failed, %d\n", ret);
goto err_phy; goto err_phy;
......
...@@ -76,7 +76,6 @@ static int al_pcie_init(struct pci_config_window *cfg) ...@@ -76,7 +76,6 @@ static int al_pcie_init(struct pci_config_window *cfg)
} }
const struct pci_ecam_ops al_pcie_ops = { const struct pci_ecam_ops al_pcie_ops = {
.bus_shift = 20,
.init = al_pcie_init, .init = al_pcie_init,
.pci_ops = { .pci_ops = {
.map_bus = al_pcie_map_bus, .map_bus = al_pcie_map_bus,
...@@ -138,8 +137,6 @@ struct al_pcie { ...@@ -138,8 +137,6 @@ struct al_pcie {
struct al_pcie_target_bus_cfg target_bus_cfg; struct al_pcie_target_bus_cfg target_bus_cfg;
}; };
#define PCIE_ECAM_DEVFN(x) (((x) & 0xff) << 12)
#define to_al_pcie(x) dev_get_drvdata((x)->dev) #define to_al_pcie(x) dev_get_drvdata((x)->dev)
static inline u32 al_pcie_controller_readl(struct al_pcie *pcie, u32 offset) static inline u32 al_pcie_controller_readl(struct al_pcie *pcie, u32 offset)
...@@ -226,11 +223,6 @@ static void __iomem *al_pcie_conf_addr_map_bus(struct pci_bus *bus, ...@@ -226,11 +223,6 @@ static void __iomem *al_pcie_conf_addr_map_bus(struct pci_bus *bus,
struct al_pcie_target_bus_cfg *target_bus_cfg = &pcie->target_bus_cfg; struct al_pcie_target_bus_cfg *target_bus_cfg = &pcie->target_bus_cfg;
unsigned int busnr_ecam = busnr & target_bus_cfg->ecam_mask; unsigned int busnr_ecam = busnr & target_bus_cfg->ecam_mask;
unsigned int busnr_reg = busnr & target_bus_cfg->reg_mask; unsigned int busnr_reg = busnr & target_bus_cfg->reg_mask;
void __iomem *pci_base_addr;
pci_base_addr = (void __iomem *)((uintptr_t)pp->va_cfg0_base +
(busnr_ecam << 20) +
PCIE_ECAM_DEVFN(devfn));
if (busnr_reg != target_bus_cfg->reg_val) { if (busnr_reg != target_bus_cfg->reg_val) {
dev_dbg(pcie->pci->dev, "Changing target bus busnum val from 0x%x to 0x%x\n", dev_dbg(pcie->pci->dev, "Changing target bus busnum val from 0x%x to 0x%x\n",
...@@ -241,7 +233,7 @@ static void __iomem *al_pcie_conf_addr_map_bus(struct pci_bus *bus, ...@@ -241,7 +233,7 @@ static void __iomem *al_pcie_conf_addr_map_bus(struct pci_bus *bus,
target_bus_cfg->reg_mask); target_bus_cfg->reg_mask);
} }
return pci_base_addr + where; return pp->va_cfg0_base + PCIE_ECAM_OFFSET(busnr_ecam, devfn, where);
} }
static struct pci_ops al_child_pci_ops = { static struct pci_ops al_child_pci_ops = {
...@@ -264,7 +256,7 @@ static void al_pcie_config_prepare(struct al_pcie *pcie) ...@@ -264,7 +256,7 @@ static void al_pcie_config_prepare(struct al_pcie *pcie)
target_bus_cfg = &pcie->target_bus_cfg; target_bus_cfg = &pcie->target_bus_cfg;
ecam_bus_mask = (pcie->ecam_size >> 20) - 1; ecam_bus_mask = (pcie->ecam_size >> PCIE_ECAM_BUS_SHIFT) - 1;
if (ecam_bus_mask > 255) { if (ecam_bus_mask > 255) {
dev_warn(pcie->dev, "ECAM window size is larger than 256MB. Cutting off at 256\n"); dev_warn(pcie->dev, "ECAM window size is larger than 256MB. Cutting off at 256\n");
ecam_bus_mask = 255; ecam_bus_mask = 255;
...@@ -322,23 +314,6 @@ static const struct dw_pcie_host_ops al_pcie_host_ops = { ...@@ -322,23 +314,6 @@ static const struct dw_pcie_host_ops al_pcie_host_ops = {
.host_init = al_pcie_host_init, .host_init = al_pcie_host_init,
}; };
static int al_add_pcie_port(struct pcie_port *pp,
struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
int ret;
pp->ops = &al_pcie_host_ops;
ret = dw_pcie_host_init(pp);
if (ret) {
dev_err(dev, "failed to initialize host\n");
return ret;
}
return 0;
}
static const struct dw_pcie_ops dw_pcie_ops = { static const struct dw_pcie_ops dw_pcie_ops = {
}; };
...@@ -347,7 +322,6 @@ static int al_pcie_probe(struct platform_device *pdev) ...@@ -347,7 +322,6 @@ static int al_pcie_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct resource *controller_res; struct resource *controller_res;
struct resource *ecam_res; struct resource *ecam_res;
struct resource *dbi_res;
struct al_pcie *al_pcie; struct al_pcie *al_pcie;
struct dw_pcie *pci; struct dw_pcie *pci;
...@@ -361,15 +335,11 @@ static int al_pcie_probe(struct platform_device *pdev) ...@@ -361,15 +335,11 @@ static int al_pcie_probe(struct platform_device *pdev)
pci->dev = dev; pci->dev = dev;
pci->ops = &dw_pcie_ops; pci->ops = &dw_pcie_ops;
pci->pp.ops = &al_pcie_host_ops;
al_pcie->pci = pci; al_pcie->pci = pci;
al_pcie->dev = dev; al_pcie->dev = dev;
dbi_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi");
pci->dbi_base = devm_pci_remap_cfg_resource(dev, dbi_res);
if (IS_ERR(pci->dbi_base))
return PTR_ERR(pci->dbi_base);
ecam_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "config"); ecam_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "config");
if (!ecam_res) { if (!ecam_res) {
dev_err(dev, "couldn't find 'config' reg in DT\n"); dev_err(dev, "couldn't find 'config' reg in DT\n");
...@@ -386,12 +356,11 @@ static int al_pcie_probe(struct platform_device *pdev) ...@@ -386,12 +356,11 @@ static int al_pcie_probe(struct platform_device *pdev)
return PTR_ERR(al_pcie->controller_base); return PTR_ERR(al_pcie->controller_base);
} }
dev_dbg(dev, "From DT: dbi_base: %pR, controller_base: %pR\n", dev_dbg(dev, "From DT: controller_base: %pR\n", controller_res);
dbi_res, controller_res);
platform_set_drvdata(pdev, al_pcie); platform_set_drvdata(pdev, al_pcie);
return al_add_pcie_port(&pci->pp, pdev); return dw_pcie_host_init(&pci->pp);
} }
static const struct of_device_id al_pcie_of_match[] = { static const struct of_device_id al_pcie_of_match[] = {
......
...@@ -154,10 +154,22 @@ static int armada8k_pcie_link_up(struct dw_pcie *pci) ...@@ -154,10 +154,22 @@ static int armada8k_pcie_link_up(struct dw_pcie *pci)
return 0; return 0;
} }
static void armada8k_pcie_establish_link(struct armada8k_pcie *pcie) static int armada8k_pcie_start_link(struct dw_pcie *pci)
{
u32 reg;
/* Start LTSSM */
reg = dw_pcie_readl_dbi(pci, PCIE_GLOBAL_CONTROL_REG);
reg |= PCIE_APP_LTSSM_EN;
dw_pcie_writel_dbi(pci, PCIE_GLOBAL_CONTROL_REG, reg);
return 0;
}
static int armada8k_pcie_host_init(struct pcie_port *pp)
{ {
struct dw_pcie *pci = pcie->pci;
u32 reg; u32 reg;
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
if (!dw_pcie_link_up(pci)) { if (!dw_pcie_link_up(pci)) {
/* Disable LTSSM state machine to enable configuration */ /* Disable LTSSM state machine to enable configuration */
...@@ -193,26 +205,6 @@ static void armada8k_pcie_establish_link(struct armada8k_pcie *pcie) ...@@ -193,26 +205,6 @@ static void armada8k_pcie_establish_link(struct armada8k_pcie *pcie)
PCIE_INT_C_ASSERT_MASK | PCIE_INT_D_ASSERT_MASK; PCIE_INT_C_ASSERT_MASK | PCIE_INT_D_ASSERT_MASK;
dw_pcie_writel_dbi(pci, PCIE_GLOBAL_INT_MASK1_REG, reg); dw_pcie_writel_dbi(pci, PCIE_GLOBAL_INT_MASK1_REG, reg);
if (!dw_pcie_link_up(pci)) {
/* Configuration done. Start LTSSM */
reg = dw_pcie_readl_dbi(pci, PCIE_GLOBAL_CONTROL_REG);
reg |= PCIE_APP_LTSSM_EN;
dw_pcie_writel_dbi(pci, PCIE_GLOBAL_CONTROL_REG, reg);
}
/* Wait until the link becomes active again */
if (dw_pcie_wait_for_link(pci))
dev_err(pci->dev, "Link not up after reconfiguration\n");
}
static int armada8k_pcie_host_init(struct pcie_port *pp)
{
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
struct armada8k_pcie *pcie = to_armada8k_pcie(pci);
dw_pcie_setup_rc(pp);
armada8k_pcie_establish_link(pcie);
return 0; return 0;
} }
...@@ -269,6 +261,7 @@ static int armada8k_add_pcie_port(struct armada8k_pcie *pcie, ...@@ -269,6 +261,7 @@ static int armada8k_add_pcie_port(struct armada8k_pcie *pcie,
static const struct dw_pcie_ops dw_pcie_ops = { static const struct dw_pcie_ops dw_pcie_ops = {
.link_up = armada8k_pcie_link_up, .link_up = armada8k_pcie_link_up,
.start_link = armada8k_pcie_start_link,
}; };
static int armada8k_pcie_probe(struct platform_device *pdev) static int armada8k_pcie_probe(struct platform_device *pdev)
......
...@@ -328,10 +328,6 @@ static int artpec6_pcie_host_init(struct pcie_port *pp) ...@@ -328,10 +328,6 @@ static int artpec6_pcie_host_init(struct pcie_port *pp)
artpec6_pcie_init_phy(artpec6_pcie); artpec6_pcie_init_phy(artpec6_pcie);
artpec6_pcie_deassert_core_reset(artpec6_pcie); artpec6_pcie_deassert_core_reset(artpec6_pcie);
artpec6_pcie_wait_for_phy(artpec6_pcie); artpec6_pcie_wait_for_phy(artpec6_pcie);
dw_pcie_setup_rc(pp);
artpec6_pcie_establish_link(pci);
dw_pcie_wait_for_link(pci);
dw_pcie_msi_init(pp);
return 0; return 0;
} }
...@@ -340,31 +336,6 @@ static const struct dw_pcie_host_ops artpec6_pcie_host_ops = { ...@@ -340,31 +336,6 @@ static const struct dw_pcie_host_ops artpec6_pcie_host_ops = {
.host_init = artpec6_pcie_host_init, .host_init = artpec6_pcie_host_init,
}; };
static int artpec6_add_pcie_port(struct artpec6_pcie *artpec6_pcie,
struct platform_device *pdev)
{
struct dw_pcie *pci = artpec6_pcie->pci;
struct pcie_port *pp = &pci->pp;
struct device *dev = pci->dev;
int ret;
if (IS_ENABLED(CONFIG_PCI_MSI)) {
pp->msi_irq = platform_get_irq_byname(pdev, "msi");
if (pp->msi_irq < 0)
return pp->msi_irq;
}
pp->ops = &artpec6_pcie_host_ops;
ret = dw_pcie_host_init(pp);
if (ret) {
dev_err(dev, "failed to initialize host\n");
return ret;
}
return 0;
}
static void artpec6_pcie_ep_init(struct dw_pcie_ep *ep) static void artpec6_pcie_ep_init(struct dw_pcie_ep *ep)
{ {
struct dw_pcie *pci = to_dw_pcie_from_ep(ep); struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
...@@ -403,38 +374,6 @@ static const struct dw_pcie_ep_ops pcie_ep_ops = { ...@@ -403,38 +374,6 @@ static const struct dw_pcie_ep_ops pcie_ep_ops = {
.raise_irq = artpec6_pcie_raise_irq, .raise_irq = artpec6_pcie_raise_irq,
}; };
static int artpec6_add_pcie_ep(struct artpec6_pcie *artpec6_pcie,
struct platform_device *pdev)
{
int ret;
struct dw_pcie_ep *ep;
struct resource *res;
struct device *dev = &pdev->dev;
struct dw_pcie *pci = artpec6_pcie->pci;
ep = &pci->ep;
ep->ops = &pcie_ep_ops;
pci->dbi_base2 = devm_platform_ioremap_resource_byname(pdev, "dbi2");
if (IS_ERR(pci->dbi_base2))
return PTR_ERR(pci->dbi_base2);
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "addr_space");
if (!res)
return -EINVAL;
ep->phys_base = res->start;
ep->addr_size = resource_size(res);
ret = dw_pcie_ep_init(ep);
if (ret) {
dev_err(dev, "failed to initialize endpoint\n");
return ret;
}
return 0;
}
static int artpec6_pcie_probe(struct platform_device *pdev) static int artpec6_pcie_probe(struct platform_device *pdev)
{ {
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
...@@ -469,10 +408,6 @@ static int artpec6_pcie_probe(struct platform_device *pdev) ...@@ -469,10 +408,6 @@ static int artpec6_pcie_probe(struct platform_device *pdev)
artpec6_pcie->variant = variant; artpec6_pcie->variant = variant;
artpec6_pcie->mode = mode; artpec6_pcie->mode = mode;
pci->dbi_base = devm_platform_ioremap_resource_byname(pdev, "dbi");
if (IS_ERR(pci->dbi_base))
return PTR_ERR(pci->dbi_base);
artpec6_pcie->phy_base = artpec6_pcie->phy_base =
devm_platform_ioremap_resource_byname(pdev, "phy"); devm_platform_ioremap_resource_byname(pdev, "phy");
if (IS_ERR(artpec6_pcie->phy_base)) if (IS_ERR(artpec6_pcie->phy_base))
...@@ -491,7 +426,9 @@ static int artpec6_pcie_probe(struct platform_device *pdev) ...@@ -491,7 +426,9 @@ static int artpec6_pcie_probe(struct platform_device *pdev)
if (!IS_ENABLED(CONFIG_PCIE_ARTPEC6_HOST)) if (!IS_ENABLED(CONFIG_PCIE_ARTPEC6_HOST))
return -ENODEV; return -ENODEV;
ret = artpec6_add_pcie_port(artpec6_pcie, pdev); pci->pp.ops = &artpec6_pcie_host_ops;
ret = dw_pcie_host_init(&pci->pp);
if (ret < 0) if (ret < 0)
return ret; return ret;
break; break;
...@@ -504,9 +441,10 @@ static int artpec6_pcie_probe(struct platform_device *pdev) ...@@ -504,9 +441,10 @@ static int artpec6_pcie_probe(struct platform_device *pdev)
val = artpec6_pcie_readl(artpec6_pcie, PCIECFG); val = artpec6_pcie_readl(artpec6_pcie, PCIECFG);
val &= ~PCIECFG_DEVICE_TYPE_MASK; val &= ~PCIECFG_DEVICE_TYPE_MASK;
artpec6_pcie_writel(artpec6_pcie, PCIECFG, val); artpec6_pcie_writel(artpec6_pcie, PCIECFG, val);
ret = artpec6_add_pcie_ep(artpec6_pcie, pdev);
if (ret < 0) pci->ep.ops = &pcie_ep_ops;
return ret;
return dw_pcie_ep_init(&pci->ep);
break; break;
} }
default: default:
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
*/ */
#include <linux/of.h> #include <linux/of.h>
#include <linux/platform_device.h>
#include "pcie-designware.h" #include "pcie-designware.h"
#include <linux/pci-epc.h> #include <linux/pci-epc.h>
...@@ -160,8 +161,8 @@ static int dw_pcie_ep_inbound_atu(struct dw_pcie_ep *ep, u8 func_no, ...@@ -160,8 +161,8 @@ static int dw_pcie_ep_inbound_atu(struct dw_pcie_ep *ep, u8 func_no,
u32 free_win; u32 free_win;
struct dw_pcie *pci = to_dw_pcie_from_ep(ep); struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
free_win = find_first_zero_bit(ep->ib_window_map, ep->num_ib_windows); free_win = find_first_zero_bit(ep->ib_window_map, pci->num_ib_windows);
if (free_win >= ep->num_ib_windows) { if (free_win >= pci->num_ib_windows) {
dev_err(pci->dev, "No free inbound window\n"); dev_err(pci->dev, "No free inbound window\n");
return -EINVAL; return -EINVAL;
} }
...@@ -186,8 +187,8 @@ static int dw_pcie_ep_outbound_atu(struct dw_pcie_ep *ep, u8 func_no, ...@@ -186,8 +187,8 @@ static int dw_pcie_ep_outbound_atu(struct dw_pcie_ep *ep, u8 func_no,
u32 free_win; u32 free_win;
struct dw_pcie *pci = to_dw_pcie_from_ep(ep); struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
free_win = find_first_zero_bit(ep->ob_window_map, ep->num_ob_windows); free_win = find_first_zero_bit(ep->ob_window_map, pci->num_ob_windows);
if (free_win >= ep->num_ob_windows) { if (free_win >= pci->num_ob_windows) {
dev_err(pci->dev, "No free outbound window\n"); dev_err(pci->dev, "No free outbound window\n");
return -EINVAL; return -EINVAL;
} }
...@@ -263,8 +264,9 @@ static int dw_pcie_find_index(struct dw_pcie_ep *ep, phys_addr_t addr, ...@@ -263,8 +264,9 @@ static int dw_pcie_find_index(struct dw_pcie_ep *ep, phys_addr_t addr,
u32 *atu_index) u32 *atu_index)
{ {
u32 index; u32 index;
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
for (index = 0; index < ep->num_ob_windows; index++) { for (index = 0; index < pci->num_ob_windows; index++) {
if (ep->outbound_addr[index] != addr) if (ep->outbound_addr[index] != addr)
continue; continue;
*atu_index = index; *atu_index = index;
...@@ -676,55 +678,57 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep) ...@@ -676,55 +678,57 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep)
int ret; int ret;
void *addr; void *addr;
u8 func_no; u8 func_no;
struct resource *res;
struct pci_epc *epc; struct pci_epc *epc;
struct dw_pcie *pci = to_dw_pcie_from_ep(ep); struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
struct device *dev = pci->dev; struct device *dev = pci->dev;
struct platform_device *pdev = to_platform_device(dev);
struct device_node *np = dev->of_node; struct device_node *np = dev->of_node;
const struct pci_epc_features *epc_features; const struct pci_epc_features *epc_features;
struct dw_pcie_ep_func *ep_func; struct dw_pcie_ep_func *ep_func;
INIT_LIST_HEAD(&ep->func_list); INIT_LIST_HEAD(&ep->func_list);
if (!pci->dbi_base || !pci->dbi_base2) { if (!pci->dbi_base) {
dev_err(dev, "dbi_base/dbi_base2 is not populated\n"); res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi");
return -EINVAL; pci->dbi_base = devm_pci_remap_cfg_resource(dev, res);
if (IS_ERR(pci->dbi_base))
return PTR_ERR(pci->dbi_base);
} }
ret = of_property_read_u32(np, "num-ib-windows", &ep->num_ib_windows); if (!pci->dbi_base2) {
if (ret < 0) { res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi2");
dev_err(dev, "Unable to read *num-ib-windows* property\n"); if (!res)
return ret; pci->dbi_base2 = pci->dbi_base + SZ_4K;
} else {
if (ep->num_ib_windows > MAX_IATU_IN) { pci->dbi_base2 = devm_pci_remap_cfg_resource(dev, res);
dev_err(dev, "Invalid *num-ib-windows*\n"); if (IS_ERR(pci->dbi_base2))
return -EINVAL; return PTR_ERR(pci->dbi_base2);
}
} }
ret = of_property_read_u32(np, "num-ob-windows", &ep->num_ob_windows); res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "addr_space");
if (ret < 0) { if (!res)
dev_err(dev, "Unable to read *num-ob-windows* property\n");
return ret;
}
if (ep->num_ob_windows > MAX_IATU_OUT) {
dev_err(dev, "Invalid *num-ob-windows*\n");
return -EINVAL; return -EINVAL;
}
ep->phys_base = res->start;
ep->addr_size = resource_size(res);
ep->ib_window_map = devm_kcalloc(dev, ep->ib_window_map = devm_kcalloc(dev,
BITS_TO_LONGS(ep->num_ib_windows), BITS_TO_LONGS(pci->num_ib_windows),
sizeof(long), sizeof(long),
GFP_KERNEL); GFP_KERNEL);
if (!ep->ib_window_map) if (!ep->ib_window_map)
return -ENOMEM; return -ENOMEM;
ep->ob_window_map = devm_kcalloc(dev, ep->ob_window_map = devm_kcalloc(dev,
BITS_TO_LONGS(ep->num_ob_windows), BITS_TO_LONGS(pci->num_ob_windows),
sizeof(long), sizeof(long),
GFP_KERNEL); GFP_KERNEL);
if (!ep->ob_window_map) if (!ep->ob_window_map)
return -ENOMEM; return -ENOMEM;
addr = devm_kcalloc(dev, ep->num_ob_windows, sizeof(phys_addr_t), addr = devm_kcalloc(dev, pci->num_ob_windows, sizeof(phys_addr_t),
GFP_KERNEL); GFP_KERNEL);
if (!addr) if (!addr)
return -ENOMEM; return -ENOMEM;
......
...@@ -256,7 +256,7 @@ int dw_pcie_allocate_domains(struct pcie_port *pp) ...@@ -256,7 +256,7 @@ int dw_pcie_allocate_domains(struct pcie_port *pp)
return 0; return 0;
} }
void dw_pcie_free_msi(struct pcie_port *pp) static void dw_pcie_free_msi(struct pcie_port *pp)
{ {
if (pp->msi_irq) { if (pp->msi_irq) {
irq_set_chained_handler(pp->msi_irq, NULL); irq_set_chained_handler(pp->msi_irq, NULL);
...@@ -275,19 +275,18 @@ void dw_pcie_free_msi(struct pcie_port *pp) ...@@ -275,19 +275,18 @@ void dw_pcie_free_msi(struct pcie_port *pp)
} }
} }
void dw_pcie_msi_init(struct pcie_port *pp) static void dw_pcie_msi_init(struct pcie_port *pp)
{ {
struct dw_pcie *pci = to_dw_pcie_from_pp(pp); struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
u64 msi_target = (u64)pp->msi_data; u64 msi_target = (u64)pp->msi_data;
if (!IS_ENABLED(CONFIG_PCI_MSI)) if (!pci_msi_enabled() || !pp->has_msi_ctrl)
return; return;
/* Program the msi_data */ /* Program the msi_data */
dw_pcie_writel_dbi(pci, PCIE_MSI_ADDR_LO, lower_32_bits(msi_target)); dw_pcie_writel_dbi(pci, PCIE_MSI_ADDR_LO, lower_32_bits(msi_target));
dw_pcie_writel_dbi(pci, PCIE_MSI_ADDR_HI, upper_32_bits(msi_target)); dw_pcie_writel_dbi(pci, PCIE_MSI_ADDR_HI, upper_32_bits(msi_target));
} }
EXPORT_SYMBOL_GPL(dw_pcie_msi_init);
int dw_pcie_host_init(struct pcie_port *pp) int dw_pcie_host_init(struct pcie_port *pp)
{ {
...@@ -310,6 +309,13 @@ int dw_pcie_host_init(struct pcie_port *pp) ...@@ -310,6 +309,13 @@ int dw_pcie_host_init(struct pcie_port *pp)
dev_err(dev, "Missing *config* reg space\n"); dev_err(dev, "Missing *config* reg space\n");
} }
if (!pci->dbi_base) {
struct resource *dbi_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi");
pci->dbi_base = devm_pci_remap_cfg_resource(dev, dbi_res);
if (IS_ERR(pci->dbi_base))
return PTR_ERR(pci->dbi_base);
}
bridge = devm_pci_alloc_host_bridge(dev, 0); bridge = devm_pci_alloc_host_bridge(dev, 0);
if (!bridge) if (!bridge)
return -ENOMEM; return -ENOMEM;
...@@ -350,44 +356,54 @@ int dw_pcie_host_init(struct pcie_port *pp) ...@@ -350,44 +356,54 @@ int dw_pcie_host_init(struct pcie_port *pp)
} }
} }
ret = of_property_read_u32(np, "num-viewport", &pci->num_viewport);
if (ret)
pci->num_viewport = 2;
if (pci->link_gen < 1) if (pci->link_gen < 1)
pci->link_gen = of_pci_get_max_link_speed(np); pci->link_gen = of_pci_get_max_link_speed(np);
if (pci_msi_enabled()) { if (pci_msi_enabled()) {
/* pp->has_msi_ctrl = !(pp->ops->msi_host_init ||
* If a specific SoC driver needs to change the of_property_read_bool(np, "msi-parent") ||
* default number of vectors, it needs to implement of_property_read_bool(np, "msi-map"));
* the set_num_vectors callback.
*/ if (!pp->num_vectors) {
if (!pp->ops->set_num_vectors) {
pp->num_vectors = MSI_DEF_NUM_VECTORS; pp->num_vectors = MSI_DEF_NUM_VECTORS;
} else { } else if (pp->num_vectors > MAX_MSI_IRQS) {
pp->ops->set_num_vectors(pp); dev_err(dev, "Invalid number of vectors\n");
return -EINVAL;
if (pp->num_vectors > MAX_MSI_IRQS ||
pp->num_vectors == 0) {
dev_err(dev,
"Invalid number of vectors\n");
return -EINVAL;
}
} }
if (!pp->ops->msi_host_init) { if (pp->ops->msi_host_init) {
ret = pp->ops->msi_host_init(pp);
if (ret < 0)
return ret;
} 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;
}
}
pp->msi_irq_chip = &dw_pci_msi_bottom_irq_chip; pp->msi_irq_chip = &dw_pci_msi_bottom_irq_chip;
ret = dw_pcie_allocate_domains(pp); ret = dw_pcie_allocate_domains(pp);
if (ret) if (ret)
return ret; return ret;
if (pp->msi_irq) if (pp->msi_irq > 0)
irq_set_chained_handler_and_data(pp->msi_irq, irq_set_chained_handler_and_data(pp->msi_irq,
dw_chained_msi_isr, dw_chained_msi_isr,
pp); pp);
ret = dma_set_mask(pci->dev, DMA_BIT_MASK(32));
if (!ret) {
dev_warn(pci->dev,
"Failed to set DMA mask to 32-bit. "
"Devices with only 32-bit MSI support"
" may not work properly\n");
}
pp->msi_data = dma_map_single_attrs(pci->dev, &pp->msi_msg, pp->msi_data = dma_map_single_attrs(pci->dev, &pp->msi_msg,
sizeof(pp->msi_msg), sizeof(pp->msi_msg),
DMA_FROM_DEVICE, DMA_FROM_DEVICE,
...@@ -397,10 +413,6 @@ int dw_pcie_host_init(struct pcie_port *pp) ...@@ -397,10 +413,6 @@ int dw_pcie_host_init(struct pcie_port *pp)
pp->msi_data = 0; pp->msi_data = 0;
goto err_free_msi; goto err_free_msi;
} }
} else {
ret = pp->ops->msi_host_init(pp);
if (ret < 0)
return ret;
} }
} }
...@@ -414,6 +426,18 @@ int dw_pcie_host_init(struct pcie_port *pp) ...@@ -414,6 +426,18 @@ int dw_pcie_host_init(struct pcie_port *pp)
goto err_free_msi; goto err_free_msi;
} }
dw_pcie_setup_rc(pp);
dw_pcie_msi_init(pp);
if (!dw_pcie_link_up(pci) && pci->ops->start_link) {
ret = pci->ops->start_link(pci);
if (ret)
goto err_free_msi;
}
/* Ignore errors, the link may come up later */
dw_pcie_wait_for_link(pci);
bridge->sysdata = pp; bridge->sysdata = pp;
ret = pci_host_probe(bridge); ret = pci_host_probe(bridge);
...@@ -421,7 +445,7 @@ int dw_pcie_host_init(struct pcie_port *pp) ...@@ -421,7 +445,7 @@ int dw_pcie_host_init(struct pcie_port *pp)
return 0; return 0;
err_free_msi: err_free_msi:
if (pci_msi_enabled() && !pp->ops->msi_host_init) if (pp->has_msi_ctrl)
dw_pcie_free_msi(pp); dw_pcie_free_msi(pp);
return ret; return ret;
} }
...@@ -431,7 +455,7 @@ void dw_pcie_host_deinit(struct pcie_port *pp) ...@@ -431,7 +455,7 @@ void dw_pcie_host_deinit(struct pcie_port *pp)
{ {
pci_stop_root_bus(pp->bridge->bus); pci_stop_root_bus(pp->bridge->bus);
pci_remove_root_bus(pp->bridge->bus); pci_remove_root_bus(pp->bridge->bus);
if (pci_msi_enabled() && !pp->ops->msi_host_init) if (pp->has_msi_ctrl)
dw_pcie_free_msi(pp); dw_pcie_free_msi(pp);
} }
EXPORT_SYMBOL_GPL(dw_pcie_host_deinit); EXPORT_SYMBOL_GPL(dw_pcie_host_deinit);
...@@ -464,9 +488,7 @@ static void __iomem *dw_pcie_other_conf_map_bus(struct pci_bus *bus, ...@@ -464,9 +488,7 @@ static void __iomem *dw_pcie_other_conf_map_bus(struct pci_bus *bus,
type = PCIE_ATU_TYPE_CFG1; type = PCIE_ATU_TYPE_CFG1;
dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX1, dw_pcie_prog_outbound_atu(pci, 0, type, pp->cfg0_base, busdev, pp->cfg0_size);
type, pp->cfg0_base,
busdev, pp->cfg0_size);
return pp->va_cfg0_base + where; return pp->va_cfg0_base + where;
} }
...@@ -480,9 +502,8 @@ static int dw_pcie_rd_other_conf(struct pci_bus *bus, unsigned int devfn, ...@@ -480,9 +502,8 @@ static int dw_pcie_rd_other_conf(struct pci_bus *bus, unsigned int devfn,
ret = pci_generic_config_read(bus, devfn, where, size, val); ret = pci_generic_config_read(bus, devfn, where, size, val);
if (!ret && pci->num_viewport <= 2) if (!ret && pci->io_cfg_atu_shared)
dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX1, dw_pcie_prog_outbound_atu(pci, 0, PCIE_ATU_TYPE_IO, pp->io_base,
PCIE_ATU_TYPE_IO, pp->io_base,
pp->io_bus_addr, pp->io_size); pp->io_bus_addr, pp->io_size);
return ret; return ret;
...@@ -497,9 +518,8 @@ static int dw_pcie_wr_other_conf(struct pci_bus *bus, unsigned int devfn, ...@@ -497,9 +518,8 @@ static int dw_pcie_wr_other_conf(struct pci_bus *bus, unsigned int devfn,
ret = pci_generic_config_write(bus, devfn, where, size, val); ret = pci_generic_config_write(bus, devfn, where, size, val);
if (!ret && pci->num_viewport <= 2) if (!ret && pci->io_cfg_atu_shared)
dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX1, dw_pcie_prog_outbound_atu(pci, 0, PCIE_ATU_TYPE_IO, pp->io_base,
PCIE_ATU_TYPE_IO, pp->io_base,
pp->io_bus_addr, pp->io_size); pp->io_bus_addr, pp->io_size);
return ret; return ret;
...@@ -531,6 +551,7 @@ static struct pci_ops dw_pcie_ops = { ...@@ -531,6 +551,7 @@ static struct pci_ops dw_pcie_ops = {
void dw_pcie_setup_rc(struct pcie_port *pp) void dw_pcie_setup_rc(struct pcie_port *pp)
{ {
int i;
u32 val, ctrl, num_ctrls; u32 val, ctrl, num_ctrls;
struct dw_pcie *pci = to_dw_pcie_from_pp(pp); struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
...@@ -542,7 +563,7 @@ void dw_pcie_setup_rc(struct pcie_port *pp) ...@@ -542,7 +563,7 @@ void dw_pcie_setup_rc(struct pcie_port *pp)
dw_pcie_setup(pci); dw_pcie_setup(pci);
if (pci_msi_enabled() && !pp->ops->msi_host_init) { if (pp->has_msi_ctrl) {
num_ctrls = pp->num_vectors / MAX_MSI_IRQS_PER_CTRL; num_ctrls = pp->num_vectors / MAX_MSI_IRQS_PER_CTRL;
/* Initialize IRQ Status array */ /* Initialize IRQ Status array */
...@@ -580,27 +601,45 @@ void dw_pcie_setup_rc(struct pcie_port *pp) ...@@ -580,27 +601,45 @@ void dw_pcie_setup_rc(struct pcie_port *pp)
PCI_COMMAND_MASTER | PCI_COMMAND_SERR; PCI_COMMAND_MASTER | PCI_COMMAND_SERR;
dw_pcie_writel_dbi(pci, PCI_COMMAND, val); dw_pcie_writel_dbi(pci, PCI_COMMAND, val);
/* 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, i, DW_PCIE_REGION_OUTBOUND);
/* /*
* If the platform provides its own child bus config accesses, it means * If the platform provides its own child bus config accesses, it means
* the platform uses its own address translation component rather than * the platform uses its own address translation component rather than
* ATU, so we should not program the ATU here. * ATU, so we should not program the ATU here.
*/ */
if (pp->bridge->child_ops == &dw_child_pcie_ops) { if (pp->bridge->child_ops == &dw_child_pcie_ops) {
struct resource_entry *tmp, *entry = NULL; int atu_idx = 0;
struct resource_entry *entry;
/* Get last memory resource entry */ /* Get last memory resource entry */
resource_list_for_each_entry(tmp, &pp->bridge->windows) resource_list_for_each_entry(entry, &pp->bridge->windows) {
if (resource_type(tmp->res) == IORESOURCE_MEM) if (resource_type(entry->res) != IORESOURCE_MEM)
entry = tmp; continue;
dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX0, if (pci->num_ob_windows <= ++atu_idx)
PCIE_ATU_TYPE_MEM, entry->res->start, break;
entry->res->start - entry->offset,
resource_size(entry->res)); dw_pcie_prog_outbound_atu(pci, atu_idx,
if (pci->num_viewport > 2) PCIE_ATU_TYPE_MEM, entry->res->start,
dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX2, entry->res->start - entry->offset,
PCIE_ATU_TYPE_IO, pp->io_base, resource_size(entry->res));
pp->io_bus_addr, pp->io_size); }
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)",
pci->num_ob_windows);
} }
dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_0, 0); dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_0, 0);
......
...@@ -33,25 +33,7 @@ struct dw_plat_pcie_of_data { ...@@ -33,25 +33,7 @@ struct dw_plat_pcie_of_data {
static const struct of_device_id dw_plat_pcie_of_match[]; static const struct of_device_id dw_plat_pcie_of_match[];
static int dw_plat_pcie_host_init(struct pcie_port *pp)
{
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
dw_pcie_setup_rc(pp);
dw_pcie_wait_for_link(pci);
dw_pcie_msi_init(pp);
return 0;
}
static void dw_plat_set_num_vectors(struct pcie_port *pp)
{
pp->num_vectors = MAX_MSI_IRQS;
}
static const struct dw_pcie_host_ops dw_plat_pcie_host_ops = { static const struct dw_pcie_host_ops dw_plat_pcie_host_ops = {
.host_init = dw_plat_pcie_host_init,
.set_num_vectors = dw_plat_set_num_vectors,
}; };
static int dw_plat_pcie_establish_link(struct dw_pcie *pci) static int dw_plat_pcie_establish_link(struct dw_pcie *pci)
...@@ -122,12 +104,7 @@ static int dw_plat_add_pcie_port(struct dw_plat_pcie *dw_plat_pcie, ...@@ -122,12 +104,7 @@ static int dw_plat_add_pcie_port(struct dw_plat_pcie *dw_plat_pcie,
if (pp->irq < 0) if (pp->irq < 0)
return pp->irq; return pp->irq;
if (IS_ENABLED(CONFIG_PCI_MSI)) { pp->num_vectors = MAX_MSI_IRQS;
pp->msi_irq = platform_get_irq(pdev, 0);
if (pp->msi_irq < 0)
return pp->msi_irq;
}
pp->ops = &dw_plat_pcie_host_ops; pp->ops = &dw_plat_pcie_host_ops;
ret = dw_pcie_host_init(pp); ret = dw_pcie_host_init(pp);
...@@ -139,43 +116,11 @@ static int dw_plat_add_pcie_port(struct dw_plat_pcie *dw_plat_pcie, ...@@ -139,43 +116,11 @@ static int dw_plat_add_pcie_port(struct dw_plat_pcie *dw_plat_pcie,
return 0; return 0;
} }
static int dw_plat_add_pcie_ep(struct dw_plat_pcie *dw_plat_pcie,
struct platform_device *pdev)
{
int ret;
struct dw_pcie_ep *ep;
struct resource *res;
struct device *dev = &pdev->dev;
struct dw_pcie *pci = dw_plat_pcie->pci;
ep = &pci->ep;
ep->ops = &pcie_ep_ops;
pci->dbi_base2 = devm_platform_ioremap_resource_byname(pdev, "dbi2");
if (IS_ERR(pci->dbi_base2))
return PTR_ERR(pci->dbi_base2);
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "addr_space");
if (!res)
return -EINVAL;
ep->phys_base = res->start;
ep->addr_size = resource_size(res);
ret = dw_pcie_ep_init(ep);
if (ret) {
dev_err(dev, "Failed to initialize endpoint\n");
return ret;
}
return 0;
}
static int dw_plat_pcie_probe(struct platform_device *pdev) static int dw_plat_pcie_probe(struct platform_device *pdev)
{ {
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct dw_plat_pcie *dw_plat_pcie; struct dw_plat_pcie *dw_plat_pcie;
struct dw_pcie *pci; struct dw_pcie *pci;
struct resource *res; /* Resource from DT */
int ret; int ret;
const struct of_device_id *match; const struct of_device_id *match;
const struct dw_plat_pcie_of_data *data; const struct dw_plat_pcie_of_data *data;
...@@ -202,14 +147,6 @@ static int dw_plat_pcie_probe(struct platform_device *pdev) ...@@ -202,14 +147,6 @@ static int dw_plat_pcie_probe(struct platform_device *pdev)
dw_plat_pcie->pci = pci; dw_plat_pcie->pci = pci;
dw_plat_pcie->mode = mode; dw_plat_pcie->mode = mode;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi");
if (!res)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
pci->dbi_base = devm_ioremap_resource(dev, res);
if (IS_ERR(pci->dbi_base))
return PTR_ERR(pci->dbi_base);
platform_set_drvdata(pdev, dw_plat_pcie); platform_set_drvdata(pdev, dw_plat_pcie);
switch (dw_plat_pcie->mode) { switch (dw_plat_pcie->mode) {
...@@ -225,9 +162,8 @@ static int dw_plat_pcie_probe(struct platform_device *pdev) ...@@ -225,9 +162,8 @@ static int dw_plat_pcie_probe(struct platform_device *pdev)
if (!IS_ENABLED(CONFIG_PCIE_DW_PLAT_EP)) if (!IS_ENABLED(CONFIG_PCIE_DW_PLAT_EP))
return -ENODEV; return -ENODEV;
ret = dw_plat_add_pcie_ep(dw_plat_pcie, pdev); pci->ep.ops = &pcie_ep_ops;
if (ret < 0) return dw_pcie_ep_init(&pci->ep);
return ret;
break; break;
default: default:
dev_err(dev, "INVALID device type %d\n", dw_plat_pcie->mode); dev_err(dev, "INVALID device type %d\n", dw_plat_pcie->mode);
......
...@@ -228,7 +228,7 @@ static void dw_pcie_writel_ob_unroll(struct dw_pcie *pci, u32 index, u32 reg, ...@@ -228,7 +228,7 @@ static void dw_pcie_writel_ob_unroll(struct dw_pcie *pci, u32 index, u32 reg,
static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, u8 func_no, static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, u8 func_no,
int index, int type, int index, int type,
u64 cpu_addr, u64 pci_addr, u64 cpu_addr, u64 pci_addr,
u32 size) u64 size)
{ {
u32 retries, val; u32 retries, val;
u64 limit_addr = cpu_addr + size - 1; u64 limit_addr = cpu_addr + size - 1;
...@@ -245,8 +245,10 @@ static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, u8 func_no, ...@@ -245,8 +245,10 @@ static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, u8 func_no,
lower_32_bits(pci_addr)); lower_32_bits(pci_addr));
dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_TARGET, dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_TARGET,
upper_32_bits(pci_addr)); upper_32_bits(pci_addr));
dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1, val = type | PCIE_ATU_FUNC_NUM(func_no);
type | PCIE_ATU_FUNC_NUM(func_no)); val = upper_32_bits(size - 1) ?
val | PCIE_ATU_INCREASE_REGION_SIZE : 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, dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL2,
PCIE_ATU_ENABLE); PCIE_ATU_ENABLE);
...@@ -267,7 +269,7 @@ static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, u8 func_no, ...@@ -267,7 +269,7 @@ static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, u8 func_no,
static void __dw_pcie_prog_outbound_atu(struct dw_pcie *pci, u8 func_no, static void __dw_pcie_prog_outbound_atu(struct dw_pcie *pci, u8 func_no,
int index, int type, u64 cpu_addr, int index, int type, u64 cpu_addr,
u64 pci_addr, u32 size) u64 pci_addr, u64 size)
{ {
u32 retries, val; u32 retries, val;
...@@ -311,7 +313,7 @@ static void __dw_pcie_prog_outbound_atu(struct dw_pcie *pci, u8 func_no, ...@@ -311,7 +313,7 @@ static void __dw_pcie_prog_outbound_atu(struct dw_pcie *pci, u8 func_no,
} }
void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index, int type, void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index, int type,
u64 cpu_addr, u64 pci_addr, u32 size) u64 cpu_addr, u64 pci_addr, u64 size)
{ {
__dw_pcie_prog_outbound_atu(pci, 0, index, type, __dw_pcie_prog_outbound_atu(pci, 0, index, type,
cpu_addr, pci_addr, size); cpu_addr, pci_addr, size);
...@@ -544,6 +546,70 @@ static u8 dw_pcie_iatu_unroll_enabled(struct dw_pcie *pci) ...@@ -544,6 +546,70 @@ static u8 dw_pcie_iatu_unroll_enabled(struct dw_pcie *pci)
return 0; return 0;
} }
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;
u32 val;
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
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
break;
}
pci->num_ib_windows = ib;
pci->num_ob_windows = ob;
}
void dw_pcie_setup(struct dw_pcie *pci) void dw_pcie_setup(struct dw_pcie *pci)
{ {
u32 val; u32 val;
...@@ -554,15 +620,30 @@ void dw_pcie_setup(struct dw_pcie *pci) ...@@ -554,15 +620,30 @@ void dw_pcie_setup(struct dw_pcie *pci)
if (pci->version >= 0x480A || (!pci->version && if (pci->version >= 0x480A || (!pci->version &&
dw_pcie_iatu_unroll_enabled(pci))) { dw_pcie_iatu_unroll_enabled(pci))) {
pci->iatu_unroll_enabled = true; pci->iatu_unroll_enabled = true;
if (!pci->atu_base) if (!pci->atu_base) {
pci->atu_base = struct resource *res =
devm_platform_ioremap_resource_byname(pdev, "atu"); platform_get_resource_byname(pdev, IORESOURCE_MEM, "atu");
if (IS_ERR(pci->atu_base)) if (res)
pci->atu_base = pci->dbi_base + DEFAULT_DBI_ATU_OFFSET; pci->atu_size = resource_size(res);
} pci->atu_base = devm_ioremap_resource(dev, res);
dev_dbg(pci->dev, "iATU unroll: %s\n", pci->iatu_unroll_enabled ? if (IS_ERR(pci->atu_base))
pci->atu_base = pci->dbi_base + DEFAULT_DBI_ATU_OFFSET;
}
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);
dev_info(pci->dev, "iATU unroll: %s\n", pci->iatu_unroll_enabled ?
"enabled" : "disabled"); "enabled" : "disabled");
dev_info(pci->dev, "Detected iATU regions: %u outbound, %u inbound",
pci->num_ob_windows, pci->num_ib_windows);
if (pci->link_gen > 0) if (pci->link_gen > 0)
dw_pcie_link_set_max_speed(pci, pci->link_gen); dw_pcie_link_set_max_speed(pci, pci->link_gen);
......
...@@ -80,10 +80,8 @@ ...@@ -80,10 +80,8 @@
#define PCIE_ATU_VIEWPORT 0x900 #define PCIE_ATU_VIEWPORT 0x900
#define PCIE_ATU_REGION_INBOUND BIT(31) #define PCIE_ATU_REGION_INBOUND BIT(31)
#define PCIE_ATU_REGION_OUTBOUND 0 #define PCIE_ATU_REGION_OUTBOUND 0
#define PCIE_ATU_REGION_INDEX2 0x2
#define PCIE_ATU_REGION_INDEX1 0x1
#define PCIE_ATU_REGION_INDEX0 0x0
#define PCIE_ATU_CR1 0x904 #define PCIE_ATU_CR1 0x904
#define PCIE_ATU_INCREASE_REGION_SIZE BIT(13)
#define PCIE_ATU_TYPE_MEM 0x0 #define PCIE_ATU_TYPE_MEM 0x0
#define PCIE_ATU_TYPE_IO 0x2 #define PCIE_ATU_TYPE_IO 0x2
#define PCIE_ATU_TYPE_CFG0 0x4 #define PCIE_ATU_TYPE_CFG0 0x4
...@@ -174,11 +172,11 @@ enum dw_pcie_device_mode { ...@@ -174,11 +172,11 @@ enum dw_pcie_device_mode {
struct dw_pcie_host_ops { struct dw_pcie_host_ops {
int (*host_init)(struct pcie_port *pp); int (*host_init)(struct pcie_port *pp);
void (*set_num_vectors)(struct pcie_port *pp);
int (*msi_host_init)(struct pcie_port *pp); int (*msi_host_init)(struct pcie_port *pp);
}; };
struct pcie_port { struct pcie_port {
bool has_msi_ctrl:1;
u64 cfg0_base; u64 cfg0_base;
void __iomem *va_cfg0_base; void __iomem *va_cfg0_base;
u32 cfg0_size; u32 cfg0_size;
...@@ -239,8 +237,6 @@ struct dw_pcie_ep { ...@@ -239,8 +237,6 @@ struct dw_pcie_ep {
phys_addr_t *outbound_addr; phys_addr_t *outbound_addr;
unsigned long *ib_window_map; unsigned long *ib_window_map;
unsigned long *ob_window_map; unsigned long *ob_window_map;
u32 num_ib_windows;
u32 num_ob_windows;
void __iomem *msi_mem; void __iomem *msi_mem;
phys_addr_t msi_mem_phys; phys_addr_t msi_mem_phys;
struct pci_epf_bar *epf_bar[PCI_STD_NUM_BARS]; struct pci_epf_bar *epf_bar[PCI_STD_NUM_BARS];
...@@ -265,8 +261,9 @@ struct dw_pcie { ...@@ -265,8 +261,9 @@ struct dw_pcie {
void __iomem *dbi_base2; void __iomem *dbi_base2;
/* Used when iatu_unroll_enabled is true */ /* Used when iatu_unroll_enabled is true */
void __iomem *atu_base; void __iomem *atu_base;
u32 num_viewport; size_t atu_size;
u8 iatu_unroll_enabled; u32 num_ib_windows;
u32 num_ob_windows;
struct pcie_port pp; struct pcie_port pp;
struct dw_pcie_ep ep; struct dw_pcie_ep ep;
const struct dw_pcie_ops *ops; const struct dw_pcie_ops *ops;
...@@ -274,6 +271,8 @@ struct dw_pcie { ...@@ -274,6 +271,8 @@ struct dw_pcie {
int num_lanes; int num_lanes;
int link_gen; int link_gen;
u8 n_fts[2]; u8 n_fts[2];
bool iatu_unroll_enabled: 1;
bool io_cfg_atu_shared: 1;
}; };
#define to_dw_pcie_from_pp(port) container_of((port), struct dw_pcie, pp) #define to_dw_pcie_from_pp(port) container_of((port), struct dw_pcie, pp)
...@@ -295,7 +294,7 @@ void dw_pcie_upconfig_setup(struct dw_pcie *pci); ...@@ -295,7 +294,7 @@ void dw_pcie_upconfig_setup(struct dw_pcie *pci);
int dw_pcie_wait_for_link(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, void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index,
int type, u64 cpu_addr, u64 pci_addr, int type, u64 cpu_addr, u64 pci_addr,
u32 size); u64 size);
void dw_pcie_prog_ep_outbound_atu(struct dw_pcie *pci, u8 func_no, int index, void dw_pcie_prog_ep_outbound_atu(struct dw_pcie *pci, u8 func_no, int index,
int type, u64 cpu_addr, u64 pci_addr, int type, u64 cpu_addr, u64 pci_addr,
u32 size); u32 size);
...@@ -365,8 +364,6 @@ static inline void dw_pcie_dbi_ro_wr_dis(struct dw_pcie *pci) ...@@ -365,8 +364,6 @@ static inline void dw_pcie_dbi_ro_wr_dis(struct dw_pcie *pci)
#ifdef CONFIG_PCIE_DW_HOST #ifdef CONFIG_PCIE_DW_HOST
irqreturn_t dw_handle_msi_irq(struct pcie_port *pp); irqreturn_t dw_handle_msi_irq(struct pcie_port *pp);
void dw_pcie_msi_init(struct pcie_port *pp);
void dw_pcie_free_msi(struct pcie_port *pp);
void dw_pcie_setup_rc(struct pcie_port *pp); void dw_pcie_setup_rc(struct pcie_port *pp);
int dw_pcie_host_init(struct pcie_port *pp); int dw_pcie_host_init(struct pcie_port *pp);
void dw_pcie_host_deinit(struct pcie_port *pp); void dw_pcie_host_deinit(struct pcie_port *pp);
...@@ -379,14 +376,6 @@ static inline irqreturn_t dw_handle_msi_irq(struct pcie_port *pp) ...@@ -379,14 +376,6 @@ static inline irqreturn_t dw_handle_msi_irq(struct pcie_port *pp)
return IRQ_NONE; return IRQ_NONE;
} }
static inline void dw_pcie_msi_init(struct pcie_port *pp)
{
}
static inline void dw_pcie_free_msi(struct pcie_port *pp)
{
}
static inline void dw_pcie_setup_rc(struct pcie_port *pp) static inline void dw_pcie_setup_rc(struct pcie_port *pp)
{ {
} }
......
...@@ -100,7 +100,6 @@ static int hisi_pcie_init(struct pci_config_window *cfg) ...@@ -100,7 +100,6 @@ static int hisi_pcie_init(struct pci_config_window *cfg)
} }
const struct pci_ecam_ops hisi_pcie_ops = { const struct pci_ecam_ops hisi_pcie_ops = {
.bus_shift = 20,
.init = hisi_pcie_init, .init = hisi_pcie_init,
.pci_ops = { .pci_ops = {
.map_bus = hisi_pcie_map_bus, .map_bus = hisi_pcie_map_bus,
...@@ -135,7 +134,6 @@ static int hisi_pcie_platform_init(struct pci_config_window *cfg) ...@@ -135,7 +134,6 @@ static int hisi_pcie_platform_init(struct pci_config_window *cfg)
} }
static const struct pci_ecam_ops hisi_pcie_platform_ops = { static const struct pci_ecam_ops hisi_pcie_platform_ops = {
.bus_shift = 20,
.init = hisi_pcie_platform_init, .init = hisi_pcie_platform_init,
.pci_ops = { .pci_ops = {
.map_bus = hisi_pcie_map_bus, .map_bus = hisi_pcie_map_bus,
......
...@@ -169,40 +169,32 @@ static int histb_pcie_link_up(struct dw_pcie *pci) ...@@ -169,40 +169,32 @@ static int histb_pcie_link_up(struct dw_pcie *pci)
return 0; return 0;
} }
static int histb_pcie_establish_link(struct pcie_port *pp) static int histb_pcie_start_link(struct dw_pcie *pci)
{ {
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
struct histb_pcie *hipcie = to_histb_pcie(pci); struct histb_pcie *hipcie = to_histb_pcie(pci);
u32 regval; u32 regval;
if (dw_pcie_link_up(pci)) {
dev_info(pci->dev, "Link already up\n");
return 0;
}
/* PCIe RC work mode */
regval = histb_pcie_readl(hipcie, PCIE_SYS_CTRL0);
regval &= ~PCIE_DEVICE_TYPE_MASK;
regval |= PCIE_WM_RC;
histb_pcie_writel(hipcie, PCIE_SYS_CTRL0, regval);
/* setup root complex */
dw_pcie_setup_rc(pp);
/* assert LTSSM enable */ /* assert LTSSM enable */
regval = histb_pcie_readl(hipcie, PCIE_SYS_CTRL7); regval = histb_pcie_readl(hipcie, PCIE_SYS_CTRL7);
regval |= PCIE_APP_LTSSM_ENABLE; regval |= PCIE_APP_LTSSM_ENABLE;
histb_pcie_writel(hipcie, PCIE_SYS_CTRL7, regval); histb_pcie_writel(hipcie, PCIE_SYS_CTRL7, regval);
return dw_pcie_wait_for_link(pci); return 0;
} }
static int histb_pcie_host_init(struct pcie_port *pp) static int histb_pcie_host_init(struct pcie_port *pp)
{ {
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
struct histb_pcie *hipcie = to_histb_pcie(pci);
u32 regval;
pp->bridge->ops = &histb_pci_ops; pp->bridge->ops = &histb_pci_ops;
histb_pcie_establish_link(pp); /* PCIe RC work mode */
dw_pcie_msi_init(pp); regval = histb_pcie_readl(hipcie, PCIE_SYS_CTRL0);
regval &= ~PCIE_DEVICE_TYPE_MASK;
regval |= PCIE_WM_RC;
histb_pcie_writel(hipcie, PCIE_SYS_CTRL0, regval);
return 0; return 0;
} }
...@@ -300,6 +292,7 @@ static const struct dw_pcie_ops dw_pcie_ops = { ...@@ -300,6 +292,7 @@ static const struct dw_pcie_ops dw_pcie_ops = {
.read_dbi = histb_pcie_read_dbi, .read_dbi = histb_pcie_read_dbi,
.write_dbi = histb_pcie_write_dbi, .write_dbi = histb_pcie_write_dbi,
.link_up = histb_pcie_link_up, .link_up = histb_pcie_link_up,
.start_link = histb_pcie_start_link,
}; };
static int histb_pcie_probe(struct platform_device *pdev) static int histb_pcie_probe(struct platform_device *pdev)
...@@ -400,12 +393,6 @@ static int histb_pcie_probe(struct platform_device *pdev) ...@@ -400,12 +393,6 @@ static int histb_pcie_probe(struct platform_device *pdev)
return PTR_ERR(hipcie->bus_reset); return PTR_ERR(hipcie->bus_reset);
} }
if (IS_ENABLED(CONFIG_PCI_MSI)) {
pp->msi_irq = platform_get_irq_byname(pdev, "msi");
if (pp->msi_irq < 0)
return pp->msi_irq;
}
hipcie->phy = devm_phy_get(dev, "phy"); hipcie->phy = devm_phy_get(dev, "phy");
if (IS_ERR(hipcie->phy)) { if (IS_ERR(hipcie->phy)) {
dev_info(dev, "no pcie-phy found\n"); dev_info(dev, "no pcie-phy found\n");
......
...@@ -58,8 +58,6 @@ ...@@ -58,8 +58,6 @@
struct intel_pcie_soc { struct intel_pcie_soc {
unsigned int pcie_ver; unsigned int pcie_ver;
unsigned int pcie_atu_offset;
u32 num_viewport;
}; };
struct intel_pcie_port { struct intel_pcie_port {
...@@ -153,15 +151,6 @@ static void intel_pcie_init_n_fts(struct dw_pcie *pci) ...@@ -153,15 +151,6 @@ static void intel_pcie_init_n_fts(struct dw_pcie *pci)
pci->n_fts[0] = PORT_AFR_N_FTS_GEN12_DFT; pci->n_fts[0] = PORT_AFR_N_FTS_GEN12_DFT;
} }
static void intel_pcie_rc_setup(struct intel_pcie_port *lpp)
{
intel_pcie_ltssm_disable(lpp);
intel_pcie_link_setup(lpp);
intel_pcie_init_n_fts(&lpp->pci);
dw_pcie_setup_rc(&lpp->pci.pp);
dw_pcie_upconfig_setup(&lpp->pci);
}
static int intel_pcie_ep_rst_init(struct intel_pcie_port *lpp) static int intel_pcie_ep_rst_init(struct intel_pcie_port *lpp)
{ {
struct device *dev = lpp->pci.dev; struct device *dev = lpp->pci.dev;
...@@ -213,14 +202,6 @@ static void intel_pcie_device_rst_deassert(struct intel_pcie_port *lpp) ...@@ -213,14 +202,6 @@ static void intel_pcie_device_rst_deassert(struct intel_pcie_port *lpp)
gpiod_set_value_cansleep(lpp->reset_gpio, 0); gpiod_set_value_cansleep(lpp->reset_gpio, 0);
} }
static int intel_pcie_app_logic_setup(struct intel_pcie_port *lpp)
{
intel_pcie_device_rst_deassert(lpp);
intel_pcie_ltssm_enable(lpp);
return dw_pcie_wait_for_link(&lpp->pci);
}
static void intel_pcie_core_irq_disable(struct intel_pcie_port *lpp) static void intel_pcie_core_irq_disable(struct intel_pcie_port *lpp)
{ {
pcie_app_wr(lpp, PCIE_APP_IRNEN, 0); pcie_app_wr(lpp, PCIE_APP_IRNEN, 0);
...@@ -234,10 +215,6 @@ static int intel_pcie_get_resources(struct platform_device *pdev) ...@@ -234,10 +215,6 @@ static int intel_pcie_get_resources(struct platform_device *pdev)
struct device *dev = pci->dev; struct device *dev = pci->dev;
int ret; int ret;
pci->dbi_base = devm_platform_ioremap_resource_byname(pdev, "dbi");
if (IS_ERR(pci->dbi_base))
return PTR_ERR(pci->dbi_base);
lpp->core_clk = devm_clk_get(dev, NULL); lpp->core_clk = devm_clk_get(dev, NULL);
if (IS_ERR(lpp->core_clk)) { if (IS_ERR(lpp->core_clk)) {
ret = PTR_ERR(lpp->core_clk); ret = PTR_ERR(lpp->core_clk);
...@@ -274,11 +251,6 @@ static int intel_pcie_get_resources(struct platform_device *pdev) ...@@ -274,11 +251,6 @@ static int intel_pcie_get_resources(struct platform_device *pdev)
return 0; return 0;
} }
static void intel_pcie_deinit_phy(struct intel_pcie_port *lpp)
{
phy_exit(lpp->phy);
}
static int intel_pcie_wait_l2(struct intel_pcie_port *lpp) static int intel_pcie_wait_l2(struct intel_pcie_port *lpp)
{ {
u32 value; u32 value;
...@@ -315,6 +287,7 @@ static void intel_pcie_turn_off(struct intel_pcie_port *lpp) ...@@ -315,6 +287,7 @@ static void intel_pcie_turn_off(struct intel_pcie_port *lpp)
static int intel_pcie_host_setup(struct intel_pcie_port *lpp) static int intel_pcie_host_setup(struct intel_pcie_port *lpp)
{ {
int ret; int ret;
struct dw_pcie *pci = &lpp->pci;
intel_pcie_core_rst_assert(lpp); intel_pcie_core_rst_assert(lpp);
intel_pcie_device_rst_assert(lpp); intel_pcie_device_rst_assert(lpp);
...@@ -331,8 +304,18 @@ static int intel_pcie_host_setup(struct intel_pcie_port *lpp) ...@@ -331,8 +304,18 @@ static int intel_pcie_host_setup(struct intel_pcie_port *lpp)
goto clk_err; goto clk_err;
} }
intel_pcie_rc_setup(lpp); pci->atu_base = pci->dbi_base + 0xC0000;
ret = intel_pcie_app_logic_setup(lpp);
intel_pcie_ltssm_disable(lpp);
intel_pcie_link_setup(lpp);
intel_pcie_init_n_fts(pci);
dw_pcie_setup_rc(&pci->pp);
dw_pcie_upconfig_setup(pci);
intel_pcie_device_rst_deassert(lpp);
intel_pcie_ltssm_enable(lpp);
ret = dw_pcie_wait_for_link(pci);
if (ret) if (ret)
goto app_init_err; goto app_init_err;
...@@ -346,7 +329,7 @@ static int intel_pcie_host_setup(struct intel_pcie_port *lpp) ...@@ -346,7 +329,7 @@ static int intel_pcie_host_setup(struct intel_pcie_port *lpp)
clk_disable_unprepare(lpp->core_clk); clk_disable_unprepare(lpp->core_clk);
clk_err: clk_err:
intel_pcie_core_rst_assert(lpp); intel_pcie_core_rst_assert(lpp);
intel_pcie_deinit_phy(lpp); phy_exit(lpp->phy);
return ret; return ret;
} }
...@@ -357,7 +340,7 @@ static void __intel_pcie_remove(struct intel_pcie_port *lpp) ...@@ -357,7 +340,7 @@ static void __intel_pcie_remove(struct intel_pcie_port *lpp)
intel_pcie_turn_off(lpp); intel_pcie_turn_off(lpp);
clk_disable_unprepare(lpp->core_clk); clk_disable_unprepare(lpp->core_clk);
intel_pcie_core_rst_assert(lpp); intel_pcie_core_rst_assert(lpp);
intel_pcie_deinit_phy(lpp); phy_exit(lpp->phy);
} }
static int intel_pcie_remove(struct platform_device *pdev) static int intel_pcie_remove(struct platform_device *pdev)
...@@ -381,7 +364,7 @@ static int __maybe_unused intel_pcie_suspend_noirq(struct device *dev) ...@@ -381,7 +364,7 @@ static int __maybe_unused intel_pcie_suspend_noirq(struct device *dev)
if (ret) if (ret)
return ret; return ret;
intel_pcie_deinit_phy(lpp); phy_exit(lpp->phy);
clk_disable_unprepare(lpp->core_clk); clk_disable_unprepare(lpp->core_clk);
return ret; return ret;
} }
...@@ -401,14 +384,6 @@ static int intel_pcie_rc_init(struct pcie_port *pp) ...@@ -401,14 +384,6 @@ static int intel_pcie_rc_init(struct pcie_port *pp)
return intel_pcie_host_setup(lpp); return intel_pcie_host_setup(lpp);
} }
/*
* Dummy function so that DW core doesn't configure MSI
*/
static int intel_pcie_msi_init(struct pcie_port *pp)
{
return 0;
}
static u64 intel_pcie_cpu_addr(struct dw_pcie *pcie, u64 cpu_addr) static u64 intel_pcie_cpu_addr(struct dw_pcie *pcie, u64 cpu_addr)
{ {
return cpu_addr + BUS_IATU_OFFSET; return cpu_addr + BUS_IATU_OFFSET;
...@@ -420,13 +395,10 @@ static const struct dw_pcie_ops intel_pcie_ops = { ...@@ -420,13 +395,10 @@ static const struct dw_pcie_ops intel_pcie_ops = {
static const struct dw_pcie_host_ops intel_pcie_dw_ops = { static const struct dw_pcie_host_ops intel_pcie_dw_ops = {
.host_init = intel_pcie_rc_init, .host_init = intel_pcie_rc_init,
.msi_host_init = intel_pcie_msi_init,
}; };
static const struct intel_pcie_soc pcie_data = { static const struct intel_pcie_soc pcie_data = {
.pcie_ver = 0x520A, .pcie_ver = 0x520A,
.pcie_atu_offset = 0xC0000,
.num_viewport = 3,
}; };
static int intel_pcie_probe(struct platform_device *pdev) static int intel_pcie_probe(struct platform_device *pdev)
...@@ -461,7 +433,6 @@ static int intel_pcie_probe(struct platform_device *pdev) ...@@ -461,7 +433,6 @@ static int intel_pcie_probe(struct platform_device *pdev)
pci->ops = &intel_pcie_ops; pci->ops = &intel_pcie_ops;
pci->version = data->pcie_ver; pci->version = data->pcie_ver;
pci->atu_base = pci->dbi_base + data->pcie_atu_offset;
pp->ops = &intel_pcie_dw_ops; pp->ops = &intel_pcie_dw_ops;
ret = dw_pcie_host_init(pp); ret = dw_pcie_host_init(pp);
...@@ -470,12 +441,6 @@ static int intel_pcie_probe(struct platform_device *pdev) ...@@ -470,12 +441,6 @@ static int intel_pcie_probe(struct platform_device *pdev)
return ret; return ret;
} }
/*
* Intel PCIe doesn't configure IO region, so set viewport
* to not perform IO region access.
*/
pci->num_viewport = data->num_viewport;
return 0; return 0;
} }
......
...@@ -157,11 +157,6 @@ static long kirin_pcie_get_resource(struct kirin_pcie *kirin_pcie, ...@@ -157,11 +157,6 @@ static long kirin_pcie_get_resource(struct kirin_pcie *kirin_pcie,
if (IS_ERR(kirin_pcie->phy_base)) if (IS_ERR(kirin_pcie->phy_base))
return PTR_ERR(kirin_pcie->phy_base); return PTR_ERR(kirin_pcie->phy_base);
kirin_pcie->pci->dbi_base =
devm_platform_ioremap_resource_byname(pdev, "dbi");
if (IS_ERR(kirin_pcie->pci->dbi_base))
return PTR_ERR(kirin_pcie->pci->dbi_base);
kirin_pcie->crgctrl = kirin_pcie->crgctrl =
syscon_regmap_lookup_by_compatible("hisilicon,hi3660-crgctrl"); syscon_regmap_lookup_by_compatible("hisilicon,hi3660-crgctrl");
if (IS_ERR(kirin_pcie->crgctrl)) if (IS_ERR(kirin_pcie->crgctrl))
...@@ -395,32 +390,14 @@ static int kirin_pcie_link_up(struct dw_pcie *pci) ...@@ -395,32 +390,14 @@ static int kirin_pcie_link_up(struct dw_pcie *pci)
return 0; return 0;
} }
static int kirin_pcie_establish_link(struct pcie_port *pp) static int kirin_pcie_start_link(struct dw_pcie *pci)
{ {
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
struct kirin_pcie *kirin_pcie = to_kirin_pcie(pci); struct kirin_pcie *kirin_pcie = to_kirin_pcie(pci);
struct device *dev = kirin_pcie->pci->dev;
int count = 0;
if (kirin_pcie_link_up(pci))
return 0;
dw_pcie_setup_rc(pp);
/* assert LTSSM enable */ /* assert LTSSM enable */
kirin_apb_ctrl_writel(kirin_pcie, PCIE_LTSSM_ENABLE_BIT, kirin_apb_ctrl_writel(kirin_pcie, PCIE_LTSSM_ENABLE_BIT,
PCIE_APP_LTSSM_ENABLE); PCIE_APP_LTSSM_ENABLE);
/* check if the link is up or not */
while (!kirin_pcie_link_up(pci)) {
usleep_range(LINK_WAIT_MIN, LINK_WAIT_MAX);
count++;
if (count == 1000) {
dev_err(dev, "Link Fail\n");
return -EINVAL;
}
}
return 0; return 0;
} }
...@@ -428,9 +405,6 @@ static int kirin_pcie_host_init(struct pcie_port *pp) ...@@ -428,9 +405,6 @@ static int kirin_pcie_host_init(struct pcie_port *pp)
{ {
pp->bridge->ops = &kirin_pci_ops; pp->bridge->ops = &kirin_pci_ops;
kirin_pcie_establish_link(pp);
dw_pcie_msi_init(pp);
return 0; return 0;
} }
...@@ -438,42 +412,13 @@ static const struct dw_pcie_ops kirin_dw_pcie_ops = { ...@@ -438,42 +412,13 @@ static const struct dw_pcie_ops kirin_dw_pcie_ops = {
.read_dbi = kirin_pcie_read_dbi, .read_dbi = kirin_pcie_read_dbi,
.write_dbi = kirin_pcie_write_dbi, .write_dbi = kirin_pcie_write_dbi,
.link_up = kirin_pcie_link_up, .link_up = kirin_pcie_link_up,
.start_link = kirin_pcie_start_link,
}; };
static const struct dw_pcie_host_ops kirin_pcie_host_ops = { static const struct dw_pcie_host_ops kirin_pcie_host_ops = {
.host_init = kirin_pcie_host_init, .host_init = kirin_pcie_host_init,
}; };
static int kirin_pcie_add_msi(struct dw_pcie *pci,
struct platform_device *pdev)
{
int irq;
if (IS_ENABLED(CONFIG_PCI_MSI)) {
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
pci->pp.msi_irq = irq;
}
return 0;
}
static int kirin_add_pcie_port(struct dw_pcie *pci,
struct platform_device *pdev)
{
int ret;
ret = kirin_pcie_add_msi(pci, pdev);
if (ret)
return ret;
pci->pp.ops = &kirin_pcie_host_ops;
return dw_pcie_host_init(&pci->pp);
}
static int kirin_pcie_probe(struct platform_device *pdev) static int kirin_pcie_probe(struct platform_device *pdev)
{ {
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
...@@ -496,6 +441,7 @@ static int kirin_pcie_probe(struct platform_device *pdev) ...@@ -496,6 +441,7 @@ static int kirin_pcie_probe(struct platform_device *pdev)
pci->dev = dev; pci->dev = dev;
pci->ops = &kirin_dw_pcie_ops; pci->ops = &kirin_dw_pcie_ops;
pci->pp.ops = &kirin_pcie_host_ops;
kirin_pcie->pci = pci; kirin_pcie->pci = pci;
ret = kirin_pcie_get_clk(kirin_pcie, pdev); ret = kirin_pcie_get_clk(kirin_pcie, pdev);
...@@ -521,7 +467,7 @@ static int kirin_pcie_probe(struct platform_device *pdev) ...@@ -521,7 +467,7 @@ static int kirin_pcie_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, kirin_pcie); platform_set_drvdata(pdev, kirin_pcie);
return kirin_add_pcie_port(pci, pdev); return dw_pcie_host_init(&pci->pp);
} }
static const struct of_device_id kirin_pcie_match[] = { static const struct of_device_id kirin_pcie_match[] = {
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
*/ */
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/crc8.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/gpio/consumer.h> #include <linux/gpio/consumer.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
...@@ -57,6 +58,7 @@ ...@@ -57,6 +58,7 @@
#define PCIE20_PARF_SID_OFFSET 0x234 #define PCIE20_PARF_SID_OFFSET 0x234
#define PCIE20_PARF_BDF_TRANSLATE_CFG 0x24C #define PCIE20_PARF_BDF_TRANSLATE_CFG 0x24C
#define PCIE20_PARF_DEVICE_TYPE 0x1000 #define PCIE20_PARF_DEVICE_TYPE 0x1000
#define PCIE20_PARF_BDF_TO_SID_TABLE_N 0x2000
#define PCIE20_ELBI_SYS_CTRL 0x04 #define PCIE20_ELBI_SYS_CTRL 0x04
#define PCIE20_ELBI_SYS_CTRL_LT_ENABLE BIT(0) #define PCIE20_ELBI_SYS_CTRL_LT_ENABLE BIT(0)
...@@ -97,6 +99,9 @@ ...@@ -97,6 +99,9 @@
#define QCOM_PCIE_2_1_0_MAX_SUPPLY 3 #define QCOM_PCIE_2_1_0_MAX_SUPPLY 3
#define QCOM_PCIE_2_1_0_MAX_CLOCKS 5 #define QCOM_PCIE_2_1_0_MAX_CLOCKS 5
#define QCOM_PCIE_CRC8_POLYNOMIAL (BIT(2) | BIT(1) | BIT(0))
struct qcom_pcie_resources_2_1_0 { struct qcom_pcie_resources_2_1_0 {
struct clk_bulk_data clks[QCOM_PCIE_2_1_0_MAX_CLOCKS]; struct clk_bulk_data clks[QCOM_PCIE_2_1_0_MAX_CLOCKS];
struct reset_control *pci_reset; struct reset_control *pci_reset;
...@@ -179,6 +184,7 @@ struct qcom_pcie_ops { ...@@ -179,6 +184,7 @@ struct qcom_pcie_ops {
void (*deinit)(struct qcom_pcie *pcie); void (*deinit)(struct qcom_pcie *pcie);
void (*post_deinit)(struct qcom_pcie *pcie); void (*post_deinit)(struct qcom_pcie *pcie);
void (*ltssm_enable)(struct qcom_pcie *pcie); void (*ltssm_enable)(struct qcom_pcie *pcie);
int (*config_sid)(struct qcom_pcie *pcie);
}; };
struct qcom_pcie { struct qcom_pcie {
...@@ -207,18 +213,15 @@ static void qcom_ep_reset_deassert(struct qcom_pcie *pcie) ...@@ -207,18 +213,15 @@ static void qcom_ep_reset_deassert(struct qcom_pcie *pcie)
usleep_range(PERST_DELAY_US, PERST_DELAY_US + 500); usleep_range(PERST_DELAY_US, PERST_DELAY_US + 500);
} }
static int qcom_pcie_establish_link(struct qcom_pcie *pcie) static int qcom_pcie_start_link(struct dw_pcie *pci)
{ {
struct dw_pcie *pci = pcie->pci; struct qcom_pcie *pcie = to_qcom_pcie(pci);
if (dw_pcie_link_up(pci))
return 0;
/* Enable Link Training state machine */ /* Enable Link Training state machine */
if (pcie->ops->ltssm_enable) if (pcie->ops->ltssm_enable)
pcie->ops->ltssm_enable(pcie); pcie->ops->ltssm_enable(pcie);
return dw_pcie_wait_for_link(pci); return 0;
} }
static void qcom_pcie_2_1_0_ltssm_enable(struct qcom_pcie *pcie) static void qcom_pcie_2_1_0_ltssm_enable(struct qcom_pcie *pcie)
...@@ -1261,6 +1264,77 @@ static int qcom_pcie_link_up(struct dw_pcie *pci) ...@@ -1261,6 +1264,77 @@ static int qcom_pcie_link_up(struct dw_pcie *pci)
return !!(val & PCI_EXP_LNKSTA_DLLLA); return !!(val & PCI_EXP_LNKSTA_DLLLA);
} }
static int qcom_pcie_config_sid_sm8250(struct qcom_pcie *pcie)
{
/* iommu map structure */
struct {
u32 bdf;
u32 phandle;
u32 smmu_sid;
u32 smmu_sid_len;
} *map;
void __iomem *bdf_to_sid_base = pcie->parf + PCIE20_PARF_BDF_TO_SID_TABLE_N;
struct device *dev = pcie->pci->dev;
u8 qcom_pcie_crc8_table[CRC8_TABLE_SIZE];
int i, nr_map, size = 0;
u32 smmu_sid_base;
of_get_property(dev->of_node, "iommu-map", &size);
if (!size)
return 0;
map = kzalloc(size, GFP_KERNEL);
if (!map)
return -ENOMEM;
of_property_read_u32_array(dev->of_node,
"iommu-map", (u32 *)map, size / sizeof(u32));
nr_map = size / (sizeof(*map));
crc8_populate_msb(qcom_pcie_crc8_table, QCOM_PCIE_CRC8_POLYNOMIAL);
/* Registers need to be zero out first */
memset_io(bdf_to_sid_base, 0, CRC8_TABLE_SIZE * sizeof(u32));
/* Extract the SMMU SID base from the first entry of iommu-map */
smmu_sid_base = map[0].smmu_sid;
/* Look for an available entry to hold the mapping */
for (i = 0; i < nr_map; i++) {
u16 bdf_be = cpu_to_be16(map[i].bdf);
u32 val;
u8 hash;
hash = crc8(qcom_pcie_crc8_table, (u8 *)&bdf_be, sizeof(bdf_be),
0);
val = readl(bdf_to_sid_base + hash * sizeof(u32));
/* If the register is already populated, look for next available entry */
while (val) {
u8 current_hash = hash++;
u8 next_mask = 0xff;
/* If NEXT field is NULL then update it with next hash */
if (!(val & next_mask)) {
val |= (u32)hash;
writel(val, bdf_to_sid_base + current_hash * sizeof(u32));
}
val = readl(bdf_to_sid_base + hash * sizeof(u32));
}
/* BDF [31:16] | SID [15:8] | NEXT [7:0] */
val = map[i].bdf << 16 | (map[i].smmu_sid - smmu_sid_base) << 8 | 0;
writel(val, bdf_to_sid_base + hash * sizeof(u32));
}
kfree(map);
return 0;
}
static int qcom_pcie_host_init(struct pcie_port *pp) static int qcom_pcie_host_init(struct pcie_port *pp)
{ {
struct dw_pcie *pci = to_dw_pcie_from_pp(pp); struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
...@@ -1283,16 +1357,16 @@ static int qcom_pcie_host_init(struct pcie_port *pp) ...@@ -1283,16 +1357,16 @@ static int qcom_pcie_host_init(struct pcie_port *pp)
goto err_disable_phy; goto err_disable_phy;
} }
dw_pcie_setup_rc(pp);
dw_pcie_msi_init(pp);
qcom_ep_reset_deassert(pcie); qcom_ep_reset_deassert(pcie);
ret = qcom_pcie_establish_link(pcie); if (pcie->ops->config_sid) {
if (ret) ret = pcie->ops->config_sid(pcie);
goto err; if (ret)
goto err;
}
return 0; return 0;
err: err:
qcom_ep_reset_assert(pcie); qcom_ep_reset_assert(pcie);
if (pcie->ops->post_deinit) if (pcie->ops->post_deinit)
...@@ -1361,14 +1435,25 @@ static const struct qcom_pcie_ops ops_2_7_0 = { ...@@ -1361,14 +1435,25 @@ static const struct qcom_pcie_ops ops_2_7_0 = {
.post_deinit = qcom_pcie_post_deinit_2_7_0, .post_deinit = qcom_pcie_post_deinit_2_7_0,
}; };
/* Qcom IP rev.: 1.9.0 */
static const struct qcom_pcie_ops ops_1_9_0 = {
.get_resources = qcom_pcie_get_resources_2_7_0,
.init = qcom_pcie_init_2_7_0,
.deinit = qcom_pcie_deinit_2_7_0,
.ltssm_enable = qcom_pcie_2_3_2_ltssm_enable,
.post_init = qcom_pcie_post_init_2_7_0,
.post_deinit = qcom_pcie_post_deinit_2_7_0,
.config_sid = qcom_pcie_config_sid_sm8250,
};
static const struct dw_pcie_ops dw_pcie_ops = { static const struct dw_pcie_ops dw_pcie_ops = {
.link_up = qcom_pcie_link_up, .link_up = qcom_pcie_link_up,
.start_link = qcom_pcie_start_link,
}; };
static int qcom_pcie_probe(struct platform_device *pdev) static int qcom_pcie_probe(struct platform_device *pdev)
{ {
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct resource *res;
struct pcie_port *pp; struct pcie_port *pp;
struct dw_pcie *pci; struct dw_pcie *pci;
struct qcom_pcie *pcie; struct qcom_pcie *pcie;
...@@ -1407,13 +1492,6 @@ static int qcom_pcie_probe(struct platform_device *pdev) ...@@ -1407,13 +1492,6 @@ static int qcom_pcie_probe(struct platform_device *pdev)
goto err_pm_runtime_put; goto err_pm_runtime_put;
} }
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi");
pci->dbi_base = devm_pci_remap_cfg_resource(dev, res);
if (IS_ERR(pci->dbi_base)) {
ret = PTR_ERR(pci->dbi_base);
goto err_pm_runtime_put;
}
pcie->elbi = devm_platform_ioremap_resource_byname(pdev, "elbi"); pcie->elbi = devm_platform_ioremap_resource_byname(pdev, "elbi");
if (IS_ERR(pcie->elbi)) { if (IS_ERR(pcie->elbi)) {
ret = PTR_ERR(pcie->elbi); ret = PTR_ERR(pcie->elbi);
...@@ -1432,14 +1510,6 @@ static int qcom_pcie_probe(struct platform_device *pdev) ...@@ -1432,14 +1510,6 @@ static int qcom_pcie_probe(struct platform_device *pdev)
pp->ops = &qcom_pcie_dw_ops; pp->ops = &qcom_pcie_dw_ops;
if (IS_ENABLED(CONFIG_PCI_MSI)) {
pp->msi_irq = platform_get_irq_byname(pdev, "msi");
if (pp->msi_irq < 0) {
ret = pp->msi_irq;
goto err_pm_runtime_put;
}
}
ret = phy_init(pcie->phy); ret = phy_init(pcie->phy);
if (ret) { if (ret) {
pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev);
...@@ -1474,6 +1544,7 @@ static const struct of_device_id qcom_pcie_match[] = { ...@@ -1474,6 +1544,7 @@ static const struct of_device_id qcom_pcie_match[] = {
{ .compatible = "qcom,pcie-ipq4019", .data = &ops_2_4_0 }, { .compatible = "qcom,pcie-ipq4019", .data = &ops_2_4_0 },
{ .compatible = "qcom,pcie-qcs404", .data = &ops_2_4_0 }, { .compatible = "qcom,pcie-qcs404", .data = &ops_2_4_0 },
{ .compatible = "qcom,pcie-sdm845", .data = &ops_2_7_0 }, { .compatible = "qcom,pcie-sdm845", .data = &ops_2_7_0 },
{ .compatible = "qcom,pcie-sm8250", .data = &ops_1_9_0 },
{ } { }
}; };
......
...@@ -66,32 +66,10 @@ struct pcie_app_reg { ...@@ -66,32 +66,10 @@ struct pcie_app_reg {
#define to_spear13xx_pcie(x) dev_get_drvdata((x)->dev) #define to_spear13xx_pcie(x) dev_get_drvdata((x)->dev)
static int spear13xx_pcie_establish_link(struct spear13xx_pcie *spear13xx_pcie) static int spear13xx_pcie_start_link(struct dw_pcie *pci)
{ {
struct dw_pcie *pci = spear13xx_pcie->pci; struct spear13xx_pcie *spear13xx_pcie = to_spear13xx_pcie(pci);
struct pcie_port *pp = &pci->pp;
struct pcie_app_reg *app_reg = spear13xx_pcie->app_base; struct pcie_app_reg *app_reg = spear13xx_pcie->app_base;
u32 val;
u32 exp_cap_off = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
if (dw_pcie_link_up(pci)) {
dev_err(pci->dev, "link already up\n");
return 0;
}
dw_pcie_setup_rc(pp);
/*
* this controller support only 128 bytes read size, however its
* default value in capability register is 512 bytes. So force
* it to 128 here.
*/
val = dw_pcie_readw_dbi(pci, exp_cap_off + PCI_EXP_DEVCTL);
val &= ~PCI_EXP_DEVCTL_READRQ;
dw_pcie_writew_dbi(pci, exp_cap_off + PCI_EXP_DEVCTL, val);
dw_pcie_writew_dbi(pci, PCI_VENDOR_ID, 0x104A);
dw_pcie_writew_dbi(pci, PCI_DEVICE_ID, 0xCD80);
/* enable ltssm */ /* enable ltssm */
writel(DEVICE_TYPE_RC | (1 << MISCTRL_EN_ID) writel(DEVICE_TYPE_RC | (1 << MISCTRL_EN_ID)
...@@ -99,7 +77,7 @@ static int spear13xx_pcie_establish_link(struct spear13xx_pcie *spear13xx_pcie) ...@@ -99,7 +77,7 @@ static int spear13xx_pcie_establish_link(struct spear13xx_pcie *spear13xx_pcie)
| ((u32)1 << REG_TRANSLATION_ENABLE), | ((u32)1 << REG_TRANSLATION_ENABLE),
&app_reg->app_ctrl_0); &app_reg->app_ctrl_0);
return dw_pcie_wait_for_link(pci); return 0;
} }
static irqreturn_t spear13xx_pcie_irq_handler(int irq, void *arg) static irqreturn_t spear13xx_pcie_irq_handler(int irq, void *arg)
...@@ -124,16 +102,12 @@ static irqreturn_t spear13xx_pcie_irq_handler(int irq, void *arg) ...@@ -124,16 +102,12 @@ static irqreturn_t spear13xx_pcie_irq_handler(int irq, void *arg)
static void spear13xx_pcie_enable_interrupts(struct spear13xx_pcie *spear13xx_pcie) static void spear13xx_pcie_enable_interrupts(struct spear13xx_pcie *spear13xx_pcie)
{ {
struct dw_pcie *pci = spear13xx_pcie->pci;
struct pcie_port *pp = &pci->pp;
struct pcie_app_reg *app_reg = spear13xx_pcie->app_base; struct pcie_app_reg *app_reg = spear13xx_pcie->app_base;
/* Enable MSI interrupt */ /* Enable MSI interrupt */
if (IS_ENABLED(CONFIG_PCI_MSI)) { if (IS_ENABLED(CONFIG_PCI_MSI))
dw_pcie_msi_init(pp);
writel(readl(&app_reg->int_mask) | writel(readl(&app_reg->int_mask) |
MSI_CTRL_INT, &app_reg->int_mask); MSI_CTRL_INT, &app_reg->int_mask);
}
} }
static int spear13xx_pcie_link_up(struct dw_pcie *pci) static int spear13xx_pcie_link_up(struct dw_pcie *pci)
...@@ -151,8 +125,23 @@ static int spear13xx_pcie_host_init(struct pcie_port *pp) ...@@ -151,8 +125,23 @@ static int spear13xx_pcie_host_init(struct pcie_port *pp)
{ {
struct dw_pcie *pci = to_dw_pcie_from_pp(pp); struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
struct spear13xx_pcie *spear13xx_pcie = to_spear13xx_pcie(pci); struct spear13xx_pcie *spear13xx_pcie = to_spear13xx_pcie(pci);
u32 exp_cap_off = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
u32 val;
spear13xx_pcie->app_base = pci->dbi_base + 0x2000;
/*
* this controller support only 128 bytes read size, however its
* default value in capability register is 512 bytes. So force
* it to 128 here.
*/
val = dw_pcie_readw_dbi(pci, exp_cap_off + PCI_EXP_DEVCTL);
val &= ~PCI_EXP_DEVCTL_READRQ;
dw_pcie_writew_dbi(pci, exp_cap_off + PCI_EXP_DEVCTL, val);
dw_pcie_writew_dbi(pci, PCI_VENDOR_ID, 0x104A);
dw_pcie_writew_dbi(pci, PCI_DEVICE_ID, 0xCD80);
spear13xx_pcie_establish_link(spear13xx_pcie);
spear13xx_pcie_enable_interrupts(spear13xx_pcie); spear13xx_pcie_enable_interrupts(spear13xx_pcie);
return 0; return 0;
...@@ -183,6 +172,7 @@ static int spear13xx_add_pcie_port(struct spear13xx_pcie *spear13xx_pcie, ...@@ -183,6 +172,7 @@ static int spear13xx_add_pcie_port(struct spear13xx_pcie *spear13xx_pcie,
} }
pp->ops = &spear13xx_pcie_host_ops; pp->ops = &spear13xx_pcie_host_ops;
pp->msi_irq = -ENODEV;
ret = dw_pcie_host_init(pp); ret = dw_pcie_host_init(pp);
if (ret) { if (ret) {
...@@ -195,6 +185,7 @@ static int spear13xx_add_pcie_port(struct spear13xx_pcie *spear13xx_pcie, ...@@ -195,6 +185,7 @@ static int spear13xx_add_pcie_port(struct spear13xx_pcie *spear13xx_pcie,
static const struct dw_pcie_ops dw_pcie_ops = { static const struct dw_pcie_ops dw_pcie_ops = {
.link_up = spear13xx_pcie_link_up, .link_up = spear13xx_pcie_link_up,
.start_link = spear13xx_pcie_start_link,
}; };
static int spear13xx_pcie_probe(struct platform_device *pdev) static int spear13xx_pcie_probe(struct platform_device *pdev)
...@@ -203,7 +194,6 @@ static int spear13xx_pcie_probe(struct platform_device *pdev) ...@@ -203,7 +194,6 @@ static int spear13xx_pcie_probe(struct platform_device *pdev)
struct dw_pcie *pci; struct dw_pcie *pci;
struct spear13xx_pcie *spear13xx_pcie; struct spear13xx_pcie *spear13xx_pcie;
struct device_node *np = dev->of_node; struct device_node *np = dev->of_node;
struct resource *dbi_base;
int ret; int ret;
spear13xx_pcie = devm_kzalloc(dev, sizeof(*spear13xx_pcie), GFP_KERNEL); spear13xx_pcie = devm_kzalloc(dev, sizeof(*spear13xx_pcie), GFP_KERNEL);
...@@ -242,14 +232,6 @@ static int spear13xx_pcie_probe(struct platform_device *pdev) ...@@ -242,14 +232,6 @@ static int spear13xx_pcie_probe(struct platform_device *pdev)
return ret; return ret;
} }
dbi_base = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi");
pci->dbi_base = devm_pci_remap_cfg_resource(dev, dbi_base);
if (IS_ERR(pci->dbi_base)) {
ret = PTR_ERR(pci->dbi_base);
goto fail_clk;
}
spear13xx_pcie->app_base = pci->dbi_base + 0x2000;
if (of_property_read_bool(np, "st,pcie-is-gen1")) if (of_property_read_bool(np, "st,pcie-is-gen1"))
pci->link_gen = 1; pci->link_gen = 1;
......
...@@ -765,8 +765,6 @@ static void tegra_pcie_enable_msi_interrupts(struct pcie_port *pp) ...@@ -765,8 +765,6 @@ static void tegra_pcie_enable_msi_interrupts(struct pcie_port *pp)
struct tegra_pcie_dw *pcie = to_tegra_pcie(pci); struct tegra_pcie_dw *pcie = to_tegra_pcie(pci);
u32 val; u32 val;
dw_pcie_msi_init(pp);
/* Enable MSI interrupt generation */ /* Enable MSI interrupt generation */
val = appl_readl(pcie, APPL_INTR_EN_L0_0); val = appl_readl(pcie, APPL_INTR_EN_L0_0);
val |= APPL_INTR_EN_L0_0_SYS_MSI_INTR_EN; val |= APPL_INTR_EN_L0_0_SYS_MSI_INTR_EN;
...@@ -861,6 +859,10 @@ static void tegra_pcie_prepare_host(struct pcie_port *pp) ...@@ -861,6 +859,10 @@ static void tegra_pcie_prepare_host(struct pcie_port *pp)
struct tegra_pcie_dw *pcie = to_tegra_pcie(pci); struct tegra_pcie_dw *pcie = to_tegra_pcie(pci);
u32 val; u32 val;
if (!pcie->pcie_cap_base)
pcie->pcie_cap_base = dw_pcie_find_capability(&pcie->pci,
PCI_CAP_ID_EXP);
val = dw_pcie_readl_dbi(pci, PCI_IO_BASE); val = dw_pcie_readl_dbi(pci, PCI_IO_BASE);
val &= ~(IO_BASE_IO_DECODE | IO_BASE_IO_DECODE_BIT8); val &= ~(IO_BASE_IO_DECODE | IO_BASE_IO_DECODE_BIT8);
dw_pcie_writel_dbi(pci, PCI_IO_BASE, val); dw_pcie_writel_dbi(pci, PCI_IO_BASE, val);
...@@ -889,6 +891,12 @@ static void tegra_pcie_prepare_host(struct pcie_port *pp) ...@@ -889,6 +891,12 @@ static void tegra_pcie_prepare_host(struct pcie_port *pp)
init_host_aspm(pcie); init_host_aspm(pcie);
/* Disable ASPM-L1SS advertisement if there is no CLKREQ routing */
if (!pcie->supports_clkreq) {
disable_aspm_l11(pcie);
disable_aspm_l12(pcie);
}
val = dw_pcie_readl_dbi(pci, GEN3_RELATED_OFF); val = dw_pcie_readl_dbi(pci, GEN3_RELATED_OFF);
val &= ~GEN3_RELATED_OFF_GEN3_ZRXDC_NONCOMPL; val &= ~GEN3_RELATED_OFF_GEN3_ZRXDC_NONCOMPL;
dw_pcie_writel_dbi(pci, GEN3_RELATED_OFF, val); dw_pcie_writel_dbi(pci, GEN3_RELATED_OFF, val);
...@@ -990,11 +998,6 @@ static int tegra_pcie_dw_link_up(struct dw_pcie *pci) ...@@ -990,11 +998,6 @@ static int tegra_pcie_dw_link_up(struct dw_pcie *pci)
return !!(val & PCI_EXP_LNKSTA_DLLLA); return !!(val & PCI_EXP_LNKSTA_DLLLA);
} }
static void tegra_pcie_set_msi_vec_num(struct pcie_port *pp)
{
pp->num_vectors = MAX_MSI_IRQS;
}
static int tegra_pcie_dw_start_link(struct dw_pcie *pci) static int tegra_pcie_dw_start_link(struct dw_pcie *pci)
{ {
struct tegra_pcie_dw *pcie = to_tegra_pcie(pci); struct tegra_pcie_dw *pcie = to_tegra_pcie(pci);
...@@ -1019,7 +1022,6 @@ static const struct dw_pcie_ops tegra_dw_pcie_ops = { ...@@ -1019,7 +1022,6 @@ static const struct dw_pcie_ops tegra_dw_pcie_ops = {
static struct dw_pcie_host_ops tegra_pcie_dw_host_ops = { static struct dw_pcie_host_ops tegra_pcie_dw_host_ops = {
.host_init = tegra_pcie_dw_host_init, .host_init = tegra_pcie_dw_host_init,
.set_num_vectors = tegra_pcie_set_msi_vec_num,
}; };
static void tegra_pcie_disable_phy(struct tegra_pcie_dw *pcie) static void tegra_pcie_disable_phy(struct tegra_pcie_dw *pcie)
...@@ -1061,9 +1063,16 @@ static int tegra_pcie_enable_phy(struct tegra_pcie_dw *pcie) ...@@ -1061,9 +1063,16 @@ static int tegra_pcie_enable_phy(struct tegra_pcie_dw *pcie)
static int tegra_pcie_dw_parse_dt(struct tegra_pcie_dw *pcie) static int tegra_pcie_dw_parse_dt(struct tegra_pcie_dw *pcie)
{ {
struct platform_device *pdev = to_platform_device(pcie->dev);
struct device_node *np = pcie->dev->of_node; struct device_node *np = pcie->dev->of_node;
int ret; int ret;
pcie->dbi_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi");
if (!pcie->dbi_res) {
dev_err(pcie->dev, "Failed to find \"dbi\" region\n");
return -ENODEV;
}
ret = of_property_read_u32(np, "nvidia,aspm-cmrt-us", &pcie->aspm_cmrt); ret = of_property_read_u32(np, "nvidia,aspm-cmrt-us", &pcie->aspm_cmrt);
if (ret < 0) { if (ret < 0) {
dev_info(pcie->dev, "Failed to read ASPM T_cmrt: %d\n", ret); dev_info(pcie->dev, "Failed to read ASPM T_cmrt: %d\n", ret);
...@@ -1390,15 +1399,6 @@ static int tegra_pcie_config_controller(struct tegra_pcie_dw *pcie, ...@@ -1390,15 +1399,6 @@ static int tegra_pcie_config_controller(struct tegra_pcie_dw *pcie,
reset_control_deassert(pcie->core_rst); reset_control_deassert(pcie->core_rst);
pcie->pcie_cap_base = dw_pcie_find_capability(&pcie->pci,
PCI_CAP_ID_EXP);
/* Disable ASPM-L1SS advertisement as there is no CLKREQ routing */
if (!pcie->supports_clkreq) {
disable_aspm_l11(pcie);
disable_aspm_l12(pcie);
}
return ret; return ret;
fail_phy: fail_phy:
...@@ -1415,43 +1415,32 @@ static int tegra_pcie_config_controller(struct tegra_pcie_dw *pcie, ...@@ -1415,43 +1415,32 @@ static int tegra_pcie_config_controller(struct tegra_pcie_dw *pcie,
return ret; return ret;
} }
static int __deinit_controller(struct tegra_pcie_dw *pcie) static void tegra_pcie_unconfig_controller(struct tegra_pcie_dw *pcie)
{ {
int ret; int ret;
ret = reset_control_assert(pcie->core_rst); ret = reset_control_assert(pcie->core_rst);
if (ret) { if (ret)
dev_err(pcie->dev, "Failed to assert \"core\" reset: %d\n", dev_err(pcie->dev, "Failed to assert \"core\" reset: %d\n", ret);
ret);
return ret;
}
tegra_pcie_disable_phy(pcie); tegra_pcie_disable_phy(pcie);
ret = reset_control_assert(pcie->core_apb_rst); ret = reset_control_assert(pcie->core_apb_rst);
if (ret) { if (ret)
dev_err(pcie->dev, "Failed to assert APB reset: %d\n", ret); dev_err(pcie->dev, "Failed to assert APB reset: %d\n", ret);
return ret;
}
clk_disable_unprepare(pcie->core_clk); clk_disable_unprepare(pcie->core_clk);
ret = regulator_disable(pcie->pex_ctl_supply); ret = regulator_disable(pcie->pex_ctl_supply);
if (ret) { if (ret)
dev_err(pcie->dev, "Failed to disable regulator: %d\n", ret); dev_err(pcie->dev, "Failed to disable regulator: %d\n", ret);
return ret;
}
tegra_pcie_disable_slot_regulators(pcie); tegra_pcie_disable_slot_regulators(pcie);
ret = tegra_pcie_bpmp_set_ctrl_state(pcie, false); ret = tegra_pcie_bpmp_set_ctrl_state(pcie, false);
if (ret) { if (ret)
dev_err(pcie->dev, "Failed to disable controller %d: %d\n", dev_err(pcie->dev, "Failed to disable controller %d: %d\n",
pcie->cid, ret); pcie->cid, ret);
return ret;
}
return ret;
} }
static int tegra_pcie_init_controller(struct tegra_pcie_dw *pcie) static int tegra_pcie_init_controller(struct tegra_pcie_dw *pcie)
...@@ -1475,7 +1464,8 @@ static int tegra_pcie_init_controller(struct tegra_pcie_dw *pcie) ...@@ -1475,7 +1464,8 @@ static int tegra_pcie_init_controller(struct tegra_pcie_dw *pcie)
return 0; return 0;
fail_host_init: fail_host_init:
return __deinit_controller(pcie); tegra_pcie_unconfig_controller(pcie);
return ret;
} }
static int tegra_pcie_try_link_l2(struct tegra_pcie_dw *pcie) static int tegra_pcie_try_link_l2(struct tegra_pcie_dw *pcie)
...@@ -1516,6 +1506,14 @@ static void tegra_pcie_dw_pme_turnoff(struct tegra_pcie_dw *pcie) ...@@ -1516,6 +1506,14 @@ static void tegra_pcie_dw_pme_turnoff(struct tegra_pcie_dw *pcie)
data &= ~APPL_PINMUX_PEX_RST; data &= ~APPL_PINMUX_PEX_RST;
appl_writel(pcie, data, APPL_PINMUX); appl_writel(pcie, data, APPL_PINMUX);
/*
* Some cards do not go to detect state even after de-asserting
* PERST#. So, de-assert LTSSM to bring link to detect state.
*/
data = readl(pcie->appl_base + APPL_CTRL);
data &= ~APPL_CTRL_LTSSM_EN;
writel(data, pcie->appl_base + APPL_CTRL);
err = readl_poll_timeout_atomic(pcie->appl_base + APPL_DEBUG, err = readl_poll_timeout_atomic(pcie->appl_base + APPL_DEBUG,
data, data,
((data & ((data &
...@@ -1523,14 +1521,8 @@ static void tegra_pcie_dw_pme_turnoff(struct tegra_pcie_dw *pcie) ...@@ -1523,14 +1521,8 @@ static void tegra_pcie_dw_pme_turnoff(struct tegra_pcie_dw *pcie)
APPL_DEBUG_LTSSM_STATE_SHIFT) == APPL_DEBUG_LTSSM_STATE_SHIFT) ==
LTSSM_STATE_PRE_DETECT, LTSSM_STATE_PRE_DETECT,
1, LTSSM_TIMEOUT); 1, LTSSM_TIMEOUT);
if (err) { if (err)
dev_info(pcie->dev, "Link didn't go to detect state\n"); dev_info(pcie->dev, "Link didn't go to detect state\n");
} else {
/* Disable LTSSM after link is in detect state */
data = appl_readl(pcie, APPL_CTRL);
data &= ~APPL_CTRL_LTSSM_EN;
appl_writel(pcie, data, APPL_CTRL);
}
} }
/* /*
* DBI registers may not be accessible after this as PLL-E would be * DBI registers may not be accessible after this as PLL-E would be
...@@ -1544,30 +1536,20 @@ static void tegra_pcie_dw_pme_turnoff(struct tegra_pcie_dw *pcie) ...@@ -1544,30 +1536,20 @@ static void tegra_pcie_dw_pme_turnoff(struct tegra_pcie_dw *pcie)
appl_writel(pcie, data, APPL_PINMUX); appl_writel(pcie, data, APPL_PINMUX);
} }
static int tegra_pcie_deinit_controller(struct tegra_pcie_dw *pcie) static void tegra_pcie_deinit_controller(struct tegra_pcie_dw *pcie)
{ {
tegra_pcie_downstream_dev_to_D0(pcie); tegra_pcie_downstream_dev_to_D0(pcie);
dw_pcie_host_deinit(&pcie->pci.pp); dw_pcie_host_deinit(&pcie->pci.pp);
tegra_pcie_dw_pme_turnoff(pcie); tegra_pcie_dw_pme_turnoff(pcie);
tegra_pcie_unconfig_controller(pcie);
return __deinit_controller(pcie);
} }
static int tegra_pcie_config_rp(struct tegra_pcie_dw *pcie) static int tegra_pcie_config_rp(struct tegra_pcie_dw *pcie)
{ {
struct pcie_port *pp = &pcie->pci.pp;
struct device *dev = pcie->dev; struct device *dev = pcie->dev;
char *name; char *name;
int ret; int ret;
if (IS_ENABLED(CONFIG_PCI_MSI)) {
pp->msi_irq = of_irq_get_byname(dev->of_node, "msi");
if (!pp->msi_irq) {
dev_err(dev, "Failed to get MSI interrupt\n");
return -ENODEV;
}
}
pm_runtime_enable(dev); pm_runtime_enable(dev);
ret = pm_runtime_get_sync(dev); ret = pm_runtime_get_sync(dev);
...@@ -1583,7 +1565,11 @@ static int tegra_pcie_config_rp(struct tegra_pcie_dw *pcie) ...@@ -1583,7 +1565,11 @@ static int tegra_pcie_config_rp(struct tegra_pcie_dw *pcie)
goto fail_pm_get_sync; goto fail_pm_get_sync;
} }
tegra_pcie_init_controller(pcie); ret = tegra_pcie_init_controller(pcie);
if (ret < 0) {
dev_err(dev, "Failed to initialize controller: %d\n", ret);
goto fail_pm_get_sync;
}
pcie->link_state = tegra_pcie_dw_link_up(&pcie->pci); pcie->link_state = tegra_pcie_dw_link_up(&pcie->pci);
if (!pcie->link_state) { if (!pcie->link_state) {
...@@ -1907,19 +1893,12 @@ static int tegra_pcie_config_ep(struct tegra_pcie_dw *pcie, ...@@ -1907,19 +1893,12 @@ static int tegra_pcie_config_ep(struct tegra_pcie_dw *pcie,
struct dw_pcie *pci = &pcie->pci; struct dw_pcie *pci = &pcie->pci;
struct device *dev = pcie->dev; struct device *dev = pcie->dev;
struct dw_pcie_ep *ep; struct dw_pcie_ep *ep;
struct resource *res;
char *name; char *name;
int ret; int ret;
ep = &pci->ep; ep = &pci->ep;
ep->ops = &pcie_ep_ops; ep->ops = &pcie_ep_ops;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "addr_space");
if (!res)
return -EINVAL;
ep->phys_base = res->start;
ep->addr_size = resource_size(res);
ep->page_size = SZ_64K; ep->page_size = SZ_64K;
ret = gpiod_set_debounce(pcie->pex_rst_gpiod, PERST_DEBOUNCE_TIME); ret = gpiod_set_debounce(pcie->pex_rst_gpiod, PERST_DEBOUNCE_TIME);
...@@ -1982,7 +1961,6 @@ static int tegra_pcie_dw_probe(struct platform_device *pdev) ...@@ -1982,7 +1961,6 @@ static int tegra_pcie_dw_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct resource *atu_dma_res; struct resource *atu_dma_res;
struct tegra_pcie_dw *pcie; struct tegra_pcie_dw *pcie;
struct resource *dbi_res;
struct pcie_port *pp; struct pcie_port *pp;
struct dw_pcie *pci; struct dw_pcie *pci;
struct phy **phys; struct phy **phys;
...@@ -2001,8 +1979,10 @@ static int tegra_pcie_dw_probe(struct platform_device *pdev) ...@@ -2001,8 +1979,10 @@ static int tegra_pcie_dw_probe(struct platform_device *pdev)
pci->ops = &tegra_dw_pcie_ops; pci->ops = &tegra_dw_pcie_ops;
pci->n_fts[0] = N_FTS_VAL; pci->n_fts[0] = N_FTS_VAL;
pci->n_fts[1] = FTS_VAL; pci->n_fts[1] = FTS_VAL;
pci->version = 0x490A;
pp = &pci->pp; pp = &pci->pp;
pp->num_vectors = MAX_MSI_IRQS;
pcie->dev = &pdev->dev; pcie->dev = &pdev->dev;
pcie->mode = (enum dw_pcie_device_mode)data->mode; pcie->mode = (enum dw_pcie_device_mode)data->mode;
...@@ -2091,20 +2071,6 @@ static int tegra_pcie_dw_probe(struct platform_device *pdev) ...@@ -2091,20 +2071,6 @@ static int tegra_pcie_dw_probe(struct platform_device *pdev)
pcie->phys = phys; pcie->phys = phys;
dbi_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi");
if (!dbi_res) {
dev_err(dev, "Failed to find \"dbi\" region\n");
return -ENODEV;
}
pcie->dbi_res = dbi_res;
pci->dbi_base = devm_ioremap_resource(dev, dbi_res);
if (IS_ERR(pci->dbi_base))
return PTR_ERR(pci->dbi_base);
/* Tegra HW locates DBI2 at a fixed offset from DBI */
pci->dbi_base2 = pci->dbi_base + 0x1000;
atu_dma_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, atu_dma_res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"atu_dma"); "atu_dma");
if (!atu_dma_res) { if (!atu_dma_res) {
...@@ -2113,6 +2079,7 @@ static int tegra_pcie_dw_probe(struct platform_device *pdev) ...@@ -2113,6 +2079,7 @@ static int tegra_pcie_dw_probe(struct platform_device *pdev)
} }
pcie->atu_dma_res = atu_dma_res; pcie->atu_dma_res = atu_dma_res;
pci->atu_size = resource_size(atu_dma_res);
pci->atu_base = devm_ioremap_resource(dev, atu_dma_res); pci->atu_base = devm_ioremap_resource(dev, atu_dma_res);
if (IS_ERR(pci->atu_base)) if (IS_ERR(pci->atu_base))
return PTR_ERR(pci->atu_base); return PTR_ERR(pci->atu_base);
...@@ -2225,8 +2192,9 @@ static int tegra_pcie_dw_suspend_noirq(struct device *dev) ...@@ -2225,8 +2192,9 @@ static int tegra_pcie_dw_suspend_noirq(struct device *dev)
PORT_LOGIC_MSI_CTRL_INT_0_EN); PORT_LOGIC_MSI_CTRL_INT_0_EN);
tegra_pcie_downstream_dev_to_D0(pcie); tegra_pcie_downstream_dev_to_D0(pcie);
tegra_pcie_dw_pme_turnoff(pcie); tegra_pcie_dw_pme_turnoff(pcie);
tegra_pcie_unconfig_controller(pcie);
return __deinit_controller(pcie); return 0;
} }
static int tegra_pcie_dw_resume_noirq(struct device *dev) static int tegra_pcie_dw_resume_noirq(struct device *dev)
...@@ -2254,7 +2222,8 @@ static int tegra_pcie_dw_resume_noirq(struct device *dev) ...@@ -2254,7 +2222,8 @@ static int tegra_pcie_dw_resume_noirq(struct device *dev)
return 0; return 0;
fail_host_init: fail_host_init:
return __deinit_controller(pcie); tegra_pcie_unconfig_controller(pcie);
return ret;
} }
static int tegra_pcie_dw_resume_early(struct device *dev) static int tegra_pcie_dw_resume_early(struct device *dev)
...@@ -2292,7 +2261,7 @@ static void tegra_pcie_dw_shutdown(struct platform_device *pdev) ...@@ -2292,7 +2261,7 @@ static void tegra_pcie_dw_shutdown(struct platform_device *pdev)
disable_irq(pcie->pci.pp.msi_irq); disable_irq(pcie->pci.pp.msi_irq);
tegra_pcie_dw_pme_turnoff(pcie); tegra_pcie_dw_pme_turnoff(pcie);
__deinit_controller(pcie); tegra_pcie_unconfig_controller(pcie);
} }
static const struct tegra_pcie_dw_of_data tegra_pcie_dw_rc_of_data = { static const struct tegra_pcie_dw_of_data tegra_pcie_dw_rc_of_data = {
......
...@@ -218,35 +218,6 @@ static const struct dw_pcie_ep_ops uniphier_pcie_ep_ops = { ...@@ -218,35 +218,6 @@ static const struct dw_pcie_ep_ops uniphier_pcie_ep_ops = {
.get_features = uniphier_pcie_get_features, .get_features = uniphier_pcie_get_features,
}; };
static int uniphier_add_pcie_ep(struct uniphier_pcie_ep_priv *priv,
struct platform_device *pdev)
{
struct dw_pcie *pci = &priv->pci;
struct dw_pcie_ep *ep = &pci->ep;
struct device *dev = &pdev->dev;
struct resource *res;
int ret;
ep->ops = &uniphier_pcie_ep_ops;
pci->dbi_base2 = devm_platform_ioremap_resource_byname(pdev, "dbi2");
if (IS_ERR(pci->dbi_base2))
return PTR_ERR(pci->dbi_base2);
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "addr_space");
if (!res)
return -EINVAL;
ep->phys_base = res->start;
ep->addr_size = resource_size(res);
ret = dw_pcie_ep_init(ep);
if (ret)
dev_err(dev, "Failed to initialize endpoint (%d)\n", ret);
return ret;
}
static int uniphier_pcie_ep_enable(struct uniphier_pcie_ep_priv *priv) static int uniphier_pcie_ep_enable(struct uniphier_pcie_ep_priv *priv)
{ {
int ret; int ret;
...@@ -300,7 +271,6 @@ static int uniphier_pcie_ep_probe(struct platform_device *pdev) ...@@ -300,7 +271,6 @@ static int uniphier_pcie_ep_probe(struct platform_device *pdev)
{ {
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct uniphier_pcie_ep_priv *priv; struct uniphier_pcie_ep_priv *priv;
struct resource *res;
int ret; int ret;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
...@@ -314,11 +284,6 @@ static int uniphier_pcie_ep_probe(struct platform_device *pdev) ...@@ -314,11 +284,6 @@ static int uniphier_pcie_ep_probe(struct platform_device *pdev)
priv->pci.dev = dev; priv->pci.dev = dev;
priv->pci.ops = &dw_pcie_ops; priv->pci.ops = &dw_pcie_ops;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi");
priv->pci.dbi_base = devm_pci_remap_cfg_resource(dev, res);
if (IS_ERR(priv->pci.dbi_base))
return PTR_ERR(priv->pci.dbi_base);
priv->base = devm_platform_ioremap_resource_byname(pdev, "link"); priv->base = devm_platform_ioremap_resource_byname(pdev, "link");
if (IS_ERR(priv->base)) if (IS_ERR(priv->base))
return PTR_ERR(priv->base); return PTR_ERR(priv->base);
...@@ -352,7 +317,8 @@ static int uniphier_pcie_ep_probe(struct platform_device *pdev) ...@@ -352,7 +317,8 @@ static int uniphier_pcie_ep_probe(struct platform_device *pdev)
if (ret) if (ret)
return ret; return ret;
return uniphier_add_pcie_ep(priv, pdev); priv->pci.ep.ops = &uniphier_pcie_ep_ops;
return dw_pcie_ep_init(&priv->pci.ep);
} }
static const struct pci_epc_features uniphier_pro5_data = { static const struct pci_epc_features uniphier_pro5_data = {
......
...@@ -146,16 +146,13 @@ static int uniphier_pcie_link_up(struct dw_pcie *pci) ...@@ -146,16 +146,13 @@ static int uniphier_pcie_link_up(struct dw_pcie *pci)
return (val & mask) == mask; return (val & mask) == mask;
} }
static int uniphier_pcie_establish_link(struct dw_pcie *pci) static int uniphier_pcie_start_link(struct dw_pcie *pci)
{ {
struct uniphier_pcie_priv *priv = to_uniphier_pcie(pci); struct uniphier_pcie_priv *priv = to_uniphier_pcie(pci);
if (dw_pcie_link_up(pci))
return 0;
uniphier_pcie_ltssm_enable(priv, true); uniphier_pcie_ltssm_enable(priv, true);
return dw_pcie_wait_for_link(pci); return 0;
} }
static void uniphier_pcie_stop_link(struct dw_pcie *pci) static void uniphier_pcie_stop_link(struct dw_pcie *pci)
...@@ -317,13 +314,6 @@ static int uniphier_pcie_host_init(struct pcie_port *pp) ...@@ -317,13 +314,6 @@ static int uniphier_pcie_host_init(struct pcie_port *pp)
uniphier_pcie_irq_enable(priv); uniphier_pcie_irq_enable(priv);
dw_pcie_setup_rc(pp);
ret = uniphier_pcie_establish_link(pci);
if (ret)
return ret;
dw_pcie_msi_init(pp);
return 0; return 0;
} }
...@@ -331,31 +321,6 @@ static const struct dw_pcie_host_ops uniphier_pcie_host_ops = { ...@@ -331,31 +321,6 @@ static const struct dw_pcie_host_ops uniphier_pcie_host_ops = {
.host_init = uniphier_pcie_host_init, .host_init = uniphier_pcie_host_init,
}; };
static int uniphier_add_pcie_port(struct uniphier_pcie_priv *priv,
struct platform_device *pdev)
{
struct dw_pcie *pci = &priv->pci;
struct pcie_port *pp = &pci->pp;
struct device *dev = &pdev->dev;
int ret;
pp->ops = &uniphier_pcie_host_ops;
if (IS_ENABLED(CONFIG_PCI_MSI)) {
pp->msi_irq = platform_get_irq_byname(pdev, "msi");
if (pp->msi_irq < 0)
return pp->msi_irq;
}
ret = dw_pcie_host_init(pp);
if (ret) {
dev_err(dev, "Failed to initialize host (%d)\n", ret);
return ret;
}
return 0;
}
static int uniphier_pcie_host_enable(struct uniphier_pcie_priv *priv) static int uniphier_pcie_host_enable(struct uniphier_pcie_priv *priv)
{ {
int ret; int ret;
...@@ -391,7 +356,7 @@ static int uniphier_pcie_host_enable(struct uniphier_pcie_priv *priv) ...@@ -391,7 +356,7 @@ static int uniphier_pcie_host_enable(struct uniphier_pcie_priv *priv)
} }
static const struct dw_pcie_ops dw_pcie_ops = { static const struct dw_pcie_ops dw_pcie_ops = {
.start_link = uniphier_pcie_establish_link, .start_link = uniphier_pcie_start_link,
.stop_link = uniphier_pcie_stop_link, .stop_link = uniphier_pcie_stop_link,
.link_up = uniphier_pcie_link_up, .link_up = uniphier_pcie_link_up,
}; };
...@@ -400,7 +365,6 @@ static int uniphier_pcie_probe(struct platform_device *pdev) ...@@ -400,7 +365,6 @@ static int uniphier_pcie_probe(struct platform_device *pdev)
{ {
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct uniphier_pcie_priv *priv; struct uniphier_pcie_priv *priv;
struct resource *res;
int ret; int ret;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
...@@ -410,11 +374,6 @@ static int uniphier_pcie_probe(struct platform_device *pdev) ...@@ -410,11 +374,6 @@ static int uniphier_pcie_probe(struct platform_device *pdev)
priv->pci.dev = dev; priv->pci.dev = dev;
priv->pci.ops = &dw_pcie_ops; priv->pci.ops = &dw_pcie_ops;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi");
priv->pci.dbi_base = devm_pci_remap_cfg_resource(dev, res);
if (IS_ERR(priv->pci.dbi_base))
return PTR_ERR(priv->pci.dbi_base);
priv->base = devm_platform_ioremap_resource_byname(pdev, "link"); priv->base = devm_platform_ioremap_resource_byname(pdev, "link");
if (IS_ERR(priv->base)) if (IS_ERR(priv->base))
return PTR_ERR(priv->base); return PTR_ERR(priv->base);
...@@ -437,7 +396,9 @@ static int uniphier_pcie_probe(struct platform_device *pdev) ...@@ -437,7 +396,9 @@ static int uniphier_pcie_probe(struct platform_device *pdev)
if (ret) if (ret)
return ret; return ret;
return uniphier_add_pcie_port(priv, pdev); priv->pci.pp.ops = &uniphier_pcie_host_ops;
return dw_pcie_host_init(&priv->pci.pp);
} }
static const struct of_device_id uniphier_pcie_match[] = { static const struct of_device_id uniphier_pcie_match[] = {
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/pci-ecam.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/phy/phy.h> #include <linux/phy/phy.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
...@@ -164,14 +165,6 @@ ...@@ -164,14 +165,6 @@
#define PCIE_CONFIG_WR_TYPE0 0xa #define PCIE_CONFIG_WR_TYPE0 0xa
#define PCIE_CONFIG_WR_TYPE1 0xb #define PCIE_CONFIG_WR_TYPE1 0xb
#define PCIE_CONF_BUS(bus) (((bus) & 0xff) << 20)
#define PCIE_CONF_DEV(dev) (((dev) & 0x1f) << 15)
#define PCIE_CONF_FUNC(fun) (((fun) & 0x7) << 12)
#define PCIE_CONF_REG(reg) ((reg) & 0xffc)
#define PCIE_CONF_ADDR(bus, devfn, where) \
(PCIE_CONF_BUS(bus) | PCIE_CONF_DEV(PCI_SLOT(devfn)) | \
PCIE_CONF_FUNC(PCI_FUNC(devfn)) | PCIE_CONF_REG(where))
#define PIO_RETRY_CNT 500 #define PIO_RETRY_CNT 500
#define PIO_RETRY_DELAY 2 /* 2 us*/ #define PIO_RETRY_DELAY 2 /* 2 us*/
...@@ -259,7 +252,14 @@ static void advk_pcie_issue_perst(struct advk_pcie *pcie) ...@@ -259,7 +252,14 @@ static void advk_pcie_issue_perst(struct advk_pcie *pcie)
if (!pcie->reset_gpio) if (!pcie->reset_gpio)
return; return;
/* PERST does not work for some cards when link training is enabled */ /*
* As required by PCI Express spec (PCI Express Base Specification, REV.
* 4.0 PCI Express, February 19 2014, 6.6.1 Conventional Reset) a delay
* for at least 100ms after de-asserting PERST# signal is needed before
* link training is enabled. So ensure that link training is disabled
* prior de-asserting PERST# signal to fulfill that PCI Express spec
* requirement.
*/
reg = advk_readl(pcie, PCIE_CORE_CTRL0_REG); reg = advk_readl(pcie, PCIE_CORE_CTRL0_REG);
reg &= ~LINK_TRAINING_EN; reg &= ~LINK_TRAINING_EN;
advk_writel(pcie, reg, PCIE_CORE_CTRL0_REG); advk_writel(pcie, reg, PCIE_CORE_CTRL0_REG);
...@@ -687,7 +687,7 @@ static int advk_pcie_rd_conf(struct pci_bus *bus, u32 devfn, ...@@ -687,7 +687,7 @@ static int advk_pcie_rd_conf(struct pci_bus *bus, u32 devfn,
advk_writel(pcie, reg, PIO_CTRL); advk_writel(pcie, reg, PIO_CTRL);
/* Program the address registers */ /* Program the address registers */
reg = PCIE_CONF_ADDR(bus->number, devfn, where); reg = ALIGN_DOWN(PCIE_ECAM_OFFSET(bus->number, devfn, where), 4);
advk_writel(pcie, reg, PIO_ADDR_LS); advk_writel(pcie, reg, PIO_ADDR_LS);
advk_writel(pcie, 0, PIO_ADDR_MS); advk_writel(pcie, 0, PIO_ADDR_MS);
...@@ -748,7 +748,7 @@ static int advk_pcie_wr_conf(struct pci_bus *bus, u32 devfn, ...@@ -748,7 +748,7 @@ static int advk_pcie_wr_conf(struct pci_bus *bus, u32 devfn,
advk_writel(pcie, reg, PIO_CTRL); advk_writel(pcie, reg, PIO_CTRL);
/* Program the address registers */ /* Program the address registers */
reg = PCIE_CONF_ADDR(bus->number, devfn, where); reg = ALIGN_DOWN(PCIE_ECAM_OFFSET(bus->number, devfn, where), 4);
advk_writel(pcie, reg, PIO_ADDR_LS); advk_writel(pcie, reg, PIO_ADDR_LS);
advk_writel(pcie, 0, PIO_ADDR_MS); advk_writel(pcie, 0, PIO_ADDR_MS);
......
...@@ -49,7 +49,6 @@ static void __iomem *pci_dw_ecam_map_bus(struct pci_bus *bus, ...@@ -49,7 +49,6 @@ static void __iomem *pci_dw_ecam_map_bus(struct pci_bus *bus,
} }
static const struct pci_ecam_ops pci_dw_ecam_bus_ops = { static const struct pci_ecam_ops pci_dw_ecam_bus_ops = {
.bus_shift = 20,
.pci_ops = { .pci_ops = {
.map_bus = pci_dw_ecam_map_bus, .map_bus = pci_dw_ecam_map_bus,
.read = pci_generic_config_read, .read = pci_generic_config_read,
......
...@@ -346,7 +346,6 @@ static int thunder_ecam_config_write(struct pci_bus *bus, unsigned int devfn, ...@@ -346,7 +346,6 @@ static int thunder_ecam_config_write(struct pci_bus *bus, unsigned int devfn,
} }
const struct pci_ecam_ops pci_thunder_ecam_ops = { const struct pci_ecam_ops pci_thunder_ecam_ops = {
.bus_shift = 20,
.pci_ops = { .pci_ops = {
.map_bus = pci_ecam_map_bus, .map_bus = pci_ecam_map_bus,
.read = thunder_ecam_config_read, .read = thunder_ecam_config_read,
......
...@@ -19,6 +19,15 @@ ...@@ -19,6 +19,15 @@
#define PEM_CFG_WR 0x28 #define PEM_CFG_WR 0x28
#define PEM_CFG_RD 0x30 #define PEM_CFG_RD 0x30
/*
* Enhanced Configuration Access Mechanism (ECAM)
*
* N.B. This is a non-standard platform-specific ECAM bus shift value. For
* standard values defined in the PCI Express Base Specification see
* include/linux/pci-ecam.h.
*/
#define THUNDER_PCIE_ECAM_BUS_SHIFT 24
struct thunder_pem_pci { struct thunder_pem_pci {
u32 ea_entry[3]; u32 ea_entry[3];
void __iomem *pem_reg_base; void __iomem *pem_reg_base;
...@@ -404,7 +413,7 @@ static int thunder_pem_acpi_init(struct pci_config_window *cfg) ...@@ -404,7 +413,7 @@ static int thunder_pem_acpi_init(struct pci_config_window *cfg)
} }
const struct pci_ecam_ops thunder_pem_ecam_ops = { const struct pci_ecam_ops thunder_pem_ecam_ops = {
.bus_shift = 24, .bus_shift = THUNDER_PCIE_ECAM_BUS_SHIFT,
.init = thunder_pem_acpi_init, .init = thunder_pem_acpi_init,
.pci_ops = { .pci_ops = {
.map_bus = pci_ecam_map_bus, .map_bus = pci_ecam_map_bus,
...@@ -441,7 +450,7 @@ static int thunder_pem_platform_init(struct pci_config_window *cfg) ...@@ -441,7 +450,7 @@ static int thunder_pem_platform_init(struct pci_config_window *cfg)
} }
static const struct pci_ecam_ops pci_thunder_pem_ops = { static const struct pci_ecam_ops pci_thunder_pem_ops = {
.bus_shift = 24, .bus_shift = THUNDER_PCIE_ECAM_BUS_SHIFT,
.init = thunder_pem_platform_init, .init = thunder_pem_platform_init,
.pci_ops = { .pci_ops = {
.map_bus = pci_ecam_map_bus, .map_bus = pci_ecam_map_bus,
......
...@@ -257,7 +257,6 @@ static int xgene_v1_pcie_ecam_init(struct pci_config_window *cfg) ...@@ -257,7 +257,6 @@ static int xgene_v1_pcie_ecam_init(struct pci_config_window *cfg)
} }
const struct pci_ecam_ops xgene_v1_pcie_ecam_ops = { const struct pci_ecam_ops xgene_v1_pcie_ecam_ops = {
.bus_shift = 16,
.init = xgene_v1_pcie_ecam_init, .init = xgene_v1_pcie_ecam_init,
.pci_ops = { .pci_ops = {
.map_bus = xgene_pcie_map_bus, .map_bus = xgene_pcie_map_bus,
...@@ -272,7 +271,6 @@ static int xgene_v2_pcie_ecam_init(struct pci_config_window *cfg) ...@@ -272,7 +271,6 @@ static int xgene_v2_pcie_ecam_init(struct pci_config_window *cfg)
} }
const struct pci_ecam_ops xgene_v2_pcie_ecam_ops = { const struct pci_ecam_ops xgene_v2_pcie_ecam_ops = {
.bus_shift = 16,
.init = xgene_v2_pcie_ecam_init, .init = xgene_v2_pcie_ecam_init,
.pci_ops = { .pci_ops = {
.map_bus = xgene_pcie_map_bus, .map_bus = xgene_pcie_map_bus,
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include <linux/of_pci.h> #include <linux/of_pci.h>
#include <linux/of_platform.h> #include <linux/of_platform.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/pci-ecam.h>
#include <linux/printk.h> #include <linux/printk.h>
#include <linux/reset.h> #include <linux/reset.h>
#include <linux/sizes.h> #include <linux/sizes.h>
...@@ -127,11 +128,7 @@ ...@@ -127,11 +128,7 @@
#define MSI_INT_MASK_CLR 0x14 #define MSI_INT_MASK_CLR 0x14
#define PCIE_EXT_CFG_DATA 0x8000 #define PCIE_EXT_CFG_DATA 0x8000
#define PCIE_EXT_CFG_INDEX 0x9000 #define PCIE_EXT_CFG_INDEX 0x9000
#define PCIE_EXT_BUSNUM_SHIFT 20
#define PCIE_EXT_SLOT_SHIFT 15
#define PCIE_EXT_FUNC_SHIFT 12
#define PCIE_RGR1_SW_INIT_1_PERST_MASK 0x1 #define PCIE_RGR1_SW_INIT_1_PERST_MASK 0x1
#define PCIE_RGR1_SW_INIT_1_PERST_SHIFT 0x0 #define PCIE_RGR1_SW_INIT_1_PERST_SHIFT 0x0
...@@ -695,15 +692,6 @@ static bool brcm_pcie_link_up(struct brcm_pcie *pcie) ...@@ -695,15 +692,6 @@ static bool brcm_pcie_link_up(struct brcm_pcie *pcie)
return dla && plu; return dla && plu;
} }
/* Configuration space read/write support */
static inline int brcm_pcie_cfg_index(int busnr, int devfn, int reg)
{
return ((PCI_SLOT(devfn) & 0x1f) << PCIE_EXT_SLOT_SHIFT)
| ((PCI_FUNC(devfn) & 0x07) << PCIE_EXT_FUNC_SHIFT)
| (busnr << PCIE_EXT_BUSNUM_SHIFT)
| (reg & ~3);
}
static void __iomem *brcm_pcie_map_conf(struct pci_bus *bus, unsigned int devfn, static void __iomem *brcm_pcie_map_conf(struct pci_bus *bus, unsigned int devfn,
int where) int where)
{ {
...@@ -716,7 +704,7 @@ static void __iomem *brcm_pcie_map_conf(struct pci_bus *bus, unsigned int devfn, ...@@ -716,7 +704,7 @@ static void __iomem *brcm_pcie_map_conf(struct pci_bus *bus, unsigned int devfn,
return PCI_SLOT(devfn) ? NULL : base + where; return PCI_SLOT(devfn) ? NULL : base + where;
/* For devices, write to the config space index register */ /* For devices, write to the config space index register */
idx = brcm_pcie_cfg_index(bus->number, devfn, 0); idx = PCIE_ECAM_OFFSET(bus->number, devfn, 0);
writel(idx, pcie->base + PCIE_EXT_CFG_INDEX); writel(idx, pcie->base + PCIE_EXT_CFG_INDEX);
return base + PCIE_EXT_CFG_DATA + where; return base + PCIE_EXT_CFG_DATA + where;
} }
...@@ -893,6 +881,7 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie) ...@@ -893,6 +881,7 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie)
burst = 0x2; /* 512 bytes */ burst = 0x2; /* 512 bytes */
/* Set SCB_MAX_BURST_SIZE, CFG_READ_UR_MODE, SCB_ACCESS_EN */ /* Set SCB_MAX_BURST_SIZE, CFG_READ_UR_MODE, SCB_ACCESS_EN */
tmp = readl(base + PCIE_MISC_MISC_CTRL);
u32p_replace_bits(&tmp, 1, PCIE_MISC_MISC_CTRL_SCB_ACCESS_EN_MASK); u32p_replace_bits(&tmp, 1, PCIE_MISC_MISC_CTRL_SCB_ACCESS_EN_MASK);
u32p_replace_bits(&tmp, 1, PCIE_MISC_MISC_CTRL_CFG_READ_UR_MODE_MASK); u32p_replace_bits(&tmp, 1, PCIE_MISC_MISC_CTRL_CFG_READ_UR_MODE_MASK);
u32p_replace_bits(&tmp, burst, PCIE_MISC_MISC_CTRL_MAX_BURST_SIZE_MASK); u32p_replace_bits(&tmp, burst, PCIE_MISC_MISC_CTRL_MAX_BURST_SIZE_MASK);
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/pci-ecam.h>
#include <linux/msi.h> #include <linux/msi.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/module.h> #include <linux/module.h>
...@@ -39,16 +40,8 @@ ...@@ -39,16 +40,8 @@
#define CFG_IND_ADDR_MASK 0x00001ffc #define CFG_IND_ADDR_MASK 0x00001ffc
#define CFG_ADDR_BUS_NUM_SHIFT 20
#define CFG_ADDR_BUS_NUM_MASK 0x0ff00000
#define CFG_ADDR_DEV_NUM_SHIFT 15
#define CFG_ADDR_DEV_NUM_MASK 0x000f8000
#define CFG_ADDR_FUNC_NUM_SHIFT 12
#define CFG_ADDR_FUNC_NUM_MASK 0x00007000
#define CFG_ADDR_REG_NUM_SHIFT 2
#define CFG_ADDR_REG_NUM_MASK 0x00000ffc #define CFG_ADDR_REG_NUM_MASK 0x00000ffc
#define CFG_ADDR_CFG_TYPE_SHIFT 0 #define CFG_ADDR_CFG_TYPE_1 1
#define CFG_ADDR_CFG_TYPE_MASK 0x00000003
#define SYS_RC_INTX_MASK 0xf #define SYS_RC_INTX_MASK 0xf
...@@ -192,8 +185,15 @@ static const struct iproc_pcie_ib_map paxb_v2_ib_map[] = { ...@@ -192,8 +185,15 @@ static const struct iproc_pcie_ib_map paxb_v2_ib_map[] = {
.imap_window_offset = 0x4, .imap_window_offset = 0x4,
}, },
{ {
/* IARR1/IMAP1 (currently unused) */ /* IARR1/IMAP1 */
.type = IPROC_PCIE_IB_MAP_INVALID, .type = IPROC_PCIE_IB_MAP_MEM,
.size_unit = SZ_1M,
.region_sizes = { 8 },
.nr_sizes = 1,
.nr_windows = 8,
.imap_addr_offset = 0x4,
.imap_window_offset = 0x8,
}, },
{ {
/* IARR2/IMAP2 */ /* IARR2/IMAP2 */
...@@ -307,7 +307,7 @@ enum iproc_pcie_reg { ...@@ -307,7 +307,7 @@ enum iproc_pcie_reg {
}; };
/* iProc PCIe PAXB BCMA registers */ /* iProc PCIe PAXB BCMA registers */
static const u16 iproc_pcie_reg_paxb_bcma[] = { static const u16 iproc_pcie_reg_paxb_bcma[IPROC_PCIE_MAX_NUM_REG] = {
[IPROC_PCIE_CLK_CTRL] = 0x000, [IPROC_PCIE_CLK_CTRL] = 0x000,
[IPROC_PCIE_CFG_IND_ADDR] = 0x120, [IPROC_PCIE_CFG_IND_ADDR] = 0x120,
[IPROC_PCIE_CFG_IND_DATA] = 0x124, [IPROC_PCIE_CFG_IND_DATA] = 0x124,
...@@ -318,7 +318,7 @@ static const u16 iproc_pcie_reg_paxb_bcma[] = { ...@@ -318,7 +318,7 @@ static const u16 iproc_pcie_reg_paxb_bcma[] = {
}; };
/* iProc PCIe PAXB registers */ /* iProc PCIe PAXB registers */
static const u16 iproc_pcie_reg_paxb[] = { static const u16 iproc_pcie_reg_paxb[IPROC_PCIE_MAX_NUM_REG] = {
[IPROC_PCIE_CLK_CTRL] = 0x000, [IPROC_PCIE_CLK_CTRL] = 0x000,
[IPROC_PCIE_CFG_IND_ADDR] = 0x120, [IPROC_PCIE_CFG_IND_ADDR] = 0x120,
[IPROC_PCIE_CFG_IND_DATA] = 0x124, [IPROC_PCIE_CFG_IND_DATA] = 0x124,
...@@ -334,7 +334,7 @@ static const u16 iproc_pcie_reg_paxb[] = { ...@@ -334,7 +334,7 @@ static const u16 iproc_pcie_reg_paxb[] = {
}; };
/* iProc PCIe PAXB v2 registers */ /* iProc PCIe PAXB v2 registers */
static const u16 iproc_pcie_reg_paxb_v2[] = { static const u16 iproc_pcie_reg_paxb_v2[IPROC_PCIE_MAX_NUM_REG] = {
[IPROC_PCIE_CLK_CTRL] = 0x000, [IPROC_PCIE_CLK_CTRL] = 0x000,
[IPROC_PCIE_CFG_IND_ADDR] = 0x120, [IPROC_PCIE_CFG_IND_ADDR] = 0x120,
[IPROC_PCIE_CFG_IND_DATA] = 0x124, [IPROC_PCIE_CFG_IND_DATA] = 0x124,
...@@ -351,6 +351,8 @@ static const u16 iproc_pcie_reg_paxb_v2[] = { ...@@ -351,6 +351,8 @@ static const u16 iproc_pcie_reg_paxb_v2[] = {
[IPROC_PCIE_OMAP3] = 0xdf8, [IPROC_PCIE_OMAP3] = 0xdf8,
[IPROC_PCIE_IARR0] = 0xd00, [IPROC_PCIE_IARR0] = 0xd00,
[IPROC_PCIE_IMAP0] = 0xc00, [IPROC_PCIE_IMAP0] = 0xc00,
[IPROC_PCIE_IARR1] = 0xd08,
[IPROC_PCIE_IMAP1] = 0xd70,
[IPROC_PCIE_IARR2] = 0xd10, [IPROC_PCIE_IARR2] = 0xd10,
[IPROC_PCIE_IMAP2] = 0xcc0, [IPROC_PCIE_IMAP2] = 0xcc0,
[IPROC_PCIE_IARR3] = 0xe00, [IPROC_PCIE_IARR3] = 0xe00,
...@@ -363,7 +365,7 @@ static const u16 iproc_pcie_reg_paxb_v2[] = { ...@@ -363,7 +365,7 @@ static const u16 iproc_pcie_reg_paxb_v2[] = {
}; };
/* iProc PCIe PAXC v1 registers */ /* iProc PCIe PAXC v1 registers */
static const u16 iproc_pcie_reg_paxc[] = { static const u16 iproc_pcie_reg_paxc[IPROC_PCIE_MAX_NUM_REG] = {
[IPROC_PCIE_CLK_CTRL] = 0x000, [IPROC_PCIE_CLK_CTRL] = 0x000,
[IPROC_PCIE_CFG_IND_ADDR] = 0x1f0, [IPROC_PCIE_CFG_IND_ADDR] = 0x1f0,
[IPROC_PCIE_CFG_IND_DATA] = 0x1f4, [IPROC_PCIE_CFG_IND_DATA] = 0x1f4,
...@@ -372,7 +374,7 @@ static const u16 iproc_pcie_reg_paxc[] = { ...@@ -372,7 +374,7 @@ static const u16 iproc_pcie_reg_paxc[] = {
}; };
/* iProc PCIe PAXC v2 registers */ /* iProc PCIe PAXC v2 registers */
static const u16 iproc_pcie_reg_paxc_v2[] = { static const u16 iproc_pcie_reg_paxc_v2[IPROC_PCIE_MAX_NUM_REG] = {
[IPROC_PCIE_MSI_GIC_MODE] = 0x050, [IPROC_PCIE_MSI_GIC_MODE] = 0x050,
[IPROC_PCIE_MSI_BASE_ADDR] = 0x074, [IPROC_PCIE_MSI_BASE_ADDR] = 0x074,
[IPROC_PCIE_MSI_WINDOW_SIZE] = 0x078, [IPROC_PCIE_MSI_WINDOW_SIZE] = 0x078,
...@@ -459,19 +461,15 @@ static inline void iproc_pcie_apb_err_disable(struct pci_bus *bus, ...@@ -459,19 +461,15 @@ static inline void iproc_pcie_apb_err_disable(struct pci_bus *bus,
static void __iomem *iproc_pcie_map_ep_cfg_reg(struct iproc_pcie *pcie, static void __iomem *iproc_pcie_map_ep_cfg_reg(struct iproc_pcie *pcie,
unsigned int busno, unsigned int busno,
unsigned int slot, unsigned int devfn,
unsigned int fn,
int where) int where)
{ {
u16 offset; u16 offset;
u32 val; u32 val;
/* EP device access */ /* EP device access */
val = (busno << CFG_ADDR_BUS_NUM_SHIFT) | val = ALIGN_DOWN(PCIE_ECAM_OFFSET(busno, devfn, where), 4) |
(slot << CFG_ADDR_DEV_NUM_SHIFT) | CFG_ADDR_CFG_TYPE_1;
(fn << CFG_ADDR_FUNC_NUM_SHIFT) |
(where & CFG_ADDR_REG_NUM_MASK) |
(1 & CFG_ADDR_CFG_TYPE_MASK);
iproc_pcie_write_reg(pcie, IPROC_PCIE_CFG_ADDR, val); iproc_pcie_write_reg(pcie, IPROC_PCIE_CFG_ADDR, val);
offset = iproc_pcie_reg_offset(pcie, IPROC_PCIE_CFG_DATA); offset = iproc_pcie_reg_offset(pcie, IPROC_PCIE_CFG_DATA);
...@@ -574,8 +572,6 @@ static int iproc_pcie_config_read(struct pci_bus *bus, unsigned int devfn, ...@@ -574,8 +572,6 @@ static int iproc_pcie_config_read(struct pci_bus *bus, unsigned int devfn,
int where, int size, u32 *val) int where, int size, u32 *val)
{ {
struct iproc_pcie *pcie = iproc_data(bus); struct iproc_pcie *pcie = iproc_data(bus);
unsigned int slot = PCI_SLOT(devfn);
unsigned int fn = PCI_FUNC(devfn);
unsigned int busno = bus->number; unsigned int busno = bus->number;
void __iomem *cfg_data_p; void __iomem *cfg_data_p;
unsigned int data; unsigned int data;
...@@ -590,7 +586,7 @@ static int iproc_pcie_config_read(struct pci_bus *bus, unsigned int devfn, ...@@ -590,7 +586,7 @@ static int iproc_pcie_config_read(struct pci_bus *bus, unsigned int devfn,
return ret; return ret;
} }
cfg_data_p = iproc_pcie_map_ep_cfg_reg(pcie, busno, slot, fn, where); cfg_data_p = iproc_pcie_map_ep_cfg_reg(pcie, busno, devfn, where);
if (!cfg_data_p) if (!cfg_data_p)
return PCIBIOS_DEVICE_NOT_FOUND; return PCIBIOS_DEVICE_NOT_FOUND;
...@@ -631,13 +627,11 @@ static void __iomem *iproc_pcie_map_cfg_bus(struct iproc_pcie *pcie, ...@@ -631,13 +627,11 @@ static void __iomem *iproc_pcie_map_cfg_bus(struct iproc_pcie *pcie,
int busno, unsigned int devfn, int busno, unsigned int devfn,
int where) int where)
{ {
unsigned slot = PCI_SLOT(devfn);
unsigned fn = PCI_FUNC(devfn);
u16 offset; u16 offset;
/* root complex access */ /* root complex access */
if (busno == 0) { if (busno == 0) {
if (slot > 0 || fn > 0) if (PCIE_ECAM_DEVFN(devfn) > 0)
return NULL; return NULL;
iproc_pcie_write_reg(pcie, IPROC_PCIE_CFG_IND_ADDR, iproc_pcie_write_reg(pcie, IPROC_PCIE_CFG_IND_ADDR,
...@@ -649,7 +643,7 @@ static void __iomem *iproc_pcie_map_cfg_bus(struct iproc_pcie *pcie, ...@@ -649,7 +643,7 @@ static void __iomem *iproc_pcie_map_cfg_bus(struct iproc_pcie *pcie,
return (pcie->base + offset); return (pcie->base + offset);
} }
return iproc_pcie_map_ep_cfg_reg(pcie, busno, slot, fn, where); return iproc_pcie_map_ep_cfg_reg(pcie, busno, devfn, where);
} }
static void __iomem *iproc_pcie_bus_map_cfg_bus(struct pci_bus *bus, static void __iomem *iproc_pcie_bus_map_cfg_bus(struct pci_bus *bus,
...@@ -1470,6 +1464,7 @@ int iproc_pcie_setup(struct iproc_pcie *pcie, struct list_head *res) ...@@ -1470,6 +1464,7 @@ int iproc_pcie_setup(struct iproc_pcie *pcie, struct list_head *res)
{ {
struct device *dev; struct device *dev;
int ret; int ret;
struct pci_dev *pdev;
struct pci_host_bridge *host = pci_host_bridge_from_priv(pcie); struct pci_host_bridge *host = pci_host_bridge_from_priv(pcie);
dev = pcie->dev; dev = pcie->dev;
...@@ -1533,6 +1528,11 @@ int iproc_pcie_setup(struct iproc_pcie *pcie, struct list_head *res) ...@@ -1533,6 +1528,11 @@ int iproc_pcie_setup(struct iproc_pcie *pcie, struct list_head *res)
goto err_power_off_phy; goto err_power_off_phy;
} }
for_each_pci_bridge(pdev, host->bus) {
if (pci_pcie_type(pdev) == PCI_EXP_TYPE_ROOT_PORT)
pcie_print_link_status(pdev);
}
return 0; return 0;
err_power_off_phy: err_power_off_phy:
......
...@@ -50,9 +50,7 @@ static inline struct rcar_msi *to_rcar_msi(struct msi_controller *chip) ...@@ -50,9 +50,7 @@ static inline struct rcar_msi *to_rcar_msi(struct msi_controller *chip)
/* Structure representing the PCIe interface */ /* Structure representing the PCIe interface */
struct rcar_pcie_host { struct rcar_pcie_host {
struct rcar_pcie pcie; struct rcar_pcie pcie;
struct device *dev;
struct phy *phy; struct phy *phy;
void __iomem *base;
struct clk *bus_clk; struct clk *bus_clk;
struct rcar_msi msi; struct rcar_msi msi;
int (*phy_init_fn)(struct rcar_pcie_host *host); int (*phy_init_fn)(struct rcar_pcie_host *host);
......
...@@ -157,12 +157,11 @@ static int rockchip_pcie_rd_other_conf(struct rockchip_pcie *rockchip, ...@@ -157,12 +157,11 @@ static int rockchip_pcie_rd_other_conf(struct rockchip_pcie *rockchip,
struct pci_bus *bus, u32 devfn, struct pci_bus *bus, u32 devfn,
int where, int size, u32 *val) int where, int size, u32 *val)
{ {
u32 busdev; void __iomem *addr;
busdev = PCIE_ECAM_ADDR(bus->number, PCI_SLOT(devfn), addr = rockchip->reg_base + PCIE_ECAM_OFFSET(bus->number, devfn, where);
PCI_FUNC(devfn), where);
if (!IS_ALIGNED(busdev, size)) { if (!IS_ALIGNED((uintptr_t)addr, size)) {
*val = 0; *val = 0;
return PCIBIOS_BAD_REGISTER_NUMBER; return PCIBIOS_BAD_REGISTER_NUMBER;
} }
...@@ -175,11 +174,11 @@ static int rockchip_pcie_rd_other_conf(struct rockchip_pcie *rockchip, ...@@ -175,11 +174,11 @@ static int rockchip_pcie_rd_other_conf(struct rockchip_pcie *rockchip,
AXI_WRAPPER_TYPE1_CFG); AXI_WRAPPER_TYPE1_CFG);
if (size == 4) { if (size == 4) {
*val = readl(rockchip->reg_base + busdev); *val = readl(addr);
} else if (size == 2) { } else if (size == 2) {
*val = readw(rockchip->reg_base + busdev); *val = readw(addr);
} else if (size == 1) { } else if (size == 1) {
*val = readb(rockchip->reg_base + busdev); *val = readb(addr);
} else { } else {
*val = 0; *val = 0;
return PCIBIOS_BAD_REGISTER_NUMBER; return PCIBIOS_BAD_REGISTER_NUMBER;
...@@ -191,11 +190,11 @@ static int rockchip_pcie_wr_other_conf(struct rockchip_pcie *rockchip, ...@@ -191,11 +190,11 @@ static int rockchip_pcie_wr_other_conf(struct rockchip_pcie *rockchip,
struct pci_bus *bus, u32 devfn, struct pci_bus *bus, u32 devfn,
int where, int size, u32 val) int where, int size, u32 val)
{ {
u32 busdev; void __iomem *addr;
busdev = PCIE_ECAM_ADDR(bus->number, PCI_SLOT(devfn), addr = rockchip->reg_base + PCIE_ECAM_OFFSET(bus->number, devfn, where);
PCI_FUNC(devfn), where);
if (!IS_ALIGNED(busdev, size)) if (!IS_ALIGNED((uintptr_t)addr, size))
return PCIBIOS_BAD_REGISTER_NUMBER; return PCIBIOS_BAD_REGISTER_NUMBER;
if (pci_is_root_bus(bus->parent)) if (pci_is_root_bus(bus->parent))
...@@ -206,11 +205,11 @@ static int rockchip_pcie_wr_other_conf(struct rockchip_pcie *rockchip, ...@@ -206,11 +205,11 @@ static int rockchip_pcie_wr_other_conf(struct rockchip_pcie *rockchip,
AXI_WRAPPER_TYPE1_CFG); AXI_WRAPPER_TYPE1_CFG);
if (size == 4) if (size == 4)
writel(val, rockchip->reg_base + busdev); writel(val, addr);
else if (size == 2) else if (size == 2)
writew(val, rockchip->reg_base + busdev); writew(val, addr);
else if (size == 1) else if (size == 1)
writeb(val, rockchip->reg_base + busdev); writeb(val, addr);
else else
return PCIBIOS_BAD_REGISTER_NUMBER; return PCIBIOS_BAD_REGISTER_NUMBER;
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/pci-ecam.h>
/* /*
* The upper 16 bits of PCIE_CLIENT_CONFIG are a write mask for the lower 16 * The upper 16 bits of PCIE_CLIENT_CONFIG are a write mask for the lower 16
...@@ -178,13 +179,6 @@ ...@@ -178,13 +179,6 @@
#define MIN_AXI_ADDR_BITS_PASSED 8 #define MIN_AXI_ADDR_BITS_PASSED 8
#define PCIE_RC_SEND_PME_OFF 0x11960 #define PCIE_RC_SEND_PME_OFF 0x11960
#define ROCKCHIP_VENDOR_ID 0x1d87 #define ROCKCHIP_VENDOR_ID 0x1d87
#define PCIE_ECAM_BUS(x) (((x) & 0xff) << 20)
#define PCIE_ECAM_DEV(x) (((x) & 0x1f) << 15)
#define PCIE_ECAM_FUNC(x) (((x) & 0x7) << 12)
#define PCIE_ECAM_REG(x) (((x) & 0xfff) << 0)
#define PCIE_ECAM_ADDR(bus, dev, func, reg) \
(PCIE_ECAM_BUS(bus) | PCIE_ECAM_DEV(dev) | \
PCIE_ECAM_FUNC(func) | PCIE_ECAM_REG(reg))
#define PCIE_LINK_IS_L2(x) \ #define PCIE_LINK_IS_L2(x) \
(((x) & PCIE_CLIENT_DEBUG_LTSSM_MASK) == PCIE_CLIENT_DEBUG_LTSSM_L2) (((x) & PCIE_CLIENT_DEBUG_LTSSM_MASK) == PCIE_CLIENT_DEBUG_LTSSM_L2)
#define PCIE_LINK_UP(x) \ #define PCIE_LINK_UP(x) \
......
...@@ -208,7 +208,6 @@ static int smp8759_config_write(struct pci_bus *bus, unsigned int devfn, ...@@ -208,7 +208,6 @@ static int smp8759_config_write(struct pci_bus *bus, unsigned int devfn,
} }
static const struct pci_ecam_ops smp8759_ecam_ops = { static const struct pci_ecam_ops smp8759_ecam_ops = {
.bus_shift = 20,
.pci_ops = { .pci_ops = {
.map_bus = pci_ecam_map_bus, .map_bus = pci_ecam_map_bus,
.read = smp8759_config_read, .read = smp8759_config_read,
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include <linux/of_platform.h> #include <linux/of_platform.h>
#include <linux/of_irq.h> #include <linux/of_irq.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/pci-ecam.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/irqchip/chained_irq.h> #include <linux/irqchip/chained_irq.h>
...@@ -124,8 +125,6 @@ ...@@ -124,8 +125,6 @@
#define E_ECAM_CR_ENABLE BIT(0) #define E_ECAM_CR_ENABLE BIT(0)
#define E_ECAM_SIZE_LOC GENMASK(20, 16) #define E_ECAM_SIZE_LOC GENMASK(20, 16)
#define E_ECAM_SIZE_SHIFT 16 #define E_ECAM_SIZE_SHIFT 16
#define ECAM_BUS_LOC_SHIFT 20
#define ECAM_DEV_LOC_SHIFT 12
#define NWL_ECAM_VALUE_DEFAULT 12 #define NWL_ECAM_VALUE_DEFAULT 12
#define CFG_DMA_REG_BAR GENMASK(2, 0) #define CFG_DMA_REG_BAR GENMASK(2, 0)
...@@ -240,15 +239,11 @@ static void __iomem *nwl_pcie_map_bus(struct pci_bus *bus, unsigned int devfn, ...@@ -240,15 +239,11 @@ static void __iomem *nwl_pcie_map_bus(struct pci_bus *bus, unsigned int devfn,
int where) int where)
{ {
struct nwl_pcie *pcie = bus->sysdata; struct nwl_pcie *pcie = bus->sysdata;
int relbus;
if (!nwl_pcie_valid_device(bus, devfn)) if (!nwl_pcie_valid_device(bus, devfn))
return NULL; return NULL;
relbus = (bus->number << ECAM_BUS_LOC_SHIFT) | return pcie->ecam_base + PCIE_ECAM_OFFSET(bus->number, devfn, where);
(devfn << ECAM_DEV_LOC_SHIFT);
return pcie->ecam_base + relbus + where;
} }
/* PCIe operations */ /* PCIe operations */
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include <linux/of_platform.h> #include <linux/of_platform.h>
#include <linux/of_irq.h> #include <linux/of_irq.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/pci-ecam.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include "../pci.h" #include "../pci.h"
...@@ -86,10 +87,6 @@ ...@@ -86,10 +87,6 @@
/* Phy Status/Control Register definitions */ /* Phy Status/Control Register definitions */
#define XILINX_PCIE_REG_PSCR_LNKUP BIT(11) #define XILINX_PCIE_REG_PSCR_LNKUP BIT(11)
/* ECAM definitions */
#define ECAM_BUS_NUM_SHIFT 20
#define ECAM_DEV_NUM_SHIFT 12
/* Number of MSI IRQs */ /* Number of MSI IRQs */
#define XILINX_NUM_MSI_IRQS 128 #define XILINX_NUM_MSI_IRQS 128
...@@ -183,15 +180,11 @@ static void __iomem *xilinx_pcie_map_bus(struct pci_bus *bus, ...@@ -183,15 +180,11 @@ static void __iomem *xilinx_pcie_map_bus(struct pci_bus *bus,
unsigned int devfn, int where) unsigned int devfn, int where)
{ {
struct xilinx_pcie_port *port = bus->sysdata; struct xilinx_pcie_port *port = bus->sysdata;
int relbus;
if (!xilinx_pcie_valid_device(bus, devfn)) if (!xilinx_pcie_valid_device(bus, devfn))
return NULL; return NULL;
relbus = (bus->number << ECAM_BUS_NUM_SHIFT) | return port->reg_base + PCIE_ECAM_OFFSET(bus->number, devfn, where);
(devfn << ECAM_DEV_NUM_SHIFT);
return port->reg_base + relbus + where;
} }
/* PCIe operations */ /* PCIe operations */
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/msi.h> #include <linux/msi.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/pci-ecam.h>
#include <linux/srcu.h> #include <linux/srcu.h>
#include <linux/rculist.h> #include <linux/rculist.h>
#include <linux/rcupdate.h> #include <linux/rcupdate.h>
...@@ -52,6 +53,12 @@ enum vmd_features { ...@@ -52,6 +53,12 @@ enum vmd_features {
* vendor-specific capability space * vendor-specific capability space
*/ */
VMD_FEAT_HAS_MEMBAR_SHADOW_VSCAP = (1 << 2), VMD_FEAT_HAS_MEMBAR_SHADOW_VSCAP = (1 << 2),
/*
* Device may use MSI-X vector 0 for software triggering and will not
* be used for MSI remapping
*/
VMD_FEAT_OFFSET_FIRST_VECTOR = (1 << 3),
}; };
/* /*
...@@ -93,7 +100,7 @@ struct vmd_dev { ...@@ -93,7 +100,7 @@ struct vmd_dev {
struct pci_dev *dev; struct pci_dev *dev;
spinlock_t cfg_lock; spinlock_t cfg_lock;
char __iomem *cfgbar; void __iomem *cfgbar;
int msix_count; int msix_count;
struct vmd_irq_list *irqs; struct vmd_irq_list *irqs;
...@@ -103,6 +110,7 @@ struct vmd_dev { ...@@ -103,6 +110,7 @@ struct vmd_dev {
struct irq_domain *irq_domain; struct irq_domain *irq_domain;
struct pci_bus *bus; struct pci_bus *bus;
u8 busn_start; u8 busn_start;
u8 first_vec;
}; };
static inline struct vmd_dev *vmd_from_bus(struct pci_bus *bus) static inline struct vmd_dev *vmd_from_bus(struct pci_bus *bus)
...@@ -198,11 +206,11 @@ static irq_hw_number_t vmd_get_hwirq(struct msi_domain_info *info, ...@@ -198,11 +206,11 @@ static irq_hw_number_t vmd_get_hwirq(struct msi_domain_info *info,
*/ */
static struct vmd_irq_list *vmd_next_irq(struct vmd_dev *vmd, struct msi_desc *desc) static struct vmd_irq_list *vmd_next_irq(struct vmd_dev *vmd, struct msi_desc *desc)
{ {
int i, best = 1;
unsigned long flags; unsigned long flags;
int i, best;
if (vmd->msix_count == 1) if (vmd->msix_count == 1 + vmd->first_vec)
return &vmd->irqs[0]; return &vmd->irqs[vmd->first_vec];
/* /*
* White list for fast-interrupt handlers. All others will share the * White list for fast-interrupt handlers. All others will share the
...@@ -212,11 +220,12 @@ static struct vmd_irq_list *vmd_next_irq(struct vmd_dev *vmd, struct msi_desc *d ...@@ -212,11 +220,12 @@ static struct vmd_irq_list *vmd_next_irq(struct vmd_dev *vmd, struct msi_desc *d
case PCI_CLASS_STORAGE_EXPRESS: case PCI_CLASS_STORAGE_EXPRESS:
break; break;
default: default:
return &vmd->irqs[0]; return &vmd->irqs[vmd->first_vec];
} }
raw_spin_lock_irqsave(&list_lock, flags); raw_spin_lock_irqsave(&list_lock, flags);
for (i = 1; i < vmd->msix_count; i++) best = vmd->first_vec + 1;
for (i = best; i < vmd->msix_count; i++)
if (vmd->irqs[i].count < vmd->irqs[best].count) if (vmd->irqs[i].count < vmd->irqs[best].count)
best = i; best = i;
vmd->irqs[best].count++; vmd->irqs[best].count++;
...@@ -324,18 +333,16 @@ static void vmd_remove_irq_domain(struct vmd_dev *vmd) ...@@ -324,18 +333,16 @@ static void vmd_remove_irq_domain(struct vmd_dev *vmd)
} }
} }
static char __iomem *vmd_cfg_addr(struct vmd_dev *vmd, struct pci_bus *bus, static void __iomem *vmd_cfg_addr(struct vmd_dev *vmd, struct pci_bus *bus,
unsigned int devfn, int reg, int len) unsigned int devfn, int reg, int len)
{ {
char __iomem *addr = vmd->cfgbar + unsigned int busnr_ecam = bus->number - vmd->busn_start;
((bus->number - vmd->busn_start) << 20) + u32 offset = PCIE_ECAM_OFFSET(busnr_ecam, devfn, reg);
(devfn << 12) + reg;
if ((addr - vmd->cfgbar) + len >= if (offset + len >= resource_size(&vmd->dev->resource[VMD_CFGBAR]))
resource_size(&vmd->dev->resource[VMD_CFGBAR]))
return NULL; return NULL;
return addr; return vmd->cfgbar + offset;
} }
/* /*
...@@ -346,7 +353,7 @@ static int vmd_pci_read(struct pci_bus *bus, unsigned int devfn, int reg, ...@@ -346,7 +353,7 @@ static int vmd_pci_read(struct pci_bus *bus, unsigned int devfn, int reg,
int len, u32 *value) int len, u32 *value)
{ {
struct vmd_dev *vmd = vmd_from_bus(bus); struct vmd_dev *vmd = vmd_from_bus(bus);
char __iomem *addr = vmd_cfg_addr(vmd, bus, devfn, reg, len); void __iomem *addr = vmd_cfg_addr(vmd, bus, devfn, reg, len);
unsigned long flags; unsigned long flags;
int ret = 0; int ret = 0;
...@@ -381,7 +388,7 @@ static int vmd_pci_write(struct pci_bus *bus, unsigned int devfn, int reg, ...@@ -381,7 +388,7 @@ static int vmd_pci_write(struct pci_bus *bus, unsigned int devfn, int reg,
int len, u32 value) int len, u32 value)
{ {
struct vmd_dev *vmd = vmd_from_bus(bus); struct vmd_dev *vmd = vmd_from_bus(bus);
char __iomem *addr = vmd_cfg_addr(vmd, bus, devfn, reg, len); void __iomem *addr = vmd_cfg_addr(vmd, bus, devfn, reg, len);
unsigned long flags; unsigned long flags;
int ret = 0; int ret = 0;
...@@ -549,8 +556,8 @@ static int vmd_alloc_irqs(struct vmd_dev *vmd) ...@@ -549,8 +556,8 @@ static int vmd_alloc_irqs(struct vmd_dev *vmd)
if (vmd->msix_count < 0) if (vmd->msix_count < 0)
return -ENODEV; return -ENODEV;
vmd->msix_count = pci_alloc_irq_vectors(dev, 1, vmd->msix_count, vmd->msix_count = pci_alloc_irq_vectors(dev, vmd->first_vec + 1,
PCI_IRQ_MSIX); vmd->msix_count, PCI_IRQ_MSIX);
if (vmd->msix_count < 0) if (vmd->msix_count < 0)
return vmd->msix_count; return vmd->msix_count;
...@@ -718,6 +725,7 @@ static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features) ...@@ -718,6 +725,7 @@ static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features)
static int vmd_probe(struct pci_dev *dev, const struct pci_device_id *id) static int vmd_probe(struct pci_dev *dev, const struct pci_device_id *id)
{ {
unsigned long features = (unsigned long) id->driver_data;
struct vmd_dev *vmd; struct vmd_dev *vmd;
int err; int err;
...@@ -742,13 +750,16 @@ static int vmd_probe(struct pci_dev *dev, const struct pci_device_id *id) ...@@ -742,13 +750,16 @@ static int vmd_probe(struct pci_dev *dev, const struct pci_device_id *id)
dma_set_mask_and_coherent(&dev->dev, DMA_BIT_MASK(32))) dma_set_mask_and_coherent(&dev->dev, DMA_BIT_MASK(32)))
return -ENODEV; return -ENODEV;
if (features & VMD_FEAT_OFFSET_FIRST_VECTOR)
vmd->first_vec = 1;
err = vmd_alloc_irqs(vmd); err = vmd_alloc_irqs(vmd);
if (err) if (err)
return err; return err;
spin_lock_init(&vmd->cfg_lock); spin_lock_init(&vmd->cfg_lock);
pci_set_drvdata(dev, vmd); pci_set_drvdata(dev, vmd);
err = vmd_enable_domain(vmd, (unsigned long) id->driver_data); err = vmd_enable_domain(vmd, features);
if (err) if (err)
return err; return err;
...@@ -817,13 +828,16 @@ static const struct pci_device_id vmd_ids[] = { ...@@ -817,13 +828,16 @@ static const struct pci_device_id vmd_ids[] = {
VMD_FEAT_HAS_BUS_RESTRICTIONS,}, VMD_FEAT_HAS_BUS_RESTRICTIONS,},
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x467f), {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x467f),
.driver_data = VMD_FEAT_HAS_MEMBAR_SHADOW_VSCAP | .driver_data = VMD_FEAT_HAS_MEMBAR_SHADOW_VSCAP |
VMD_FEAT_HAS_BUS_RESTRICTIONS,}, VMD_FEAT_HAS_BUS_RESTRICTIONS |
VMD_FEAT_OFFSET_FIRST_VECTOR,},
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x4c3d), {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x4c3d),
.driver_data = VMD_FEAT_HAS_MEMBAR_SHADOW_VSCAP | .driver_data = VMD_FEAT_HAS_MEMBAR_SHADOW_VSCAP |
VMD_FEAT_HAS_BUS_RESTRICTIONS,}, VMD_FEAT_HAS_BUS_RESTRICTIONS |
VMD_FEAT_OFFSET_FIRST_VECTOR,},
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_VMD_9A0B), {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_VMD_9A0B),
.driver_data = VMD_FEAT_HAS_MEMBAR_SHADOW_VSCAP | .driver_data = VMD_FEAT_HAS_MEMBAR_SHADOW_VSCAP |
VMD_FEAT_HAS_BUS_RESTRICTIONS,}, VMD_FEAT_HAS_BUS_RESTRICTIONS |
VMD_FEAT_OFFSET_FIRST_VECTOR,},
{0,} {0,}
}; };
MODULE_DEVICE_TABLE(pci, vmd_ids); MODULE_DEVICE_TABLE(pci, vmd_ids);
......
...@@ -28,6 +28,7 @@ struct pci_config_window *pci_ecam_create(struct device *dev, ...@@ -28,6 +28,7 @@ struct pci_config_window *pci_ecam_create(struct device *dev,
struct resource *cfgres, struct resource *busr, struct resource *cfgres, struct resource *busr,
const struct pci_ecam_ops *ops) const struct pci_ecam_ops *ops)
{ {
unsigned int bus_shift = ops->bus_shift;
struct pci_config_window *cfg; struct pci_config_window *cfg;
unsigned int bus_range, bus_range_max, bsz; unsigned int bus_range, bus_range_max, bsz;
struct resource *conflict; struct resource *conflict;
...@@ -40,20 +41,24 @@ struct pci_config_window *pci_ecam_create(struct device *dev, ...@@ -40,20 +41,24 @@ struct pci_config_window *pci_ecam_create(struct device *dev,
if (!cfg) if (!cfg)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
/* ECAM-compliant platforms need not supply ops->bus_shift */
if (!bus_shift)
bus_shift = PCIE_ECAM_BUS_SHIFT;
cfg->parent = dev; cfg->parent = dev;
cfg->ops = ops; cfg->ops = ops;
cfg->busr.start = busr->start; cfg->busr.start = busr->start;
cfg->busr.end = busr->end; cfg->busr.end = busr->end;
cfg->busr.flags = IORESOURCE_BUS; cfg->busr.flags = IORESOURCE_BUS;
bus_range = resource_size(&cfg->busr); bus_range = resource_size(&cfg->busr);
bus_range_max = resource_size(cfgres) >> ops->bus_shift; bus_range_max = resource_size(cfgres) >> bus_shift;
if (bus_range > bus_range_max) { if (bus_range > bus_range_max) {
bus_range = bus_range_max; bus_range = bus_range_max;
cfg->busr.end = busr->start + bus_range - 1; cfg->busr.end = busr->start + bus_range - 1;
dev_warn(dev, "ECAM area %pR can only accommodate %pR (reduced from %pR desired)\n", dev_warn(dev, "ECAM area %pR can only accommodate %pR (reduced from %pR desired)\n",
cfgres, &cfg->busr, busr); cfgres, &cfg->busr, busr);
} }
bsz = 1 << ops->bus_shift; bsz = 1 << bus_shift;
cfg->res.start = cfgres->start; cfg->res.start = cfgres->start;
cfg->res.end = cfgres->end; cfg->res.end = cfgres->end;
...@@ -131,25 +136,36 @@ void __iomem *pci_ecam_map_bus(struct pci_bus *bus, unsigned int devfn, ...@@ -131,25 +136,36 @@ void __iomem *pci_ecam_map_bus(struct pci_bus *bus, unsigned int devfn,
int where) int where)
{ {
struct pci_config_window *cfg = bus->sysdata; struct pci_config_window *cfg = bus->sysdata;
unsigned int bus_shift = cfg->ops->bus_shift;
unsigned int devfn_shift = cfg->ops->bus_shift - 8; unsigned int devfn_shift = cfg->ops->bus_shift - 8;
unsigned int busn = bus->number; unsigned int busn = bus->number;
void __iomem *base; void __iomem *base;
u32 bus_offset, devfn_offset;
if (busn < cfg->busr.start || busn > cfg->busr.end) if (busn < cfg->busr.start || busn > cfg->busr.end)
return NULL; return NULL;
busn -= cfg->busr.start; busn -= cfg->busr.start;
if (per_bus_mapping) if (per_bus_mapping) {
base = cfg->winp[busn]; base = cfg->winp[busn];
else busn = 0;
base = cfg->win + (busn << cfg->ops->bus_shift); } else
return base + (devfn << devfn_shift) + where; base = cfg->win;
if (cfg->ops->bus_shift) {
bus_offset = (busn & PCIE_ECAM_BUS_MASK) << bus_shift;
devfn_offset = (devfn & PCIE_ECAM_DEVFN_MASK) << devfn_shift;
where &= PCIE_ECAM_REG_MASK;
return base + (bus_offset | devfn_offset | where);
}
return base + PCIE_ECAM_OFFSET(busn, devfn, where);
} }
EXPORT_SYMBOL_GPL(pci_ecam_map_bus); EXPORT_SYMBOL_GPL(pci_ecam_map_bus);
/* ECAM ops */ /* ECAM ops */
const struct pci_ecam_ops pci_generic_ecam_ops = { const struct pci_ecam_ops pci_generic_ecam_ops = {
.bus_shift = 20,
.pci_ops = { .pci_ops = {
.map_bus = pci_ecam_map_bus, .map_bus = pci_ecam_map_bus,
.read = pci_generic_config_read, .read = pci_generic_config_read,
...@@ -161,7 +177,6 @@ EXPORT_SYMBOL_GPL(pci_generic_ecam_ops); ...@@ -161,7 +177,6 @@ EXPORT_SYMBOL_GPL(pci_generic_ecam_ops);
#if defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS) #if defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS)
/* ECAM ops for 32-bit access only (non-compliant) */ /* ECAM ops for 32-bit access only (non-compliant) */
const struct pci_ecam_ops pci_32b_ops = { const struct pci_ecam_ops pci_32b_ops = {
.bus_shift = 20,
.pci_ops = { .pci_ops = {
.map_bus = pci_ecam_map_bus, .map_bus = pci_ecam_map_bus,
.read = pci_generic_config_read32, .read = pci_generic_config_read32,
...@@ -171,7 +186,6 @@ const struct pci_ecam_ops pci_32b_ops = { ...@@ -171,7 +186,6 @@ const struct pci_ecam_ops pci_32b_ops = {
/* ECAM ops for 32-bit read only (non-compliant) */ /* ECAM ops for 32-bit read only (non-compliant) */
const struct pci_ecam_ops pci_32b_read_ops = { const struct pci_ecam_ops pci_32b_read_ops = {
.bus_shift = 20,
.pci_ops = { .pci_ops = {
.map_bus = pci_ecam_map_bus, .map_bus = pci_ecam_map_bus,
.read = pci_generic_config_read32, .read = pci_generic_config_read32,
......
...@@ -294,7 +294,6 @@ int ibmphp_configure_card(struct pci_func *func, u8 slotno) ...@@ -294,7 +294,6 @@ int ibmphp_configure_card(struct pci_func *func, u8 slotno)
default: default:
err("MAJOR PROBLEM!!!!, header type not supported? %x\n", hdr_type); err("MAJOR PROBLEM!!!!, header type not supported? %x\n", hdr_type);
return -ENXIO; return -ENXIO;
break;
} /* end of switch */ } /* end of switch */
} /* end of valid device */ } /* end of valid device */
} /* end of for */ } /* end of for */
...@@ -1509,7 +1508,6 @@ static int unconfigure_boot_card(struct slot *slot_cur) ...@@ -1509,7 +1508,6 @@ static int unconfigure_boot_card(struct slot *slot_cur)
default: default:
err("MAJOR PROBLEM!!!! Cannot read device's header\n"); err("MAJOR PROBLEM!!!! Cannot read device's header\n");
return -1; return -1;
break;
} /* end of switch */ } /* end of switch */
} /* end of valid device */ } /* end of valid device */
} /* end of for */ } /* end of for */
......
...@@ -26,6 +26,8 @@ ...@@ -26,6 +26,8 @@
#include "pci.h" #include "pci.h"
#ifdef CONFIG_PCI_MSI
static int pci_msi_enable = 1; static int pci_msi_enable = 1;
int pci_msi_ignore_mask; int pci_msi_ignore_mask;
...@@ -410,6 +412,17 @@ static void pci_intx_for_msi(struct pci_dev *dev, int enable) ...@@ -410,6 +412,17 @@ static void pci_intx_for_msi(struct pci_dev *dev, int enable)
pci_intx(dev, enable); pci_intx(dev, enable);
} }
static void pci_msi_set_enable(struct pci_dev *dev, int enable)
{
u16 control;
pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &control);
control &= ~PCI_MSI_FLAGS_ENABLE;
if (enable)
control |= PCI_MSI_FLAGS_ENABLE;
pci_write_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, control);
}
static void __pci_restore_msi_state(struct pci_dev *dev) static void __pci_restore_msi_state(struct pci_dev *dev)
{ {
u16 control; u16 control;
...@@ -432,6 +445,16 @@ static void __pci_restore_msi_state(struct pci_dev *dev) ...@@ -432,6 +445,16 @@ static void __pci_restore_msi_state(struct pci_dev *dev)
pci_write_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, control); pci_write_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, control);
} }
static void pci_msix_clear_and_set_ctrl(struct pci_dev *dev, u16 clear, u16 set)
{
u16 ctrl;
pci_read_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, &ctrl);
ctrl &= ~clear;
ctrl |= set;
pci_write_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, ctrl);
}
static void __pci_restore_msix_state(struct pci_dev *dev) static void __pci_restore_msix_state(struct pci_dev *dev)
{ {
struct msi_desc *entry; struct msi_desc *entry;
...@@ -600,11 +623,11 @@ static int msi_verify_entries(struct pci_dev *dev) ...@@ -600,11 +623,11 @@ static int msi_verify_entries(struct pci_dev *dev)
struct msi_desc *entry; struct msi_desc *entry;
for_each_pci_msi_entry(entry, dev) { for_each_pci_msi_entry(entry, dev) {
if (!dev->no_64bit_msi || !entry->msg.address_hi) if (entry->msg.address_hi && dev->no_64bit_msi) {
continue; pci_err(dev, "arch assigned 64-bit MSI address %#x%08x but device only supports 32 bits\n",
pci_err(dev, "Device has broken 64-bit MSI but arch" entry->msg.address_hi, entry->msg.address_lo);
" tried to assign one above 4G\n"); return -EIO;
return -EIO; }
} }
return 0; return 0;
} }
...@@ -1577,3 +1600,40 @@ bool pci_dev_has_special_msi_domain(struct pci_dev *pdev) ...@@ -1577,3 +1600,40 @@ bool pci_dev_has_special_msi_domain(struct pci_dev *pdev)
} }
#endif /* CONFIG_PCI_MSI_IRQ_DOMAIN */ #endif /* CONFIG_PCI_MSI_IRQ_DOMAIN */
#endif /* CONFIG_PCI_MSI */
void pci_msi_init(struct pci_dev *dev)
{
u16 ctrl;
/*
* Disable the MSI hardware to avoid screaming interrupts
* during boot. This is the power on reset default so
* usually this should be a noop.
*/
dev->msi_cap = pci_find_capability(dev, PCI_CAP_ID_MSI);
if (!dev->msi_cap)
return;
pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &ctrl);
if (ctrl & PCI_MSI_FLAGS_ENABLE)
pci_write_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS,
ctrl & ~PCI_MSI_FLAGS_ENABLE);
if (!(ctrl & PCI_MSI_FLAGS_64BIT))
dev->no_64bit_msi = 1;
}
void pci_msix_init(struct pci_dev *dev)
{
u16 ctrl;
dev->msix_cap = pci_find_capability(dev, PCI_CAP_ID_MSIX);
if (!dev->msix_cap)
return;
pci_read_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, &ctrl);
if (ctrl & PCI_MSIX_FLAGS_ENABLE)
pci_write_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS,
ctrl & ~PCI_MSIX_FLAGS_ENABLE);
}
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册