Merge branch 'lorenzo/pci/tegra'
- Fix Tegra OF node reference leak (Nishka Dasgupta) - Add #defines for PCIe Data Link Feature and Physical Layer 16.0 GT/s features (Vidya Sagar) - Disable MSI for Tegra Root Ports since they don't support using MSI for all Root Port events (Vidya Sagar) - Group DesignWare write-protected register writes together (Vidya Sagar) - Move DesignWare capability search interfaces so they can be used by both host and endpoint drivers (Vidya Sagar) - Add DesignWare extended capability search interfaces (Vidya Sagar) - Export dw_pcie_wait_for_link() so drivers can be modules (Vidya Sagar) - Add "snps,enable-cdm-check" DT binding for Configuration Dependent Module (CDM) register checking (Vidya Sagar) - Add DesignWare support for "snps,enable-cdm-check" CDM checking (Vidya Sagar) - Add "supports-clkreq" DT binding for host drivers to decide whether to advertise low power features (Vidya Sagar) - Add DT binding for Tegra194 (Vidya Sagar) - Add DT binding for Tegra194 P2U (PIPE to UPHY) block (Vidya Sagar) - Add support for Tegra194 P2U (PIPE to UPHY) (Vidya Sagar) - Add support for Tegra194 host controller (Vidya Sagar) - Add Tegra support for sideband PERST# and CLKREQ# for C5 (Vidya Sagar) - Add Tegra support for slot regulators for p2972-0000 platform (Vidya Sagar) * lorenzo/pci/tegra: arm64: tegra: Add PCIe slot supply information in p2972-0000 platform arm64: tegra: Add configuration for PCIe C5 sideband signals PCI: tegra: Add support to enable slot regulators PCI: tegra: Add support to configure sideband pins dt-bindings: PCI: tegra: Add PCIe slot supplies regulator entries dt-bindings: PCI: tegra: Add sideband pins configuration entries PCI: tegra: Add Tegra194 PCIe support phy: tegra: Add PCIe PIPE2UPHY support dt-bindings: PHY: P2U: Add Tegra194 P2U block dt-bindings: PCI: tegra: Add device tree support for Tegra194 dt-bindings: Add PCIe supports-clkreq property PCI: dwc: Add support to enable CDM register check dt-bindings: PCI: designware: Add binding for CDM register check PCI: dwc: Export dw_pcie_wait_for_link() API PCI: dwc: Add extended configuration space capability search API PCI: dwc: Move config space capability search API PCI: dwc: Group DBI registers writes requiring unlocking PCI: Disable MSI for Tegra root ports PCI: Add #defines for some of PCIe spec r4.0 features PCI: tegra: Fix OF node reference leak
This commit is contained in:
commit
3efa7f1feb
|
@ -33,6 +33,11 @@ Optional properties:
|
||||||
- clock-names: Must include the following entries:
|
- clock-names: Must include the following entries:
|
||||||
- "pcie"
|
- "pcie"
|
||||||
- "pcie_bus"
|
- "pcie_bus"
|
||||||
|
- snps,enable-cdm-check: This is a boolean property and if present enables
|
||||||
|
automatic checking of CDM (Configuration Dependent Module) registers
|
||||||
|
for data corruption. CDM registers include standard PCIe configuration
|
||||||
|
space registers, Port Logic registers, DMA and iATU (internal Address
|
||||||
|
Translation Unit) registers.
|
||||||
RC mode:
|
RC mode:
|
||||||
- num-viewport: number of view ports configured in hardware. If a platform
|
- num-viewport: number of view ports configured in hardware. If a platform
|
||||||
does not specify it, the driver assumes 2.
|
does not specify it, the driver assumes 2.
|
||||||
|
|
|
@ -0,0 +1,171 @@
|
||||||
|
NVIDIA Tegra PCIe controller (Synopsys DesignWare Core based)
|
||||||
|
|
||||||
|
This PCIe host controller is based on the Synopsis Designware PCIe IP
|
||||||
|
and thus inherits all the common properties defined in designware-pcie.txt.
|
||||||
|
|
||||||
|
Required properties:
|
||||||
|
- compatible: For Tegra19x, must contain "nvidia,tegra194-pcie".
|
||||||
|
- device_type: Must be "pci"
|
||||||
|
- power-domains: A phandle to the node that controls power to the respective
|
||||||
|
PCIe controller and a specifier name for the PCIe controller. Following are
|
||||||
|
the specifiers for the different PCIe controllers
|
||||||
|
TEGRA194_POWER_DOMAIN_PCIEX8B: C0
|
||||||
|
TEGRA194_POWER_DOMAIN_PCIEX1A: C1
|
||||||
|
TEGRA194_POWER_DOMAIN_PCIEX1A: C2
|
||||||
|
TEGRA194_POWER_DOMAIN_PCIEX1A: C3
|
||||||
|
TEGRA194_POWER_DOMAIN_PCIEX4A: C4
|
||||||
|
TEGRA194_POWER_DOMAIN_PCIEX8A: C5
|
||||||
|
these specifiers are defined in
|
||||||
|
"include/dt-bindings/power/tegra194-powergate.h" file.
|
||||||
|
- reg: A list of physical base address and length pairs for each set of
|
||||||
|
controller registers. Must contain an entry for each entry in the reg-names
|
||||||
|
property.
|
||||||
|
- reg-names: Must include the following entries:
|
||||||
|
"appl": Controller's application logic registers
|
||||||
|
"config": As per the definition in designware-pcie.txt
|
||||||
|
"atu_dma": iATU and DMA registers. This is where the iATU (internal Address
|
||||||
|
Translation Unit) registers of the PCIe core are made available
|
||||||
|
for SW access.
|
||||||
|
"dbi": The aperture where root port's own configuration registers are
|
||||||
|
available
|
||||||
|
- interrupts: A list of interrupt outputs of the controller. Must contain an
|
||||||
|
entry for each entry in the interrupt-names property.
|
||||||
|
- interrupt-names: Must include the following entries:
|
||||||
|
"intr": The Tegra interrupt that is asserted for controller interrupts
|
||||||
|
"msi": The Tegra interrupt that is asserted when an MSI is received
|
||||||
|
- bus-range: Range of bus numbers associated with this controller
|
||||||
|
- #address-cells: Address representation for root ports (must be 3)
|
||||||
|
- cell 0 specifies the bus and device numbers of the root port:
|
||||||
|
[23:16]: bus number
|
||||||
|
[15:11]: device number
|
||||||
|
- cell 1 denotes the upper 32 address bits and should be 0
|
||||||
|
- cell 2 contains the lower 32 address bits and is used to translate to the
|
||||||
|
CPU address space
|
||||||
|
- #size-cells: Size representation for root ports (must be 2)
|
||||||
|
- ranges: Describes the translation of addresses for root ports and standard
|
||||||
|
PCI regions. The entries must be 7 cells each, where the first three cells
|
||||||
|
correspond to the address as described for the #address-cells property
|
||||||
|
above, the fourth and fifth cells are for the physical CPU address to
|
||||||
|
translate to and the sixth and seventh cells are as described for the
|
||||||
|
#size-cells property above.
|
||||||
|
- Entries setup the mapping for the standard I/O, memory and
|
||||||
|
prefetchable PCI regions. The first cell determines the type of region
|
||||||
|
that is setup:
|
||||||
|
- 0x81000000: I/O memory region
|
||||||
|
- 0x82000000: non-prefetchable memory region
|
||||||
|
- 0xc2000000: prefetchable memory region
|
||||||
|
Please refer to the standard PCI bus binding document for a more detailed
|
||||||
|
explanation.
|
||||||
|
- #interrupt-cells: Size representation for interrupts (must be 1)
|
||||||
|
- interrupt-map-mask and interrupt-map: Standard PCI IRQ mapping properties
|
||||||
|
Please refer to the standard PCI bus binding document for a more detailed
|
||||||
|
explanation.
|
||||||
|
- clocks: Must contain an entry for each entry in clock-names.
|
||||||
|
See ../clocks/clock-bindings.txt for details.
|
||||||
|
- clock-names: Must include the following entries:
|
||||||
|
- core
|
||||||
|
- resets: Must contain an entry for each entry in reset-names.
|
||||||
|
See ../reset/reset.txt for details.
|
||||||
|
- reset-names: Must include the following entries:
|
||||||
|
- apb
|
||||||
|
- core
|
||||||
|
- phys: Must contain a phandle to P2U PHY for each entry in phy-names.
|
||||||
|
- phy-names: Must include an entry for each active lane.
|
||||||
|
"p2u-N": where N ranges from 0 to one less than the total number of lanes
|
||||||
|
- nvidia,bpmp: Must contain a pair of phandle to BPMP controller node followed
|
||||||
|
by controller-id. Following are the controller ids for each controller.
|
||||||
|
0: C0
|
||||||
|
1: C1
|
||||||
|
2: C2
|
||||||
|
3: C3
|
||||||
|
4: C4
|
||||||
|
5: C5
|
||||||
|
- vddio-pex-ctl-supply: Regulator supply for PCIe side band signals
|
||||||
|
|
||||||
|
Optional properties:
|
||||||
|
- pinctrl-names: A list of pinctrl state names.
|
||||||
|
It is mandatory for C5 controller and optional for other controllers.
|
||||||
|
- "default": Configures PCIe I/O for proper operation.
|
||||||
|
- pinctrl-0: phandle for the 'default' state of pin configuration.
|
||||||
|
It is mandatory for C5 controller and optional for other controllers.
|
||||||
|
- supports-clkreq: Refer to Documentation/devicetree/bindings/pci/pci.txt
|
||||||
|
- nvidia,update-fc-fixup: This is a boolean property and needs to be present to
|
||||||
|
improve performance when a platform is designed in such a way that it
|
||||||
|
satisfies at least one of the following conditions thereby enabling root
|
||||||
|
port to exchange optimum number of FC (Flow Control) credits with
|
||||||
|
downstream devices
|
||||||
|
1. If C0/C4/C5 run at x1/x2 link widths (irrespective of speed and MPS)
|
||||||
|
2. If C0/C1/C2/C3/C4/C5 operate at their respective max link widths and
|
||||||
|
a) speed is Gen-2 and MPS is 256B
|
||||||
|
b) speed is >= Gen-3 with any MPS
|
||||||
|
- nvidia,aspm-cmrt-us: Common Mode Restore Time for proper operation of ASPM
|
||||||
|
to be specified in microseconds
|
||||||
|
- nvidia,aspm-pwr-on-t-us: Power On time for proper operation of ASPM to be
|
||||||
|
specified in microseconds
|
||||||
|
- nvidia,aspm-l0s-entrance-latency-us: ASPM L0s entrance latency to be
|
||||||
|
specified in microseconds
|
||||||
|
- vpcie3v3-supply: A phandle to the regulator node that supplies 3.3V to the slot
|
||||||
|
if the platform has one such slot. (Ex:- x16 slot owned by C5 controller
|
||||||
|
in p2972-0000 platform).
|
||||||
|
- vpcie12v-supply: A phandle to the regulator node that supplies 12V to the slot
|
||||||
|
if the platform has one such slot. (Ex:- x16 slot owned by C5 controller
|
||||||
|
in p2972-0000 platform).
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
=========
|
||||||
|
|
||||||
|
Tegra194:
|
||||||
|
--------
|
||||||
|
|
||||||
|
pcie@14180000 {
|
||||||
|
compatible = "nvidia,tegra194-pcie", "snps,dw-pcie";
|
||||||
|
power-domains = <&bpmp TEGRA194_POWER_DOMAIN_PCIEX8B>;
|
||||||
|
reg = <0x00 0x14180000 0x0 0x00020000 /* appl registers (128K) */
|
||||||
|
0x00 0x38000000 0x0 0x00040000 /* configuration space (256K) */
|
||||||
|
0x00 0x38040000 0x0 0x00040000>; /* iATU_DMA reg space (256K) */
|
||||||
|
reg-names = "appl", "config", "atu_dma";
|
||||||
|
|
||||||
|
#address-cells = <3>;
|
||||||
|
#size-cells = <2>;
|
||||||
|
device_type = "pci";
|
||||||
|
num-lanes = <8>;
|
||||||
|
linux,pci-domain = <0>;
|
||||||
|
|
||||||
|
pinctrl-names = "default";
|
||||||
|
pinctrl-0 = <&pex_rst_c5_out_state>, <&clkreq_c5_bi_dir_state>;
|
||||||
|
|
||||||
|
clocks = <&bpmp TEGRA194_CLK_PEX0_CORE_0>;
|
||||||
|
clock-names = "core";
|
||||||
|
|
||||||
|
resets = <&bpmp TEGRA194_RESET_PEX0_CORE_0_APB>,
|
||||||
|
<&bpmp TEGRA194_RESET_PEX0_CORE_0>;
|
||||||
|
reset-names = "apb", "core";
|
||||||
|
|
||||||
|
interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>, /* controller interrupt */
|
||||||
|
<GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>; /* MSI interrupt */
|
||||||
|
interrupt-names = "intr", "msi";
|
||||||
|
|
||||||
|
#interrupt-cells = <1>;
|
||||||
|
interrupt-map-mask = <0 0 0 0>;
|
||||||
|
interrupt-map = <0 0 0 0 &gic GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>;
|
||||||
|
|
||||||
|
nvidia,bpmp = <&bpmp 0>;
|
||||||
|
|
||||||
|
supports-clkreq;
|
||||||
|
nvidia,aspm-cmrt-us = <60>;
|
||||||
|
nvidia,aspm-pwr-on-t-us = <20>;
|
||||||
|
nvidia,aspm-l0s-entrance-latency-us = <3>;
|
||||||
|
|
||||||
|
bus-range = <0x0 0xff>;
|
||||||
|
ranges = <0x81000000 0x0 0x38100000 0x0 0x38100000 0x0 0x00100000 /* downstream I/O (1MB) */
|
||||||
|
0x82000000 0x0 0x38200000 0x0 0x38200000 0x0 0x01E00000 /* non-prefetchable memory (30MB) */
|
||||||
|
0xc2000000 0x18 0x00000000 0x18 0x00000000 0x4 0x00000000>; /* prefetchable memory (16GB) */
|
||||||
|
|
||||||
|
vddio-pex-ctl-supply = <&vdd_1v8ao>;
|
||||||
|
vpcie3v3-supply = <&vdd_3v3_pcie>;
|
||||||
|
vpcie12v-supply = <&vdd_12v_pcie>;
|
||||||
|
|
||||||
|
phys = <&p2u_hsio_2>, <&p2u_hsio_3>, <&p2u_hsio_4>,
|
||||||
|
<&p2u_hsio_5>;
|
||||||
|
phy-names = "p2u-0", "p2u-1", "p2u-2", "p2u-3";
|
||||||
|
};
|
|
@ -27,6 +27,11 @@ driver implementation may support the following properties:
|
||||||
- reset-gpios:
|
- reset-gpios:
|
||||||
If present this property specifies PERST# GPIO. Host drivers can parse the
|
If present this property specifies PERST# GPIO. Host drivers can parse the
|
||||||
GPIO and apply fundamental reset to endpoints.
|
GPIO and apply fundamental reset to endpoints.
|
||||||
|
- supports-clkreq:
|
||||||
|
If present this property specifies that CLKREQ signal routing exists from
|
||||||
|
root port to downstream device and host bridge drivers can do programming
|
||||||
|
which depends on CLKREQ signal existence. For example, programming root port
|
||||||
|
not to advertise ASPM L1 Sub-States support if there is no CLKREQ signal.
|
||||||
|
|
||||||
PCI-PCI Bridge properties
|
PCI-PCI Bridge properties
|
||||||
-------------------------
|
-------------------------
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
NVIDIA Tegra194 P2U binding
|
||||||
|
|
||||||
|
Tegra194 has two PHY bricks namely HSIO (High Speed IO) and NVHS (NVIDIA High
|
||||||
|
Speed) each interfacing with 12 and 8 P2U instances respectively.
|
||||||
|
A P2U instance is a glue logic between Synopsys DesignWare Core PCIe IP's PIPE
|
||||||
|
interface and PHY of HSIO/NVHS bricks. Each P2U instance represents one PCIe
|
||||||
|
lane.
|
||||||
|
|
||||||
|
Required properties:
|
||||||
|
- compatible: For Tegra19x, must contain "nvidia,tegra194-p2u".
|
||||||
|
- reg: Should be the physical address space and length of respective each P2U
|
||||||
|
instance.
|
||||||
|
- reg-names: Must include the entry "ctl".
|
||||||
|
|
||||||
|
Required properties for PHY port node:
|
||||||
|
- #phy-cells: Defined by generic PHY bindings. Must be 0.
|
||||||
|
|
||||||
|
Refer to phy/phy-bindings.txt for the generic PHY binding properties.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
p2u_hsio_0: phy@3e10000 {
|
||||||
|
compatible = "nvidia,tegra194-p2u";
|
||||||
|
reg = <0x03e10000 0x10000>;
|
||||||
|
reg-names = "ctl";
|
||||||
|
|
||||||
|
#phy-cells = <0>;
|
||||||
|
};
|
|
@ -289,5 +289,29 @@
|
||||||
gpio = <&gpio TEGRA194_MAIN_GPIO(A, 3) GPIO_ACTIVE_HIGH>;
|
gpio = <&gpio TEGRA194_MAIN_GPIO(A, 3) GPIO_ACTIVE_HIGH>;
|
||||||
enable-active-high;
|
enable-active-high;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
vdd_3v3_pcie: regulator@2 {
|
||||||
|
compatible = "regulator-fixed";
|
||||||
|
reg = <2>;
|
||||||
|
|
||||||
|
regulator-name = "PEX_3V3";
|
||||||
|
regulator-min-microvolt = <3300000>;
|
||||||
|
regulator-max-microvolt = <3300000>;
|
||||||
|
gpio = <&gpio TEGRA194_MAIN_GPIO(Z, 2) GPIO_ACTIVE_HIGH>;
|
||||||
|
regulator-boot-on;
|
||||||
|
enable-active-high;
|
||||||
|
};
|
||||||
|
|
||||||
|
vdd_12v_pcie: regulator@3 {
|
||||||
|
compatible = "regulator-fixed";
|
||||||
|
reg = <3>;
|
||||||
|
|
||||||
|
regulator-name = "VDD_12V";
|
||||||
|
regulator-min-microvolt = <1200000>;
|
||||||
|
regulator-max-microvolt = <1200000>;
|
||||||
|
gpio = <&gpio TEGRA194_MAIN_GPIO(A, 1) GPIO_ACTIVE_LOW>;
|
||||||
|
regulator-boot-on;
|
||||||
|
enable-active-low;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -93,9 +93,11 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
pcie@141a0000 {
|
pcie@141a0000 {
|
||||||
status = "disabled";
|
status = "okay";
|
||||||
|
|
||||||
vddio-pex-ctl-supply = <&vdd_1v8ao>;
|
vddio-pex-ctl-supply = <&vdd_1v8ao>;
|
||||||
|
vpcie3v3-supply = <&vdd_3v3_pcie>;
|
||||||
|
vpcie12v-supply = <&vdd_12v_pcie>;
|
||||||
|
|
||||||
phys = <&p2u_nvhs_0>, <&p2u_nvhs_1>, <&p2u_nvhs_2>,
|
phys = <&p2u_nvhs_0>, <&p2u_nvhs_1>, <&p2u_nvhs_2>,
|
||||||
<&p2u_nvhs_3>, <&p2u_nvhs_4>, <&p2u_nvhs_5>,
|
<&p2u_nvhs_3>, <&p2u_nvhs_4>, <&p2u_nvhs_5>,
|
||||||
|
|
|
@ -3,8 +3,9 @@
|
||||||
#include <dt-bindings/gpio/tegra194-gpio.h>
|
#include <dt-bindings/gpio/tegra194-gpio.h>
|
||||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||||
#include <dt-bindings/mailbox/tegra186-hsp.h>
|
#include <dt-bindings/mailbox/tegra186-hsp.h>
|
||||||
#include <dt-bindings/reset/tegra194-reset.h>
|
#include <dt-bindings/pinctrl/pinctrl-tegra.h>
|
||||||
#include <dt-bindings/power/tegra194-powergate.h>
|
#include <dt-bindings/power/tegra194-powergate.h>
|
||||||
|
#include <dt-bindings/reset/tegra194-reset.h>
|
||||||
#include <dt-bindings/thermal/tegra194-bpmp-thermal.h>
|
#include <dt-bindings/thermal/tegra194-bpmp-thermal.h>
|
||||||
|
|
||||||
/ {
|
/ {
|
||||||
|
@ -130,6 +131,38 @@
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pinmux: pinmux@2430000 {
|
||||||
|
compatible = "nvidia,tegra194-pinmux";
|
||||||
|
reg = <0x2430000 0x17000
|
||||||
|
0xc300000 0x4000>;
|
||||||
|
|
||||||
|
status = "okay";
|
||||||
|
|
||||||
|
pex_rst_c5_out_state: pex_rst_c5_out {
|
||||||
|
pex_rst {
|
||||||
|
nvidia,pins = "pex_l5_rst_n_pgg1";
|
||||||
|
nvidia,schmitt = <TEGRA_PIN_DISABLE>;
|
||||||
|
nvidia,lpdr = <TEGRA_PIN_ENABLE>;
|
||||||
|
nvidia,enable-input = <TEGRA_PIN_DISABLE>;
|
||||||
|
nvidia,io-high-voltage = <TEGRA_PIN_ENABLE>;
|
||||||
|
nvidia,tristate = <TEGRA_PIN_DISABLE>;
|
||||||
|
nvidia,pull = <TEGRA_PIN_PULL_NONE>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
clkreq_c5_bi_dir_state: clkreq_c5_bi_dir {
|
||||||
|
clkreq {
|
||||||
|
nvidia,pins = "pex_l5_clkreq_n_pgg0";
|
||||||
|
nvidia,schmitt = <TEGRA_PIN_DISABLE>;
|
||||||
|
nvidia,lpdr = <TEGRA_PIN_ENABLE>;
|
||||||
|
nvidia,enable-input = <TEGRA_PIN_ENABLE>;
|
||||||
|
nvidia,io-high-voltage = <TEGRA_PIN_ENABLE>;
|
||||||
|
nvidia,tristate = <TEGRA_PIN_DISABLE>;
|
||||||
|
nvidia,pull = <TEGRA_PIN_PULL_NONE>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
uarta: serial@3100000 {
|
uarta: serial@3100000 {
|
||||||
compatible = "nvidia,tegra194-uart", "nvidia,tegra20-uart";
|
compatible = "nvidia,tegra194-uart", "nvidia,tegra20-uart";
|
||||||
reg = <0x03100000 0x40>;
|
reg = <0x03100000 0x40>;
|
||||||
|
@ -1365,6 +1398,9 @@
|
||||||
num-viewport = <8>;
|
num-viewport = <8>;
|
||||||
linux,pci-domain = <5>;
|
linux,pci-domain = <5>;
|
||||||
|
|
||||||
|
pinctrl-names = "default";
|
||||||
|
pinctrl-0 = <&pex_rst_c5_out_state>, <&clkreq_c5_bi_dir_state>;
|
||||||
|
|
||||||
clocks = <&bpmp TEGRA194_CLK_PEX1_CORE_5>,
|
clocks = <&bpmp TEGRA194_CLK_PEX1_CORE_5>,
|
||||||
<&bpmp TEGRA194_CLK_PEX1_CORE_5M>;
|
<&bpmp TEGRA194_CLK_PEX1_CORE_5M>;
|
||||||
clock-names = "core", "core_m";
|
clock-names = "core", "core_m";
|
||||||
|
|
|
@ -236,6 +236,16 @@ config PCI_MESON
|
||||||
and therefore the driver re-uses the DesignWare core functions to
|
and therefore the driver re-uses the DesignWare core functions to
|
||||||
implement the driver.
|
implement the driver.
|
||||||
|
|
||||||
|
config PCIE_TEGRA194
|
||||||
|
tristate "NVIDIA Tegra194 (and later) PCIe controller"
|
||||||
|
depends on ARCH_TEGRA_194_SOC || COMPILE_TEST
|
||||||
|
depends on PCI_MSI_IRQ_DOMAIN
|
||||||
|
select PCIE_DW_HOST
|
||||||
|
select PHY_TEGRA194_P2U
|
||||||
|
help
|
||||||
|
Say Y here if you want support for DesignWare core based PCIe host
|
||||||
|
controller found in NVIDIA Tegra194 SoC.
|
||||||
|
|
||||||
config PCIE_UNIPHIER
|
config PCIE_UNIPHIER
|
||||||
bool "Socionext UniPhier PCIe controllers"
|
bool "Socionext UniPhier PCIe controllers"
|
||||||
depends on ARCH_UNIPHIER || COMPILE_TEST
|
depends on ARCH_UNIPHIER || COMPILE_TEST
|
||||||
|
|
|
@ -16,6 +16,7 @@ obj-$(CONFIG_PCIE_ARTPEC6) += pcie-artpec6.o
|
||||||
obj-$(CONFIG_PCIE_KIRIN) += pcie-kirin.o
|
obj-$(CONFIG_PCIE_KIRIN) += pcie-kirin.o
|
||||||
obj-$(CONFIG_PCIE_HISI_STB) += pcie-histb.o
|
obj-$(CONFIG_PCIE_HISI_STB) += pcie-histb.o
|
||||||
obj-$(CONFIG_PCI_MESON) += pci-meson.o
|
obj-$(CONFIG_PCI_MESON) += pci-meson.o
|
||||||
|
obj-$(CONFIG_PCIE_TEGRA194) += pcie-tegra194.o
|
||||||
obj-$(CONFIG_PCIE_UNIPHIER) += pcie-uniphier.o
|
obj-$(CONFIG_PCIE_UNIPHIER) += pcie-uniphier.o
|
||||||
|
|
||||||
# The following drivers are for devices that use the generic ACPI
|
# The following drivers are for devices that use the generic ACPI
|
||||||
|
|
|
@ -40,39 +40,6 @@ void dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar)
|
||||||
__dw_pcie_ep_reset_bar(pci, bar, 0);
|
__dw_pcie_ep_reset_bar(pci, bar, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static u8 __dw_pcie_ep_find_next_cap(struct dw_pcie *pci, u8 cap_ptr,
|
|
||||||
u8 cap)
|
|
||||||
{
|
|
||||||
u8 cap_id, next_cap_ptr;
|
|
||||||
u16 reg;
|
|
||||||
|
|
||||||
if (!cap_ptr)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
reg = dw_pcie_readw_dbi(pci, cap_ptr);
|
|
||||||
cap_id = (reg & 0x00ff);
|
|
||||||
|
|
||||||
if (cap_id > PCI_CAP_ID_MAX)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (cap_id == cap)
|
|
||||||
return cap_ptr;
|
|
||||||
|
|
||||||
next_cap_ptr = (reg & 0xff00) >> 8;
|
|
||||||
return __dw_pcie_ep_find_next_cap(pci, next_cap_ptr, cap);
|
|
||||||
}
|
|
||||||
|
|
||||||
static u8 dw_pcie_ep_find_capability(struct dw_pcie *pci, u8 cap)
|
|
||||||
{
|
|
||||||
u8 next_cap_ptr;
|
|
||||||
u16 reg;
|
|
||||||
|
|
||||||
reg = dw_pcie_readw_dbi(pci, PCI_CAPABILITY_LIST);
|
|
||||||
next_cap_ptr = (reg & 0x00ff);
|
|
||||||
|
|
||||||
return __dw_pcie_ep_find_next_cap(pci, next_cap_ptr, cap);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int dw_pcie_ep_write_header(struct pci_epc *epc, u8 func_no,
|
static int dw_pcie_ep_write_header(struct pci_epc *epc, u8 func_no,
|
||||||
struct pci_epf_header *hdr)
|
struct pci_epf_header *hdr)
|
||||||
{
|
{
|
||||||
|
@ -620,9 +587,9 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep)
|
||||||
dev_err(dev, "Failed to reserve memory for MSI/MSI-X\n");
|
dev_err(dev, "Failed to reserve memory for MSI/MSI-X\n");
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
ep->msi_cap = dw_pcie_ep_find_capability(pci, PCI_CAP_ID_MSI);
|
ep->msi_cap = dw_pcie_find_capability(pci, PCI_CAP_ID_MSI);
|
||||||
|
|
||||||
ep->msix_cap = dw_pcie_ep_find_capability(pci, PCI_CAP_ID_MSIX);
|
ep->msix_cap = dw_pcie_find_capability(pci, PCI_CAP_ID_MSIX);
|
||||||
|
|
||||||
offset = dw_pcie_ep_find_ext_capability(pci, PCI_EXT_CAP_ID_REBAR);
|
offset = dw_pcie_ep_find_ext_capability(pci, PCI_EXT_CAP_ID_REBAR);
|
||||||
if (offset) {
|
if (offset) {
|
||||||
|
|
|
@ -644,6 +644,12 @@ void dw_pcie_setup_rc(struct pcie_port *pp)
|
||||||
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);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Enable DBI read-only registers for writing/updating configuration.
|
||||||
|
* Write permission gets disabled towards the end of this function.
|
||||||
|
*/
|
||||||
|
dw_pcie_dbi_ro_wr_en(pci);
|
||||||
|
|
||||||
dw_pcie_setup(pci);
|
dw_pcie_setup(pci);
|
||||||
|
|
||||||
if (!pp->ops->msi_host_init) {
|
if (!pp->ops->msi_host_init) {
|
||||||
|
@ -666,12 +672,10 @@ void dw_pcie_setup_rc(struct pcie_port *pp)
|
||||||
dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_1, 0x00000000);
|
dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_1, 0x00000000);
|
||||||
|
|
||||||
/* Setup interrupt pins */
|
/* Setup interrupt pins */
|
||||||
dw_pcie_dbi_ro_wr_en(pci);
|
|
||||||
val = dw_pcie_readl_dbi(pci, PCI_INTERRUPT_LINE);
|
val = dw_pcie_readl_dbi(pci, PCI_INTERRUPT_LINE);
|
||||||
val &= 0xffff00ff;
|
val &= 0xffff00ff;
|
||||||
val |= 0x00000100;
|
val |= 0x00000100;
|
||||||
dw_pcie_writel_dbi(pci, PCI_INTERRUPT_LINE, val);
|
dw_pcie_writel_dbi(pci, PCI_INTERRUPT_LINE, val);
|
||||||
dw_pcie_dbi_ro_wr_dis(pci);
|
|
||||||
|
|
||||||
/* Setup bus numbers */
|
/* Setup bus numbers */
|
||||||
val = dw_pcie_readl_dbi(pci, PCI_PRIMARY_BUS);
|
val = dw_pcie_readl_dbi(pci, PCI_PRIMARY_BUS);
|
||||||
|
@ -703,15 +707,13 @@ void dw_pcie_setup_rc(struct pcie_port *pp)
|
||||||
|
|
||||||
dw_pcie_wr_own_conf(pp, PCI_BASE_ADDRESS_0, 4, 0);
|
dw_pcie_wr_own_conf(pp, PCI_BASE_ADDRESS_0, 4, 0);
|
||||||
|
|
||||||
/* Enable write permission for the DBI read-only register */
|
|
||||||
dw_pcie_dbi_ro_wr_en(pci);
|
|
||||||
/* Program correct class for RC */
|
/* Program correct class for RC */
|
||||||
dw_pcie_wr_own_conf(pp, PCI_CLASS_DEVICE, 2, PCI_CLASS_BRIDGE_PCI);
|
dw_pcie_wr_own_conf(pp, PCI_CLASS_DEVICE, 2, PCI_CLASS_BRIDGE_PCI);
|
||||||
/* Better disable write permission right after the update */
|
|
||||||
dw_pcie_dbi_ro_wr_dis(pci);
|
|
||||||
|
|
||||||
dw_pcie_rd_own_conf(pp, PCIE_LINK_WIDTH_SPEED_CONTROL, 4, &val);
|
dw_pcie_rd_own_conf(pp, PCIE_LINK_WIDTH_SPEED_CONTROL, 4, &val);
|
||||||
val |= PORT_LOGIC_SPEED_CHANGE;
|
val |= PORT_LOGIC_SPEED_CHANGE;
|
||||||
dw_pcie_wr_own_conf(pp, PCIE_LINK_WIDTH_SPEED_CONTROL, 4, val);
|
dw_pcie_wr_own_conf(pp, PCIE_LINK_WIDTH_SPEED_CONTROL, 4, val);
|
||||||
|
|
||||||
|
dw_pcie_dbi_ro_wr_dis(pci);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(dw_pcie_setup_rc);
|
EXPORT_SYMBOL_GPL(dw_pcie_setup_rc);
|
||||||
|
|
|
@ -14,6 +14,86 @@
|
||||||
|
|
||||||
#include "pcie-designware.h"
|
#include "pcie-designware.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* These interfaces resemble the pci_find_*capability() interfaces, but these
|
||||||
|
* are for configuring host controllers, which are bridges *to* PCI devices but
|
||||||
|
* are not PCI devices themselves.
|
||||||
|
*/
|
||||||
|
static u8 __dw_pcie_find_next_cap(struct dw_pcie *pci, u8 cap_ptr,
|
||||||
|
u8 cap)
|
||||||
|
{
|
||||||
|
u8 cap_id, next_cap_ptr;
|
||||||
|
u16 reg;
|
||||||
|
|
||||||
|
if (!cap_ptr)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
reg = dw_pcie_readw_dbi(pci, cap_ptr);
|
||||||
|
cap_id = (reg & 0x00ff);
|
||||||
|
|
||||||
|
if (cap_id > PCI_CAP_ID_MAX)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (cap_id == cap)
|
||||||
|
return cap_ptr;
|
||||||
|
|
||||||
|
next_cap_ptr = (reg & 0xff00) >> 8;
|
||||||
|
return __dw_pcie_find_next_cap(pci, next_cap_ptr, cap);
|
||||||
|
}
|
||||||
|
|
||||||
|
u8 dw_pcie_find_capability(struct dw_pcie *pci, u8 cap)
|
||||||
|
{
|
||||||
|
u8 next_cap_ptr;
|
||||||
|
u16 reg;
|
||||||
|
|
||||||
|
reg = dw_pcie_readw_dbi(pci, PCI_CAPABILITY_LIST);
|
||||||
|
next_cap_ptr = (reg & 0x00ff);
|
||||||
|
|
||||||
|
return __dw_pcie_find_next_cap(pci, next_cap_ptr, cap);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(dw_pcie_find_capability);
|
||||||
|
|
||||||
|
static u16 dw_pcie_find_next_ext_capability(struct dw_pcie *pci, u16 start,
|
||||||
|
u8 cap)
|
||||||
|
{
|
||||||
|
u32 header;
|
||||||
|
int ttl;
|
||||||
|
int pos = PCI_CFG_SPACE_SIZE;
|
||||||
|
|
||||||
|
/* minimum 8 bytes per capability */
|
||||||
|
ttl = (PCI_CFG_SPACE_EXP_SIZE - PCI_CFG_SPACE_SIZE) / 8;
|
||||||
|
|
||||||
|
if (start)
|
||||||
|
pos = start;
|
||||||
|
|
||||||
|
header = dw_pcie_readl_dbi(pci, pos);
|
||||||
|
/*
|
||||||
|
* If we have no capabilities, this is indicated by cap ID,
|
||||||
|
* cap version and next pointer all being 0.
|
||||||
|
*/
|
||||||
|
if (header == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
while (ttl-- > 0) {
|
||||||
|
if (PCI_EXT_CAP_ID(header) == cap && pos != start)
|
||||||
|
return pos;
|
||||||
|
|
||||||
|
pos = PCI_EXT_CAP_NEXT(header);
|
||||||
|
if (pos < PCI_CFG_SPACE_SIZE)
|
||||||
|
break;
|
||||||
|
|
||||||
|
header = dw_pcie_readl_dbi(pci, pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
u16 dw_pcie_find_ext_capability(struct dw_pcie *pci, u8 cap)
|
||||||
|
{
|
||||||
|
return dw_pcie_find_next_ext_capability(pci, 0, cap);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(dw_pcie_find_ext_capability);
|
||||||
|
|
||||||
int dw_pcie_read(void __iomem *addr, int size, u32 *val)
|
int dw_pcie_read(void __iomem *addr, int size, u32 *val)
|
||||||
{
|
{
|
||||||
if (!IS_ALIGNED((uintptr_t)addr, size)) {
|
if (!IS_ALIGNED((uintptr_t)addr, size)) {
|
||||||
|
@ -376,10 +456,11 @@ int dw_pcie_wait_for_link(struct dw_pcie *pci)
|
||||||
usleep_range(LINK_WAIT_USLEEP_MIN, LINK_WAIT_USLEEP_MAX);
|
usleep_range(LINK_WAIT_USLEEP_MIN, LINK_WAIT_USLEEP_MAX);
|
||||||
}
|
}
|
||||||
|
|
||||||
dev_err(pci->dev, "Phy link never came up\n");
|
dev_info(pci->dev, "Phy link never came up\n");
|
||||||
|
|
||||||
return -ETIMEDOUT;
|
return -ETIMEDOUT;
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(dw_pcie_wait_for_link);
|
||||||
|
|
||||||
int dw_pcie_link_up(struct dw_pcie *pci)
|
int dw_pcie_link_up(struct dw_pcie *pci)
|
||||||
{
|
{
|
||||||
|
@ -468,4 +549,11 @@ void dw_pcie_setup(struct dw_pcie *pci)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, val);
|
dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, val);
|
||||||
|
|
||||||
|
if (of_property_read_bool(np, "snps,enable-cdm-check")) {
|
||||||
|
val = dw_pcie_readl_dbi(pci, PCIE_PL_CHK_REG_CONTROL_STATUS);
|
||||||
|
val |= PCIE_PL_CHK_REG_CHK_REG_CONTINUOUS |
|
||||||
|
PCIE_PL_CHK_REG_CHK_REG_START;
|
||||||
|
dw_pcie_writel_dbi(pci, PCIE_PL_CHK_REG_CONTROL_STATUS, val);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,6 +86,15 @@
|
||||||
#define PCIE_MISC_CONTROL_1_OFF 0x8BC
|
#define PCIE_MISC_CONTROL_1_OFF 0x8BC
|
||||||
#define PCIE_DBI_RO_WR_EN BIT(0)
|
#define PCIE_DBI_RO_WR_EN BIT(0)
|
||||||
|
|
||||||
|
#define PCIE_PL_CHK_REG_CONTROL_STATUS 0xB20
|
||||||
|
#define PCIE_PL_CHK_REG_CHK_REG_START BIT(0)
|
||||||
|
#define PCIE_PL_CHK_REG_CHK_REG_CONTINUOUS BIT(1)
|
||||||
|
#define PCIE_PL_CHK_REG_CHK_REG_COMPARISON_ERROR BIT(16)
|
||||||
|
#define PCIE_PL_CHK_REG_CHK_REG_LOGIC_ERROR BIT(17)
|
||||||
|
#define PCIE_PL_CHK_REG_CHK_REG_COMPLETE BIT(18)
|
||||||
|
|
||||||
|
#define PCIE_PL_CHK_REG_ERR_ADDR 0xB28
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* iATU Unroll-specific register definitions
|
* iATU Unroll-specific register definitions
|
||||||
* From 4.80 core version the address translation will be made by unroll
|
* From 4.80 core version the address translation will be made by unroll
|
||||||
|
@ -251,6 +260,9 @@ struct dw_pcie {
|
||||||
#define to_dw_pcie_from_ep(endpoint) \
|
#define to_dw_pcie_from_ep(endpoint) \
|
||||||
container_of((endpoint), struct dw_pcie, ep)
|
container_of((endpoint), struct dw_pcie, ep)
|
||||||
|
|
||||||
|
u8 dw_pcie_find_capability(struct dw_pcie *pci, u8 cap);
|
||||||
|
u16 dw_pcie_find_ext_capability(struct dw_pcie *pci, u8 cap);
|
||||||
|
|
||||||
int dw_pcie_read(void __iomem *addr, int size, u32 *val);
|
int dw_pcie_read(void __iomem *addr, int size, u32 *val);
|
||||||
int dw_pcie_write(void __iomem *addr, int size, u32 val);
|
int dw_pcie_write(void __iomem *addr, int size, u32 val);
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -2237,14 +2237,15 @@ static int tegra_pcie_parse_dt(struct tegra_pcie *pcie)
|
||||||
err = of_pci_get_devfn(port);
|
err = of_pci_get_devfn(port);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
dev_err(dev, "failed to parse address: %d\n", err);
|
dev_err(dev, "failed to parse address: %d\n", err);
|
||||||
return err;
|
goto err_node_put;
|
||||||
}
|
}
|
||||||
|
|
||||||
index = PCI_SLOT(err);
|
index = PCI_SLOT(err);
|
||||||
|
|
||||||
if (index < 1 || index > soc->num_ports) {
|
if (index < 1 || index > soc->num_ports) {
|
||||||
dev_err(dev, "invalid port number: %d\n", index);
|
dev_err(dev, "invalid port number: %d\n", index);
|
||||||
return -EINVAL;
|
err = -EINVAL;
|
||||||
|
goto err_node_put;
|
||||||
}
|
}
|
||||||
|
|
||||||
index--;
|
index--;
|
||||||
|
@ -2253,12 +2254,13 @@ static int tegra_pcie_parse_dt(struct tegra_pcie *pcie)
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
dev_err(dev, "failed to parse # of lanes: %d\n",
|
dev_err(dev, "failed to parse # of lanes: %d\n",
|
||||||
err);
|
err);
|
||||||
return err;
|
goto err_node_put;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (value > 16) {
|
if (value > 16) {
|
||||||
dev_err(dev, "invalid # of lanes: %u\n", value);
|
dev_err(dev, "invalid # of lanes: %u\n", value);
|
||||||
return -EINVAL;
|
err = -EINVAL;
|
||||||
|
goto err_node_put;
|
||||||
}
|
}
|
||||||
|
|
||||||
lanes |= value << (index << 3);
|
lanes |= value << (index << 3);
|
||||||
|
@ -2272,13 +2274,15 @@ static int tegra_pcie_parse_dt(struct tegra_pcie *pcie)
|
||||||
lane += value;
|
lane += value;
|
||||||
|
|
||||||
rp = devm_kzalloc(dev, sizeof(*rp), GFP_KERNEL);
|
rp = devm_kzalloc(dev, sizeof(*rp), GFP_KERNEL);
|
||||||
if (!rp)
|
if (!rp) {
|
||||||
return -ENOMEM;
|
err = -ENOMEM;
|
||||||
|
goto err_node_put;
|
||||||
|
}
|
||||||
|
|
||||||
err = of_address_to_resource(port, 0, &rp->regs);
|
err = of_address_to_resource(port, 0, &rp->regs);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
dev_err(dev, "failed to parse address: %d\n", err);
|
dev_err(dev, "failed to parse address: %d\n", err);
|
||||||
return err;
|
goto err_node_put;
|
||||||
}
|
}
|
||||||
|
|
||||||
INIT_LIST_HEAD(&rp->list);
|
INIT_LIST_HEAD(&rp->list);
|
||||||
|
@ -2330,6 +2334,10 @@ static int tegra_pcie_parse_dt(struct tegra_pcie *pcie)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
err_node_put:
|
||||||
|
of_node_put(port);
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -2591,6 +2591,59 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_NVIDIA,
|
||||||
PCI_DEVICE_ID_NVIDIA_NVENET_15,
|
PCI_DEVICE_ID_NVIDIA_NVENET_15,
|
||||||
nvenet_msi_disable);
|
nvenet_msi_disable);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* PCIe spec r4.0 sec 7.7.1.2 and sec 7.7.2.2 say that if MSI/MSI-X is enabled,
|
||||||
|
* then the device can't use INTx interrupts. Tegra's PCIe root ports don't
|
||||||
|
* generate MSI interrupts for PME and AER events instead only INTx interrupts
|
||||||
|
* are generated. Though Tegra's PCIe root ports can generate MSI interrupts
|
||||||
|
* for other events, since PCIe specificiation doesn't support using a mix of
|
||||||
|
* INTx and MSI/MSI-X, it is required to disable MSI interrupts to avoid port
|
||||||
|
* service drivers registering their respective ISRs for MSIs.
|
||||||
|
*/
|
||||||
|
static void pci_quirk_nvidia_tegra_disable_rp_msi(struct pci_dev *dev)
|
||||||
|
{
|
||||||
|
dev->no_msi = 1;
|
||||||
|
}
|
||||||
|
DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_VENDOR_ID_NVIDIA, 0x1ad0,
|
||||||
|
PCI_CLASS_BRIDGE_PCI, 8,
|
||||||
|
pci_quirk_nvidia_tegra_disable_rp_msi);
|
||||||
|
DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_VENDOR_ID_NVIDIA, 0x1ad1,
|
||||||
|
PCI_CLASS_BRIDGE_PCI, 8,
|
||||||
|
pci_quirk_nvidia_tegra_disable_rp_msi);
|
||||||
|
DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_VENDOR_ID_NVIDIA, 0x1ad2,
|
||||||
|
PCI_CLASS_BRIDGE_PCI, 8,
|
||||||
|
pci_quirk_nvidia_tegra_disable_rp_msi);
|
||||||
|
DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_VENDOR_ID_NVIDIA, 0x0bf0,
|
||||||
|
PCI_CLASS_BRIDGE_PCI, 8,
|
||||||
|
pci_quirk_nvidia_tegra_disable_rp_msi);
|
||||||
|
DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_VENDOR_ID_NVIDIA, 0x0bf1,
|
||||||
|
PCI_CLASS_BRIDGE_PCI, 8,
|
||||||
|
pci_quirk_nvidia_tegra_disable_rp_msi);
|
||||||
|
DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_VENDOR_ID_NVIDIA, 0x0e1c,
|
||||||
|
PCI_CLASS_BRIDGE_PCI, 8,
|
||||||
|
pci_quirk_nvidia_tegra_disable_rp_msi);
|
||||||
|
DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_VENDOR_ID_NVIDIA, 0x0e1d,
|
||||||
|
PCI_CLASS_BRIDGE_PCI, 8,
|
||||||
|
pci_quirk_nvidia_tegra_disable_rp_msi);
|
||||||
|
DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_VENDOR_ID_NVIDIA, 0x0e12,
|
||||||
|
PCI_CLASS_BRIDGE_PCI, 8,
|
||||||
|
pci_quirk_nvidia_tegra_disable_rp_msi);
|
||||||
|
DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_VENDOR_ID_NVIDIA, 0x0e13,
|
||||||
|
PCI_CLASS_BRIDGE_PCI, 8,
|
||||||
|
pci_quirk_nvidia_tegra_disable_rp_msi);
|
||||||
|
DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_VENDOR_ID_NVIDIA, 0x0fae,
|
||||||
|
PCI_CLASS_BRIDGE_PCI, 8,
|
||||||
|
pci_quirk_nvidia_tegra_disable_rp_msi);
|
||||||
|
DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_VENDOR_ID_NVIDIA, 0x0faf,
|
||||||
|
PCI_CLASS_BRIDGE_PCI, 8,
|
||||||
|
pci_quirk_nvidia_tegra_disable_rp_msi);
|
||||||
|
DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_VENDOR_ID_NVIDIA, 0x10e5,
|
||||||
|
PCI_CLASS_BRIDGE_PCI, 8,
|
||||||
|
pci_quirk_nvidia_tegra_disable_rp_msi);
|
||||||
|
DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_VENDOR_ID_NVIDIA, 0x10e6,
|
||||||
|
PCI_CLASS_BRIDGE_PCI, 8,
|
||||||
|
pci_quirk_nvidia_tegra_disable_rp_msi);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Some versions of the MCP55 bridge from Nvidia have a legacy IRQ routing
|
* Some versions of the MCP55 bridge from Nvidia have a legacy IRQ routing
|
||||||
* config register. This register controls the routing of legacy
|
* config register. This register controls the routing of legacy
|
||||||
|
|
|
@ -7,3 +7,10 @@ config PHY_TEGRA_XUSB
|
||||||
|
|
||||||
To compile this driver as a module, choose M here: the module will
|
To compile this driver as a module, choose M here: the module will
|
||||||
be called phy-tegra-xusb.
|
be called phy-tegra-xusb.
|
||||||
|
|
||||||
|
config PHY_TEGRA194_P2U
|
||||||
|
tristate "NVIDIA Tegra194 PIPE2UPHY PHY driver"
|
||||||
|
depends on ARCH_TEGRA_194_SOC || COMPILE_TEST
|
||||||
|
select GENERIC_PHY
|
||||||
|
help
|
||||||
|
Enable this to support the P2U (PIPE to UPHY) that is part of Tegra 19x SOCs.
|
||||||
|
|
|
@ -6,3 +6,4 @@ phy-tegra-xusb-$(CONFIG_ARCH_TEGRA_124_SOC) += xusb-tegra124.o
|
||||||
phy-tegra-xusb-$(CONFIG_ARCH_TEGRA_132_SOC) += xusb-tegra124.o
|
phy-tegra-xusb-$(CONFIG_ARCH_TEGRA_132_SOC) += xusb-tegra124.o
|
||||||
phy-tegra-xusb-$(CONFIG_ARCH_TEGRA_210_SOC) += xusb-tegra210.o
|
phy-tegra-xusb-$(CONFIG_ARCH_TEGRA_210_SOC) += xusb-tegra210.o
|
||||||
phy-tegra-xusb-$(CONFIG_ARCH_TEGRA_186_SOC) += xusb-tegra186.o
|
phy-tegra-xusb-$(CONFIG_ARCH_TEGRA_186_SOC) += xusb-tegra186.o
|
||||||
|
obj-$(CONFIG_PHY_TEGRA194_P2U) += phy-tegra194-p2u.o
|
||||||
|
|
|
@ -0,0 +1,120 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0+
|
||||||
|
/*
|
||||||
|
* P2U (PIPE to UPHY) driver for Tegra T194 SoC
|
||||||
|
*
|
||||||
|
* Copyright (C) 2019 NVIDIA Corporation.
|
||||||
|
*
|
||||||
|
* Author: Vidya Sagar <vidyas@nvidia.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/err.h>
|
||||||
|
#include <linux/io.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/of.h>
|
||||||
|
#include <linux/of_platform.h>
|
||||||
|
#include <linux/phy/phy.h>
|
||||||
|
|
||||||
|
#define P2U_PERIODIC_EQ_CTRL_GEN3 0xc0
|
||||||
|
#define P2U_PERIODIC_EQ_CTRL_GEN3_PERIODIC_EQ_EN BIT(0)
|
||||||
|
#define P2U_PERIODIC_EQ_CTRL_GEN3_INIT_PRESET_EQ_TRAIN_EN BIT(1)
|
||||||
|
#define P2U_PERIODIC_EQ_CTRL_GEN4 0xc4
|
||||||
|
#define P2U_PERIODIC_EQ_CTRL_GEN4_INIT_PRESET_EQ_TRAIN_EN BIT(1)
|
||||||
|
|
||||||
|
#define P2U_RX_DEBOUNCE_TIME 0xa4
|
||||||
|
#define P2U_RX_DEBOUNCE_TIME_DEBOUNCE_TIMER_MASK 0xffff
|
||||||
|
#define P2U_RX_DEBOUNCE_TIME_DEBOUNCE_TIMER_VAL 160
|
||||||
|
|
||||||
|
struct tegra_p2u {
|
||||||
|
void __iomem *base;
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline void p2u_writel(struct tegra_p2u *phy, const u32 value,
|
||||||
|
const u32 reg)
|
||||||
|
{
|
||||||
|
writel_relaxed(value, phy->base + reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline u32 p2u_readl(struct tegra_p2u *phy, const u32 reg)
|
||||||
|
{
|
||||||
|
return readl_relaxed(phy->base + reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tegra_p2u_power_on(struct phy *x)
|
||||||
|
{
|
||||||
|
struct tegra_p2u *phy = phy_get_drvdata(x);
|
||||||
|
u32 val;
|
||||||
|
|
||||||
|
val = p2u_readl(phy, P2U_PERIODIC_EQ_CTRL_GEN3);
|
||||||
|
val &= ~P2U_PERIODIC_EQ_CTRL_GEN3_PERIODIC_EQ_EN;
|
||||||
|
val |= P2U_PERIODIC_EQ_CTRL_GEN3_INIT_PRESET_EQ_TRAIN_EN;
|
||||||
|
p2u_writel(phy, val, P2U_PERIODIC_EQ_CTRL_GEN3);
|
||||||
|
|
||||||
|
val = p2u_readl(phy, P2U_PERIODIC_EQ_CTRL_GEN4);
|
||||||
|
val |= P2U_PERIODIC_EQ_CTRL_GEN4_INIT_PRESET_EQ_TRAIN_EN;
|
||||||
|
p2u_writel(phy, val, P2U_PERIODIC_EQ_CTRL_GEN4);
|
||||||
|
|
||||||
|
val = p2u_readl(phy, P2U_RX_DEBOUNCE_TIME);
|
||||||
|
val &= ~P2U_RX_DEBOUNCE_TIME_DEBOUNCE_TIMER_MASK;
|
||||||
|
val |= P2U_RX_DEBOUNCE_TIME_DEBOUNCE_TIMER_VAL;
|
||||||
|
p2u_writel(phy, val, P2U_RX_DEBOUNCE_TIME);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct phy_ops ops = {
|
||||||
|
.power_on = tegra_p2u_power_on,
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int tegra_p2u_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct phy_provider *phy_provider;
|
||||||
|
struct device *dev = &pdev->dev;
|
||||||
|
struct phy *generic_phy;
|
||||||
|
struct tegra_p2u *phy;
|
||||||
|
struct resource *res;
|
||||||
|
|
||||||
|
phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL);
|
||||||
|
if (!phy)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ctl");
|
||||||
|
phy->base = devm_ioremap_resource(dev, res);
|
||||||
|
if (IS_ERR(phy->base))
|
||||||
|
return PTR_ERR(phy->base);
|
||||||
|
|
||||||
|
platform_set_drvdata(pdev, phy);
|
||||||
|
|
||||||
|
generic_phy = devm_phy_create(dev, NULL, &ops);
|
||||||
|
if (IS_ERR(generic_phy))
|
||||||
|
return PTR_ERR(generic_phy);
|
||||||
|
|
||||||
|
phy_set_drvdata(generic_phy, phy);
|
||||||
|
|
||||||
|
phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
|
||||||
|
if (IS_ERR(phy_provider))
|
||||||
|
return PTR_ERR(phy_provider);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct of_device_id tegra_p2u_id_table[] = {
|
||||||
|
{
|
||||||
|
.compatible = "nvidia,tegra194-p2u",
|
||||||
|
},
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(of, tegra_p2u_id_table);
|
||||||
|
|
||||||
|
static struct platform_driver tegra_p2u_driver = {
|
||||||
|
.probe = tegra_p2u_probe,
|
||||||
|
.driver = {
|
||||||
|
.name = "tegra194-p2u",
|
||||||
|
.of_match_table = tegra_p2u_id_table,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
module_platform_driver(tegra_p2u_driver);
|
||||||
|
|
||||||
|
MODULE_AUTHOR("Vidya Sagar <vidyas@nvidia.com>");
|
||||||
|
MODULE_DESCRIPTION("NVIDIA Tegra194 PIPE2UPHY PHY driver");
|
||||||
|
MODULE_LICENSE("GPL v2");
|
|
@ -714,7 +714,9 @@
|
||||||
#define PCI_EXT_CAP_ID_DPC 0x1D /* Downstream Port Containment */
|
#define PCI_EXT_CAP_ID_DPC 0x1D /* Downstream Port Containment */
|
||||||
#define PCI_EXT_CAP_ID_L1SS 0x1E /* L1 PM Substates */
|
#define PCI_EXT_CAP_ID_L1SS 0x1E /* L1 PM Substates */
|
||||||
#define PCI_EXT_CAP_ID_PTM 0x1F /* Precision Time Measurement */
|
#define PCI_EXT_CAP_ID_PTM 0x1F /* Precision Time Measurement */
|
||||||
#define PCI_EXT_CAP_ID_MAX PCI_EXT_CAP_ID_PTM
|
#define PCI_EXT_CAP_ID_DLF 0x25 /* Data Link Feature */
|
||||||
|
#define PCI_EXT_CAP_ID_PL_16GT 0x26 /* Physical Layer 16.0 GT/s */
|
||||||
|
#define PCI_EXT_CAP_ID_MAX PCI_EXT_CAP_ID_PL_16GT
|
||||||
|
|
||||||
#define PCI_EXT_CAP_DSN_SIZEOF 12
|
#define PCI_EXT_CAP_DSN_SIZEOF 12
|
||||||
#define PCI_EXT_CAP_MCAST_ENDPOINT_SIZEOF 40
|
#define PCI_EXT_CAP_MCAST_ENDPOINT_SIZEOF 40
|
||||||
|
@ -1054,4 +1056,14 @@
|
||||||
#define PCI_L1SS_CTL1_LTR_L12_TH_SCALE 0xe0000000 /* LTR_L1.2_THRESHOLD_Scale */
|
#define PCI_L1SS_CTL1_LTR_L12_TH_SCALE 0xe0000000 /* LTR_L1.2_THRESHOLD_Scale */
|
||||||
#define PCI_L1SS_CTL2 0x0c /* Control 2 Register */
|
#define PCI_L1SS_CTL2 0x0c /* Control 2 Register */
|
||||||
|
|
||||||
|
/* Data Link Feature */
|
||||||
|
#define PCI_DLF_CAP 0x04 /* Capabilities Register */
|
||||||
|
#define PCI_DLF_EXCHANGE_ENABLE 0x80000000 /* Data Link Feature Exchange Enable */
|
||||||
|
|
||||||
|
/* Physical Layer 16.0 GT/s */
|
||||||
|
#define PCI_PL_16GT_LE_CTRL 0x20 /* Lane Equalization Control Register */
|
||||||
|
#define PCI_PL_16GT_LE_CTRL_DSP_TX_PRESET_MASK 0x0000000F
|
||||||
|
#define PCI_PL_16GT_LE_CTRL_USP_TX_PRESET_MASK 0x000000F0
|
||||||
|
#define PCI_PL_16GT_LE_CTRL_USP_TX_PRESET_SHIFT 4
|
||||||
|
|
||||||
#endif /* LINUX_PCI_REGS_H */
|
#endif /* LINUX_PCI_REGS_H */
|
||||||
|
|
Loading…
Reference in New Issue