pci-v4.14-changes
-----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJZsr8cAAoJEFmIoMA60/r8lXYQAKViYIRMJDD4n3NhjMeLOsnJ vwaBmWlLRjSFIEpag5kMjS1RJE17qAvmkBZnDvSNZ6cT28INkkZnVM2IW96WECVq 64MIvDijVPcvqGuWePCfWdDiSXApiDWwJuw55BOhmvV996wGy0gYgzpPY+1g0Knh XzH9IOzDL79hZleLfsxX0MLV6FGBVtOsr0jvQ04k4IgEMIxEDTlbw85rnrvzQUtc 0Vj2koaxWIESZsq7G/wiZb2n6ekaFdXO/VlVvvhmTSDLCBaJ63Hb/gfOhwMuVkS6 B3cVprNrCT0dSzWmU4ZXf+wpOyDpBexlemW/OR/6CQUkC6AUS6kQ5si1X44dbGmJ nBPh414tdlm/6V4h/A3UFPOajSGa/ZWZ/uQZPfvKs1R6WfjUerWVBfUpAzPbgjam c/mhJ19HYT1J7vFBfhekBMeY2Px3JgSJ9rNsrFl48ynAALaX5GEwdpo4aqBfscKz 4/f9fU4ysumopvCEuKD2SsJvsPKd5gMQGGtvAhXM1TxvAoQ5V4cc99qEetAPXXPf h2EqWm4ph7YP4a+n/OZBjzluHCmZJn1CntH5+//6wpUk6HnmzsftGELuO9n12cLE GGkreI3T9ctV1eOkzVVa0l0QTE1X/VLyEyKCtb9obXsDaG4Ud7uKQoZgB19DwyTJ EG76ridTolUFVV+wzJD9 =9cLP -----END PGP SIGNATURE----- Merge tag 'pci-v4.14-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci Pull PCI updates from Bjorn Helgaas: - add enhanced Downstream Port Containment support, which prints more details about Root Port Programmed I/O errors (Dongdong Liu) - add Layerscape ls1088a and ls2088a support (Hou Zhiqiang) - add MediaTek MT2712 and MT7622 support (Ryder Lee) - add MediaTek MT2712 and MT7622 MSI support (Honghui Zhang) - add Qualcom IPQ8074 support (Varadarajan Narayanan) - add R-Car r8a7743/5 device tree support (Biju Das) - add Rockchip per-lane PHY support for better power management (Shawn Lin) - fix IRQ mapping for hot-added devices by replacing the pci_fixup_irqs() boot-time design with a host bridge hook called at probe-time (Lorenzo Pieralisi, Matthew Minter) - fix race when enabling two devices that results in upstream bridge not being enabled correctly (Srinath Mannam) - fix pciehp power fault infinite loop (Keith Busch) - fix SHPC bridge MSI hotplug events by enabling bus mastering (Aleksandr Bezzubikov) - fix a VFIO issue by correcting PCIe capability sizes (Alex Williamson) - fix an INTD issue on Xilinx and possibly other drivers by unifying INTx IRQ domain support (Paul Burton) - avoid IOMMU stalls by marking AMD Stoney GPU ATS as broken (Joerg Roedel) - allow APM X-Gene device assignment to guests by adding an ACS quirk (Feng Kan) - fix driver crashes by disabling Extended Tags on Broadcom HT2100 (Extended Tags support is required for PCIe Receivers but not Requesters, and we now enable them by default when Requesters support them) (Sinan Kaya) - fix MSIs for devices that use phantom RIDs for DMA by assuming MSIs use the real Requester ID (not a phantom RID) (Robin Murphy) - prevent assignment of Intel VMD children to guests (which may be supported eventually, but isn't yet) by not associating an IOMMU with them (Jon Derrick) - fix Intel VMD suspend/resume by releasing IRQs on suspend (Scott Bauer) - fix a Function-Level Reset issue with Intel 750 NVMe by waiting longer (up to 60sec instead of 1sec) for device to become ready (Sinan Kaya) - fix a Function-Level Reset issue on iProc Stingray by working around hardware defects in the CRS implementation (Oza Pawandeep) - fix an issue with Intel NVMe P3700 after an iProc reset by adding a delay during shutdown (Oza Pawandeep) - fix a Microsoft Hyper-V lockdep issue by polling instead of blocking in compose_msi_msg() (Stephen Hemminger) - fix a wireless LAN driver timeout by clearing DesignWare MSI interrupt status after it is handled, not before (Faiz Abbas) - fix DesignWare ATU enable checking (Jisheng Zhang) - reduce Layerscape dependencies on the bootloader by doing more initialization in the driver (Hou Zhiqiang) - improve Intel VMD performance allowing allocation of more IRQ vectors than present CPUs (Keith Busch) - improve endpoint framework support for initial DMA mask, different BAR sizes, configurable page sizes, MSI, test driver, etc (Kishon Vijay Abraham I, Stan Drozd) - rework CRS support to add periodic messages while we poll during enumeration and after Function-Level Reset and prepare for possible other uses of CRS (Sinan Kaya) - clean up Root Port AER handling by removing unnecessary code and moving error handler methods to struct pcie_port_service_driver (Christoph Hellwig) - clean up error handling paths in various drivers (Bjorn Andersson, Fabio Estevam, Gustavo A. R. Silva, Harunobu Kurokawa, Jeffy Chen, Lorenzo Pieralisi, Sergei Shtylyov) - clean up SR-IOV resource handling by disabling VF decoding before updating the corresponding resource structs (Gavin Shan) - clean up DesignWare-based drivers by unifying quirks to update Class Code and Interrupt Pin and related handling of write-protected registers (Hou Zhiqiang) - clean up by adding empty generic pcibios_align_resource() and pcibios_fixup_bus() and removing empty arch-specific implementations (Palmer Dabbelt) - request exclusive reset control for several drivers to allow cleanup elsewhere (Philipp Zabel) - constify various structures (Arvind Yadav, Bhumika Goyal) - convert from full_name() to %pOF (Rob Herring) - remove unused variables from iProc, HiSi, Altera, Keystone (Shawn Lin) * tag 'pci-v4.14-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci: (170 commits) PCI: xgene: Clean up whitespace PCI: xgene: Define XGENE_PCI_EXP_CAP and use generic PCI_EXP_RTCTL offset PCI: xgene: Fix platform_get_irq() error handling PCI: xilinx-nwl: Fix platform_get_irq() error handling PCI: rockchip: Fix platform_get_irq() error handling PCI: altera: Fix platform_get_irq() error handling PCI: spear13xx: Fix platform_get_irq() error handling PCI: artpec6: Fix platform_get_irq() error handling PCI: armada8k: Fix platform_get_irq() error handling PCI: dra7xx: Fix platform_get_irq() error handling PCI: exynos: Fix platform_get_irq() error handling PCI: iproc: Clean up whitespace PCI: iproc: Rename PCI_EXP_CAP to IPROC_PCI_EXP_CAP PCI: iproc: Add 500ms delay during device shutdown PCI: Fix typos and whitespace errors PCI: Remove unused "res" variable from pci_resource_io() PCI: Correct kernel-doc of pci_vpd_srdt_size(), pci_vpd_srdt_tag() PCI/AER: Reformat AER register definitions iommu/vt-d: Prevent VMD child devices from being remapping targets x86/PCI: Use is_vmd() rather than relying on the domain number ...
This commit is contained in:
commit
0d519f2d1e
2
CREDITS
2
CREDITS
|
@ -2090,7 +2090,7 @@ S: Kuala Lumpur, Malaysia
|
|||
|
||||
N: Mohit Kumar
|
||||
D: ST Microelectronics SPEAr13xx PCI host bridge driver
|
||||
D: Synopsys Designware PCI host bridge driver
|
||||
D: Synopsys DesignWare PCI host bridge driver
|
||||
|
||||
N: Gabor Kuti
|
||||
E: seasons@falcon.sch.bme.hu
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
* Freescale 83xx and 512x PCI bridges
|
||||
|
||||
Freescale 83xx and 512x SOCs include the same pci bridge core.
|
||||
Freescale 83xx and 512x SOCs include the same PCI bridge core.
|
||||
|
||||
83xx/512x specific notes:
|
||||
- reg: should contain two address length tuples
|
||||
The first is for the internal pci bridge registers
|
||||
The second is for the pci config space access registers
|
||||
The first is for the internal PCI bridge registers
|
||||
The second is for the PCI config space access registers
|
||||
|
||||
Example (MPC8313ERDB)
|
||||
pci0: pci@e0008500 {
|
||||
|
|
|
@ -7,21 +7,21 @@ Required properties:
|
|||
"Txs": TX slave port region
|
||||
"Cra": Control register access region
|
||||
- interrupt-parent: interrupt source phandle.
|
||||
- interrupts: specifies the interrupt source of the parent interrupt controller.
|
||||
The format of the interrupt specifier depends on the parent interrupt
|
||||
controller.
|
||||
- interrupts: specifies the interrupt source of the parent interrupt
|
||||
controller. The format of the interrupt specifier depends
|
||||
on the parent interrupt controller.
|
||||
- device_type: must be "pci"
|
||||
- #address-cells: set to <3>
|
||||
- #size-cells: set to <2>
|
||||
- #size-cells: set to <2>
|
||||
- #interrupt-cells: set to <1>
|
||||
- ranges: describes the translation of addresses for root ports and standard
|
||||
PCI regions.
|
||||
- ranges: describes the translation of addresses for root ports and
|
||||
standard PCI regions.
|
||||
- interrupt-map-mask and interrupt-map: standard PCI properties to define the
|
||||
mapping of the PCIe interface to interrupt numbers.
|
||||
|
||||
Optional properties:
|
||||
- msi-parent: Link to the hardware entity that serves as the MSI controller for this PCIe
|
||||
controller.
|
||||
- msi-parent: Link to the hardware entity that serves as the MSI controller
|
||||
for this PCIe controller.
|
||||
- bus-range: PCI bus numbers covered
|
||||
|
||||
Example
|
||||
|
@ -45,5 +45,5 @@ Example
|
|||
<0 0 0 3 &pcie_0 3>,
|
||||
<0 0 0 4 &pcie_0 4>;
|
||||
ranges = <0x82000000 0x00000000 0x00000000 0xc0000000 0x00000000 0x10000000
|
||||
0x82000000 0x00000000 0x10000000 0xd0000000 0x00000000 0x10000000>;
|
||||
0x82000000 0x00000000 0x10000000 0xd0000000 0x00000000 0x10000000>;
|
||||
};
|
||||
|
|
|
@ -6,7 +6,7 @@ and thus inherits all the common properties defined in designware-pcie.txt.
|
|||
Required properties:
|
||||
- compatible: "axis,artpec6-pcie", "snps,dw-pcie"
|
||||
- reg: base addresses and lengths of the PCIe controller (DBI),
|
||||
the phy controller, and configuration address space.
|
||||
the PHY controller, and configuration address space.
|
||||
- reg-names: Must include the following entries:
|
||||
- "dbi"
|
||||
- "phy"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
* Synopsys Designware PCIe interface
|
||||
* Synopsys DesignWare PCIe interface
|
||||
|
||||
Required properties:
|
||||
- compatible: should contain "snps,dw-pcie" to identify the core.
|
||||
|
@ -17,29 +17,27 @@ RC mode:
|
|||
properties to define the mapping of the PCIe interface to interrupt
|
||||
numbers.
|
||||
EP mode:
|
||||
- num-ib-windows: number of inbound address translation
|
||||
windows
|
||||
- num-ob-windows: number of outbound address translation
|
||||
windows
|
||||
- num-ib-windows: number of inbound address translation windows
|
||||
- num-ob-windows: number of outbound address translation windows
|
||||
|
||||
Optional properties:
|
||||
- num-lanes: number of lanes to use (this property should be specified unless
|
||||
the link is brought already up in BIOS)
|
||||
- reset-gpio: gpio pin number of power good signal
|
||||
- reset-gpio: GPIO pin number of power good signal
|
||||
- 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:
|
||||
- "pcie"
|
||||
- "pcie_bus"
|
||||
RC mode:
|
||||
- num-viewport: number of view ports configured in
|
||||
hardware. If a platform does not specify it, the driver assumes 2.
|
||||
- bus-range: PCI bus numbers covered (it is recommended
|
||||
for new devicetrees to specify this property, to keep backwards
|
||||
compatibility a range of 0x00-0xff is assumed if not present)
|
||||
- num-viewport: number of view ports configured in hardware. If a platform
|
||||
does not specify it, the driver assumes 2.
|
||||
- bus-range: PCI bus numbers covered (it is recommended for new devicetrees
|
||||
to specify this property, to keep backwards compatibility a range of
|
||||
0x00-0xff is assumed if not present)
|
||||
|
||||
EP mode:
|
||||
- max-functions: maximum number of functions that can be
|
||||
configured
|
||||
- max-functions: maximum number of functions that can be configured
|
||||
|
||||
Example configuration:
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
* Freescale i.MX6 PCIe interface
|
||||
|
||||
This PCIe host controller is based on the Synopsis Designware PCIe IP
|
||||
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:
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
HiSilicon Hip05 and Hip06 PCIe host bridge DT description
|
||||
|
||||
HiSilicon PCIe host controller is based on Designware PCI core.
|
||||
It shares common functions with PCIe Designware core driver and inherits
|
||||
HiSilicon PCIe host controller is based on the Synopsys DesignWare PCI core.
|
||||
It shares common functions with the PCIe DesignWare core driver and inherits
|
||||
common properties defined in
|
||||
Documentation/devicetree/bindings/pci/designware-pci.txt.
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
HiSilicon Kirin SoCs PCIe host DT description
|
||||
|
||||
Kirin PCIe host controller is based on Designware PCI core.
|
||||
It shares common functions with PCIe Designware core driver
|
||||
and inherits common properties defined in
|
||||
Kirin PCIe host controller is based on the Synopsys DesignWare PCI core.
|
||||
It shares common functions with the PCIe DesignWare core driver and
|
||||
inherits common properties defined in
|
||||
Documentation/devicetree/bindings/pci/designware-pci.txt.
|
||||
|
||||
Additional properties are described here:
|
||||
|
@ -16,7 +16,7 @@ Required properties
|
|||
"apb": apb Ctrl register defined by Kirin;
|
||||
"phy": apb PHY register defined by Kirin;
|
||||
"config": PCIe configuration space registers.
|
||||
- reset-gpios: The gpio to generate PCIe perst assert and deassert signal.
|
||||
- reset-gpios: The GPIO to generate PCIe PERST# assert and deassert signal.
|
||||
|
||||
Optional properties:
|
||||
|
||||
|
|
|
@ -15,8 +15,10 @@ Required properties:
|
|||
- compatible: should contain the platform identifier such as:
|
||||
"fsl,ls1021a-pcie", "snps,dw-pcie"
|
||||
"fsl,ls2080a-pcie", "fsl,ls2085a-pcie", "snps,dw-pcie"
|
||||
"fsl,ls2088a-pcie"
|
||||
"fsl,ls1088a-pcie"
|
||||
"fsl,ls1046a-pcie"
|
||||
- reg: base addresses and lengths of the PCIe controller
|
||||
- reg: base addresses and lengths of the PCIe controller register blocks.
|
||||
- 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:
|
||||
|
|
|
@ -1,130 +0,0 @@
|
|||
MediaTek Gen2 PCIe controller which is available on MT7623 series SoCs
|
||||
|
||||
PCIe subsys supports single root complex (RC) with 3 Root Ports. Each root
|
||||
ports supports a Gen2 1-lane Link and has PIPE interface to PHY.
|
||||
|
||||
Required properties:
|
||||
- compatible: Should contain "mediatek,mt7623-pcie".
|
||||
- device_type: Must be "pci"
|
||||
- reg: Base addresses and lengths of the PCIe controller.
|
||||
- #address-cells: Address representation for root ports (must be 3)
|
||||
- #size-cells: Size representation for root ports (must be 2)
|
||||
- #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:
|
||||
- free_ck :for reference clock of PCIe subsys
|
||||
- sys_ck0 :for clock of Port0
|
||||
- sys_ck1 :for clock of Port1
|
||||
- sys_ck2 :for clock of Port2
|
||||
- resets: Must contain an entry for each entry in reset-names.
|
||||
See ../reset/reset.txt for details.
|
||||
- reset-names: Must include the following entries:
|
||||
- pcie-rst0 :port0 reset
|
||||
- pcie-rst1 :port1 reset
|
||||
- pcie-rst2 :port2 reset
|
||||
- phys: List of PHY specifiers (used by generic PHY framework).
|
||||
- phy-names : Must be "pcie-phy0", "pcie-phy1", "pcie-phyN".. based on the
|
||||
number of PHYs as specified in *phys* property.
|
||||
- power-domains: A phandle and power domain specifier pair to the power domain
|
||||
which is responsible for collapsing and restoring power to the peripheral.
|
||||
- bus-range: Range of bus numbers associated with this controller.
|
||||
- ranges: Ranges for the PCI memory and I/O regions.
|
||||
|
||||
In addition, the device tree node must have sub-nodes describing each
|
||||
PCIe port interface, having the following mandatory properties:
|
||||
|
||||
Required properties:
|
||||
- device_type: Must be "pci"
|
||||
- reg: Only the first four bytes are used to refer to the correct bus number
|
||||
and device number.
|
||||
- #address-cells: Must be 3
|
||||
- #size-cells: Must be 2
|
||||
- #interrupt-cells: 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.
|
||||
- ranges: Sub-ranges distributed from the PCIe controller node. An empty
|
||||
property is sufficient.
|
||||
- num-lanes: Number of lanes to use for this port.
|
||||
|
||||
Examples:
|
||||
|
||||
hifsys: syscon@1a000000 {
|
||||
compatible = "mediatek,mt7623-hifsys",
|
||||
"mediatek,mt2701-hifsys",
|
||||
"syscon";
|
||||
reg = <0 0x1a000000 0 0x1000>;
|
||||
#clock-cells = <1>;
|
||||
#reset-cells = <1>;
|
||||
};
|
||||
|
||||
pcie: pcie-controller@1a140000 {
|
||||
compatible = "mediatek,mt7623-pcie";
|
||||
device_type = "pci";
|
||||
reg = <0 0x1a140000 0 0x1000>, /* PCIe shared registers */
|
||||
<0 0x1a142000 0 0x1000>, /* Port0 registers */
|
||||
<0 0x1a143000 0 0x1000>, /* Port1 registers */
|
||||
<0 0x1a144000 0 0x1000>; /* Port2 registers */
|
||||
#address-cells = <3>;
|
||||
#size-cells = <2>;
|
||||
#interrupt-cells = <1>;
|
||||
interrupt-map-mask = <0xf800 0 0 0>;
|
||||
interrupt-map = <0x0000 0 0 0 &sysirq GIC_SPI 193 IRQ_TYPE_LEVEL_LOW>,
|
||||
<0x0800 0 0 0 &sysirq GIC_SPI 194 IRQ_TYPE_LEVEL_LOW>,
|
||||
<0x1000 0 0 0 &sysirq GIC_SPI 195 IRQ_TYPE_LEVEL_LOW>;
|
||||
clocks = <&topckgen CLK_TOP_ETHIF_SEL>,
|
||||
<&hifsys CLK_HIFSYS_PCIE0>,
|
||||
<&hifsys CLK_HIFSYS_PCIE1>,
|
||||
<&hifsys CLK_HIFSYS_PCIE2>;
|
||||
clock-names = "free_ck", "sys_ck0", "sys_ck1", "sys_ck2";
|
||||
resets = <&hifsys MT2701_HIFSYS_PCIE0_RST>,
|
||||
<&hifsys MT2701_HIFSYS_PCIE1_RST>,
|
||||
<&hifsys MT2701_HIFSYS_PCIE2_RST>;
|
||||
reset-names = "pcie-rst0", "pcie-rst1", "pcie-rst2";
|
||||
phys = <&pcie0_phy>, <&pcie1_phy>, <&pcie2_phy>;
|
||||
phy-names = "pcie-phy0", "pcie-phy1", "pcie-phy2";
|
||||
power-domains = <&scpsys MT2701_POWER_DOMAIN_HIF>;
|
||||
bus-range = <0x00 0xff>;
|
||||
ranges = <0x81000000 0 0x1a160000 0 0x1a160000 0 0x00010000 /* I/O space */
|
||||
0x83000000 0 0x60000000 0 0x60000000 0 0x10000000>; /* memory space */
|
||||
|
||||
pcie@0,0 {
|
||||
device_type = "pci";
|
||||
reg = <0x0000 0 0 0 0>;
|
||||
#address-cells = <3>;
|
||||
#size-cells = <2>;
|
||||
#interrupt-cells = <1>;
|
||||
interrupt-map-mask = <0 0 0 0>;
|
||||
interrupt-map = <0 0 0 0 &sysirq GIC_SPI 193 IRQ_TYPE_LEVEL_LOW>;
|
||||
ranges;
|
||||
num-lanes = <1>;
|
||||
};
|
||||
|
||||
pcie@1,0 {
|
||||
device_type = "pci";
|
||||
reg = <0x0800 0 0 0 0>;
|
||||
#address-cells = <3>;
|
||||
#size-cells = <2>;
|
||||
#interrupt-cells = <1>;
|
||||
interrupt-map-mask = <0 0 0 0>;
|
||||
interrupt-map = <0 0 0 0 &sysirq GIC_SPI 194 IRQ_TYPE_LEVEL_LOW>;
|
||||
ranges;
|
||||
num-lanes = <1>;
|
||||
};
|
||||
|
||||
pcie@2,0 {
|
||||
device_type = "pci";
|
||||
reg = <0x1000 0 0 0 0>;
|
||||
#address-cells = <3>;
|
||||
#size-cells = <2>;
|
||||
#interrupt-cells = <1>;
|
||||
interrupt-map-mask = <0 0 0 0>;
|
||||
interrupt-map = <0 0 0 0 &sysirq GIC_SPI 195 IRQ_TYPE_LEVEL_LOW>;
|
||||
ranges;
|
||||
num-lanes = <1>;
|
||||
};
|
||||
};
|
|
@ -0,0 +1,284 @@
|
|||
MediaTek Gen2 PCIe controller
|
||||
|
||||
Required properties:
|
||||
- compatible: Should contain one of the following strings:
|
||||
"mediatek,mt2701-pcie"
|
||||
"mediatek,mt2712-pcie"
|
||||
"mediatek,mt7622-pcie"
|
||||
"mediatek,mt7623-pcie"
|
||||
- device_type: Must be "pci"
|
||||
- reg: Base addresses and lengths of the PCIe subsys and root ports.
|
||||
- reg-names: Names of the above areas to use during resource lookup.
|
||||
- #address-cells: Address representation for root ports (must be 3)
|
||||
- #size-cells: Size representation for root ports (must be 2)
|
||||
- clocks: Must contain an entry for each entry in clock-names.
|
||||
See ../clocks/clock-bindings.txt for details.
|
||||
- clock-names:
|
||||
Mandatory entries:
|
||||
- sys_ckN :transaction layer and data link layer clock
|
||||
Required entries for MT2701/MT7623:
|
||||
- free_ck :for reference clock of PCIe subsys
|
||||
Required entries for MT2712/MT7622:
|
||||
- ahb_ckN :AHB slave interface operating clock for CSR access and RC
|
||||
initiated MMIO access
|
||||
Required entries for MT7622:
|
||||
- axi_ckN :application layer MMIO channel operating clock
|
||||
- aux_ckN :pe2_mac_bridge and pe2_mac_core operating clock when
|
||||
pcie_mac_ck/pcie_pipe_ck is turned off
|
||||
- obff_ckN :OBFF functional block operating clock
|
||||
- pipe_ckN :LTSSM and PHY/MAC layer operating clock
|
||||
where N starting from 0 to one less than the number of root ports.
|
||||
- phys: List of PHY specifiers (used by generic PHY framework).
|
||||
- phy-names : Must be "pcie-phy0", "pcie-phy1", "pcie-phyN".. based on the
|
||||
number of PHYs as specified in *phys* property.
|
||||
- power-domains: A phandle and power domain specifier pair to the power domain
|
||||
which is responsible for collapsing and restoring power to the peripheral.
|
||||
- bus-range: Range of bus numbers associated with this controller.
|
||||
- ranges: Ranges for the PCI memory and I/O regions.
|
||||
|
||||
Required properties for MT7623/MT2701:
|
||||
- #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.
|
||||
- resets: Must contain an entry for each entry in reset-names.
|
||||
See ../reset/reset.txt for details.
|
||||
- reset-names: Must be "pcie-rst0", "pcie-rst1", "pcie-rstN".. based on the
|
||||
number of root ports.
|
||||
|
||||
Required properties for MT2712/MT7622:
|
||||
-interrupts: A list of interrupt outputs of the controller, must have one
|
||||
entry for each PCIe port
|
||||
|
||||
In addition, the device tree node must have sub-nodes describing each
|
||||
PCIe port interface, having the following mandatory properties:
|
||||
|
||||
Required properties:
|
||||
- device_type: Must be "pci"
|
||||
- reg: Only the first four bytes are used to refer to the correct bus number
|
||||
and device number.
|
||||
- #address-cells: Must be 3
|
||||
- #size-cells: Must be 2
|
||||
- #interrupt-cells: 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.
|
||||
- ranges: Sub-ranges distributed from the PCIe controller node. An empty
|
||||
property is sufficient.
|
||||
- num-lanes: Number of lanes to use for this port.
|
||||
|
||||
Examples for MT7623:
|
||||
|
||||
hifsys: syscon@1a000000 {
|
||||
compatible = "mediatek,mt7623-hifsys",
|
||||
"mediatek,mt2701-hifsys",
|
||||
"syscon";
|
||||
reg = <0 0x1a000000 0 0x1000>;
|
||||
#clock-cells = <1>;
|
||||
#reset-cells = <1>;
|
||||
};
|
||||
|
||||
pcie: pcie-controller@1a140000 {
|
||||
compatible = "mediatek,mt7623-pcie";
|
||||
device_type = "pci";
|
||||
reg = <0 0x1a140000 0 0x1000>, /* PCIe shared registers */
|
||||
<0 0x1a142000 0 0x1000>, /* Port0 registers */
|
||||
<0 0x1a143000 0 0x1000>, /* Port1 registers */
|
||||
<0 0x1a144000 0 0x1000>; /* Port2 registers */
|
||||
reg-names = "subsys", "port0", "port1", "port2";
|
||||
#address-cells = <3>;
|
||||
#size-cells = <2>;
|
||||
#interrupt-cells = <1>;
|
||||
interrupt-map-mask = <0xf800 0 0 0>;
|
||||
interrupt-map = <0x0000 0 0 0 &sysirq GIC_SPI 193 IRQ_TYPE_LEVEL_LOW>,
|
||||
<0x0800 0 0 0 &sysirq GIC_SPI 194 IRQ_TYPE_LEVEL_LOW>,
|
||||
<0x1000 0 0 0 &sysirq GIC_SPI 195 IRQ_TYPE_LEVEL_LOW>;
|
||||
clocks = <&topckgen CLK_TOP_ETHIF_SEL>,
|
||||
<&hifsys CLK_HIFSYS_PCIE0>,
|
||||
<&hifsys CLK_HIFSYS_PCIE1>,
|
||||
<&hifsys CLK_HIFSYS_PCIE2>;
|
||||
clock-names = "free_ck", "sys_ck0", "sys_ck1", "sys_ck2";
|
||||
resets = <&hifsys MT2701_HIFSYS_PCIE0_RST>,
|
||||
<&hifsys MT2701_HIFSYS_PCIE1_RST>,
|
||||
<&hifsys MT2701_HIFSYS_PCIE2_RST>;
|
||||
reset-names = "pcie-rst0", "pcie-rst1", "pcie-rst2";
|
||||
phys = <&pcie0_phy PHY_TYPE_PCIE>, <&pcie1_phy PHY_TYPE_PCIE>,
|
||||
<&pcie2_phy PHY_TYPE_PCIE>;
|
||||
phy-names = "pcie-phy0", "pcie-phy1", "pcie-phy2";
|
||||
power-domains = <&scpsys MT2701_POWER_DOMAIN_HIF>;
|
||||
bus-range = <0x00 0xff>;
|
||||
ranges = <0x81000000 0 0x1a160000 0 0x1a160000 0 0x00010000 /* I/O space */
|
||||
0x83000000 0 0x60000000 0 0x60000000 0 0x10000000>; /* memory space */
|
||||
|
||||
pcie@0,0 {
|
||||
device_type = "pci";
|
||||
reg = <0x0000 0 0 0 0>;
|
||||
#address-cells = <3>;
|
||||
#size-cells = <2>;
|
||||
#interrupt-cells = <1>;
|
||||
interrupt-map-mask = <0 0 0 0>;
|
||||
interrupt-map = <0 0 0 0 &sysirq GIC_SPI 193 IRQ_TYPE_LEVEL_LOW>;
|
||||
ranges;
|
||||
num-lanes = <1>;
|
||||
};
|
||||
|
||||
pcie@1,0 {
|
||||
device_type = "pci";
|
||||
reg = <0x0800 0 0 0 0>;
|
||||
#address-cells = <3>;
|
||||
#size-cells = <2>;
|
||||
#interrupt-cells = <1>;
|
||||
interrupt-map-mask = <0 0 0 0>;
|
||||
interrupt-map = <0 0 0 0 &sysirq GIC_SPI 194 IRQ_TYPE_LEVEL_LOW>;
|
||||
ranges;
|
||||
num-lanes = <1>;
|
||||
};
|
||||
|
||||
pcie@2,0 {
|
||||
device_type = "pci";
|
||||
reg = <0x1000 0 0 0 0>;
|
||||
#address-cells = <3>;
|
||||
#size-cells = <2>;
|
||||
#interrupt-cells = <1>;
|
||||
interrupt-map-mask = <0 0 0 0>;
|
||||
interrupt-map = <0 0 0 0 &sysirq GIC_SPI 195 IRQ_TYPE_LEVEL_LOW>;
|
||||
ranges;
|
||||
num-lanes = <1>;
|
||||
};
|
||||
};
|
||||
|
||||
Examples for MT2712:
|
||||
pcie: pcie@11700000 {
|
||||
compatible = "mediatek,mt2712-pcie";
|
||||
device_type = "pci";
|
||||
reg = <0 0x11700000 0 0x1000>,
|
||||
<0 0x112ff000 0 0x1000>;
|
||||
reg-names = "port0", "port1";
|
||||
#address-cells = <3>;
|
||||
#size-cells = <2>;
|
||||
interrupts = <GIC_SPI 115 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&topckgen CLK_TOP_PE2_MAC_P0_SEL>,
|
||||
<&topckgen CLK_TOP_PE2_MAC_P1_SEL>,
|
||||
<&pericfg CLK_PERI_PCIE0>,
|
||||
<&pericfg CLK_PERI_PCIE1>;
|
||||
clock-names = "sys_ck0", "sys_ck1", "ahb_ck0", "ahb_ck1";
|
||||
phys = <&pcie0_phy PHY_TYPE_PCIE>, <&pcie1_phy PHY_TYPE_PCIE>;
|
||||
phy-names = "pcie-phy0", "pcie-phy1";
|
||||
bus-range = <0x00 0xff>;
|
||||
ranges = <0x82000000 0 0x20000000 0x0 0x20000000 0 0x10000000>;
|
||||
|
||||
pcie0: pcie@0,0 {
|
||||
device_type = "pci";
|
||||
reg = <0x0000 0 0 0 0>;
|
||||
#address-cells = <3>;
|
||||
#size-cells = <2>;
|
||||
#interrupt-cells = <1>;
|
||||
ranges;
|
||||
num-lanes = <1>;
|
||||
interrupt-map-mask = <0 0 0 7>;
|
||||
interrupt-map = <0 0 0 1 &pcie_intc0 0>,
|
||||
<0 0 0 2 &pcie_intc0 1>,
|
||||
<0 0 0 3 &pcie_intc0 2>,
|
||||
<0 0 0 4 &pcie_intc0 3>;
|
||||
pcie_intc0: interrupt-controller {
|
||||
interrupt-controller;
|
||||
#address-cells = <0>;
|
||||
#interrupt-cells = <1>;
|
||||
};
|
||||
};
|
||||
|
||||
pcie1: pcie@1,0 {
|
||||
device_type = "pci";
|
||||
reg = <0x0800 0 0 0 0>;
|
||||
#address-cells = <3>;
|
||||
#size-cells = <2>;
|
||||
#interrupt-cells = <1>;
|
||||
ranges;
|
||||
num-lanes = <1>;
|
||||
interrupt-map-mask = <0 0 0 7>;
|
||||
interrupt-map = <0 0 0 1 &pcie_intc1 0>,
|
||||
<0 0 0 2 &pcie_intc1 1>,
|
||||
<0 0 0 3 &pcie_intc1 2>,
|
||||
<0 0 0 4 &pcie_intc1 3>;
|
||||
pcie_intc1: interrupt-controller {
|
||||
interrupt-controller;
|
||||
#address-cells = <0>;
|
||||
#interrupt-cells = <1>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
Examples for MT7622:
|
||||
pcie: pcie@1a140000 {
|
||||
compatible = "mediatek,mt7622-pcie";
|
||||
device_type = "pci";
|
||||
reg = <0 0x1a140000 0 0x1000>,
|
||||
<0 0x1a143000 0 0x1000>,
|
||||
<0 0x1a145000 0 0x1000>;
|
||||
reg-names = "subsys", "port0", "port1";
|
||||
#address-cells = <3>;
|
||||
#size-cells = <2>;
|
||||
interrupts = <GIC_SPI 228 IRQ_TYPE_LEVEL_LOW>,
|
||||
<GIC_SPI 229 IRQ_TYPE_LEVEL_LOW>;
|
||||
clocks = <&pciesys CLK_PCIE_P0_MAC_EN>,
|
||||
<&pciesys CLK_PCIE_P1_MAC_EN>,
|
||||
<&pciesys CLK_PCIE_P0_AHB_EN>,
|
||||
<&pciesys CLK_PCIE_P1_AHB_EN>,
|
||||
<&pciesys CLK_PCIE_P0_AUX_EN>,
|
||||
<&pciesys CLK_PCIE_P1_AUX_EN>,
|
||||
<&pciesys CLK_PCIE_P0_AXI_EN>,
|
||||
<&pciesys CLK_PCIE_P1_AXI_EN>,
|
||||
<&pciesys CLK_PCIE_P0_OBFF_EN>,
|
||||
<&pciesys CLK_PCIE_P1_OBFF_EN>,
|
||||
<&pciesys CLK_PCIE_P0_PIPE_EN>,
|
||||
<&pciesys CLK_PCIE_P1_PIPE_EN>;
|
||||
clock-names = "sys_ck0", "sys_ck1", "ahb_ck0", "ahb_ck1",
|
||||
"aux_ck0", "aux_ck1", "axi_ck0", "axi_ck1",
|
||||
"obff_ck0", "obff_ck1", "pipe_ck0", "pipe_ck1";
|
||||
phys = <&pcie0_phy PHY_TYPE_PCIE>, <&pcie1_phy PHY_TYPE_PCIE>;
|
||||
phy-names = "pcie-phy0", "pcie-phy1";
|
||||
power-domains = <&scpsys MT7622_POWER_DOMAIN_HIF0>;
|
||||
bus-range = <0x00 0xff>;
|
||||
ranges = <0x82000000 0 0x20000000 0x0 0x20000000 0 0x10000000>;
|
||||
|
||||
pcie0: pcie@0,0 {
|
||||
device_type = "pci";
|
||||
reg = <0x0000 0 0 0 0>;
|
||||
#address-cells = <3>;
|
||||
#size-cells = <2>;
|
||||
#interrupt-cells = <1>;
|
||||
ranges;
|
||||
num-lanes = <1>;
|
||||
interrupt-map-mask = <0 0 0 7>;
|
||||
interrupt-map = <0 0 0 1 &pcie_intc0 0>,
|
||||
<0 0 0 2 &pcie_intc0 1>,
|
||||
<0 0 0 3 &pcie_intc0 2>,
|
||||
<0 0 0 4 &pcie_intc0 3>;
|
||||
pcie_intc0: interrupt-controller {
|
||||
interrupt-controller;
|
||||
#address-cells = <0>;
|
||||
#interrupt-cells = <1>;
|
||||
};
|
||||
};
|
||||
|
||||
pcie1: pcie@1,0 {
|
||||
device_type = "pci";
|
||||
reg = <0x0800 0 0 0 0>;
|
||||
#address-cells = <3>;
|
||||
#size-cells = <2>;
|
||||
#interrupt-cells = <1>;
|
||||
ranges;
|
||||
num-lanes = <1>;
|
||||
interrupt-map-mask = <0 0 0 7>;
|
||||
interrupt-map = <0 0 0 1 &pcie_intc1 0>,
|
||||
<0 0 0 2 &pcie_intc1 1>,
|
||||
<0 0 0 3 &pcie_intc1 2>,
|
||||
<0 0 0 4 &pcie_intc1 3>;
|
||||
pcie_intc1: interrupt-controller {
|
||||
interrupt-controller;
|
||||
#address-cells = <0>;
|
||||
#interrupt-cells = <1>;
|
||||
};
|
||||
};
|
||||
};
|
|
@ -77,7 +77,7 @@ and the following optional properties:
|
|||
- marvell,pcie-lane: the physical PCIe lane number, for ports having
|
||||
multiple lanes. If this property is not found, we assume that the
|
||||
value is 0.
|
||||
- reset-gpios: optional gpio to PERST#
|
||||
- reset-gpios: optional GPIO to PERST#
|
||||
- reset-delay-us: delay in us to wait after reset de-assertion, if not
|
||||
specified will default to 100ms, as required by the PCIe specification.
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
* Marvell Armada 7K/8K PCIe interface
|
||||
|
||||
This PCIe host controller is based on the Synopsis Designware PCIe IP
|
||||
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:
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
TI Keystone PCIe interface
|
||||
|
||||
Keystone PCI host Controller is based on Designware PCI h/w version 3.65.
|
||||
It shares common functions with PCIe Designware core driver and inherit
|
||||
common properties defined in
|
||||
Keystone PCI host Controller is based on the Synopsys DesignWare PCI
|
||||
hardware version 3.65. It shares common functions with the PCIe DesignWare
|
||||
core driver and inherits common properties defined in
|
||||
Documentation/devicetree/bindings/pci/designware-pci.txt
|
||||
|
||||
Please refer to Documentation/devicetree/bindings/pci/designware-pci.txt
|
||||
for the details of Designware DT bindings. Additional properties are
|
||||
for the details of DesignWare DT bindings. Additional properties are
|
||||
described here as well as properties that are not applicable.
|
||||
|
||||
Required Properties:-
|
||||
|
@ -52,13 +52,12 @@ pcie_intc: Interrupt controller device node for Legacy IRQ chip
|
|||
};
|
||||
|
||||
Optional properties:-
|
||||
phys: phandle to Generic Keystone SerDes phy for PCI
|
||||
phy-names: name of the Generic Keystine SerDes phy for PCI
|
||||
phys: phandle to generic Keystone SerDes PHY for PCI
|
||||
phy-names: name of the generic Keystone SerDes PHY for PCI
|
||||
- If boot loader already does PCI link establishment, then phys and
|
||||
phy-names shouldn't be present.
|
||||
interrupts: platform interrupt for error interrupts.
|
||||
|
||||
Designware DT Properties not applicable for Keystone PCI
|
||||
DesignWare DT Properties not applicable for Keystone PCI
|
||||
|
||||
1. pcie_bus clock-names not used. Instead, a phandle to phys is used.
|
||||
|
||||
|
|
|
@ -6,11 +6,14 @@ AHB. There is one bridge instance per USB port connected to the internal
|
|||
OHCI and EHCI controllers.
|
||||
|
||||
Required properties:
|
||||
- compatible: "renesas,pci-r8a7790" for the R8A7790 SoC;
|
||||
- compatible: "renesas,pci-r8a7743" for the R8A7743 SoC;
|
||||
"renesas,pci-r8a7745" for the R8A7745 SoC;
|
||||
"renesas,pci-r8a7790" for the R8A7790 SoC;
|
||||
"renesas,pci-r8a7791" for the R8A7791 SoC;
|
||||
"renesas,pci-r8a7793" for the R8A7793 SoC;
|
||||
"renesas,pci-r8a7794" for the R8A7794 SoC;
|
||||
"renesas,pci-rcar-gen2" for a generic R-Car Gen2 compatible device
|
||||
"renesas,pci-rcar-gen2" for a generic R-Car Gen2 or
|
||||
RZ/G1 compatible device.
|
||||
|
||||
|
||||
When compatible with the generic version, nodes must list the
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
- "qcom,pcie-apq8084" for apq8084
|
||||
- "qcom,pcie-msm8996" for msm8996 or apq8096
|
||||
- "qcom,pcie-ipq4019" for ipq4019
|
||||
- "qcom,pcie-ipq8074" for ipq8074
|
||||
|
||||
- reg:
|
||||
Usage: required
|
||||
|
@ -20,7 +21,7 @@
|
|||
Value type: <stringlist>
|
||||
Definition: Must include the following entries
|
||||
- "parf" Qualcomm specific registers
|
||||
- "dbi" Designware PCIe registers
|
||||
- "dbi" DesignWare PCIe registers
|
||||
- "elbi" External local bus interface registers
|
||||
- "config" PCIe configuration space
|
||||
|
||||
|
@ -105,6 +106,16 @@
|
|||
- "bus_master" Master AXI clock
|
||||
- "bus_slave" Slave AXI clock
|
||||
|
||||
- clock-names:
|
||||
Usage: required for ipq8074
|
||||
Value type: <stringlist>
|
||||
Definition: Should contain the following entries
|
||||
- "iface" PCIe to SysNOC BIU clock
|
||||
- "axi_m" AXI Master clock
|
||||
- "axi_s" AXI Slave clock
|
||||
- "ahb" AHB clock
|
||||
- "aux" Auxiliary clock
|
||||
|
||||
- resets:
|
||||
Usage: required
|
||||
Value type: <prop-encoded-array>
|
||||
|
@ -144,6 +155,18 @@
|
|||
- "ahb" AHB reset
|
||||
- "phy_ahb" PHY AHB reset
|
||||
|
||||
- reset-names:
|
||||
Usage: required for ipq8074
|
||||
Value type: <stringlist>
|
||||
Definition: Should contain the following entries
|
||||
- "pipe" PIPE reset
|
||||
- "sleep" Sleep reset
|
||||
- "sticky" Core Sticky reset
|
||||
- "axi_m" AXI Master reset
|
||||
- "axi_s" AXI Slave reset
|
||||
- "ahb" AHB Reset
|
||||
- "axi_m_sticky" AXI Master Sticky reset
|
||||
|
||||
- power-domains:
|
||||
Usage: required for apq8084 and msm8996/apq8096
|
||||
Value type: <prop-encoded-array>
|
||||
|
@ -180,7 +203,7 @@
|
|||
- <name>-gpios:
|
||||
Usage: optional
|
||||
Value type: <prop-encoded-array>
|
||||
Definition: List of phandle and gpio specifier pairs. Should contain
|
||||
Definition: List of phandle and GPIO specifier pairs. Should contain
|
||||
- "perst-gpios" PCIe endpoint reset signal line
|
||||
- "wake-gpios" PCIe endpoint wake signal line
|
||||
|
||||
|
|
|
@ -71,7 +71,7 @@
|
|||
- interrupt-map: standard PCI properties to define the mapping of the
|
||||
PCI interface to interrupt numbers.
|
||||
|
||||
The PCI host bridge node migh have additional sub-nodes representing
|
||||
The PCI host bridge node might have additional sub-nodes representing
|
||||
the onboard PCI devices/PCI slots. Each such sub-node must have the
|
||||
following mandatory properties:
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ compatible: "renesas,pcie-r8a7779" for the R8A7779 SoC;
|
|||
SoC-specific version corresponding to the platform first
|
||||
followed by the generic version.
|
||||
|
||||
- reg: base address and length of the pcie controller registers.
|
||||
- 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
|
||||
|
@ -25,15 +25,14 @@ compatible: "renesas,pcie-r8a7779" for the R8A7779 SoC;
|
|||
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.
|
||||
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".
|
||||
|
||||
Example:
|
||||
|
||||
SoC specific DT Entry:
|
||||
SoC-specific DT Entry:
|
||||
|
||||
pcie: pcie@fe000000 {
|
||||
compatible = "renesas,pcie-r8a7791", "renesas,pcie-rcar-gen2";
|
||||
|
|
|
@ -19,8 +19,6 @@ Required properties:
|
|||
- "pm"
|
||||
- msi-map: Maps a Requester ID to an MSI controller and associated
|
||||
msi-specifier data. See ./pci-msi.txt
|
||||
- phys: From PHY bindings: Phandle for the Generic PHY for PCIe.
|
||||
- phy-names: MUST be "pcie-phy".
|
||||
- interrupts: Three interrupt entries must be specified.
|
||||
- interrupt-names: Must include the following names
|
||||
- "sys"
|
||||
|
@ -42,11 +40,24 @@ Required properties:
|
|||
interrupt source. The value must be 1.
|
||||
- interrupt-map-mask and interrupt-map: standard PCI properties
|
||||
|
||||
Required properties for legacy PHY model (deprecated):
|
||||
- phys: From PHY bindings: Phandle for the Generic PHY for PCIe.
|
||||
- phy-names: MUST be "pcie-phy".
|
||||
|
||||
Required properties for per-lane PHY model (preferred):
|
||||
- phys: Must contain an phandle to a PHY for each entry in phy-names.
|
||||
- phy-names: Must include 4 entries for all 4 lanes even if some of
|
||||
them won't be used for your cases. Entries are of the form "pcie-phy-N":
|
||||
where N ranges from 0 to 3.
|
||||
(see example below and you MUST also refer to ../phy/rockchip-pcie-phy.txt
|
||||
for changing the #phy-cells of phy node to support it)
|
||||
|
||||
Optional Property:
|
||||
- aspm-no-l0s: RC won't support ASPM L0s. This property is needed if
|
||||
using 24MHz OSC for RC's PHY.
|
||||
- ep-gpios: contain the entry for pre-reset gpio
|
||||
- ep-gpios: contain the entry for pre-reset GPIO
|
||||
- num-lanes: number of lanes to use
|
||||
- vpcie12v-supply: The phandle to the 12v regulator to use for PCIe.
|
||||
- vpcie3v3-supply: The phandle to the 3.3v regulator to use for PCIe.
|
||||
- vpcie1v8-supply: The phandle to the 1.8v regulator to use for PCIe.
|
||||
- vpcie0v9-supply: The phandle to the 0.9v regulator to use for PCIe.
|
||||
|
@ -95,6 +106,7 @@ pcie0: pcie@f8000000 {
|
|||
<&cru SRST_PCIE_PM>, <&cru SRST_P_PCIE>, <&cru SRST_A_PCIE>;
|
||||
reset-names = "core", "mgmt", "mgmt-sticky", "pipe",
|
||||
"pm", "pclk", "aclk";
|
||||
/* deprecated legacy PHY model */
|
||||
phys = <&pcie_phy>;
|
||||
phy-names = "pcie-phy";
|
||||
pinctrl-names = "default";
|
||||
|
@ -111,3 +123,13 @@ pcie0: pcie@f8000000 {
|
|||
#interrupt-cells = <1>;
|
||||
};
|
||||
};
|
||||
|
||||
pcie0: pcie@f8000000 {
|
||||
...
|
||||
|
||||
/* preferred per-lane PHY model */
|
||||
phys = <&pcie_phy 0>, <&pcie_phy 1>, <&pcie_phy 2>, <&pcie_phy 3>;
|
||||
phy-names = "pcie-phy-0", "pcie-phy-1", "pcie-phy-2", "pcie-phy-3";
|
||||
|
||||
...
|
||||
};
|
||||
|
|
|
@ -1,29 +1,29 @@
|
|||
* Samsung Exynos 5440 PCIe interface
|
||||
|
||||
This PCIe host controller is based on the Synopsis Designware PCIe IP
|
||||
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,
|
||||
the phy controller, additional register for the phy controller.
|
||||
(Registers for the phy controller are DEPRECATED.
|
||||
- reg: base addresses and lengths of the PCIe controller,
|
||||
the PHY controller, additional register for the PHY controller.
|
||||
(Registers for the PHY controller are DEPRECATED.
|
||||
Use the PHY framework.)
|
||||
- reg-names : First name should be set to "elbi".
|
||||
And use the "config" instead of getting the confgiruation address space
|
||||
And use the "config" instead of getting the configuration address space
|
||||
from "ranges".
|
||||
NOTE: When use the "config" property, reg-names must be set.
|
||||
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.
|
||||
- phys: From PHY binding. Phandle for the generic PHY.
|
||||
Refer to Documentation/devicetree/bindings/phy/samsung-phy.txt
|
||||
|
||||
Other common properties refer to
|
||||
Documentation/devicetree/binding/pci/designware-pcie.txt
|
||||
For other common properties, refer to
|
||||
Documentation/devicetree/bindings/pci/designware-pcie.txt
|
||||
|
||||
Example:
|
||||
|
||||
SoC specific DT Entry:
|
||||
SoC-specific DT Entry:
|
||||
|
||||
pcie@290000 {
|
||||
compatible = "samsung,exynos5440-pcie", "snps,dw-pcie";
|
||||
|
@ -83,7 +83,7 @@ With using PHY framework:
|
|||
...
|
||||
};
|
||||
|
||||
Board specific DT Entry:
|
||||
Board-specific DT Entry:
|
||||
|
||||
pcie@290000 {
|
||||
reset-gpio = <&pin_ctrl 5 0>;
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
SPEAr13XX PCIe DT detail:
|
||||
================================
|
||||
|
||||
SPEAr13XX uses synopsis designware PCIe controller and ST MiPHY as phy
|
||||
SPEAr13XX uses the Synopsys DesignWare PCIe controller and ST MiPHY as PHY
|
||||
controller.
|
||||
|
||||
Required properties:
|
||||
- compatible : should be "st,spear1340-pcie", "snps,dw-pcie".
|
||||
- phys : phandle to phy node associated with pcie controller
|
||||
- compatible : should be "st,spear1340-pcie", "snps,dw-pcie".
|
||||
- phys : phandle to PHY node associated with PCIe controller
|
||||
- phy-names : must be "pcie-phy"
|
||||
- All other definitions as per generic PCI bindings
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
TI PCI Controllers
|
||||
|
||||
PCIe Designware Controller
|
||||
PCIe DesignWare Controller
|
||||
- compatible: Should be "ti,dra7-pcie" for RC
|
||||
Should be "ti,dra7-pcie-ep" for EP
|
||||
- phys : list of PHY specifiers (used by generic PHY framework)
|
||||
|
@ -13,7 +13,7 @@ PCIe Designware Controller
|
|||
HOST MODE
|
||||
=========
|
||||
- reg : Two register ranges as listed in the reg-names property
|
||||
- reg-names : The first entry must be "ti-conf" for the TI specific registers
|
||||
- reg-names : The first entry must be "ti-conf" for the TI-specific registers
|
||||
The second entry must be "rc-dbics" for the DesignWare PCIe
|
||||
registers
|
||||
The third entry must be "config" for the PCIe configuration space
|
||||
|
@ -30,7 +30,7 @@ HOST MODE
|
|||
DEVICE MODE
|
||||
===========
|
||||
- reg : Four register ranges as listed in the reg-names property
|
||||
- reg-names : "ti-conf" for the TI specific registers
|
||||
- reg-names : "ti-conf" for the TI-specific registers
|
||||
"ep_dbics" for the standard configuration registers as
|
||||
they are locally accessed within the DIF CS space
|
||||
"ep_dbics2" for the standard configuration registers as
|
||||
|
@ -46,7 +46,7 @@ DEVICE MODE
|
|||
access.
|
||||
|
||||
Optional Property:
|
||||
- gpios : Should be added if a gpio line is required to drive PERST# line
|
||||
- gpios : Should be added if a GPIO line is required to drive PERST# line
|
||||
|
||||
NOTE: Two DT nodes may be added for each PCI controller; one for host
|
||||
mode and another for device mode. So in order for PCI to
|
||||
|
|
|
@ -5,7 +5,7 @@ PCI host controller found on the ARM Versatile PB board's FPGA.
|
|||
Required properties:
|
||||
- compatible: should contain "arm,versatile-pci" to identify the Versatile PCI
|
||||
controller.
|
||||
- reg: base addresses and lengths of the pci controller. There must be 3
|
||||
- reg: base addresses and lengths of the PCI controller. There must be 3
|
||||
entries:
|
||||
- Versatile-specific registers
|
||||
- Self Config space
|
||||
|
|
|
@ -4,7 +4,7 @@ Required properties:
|
|||
|
||||
- compatible: should be "apm,xgene1-msi" to identify
|
||||
X-Gene v1 PCIe MSI controller block.
|
||||
- msi-controller: indicates that this is X-Gene v1 PCIe MSI controller node
|
||||
- msi-controller: indicates that this is an X-Gene v1 PCIe MSI controller node
|
||||
- reg: physical base address (0x79000000) and length (0x900000) for controller
|
||||
registers. These registers include the MSI termination address and data
|
||||
registers as well as the MSI interrupt status registers.
|
||||
|
@ -13,7 +13,8 @@ Required properties:
|
|||
interrupt number 0x10 to 0x1f.
|
||||
- interrupt-names: not required
|
||||
|
||||
Each PCIe node needs to have property msi-parent that points to msi controller node
|
||||
Each PCIe node needs to have property msi-parent that points to an MSI
|
||||
controller node
|
||||
|
||||
Examples:
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ Required properties:
|
|||
property.
|
||||
- reg-names: Must include the following entries:
|
||||
"csr": controller configuration registers.
|
||||
"cfg": pcie configuration space registers.
|
||||
"cfg": PCIe configuration space registers.
|
||||
- #address-cells: set to <3>
|
||||
- #size-cells: set to <2>
|
||||
- ranges: ranges for the outbound memory, I/O regions.
|
||||
|
@ -21,11 +21,11 @@ Required properties:
|
|||
|
||||
Optional properties:
|
||||
- status: Either "ok" or "disabled".
|
||||
- dma-coherent: Present if dma operations are coherent
|
||||
- dma-coherent: Present if DMA operations are coherent
|
||||
|
||||
Example:
|
||||
|
||||
SoC specific DT Entry:
|
||||
SoC-specific DT Entry:
|
||||
|
||||
pcie0: pcie@1f2b0000 {
|
||||
status = "disabled";
|
||||
|
@ -51,7 +51,7 @@ SoC specific DT Entry:
|
|||
};
|
||||
|
||||
|
||||
Board specific DT Entry:
|
||||
Board-specific DT Entry:
|
||||
&pcie0 {
|
||||
status = "ok";
|
||||
};
|
||||
|
|
|
@ -15,9 +15,9 @@ Required properties:
|
|||
- device_type: must be "pci"
|
||||
- interrupts: Should contain NWL PCIe interrupt
|
||||
- interrupt-names: Must include the following entries:
|
||||
"msi1, msi0": interrupt asserted when MSI is received
|
||||
"msi1, msi0": interrupt asserted when an MSI is received
|
||||
"intx": interrupt asserted when a legacy interrupt is received
|
||||
"misc": interrupt asserted when miscellaneous is received
|
||||
"misc": interrupt asserted when miscellaneous interrupt is received
|
||||
- interrupt-map-mask and interrupt-map: standard PCI properties to define the
|
||||
mapping of the PCI interface to interrupt numbers.
|
||||
- ranges: ranges for the PCI memory regions (I/O space region is not
|
||||
|
@ -26,7 +26,8 @@ Required properties:
|
|||
detailed explanation
|
||||
- msi-controller: indicates that this is MSI controller node
|
||||
- msi-parent: MSI parent of the root complex itself
|
||||
- legacy-interrupt-controller: Interrupt controller device node for Legacy interrupts
|
||||
- legacy-interrupt-controller: Interrupt controller device node for Legacy
|
||||
interrupts
|
||||
- interrupt-controller: identifies the node as an interrupt controller
|
||||
- #interrupt-cells: should be set to 1
|
||||
- #address-cells: specifies the number of cells needed to encode an
|
||||
|
|
|
@ -3,7 +3,6 @@ Rockchip PCIE PHY
|
|||
|
||||
Required properties:
|
||||
- compatible: rockchip,rk3399-pcie-phy
|
||||
- #phy-cells: must be 0
|
||||
- clocks: Must contain an entry in clock-names.
|
||||
See ../clocks/clock-bindings.txt for details.
|
||||
- clock-names: Must be "refclk"
|
||||
|
@ -11,6 +10,12 @@ Required properties:
|
|||
See ../reset/reset.txt for details.
|
||||
- reset-names: Must be "phy"
|
||||
|
||||
Required properties for legacy PHY mode (deprecated):
|
||||
- #phy-cells: must be 0
|
||||
|
||||
Required properties for per-lane PHY mode (preferred):
|
||||
- #phy-cells: must be 1
|
||||
|
||||
Example:
|
||||
|
||||
grf: syscon@ff770000 {
|
||||
|
|
|
@ -10244,6 +10244,7 @@ F: drivers/pci/dwc/*imx6*
|
|||
|
||||
PCI DRIVER FOR INTEL VOLUME MANAGEMENT DEVICE (VMD)
|
||||
M: Keith Busch <keith.busch@intel.com>
|
||||
M: Jonathan Derrick <jonathan.derrick@intel.com>
|
||||
L: linux-pci@vger.kernel.org
|
||||
S: Supported
|
||||
F: drivers/pci/host/vmd.c
|
||||
|
@ -10290,7 +10291,7 @@ L: linux-samsung-soc@vger.kernel.org (moderated for non-subscribers)
|
|||
S: Maintained
|
||||
F: drivers/pci/dwc/pci-exynos.c
|
||||
|
||||
PCI DRIVER FOR SYNOPSIS DESIGNWARE
|
||||
PCI DRIVER FOR SYNOPSYS DESIGNWARE
|
||||
M: Jingoo Han <jingoohan1@gmail.com>
|
||||
M: Joao Pinto <Joao.Pinto@synopsys.com>
|
||||
L: linux-pci@vger.kernel.org
|
||||
|
|
|
@ -312,8 +312,9 @@ common_init_pci(void)
|
|||
{
|
||||
struct pci_controller *hose;
|
||||
struct list_head resources;
|
||||
struct pci_host_bridge *bridge;
|
||||
struct pci_bus *bus;
|
||||
int next_busno;
|
||||
int ret, next_busno;
|
||||
int need_domain_info = 0;
|
||||
u32 pci_mem_end;
|
||||
u32 sg_base;
|
||||
|
@ -336,11 +337,25 @@ common_init_pci(void)
|
|||
pci_add_resource_offset(&resources, hose->mem_space,
|
||||
hose->mem_space->start);
|
||||
|
||||
bus = pci_scan_root_bus(NULL, next_busno, alpha_mv.pci_ops,
|
||||
hose, &resources);
|
||||
if (!bus)
|
||||
bridge = pci_alloc_host_bridge(0);
|
||||
if (!bridge)
|
||||
continue;
|
||||
hose->bus = bus;
|
||||
|
||||
list_splice_init(&resources, &bridge->windows);
|
||||
bridge->dev.parent = NULL;
|
||||
bridge->sysdata = hose;
|
||||
bridge->busnr = next_busno;
|
||||
bridge->ops = alpha_mv.pci_ops;
|
||||
bridge->swizzle_irq = alpha_mv.pci_swizzle;
|
||||
bridge->map_irq = alpha_mv.pci_map_irq;
|
||||
|
||||
ret = pci_scan_root_bus_bridge(bridge);
|
||||
if (ret) {
|
||||
pci_free_host_bridge(bridge);
|
||||
continue;
|
||||
}
|
||||
|
||||
bus = hose->bus = bridge->bus;
|
||||
hose->need_domain_info = need_domain_info;
|
||||
next_busno = bus->busn_res.end + 1;
|
||||
/* Don't allow 8-bit bus number overflow inside the hose -
|
||||
|
@ -354,7 +369,6 @@ common_init_pci(void)
|
|||
pcibios_claim_console_setup();
|
||||
|
||||
pci_assign_unassigned_resources();
|
||||
pci_fixup_irqs(alpha_mv.pci_swizzle, alpha_mv.pci_map_irq);
|
||||
for (hose = hose_head; hose; hose = hose->next) {
|
||||
bus = hose->bus;
|
||||
if (bus)
|
||||
|
@ -362,7 +376,6 @@ common_init_pci(void)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
struct pci_controller * __init
|
||||
alloc_pci_controller(void)
|
||||
{
|
||||
|
|
|
@ -194,22 +194,46 @@ static struct resource irongate_mem = {
|
|||
.name = "Irongate PCI MEM",
|
||||
.flags = IORESOURCE_MEM,
|
||||
};
|
||||
static struct resource busn_resource = {
|
||||
.name = "PCI busn",
|
||||
.start = 0,
|
||||
.end = 255,
|
||||
.flags = IORESOURCE_BUS,
|
||||
};
|
||||
|
||||
void __init
|
||||
nautilus_init_pci(void)
|
||||
{
|
||||
struct pci_controller *hose = hose_head;
|
||||
struct pci_host_bridge *bridge;
|
||||
struct pci_bus *bus;
|
||||
struct pci_dev *irongate;
|
||||
unsigned long bus_align, bus_size, pci_mem;
|
||||
unsigned long memtop = max_low_pfn << PAGE_SHIFT;
|
||||
int ret;
|
||||
|
||||
/* Scan our single hose. */
|
||||
bus = pci_scan_bus(0, alpha_mv.pci_ops, hose);
|
||||
if (!bus)
|
||||
bridge = pci_alloc_host_bridge(0);
|
||||
if (!bridge)
|
||||
return;
|
||||
|
||||
hose->bus = bus;
|
||||
pci_add_resource(&bridge->windows, &ioport_resource);
|
||||
pci_add_resource(&bridge->windows, &iomem_resource);
|
||||
pci_add_resource(&bridge->windows, &busn_resource);
|
||||
bridge->dev.parent = NULL;
|
||||
bridge->sysdata = hose;
|
||||
bridge->busnr = 0;
|
||||
bridge->ops = alpha_mv.pci_ops;
|
||||
bridge->swizzle_irq = alpha_mv.pci_swizzle;
|
||||
bridge->map_irq = alpha_mv.pci_map_irq;
|
||||
|
||||
/* Scan our single hose. */
|
||||
ret = pci_scan_root_bus_bridge(bridge);
|
||||
if (ret) {
|
||||
pci_free_host_bridge(bridge);
|
||||
return;
|
||||
}
|
||||
|
||||
bus = hose->bus = bridge->bus;
|
||||
pcibios_claim_one_bus(bus);
|
||||
|
||||
irongate = pci_get_bus_and_slot(0, 0);
|
||||
|
@ -254,7 +278,6 @@ nautilus_init_pci(void)
|
|||
/* pci_common_swizzle() relies on bus->self being NULL
|
||||
for the root bus, so just clear it. */
|
||||
bus->self = NULL;
|
||||
pci_fixup_irqs(alpha_mv.pci_swizzle, alpha_mv.pci_map_irq);
|
||||
pci_bus_add_devices(bus);
|
||||
}
|
||||
|
||||
|
|
|
@ -12,7 +12,6 @@ obj-y := arcksyms.o setup.o irq.o reset.o ptrace.o process.o devtree.o
|
|||
obj-y += signal.o traps.o sys.o troubleshoot.o stacktrace.o disasm.o
|
||||
obj-$(CONFIG_ISA_ARCOMPACT) += entry-compact.o intc-compact.o
|
||||
obj-$(CONFIG_ISA_ARCV2) += entry-arcv2.o intc-arcv2.o
|
||||
obj-$(CONFIG_PCI) += pcibios.o
|
||||
|
||||
obj-$(CONFIG_MODULES) += arcksyms.o module.o
|
||||
obj-$(CONFIG_SMP) += smp.o
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2014-2015 Synopsys, Inc. (www.synopsys.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/pci.h>
|
||||
|
||||
/*
|
||||
* We don't have to worry about legacy ISA devices, so nothing to do here
|
||||
*/
|
||||
resource_size_t pcibios_align_resource(void *data, const struct resource *res,
|
||||
resource_size_t size, resource_size_t align)
|
||||
{
|
||||
return res->start;
|
||||
}
|
||||
|
||||
void pcibios_fixup_bus(struct pci_bus *bus)
|
||||
{
|
||||
}
|
|
@ -238,8 +238,10 @@
|
|||
linux,pci-domain = <0>;
|
||||
max-link-speed = <1>;
|
||||
msi-map = <0x0 &its 0x0 0x1000>;
|
||||
phys = <&pcie_phy>;
|
||||
phy-names = "pcie-phy";
|
||||
phys = <&pcie_phy 0>, <&pcie_phy 1>,
|
||||
<&pcie_phy 2>, <&pcie_phy 3>;
|
||||
phy-names = "pcie-phy-0", "pcie-phy-1",
|
||||
"pcie-phy-2", "pcie-phy-3";
|
||||
ranges = <0x83000000 0x0 0xfa000000 0x0 0xfa000000 0x0 0x1e00000
|
||||
0x81000000 0x0 0xfbe00000 0x0 0xfbe00000 0x0 0x100000>;
|
||||
resets = <&cru SRST_PCIE_CORE>, <&cru SRST_PCIE_MGMT>,
|
||||
|
@ -1295,7 +1297,7 @@
|
|||
compatible = "rockchip,rk3399-pcie-phy";
|
||||
clocks = <&cru SCLK_PCIEPHY_REF>;
|
||||
clock-names = "refclk";
|
||||
#phy-cells = <0>;
|
||||
#phy-cells = <1>;
|
||||
resets = <&cru SRST_PCIEPHY>;
|
||||
reset-names = "phy";
|
||||
status = "disabled";
|
||||
|
|
|
@ -22,23 +22,6 @@
|
|||
#include <linux/pci-ecam.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
/*
|
||||
* Called after each bus is probed, but before its children are examined
|
||||
*/
|
||||
void pcibios_fixup_bus(struct pci_bus *bus)
|
||||
{
|
||||
/* nothing to do, expected to be removed in the future */
|
||||
}
|
||||
|
||||
/*
|
||||
* We don't have to worry about legacy ISA devices, so nothing to do here
|
||||
*/
|
||||
resource_size_t pcibios_align_resource(void *data, const struct resource *res,
|
||||
resource_size_t size, resource_size_t align)
|
||||
{
|
||||
return res->start;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
/*
|
||||
* Try to assign the IRQ number when probing a new device
|
||||
|
|
|
@ -2,10 +2,6 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <hwregs/intr_vect.h>
|
||||
|
||||
void pcibios_fixup_bus(struct pci_bus *b)
|
||||
{
|
||||
}
|
||||
|
||||
void pcibios_set_master(struct pci_dev *dev)
|
||||
{
|
||||
u8 lat;
|
||||
|
|
|
@ -411,13 +411,6 @@ pcibios_disable_device (struct pci_dev *dev)
|
|||
acpi_pci_irq_disable(dev);
|
||||
}
|
||||
|
||||
resource_size_t
|
||||
pcibios_align_resource (void *data, const struct resource *res,
|
||||
resource_size_t size, resource_size_t align)
|
||||
{
|
||||
return res->start;
|
||||
}
|
||||
|
||||
/**
|
||||
* ia64_pci_get_legacy_mem - generic legacy mem routine
|
||||
* @bus: bus to get legacy memory base address for
|
||||
|
|
|
@ -243,6 +243,13 @@ static struct resource mcf_pci_io = {
|
|||
.flags = IORESOURCE_IO,
|
||||
};
|
||||
|
||||
static struct resource busn_resource = {
|
||||
.name = "PCI busn",
|
||||
.start = 0,
|
||||
.end = 255,
|
||||
.flags = IORESOURCE_BUS,
|
||||
};
|
||||
|
||||
/*
|
||||
* Interrupt mapping and setting.
|
||||
*/
|
||||
|
@ -258,6 +265,13 @@ static int mcf_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
|
|||
|
||||
static int __init mcf_pci_init(void)
|
||||
{
|
||||
struct pci_host_bridge *bridge;
|
||||
int ret;
|
||||
|
||||
bridge = pci_alloc_host_bridge(0);
|
||||
if (!bridge)
|
||||
return -ENOMEM;
|
||||
|
||||
pr_info("ColdFire: PCI bus initialization...\n");
|
||||
|
||||
/* Reset the external PCI bus */
|
||||
|
@ -312,14 +326,28 @@ static int __init mcf_pci_init(void)
|
|||
set_current_state(TASK_UNINTERRUPTIBLE);
|
||||
schedule_timeout(msecs_to_jiffies(200));
|
||||
|
||||
rootbus = pci_scan_bus(0, &mcf_pci_ops, NULL);
|
||||
if (!rootbus)
|
||||
return -ENODEV;
|
||||
|
||||
pci_add_resource(&bridge->windows, &ioport_resource);
|
||||
pci_add_resource(&bridge->windows, &iomem_resource);
|
||||
pci_add_resource(&bridge->windows, &busn_resource);
|
||||
bridge->dev.parent = NULL;
|
||||
bridge->sysdata = NULL;
|
||||
bridge->busnr = 0;
|
||||
bridge->ops = &mcf_pci_ops;
|
||||
bridge->swizzle_irq = pci_common_swizzle;
|
||||
bridge->map_irq = mcf_pci_map_irq;
|
||||
|
||||
ret = pci_scan_root_bus_bridge(bridge);
|
||||
if (ret) {
|
||||
pci_free_host_bridge(bridge);
|
||||
return ret;
|
||||
}
|
||||
|
||||
rootbus = bridge->bus;
|
||||
|
||||
rootbus->resource[0] = &mcf_pci_io;
|
||||
rootbus->resource[1] = &mcf_pci_mem;
|
||||
|
||||
pci_fixup_irqs(pci_common_swizzle, mcf_pci_map_irq);
|
||||
pci_bus_size_bridges(rootbus);
|
||||
pci_bus_assign_resources(rootbus);
|
||||
pci_bus_add_devices(rootbus);
|
||||
|
|
|
@ -81,9 +81,6 @@ extern pgprot_t pci_phys_mem_access_prot(struct file *file,
|
|||
|
||||
#define HAVE_ARCH_PCI_RESOURCE_TO_USER
|
||||
|
||||
extern void pcibios_setup_bus_devices(struct pci_bus *bus);
|
||||
extern void pcibios_setup_bus_self(struct pci_bus *bus);
|
||||
|
||||
/* This part of code was originally in xilinx-pci.h */
|
||||
#ifdef CONFIG_PCI_XILINX
|
||||
extern void __init xilinx_pci_init(void);
|
||||
|
|
|
@ -678,144 +678,6 @@ static void pcibios_fixup_resources(struct pci_dev *dev)
|
|||
}
|
||||
DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pcibios_fixup_resources);
|
||||
|
||||
/* This function tries to figure out if a bridge resource has been initialized
|
||||
* by the firmware or not. It doesn't have to be absolutely bullet proof, but
|
||||
* things go more smoothly when it gets it right. It should covers cases such
|
||||
* as Apple "closed" bridge resources and bare-metal pSeries unassigned bridges
|
||||
*/
|
||||
static int pcibios_uninitialized_bridge_resource(struct pci_bus *bus,
|
||||
struct resource *res)
|
||||
{
|
||||
struct pci_controller *hose = pci_bus_to_host(bus);
|
||||
struct pci_dev *dev = bus->self;
|
||||
resource_size_t offset;
|
||||
u16 command;
|
||||
int i;
|
||||
|
||||
/* Job is a bit different between memory and IO */
|
||||
if (res->flags & IORESOURCE_MEM) {
|
||||
/* If the BAR is non-0 (res != pci_mem_offset) then it's
|
||||
* probably been initialized by somebody
|
||||
*/
|
||||
if (res->start != hose->pci_mem_offset)
|
||||
return 0;
|
||||
|
||||
/* The BAR is 0, let's check if memory decoding is enabled on
|
||||
* the bridge. If not, we consider it unassigned
|
||||
*/
|
||||
pci_read_config_word(dev, PCI_COMMAND, &command);
|
||||
if ((command & PCI_COMMAND_MEMORY) == 0)
|
||||
return 1;
|
||||
|
||||
/* Memory decoding is enabled and the BAR is 0. If any of
|
||||
* the bridge resources covers that starting address (0 then
|
||||
* it's good enough for us for memory
|
||||
*/
|
||||
for (i = 0; i < 3; i++) {
|
||||
if ((hose->mem_resources[i].flags & IORESOURCE_MEM) &&
|
||||
hose->mem_resources[i].start == hose->pci_mem_offset)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Well, it starts at 0 and we know it will collide so we may as
|
||||
* well consider it as unassigned. That covers the Apple case.
|
||||
*/
|
||||
return 1;
|
||||
} else {
|
||||
/* If the BAR is non-0, then we consider it assigned */
|
||||
offset = (unsigned long)hose->io_base_virt - _IO_BASE;
|
||||
if (((res->start - offset) & 0xfffffffful) != 0)
|
||||
return 0;
|
||||
|
||||
/* Here, we are a bit different than memory as typically IO
|
||||
* space starting at low addresses -is- valid. What we do
|
||||
* instead if that we consider as unassigned anything that
|
||||
* doesn't have IO enabled in the PCI command register,
|
||||
* and that's it.
|
||||
*/
|
||||
pci_read_config_word(dev, PCI_COMMAND, &command);
|
||||
if (command & PCI_COMMAND_IO)
|
||||
return 0;
|
||||
|
||||
/* It's starting at 0 and IO is disabled in the bridge, consider
|
||||
* it unassigned
|
||||
*/
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Fixup resources of a PCI<->PCI bridge */
|
||||
static void pcibios_fixup_bridge(struct pci_bus *bus)
|
||||
{
|
||||
struct resource *res;
|
||||
int i;
|
||||
|
||||
struct pci_dev *dev = bus->self;
|
||||
|
||||
pci_bus_for_each_resource(bus, res, i) {
|
||||
if (!res)
|
||||
continue;
|
||||
if (!res->flags)
|
||||
continue;
|
||||
if (i >= 3 && bus->self->transparent)
|
||||
continue;
|
||||
|
||||
pr_debug("PCI:%s Bus rsrc %d %016llx-%016llx [%x] fixup...\n",
|
||||
pci_name(dev), i,
|
||||
(unsigned long long)res->start,
|
||||
(unsigned long long)res->end,
|
||||
(unsigned int)res->flags);
|
||||
|
||||
/* Try to detect uninitialized P2P bridge resources,
|
||||
* and clear them out so they get re-assigned later
|
||||
*/
|
||||
if (pcibios_uninitialized_bridge_resource(bus, res)) {
|
||||
res->flags = 0;
|
||||
pr_debug("PCI:%s (unassigned)\n",
|
||||
pci_name(dev));
|
||||
} else {
|
||||
pr_debug("PCI:%s %016llx-%016llx\n",
|
||||
pci_name(dev),
|
||||
(unsigned long long)res->start,
|
||||
(unsigned long long)res->end);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void pcibios_setup_bus_self(struct pci_bus *bus)
|
||||
{
|
||||
/* Fix up the bus resources for P2P bridges */
|
||||
if (bus->self != NULL)
|
||||
pcibios_fixup_bridge(bus);
|
||||
}
|
||||
|
||||
void pcibios_setup_bus_devices(struct pci_bus *bus)
|
||||
{
|
||||
struct pci_dev *dev;
|
||||
|
||||
pr_debug("PCI: Fixup bus devices %d (%s)\n",
|
||||
bus->number, bus->self ? pci_name(bus->self) : "PHB");
|
||||
|
||||
list_for_each_entry(dev, &bus->devices, bus_list) {
|
||||
/* Setup OF node pointer in archdata */
|
||||
dev->dev.of_node = pci_device_to_OF_node(dev);
|
||||
|
||||
/* Fixup NUMA node as it may not be setup yet by the generic
|
||||
* code and is needed by the DMA init
|
||||
*/
|
||||
set_dev_node(&dev->dev, pcibus_to_node(dev->bus));
|
||||
|
||||
/* Read default IRQs and fixup if necessary */
|
||||
dev->irq = of_irq_parse_and_map_pci(dev, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void pcibios_fixup_bus(struct pci_bus *bus)
|
||||
{
|
||||
/* nothing to do */
|
||||
}
|
||||
EXPORT_SYMBOL(pcibios_fixup_bus);
|
||||
|
||||
/*
|
||||
* We need to avoid collisions with `mirrored' VGA ports
|
||||
* and other strange ISA hardware, so we always want the
|
||||
|
@ -829,13 +691,6 @@ EXPORT_SYMBOL(pcibios_fixup_bus);
|
|||
* but we want to try to avoid allocating at 0x2900-0x2bff
|
||||
* which might have be mirrored at 0x0100-0x03ff..
|
||||
*/
|
||||
resource_size_t pcibios_align_resource(void *data, const struct resource *res,
|
||||
resource_size_t size, resource_size_t align)
|
||||
{
|
||||
return res->start;
|
||||
}
|
||||
EXPORT_SYMBOL(pcibios_align_resource);
|
||||
|
||||
int pcibios_add_device(struct pci_dev *dev)
|
||||
{
|
||||
dev->irq = of_irq_parse_and_map_pci(dev, 0, 0);
|
||||
|
|
|
@ -78,6 +78,12 @@ static void pcibios_scanbus(struct pci_controller *hose)
|
|||
static int need_domain_info;
|
||||
LIST_HEAD(resources);
|
||||
struct pci_bus *bus;
|
||||
struct pci_host_bridge *bridge;
|
||||
int ret;
|
||||
|
||||
bridge = pci_alloc_host_bridge(0);
|
||||
if (!bridge)
|
||||
return;
|
||||
|
||||
if (hose->get_busno && pci_has_flag(PCI_PROBE_ONLY))
|
||||
next_busno = (*hose->get_busno)();
|
||||
|
@ -87,18 +93,24 @@ static void pcibios_scanbus(struct pci_controller *hose)
|
|||
pci_add_resource_offset(&resources,
|
||||
hose->io_resource, hose->io_offset);
|
||||
pci_add_resource(&resources, hose->busn_resource);
|
||||
bus = pci_scan_root_bus(NULL, next_busno, hose->pci_ops, hose,
|
||||
&resources);
|
||||
hose->bus = bus;
|
||||
list_splice_init(&resources, &bridge->windows);
|
||||
bridge->dev.parent = NULL;
|
||||
bridge->sysdata = hose;
|
||||
bridge->busnr = next_busno;
|
||||
bridge->ops = hose->pci_ops;
|
||||
bridge->swizzle_irq = pci_common_swizzle;
|
||||
bridge->map_irq = pcibios_map_irq;
|
||||
ret = pci_scan_root_bus_bridge(bridge);
|
||||
if (ret) {
|
||||
pci_free_host_bridge(bridge);
|
||||
return;
|
||||
}
|
||||
|
||||
hose->bus = bus = bridge->bus;
|
||||
|
||||
need_domain_info = need_domain_info || pci_domain_nr(bus);
|
||||
set_pci_need_domain_info(hose, need_domain_info);
|
||||
|
||||
if (!bus) {
|
||||
pci_free_resource_list(&resources);
|
||||
return;
|
||||
}
|
||||
|
||||
next_busno = bus->busn_res.end + 1;
|
||||
/* Don't allow 8-bit bus number overflow inside the hose -
|
||||
reserve some space for bridges. */
|
||||
|
@ -224,8 +236,6 @@ static int __init pcibios_init(void)
|
|||
list_for_each_entry(hose, &controllers, list)
|
||||
pcibios_scanbus(hose);
|
||||
|
||||
pci_fixup_irqs(pci_common_swizzle, pcibios_map_irq);
|
||||
|
||||
pci_initialized = 1;
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -262,10 +262,6 @@ static int zpci_cfg_store(struct zpci_dev *zdev, int offset, u32 val, u8 len)
|
|||
return rc;
|
||||
}
|
||||
|
||||
void pcibios_fixup_bus(struct pci_bus *bus)
|
||||
{
|
||||
}
|
||||
|
||||
resource_size_t pcibios_align_resource(void *data, const struct resource *res,
|
||||
resource_size_t size,
|
||||
resource_size_t align)
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#include <cpu/irq.h>
|
||||
#include "pci-sh5.h"
|
||||
|
||||
int __init pcibios_map_platform_irq(const struct pci_dev *dev, u8 slot, u8 pin)
|
||||
int pcibios_map_platform_irq(const struct pci_dev *dev, u8 slot, u8 pin)
|
||||
{
|
||||
int result = -1;
|
||||
|
||||
|
|
|
@ -76,7 +76,7 @@ static void gapspci_fixup_resources(struct pci_dev *dev)
|
|||
}
|
||||
DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, gapspci_fixup_resources);
|
||||
|
||||
int __init pcibios_map_platform_irq(const struct pci_dev *dev, u8 slot, u8 pin)
|
||||
int pcibios_map_platform_irq(const struct pci_dev *dev, u8 slot, u8 pin)
|
||||
{
|
||||
/*
|
||||
* The interrupt routing semantics here are quite trivial.
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
#include <linux/sh_intc.h>
|
||||
#include "pci-sh4.h"
|
||||
|
||||
int __init pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
|
||||
int pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
|
||||
{
|
||||
return evt2irq(0xa20) + slot;
|
||||
}
|
||||
|
|
|
@ -20,18 +20,18 @@
|
|||
#define PCIMCR_MRSET_OFF 0xBFFFFFFF
|
||||
#define PCIMCR_RFSH_OFF 0xFFFFFFFB
|
||||
|
||||
static u8 rts7751r2d_irq_tab[] __initdata = {
|
||||
static u8 rts7751r2d_irq_tab[] = {
|
||||
IRQ_PCI_INTA,
|
||||
IRQ_PCI_INTB,
|
||||
IRQ_PCI_INTC,
|
||||
IRQ_PCI_INTD,
|
||||
};
|
||||
|
||||
static char lboxre2_irq_tab[] __initdata = {
|
||||
static char lboxre2_irq_tab[] = {
|
||||
IRQ_ETH0, IRQ_ETH1, IRQ_INTA, IRQ_INTD,
|
||||
};
|
||||
|
||||
int __init pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
|
||||
int pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
|
||||
{
|
||||
if (mach_is_lboxre2())
|
||||
return lboxre2_irq_tab[slot];
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
#define IRQ_INTD evt2irq(0xa80)
|
||||
|
||||
/* IDSEL [16][17][18][19][20][21][22][23][24][25][26][27][28][29][30][31] */
|
||||
static char sdk7780_irq_tab[4][16] __initdata = {
|
||||
static char sdk7780_irq_tab[4][16] = {
|
||||
/* INTA */
|
||||
{ IRQ_INTA, IRQ_INTD, IRQ_INTC, IRQ_INTD, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1 },
|
||||
|
@ -37,7 +37,7 @@ static char sdk7780_irq_tab[4][16] __initdata = {
|
|||
-1, -1, -1 },
|
||||
};
|
||||
|
||||
int __init pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
|
||||
int pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
|
||||
{
|
||||
return sdk7780_irq_tab[pin-1][slot];
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
#include <linux/sh_intc.h>
|
||||
#include "pci-sh4.h"
|
||||
|
||||
int __init pcibios_map_platform_irq(const struct pci_dev *, u8 slot, u8 pin)
|
||||
int pcibios_map_platform_irq(const struct pci_dev *, u8 slot, u8 pin)
|
||||
{
|
||||
switch (slot) {
|
||||
case 0: return evt2irq(0x3a0);
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
#include <linux/pci.h>
|
||||
#include <linux/sh_intc.h>
|
||||
|
||||
int __init pcibios_map_platform_irq(const struct pci_dev *dev, u8 slot, u8 pin)
|
||||
int pcibios_map_platform_irq(const struct pci_dev *dev, u8 slot, u8 pin)
|
||||
{
|
||||
int irq;
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
#include <linux/sh_intc.h>
|
||||
#include "pci-sh4.h"
|
||||
|
||||
int __init pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
|
||||
int pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
|
||||
{
|
||||
int irq = -1;
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
#include <mach/titan.h>
|
||||
#include "pci-sh4.h"
|
||||
|
||||
static char titan_irq_tab[] __initdata = {
|
||||
static char titan_irq_tab[] = {
|
||||
TITAN_IRQ_WAN,
|
||||
TITAN_IRQ_LAN,
|
||||
TITAN_IRQ_MPCIA,
|
||||
|
@ -27,7 +27,7 @@ static char titan_irq_tab[] __initdata = {
|
|||
TITAN_IRQ_USB,
|
||||
};
|
||||
|
||||
int __init pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
|
||||
int pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
|
||||
{
|
||||
int irq = titan_irq_tab[slot];
|
||||
|
||||
|
|
|
@ -39,8 +39,12 @@ static void pcibios_scanbus(struct pci_channel *hose)
|
|||
LIST_HEAD(resources);
|
||||
struct resource *res;
|
||||
resource_size_t offset;
|
||||
int i;
|
||||
struct pci_bus *bus;
|
||||
int i, ret;
|
||||
struct pci_host_bridge *bridge;
|
||||
|
||||
bridge = pci_alloc_host_bridge(0);
|
||||
if (!bridge)
|
||||
return;
|
||||
|
||||
for (i = 0; i < hose->nr_resources; i++) {
|
||||
res = hose->resources + i;
|
||||
|
@ -52,19 +56,26 @@ static void pcibios_scanbus(struct pci_channel *hose)
|
|||
pci_add_resource_offset(&resources, res, offset);
|
||||
}
|
||||
|
||||
bus = pci_scan_root_bus(NULL, next_busno, hose->pci_ops, hose,
|
||||
&resources);
|
||||
hose->bus = bus;
|
||||
list_splice_init(&resources, &bridge->windows);
|
||||
bridge->dev.parent = NULL;
|
||||
bridge->sysdata = hose;
|
||||
bridge->busnr = next_busno;
|
||||
bridge->ops = hose->pci_ops;
|
||||
bridge->swizzle_irq = pci_common_swizzle;
|
||||
bridge->map_irq = pcibios_map_platform_irq;
|
||||
|
||||
ret = pci_scan_root_bus_bridge(bridge);
|
||||
if (ret) {
|
||||
pci_free_host_bridge(bridge);
|
||||
return;
|
||||
}
|
||||
|
||||
hose->bus = bridge->bus;
|
||||
|
||||
need_domain_info = need_domain_info || hose->index;
|
||||
hose->need_domain_info = need_domain_info;
|
||||
|
||||
if (!bus) {
|
||||
pci_free_resource_list(&resources);
|
||||
return;
|
||||
}
|
||||
|
||||
next_busno = bus->busn_res.end + 1;
|
||||
next_busno = hose->bus->busn_res.end + 1;
|
||||
/* Don't allow 8-bit bus number overflow inside the hose -
|
||||
reserve some space for bridges. */
|
||||
if (next_busno > 224) {
|
||||
|
@ -72,9 +83,9 @@ static void pcibios_scanbus(struct pci_channel *hose)
|
|||
need_domain_info = 1;
|
||||
}
|
||||
|
||||
pci_bus_size_bridges(bus);
|
||||
pci_bus_assign_resources(bus);
|
||||
pci_bus_add_devices(bus);
|
||||
pci_bus_size_bridges(hose->bus);
|
||||
pci_bus_assign_resources(hose->bus);
|
||||
pci_bus_add_devices(hose->bus);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -144,8 +155,6 @@ static int __init pcibios_init(void)
|
|||
for (hose = hose_head; hose; hose = hose->next)
|
||||
pcibios_scanbus(hose);
|
||||
|
||||
pci_fixup_irqs(pci_common_swizzle, pcibios_map_platform_irq);
|
||||
|
||||
dma_debug_add_bus(&pci_bus_type);
|
||||
|
||||
pci_initialized = 1;
|
||||
|
@ -154,14 +163,6 @@ static int __init pcibios_init(void)
|
|||
}
|
||||
subsys_initcall(pcibios_init);
|
||||
|
||||
/*
|
||||
* Called after each bus is probed, but before its children
|
||||
* are examined.
|
||||
*/
|
||||
void pcibios_fixup_bus(struct pci_bus *bus)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* We need to avoid collisions with `mirrored' VGA ports
|
||||
* and other strange ISA hardware, so we always want the
|
||||
|
|
|
@ -467,7 +467,7 @@ static int __init pcie_init(struct sh7786_pcie_port *port)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int __init pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
|
||||
int pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
|
||||
{
|
||||
return evt2irq(0xae0);
|
||||
}
|
||||
|
|
|
@ -25,6 +25,12 @@ void leon_pci_init(struct platform_device *ofdev, struct leon_pci_info *info)
|
|||
{
|
||||
LIST_HEAD(resources);
|
||||
struct pci_bus *root_bus;
|
||||
struct pci_host_bridge *bridge;
|
||||
int ret;
|
||||
|
||||
bridge = pci_alloc_host_bridge(0);
|
||||
if (!bridge)
|
||||
return;
|
||||
|
||||
pci_add_resource_offset(&resources, &info->io_space,
|
||||
info->io_space.start - 0x1000);
|
||||
|
@ -32,15 +38,21 @@ void leon_pci_init(struct platform_device *ofdev, struct leon_pci_info *info)
|
|||
info->busn.flags = IORESOURCE_BUS;
|
||||
pci_add_resource(&resources, &info->busn);
|
||||
|
||||
root_bus = pci_scan_root_bus(&ofdev->dev, 0, info->ops, info,
|
||||
&resources);
|
||||
if (!root_bus) {
|
||||
pci_free_resource_list(&resources);
|
||||
list_splice_init(&resources, &bridge->windows);
|
||||
bridge->dev.parent = &ofdev->dev;
|
||||
bridge->sysdata = info;
|
||||
bridge->busnr = 0;
|
||||
bridge->ops = info->ops;
|
||||
bridge->swizzle_irq = pci_common_swizzle;
|
||||
bridge->map_irq = info->map_irq;
|
||||
|
||||
ret = pci_scan_root_bus_bridge(bridge);
|
||||
if (ret) {
|
||||
pci_free_host_bridge(bridge);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Setup IRQs of all devices using custom routines */
|
||||
pci_fixup_irqs(pci_common_swizzle, info->map_irq);
|
||||
root_bus = bridge->bus;
|
||||
|
||||
/* Assign devices with resources */
|
||||
pci_assign_unassigned_resources();
|
||||
|
@ -94,9 +106,3 @@ void pcibios_fixup_bus(struct pci_bus *pbus)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
resource_size_t pcibios_align_resource(void *data, const struct resource *res,
|
||||
resource_size_t size, resource_size_t align)
|
||||
{
|
||||
return res->start;
|
||||
}
|
||||
|
|
|
@ -690,16 +690,6 @@ struct pci_bus *pci_scan_one_pbm(struct pci_pbm_info *pbm,
|
|||
return bus;
|
||||
}
|
||||
|
||||
void pcibios_fixup_bus(struct pci_bus *pbus)
|
||||
{
|
||||
}
|
||||
|
||||
resource_size_t pcibios_align_resource(void *data, const struct resource *res,
|
||||
resource_size_t size, resource_size_t align)
|
||||
{
|
||||
return res->start;
|
||||
}
|
||||
|
||||
int pcibios_enable_device(struct pci_dev *dev, int mask)
|
||||
{
|
||||
u16 cmd, oldcmd;
|
||||
|
|
|
@ -746,12 +746,6 @@ static void watchdog_reset() {
|
|||
}
|
||||
#endif
|
||||
|
||||
resource_size_t pcibios_align_resource(void *data, const struct resource *res,
|
||||
resource_size_t size, resource_size_t align)
|
||||
{
|
||||
return res->start;
|
||||
}
|
||||
|
||||
int pcibios_enable_device(struct pci_dev *pdev, int mask)
|
||||
{
|
||||
return 0;
|
||||
|
|
|
@ -66,16 +66,6 @@ static int pci_scan_flags[TILE_NUM_PCIE];
|
|||
static struct pci_ops tile_cfg_ops;
|
||||
|
||||
|
||||
/*
|
||||
* We don't need to worry about the alignment of resources.
|
||||
*/
|
||||
resource_size_t pcibios_align_resource(void *data, const struct resource *res,
|
||||
resource_size_t size, resource_size_t align)
|
||||
{
|
||||
return res->start;
|
||||
}
|
||||
EXPORT_SYMBOL(pcibios_align_resource);
|
||||
|
||||
/*
|
||||
* Open a FD to the hypervisor PCI device.
|
||||
*
|
||||
|
@ -274,6 +264,7 @@ static void fixup_read_and_payload_sizes(void)
|
|||
*/
|
||||
int __init pcibios_init(void)
|
||||
{
|
||||
struct pci_host_bridge *bridge;
|
||||
int i;
|
||||
|
||||
pr_info("PCI: Probing PCI hardware\n");
|
||||
|
@ -306,16 +297,26 @@ int __init pcibios_init(void)
|
|||
|
||||
pci_add_resource(&resources, &ioport_resource);
|
||||
pci_add_resource(&resources, &iomem_resource);
|
||||
bus = pci_scan_root_bus(NULL, 0, controller->ops,
|
||||
controller, &resources);
|
||||
|
||||
bridge = pci_alloc_host_bridge(0);
|
||||
if (!bridge)
|
||||
break;
|
||||
|
||||
list_splice_init(&resources, &bridge->windows);
|
||||
bridge->dev.parent = NULL;
|
||||
bridge->sysdata = controller;
|
||||
bridge->busnr = 0;
|
||||
bridge->ops = controller->ops;
|
||||
bridge->swizzle_irq = pci_common_swizzle;
|
||||
bridge->map_irq = tile_map_irq;
|
||||
|
||||
pci_scan_root_bus_bridge(bridge);
|
||||
bus = bridge->bus;
|
||||
controller->root_bus = bus;
|
||||
controller->last_busno = bus->busn_res.end;
|
||||
}
|
||||
}
|
||||
|
||||
/* Do machine dependent PCI interrupt routing */
|
||||
pci_fixup_irqs(pci_common_swizzle, tile_map_irq);
|
||||
|
||||
/*
|
||||
* This comes from the generic Linux PCI driver.
|
||||
*
|
||||
|
@ -369,14 +370,6 @@ int __init pcibios_init(void)
|
|||
}
|
||||
subsys_initcall(pcibios_init);
|
||||
|
||||
/*
|
||||
* No bus fixups needed.
|
||||
*/
|
||||
void pcibios_fixup_bus(struct pci_bus *bus)
|
||||
{
|
||||
/* Nothing needs to be done. */
|
||||
}
|
||||
|
||||
void pcibios_set_master(struct pci_dev *dev)
|
||||
{
|
||||
/* No special bus mastering setup handling. */
|
||||
|
|
|
@ -108,15 +108,6 @@ static struct pci_ops tile_cfg_ops;
|
|||
/* Mask of CPUs that should receive PCIe interrupts. */
|
||||
static struct cpumask intr_cpus_map;
|
||||
|
||||
/* We don't need to worry about the alignment of resources. */
|
||||
resource_size_t pcibios_align_resource(void *data, const struct resource *res,
|
||||
resource_size_t size,
|
||||
resource_size_t align)
|
||||
{
|
||||
return res->start;
|
||||
}
|
||||
EXPORT_SYMBOL(pcibios_align_resource);
|
||||
|
||||
/*
|
||||
* Pick a CPU to receive and handle the PCIe interrupts, based on the IRQ #.
|
||||
* For now, we simply send interrupts to non-dataplane CPUs.
|
||||
|
@ -669,6 +660,7 @@ int __init pcibios_init(void)
|
|||
resource_size_t offset;
|
||||
LIST_HEAD(resources);
|
||||
int next_busno;
|
||||
struct pci_host_bridge *bridge;
|
||||
int i;
|
||||
|
||||
tile_pci_init();
|
||||
|
@ -881,15 +873,25 @@ int __init pcibios_init(void)
|
|||
controller->mem_offset);
|
||||
pci_add_resource(&resources, &controller->io_space);
|
||||
controller->first_busno = next_busno;
|
||||
bus = pci_scan_root_bus(NULL, next_busno, controller->ops,
|
||||
controller, &resources);
|
||||
|
||||
bridge = pci_alloc_host_bridge(0);
|
||||
if (!bridge)
|
||||
break;
|
||||
|
||||
list_splice_init(&resources, &bridge->windows);
|
||||
bridge->dev.parent = NULL;
|
||||
bridge->sysdata = controller;
|
||||
bridge->busnr = next_busno;
|
||||
bridge->ops = controller->ops;
|
||||
bridge->swizzle_irq = pci_common_swizzle;
|
||||
bridge->map_irq = tile_map_irq;
|
||||
|
||||
pci_scan_root_bus_bridge(bridge);
|
||||
bus = bridge->bus;
|
||||
controller->root_bus = bus;
|
||||
next_busno = bus->busn_res.end + 1;
|
||||
}
|
||||
|
||||
/* Do machine dependent PCI interrupt routing */
|
||||
pci_fixup_irqs(pci_common_swizzle, tile_map_irq);
|
||||
|
||||
/*
|
||||
* This comes from the generic Linux PCI driver.
|
||||
*
|
||||
|
@ -1038,11 +1040,6 @@ alloc_mem_map_failed:
|
|||
}
|
||||
subsys_initcall(pcibios_init);
|
||||
|
||||
/* No bus fixups needed. */
|
||||
void pcibios_fixup_bus(struct pci_bus *bus)
|
||||
{
|
||||
}
|
||||
|
||||
/* Process any "pci=" kernel boot arguments. */
|
||||
char *__init pcibios_setup(char *str)
|
||||
{
|
||||
|
|
|
@ -101,7 +101,7 @@ void pci_puv3_preinit(void)
|
|||
writel(readl(PCIBRI_CMD) | PCIBRI_CMD_IO | PCIBRI_CMD_MEM, PCIBRI_CMD);
|
||||
}
|
||||
|
||||
static int __init pci_puv3_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
|
||||
static int pci_puv3_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
|
||||
{
|
||||
if (dev->bus->number == 0) {
|
||||
#ifdef CONFIG_ARCH_FPGA /* 4 pci slots */
|
||||
|
@ -252,19 +252,46 @@ void pcibios_fixup_bus(struct pci_bus *bus)
|
|||
}
|
||||
EXPORT_SYMBOL(pcibios_fixup_bus);
|
||||
|
||||
static struct resource busn_resource = {
|
||||
.name = "PCI busn",
|
||||
.start = 0,
|
||||
.end = 255,
|
||||
.flags = IORESOURCE_BUS,
|
||||
};
|
||||
|
||||
static int __init pci_common_init(void)
|
||||
{
|
||||
struct pci_bus *puv3_bus;
|
||||
struct pci_host_bridge *bridge;
|
||||
int ret;
|
||||
|
||||
bridge = pci_alloc_host_bridge(0);
|
||||
if (!bridge)
|
||||
return -ENOMEM;
|
||||
|
||||
pci_puv3_preinit();
|
||||
|
||||
puv3_bus = pci_scan_bus(0, &pci_puv3_ops, NULL);
|
||||
pci_add_resource(&bridge->windows, &ioport_resource);
|
||||
pci_add_resource(&bridge->windows, &iomem_resource);
|
||||
pci_add_resource(&bridge->windows, &busn_resource);
|
||||
bridge->sysdata = NULL;
|
||||
bridge->busnr = 0;
|
||||
bridge->ops = &pci_puv3_ops;
|
||||
bridge->swizzle_irq = pci_common_swizzle;
|
||||
bridge->map_irq = pci_puv3_map_irq;
|
||||
|
||||
/* Scan our single hose. */
|
||||
ret = pci_scan_root_bus_bridge(bridge);
|
||||
if (ret) {
|
||||
pci_free_host_bridge(bridge);
|
||||
return;
|
||||
}
|
||||
|
||||
puv3_bus = bridge->bus;
|
||||
|
||||
if (!puv3_bus)
|
||||
panic("PCI: unable to scan bus!");
|
||||
|
||||
pci_fixup_irqs(pci_common_swizzle, pci_puv3_map_irq);
|
||||
|
||||
pci_bus_size_bridges(puv3_bus);
|
||||
pci_bus_assign_resources(puv3_bus);
|
||||
pci_bus_add_devices(puv3_bus);
|
||||
|
|
|
@ -618,3 +618,20 @@ static void quirk_apple_mbp_poweroff(struct pci_dev *pdev)
|
|||
dev_info(dev, "can't work around MacBook Pro poweroff issue\n");
|
||||
}
|
||||
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x8c10, quirk_apple_mbp_poweroff);
|
||||
|
||||
/*
|
||||
* VMD-enabled root ports will change the source ID for all messages
|
||||
* to the VMD device. Rather than doing device matching with the source
|
||||
* ID, the AER driver should traverse the child device tree, reading
|
||||
* AER registers to find the faulting device.
|
||||
*/
|
||||
static void quirk_no_aersid(struct pci_dev *pdev)
|
||||
{
|
||||
/* VMD Domain */
|
||||
if (is_vmd(pdev->bus))
|
||||
pdev->bus->bus_flags |= PCI_BUS_FLAGS_NO_AERSID;
|
||||
}
|
||||
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x2030, quirk_no_aersid);
|
||||
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x2031, quirk_no_aersid);
|
||||
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x2032, quirk_no_aersid);
|
||||
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x2033, quirk_no_aersid);
|
||||
|
|
|
@ -901,6 +901,13 @@ static struct intel_iommu *device_to_iommu(struct device *dev, u8 *bus, u8 *devf
|
|||
struct pci_dev *pf_pdev;
|
||||
|
||||
pdev = to_pci_dev(dev);
|
||||
|
||||
#ifdef CONFIG_X86
|
||||
/* VMD child devices currently cannot be handled individually */
|
||||
if (is_vmd(pdev->bus))
|
||||
return NULL;
|
||||
#endif
|
||||
|
||||
/* VFs aren't listed in scope tables; we need to look up
|
||||
* the PF instead to find the IOMMU. */
|
||||
pf_pdev = pci_physfn(pdev);
|
||||
|
|
|
@ -72,6 +72,11 @@ static DEFINE_IDA(pci_endpoint_test_ida);
|
|||
|
||||
#define to_endpoint_test(priv) container_of((priv), struct pci_endpoint_test, \
|
||||
miscdev)
|
||||
|
||||
static bool no_msi;
|
||||
module_param(no_msi, bool, 0444);
|
||||
MODULE_PARM_DESC(no_msi, "Disable MSI interrupt in pci_endpoint_test");
|
||||
|
||||
enum pci_barno {
|
||||
BAR_0,
|
||||
BAR_1,
|
||||
|
@ -90,9 +95,15 @@ struct pci_endpoint_test {
|
|||
/* mutex to protect the ioctls */
|
||||
struct mutex mutex;
|
||||
struct miscdevice miscdev;
|
||||
enum pci_barno test_reg_bar;
|
||||
size_t alignment;
|
||||
};
|
||||
|
||||
static int bar_size[] = { 4, 512, 1024, 16384, 131072, 1048576 };
|
||||
struct pci_endpoint_test_data {
|
||||
enum pci_barno test_reg_bar;
|
||||
size_t alignment;
|
||||
bool no_msi;
|
||||
};
|
||||
|
||||
static inline u32 pci_endpoint_test_readl(struct pci_endpoint_test *test,
|
||||
u32 offset)
|
||||
|
@ -141,11 +152,15 @@ static bool pci_endpoint_test_bar(struct pci_endpoint_test *test,
|
|||
int j;
|
||||
u32 val;
|
||||
int size;
|
||||
struct pci_dev *pdev = test->pdev;
|
||||
|
||||
if (!test->bar[barno])
|
||||
return false;
|
||||
|
||||
size = bar_size[barno];
|
||||
size = pci_resource_len(pdev, barno);
|
||||
|
||||
if (barno == test->test_reg_bar)
|
||||
size = 0x4;
|
||||
|
||||
for (j = 0; j < size; j += 4)
|
||||
pci_endpoint_test_bar_writel(test, barno, j, 0xA0A0A0A0);
|
||||
|
@ -202,16 +217,32 @@ static bool pci_endpoint_test_copy(struct pci_endpoint_test *test, size_t size)
|
|||
dma_addr_t dst_phys_addr;
|
||||
struct pci_dev *pdev = test->pdev;
|
||||
struct device *dev = &pdev->dev;
|
||||
void *orig_src_addr;
|
||||
dma_addr_t orig_src_phys_addr;
|
||||
void *orig_dst_addr;
|
||||
dma_addr_t orig_dst_phys_addr;
|
||||
size_t offset;
|
||||
size_t alignment = test->alignment;
|
||||
u32 src_crc32;
|
||||
u32 dst_crc32;
|
||||
|
||||
src_addr = dma_alloc_coherent(dev, size, &src_phys_addr, GFP_KERNEL);
|
||||
if (!src_addr) {
|
||||
orig_src_addr = dma_alloc_coherent(dev, size + alignment,
|
||||
&orig_src_phys_addr, GFP_KERNEL);
|
||||
if (!orig_src_addr) {
|
||||
dev_err(dev, "failed to allocate source buffer\n");
|
||||
ret = false;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (alignment && !IS_ALIGNED(orig_src_phys_addr, alignment)) {
|
||||
src_phys_addr = PTR_ALIGN(orig_src_phys_addr, alignment);
|
||||
offset = src_phys_addr - orig_src_phys_addr;
|
||||
src_addr = orig_src_addr + offset;
|
||||
} else {
|
||||
src_phys_addr = orig_src_phys_addr;
|
||||
src_addr = orig_src_addr;
|
||||
}
|
||||
|
||||
pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_LOWER_SRC_ADDR,
|
||||
lower_32_bits(src_phys_addr));
|
||||
|
||||
|
@ -221,11 +252,21 @@ static bool pci_endpoint_test_copy(struct pci_endpoint_test *test, size_t size)
|
|||
get_random_bytes(src_addr, size);
|
||||
src_crc32 = crc32_le(~0, src_addr, size);
|
||||
|
||||
dst_addr = dma_alloc_coherent(dev, size, &dst_phys_addr, GFP_KERNEL);
|
||||
if (!dst_addr) {
|
||||
orig_dst_addr = dma_alloc_coherent(dev, size + alignment,
|
||||
&orig_dst_phys_addr, GFP_KERNEL);
|
||||
if (!orig_dst_addr) {
|
||||
dev_err(dev, "failed to allocate destination address\n");
|
||||
ret = false;
|
||||
goto err_src_addr;
|
||||
goto err_orig_src_addr;
|
||||
}
|
||||
|
||||
if (alignment && !IS_ALIGNED(orig_dst_phys_addr, alignment)) {
|
||||
dst_phys_addr = PTR_ALIGN(orig_dst_phys_addr, alignment);
|
||||
offset = dst_phys_addr - orig_dst_phys_addr;
|
||||
dst_addr = orig_dst_addr + offset;
|
||||
} else {
|
||||
dst_phys_addr = orig_dst_phys_addr;
|
||||
dst_addr = orig_dst_addr;
|
||||
}
|
||||
|
||||
pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_LOWER_DST_ADDR,
|
||||
|
@ -245,10 +286,12 @@ static bool pci_endpoint_test_copy(struct pci_endpoint_test *test, size_t size)
|
|||
if (dst_crc32 == src_crc32)
|
||||
ret = true;
|
||||
|
||||
dma_free_coherent(dev, size, dst_addr, dst_phys_addr);
|
||||
dma_free_coherent(dev, size + alignment, orig_dst_addr,
|
||||
orig_dst_phys_addr);
|
||||
|
||||
err_src_addr:
|
||||
dma_free_coherent(dev, size, src_addr, src_phys_addr);
|
||||
err_orig_src_addr:
|
||||
dma_free_coherent(dev, size + alignment, orig_src_addr,
|
||||
orig_src_phys_addr);
|
||||
|
||||
err:
|
||||
return ret;
|
||||
|
@ -262,15 +305,29 @@ static bool pci_endpoint_test_write(struct pci_endpoint_test *test, size_t size)
|
|||
dma_addr_t phys_addr;
|
||||
struct pci_dev *pdev = test->pdev;
|
||||
struct device *dev = &pdev->dev;
|
||||
void *orig_addr;
|
||||
dma_addr_t orig_phys_addr;
|
||||
size_t offset;
|
||||
size_t alignment = test->alignment;
|
||||
u32 crc32;
|
||||
|
||||
addr = dma_alloc_coherent(dev, size, &phys_addr, GFP_KERNEL);
|
||||
if (!addr) {
|
||||
orig_addr = dma_alloc_coherent(dev, size + alignment, &orig_phys_addr,
|
||||
GFP_KERNEL);
|
||||
if (!orig_addr) {
|
||||
dev_err(dev, "failed to allocate address\n");
|
||||
ret = false;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (alignment && !IS_ALIGNED(orig_phys_addr, alignment)) {
|
||||
phys_addr = PTR_ALIGN(orig_phys_addr, alignment);
|
||||
offset = phys_addr - orig_phys_addr;
|
||||
addr = orig_addr + offset;
|
||||
} else {
|
||||
phys_addr = orig_phys_addr;
|
||||
addr = orig_addr;
|
||||
}
|
||||
|
||||
get_random_bytes(addr, size);
|
||||
|
||||
crc32 = crc32_le(~0, addr, size);
|
||||
|
@ -293,7 +350,7 @@ static bool pci_endpoint_test_write(struct pci_endpoint_test *test, size_t size)
|
|||
if (reg & STATUS_READ_SUCCESS)
|
||||
ret = true;
|
||||
|
||||
dma_free_coherent(dev, size, addr, phys_addr);
|
||||
dma_free_coherent(dev, size + alignment, orig_addr, orig_phys_addr);
|
||||
|
||||
err:
|
||||
return ret;
|
||||
|
@ -306,15 +363,29 @@ static bool pci_endpoint_test_read(struct pci_endpoint_test *test, size_t size)
|
|||
dma_addr_t phys_addr;
|
||||
struct pci_dev *pdev = test->pdev;
|
||||
struct device *dev = &pdev->dev;
|
||||
void *orig_addr;
|
||||
dma_addr_t orig_phys_addr;
|
||||
size_t offset;
|
||||
size_t alignment = test->alignment;
|
||||
u32 crc32;
|
||||
|
||||
addr = dma_alloc_coherent(dev, size, &phys_addr, GFP_KERNEL);
|
||||
if (!addr) {
|
||||
orig_addr = dma_alloc_coherent(dev, size + alignment, &orig_phys_addr,
|
||||
GFP_KERNEL);
|
||||
if (!orig_addr) {
|
||||
dev_err(dev, "failed to allocate destination address\n");
|
||||
ret = false;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (alignment && !IS_ALIGNED(orig_phys_addr, alignment)) {
|
||||
phys_addr = PTR_ALIGN(orig_phys_addr, alignment);
|
||||
offset = phys_addr - orig_phys_addr;
|
||||
addr = orig_addr + offset;
|
||||
} else {
|
||||
phys_addr = orig_phys_addr;
|
||||
addr = orig_addr;
|
||||
}
|
||||
|
||||
pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_LOWER_DST_ADDR,
|
||||
lower_32_bits(phys_addr));
|
||||
pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_UPPER_DST_ADDR,
|
||||
|
@ -331,7 +402,7 @@ static bool pci_endpoint_test_read(struct pci_endpoint_test *test, size_t size)
|
|||
if (crc32 == pci_endpoint_test_readl(test, PCI_ENDPOINT_TEST_CHECKSUM))
|
||||
ret = true;
|
||||
|
||||
dma_free_coherent(dev, size, addr, phys_addr);
|
||||
dma_free_coherent(dev, size + alignment, orig_addr, orig_phys_addr);
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
@ -383,13 +454,15 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev,
|
|||
{
|
||||
int i;
|
||||
int err;
|
||||
int irq;
|
||||
int irq = 0;
|
||||
int id;
|
||||
char name[20];
|
||||
enum pci_barno bar;
|
||||
void __iomem *base;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct pci_endpoint_test *test;
|
||||
struct pci_endpoint_test_data *data;
|
||||
enum pci_barno test_reg_bar = BAR_0;
|
||||
struct miscdevice *misc_device;
|
||||
|
||||
if (pci_is_bridge(pdev))
|
||||
|
@ -399,7 +472,17 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev,
|
|||
if (!test)
|
||||
return -ENOMEM;
|
||||
|
||||
test->test_reg_bar = 0;
|
||||
test->alignment = 0;
|
||||
test->pdev = pdev;
|
||||
|
||||
data = (struct pci_endpoint_test_data *)ent->driver_data;
|
||||
if (data) {
|
||||
test_reg_bar = data->test_reg_bar;
|
||||
test->alignment = data->alignment;
|
||||
no_msi = data->no_msi;
|
||||
}
|
||||
|
||||
init_completion(&test->irq_raised);
|
||||
mutex_init(&test->mutex);
|
||||
|
||||
|
@ -417,9 +500,11 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev,
|
|||
|
||||
pci_set_master(pdev);
|
||||
|
||||
irq = pci_alloc_irq_vectors(pdev, 1, 32, PCI_IRQ_MSI);
|
||||
if (irq < 0)
|
||||
dev_err(dev, "failed to get MSI interrupts\n");
|
||||
if (!no_msi) {
|
||||
irq = pci_alloc_irq_vectors(pdev, 1, 32, PCI_IRQ_MSI);
|
||||
if (irq < 0)
|
||||
dev_err(dev, "failed to get MSI interrupts\n");
|
||||
}
|
||||
|
||||
err = devm_request_irq(dev, pdev->irq, pci_endpoint_test_irqhandler,
|
||||
IRQF_SHARED, DRV_MODULE_NAME, test);
|
||||
|
@ -441,14 +526,15 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev,
|
|||
base = pci_ioremap_bar(pdev, bar);
|
||||
if (!base) {
|
||||
dev_err(dev, "failed to read BAR%d\n", bar);
|
||||
WARN_ON(bar == BAR_0);
|
||||
WARN_ON(bar == test_reg_bar);
|
||||
}
|
||||
test->bar[bar] = base;
|
||||
}
|
||||
|
||||
test->base = test->bar[0];
|
||||
test->base = test->bar[test_reg_bar];
|
||||
if (!test->base) {
|
||||
dev_err(dev, "Cannot perform PCI test without BAR0\n");
|
||||
dev_err(dev, "Cannot perform PCI test without BAR%d\n",
|
||||
test_reg_bar);
|
||||
goto err_iounmap;
|
||||
}
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ config PCI_DRA7XX
|
|||
work either as EP or RC. In order to enable host-specific features
|
||||
PCI_DRA7XX_HOST must be selected and in order to enable device-
|
||||
specific features PCI_DRA7XX_EP must be selected. This uses
|
||||
the Designware core.
|
||||
the DesignWare core.
|
||||
|
||||
if PCI_DRA7XX
|
||||
|
||||
|
@ -97,8 +97,8 @@ config PCI_KEYSTONE
|
|||
select PCIE_DW_HOST
|
||||
help
|
||||
Say Y here if you want to enable PCI controller support on Keystone
|
||||
SoCs. The PCI controller on Keystone is based on Designware hardware
|
||||
and therefore the driver re-uses the Designware core functions to
|
||||
SoCs. The PCI controller on Keystone is based on DesignWare hardware
|
||||
and therefore the driver re-uses the DesignWare core functions to
|
||||
implement the driver.
|
||||
|
||||
config PCI_LAYERSCAPE
|
||||
|
@ -132,7 +132,7 @@ config PCIE_QCOM
|
|||
select PCIE_DW_HOST
|
||||
help
|
||||
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
|
||||
hardware wrappers.
|
||||
|
||||
config PCIE_ARMADA_8K
|
||||
|
@ -145,8 +145,8 @@ config PCIE_ARMADA_8K
|
|||
help
|
||||
Say Y here if you want to enable PCIe controller support on
|
||||
Armada-8K SoCs. The PCIe controller on Armada-8K is based on
|
||||
Designware hardware and therefore the driver re-uses the
|
||||
Designware core functions to implement the driver.
|
||||
DesignWare hardware and therefore the driver re-uses the
|
||||
DesignWare core functions to implement the driver.
|
||||
|
||||
config PCIE_ARTPEC6
|
||||
bool "Axis ARTPEC-6 PCIe controller"
|
||||
|
|
|
@ -195,7 +195,7 @@ static void dra7xx_pcie_enable_interrupts(struct dra7xx_pcie *dra7xx)
|
|||
dra7xx_pcie_enable_msi_interrupts(dra7xx);
|
||||
}
|
||||
|
||||
static void dra7xx_pcie_host_init(struct pcie_port *pp)
|
||||
static int dra7xx_pcie_host_init(struct pcie_port *pp)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
struct dra7xx_pcie *dra7xx = to_dra7xx_pcie(pci);
|
||||
|
@ -206,6 +206,8 @@ static void dra7xx_pcie_host_init(struct pcie_port *pp)
|
|||
dw_pcie_wait_for_link(pci);
|
||||
dw_pcie_msi_init(pp);
|
||||
dra7xx_pcie_enable_interrupts(dra7xx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dw_pcie_host_ops dra7xx_pcie_host_ops = {
|
||||
|
@ -238,7 +240,7 @@ static int dra7xx_pcie_init_irq_domain(struct pcie_port *pp)
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
dra7xx->irq_domain = irq_domain_add_linear(pcie_intc_node, 4,
|
||||
dra7xx->irq_domain = irq_domain_add_linear(pcie_intc_node, PCI_NUM_INTX,
|
||||
&intx_domain_ops, pp);
|
||||
if (!dra7xx->irq_domain) {
|
||||
dev_err(dev, "Failed to get a INTx IRQ domain\n");
|
||||
|
@ -275,7 +277,6 @@ static irqreturn_t dra7xx_pcie_msi_irq_handler(int irq, void *arg)
|
|||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
|
||||
static irqreturn_t dra7xx_pcie_irq_handler(int irq, void *arg)
|
||||
{
|
||||
struct dra7xx_pcie *dra7xx = arg;
|
||||
|
@ -335,10 +336,23 @@ static irqreturn_t dra7xx_pcie_irq_handler(int irq, void *arg)
|
|||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar)
|
||||
{
|
||||
u32 reg;
|
||||
|
||||
reg = PCI_BASE_ADDRESS_0 + (4 * bar);
|
||||
dw_pcie_writel_dbi2(pci, reg, 0x0);
|
||||
dw_pcie_writel_dbi(pci, reg, 0x0);
|
||||
}
|
||||
|
||||
static void dra7xx_pcie_ep_init(struct dw_pcie_ep *ep)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
|
||||
struct dra7xx_pcie *dra7xx = to_dra7xx_pcie(pci);
|
||||
enum pci_barno bar;
|
||||
|
||||
for (bar = BAR_0; bar <= BAR_5; bar++)
|
||||
dw_pcie_ep_reset_bar(pci, bar);
|
||||
|
||||
dra7xx_pcie_enable_wrapper_interrupts(dra7xx);
|
||||
}
|
||||
|
@ -435,7 +449,7 @@ static int __init dra7xx_add_pcie_port(struct dra7xx_pcie *dra7xx,
|
|||
pp->irq = platform_get_irq(pdev, 1);
|
||||
if (pp->irq < 0) {
|
||||
dev_err(dev, "missing IRQ resource\n");
|
||||
return -EINVAL;
|
||||
return pp->irq;
|
||||
}
|
||||
|
||||
ret = devm_request_irq(dev, pp->irq, dra7xx_pcie_msi_irq_handler,
|
||||
|
@ -616,8 +630,8 @@ static int __init dra7xx_pcie_probe(struct platform_device *pdev)
|
|||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
dev_err(dev, "missing IRQ resource\n");
|
||||
return -EINVAL;
|
||||
dev_err(dev, "missing IRQ resource: %d\n", irq);
|
||||
return irq;
|
||||
}
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ti_conf");
|
||||
|
|
|
@ -581,13 +581,15 @@ static int exynos_pcie_link_up(struct dw_pcie *pci)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void exynos_pcie_host_init(struct pcie_port *pp)
|
||||
static int exynos_pcie_host_init(struct pcie_port *pp)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
struct exynos_pcie *ep = to_exynos_pcie(pci);
|
||||
|
||||
exynos_pcie_establish_link(ep);
|
||||
exynos_pcie_enable_interrupts(ep);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dw_pcie_host_ops exynos_pcie_host_ops = {
|
||||
|
@ -605,9 +607,9 @@ static int __init exynos_add_pcie_port(struct exynos_pcie *ep,
|
|||
int ret;
|
||||
|
||||
pp->irq = platform_get_irq(pdev, 1);
|
||||
if (!pp->irq) {
|
||||
if (pp->irq < 0) {
|
||||
dev_err(dev, "failed to get irq\n");
|
||||
return -ENODEV;
|
||||
return pp->irq;
|
||||
}
|
||||
ret = devm_request_irq(dev, pp->irq, exynos_pcie_irq_handler,
|
||||
IRQF_SHARED, "exynos-pcie", ep);
|
||||
|
@ -618,9 +620,9 @@ static int __init exynos_add_pcie_port(struct exynos_pcie *ep,
|
|||
|
||||
if (IS_ENABLED(CONFIG_PCI_MSI)) {
|
||||
pp->msi_irq = platform_get_irq(pdev, 0);
|
||||
if (!pp->msi_irq) {
|
||||
if (pp->msi_irq < 0) {
|
||||
dev_err(dev, "failed to get msi irq\n");
|
||||
return -ENODEV;
|
||||
return pp->msi_irq;
|
||||
}
|
||||
|
||||
ret = devm_request_irq(dev, pp->msi_irq,
|
||||
|
|
|
@ -636,7 +636,7 @@ err_reset_phy:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void imx6_pcie_host_init(struct pcie_port *pp)
|
||||
static int imx6_pcie_host_init(struct pcie_port *pp)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
struct imx6_pcie *imx6_pcie = to_imx6_pcie(pci);
|
||||
|
@ -649,6 +649,8 @@ static void imx6_pcie_host_init(struct pcie_port *pp)
|
|||
|
||||
if (IS_ENABLED(CONFIG_PCI_MSI))
|
||||
dw_pcie_msi_init(pp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int imx6_pcie_link_up(struct dw_pcie *pci)
|
||||
|
@ -778,14 +780,15 @@ static int imx6_pcie_probe(struct platform_device *pdev)
|
|||
}
|
||||
break;
|
||||
case IMX7D:
|
||||
imx6_pcie->pciephy_reset = devm_reset_control_get(dev,
|
||||
"pciephy");
|
||||
imx6_pcie->pciephy_reset = devm_reset_control_get_exclusive(dev,
|
||||
"pciephy");
|
||||
if (IS_ERR(imx6_pcie->pciephy_reset)) {
|
||||
dev_err(dev, "Failed to get PCIEPHY reset control\n");
|
||||
return PTR_ERR(imx6_pcie->pciephy_reset);
|
||||
}
|
||||
|
||||
imx6_pcie->apps_reset = devm_reset_control_get(dev, "apps");
|
||||
imx6_pcie->apps_reset = devm_reset_control_get_exclusive(dev,
|
||||
"apps");
|
||||
if (IS_ERR(imx6_pcie->apps_reset)) {
|
||||
dev_err(dev, "Failed to get PCIE APPS reset control\n");
|
||||
return PTR_ERR(imx6_pcie->apps_reset);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Designware application register space functions for Keystone PCI controller
|
||||
* DesignWare application register space functions for Keystone PCI controller
|
||||
*
|
||||
* Copyright (C) 2013-2014 Texas Instruments., Ltd.
|
||||
* http://www.ti.com
|
||||
|
@ -168,16 +168,12 @@ void ks_dw_pcie_msi_clear_irq(struct pcie_port *pp, int irq)
|
|||
|
||||
static void ks_dw_pcie_msi_irq_mask(struct irq_data *d)
|
||||
{
|
||||
struct keystone_pcie *ks_pcie;
|
||||
struct msi_desc *msi;
|
||||
struct pcie_port *pp;
|
||||
struct dw_pcie *pci;
|
||||
u32 offset;
|
||||
|
||||
msi = irq_data_get_msi_desc(d);
|
||||
pp = (struct pcie_port *) msi_desc_to_pci_sysdata(msi);
|
||||
pci = to_dw_pcie_from_pp(pp);
|
||||
ks_pcie = to_keystone_pcie(pci);
|
||||
offset = d->irq - irq_linear_revmap(pp->irq_domain, 0);
|
||||
|
||||
/* Mask the end point if PVM implemented */
|
||||
|
@ -191,16 +187,12 @@ static void ks_dw_pcie_msi_irq_mask(struct irq_data *d)
|
|||
|
||||
static void ks_dw_pcie_msi_irq_unmask(struct irq_data *d)
|
||||
{
|
||||
struct keystone_pcie *ks_pcie;
|
||||
struct msi_desc *msi;
|
||||
struct pcie_port *pp;
|
||||
struct dw_pcie *pci;
|
||||
u32 offset;
|
||||
|
||||
msi = irq_data_get_msi_desc(d);
|
||||
pp = (struct pcie_port *) msi_desc_to_pci_sysdata(msi);
|
||||
pci = to_dw_pcie_from_pp(pp);
|
||||
ks_pcie = to_keystone_pcie(pci);
|
||||
offset = d->irq - irq_linear_revmap(pp->irq_domain, 0);
|
||||
|
||||
/* Mask the end point if PVM implemented */
|
||||
|
@ -259,7 +251,7 @@ void ks_dw_pcie_enable_legacy_irqs(struct keystone_pcie *ks_pcie)
|
|||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_LEGACY_IRQS; i++)
|
||||
for (i = 0; i < PCI_NUM_INTX; i++)
|
||||
ks_dw_app_writel(ks_pcie, IRQ_ENABLE_SET + (i << 4), 0x1);
|
||||
}
|
||||
|
||||
|
@ -565,7 +557,7 @@ int __init ks_dw_pcie_host_init(struct keystone_pcie *ks_pcie,
|
|||
/* Create legacy IRQ domain */
|
||||
ks_pcie->legacy_irq_domain =
|
||||
irq_domain_add_linear(ks_pcie->legacy_intc_np,
|
||||
MAX_LEGACY_IRQS,
|
||||
PCI_NUM_INTX,
|
||||
&ks_dw_pcie_legacy_irq_domain_ops,
|
||||
NULL);
|
||||
if (!ks_pcie->legacy_irq_domain) {
|
||||
|
|
|
@ -32,10 +32,6 @@
|
|||
|
||||
#define DRIVER_NAME "keystone-pcie"
|
||||
|
||||
/* driver specific constants */
|
||||
#define MAX_MSI_HOST_IRQS 8
|
||||
#define MAX_LEGACY_HOST_IRQS 4
|
||||
|
||||
/* DEV_STAT_CTRL */
|
||||
#define PCIE_CAP_BASE 0x70
|
||||
|
||||
|
@ -173,7 +169,7 @@ static int ks_pcie_get_irq_controller_info(struct keystone_pcie *ks_pcie,
|
|||
|
||||
if (legacy) {
|
||||
np_temp = &ks_pcie->legacy_intc_np;
|
||||
max_host_irqs = MAX_LEGACY_HOST_IRQS;
|
||||
max_host_irqs = PCI_NUM_INTX;
|
||||
host_irqs = &ks_pcie->legacy_host_irqs[0];
|
||||
} else {
|
||||
np_temp = &ks_pcie->msi_intc_np;
|
||||
|
@ -261,7 +257,7 @@ static int keystone_pcie_fault(unsigned long addr, unsigned int fsr,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void __init ks_pcie_host_init(struct pcie_port *pp)
|
||||
static int __init ks_pcie_host_init(struct pcie_port *pp)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
struct keystone_pcie *ks_pcie = to_keystone_pcie(pci);
|
||||
|
@ -289,6 +285,8 @@ static void __init ks_pcie_host_init(struct pcie_port *pp)
|
|||
*/
|
||||
hook_fault_code(17, keystone_pcie_fault, SIGBUS, 0,
|
||||
"Asynchronous external abort");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dw_pcie_host_ops keystone_pcie_host_ops = {
|
||||
|
|
|
@ -12,9 +12,7 @@
|
|||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#define MAX_LEGACY_IRQS 4
|
||||
#define MAX_MSI_HOST_IRQS 8
|
||||
#define MAX_LEGACY_HOST_IRQS 4
|
||||
|
||||
struct keystone_pcie {
|
||||
struct dw_pcie *pci;
|
||||
|
@ -22,7 +20,7 @@ struct keystone_pcie {
|
|||
/* PCI Device ID */
|
||||
u32 device_id;
|
||||
int num_legacy_host_irqs;
|
||||
int legacy_host_irqs[MAX_LEGACY_HOST_IRQS];
|
||||
int legacy_host_irqs[PCI_NUM_INTX];
|
||||
struct device_node *legacy_intc_np;
|
||||
|
||||
int num_msi_host_irqs;
|
||||
|
|
|
@ -33,7 +33,8 @@
|
|||
|
||||
/* PEX Internal Configuration Registers */
|
||||
#define PCIE_STRFMR1 0x71c /* Symbol Timer & Filter Mask Register1 */
|
||||
#define PCIE_DBI_RO_WR_EN 0x8bc /* DBI Read-Only Write Enable Register */
|
||||
|
||||
#define PCIE_IATU_NUM 6
|
||||
|
||||
struct ls_pcie_drvdata {
|
||||
u32 lut_offset;
|
||||
|
@ -72,14 +73,6 @@ static void ls_pcie_clear_multifunction(struct ls_pcie *pcie)
|
|||
iowrite8(PCI_HEADER_TYPE_BRIDGE, pci->dbi_base + PCI_HEADER_TYPE);
|
||||
}
|
||||
|
||||
/* Fix class value */
|
||||
static void ls_pcie_fix_class(struct ls_pcie *pcie)
|
||||
{
|
||||
struct dw_pcie *pci = pcie->pci;
|
||||
|
||||
iowrite16(PCI_CLASS_BRIDGE_PCI, pci->dbi_base + PCI_CLASS_DEVICE);
|
||||
}
|
||||
|
||||
/* Drop MSG TLP except for Vendor MSG */
|
||||
static void ls_pcie_drop_msg_tlp(struct ls_pcie *pcie)
|
||||
{
|
||||
|
@ -91,6 +84,14 @@ static void ls_pcie_drop_msg_tlp(struct ls_pcie *pcie)
|
|||
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, DW_PCIE_REGION_OUTBOUND, i);
|
||||
}
|
||||
|
||||
static int ls1021_pcie_link_up(struct dw_pcie *pci)
|
||||
{
|
||||
u32 state;
|
||||
|
@ -108,33 +109,6 @@ static int ls1021_pcie_link_up(struct dw_pcie *pci)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static void ls1021_pcie_host_init(struct pcie_port *pp)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
struct ls_pcie *pcie = to_ls_pcie(pci);
|
||||
struct device *dev = pci->dev;
|
||||
u32 index[2];
|
||||
|
||||
pcie->scfg = syscon_regmap_lookup_by_phandle(dev->of_node,
|
||||
"fsl,pcie-scfg");
|
||||
if (IS_ERR(pcie->scfg)) {
|
||||
dev_err(dev, "No syscfg phandle specified\n");
|
||||
pcie->scfg = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
if (of_property_read_u32_array(dev->of_node,
|
||||
"fsl,pcie-scfg", index, 2)) {
|
||||
pcie->scfg = NULL;
|
||||
return;
|
||||
}
|
||||
pcie->index = index[1];
|
||||
|
||||
dw_pcie_setup_rc(pp);
|
||||
|
||||
ls_pcie_drop_msg_tlp(pcie);
|
||||
}
|
||||
|
||||
static int ls_pcie_link_up(struct dw_pcie *pci)
|
||||
{
|
||||
struct ls_pcie *pcie = to_ls_pcie(pci);
|
||||
|
@ -150,16 +124,54 @@ static int ls_pcie_link_up(struct dw_pcie *pci)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static void ls_pcie_host_init(struct pcie_port *pp)
|
||||
static int ls_pcie_host_init(struct pcie_port *pp)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
struct ls_pcie *pcie = to_ls_pcie(pci);
|
||||
|
||||
iowrite32(1, pci->dbi_base + PCIE_DBI_RO_WR_EN);
|
||||
ls_pcie_fix_class(pcie);
|
||||
/*
|
||||
* 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);
|
||||
|
||||
dw_pcie_dbi_ro_wr_en(pci);
|
||||
ls_pcie_clear_multifunction(pcie);
|
||||
dw_pcie_dbi_ro_wr_dis(pci);
|
||||
|
||||
ls_pcie_drop_msg_tlp(pcie);
|
||||
iowrite32(0, pci->dbi_base + PCIE_DBI_RO_WR_EN);
|
||||
|
||||
dw_pcie_setup_rc(pp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ls1021_pcie_host_init(struct pcie_port *pp)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
struct ls_pcie *pcie = to_ls_pcie(pci);
|
||||
struct device *dev = pci->dev;
|
||||
u32 index[2];
|
||||
int ret;
|
||||
|
||||
pcie->scfg = syscon_regmap_lookup_by_phandle(dev->of_node,
|
||||
"fsl,pcie-scfg");
|
||||
if (IS_ERR(pcie->scfg)) {
|
||||
ret = PTR_ERR(pcie->scfg);
|
||||
dev_err(dev, "No syscfg phandle specified\n");
|
||||
pcie->scfg = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (of_property_read_u32_array(dev->of_node,
|
||||
"fsl,pcie-scfg", index, 2)) {
|
||||
pcie->scfg = NULL;
|
||||
return -EINVAL;
|
||||
}
|
||||
pcie->index = index[1];
|
||||
|
||||
return ls_pcie_host_init(pp);
|
||||
}
|
||||
|
||||
static int ls_pcie_msi_host_init(struct pcie_port *pp,
|
||||
|
@ -232,12 +244,22 @@ static struct ls_pcie_drvdata ls2080_drvdata = {
|
|||
.dw_pcie_ops = &dw_ls_pcie_ops,
|
||||
};
|
||||
|
||||
static struct ls_pcie_drvdata ls2088_drvdata = {
|
||||
.lut_offset = 0x80000,
|
||||
.ltssm_shift = 0,
|
||||
.lut_dbg = 0x407fc,
|
||||
.ops = &ls_pcie_host_ops,
|
||||
.dw_pcie_ops = &dw_ls_pcie_ops,
|
||||
};
|
||||
|
||||
static const struct of_device_id ls_pcie_of_match[] = {
|
||||
{ .compatible = "fsl,ls1021a-pcie", .data = &ls1021_drvdata },
|
||||
{ .compatible = "fsl,ls1043a-pcie", .data = &ls1043_drvdata },
|
||||
{ .compatible = "fsl,ls1046a-pcie", .data = &ls1046_drvdata },
|
||||
{ .compatible = "fsl,ls2080a-pcie", .data = &ls2080_drvdata },
|
||||
{ .compatible = "fsl,ls2085a-pcie", .data = &ls2080_drvdata },
|
||||
{ .compatible = "fsl,ls2088a-pcie", .data = &ls2088_drvdata },
|
||||
{ .compatible = "fsl,ls1088a-pcie", .data = &ls2088_drvdata },
|
||||
{ },
|
||||
};
|
||||
|
||||
|
|
|
@ -134,13 +134,15 @@ static void armada8k_pcie_establish_link(struct armada8k_pcie *pcie)
|
|||
dev_err(pci->dev, "Link not up after reconfiguration\n");
|
||||
}
|
||||
|
||||
static void armada8k_pcie_host_init(struct pcie_port *pp)
|
||||
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;
|
||||
}
|
||||
|
||||
static irqreturn_t armada8k_pcie_irq_handler(int irq, void *arg)
|
||||
|
@ -176,9 +178,9 @@ static int armada8k_add_pcie_port(struct armada8k_pcie *pcie,
|
|||
pp->ops = &armada8k_pcie_host_ops;
|
||||
|
||||
pp->irq = platform_get_irq(pdev, 0);
|
||||
if (!pp->irq) {
|
||||
if (pp->irq < 0) {
|
||||
dev_err(dev, "failed to get irq for port\n");
|
||||
return -ENODEV;
|
||||
return pp->irq;
|
||||
}
|
||||
|
||||
ret = devm_request_irq(dev, pp->irq, armada8k_pcie_irq_handler,
|
||||
|
@ -226,7 +228,9 @@ static int armada8k_pcie_probe(struct platform_device *pdev)
|
|||
if (IS_ERR(pcie->clk))
|
||||
return PTR_ERR(pcie->clk);
|
||||
|
||||
clk_prepare_enable(pcie->clk);
|
||||
ret = clk_prepare_enable(pcie->clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Get the dw-pcie unit configuration/control registers base. */
|
||||
base = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ctrl");
|
||||
|
|
|
@ -141,12 +141,6 @@ static int artpec6_pcie_establish_link(struct artpec6_pcie *artpec6_pcie)
|
|||
artpec6_pcie_writel(artpec6_pcie, PCIECFG, val);
|
||||
usleep_range(100, 200);
|
||||
|
||||
/*
|
||||
* Enable writing to config regs. This is required as the Synopsys
|
||||
* driver changes the class code. That register needs DBI write enable.
|
||||
*/
|
||||
dw_pcie_writel_dbi(pci, MISC_CONTROL_1_OFF, DBI_RO_WR_EN);
|
||||
|
||||
/* setup root complex */
|
||||
dw_pcie_setup_rc(pp);
|
||||
|
||||
|
@ -175,13 +169,15 @@ static void artpec6_pcie_enable_interrupts(struct artpec6_pcie *artpec6_pcie)
|
|||
dw_pcie_msi_init(pp);
|
||||
}
|
||||
|
||||
static void artpec6_pcie_host_init(struct pcie_port *pp)
|
||||
static int artpec6_pcie_host_init(struct pcie_port *pp)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
struct artpec6_pcie *artpec6_pcie = to_artpec6_pcie(pci);
|
||||
|
||||
artpec6_pcie_establish_link(artpec6_pcie);
|
||||
artpec6_pcie_enable_interrupts(artpec6_pcie);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dw_pcie_host_ops artpec6_pcie_host_ops = {
|
||||
|
@ -207,9 +203,9 @@ static int artpec6_add_pcie_port(struct artpec6_pcie *artpec6_pcie,
|
|||
|
||||
if (IS_ENABLED(CONFIG_PCI_MSI)) {
|
||||
pp->msi_irq = platform_get_irq_byname(pdev, "msi");
|
||||
if (pp->msi_irq <= 0) {
|
||||
if (pp->msi_irq < 0) {
|
||||
dev_err(dev, "failed to get MSI irq\n");
|
||||
return -ENODEV;
|
||||
return pp->msi_irq;
|
||||
}
|
||||
|
||||
ret = devm_request_irq(dev, pp->msi_irq,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* Synopsys Designware PCIe Endpoint controller driver
|
||||
* Synopsys DesignWare PCIe Endpoint controller driver
|
||||
*
|
||||
* Copyright (C) 2017 Texas Instruments
|
||||
* Author: Kishon Vijay Abraham I <kishon@ti.com>
|
||||
|
@ -283,7 +283,6 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep)
|
|||
{
|
||||
int ret;
|
||||
void *addr;
|
||||
enum pci_barno bar;
|
||||
struct pci_epc *epc;
|
||||
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
|
||||
struct device *dev = pci->dev;
|
||||
|
@ -312,9 +311,6 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep)
|
|||
return -ENOMEM;
|
||||
ep->outbound_addr = addr;
|
||||
|
||||
for (bar = BAR_0; bar <= BAR_5; bar++)
|
||||
dw_pcie_ep_reset_bar(pci, bar);
|
||||
|
||||
if (ep->ops->ep_init)
|
||||
ep->ops->ep_init(ep);
|
||||
|
||||
|
@ -328,7 +324,8 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep)
|
|||
if (ret < 0)
|
||||
epc->max_functions = 1;
|
||||
|
||||
ret = pci_epc_mem_init(epc, ep->phys_base, ep->addr_size);
|
||||
ret = __pci_epc_mem_init(epc, ep->phys_base, ep->addr_size,
|
||||
ep->page_size);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Failed to initialize address space\n");
|
||||
return ret;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Synopsys Designware PCIe host controller driver
|
||||
* Synopsys DesignWare PCIe host controller driver
|
||||
*
|
||||
* Copyright (C) 2013 Samsung Electronics Co., Ltd.
|
||||
* http://www.samsung.com
|
||||
|
@ -71,9 +71,9 @@ irqreturn_t dw_handle_msi_irq(struct pcie_port *pp)
|
|||
while ((pos = find_next_bit((unsigned long *) &val, 32,
|
||||
pos)) != 32) {
|
||||
irq = irq_find_mapping(pp->irq_domain, i * 32 + pos);
|
||||
generic_handle_irq(irq);
|
||||
dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_STATUS + i * 12,
|
||||
4, 1 << pos);
|
||||
generic_handle_irq(irq);
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
|
@ -401,8 +401,11 @@ int dw_pcie_host_init(struct pcie_port *pp)
|
|||
}
|
||||
}
|
||||
|
||||
if (pp->ops->host_init)
|
||||
pp->ops->host_init(pp);
|
||||
if (pp->ops->host_init) {
|
||||
ret = pp->ops->host_init(pp);
|
||||
if (ret)
|
||||
goto error;
|
||||
}
|
||||
|
||||
pp->root_bus_nr = pp->busn->start;
|
||||
|
||||
|
@ -594,10 +597,12 @@ void dw_pcie_setup_rc(struct pcie_port *pp)
|
|||
dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_1, 0x00000000);
|
||||
|
||||
/* setup interrupt pins */
|
||||
dw_pcie_dbi_ro_wr_en(pci);
|
||||
val = dw_pcie_readl_dbi(pci, PCI_INTERRUPT_LINE);
|
||||
val &= 0xffff00ff;
|
||||
val |= 0x00000100;
|
||||
dw_pcie_writel_dbi(pci, PCI_INTERRUPT_LINE, val);
|
||||
dw_pcie_dbi_ro_wr_dis(pci);
|
||||
|
||||
/* setup bus numbers */
|
||||
val = dw_pcie_readl_dbi(pci, PCI_PRIMARY_BUS);
|
||||
|
@ -634,8 +639,12 @@ void dw_pcie_setup_rc(struct pcie_port *pp)
|
|||
|
||||
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 */
|
||||
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);
|
||||
val |= PORT_LOGIC_SPEED_CHANGE;
|
||||
|
|
|
@ -35,7 +35,7 @@ static irqreturn_t dw_plat_pcie_msi_irq_handler(int irq, void *arg)
|
|||
return dw_handle_msi_irq(pp);
|
||||
}
|
||||
|
||||
static void dw_plat_pcie_host_init(struct pcie_port *pp)
|
||||
static int dw_plat_pcie_host_init(struct pcie_port *pp)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
|
||||
|
@ -44,6 +44,8 @@ static void dw_plat_pcie_host_init(struct pcie_port *pp)
|
|||
|
||||
if (IS_ENABLED(CONFIG_PCI_MSI))
|
||||
dw_pcie_msi_init(pp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dw_pcie_host_ops dw_plat_pcie_host_ops = {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Synopsys Designware PCIe host controller driver
|
||||
* Synopsys DesignWare PCIe host controller driver
|
||||
*
|
||||
* Copyright (C) 2013 Samsung Electronics Co., Ltd.
|
||||
* http://www.samsung.com
|
||||
|
@ -107,8 +107,9 @@ static void dw_pcie_writel_ob_unroll(struct dw_pcie *pci, u32 index, u32 reg,
|
|||
dw_pcie_writel_dbi(pci, offset + reg, val);
|
||||
}
|
||||
|
||||
void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, int index, int type,
|
||||
u64 cpu_addr, u64 pci_addr, u32 size)
|
||||
static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, int index,
|
||||
int type, u64 cpu_addr,
|
||||
u64 pci_addr, u32 size)
|
||||
{
|
||||
u32 retries, val;
|
||||
|
||||
|
@ -177,7 +178,7 @@ void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index, int type,
|
|||
*/
|
||||
for (retries = 0; retries < LINK_WAIT_MAX_IATU_RETRIES; retries++) {
|
||||
val = dw_pcie_readl_dbi(pci, PCIE_ATU_CR2);
|
||||
if (val == PCIE_ATU_ENABLE)
|
||||
if (val & PCIE_ATU_ENABLE)
|
||||
return;
|
||||
|
||||
usleep_range(LINK_WAIT_IATU_MIN, LINK_WAIT_IATU_MAX);
|
||||
|
@ -200,8 +201,9 @@ static void dw_pcie_writel_ib_unroll(struct dw_pcie *pci, u32 index, u32 reg,
|
|||
dw_pcie_writel_dbi(pci, offset + reg, val);
|
||||
}
|
||||
|
||||
int dw_pcie_prog_inbound_atu_unroll(struct dw_pcie *pci, int index, int bar,
|
||||
u64 cpu_addr, enum dw_pcie_as_type as_type)
|
||||
static int dw_pcie_prog_inbound_atu_unroll(struct dw_pcie *pci, int index,
|
||||
int bar, u64 cpu_addr,
|
||||
enum dw_pcie_as_type as_type)
|
||||
{
|
||||
int type;
|
||||
u32 retries, val;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Synopsys Designware PCIe host controller driver
|
||||
* Synopsys DesignWare PCIe host controller driver
|
||||
*
|
||||
* Copyright (C) 2013 Samsung Electronics Co., Ltd.
|
||||
* http://www.samsung.com
|
||||
|
@ -76,6 +76,9 @@
|
|||
#define PCIE_ATU_FUNC(x) (((x) & 0x7) << 16)
|
||||
#define PCIE_ATU_UPPER_TARGET 0x91C
|
||||
|
||||
#define PCIE_MISC_CONTROL_1_OFF 0x8BC
|
||||
#define PCIE_DBI_RO_WR_EN (0x1 << 0)
|
||||
|
||||
/*
|
||||
* iATU Unroll-specific register definitions
|
||||
* From 4.80 core version the address translation will be made by unroll
|
||||
|
@ -134,7 +137,7 @@ struct dw_pcie_host_ops {
|
|||
unsigned int devfn, int where, int size, u32 *val);
|
||||
int (*wr_other_conf)(struct pcie_port *pp, struct pci_bus *bus,
|
||||
unsigned int devfn, int where, int size, u32 val);
|
||||
void (*host_init)(struct pcie_port *pp);
|
||||
int (*host_init)(struct pcie_port *pp);
|
||||
void (*msi_set_irq)(struct pcie_port *pp, int irq);
|
||||
void (*msi_clear_irq)(struct pcie_port *pp, int irq);
|
||||
phys_addr_t (*get_msi_addr)(struct pcie_port *pp);
|
||||
|
@ -186,6 +189,7 @@ struct dw_pcie_ep {
|
|||
struct dw_pcie_ep_ops *ops;
|
||||
phys_addr_t phys_base;
|
||||
size_t addr_size;
|
||||
size_t page_size;
|
||||
u8 bar_to_atu[6];
|
||||
phys_addr_t *outbound_addr;
|
||||
unsigned long ib_window_map;
|
||||
|
@ -279,6 +283,28 @@ static inline u32 dw_pcie_readl_dbi2(struct dw_pcie *pci, u32 reg)
|
|||
return __dw_pcie_read_dbi(pci, pci->dbi_base2, reg, 0x4);
|
||||
}
|
||||
|
||||
static inline void dw_pcie_dbi_ro_wr_en(struct dw_pcie *pci)
|
||||
{
|
||||
u32 reg;
|
||||
u32 val;
|
||||
|
||||
reg = PCIE_MISC_CONTROL_1_OFF;
|
||||
val = dw_pcie_readl_dbi(pci, reg);
|
||||
val |= PCIE_DBI_RO_WR_EN;
|
||||
dw_pcie_writel_dbi(pci, reg, val);
|
||||
}
|
||||
|
||||
static inline void dw_pcie_dbi_ro_wr_dis(struct dw_pcie *pci)
|
||||
{
|
||||
u32 reg;
|
||||
u32 val;
|
||||
|
||||
reg = PCIE_MISC_CONTROL_1_OFF;
|
||||
val = dw_pcie_readl_dbi(pci, reg);
|
||||
val &= ~PCIE_DBI_RO_WR_EN;
|
||||
dw_pcie_writel_dbi(pci, reg, val);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PCIE_DW_HOST
|
||||
irqreturn_t dw_handle_msi_irq(struct pcie_port *pp);
|
||||
void dw_pcie_msi_init(struct pcie_port *pp);
|
||||
|
|
|
@ -223,7 +223,7 @@ static int hisi_pcie_link_up(struct dw_pcie *pci)
|
|||
return hisi_pcie->soc_ops->hisi_pcie_link_up(hisi_pcie);
|
||||
}
|
||||
|
||||
static struct dw_pcie_host_ops hisi_pcie_host_ops = {
|
||||
static const struct dw_pcie_host_ops hisi_pcie_host_ops = {
|
||||
.rd_own_conf = hisi_pcie_cfg_read,
|
||||
.wr_own_conf = hisi_pcie_cfg_write,
|
||||
};
|
||||
|
@ -268,7 +268,6 @@ static int hisi_pcie_probe(struct platform_device *pdev)
|
|||
struct dw_pcie *pci;
|
||||
struct hisi_pcie *hisi_pcie;
|
||||
struct resource *reg;
|
||||
struct device_driver *driver;
|
||||
int ret;
|
||||
|
||||
hisi_pcie = devm_kzalloc(dev, sizeof(*hisi_pcie), GFP_KERNEL);
|
||||
|
@ -282,8 +281,6 @@ static int hisi_pcie_probe(struct platform_device *pdev)
|
|||
pci->dev = dev;
|
||||
pci->ops = &dw_pcie_ops;
|
||||
|
||||
driver = dev->driver;
|
||||
|
||||
hisi_pcie->pci = pci;
|
||||
|
||||
hisi_pcie->soc_ops = of_device_get_match_data(dev);
|
||||
|
|
|
@ -430,9 +430,11 @@ static int kirin_pcie_establish_link(struct pcie_port *pp)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void kirin_pcie_host_init(struct pcie_port *pp)
|
||||
static int kirin_pcie_host_init(struct pcie_port *pp)
|
||||
{
|
||||
kirin_pcie_establish_link(pp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct dw_pcie_ops kirin_dw_pcie_ops = {
|
||||
|
@ -441,7 +443,7 @@ static struct dw_pcie_ops kirin_dw_pcie_ops = {
|
|||
.link_up = kirin_pcie_link_up,
|
||||
};
|
||||
|
||||
static struct dw_pcie_host_ops kirin_pcie_host_ops = {
|
||||
static const struct dw_pcie_host_ops kirin_pcie_host_ops = {
|
||||
.rd_own_conf = kirin_pcie_rd_own_conf,
|
||||
.wr_own_conf = kirin_pcie_wr_own_conf,
|
||||
.host_init = kirin_pcie_host_init,
|
||||
|
|
|
@ -37,6 +37,20 @@
|
|||
#include "pcie-designware.h"
|
||||
|
||||
#define PCIE20_PARF_SYS_CTRL 0x00
|
||||
#define MST_WAKEUP_EN BIT(13)
|
||||
#define SLV_WAKEUP_EN BIT(12)
|
||||
#define MSTR_ACLK_CGC_DIS BIT(10)
|
||||
#define SLV_ACLK_CGC_DIS BIT(9)
|
||||
#define CORE_CLK_CGC_DIS BIT(6)
|
||||
#define AUX_PWR_DET BIT(4)
|
||||
#define L23_CLK_RMV_DIS BIT(2)
|
||||
#define L1_CLK_RMV_DIS BIT(1)
|
||||
|
||||
#define PCIE20_COMMAND_STATUS 0x04
|
||||
#define CMD_BME_VAL 0x4
|
||||
#define PCIE20_DEVICE_CONTROL2_STATUS2 0x98
|
||||
#define PCIE_CAP_CPL_TIMEOUT_DISABLE 0x10
|
||||
|
||||
#define PCIE20_PARF_PHY_CTRL 0x40
|
||||
#define PCIE20_PARF_PHY_REFCLK 0x4C
|
||||
#define PCIE20_PARF_DBI_BASE_ADDR 0x168
|
||||
|
@ -58,10 +72,22 @@
|
|||
#define CFG_BRIDGE_SB_INIT BIT(0)
|
||||
|
||||
#define PCIE20_CAP 0x70
|
||||
#define PCIE20_CAP_LINK_CAPABILITIES (PCIE20_CAP + 0xC)
|
||||
#define PCIE20_CAP_ACTIVE_STATE_LINK_PM_SUPPORT (BIT(10) | BIT(11))
|
||||
#define PCIE20_CAP_LINK_1 (PCIE20_CAP + 0x14)
|
||||
#define PCIE_CAP_LINK1_VAL 0x2FD7F
|
||||
|
||||
#define PCIE20_PARF_Q2A_FLUSH 0x1AC
|
||||
|
||||
#define PCIE20_MISC_CONTROL_1_REG 0x8BC
|
||||
#define DBI_RO_WR_EN 1
|
||||
|
||||
#define PERST_DELAY_US 1000
|
||||
|
||||
struct qcom_pcie_resources_v0 {
|
||||
#define PCIE20_v3_PARF_SLV_ADDR_SPACE_SIZE 0x358
|
||||
#define SLV_ADDR_SPACE_SZ 0x10000000
|
||||
|
||||
struct qcom_pcie_resources_2_1_0 {
|
||||
struct clk *iface_clk;
|
||||
struct clk *core_clk;
|
||||
struct clk *phy_clk;
|
||||
|
@ -75,7 +101,7 @@ struct qcom_pcie_resources_v0 {
|
|||
struct regulator *vdda_refclk;
|
||||
};
|
||||
|
||||
struct qcom_pcie_resources_v1 {
|
||||
struct qcom_pcie_resources_1_0_0 {
|
||||
struct clk *iface;
|
||||
struct clk *aux;
|
||||
struct clk *master_bus;
|
||||
|
@ -84,7 +110,7 @@ struct qcom_pcie_resources_v1 {
|
|||
struct regulator *vdda;
|
||||
};
|
||||
|
||||
struct qcom_pcie_resources_v2 {
|
||||
struct qcom_pcie_resources_2_3_2 {
|
||||
struct clk *aux_clk;
|
||||
struct clk *master_clk;
|
||||
struct clk *slave_clk;
|
||||
|
@ -92,7 +118,7 @@ struct qcom_pcie_resources_v2 {
|
|||
struct clk *pipe_clk;
|
||||
};
|
||||
|
||||
struct qcom_pcie_resources_v3 {
|
||||
struct qcom_pcie_resources_2_4_0 {
|
||||
struct clk *aux_clk;
|
||||
struct clk *master_clk;
|
||||
struct clk *slave_clk;
|
||||
|
@ -110,11 +136,21 @@ struct qcom_pcie_resources_v3 {
|
|||
struct reset_control *phy_ahb_reset;
|
||||
};
|
||||
|
||||
struct qcom_pcie_resources_2_3_3 {
|
||||
struct clk *iface;
|
||||
struct clk *axi_m_clk;
|
||||
struct clk *axi_s_clk;
|
||||
struct clk *ahb_clk;
|
||||
struct clk *aux_clk;
|
||||
struct reset_control *rst[7];
|
||||
};
|
||||
|
||||
union qcom_pcie_resources {
|
||||
struct qcom_pcie_resources_v0 v0;
|
||||
struct qcom_pcie_resources_v1 v1;
|
||||
struct qcom_pcie_resources_v2 v2;
|
||||
struct qcom_pcie_resources_v3 v3;
|
||||
struct qcom_pcie_resources_1_0_0 v1_0_0;
|
||||
struct qcom_pcie_resources_2_1_0 v2_1_0;
|
||||
struct qcom_pcie_resources_2_3_2 v2_3_2;
|
||||
struct qcom_pcie_resources_2_3_3 v2_3_3;
|
||||
struct qcom_pcie_resources_2_4_0 v2_4_0;
|
||||
};
|
||||
|
||||
struct qcom_pcie;
|
||||
|
@ -124,6 +160,7 @@ struct qcom_pcie_ops {
|
|||
int (*init)(struct qcom_pcie *pcie);
|
||||
int (*post_init)(struct qcom_pcie *pcie);
|
||||
void (*deinit)(struct qcom_pcie *pcie);
|
||||
void (*post_deinit)(struct qcom_pcie *pcie);
|
||||
void (*ltssm_enable)(struct qcom_pcie *pcie);
|
||||
};
|
||||
|
||||
|
@ -141,13 +178,13 @@ struct qcom_pcie {
|
|||
|
||||
static void qcom_ep_reset_assert(struct qcom_pcie *pcie)
|
||||
{
|
||||
gpiod_set_value(pcie->reset, 1);
|
||||
gpiod_set_value_cansleep(pcie->reset, 1);
|
||||
usleep_range(PERST_DELAY_US, PERST_DELAY_US + 500);
|
||||
}
|
||||
|
||||
static void qcom_ep_reset_deassert(struct qcom_pcie *pcie)
|
||||
{
|
||||
gpiod_set_value(pcie->reset, 0);
|
||||
gpiod_set_value_cansleep(pcie->reset, 0);
|
||||
usleep_range(PERST_DELAY_US, PERST_DELAY_US + 500);
|
||||
}
|
||||
|
||||
|
@ -172,7 +209,7 @@ static int qcom_pcie_establish_link(struct qcom_pcie *pcie)
|
|||
return dw_pcie_wait_for_link(pci);
|
||||
}
|
||||
|
||||
static void qcom_pcie_v0_v1_ltssm_enable(struct qcom_pcie *pcie)
|
||||
static void qcom_pcie_2_1_0_ltssm_enable(struct qcom_pcie *pcie)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
|
@ -182,9 +219,9 @@ static void qcom_pcie_v0_v1_ltssm_enable(struct qcom_pcie *pcie)
|
|||
writel(val, pcie->elbi + PCIE20_ELBI_SYS_CTRL);
|
||||
}
|
||||
|
||||
static int qcom_pcie_get_resources_v0(struct qcom_pcie *pcie)
|
||||
static int qcom_pcie_get_resources_2_1_0(struct qcom_pcie *pcie)
|
||||
{
|
||||
struct qcom_pcie_resources_v0 *res = &pcie->res.v0;
|
||||
struct qcom_pcie_resources_2_1_0 *res = &pcie->res.v2_1_0;
|
||||
struct dw_pcie *pci = pcie->pci;
|
||||
struct device *dev = pci->dev;
|
||||
|
||||
|
@ -212,29 +249,29 @@ static int qcom_pcie_get_resources_v0(struct qcom_pcie *pcie)
|
|||
if (IS_ERR(res->phy_clk))
|
||||
return PTR_ERR(res->phy_clk);
|
||||
|
||||
res->pci_reset = devm_reset_control_get(dev, "pci");
|
||||
res->pci_reset = devm_reset_control_get_exclusive(dev, "pci");
|
||||
if (IS_ERR(res->pci_reset))
|
||||
return PTR_ERR(res->pci_reset);
|
||||
|
||||
res->axi_reset = devm_reset_control_get(dev, "axi");
|
||||
res->axi_reset = devm_reset_control_get_exclusive(dev, "axi");
|
||||
if (IS_ERR(res->axi_reset))
|
||||
return PTR_ERR(res->axi_reset);
|
||||
|
||||
res->ahb_reset = devm_reset_control_get(dev, "ahb");
|
||||
res->ahb_reset = devm_reset_control_get_exclusive(dev, "ahb");
|
||||
if (IS_ERR(res->ahb_reset))
|
||||
return PTR_ERR(res->ahb_reset);
|
||||
|
||||
res->por_reset = devm_reset_control_get(dev, "por");
|
||||
res->por_reset = devm_reset_control_get_exclusive(dev, "por");
|
||||
if (IS_ERR(res->por_reset))
|
||||
return PTR_ERR(res->por_reset);
|
||||
|
||||
res->phy_reset = devm_reset_control_get(dev, "phy");
|
||||
res->phy_reset = devm_reset_control_get_exclusive(dev, "phy");
|
||||
return PTR_ERR_OR_ZERO(res->phy_reset);
|
||||
}
|
||||
|
||||
static void qcom_pcie_deinit_v0(struct qcom_pcie *pcie)
|
||||
static void qcom_pcie_deinit_2_1_0(struct qcom_pcie *pcie)
|
||||
{
|
||||
struct qcom_pcie_resources_v0 *res = &pcie->res.v0;
|
||||
struct qcom_pcie_resources_2_1_0 *res = &pcie->res.v2_1_0;
|
||||
|
||||
reset_control_assert(res->pci_reset);
|
||||
reset_control_assert(res->axi_reset);
|
||||
|
@ -249,9 +286,9 @@ static void qcom_pcie_deinit_v0(struct qcom_pcie *pcie)
|
|||
regulator_disable(res->vdda_refclk);
|
||||
}
|
||||
|
||||
static int qcom_pcie_init_v0(struct qcom_pcie *pcie)
|
||||
static int qcom_pcie_init_2_1_0(struct qcom_pcie *pcie)
|
||||
{
|
||||
struct qcom_pcie_resources_v0 *res = &pcie->res.v0;
|
||||
struct qcom_pcie_resources_2_1_0 *res = &pcie->res.v2_1_0;
|
||||
struct dw_pcie *pci = pcie->pci;
|
||||
struct device *dev = pci->dev;
|
||||
u32 val;
|
||||
|
@ -367,9 +404,9 @@ err_refclk:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int qcom_pcie_get_resources_v1(struct qcom_pcie *pcie)
|
||||
static int qcom_pcie_get_resources_1_0_0(struct qcom_pcie *pcie)
|
||||
{
|
||||
struct qcom_pcie_resources_v1 *res = &pcie->res.v1;
|
||||
struct qcom_pcie_resources_1_0_0 *res = &pcie->res.v1_0_0;
|
||||
struct dw_pcie *pci = pcie->pci;
|
||||
struct device *dev = pci->dev;
|
||||
|
||||
|
@ -393,13 +430,13 @@ static int qcom_pcie_get_resources_v1(struct qcom_pcie *pcie)
|
|||
if (IS_ERR(res->slave_bus))
|
||||
return PTR_ERR(res->slave_bus);
|
||||
|
||||
res->core = devm_reset_control_get(dev, "core");
|
||||
res->core = devm_reset_control_get_exclusive(dev, "core");
|
||||
return PTR_ERR_OR_ZERO(res->core);
|
||||
}
|
||||
|
||||
static void qcom_pcie_deinit_v1(struct qcom_pcie *pcie)
|
||||
static void qcom_pcie_deinit_1_0_0(struct qcom_pcie *pcie)
|
||||
{
|
||||
struct qcom_pcie_resources_v1 *res = &pcie->res.v1;
|
||||
struct qcom_pcie_resources_1_0_0 *res = &pcie->res.v1_0_0;
|
||||
|
||||
reset_control_assert(res->core);
|
||||
clk_disable_unprepare(res->slave_bus);
|
||||
|
@ -409,9 +446,9 @@ static void qcom_pcie_deinit_v1(struct qcom_pcie *pcie)
|
|||
regulator_disable(res->vdda);
|
||||
}
|
||||
|
||||
static int qcom_pcie_init_v1(struct qcom_pcie *pcie)
|
||||
static int qcom_pcie_init_1_0_0(struct qcom_pcie *pcie)
|
||||
{
|
||||
struct qcom_pcie_resources_v1 *res = &pcie->res.v1;
|
||||
struct qcom_pcie_resources_1_0_0 *res = &pcie->res.v1_0_0;
|
||||
struct dw_pcie *pci = pcie->pci;
|
||||
struct device *dev = pci->dev;
|
||||
int ret;
|
||||
|
@ -477,7 +514,7 @@ err_res:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void qcom_pcie_v2_ltssm_enable(struct qcom_pcie *pcie)
|
||||
static void qcom_pcie_2_3_2_ltssm_enable(struct qcom_pcie *pcie)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
|
@ -487,9 +524,9 @@ static void qcom_pcie_v2_ltssm_enable(struct qcom_pcie *pcie)
|
|||
writel(val, pcie->parf + PCIE20_PARF_LTSSM);
|
||||
}
|
||||
|
||||
static int qcom_pcie_get_resources_v2(struct qcom_pcie *pcie)
|
||||
static int qcom_pcie_get_resources_2_3_2(struct qcom_pcie *pcie)
|
||||
{
|
||||
struct qcom_pcie_resources_v2 *res = &pcie->res.v2;
|
||||
struct qcom_pcie_resources_2_3_2 *res = &pcie->res.v2_3_2;
|
||||
struct dw_pcie *pci = pcie->pci;
|
||||
struct device *dev = pci->dev;
|
||||
|
||||
|
@ -513,20 +550,26 @@ static int qcom_pcie_get_resources_v2(struct qcom_pcie *pcie)
|
|||
return PTR_ERR_OR_ZERO(res->pipe_clk);
|
||||
}
|
||||
|
||||
static void qcom_pcie_deinit_v2(struct qcom_pcie *pcie)
|
||||
static void qcom_pcie_deinit_2_3_2(struct qcom_pcie *pcie)
|
||||
{
|
||||
struct qcom_pcie_resources_v2 *res = &pcie->res.v2;
|
||||
struct qcom_pcie_resources_2_3_2 *res = &pcie->res.v2_3_2;
|
||||
|
||||
clk_disable_unprepare(res->pipe_clk);
|
||||
clk_disable_unprepare(res->slave_clk);
|
||||
clk_disable_unprepare(res->master_clk);
|
||||
clk_disable_unprepare(res->cfg_clk);
|
||||
clk_disable_unprepare(res->aux_clk);
|
||||
}
|
||||
|
||||
static int qcom_pcie_init_v2(struct qcom_pcie *pcie)
|
||||
static void qcom_pcie_post_deinit_2_3_2(struct qcom_pcie *pcie)
|
||||
{
|
||||
struct qcom_pcie_resources_v2 *res = &pcie->res.v2;
|
||||
struct qcom_pcie_resources_2_3_2 *res = &pcie->res.v2_3_2;
|
||||
|
||||
clk_disable_unprepare(res->pipe_clk);
|
||||
}
|
||||
|
||||
static int qcom_pcie_init_2_3_2(struct qcom_pcie *pcie)
|
||||
{
|
||||
struct qcom_pcie_resources_2_3_2 *res = &pcie->res.v2_3_2;
|
||||
struct dw_pcie *pci = pcie->pci;
|
||||
struct device *dev = pci->dev;
|
||||
u32 val;
|
||||
|
@ -589,9 +632,9 @@ err_cfg_clk:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int qcom_pcie_post_init_v2(struct qcom_pcie *pcie)
|
||||
static int qcom_pcie_post_init_2_3_2(struct qcom_pcie *pcie)
|
||||
{
|
||||
struct qcom_pcie_resources_v2 *res = &pcie->res.v2;
|
||||
struct qcom_pcie_resources_2_3_2 *res = &pcie->res.v2_3_2;
|
||||
struct dw_pcie *pci = pcie->pci;
|
||||
struct device *dev = pci->dev;
|
||||
int ret;
|
||||
|
@ -605,9 +648,9 @@ static int qcom_pcie_post_init_v2(struct qcom_pcie *pcie)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int qcom_pcie_get_resources_v3(struct qcom_pcie *pcie)
|
||||
static int qcom_pcie_get_resources_2_4_0(struct qcom_pcie *pcie)
|
||||
{
|
||||
struct qcom_pcie_resources_v3 *res = &pcie->res.v3;
|
||||
struct qcom_pcie_resources_2_4_0 *res = &pcie->res.v2_4_0;
|
||||
struct dw_pcie *pci = pcie->pci;
|
||||
struct device *dev = pci->dev;
|
||||
|
||||
|
@ -623,60 +666,64 @@ static int qcom_pcie_get_resources_v3(struct qcom_pcie *pcie)
|
|||
if (IS_ERR(res->slave_clk))
|
||||
return PTR_ERR(res->slave_clk);
|
||||
|
||||
res->axi_m_reset = devm_reset_control_get(dev, "axi_m");
|
||||
res->axi_m_reset = devm_reset_control_get_exclusive(dev, "axi_m");
|
||||
if (IS_ERR(res->axi_m_reset))
|
||||
return PTR_ERR(res->axi_m_reset);
|
||||
|
||||
res->axi_s_reset = devm_reset_control_get(dev, "axi_s");
|
||||
res->axi_s_reset = devm_reset_control_get_exclusive(dev, "axi_s");
|
||||
if (IS_ERR(res->axi_s_reset))
|
||||
return PTR_ERR(res->axi_s_reset);
|
||||
|
||||
res->pipe_reset = devm_reset_control_get(dev, "pipe");
|
||||
res->pipe_reset = devm_reset_control_get_exclusive(dev, "pipe");
|
||||
if (IS_ERR(res->pipe_reset))
|
||||
return PTR_ERR(res->pipe_reset);
|
||||
|
||||
res->axi_m_vmid_reset = devm_reset_control_get(dev, "axi_m_vmid");
|
||||
res->axi_m_vmid_reset = devm_reset_control_get_exclusive(dev,
|
||||
"axi_m_vmid");
|
||||
if (IS_ERR(res->axi_m_vmid_reset))
|
||||
return PTR_ERR(res->axi_m_vmid_reset);
|
||||
|
||||
res->axi_s_xpu_reset = devm_reset_control_get(dev, "axi_s_xpu");
|
||||
res->axi_s_xpu_reset = devm_reset_control_get_exclusive(dev,
|
||||
"axi_s_xpu");
|
||||
if (IS_ERR(res->axi_s_xpu_reset))
|
||||
return PTR_ERR(res->axi_s_xpu_reset);
|
||||
|
||||
res->parf_reset = devm_reset_control_get(dev, "parf");
|
||||
res->parf_reset = devm_reset_control_get_exclusive(dev, "parf");
|
||||
if (IS_ERR(res->parf_reset))
|
||||
return PTR_ERR(res->parf_reset);
|
||||
|
||||
res->phy_reset = devm_reset_control_get(dev, "phy");
|
||||
res->phy_reset = devm_reset_control_get_exclusive(dev, "phy");
|
||||
if (IS_ERR(res->phy_reset))
|
||||
return PTR_ERR(res->phy_reset);
|
||||
|
||||
res->axi_m_sticky_reset = devm_reset_control_get(dev, "axi_m_sticky");
|
||||
res->axi_m_sticky_reset = devm_reset_control_get_exclusive(dev,
|
||||
"axi_m_sticky");
|
||||
if (IS_ERR(res->axi_m_sticky_reset))
|
||||
return PTR_ERR(res->axi_m_sticky_reset);
|
||||
|
||||
res->pipe_sticky_reset = devm_reset_control_get(dev, "pipe_sticky");
|
||||
res->pipe_sticky_reset = devm_reset_control_get_exclusive(dev,
|
||||
"pipe_sticky");
|
||||
if (IS_ERR(res->pipe_sticky_reset))
|
||||
return PTR_ERR(res->pipe_sticky_reset);
|
||||
|
||||
res->pwr_reset = devm_reset_control_get(dev, "pwr");
|
||||
res->pwr_reset = devm_reset_control_get_exclusive(dev, "pwr");
|
||||
if (IS_ERR(res->pwr_reset))
|
||||
return PTR_ERR(res->pwr_reset);
|
||||
|
||||
res->ahb_reset = devm_reset_control_get(dev, "ahb");
|
||||
res->ahb_reset = devm_reset_control_get_exclusive(dev, "ahb");
|
||||
if (IS_ERR(res->ahb_reset))
|
||||
return PTR_ERR(res->ahb_reset);
|
||||
|
||||
res->phy_ahb_reset = devm_reset_control_get(dev, "phy_ahb");
|
||||
res->phy_ahb_reset = devm_reset_control_get_exclusive(dev, "phy_ahb");
|
||||
if (IS_ERR(res->phy_ahb_reset))
|
||||
return PTR_ERR(res->phy_ahb_reset);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void qcom_pcie_deinit_v3(struct qcom_pcie *pcie)
|
||||
static void qcom_pcie_deinit_2_4_0(struct qcom_pcie *pcie)
|
||||
{
|
||||
struct qcom_pcie_resources_v3 *res = &pcie->res.v3;
|
||||
struct qcom_pcie_resources_2_4_0 *res = &pcie->res.v2_4_0;
|
||||
|
||||
reset_control_assert(res->axi_m_reset);
|
||||
reset_control_assert(res->axi_s_reset);
|
||||
|
@ -692,9 +739,9 @@ static void qcom_pcie_deinit_v3(struct qcom_pcie *pcie)
|
|||
clk_disable_unprepare(res->slave_clk);
|
||||
}
|
||||
|
||||
static int qcom_pcie_init_v3(struct qcom_pcie *pcie)
|
||||
static int qcom_pcie_init_2_4_0(struct qcom_pcie *pcie)
|
||||
{
|
||||
struct qcom_pcie_resources_v3 *res = &pcie->res.v3;
|
||||
struct qcom_pcie_resources_2_4_0 *res = &pcie->res.v2_4_0;
|
||||
struct dw_pcie *pci = pcie->pci;
|
||||
struct device *dev = pci->dev;
|
||||
u32 val;
|
||||
|
@ -884,6 +931,166 @@ err_rst_phy:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int qcom_pcie_get_resources_2_3_3(struct qcom_pcie *pcie)
|
||||
{
|
||||
struct qcom_pcie_resources_2_3_3 *res = &pcie->res.v2_3_3;
|
||||
struct dw_pcie *pci = pcie->pci;
|
||||
struct device *dev = pci->dev;
|
||||
int i;
|
||||
const char *rst_names[] = { "axi_m", "axi_s", "pipe",
|
||||
"axi_m_sticky", "sticky",
|
||||
"ahb", "sleep", };
|
||||
|
||||
res->iface = devm_clk_get(dev, "iface");
|
||||
if (IS_ERR(res->iface))
|
||||
return PTR_ERR(res->iface);
|
||||
|
||||
res->axi_m_clk = devm_clk_get(dev, "axi_m");
|
||||
if (IS_ERR(res->axi_m_clk))
|
||||
return PTR_ERR(res->axi_m_clk);
|
||||
|
||||
res->axi_s_clk = devm_clk_get(dev, "axi_s");
|
||||
if (IS_ERR(res->axi_s_clk))
|
||||
return PTR_ERR(res->axi_s_clk);
|
||||
|
||||
res->ahb_clk = devm_clk_get(dev, "ahb");
|
||||
if (IS_ERR(res->ahb_clk))
|
||||
return PTR_ERR(res->ahb_clk);
|
||||
|
||||
res->aux_clk = devm_clk_get(dev, "aux");
|
||||
if (IS_ERR(res->aux_clk))
|
||||
return PTR_ERR(res->aux_clk);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(rst_names); i++) {
|
||||
res->rst[i] = devm_reset_control_get(dev, rst_names[i]);
|
||||
if (IS_ERR(res->rst[i]))
|
||||
return PTR_ERR(res->rst[i]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void qcom_pcie_deinit_2_3_3(struct qcom_pcie *pcie)
|
||||
{
|
||||
struct qcom_pcie_resources_2_3_3 *res = &pcie->res.v2_3_3;
|
||||
|
||||
clk_disable_unprepare(res->iface);
|
||||
clk_disable_unprepare(res->axi_m_clk);
|
||||
clk_disable_unprepare(res->axi_s_clk);
|
||||
clk_disable_unprepare(res->ahb_clk);
|
||||
clk_disable_unprepare(res->aux_clk);
|
||||
}
|
||||
|
||||
static int qcom_pcie_init_2_3_3(struct qcom_pcie *pcie)
|
||||
{
|
||||
struct qcom_pcie_resources_2_3_3 *res = &pcie->res.v2_3_3;
|
||||
struct dw_pcie *pci = pcie->pci;
|
||||
struct device *dev = pci->dev;
|
||||
int i, ret;
|
||||
u32 val;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(res->rst); i++) {
|
||||
ret = reset_control_assert(res->rst[i]);
|
||||
if (ret) {
|
||||
dev_err(dev, "reset #%d assert failed (%d)\n", i, ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
usleep_range(2000, 2500);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(res->rst); i++) {
|
||||
ret = reset_control_deassert(res->rst[i]);
|
||||
if (ret) {
|
||||
dev_err(dev, "reset #%d deassert failed (%d)\n", i,
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Don't have a way to see if the reset has completed.
|
||||
* Wait for some time.
|
||||
*/
|
||||
usleep_range(2000, 2500);
|
||||
|
||||
ret = clk_prepare_enable(res->iface);
|
||||
if (ret) {
|
||||
dev_err(dev, "cannot prepare/enable core clock\n");
|
||||
goto err_clk_iface;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(res->axi_m_clk);
|
||||
if (ret) {
|
||||
dev_err(dev, "cannot prepare/enable core clock\n");
|
||||
goto err_clk_axi_m;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(res->axi_s_clk);
|
||||
if (ret) {
|
||||
dev_err(dev, "cannot prepare/enable axi slave clock\n");
|
||||
goto err_clk_axi_s;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(res->ahb_clk);
|
||||
if (ret) {
|
||||
dev_err(dev, "cannot prepare/enable ahb clock\n");
|
||||
goto err_clk_ahb;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(res->aux_clk);
|
||||
if (ret) {
|
||||
dev_err(dev, "cannot prepare/enable aux clock\n");
|
||||
goto err_clk_aux;
|
||||
}
|
||||
|
||||
writel(SLV_ADDR_SPACE_SZ,
|
||||
pcie->parf + PCIE20_v3_PARF_SLV_ADDR_SPACE_SIZE);
|
||||
|
||||
val = readl(pcie->parf + PCIE20_PARF_PHY_CTRL);
|
||||
val &= ~BIT(0);
|
||||
writel(val, pcie->parf + PCIE20_PARF_PHY_CTRL);
|
||||
|
||||
writel(0, pcie->parf + PCIE20_PARF_DBI_BASE_ADDR);
|
||||
|
||||
writel(MST_WAKEUP_EN | SLV_WAKEUP_EN | MSTR_ACLK_CGC_DIS
|
||||
| SLV_ACLK_CGC_DIS | CORE_CLK_CGC_DIS |
|
||||
AUX_PWR_DET | L23_CLK_RMV_DIS | L1_CLK_RMV_DIS,
|
||||
pcie->parf + PCIE20_PARF_SYS_CTRL);
|
||||
writel(0, pcie->parf + PCIE20_PARF_Q2A_FLUSH);
|
||||
|
||||
writel(CMD_BME_VAL, pci->dbi_base + PCIE20_COMMAND_STATUS);
|
||||
writel(DBI_RO_WR_EN, pci->dbi_base + PCIE20_MISC_CONTROL_1_REG);
|
||||
writel(PCIE_CAP_LINK1_VAL, pci->dbi_base + PCIE20_CAP_LINK_1);
|
||||
|
||||
val = readl(pci->dbi_base + PCIE20_CAP_LINK_CAPABILITIES);
|
||||
val &= ~PCIE20_CAP_ACTIVE_STATE_LINK_PM_SUPPORT;
|
||||
writel(val, pci->dbi_base + PCIE20_CAP_LINK_CAPABILITIES);
|
||||
|
||||
writel(PCIE_CAP_CPL_TIMEOUT_DISABLE, pci->dbi_base +
|
||||
PCIE20_DEVICE_CONTROL2_STATUS2);
|
||||
|
||||
return 0;
|
||||
|
||||
err_clk_aux:
|
||||
clk_disable_unprepare(res->ahb_clk);
|
||||
err_clk_ahb:
|
||||
clk_disable_unprepare(res->axi_s_clk);
|
||||
err_clk_axi_s:
|
||||
clk_disable_unprepare(res->axi_m_clk);
|
||||
err_clk_axi_m:
|
||||
clk_disable_unprepare(res->iface);
|
||||
err_clk_iface:
|
||||
/*
|
||||
* Not checking for failure, will anyway return
|
||||
* the original failure in 'ret'.
|
||||
*/
|
||||
for (i = 0; i < ARRAY_SIZE(res->rst); i++)
|
||||
reset_control_assert(res->rst[i]);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int qcom_pcie_link_up(struct dw_pcie *pci)
|
||||
{
|
||||
u16 val = readw(pci->dbi_base + PCIE20_CAP + PCI_EXP_LNKSTA);
|
||||
|
@ -891,7 +1098,7 @@ static int qcom_pcie_link_up(struct dw_pcie *pci)
|
|||
return !!(val & PCI_EXP_LNKSTA_DLLLA);
|
||||
}
|
||||
|
||||
static void 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 qcom_pcie *pcie = to_qcom_pcie(pci);
|
||||
|
@ -901,14 +1108,17 @@ static void qcom_pcie_host_init(struct pcie_port *pp)
|
|||
|
||||
ret = pcie->ops->init(pcie);
|
||||
if (ret)
|
||||
goto err_deinit;
|
||||
return ret;
|
||||
|
||||
ret = phy_power_on(pcie->phy);
|
||||
if (ret)
|
||||
goto err_deinit;
|
||||
|
||||
if (pcie->ops->post_init)
|
||||
pcie->ops->post_init(pcie);
|
||||
if (pcie->ops->post_init) {
|
||||
ret = pcie->ops->post_init(pcie);
|
||||
if (ret)
|
||||
goto err_disable_phy;
|
||||
}
|
||||
|
||||
dw_pcie_setup_rc(pp);
|
||||
|
||||
|
@ -921,12 +1131,17 @@ static void qcom_pcie_host_init(struct pcie_port *pp)
|
|||
if (ret)
|
||||
goto err;
|
||||
|
||||
return;
|
||||
return 0;
|
||||
err:
|
||||
qcom_ep_reset_assert(pcie);
|
||||
if (pcie->ops->post_deinit)
|
||||
pcie->ops->post_deinit(pcie);
|
||||
err_disable_phy:
|
||||
phy_power_off(pcie->phy);
|
||||
err_deinit:
|
||||
pcie->ops->deinit(pcie);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int qcom_pcie_rd_own_conf(struct pcie_port *pp, int where, int size,
|
||||
|
@ -950,39 +1165,52 @@ static const struct dw_pcie_host_ops qcom_pcie_dw_ops = {
|
|||
.rd_own_conf = qcom_pcie_rd_own_conf,
|
||||
};
|
||||
|
||||
static const struct qcom_pcie_ops ops_v0 = {
|
||||
.get_resources = qcom_pcie_get_resources_v0,
|
||||
.init = qcom_pcie_init_v0,
|
||||
.deinit = qcom_pcie_deinit_v0,
|
||||
.ltssm_enable = qcom_pcie_v0_v1_ltssm_enable,
|
||||
/* Qcom IP rev.: 2.1.0 Synopsys IP rev.: 4.01a */
|
||||
static const struct qcom_pcie_ops ops_2_1_0 = {
|
||||
.get_resources = qcom_pcie_get_resources_2_1_0,
|
||||
.init = qcom_pcie_init_2_1_0,
|
||||
.deinit = qcom_pcie_deinit_2_1_0,
|
||||
.ltssm_enable = qcom_pcie_2_1_0_ltssm_enable,
|
||||
};
|
||||
|
||||
static const struct qcom_pcie_ops ops_v1 = {
|
||||
.get_resources = qcom_pcie_get_resources_v1,
|
||||
.init = qcom_pcie_init_v1,
|
||||
.deinit = qcom_pcie_deinit_v1,
|
||||
.ltssm_enable = qcom_pcie_v0_v1_ltssm_enable,
|
||||
/* Qcom IP rev.: 1.0.0 Synopsys IP rev.: 4.11a */
|
||||
static const struct qcom_pcie_ops ops_1_0_0 = {
|
||||
.get_resources = qcom_pcie_get_resources_1_0_0,
|
||||
.init = qcom_pcie_init_1_0_0,
|
||||
.deinit = qcom_pcie_deinit_1_0_0,
|
||||
.ltssm_enable = qcom_pcie_2_1_0_ltssm_enable,
|
||||
};
|
||||
|
||||
static const struct qcom_pcie_ops ops_v2 = {
|
||||
.get_resources = qcom_pcie_get_resources_v2,
|
||||
.init = qcom_pcie_init_v2,
|
||||
.post_init = qcom_pcie_post_init_v2,
|
||||
.deinit = qcom_pcie_deinit_v2,
|
||||
.ltssm_enable = qcom_pcie_v2_ltssm_enable,
|
||||
/* Qcom IP rev.: 2.3.2 Synopsys IP rev.: 4.21a */
|
||||
static const struct qcom_pcie_ops ops_2_3_2 = {
|
||||
.get_resources = qcom_pcie_get_resources_2_3_2,
|
||||
.init = qcom_pcie_init_2_3_2,
|
||||
.post_init = qcom_pcie_post_init_2_3_2,
|
||||
.deinit = qcom_pcie_deinit_2_3_2,
|
||||
.post_deinit = qcom_pcie_post_deinit_2_3_2,
|
||||
.ltssm_enable = qcom_pcie_2_3_2_ltssm_enable,
|
||||
};
|
||||
|
||||
/* Qcom IP rev.: 2.4.0 Synopsys IP rev.: 4.20a */
|
||||
static const struct qcom_pcie_ops ops_2_4_0 = {
|
||||
.get_resources = qcom_pcie_get_resources_2_4_0,
|
||||
.init = qcom_pcie_init_2_4_0,
|
||||
.deinit = qcom_pcie_deinit_2_4_0,
|
||||
.ltssm_enable = qcom_pcie_2_3_2_ltssm_enable,
|
||||
};
|
||||
|
||||
/* Qcom IP rev.: 2.3.3 Synopsys IP rev.: 4.30a */
|
||||
static const struct qcom_pcie_ops ops_2_3_3 = {
|
||||
.get_resources = qcom_pcie_get_resources_2_3_3,
|
||||
.init = qcom_pcie_init_2_3_3,
|
||||
.deinit = qcom_pcie_deinit_2_3_3,
|
||||
.ltssm_enable = qcom_pcie_2_3_2_ltssm_enable,
|
||||
};
|
||||
|
||||
static const struct dw_pcie_ops dw_pcie_ops = {
|
||||
.link_up = qcom_pcie_link_up,
|
||||
};
|
||||
|
||||
static const struct qcom_pcie_ops ops_v3 = {
|
||||
.get_resources = qcom_pcie_get_resources_v3,
|
||||
.init = qcom_pcie_init_v3,
|
||||
.deinit = qcom_pcie_deinit_v3,
|
||||
.ltssm_enable = qcom_pcie_v2_ltssm_enable,
|
||||
};
|
||||
|
||||
static int qcom_pcie_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
|
@ -1069,11 +1297,12 @@ static int qcom_pcie_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
static const struct of_device_id qcom_pcie_match[] = {
|
||||
{ .compatible = "qcom,pcie-ipq8064", .data = &ops_v0 },
|
||||
{ .compatible = "qcom,pcie-apq8064", .data = &ops_v0 },
|
||||
{ .compatible = "qcom,pcie-apq8084", .data = &ops_v1 },
|
||||
{ .compatible = "qcom,pcie-msm8996", .data = &ops_v2 },
|
||||
{ .compatible = "qcom,pcie-ipq4019", .data = &ops_v3 },
|
||||
{ .compatible = "qcom,pcie-apq8084", .data = &ops_1_0_0 },
|
||||
{ .compatible = "qcom,pcie-ipq8064", .data = &ops_2_1_0 },
|
||||
{ .compatible = "qcom,pcie-apq8064", .data = &ops_2_1_0 },
|
||||
{ .compatible = "qcom,pcie-msm8996", .data = &ops_2_3_2 },
|
||||
{ .compatible = "qcom,pcie-ipq8074", .data = &ops_2_3_3 },
|
||||
{ .compatible = "qcom,pcie-ipq4019", .data = &ops_2_4_0 },
|
||||
{ }
|
||||
};
|
||||
|
||||
|
|
|
@ -177,13 +177,15 @@ static int spear13xx_pcie_link_up(struct dw_pcie *pci)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void spear13xx_pcie_host_init(struct pcie_port *pp)
|
||||
static int spear13xx_pcie_host_init(struct pcie_port *pp)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
struct spear13xx_pcie *spear13xx_pcie = to_spear13xx_pcie(pci);
|
||||
|
||||
spear13xx_pcie_establish_link(spear13xx_pcie);
|
||||
spear13xx_pcie_enable_interrupts(spear13xx_pcie);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dw_pcie_host_ops spear13xx_pcie_host_ops = {
|
||||
|
@ -199,9 +201,9 @@ static int spear13xx_add_pcie_port(struct spear13xx_pcie *spear13xx_pcie,
|
|||
int ret;
|
||||
|
||||
pp->irq = platform_get_irq(pdev, 0);
|
||||
if (!pp->irq) {
|
||||
if (pp->irq < 0) {
|
||||
dev_err(dev, "failed to get irq\n");
|
||||
return -ENODEV;
|
||||
return pp->irq;
|
||||
}
|
||||
ret = devm_request_irq(dev, pp->irq, spear13xx_pcie_irq_handler,
|
||||
IRQF_SHARED | IRQF_NO_THREAD,
|
||||
|
|
|
@ -54,6 +54,8 @@ static struct workqueue_struct *kpcitest_workqueue;
|
|||
struct pci_epf_test {
|
||||
void *reg[6];
|
||||
struct pci_epf *epf;
|
||||
enum pci_barno test_reg_bar;
|
||||
bool linkup_notifier;
|
||||
struct delayed_work cmd_handler;
|
||||
};
|
||||
|
||||
|
@ -74,7 +76,12 @@ static struct pci_epf_header test_header = {
|
|||
.interrupt_pin = PCI_INTERRUPT_INTA,
|
||||
};
|
||||
|
||||
static int bar_size[] = { 512, 1024, 16384, 131072, 1048576 };
|
||||
struct pci_epf_test_data {
|
||||
enum pci_barno test_reg_bar;
|
||||
bool linkup_notifier;
|
||||
};
|
||||
|
||||
static int bar_size[] = { 512, 512, 1024, 16384, 131072, 1048576 };
|
||||
|
||||
static int pci_epf_test_copy(struct pci_epf_test *epf_test)
|
||||
{
|
||||
|
@ -86,7 +93,8 @@ static int pci_epf_test_copy(struct pci_epf_test *epf_test)
|
|||
struct pci_epf *epf = epf_test->epf;
|
||||
struct device *dev = &epf->dev;
|
||||
struct pci_epc *epc = epf->epc;
|
||||
struct pci_epf_test_reg *reg = epf_test->reg[0];
|
||||
enum pci_barno test_reg_bar = epf_test->test_reg_bar;
|
||||
struct pci_epf_test_reg *reg = epf_test->reg[test_reg_bar];
|
||||
|
||||
src_addr = pci_epc_mem_alloc_addr(epc, &src_phys_addr, reg->size);
|
||||
if (!src_addr) {
|
||||
|
@ -145,7 +153,8 @@ static int pci_epf_test_read(struct pci_epf_test *epf_test)
|
|||
struct pci_epf *epf = epf_test->epf;
|
||||
struct device *dev = &epf->dev;
|
||||
struct pci_epc *epc = epf->epc;
|
||||
struct pci_epf_test_reg *reg = epf_test->reg[0];
|
||||
enum pci_barno test_reg_bar = epf_test->test_reg_bar;
|
||||
struct pci_epf_test_reg *reg = epf_test->reg[test_reg_bar];
|
||||
|
||||
src_addr = pci_epc_mem_alloc_addr(epc, &phys_addr, reg->size);
|
||||
if (!src_addr) {
|
||||
|
@ -195,7 +204,8 @@ static int pci_epf_test_write(struct pci_epf_test *epf_test)
|
|||
struct pci_epf *epf = epf_test->epf;
|
||||
struct device *dev = &epf->dev;
|
||||
struct pci_epc *epc = epf->epc;
|
||||
struct pci_epf_test_reg *reg = epf_test->reg[0];
|
||||
enum pci_barno test_reg_bar = epf_test->test_reg_bar;
|
||||
struct pci_epf_test_reg *reg = epf_test->reg[test_reg_bar];
|
||||
|
||||
dst_addr = pci_epc_mem_alloc_addr(epc, &phys_addr, reg->size);
|
||||
if (!dst_addr) {
|
||||
|
@ -247,7 +257,8 @@ static void pci_epf_test_raise_irq(struct pci_epf_test *epf_test)
|
|||
u8 msi_count;
|
||||
struct pci_epf *epf = epf_test->epf;
|
||||
struct pci_epc *epc = epf->epc;
|
||||
struct pci_epf_test_reg *reg = epf_test->reg[0];
|
||||
enum pci_barno test_reg_bar = epf_test->test_reg_bar;
|
||||
struct pci_epf_test_reg *reg = epf_test->reg[test_reg_bar];
|
||||
|
||||
reg->status |= STATUS_IRQ_RAISED;
|
||||
msi_count = pci_epc_get_msi(epc);
|
||||
|
@ -263,22 +274,28 @@ static void pci_epf_test_cmd_handler(struct work_struct *work)
|
|||
int ret;
|
||||
u8 irq;
|
||||
u8 msi_count;
|
||||
u32 command;
|
||||
struct pci_epf_test *epf_test = container_of(work, struct pci_epf_test,
|
||||
cmd_handler.work);
|
||||
struct pci_epf *epf = epf_test->epf;
|
||||
struct pci_epc *epc = epf->epc;
|
||||
struct pci_epf_test_reg *reg = epf_test->reg[0];
|
||||
enum pci_barno test_reg_bar = epf_test->test_reg_bar;
|
||||
struct pci_epf_test_reg *reg = epf_test->reg[test_reg_bar];
|
||||
|
||||
if (!reg->command)
|
||||
command = reg->command;
|
||||
if (!command)
|
||||
goto reset_handler;
|
||||
|
||||
if (reg->command & COMMAND_RAISE_LEGACY_IRQ) {
|
||||
reg->command = 0;
|
||||
reg->status = 0;
|
||||
|
||||
if (command & COMMAND_RAISE_LEGACY_IRQ) {
|
||||
reg->status = STATUS_IRQ_RAISED;
|
||||
pci_epc_raise_irq(epc, PCI_EPC_IRQ_LEGACY, 0);
|
||||
goto reset_handler;
|
||||
}
|
||||
|
||||
if (reg->command & COMMAND_WRITE) {
|
||||
if (command & COMMAND_WRITE) {
|
||||
ret = pci_epf_test_write(epf_test);
|
||||
if (ret)
|
||||
reg->status |= STATUS_WRITE_FAIL;
|
||||
|
@ -288,7 +305,7 @@ static void pci_epf_test_cmd_handler(struct work_struct *work)
|
|||
goto reset_handler;
|
||||
}
|
||||
|
||||
if (reg->command & COMMAND_READ) {
|
||||
if (command & COMMAND_READ) {
|
||||
ret = pci_epf_test_read(epf_test);
|
||||
if (!ret)
|
||||
reg->status |= STATUS_READ_SUCCESS;
|
||||
|
@ -298,7 +315,7 @@ static void pci_epf_test_cmd_handler(struct work_struct *work)
|
|||
goto reset_handler;
|
||||
}
|
||||
|
||||
if (reg->command & COMMAND_COPY) {
|
||||
if (command & COMMAND_COPY) {
|
||||
ret = pci_epf_test_copy(epf_test);
|
||||
if (!ret)
|
||||
reg->status |= STATUS_COPY_SUCCESS;
|
||||
|
@ -308,9 +325,9 @@ static void pci_epf_test_cmd_handler(struct work_struct *work)
|
|||
goto reset_handler;
|
||||
}
|
||||
|
||||
if (reg->command & COMMAND_RAISE_MSI_IRQ) {
|
||||
if (command & COMMAND_RAISE_MSI_IRQ) {
|
||||
msi_count = pci_epc_get_msi(epc);
|
||||
irq = (reg->command & MSI_NUMBER_MASK) >> MSI_NUMBER_SHIFT;
|
||||
irq = (command & MSI_NUMBER_MASK) >> MSI_NUMBER_SHIFT;
|
||||
if (irq > msi_count || msi_count <= 0)
|
||||
goto reset_handler;
|
||||
reg->status = STATUS_IRQ_RAISED;
|
||||
|
@ -319,8 +336,6 @@ static void pci_epf_test_cmd_handler(struct work_struct *work)
|
|||
}
|
||||
|
||||
reset_handler:
|
||||
reg->command = 0;
|
||||
|
||||
queue_delayed_work(kpcitest_workqueue, &epf_test->cmd_handler,
|
||||
msecs_to_jiffies(1));
|
||||
}
|
||||
|
@ -358,6 +373,7 @@ static int pci_epf_test_set_bar(struct pci_epf *epf)
|
|||
struct pci_epc *epc = epf->epc;
|
||||
struct device *dev = &epf->dev;
|
||||
struct pci_epf_test *epf_test = epf_get_drvdata(epf);
|
||||
enum pci_barno test_reg_bar = epf_test->test_reg_bar;
|
||||
|
||||
flags = PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_32;
|
||||
if (sizeof(dma_addr_t) == 0x8)
|
||||
|
@ -370,7 +386,7 @@ static int pci_epf_test_set_bar(struct pci_epf *epf)
|
|||
if (ret) {
|
||||
pci_epf_free_space(epf, epf_test->reg[bar], bar);
|
||||
dev_err(dev, "failed to set BAR%d\n", bar);
|
||||
if (bar == BAR_0)
|
||||
if (bar == test_reg_bar)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
@ -384,17 +400,20 @@ static int pci_epf_test_alloc_space(struct pci_epf *epf)
|
|||
struct device *dev = &epf->dev;
|
||||
void *base;
|
||||
int bar;
|
||||
enum pci_barno test_reg_bar = epf_test->test_reg_bar;
|
||||
|
||||
base = pci_epf_alloc_space(epf, sizeof(struct pci_epf_test_reg),
|
||||
BAR_0);
|
||||
test_reg_bar);
|
||||
if (!base) {
|
||||
dev_err(dev, "failed to allocated register space\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
epf_test->reg[0] = base;
|
||||
epf_test->reg[test_reg_bar] = base;
|
||||
|
||||
for (bar = BAR_1; bar <= BAR_5; bar++) {
|
||||
base = pci_epf_alloc_space(epf, bar_size[bar - 1], bar);
|
||||
for (bar = BAR_0; bar <= BAR_5; bar++) {
|
||||
if (bar == test_reg_bar)
|
||||
continue;
|
||||
base = pci_epf_alloc_space(epf, bar_size[bar], bar);
|
||||
if (!base)
|
||||
dev_err(dev, "failed to allocate space for BAR%d\n",
|
||||
bar);
|
||||
|
@ -407,6 +426,7 @@ static int pci_epf_test_alloc_space(struct pci_epf *epf)
|
|||
static int pci_epf_test_bind(struct pci_epf *epf)
|
||||
{
|
||||
int ret;
|
||||
struct pci_epf_test *epf_test = epf_get_drvdata(epf);
|
||||
struct pci_epf_header *header = epf->header;
|
||||
struct pci_epc *epc = epf->epc;
|
||||
struct device *dev = &epf->dev;
|
||||
|
@ -432,13 +452,34 @@ static int pci_epf_test_bind(struct pci_epf *epf)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!epf_test->linkup_notifier)
|
||||
queue_work(kpcitest_workqueue, &epf_test->cmd_handler.work);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct pci_epf_device_id pci_epf_test_ids[] = {
|
||||
{
|
||||
.name = "pci_epf_test",
|
||||
},
|
||||
{},
|
||||
};
|
||||
|
||||
static int pci_epf_test_probe(struct pci_epf *epf)
|
||||
{
|
||||
struct pci_epf_test *epf_test;
|
||||
struct device *dev = &epf->dev;
|
||||
const struct pci_epf_device_id *match;
|
||||
struct pci_epf_test_data *data;
|
||||
enum pci_barno test_reg_bar = BAR_0;
|
||||
bool linkup_notifier = true;
|
||||
|
||||
match = pci_epf_match_device(pci_epf_test_ids, epf);
|
||||
data = (struct pci_epf_test_data *)match->driver_data;
|
||||
if (data) {
|
||||
test_reg_bar = data->test_reg_bar;
|
||||
linkup_notifier = data->linkup_notifier;
|
||||
}
|
||||
|
||||
epf_test = devm_kzalloc(dev, sizeof(*epf_test), GFP_KERNEL);
|
||||
if (!epf_test)
|
||||
|
@ -446,6 +487,8 @@ static int pci_epf_test_probe(struct pci_epf *epf)
|
|||
|
||||
epf->header = &test_header;
|
||||
epf_test->epf = epf;
|
||||
epf_test->test_reg_bar = test_reg_bar;
|
||||
epf_test->linkup_notifier = linkup_notifier;
|
||||
|
||||
INIT_DELAYED_WORK(&epf_test->cmd_handler, pci_epf_test_cmd_handler);
|
||||
|
||||
|
@ -453,31 +496,15 @@ static int pci_epf_test_probe(struct pci_epf *epf)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int pci_epf_test_remove(struct pci_epf *epf)
|
||||
{
|
||||
struct pci_epf_test *epf_test = epf_get_drvdata(epf);
|
||||
|
||||
kfree(epf_test);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct pci_epf_ops ops = {
|
||||
.unbind = pci_epf_test_unbind,
|
||||
.bind = pci_epf_test_bind,
|
||||
.linkup = pci_epf_test_linkup,
|
||||
};
|
||||
|
||||
static const struct pci_epf_device_id pci_epf_test_ids[] = {
|
||||
{
|
||||
.name = "pci_epf_test",
|
||||
},
|
||||
{},
|
||||
};
|
||||
|
||||
static struct pci_epf_driver test_driver = {
|
||||
.driver.name = "pci_epf_test",
|
||||
.probe = pci_epf_test_probe,
|
||||
.remove = pci_epf_test_remove,
|
||||
.id_table = pci_epf_test_ids,
|
||||
.ops = &ops,
|
||||
.owner = THIS_MODULE,
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include <linux/dma-mapping.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
|
||||
#include <linux/pci-epc.h>
|
||||
#include <linux/pci-epf.h>
|
||||
|
@ -370,6 +371,7 @@ EXPORT_SYMBOL_GPL(pci_epc_write_header);
|
|||
int pci_epc_add_epf(struct pci_epc *epc, struct pci_epf *epf)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct device *dev = epc->dev.parent;
|
||||
|
||||
if (epf->epc)
|
||||
return -EBUSY;
|
||||
|
@ -381,8 +383,12 @@ int pci_epc_add_epf(struct pci_epc *epc, struct pci_epf *epf)
|
|||
return -EINVAL;
|
||||
|
||||
epf->epc = epc;
|
||||
dma_set_coherent_mask(&epf->dev, epc->dev.coherent_dma_mask);
|
||||
epf->dev.dma_mask = epc->dev.dma_mask;
|
||||
if (dev->of_node) {
|
||||
of_dma_configure(&epf->dev, dev->of_node);
|
||||
} else {
|
||||
dma_set_coherent_mask(&epf->dev, epc->dev.coherent_dma_mask);
|
||||
epf->dev.dma_mask = epc->dev.dma_mask;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&epc->lock, flags);
|
||||
list_add_tail(&epf->list, &epc->pci_epf);
|
||||
|
@ -500,6 +506,7 @@ __pci_epc_create(struct device *dev, const struct pci_epc_ops *ops,
|
|||
dma_set_coherent_mask(&epc->dev, dev->coherent_dma_mask);
|
||||
epc->dev.class = pci_epc_class;
|
||||
epc->dev.dma_mask = dev->dma_mask;
|
||||
epc->dev.parent = dev;
|
||||
epc->ops = ops;
|
||||
|
||||
ret = dev_set_name(&epc->dev, "%s", dev_name(dev));
|
||||
|
|
|
@ -24,21 +24,54 @@
|
|||
#include <linux/pci-epc.h>
|
||||
|
||||
/**
|
||||
* pci_epc_mem_init() - initialize the pci_epc_mem structure
|
||||
* pci_epc_mem_get_order() - determine the allocation order of a memory size
|
||||
* @mem: address space of the endpoint controller
|
||||
* @size: the size for which to get the order
|
||||
*
|
||||
* Reimplement get_order() for mem->page_size since the generic get_order
|
||||
* always gets order with a constant PAGE_SIZE.
|
||||
*/
|
||||
static int pci_epc_mem_get_order(struct pci_epc_mem *mem, size_t size)
|
||||
{
|
||||
int order;
|
||||
unsigned int page_shift = ilog2(mem->page_size);
|
||||
|
||||
size--;
|
||||
size >>= page_shift;
|
||||
#if BITS_PER_LONG == 32
|
||||
order = fls(size);
|
||||
#else
|
||||
order = fls64(size);
|
||||
#endif
|
||||
return order;
|
||||
}
|
||||
|
||||
/**
|
||||
* __pci_epc_mem_init() - initialize the pci_epc_mem structure
|
||||
* @epc: the EPC device that invoked pci_epc_mem_init
|
||||
* @phys_base: the physical address of the base
|
||||
* @size: the size of the address space
|
||||
* @page_size: size of each page
|
||||
*
|
||||
* Invoke to initialize the pci_epc_mem structure used by the
|
||||
* endpoint functions to allocate mapped PCI address.
|
||||
*/
|
||||
int pci_epc_mem_init(struct pci_epc *epc, phys_addr_t phys_base, size_t size)
|
||||
int __pci_epc_mem_init(struct pci_epc *epc, phys_addr_t phys_base, size_t size,
|
||||
size_t page_size)
|
||||
{
|
||||
int ret;
|
||||
struct pci_epc_mem *mem;
|
||||
unsigned long *bitmap;
|
||||
int pages = size >> PAGE_SHIFT;
|
||||
int bitmap_size = BITS_TO_LONGS(pages) * sizeof(long);
|
||||
unsigned int page_shift;
|
||||
int pages;
|
||||
int bitmap_size;
|
||||
|
||||
if (page_size < PAGE_SIZE)
|
||||
page_size = PAGE_SIZE;
|
||||
|
||||
page_shift = ilog2(page_size);
|
||||
pages = size >> page_shift;
|
||||
bitmap_size = BITS_TO_LONGS(pages) * sizeof(long);
|
||||
|
||||
mem = kzalloc(sizeof(*mem), GFP_KERNEL);
|
||||
if (!mem) {
|
||||
|
@ -54,6 +87,7 @@ int pci_epc_mem_init(struct pci_epc *epc, phys_addr_t phys_base, size_t size)
|
|||
|
||||
mem->bitmap = bitmap;
|
||||
mem->phys_base = phys_base;
|
||||
mem->page_size = page_size;
|
||||
mem->pages = pages;
|
||||
mem->size = size;
|
||||
|
||||
|
@ -67,7 +101,7 @@ err_mem:
|
|||
err:
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pci_epc_mem_init);
|
||||
EXPORT_SYMBOL_GPL(__pci_epc_mem_init);
|
||||
|
||||
/**
|
||||
* pci_epc_mem_exit() - cleanup the pci_epc_mem structure
|
||||
|
@ -101,13 +135,17 @@ void __iomem *pci_epc_mem_alloc_addr(struct pci_epc *epc,
|
|||
int pageno;
|
||||
void __iomem *virt_addr;
|
||||
struct pci_epc_mem *mem = epc->mem;
|
||||
int order = get_order(size);
|
||||
unsigned int page_shift = ilog2(mem->page_size);
|
||||
int order;
|
||||
|
||||
size = ALIGN(size, mem->page_size);
|
||||
order = pci_epc_mem_get_order(mem, size);
|
||||
|
||||
pageno = bitmap_find_free_region(mem->bitmap, mem->pages, order);
|
||||
if (pageno < 0)
|
||||
return NULL;
|
||||
|
||||
*phys_addr = mem->phys_base + (pageno << PAGE_SHIFT);
|
||||
*phys_addr = mem->phys_base + (pageno << page_shift);
|
||||
virt_addr = ioremap(*phys_addr, size);
|
||||
if (!virt_addr)
|
||||
bitmap_release_region(mem->bitmap, pageno, order);
|
||||
|
@ -129,11 +167,14 @@ void pci_epc_mem_free_addr(struct pci_epc *epc, phys_addr_t phys_addr,
|
|||
void __iomem *virt_addr, size_t size)
|
||||
{
|
||||
int pageno;
|
||||
int order = get_order(size);
|
||||
struct pci_epc_mem *mem = epc->mem;
|
||||
unsigned int page_shift = ilog2(mem->page_size);
|
||||
int order;
|
||||
|
||||
iounmap(virt_addr);
|
||||
pageno = (phys_addr - mem->phys_base) >> PAGE_SHIFT;
|
||||
pageno = (phys_addr - mem->phys_base) >> page_shift;
|
||||
size = ALIGN(size, mem->page_size);
|
||||
order = pci_epc_mem_get_order(mem, size);
|
||||
bitmap_release_region(mem->bitmap, pageno, order);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pci_epc_mem_free_addr);
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
#include <linux/pci-ep-cfs.h>
|
||||
|
||||
static struct bus_type pci_epf_bus_type;
|
||||
static struct device_type pci_epf_type;
|
||||
static const struct device_type pci_epf_type;
|
||||
|
||||
/**
|
||||
* pci_epf_linkup() - Notify the function driver that EPC device has
|
||||
|
@ -267,6 +267,22 @@ err_ret:
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(pci_epf_create);
|
||||
|
||||
const struct pci_epf_device_id *
|
||||
pci_epf_match_device(const struct pci_epf_device_id *id, struct pci_epf *epf)
|
||||
{
|
||||
if (!id || !epf)
|
||||
return NULL;
|
||||
|
||||
while (*id->name) {
|
||||
if (strcmp(epf->name, id->name) == 0)
|
||||
return id;
|
||||
id++;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pci_epf_match_device);
|
||||
|
||||
static void pci_epf_dev_release(struct device *dev)
|
||||
{
|
||||
struct pci_epf *epf = to_pci_epf(dev);
|
||||
|
@ -275,7 +291,7 @@ static void pci_epf_dev_release(struct device *dev)
|
|||
kfree(epf);
|
||||
}
|
||||
|
||||
static struct device_type pci_epf_type = {
|
||||
static const struct device_type pci_epf_type = {
|
||||
.release = pci_epf_dev_release,
|
||||
};
|
||||
|
||||
|
@ -317,11 +333,12 @@ static int pci_epf_device_probe(struct device *dev)
|
|||
|
||||
static int pci_epf_device_remove(struct device *dev)
|
||||
{
|
||||
int ret;
|
||||
int ret = 0;
|
||||
struct pci_epf *epf = to_pci_epf(dev);
|
||||
struct pci_epf_driver *driver = to_pci_epf_driver(dev->driver);
|
||||
|
||||
ret = driver->remove(epf);
|
||||
if (driver->remove)
|
||||
ret = driver->remove(epf);
|
||||
epf->driver = NULL;
|
||||
|
||||
return ret;
|
||||
|
|
|
@ -71,7 +71,7 @@ config PCI_HOST_GENERIC
|
|||
|
||||
config PCIE_XILINX
|
||||
bool "Xilinx AXI PCIe host bridge support"
|
||||
depends on ARCH_ZYNQ || MICROBLAZE
|
||||
depends on ARCH_ZYNQ || MICROBLAZE || (MIPS && PCI_DRIVERS_GENERIC)
|
||||
help
|
||||
Say 'Y' here if you want kernel to support the Xilinx AXI PCIe
|
||||
Host Bridge driver.
|
||||
|
@ -182,14 +182,13 @@ config PCIE_ROCKCHIP
|
|||
|
||||
config PCIE_MEDIATEK
|
||||
bool "MediaTek PCIe controller"
|
||||
depends on ARM && (ARCH_MEDIATEK || COMPILE_TEST)
|
||||
depends on (ARM || ARM64) && (ARCH_MEDIATEK || COMPILE_TEST)
|
||||
depends on OF
|
||||
depends on PCI
|
||||
select PCIEPORTBUS
|
||||
help
|
||||
Say Y here if you want to enable PCIe controller support on
|
||||
MT7623 series SoCs. There is one single root complex with 3 root
|
||||
ports available. Each port supports Gen2 lane x1.
|
||||
MediaTek SoCs.
|
||||
|
||||
config PCIE_TANGO_SMP8759
|
||||
bool "Tango SMP8759 PCIe controller (DANGEROUS)"
|
||||
|
|
|
@ -191,7 +191,6 @@
|
|||
#define LINK_WAIT_USLEEP_MIN 90000
|
||||
#define LINK_WAIT_USLEEP_MAX 100000
|
||||
|
||||
#define LEGACY_IRQ_NUM 4
|
||||
#define MSI_IRQ_NUM 32
|
||||
|
||||
struct advk_pcie {
|
||||
|
@ -729,7 +728,7 @@ static int advk_pcie_init_irq_domain(struct advk_pcie *pcie)
|
|||
irq_chip->irq_unmask = advk_pcie_irq_unmask;
|
||||
|
||||
pcie->irq_domain =
|
||||
irq_domain_add_linear(pcie_intc_node, LEGACY_IRQ_NUM,
|
||||
irq_domain_add_linear(pcie_intc_node, PCI_NUM_INTX,
|
||||
&advk_pcie_irq_domain_ops, pcie);
|
||||
if (!pcie->irq_domain) {
|
||||
dev_err(dev, "Failed to get a INTx IRQ domain\n");
|
||||
|
@ -786,7 +785,7 @@ static void advk_pcie_handle_int(struct advk_pcie *pcie)
|
|||
advk_pcie_handle_msi(pcie);
|
||||
|
||||
/* Process legacy interrupts */
|
||||
for (i = 0; i < LEGACY_IRQ_NUM; i++) {
|
||||
for (i = 0; i < PCI_NUM_INTX; i++) {
|
||||
if (!(status & PCIE_ISR0_INTX_ASSERT(i)))
|
||||
continue;
|
||||
|
||||
|
|
|
@ -350,12 +350,12 @@ static int faraday_pci_setup_cascaded_irq(struct faraday_pci *p)
|
|||
|
||||
/* All PCI IRQs cascade off this one */
|
||||
irq = of_irq_get(intc, 0);
|
||||
if (!irq) {
|
||||
if (irq <= 0) {
|
||||
dev_err(p->dev, "failed to get parent IRQ\n");
|
||||
return -EINVAL;
|
||||
return irq ?: -EINVAL;
|
||||
}
|
||||
|
||||
p->irqdomain = irq_domain_add_linear(intc, 4,
|
||||
p->irqdomain = irq_domain_add_linear(intc, PCI_NUM_INTX,
|
||||
&faraday_pci_irqdomain_ops, p);
|
||||
if (!p->irqdomain) {
|
||||
dev_err(p->dev, "failed to create Gemini PCI IRQ domain\n");
|
||||
|
|
|
@ -50,6 +50,7 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/semaphore.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <asm/irqdomain.h>
|
||||
|
@ -1113,7 +1114,12 @@ static void hv_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
|
|||
goto free_int_desc;
|
||||
}
|
||||
|
||||
wait_for_completion(&comp.comp_pkt.host_event);
|
||||
/*
|
||||
* Since this function is called with IRQ locks held, can't
|
||||
* do normal wait for completion; instead poll.
|
||||
*/
|
||||
while (!try_wait_for_completion(&comp.comp_pkt.host_event))
|
||||
udelay(100);
|
||||
|
||||
if (comp.comp_pkt.completion_status < 0) {
|
||||
dev_err(&hbus->hdev->device,
|
||||
|
|
|
@ -1054,8 +1054,8 @@ static int mvebu_pcie_parse_port(struct mvebu_pcie *pcie,
|
|||
port->pcie = pcie;
|
||||
|
||||
if (of_property_read_u32(child, "marvell,pcie-port", &port->port)) {
|
||||
dev_warn(dev, "ignoring %s, missing pcie-port property\n",
|
||||
of_node_full_name(child));
|
||||
dev_warn(dev, "ignoring %pOF, missing pcie-port property\n",
|
||||
child);
|
||||
goto skip;
|
||||
}
|
||||
|
||||
|
@ -1106,8 +1106,8 @@ static int mvebu_pcie_parse_port(struct mvebu_pcie *pcie,
|
|||
}
|
||||
|
||||
if (flags & OF_GPIO_ACTIVE_LOW) {
|
||||
dev_info(dev, "%s: reset gpio is active low\n",
|
||||
of_node_full_name(child));
|
||||
dev_info(dev, "%pOF: reset gpio is active low\n",
|
||||
child);
|
||||
gpio_flags = GPIOF_ACTIVE_LOW |
|
||||
GPIOF_OUT_INIT_LOW;
|
||||
} else {
|
||||
|
@ -1186,8 +1186,7 @@ static int mvebu_pcie_powerup(struct mvebu_pcie_port *port)
|
|||
*/
|
||||
static void mvebu_pcie_powerdown(struct mvebu_pcie_port *port)
|
||||
{
|
||||
if (port->reset_gpio)
|
||||
gpiod_set_value_cansleep(port->reset_gpio, 1);
|
||||
gpiod_set_value_cansleep(port->reset_gpio, 1);
|
||||
|
||||
clk_disable_unprepare(port->clk);
|
||||
}
|
||||
|
|
|
@ -1147,15 +1147,15 @@ static int tegra_pcie_resets_get(struct tegra_pcie *pcie)
|
|||
{
|
||||
struct device *dev = pcie->dev;
|
||||
|
||||
pcie->pex_rst = devm_reset_control_get(dev, "pex");
|
||||
pcie->pex_rst = devm_reset_control_get_exclusive(dev, "pex");
|
||||
if (IS_ERR(pcie->pex_rst))
|
||||
return PTR_ERR(pcie->pex_rst);
|
||||
|
||||
pcie->afi_rst = devm_reset_control_get(dev, "afi");
|
||||
pcie->afi_rst = devm_reset_control_get_exclusive(dev, "afi");
|
||||
if (IS_ERR(pcie->afi_rst))
|
||||
return PTR_ERR(pcie->afi_rst);
|
||||
|
||||
pcie->pcie_xrst = devm_reset_control_get(dev, "pcie_x");
|
||||
pcie->pcie_xrst = devm_reset_control_get_exclusive(dev, "pcie_x");
|
||||
if (IS_ERR(pcie->pcie_xrst))
|
||||
return PTR_ERR(pcie->pcie_xrst);
|
||||
|
||||
|
@ -1703,8 +1703,7 @@ static int tegra_pcie_get_legacy_regulators(struct tegra_pcie *pcie)
|
|||
pcie->num_supplies = 2;
|
||||
|
||||
if (pcie->num_supplies == 0) {
|
||||
dev_err(dev, "device %s not supported in legacy mode\n",
|
||||
np->full_name);
|
||||
dev_err(dev, "device %pOF not supported in legacy mode\n", np);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
|
|
|
@ -489,7 +489,7 @@ static int xgene_msi_probe(struct platform_device *pdev)
|
|||
if (virt_msir < 0) {
|
||||
dev_err(&pdev->dev, "Cannot translate IRQ index %d\n",
|
||||
irq_index);
|
||||
rc = -EINVAL;
|
||||
rc = virt_msir;
|
||||
goto error;
|
||||
}
|
||||
xgene_msi->msi_groups[irq_index].gic_irq = virt_msir;
|
||||
|
|
|
@ -61,7 +61,7 @@
|
|||
#define SZ_1T (SZ_1G*1024ULL)
|
||||
#define PIPE_PHY_RATE_RD(src) ((0xc000 & (u32)(src)) >> 0xe)
|
||||
|
||||
#define ROOT_CAP_AND_CTRL 0x5C
|
||||
#define XGENE_V1_PCI_EXP_CAP 0x40
|
||||
|
||||
/* PCIe IP version */
|
||||
#define XGENE_PCIE_IP_VER_UNKN 0
|
||||
|
@ -160,7 +160,7 @@ static bool xgene_pcie_hide_rc_bars(struct pci_bus *bus, int offset)
|
|||
}
|
||||
|
||||
static void __iomem *xgene_pcie_map_bus(struct pci_bus *bus, unsigned int devfn,
|
||||
int offset)
|
||||
int offset)
|
||||
{
|
||||
if ((pci_is_root_bus(bus) && devfn != 0) ||
|
||||
xgene_pcie_hide_rc_bars(bus, offset))
|
||||
|
@ -189,7 +189,7 @@ static int xgene_pcie_config_read32(struct pci_bus *bus, unsigned int devfn,
|
|||
* Avoid this by not claiming to support CRS.
|
||||
*/
|
||||
if (pci_is_root_bus(bus) && (port->version == XGENE_PCIE_IP_VER_1) &&
|
||||
((where & ~0x3) == ROOT_CAP_AND_CTRL))
|
||||
((where & ~0x3) == XGENE_V1_PCI_EXP_CAP + PCI_EXP_RTCTL))
|
||||
*val &= ~(PCI_EXP_RTCAP_CRSVIS << 16);
|
||||
|
||||
if (size <= 2)
|
||||
|
@ -265,12 +265,12 @@ static int xgene_v1_pcie_ecam_init(struct pci_config_window *cfg)
|
|||
}
|
||||
|
||||
struct pci_ecam_ops xgene_v1_pcie_ecam_ops = {
|
||||
.bus_shift = 16,
|
||||
.init = xgene_v1_pcie_ecam_init,
|
||||
.pci_ops = {
|
||||
.map_bus = xgene_pcie_map_bus,
|
||||
.read = xgene_pcie_config_read32,
|
||||
.write = pci_generic_config_write,
|
||||
.bus_shift = 16,
|
||||
.init = xgene_v1_pcie_ecam_init,
|
||||
.pci_ops = {
|
||||
.map_bus = xgene_pcie_map_bus,
|
||||
.read = xgene_pcie_config_read32,
|
||||
.write = pci_generic_config_write,
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -280,12 +280,12 @@ static int xgene_v2_pcie_ecam_init(struct pci_config_window *cfg)
|
|||
}
|
||||
|
||||
struct pci_ecam_ops xgene_v2_pcie_ecam_ops = {
|
||||
.bus_shift = 16,
|
||||
.init = xgene_v2_pcie_ecam_init,
|
||||
.pci_ops = {
|
||||
.map_bus = xgene_pcie_map_bus,
|
||||
.read = xgene_pcie_config_read32,
|
||||
.write = pci_generic_config_write,
|
||||
.bus_shift = 16,
|
||||
.init = xgene_v2_pcie_ecam_init,
|
||||
.pci_ops = {
|
||||
.map_bus = xgene_pcie_map_bus,
|
||||
.read = xgene_pcie_config_read32,
|
||||
.write = pci_generic_config_write,
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
@ -318,7 +318,7 @@ static u64 xgene_pcie_set_ib_mask(struct xgene_pcie_port *port, u32 addr,
|
|||
}
|
||||
|
||||
static void xgene_pcie_linkup(struct xgene_pcie_port *port,
|
||||
u32 *lanes, u32 *speed)
|
||||
u32 *lanes, u32 *speed)
|
||||
{
|
||||
u32 val32;
|
||||
|
||||
|
@ -593,8 +593,7 @@ static void xgene_pcie_clear_config(struct xgene_pcie_port *port)
|
|||
xgene_pcie_writel(port, i, 0);
|
||||
}
|
||||
|
||||
static int xgene_pcie_setup(struct xgene_pcie_port *port,
|
||||
struct list_head *res,
|
||||
static int xgene_pcie_setup(struct xgene_pcie_port *port, struct list_head *res,
|
||||
resource_size_t io_base)
|
||||
{
|
||||
struct device *dev = port->dev;
|
||||
|
@ -706,9 +705,9 @@ static const struct of_device_id xgene_pcie_match_table[] = {
|
|||
|
||||
static struct platform_driver xgene_pcie_driver = {
|
||||
.driver = {
|
||||
.name = "xgene-pcie",
|
||||
.of_match_table = of_match_ptr(xgene_pcie_match_table),
|
||||
.suppress_bind_attrs = true,
|
||||
.name = "xgene-pcie",
|
||||
.of_match_table = of_match_ptr(xgene_pcie_match_table),
|
||||
.suppress_bind_attrs = true,
|
||||
},
|
||||
.probe = xgene_pcie_probe_bridge,
|
||||
};
|
||||
|
|
|
@ -64,13 +64,11 @@ static void altera_msi_isr(struct irq_desc *desc)
|
|||
struct irq_chip *chip = irq_desc_get_chip(desc);
|
||||
struct altera_msi *msi;
|
||||
unsigned long status;
|
||||
u32 num_of_vectors;
|
||||
u32 bit;
|
||||
u32 virq;
|
||||
|
||||
chained_irq_enter(chip, desc);
|
||||
msi = irq_desc_get_handler_data(desc);
|
||||
num_of_vectors = msi->num_of_vectors;
|
||||
|
||||
while ((status = msi_readl(msi, MSI_STATUS)) != 0) {
|
||||
for_each_set_bit(bit, &status, msi->num_of_vectors) {
|
||||
|
@ -267,9 +265,9 @@ static int altera_msi_probe(struct platform_device *pdev)
|
|||
return ret;
|
||||
|
||||
msi->irq = platform_get_irq(pdev, 0);
|
||||
if (msi->irq <= 0) {
|
||||
if (msi->irq < 0) {
|
||||
dev_err(&pdev->dev, "failed to map IRQ: %d\n", msi->irq);
|
||||
ret = -ENODEV;
|
||||
ret = msi->irq;
|
||||
goto err;
|
||||
}
|
||||
|
||||
|
|
|
@ -76,8 +76,6 @@
|
|||
#define LINK_UP_TIMEOUT HZ
|
||||
#define LINK_RETRAIN_TIMEOUT HZ
|
||||
|
||||
#define INTX_NUM 4
|
||||
|
||||
#define DWORD_MASK 3
|
||||
|
||||
struct altera_pcie {
|
||||
|
@ -464,6 +462,7 @@ static int altera_pcie_intx_map(struct irq_domain *domain, unsigned int irq,
|
|||
|
||||
static const struct irq_domain_ops intx_domain_ops = {
|
||||
.map = altera_pcie_intx_map,
|
||||
.xlate = pci_irqd_intx_xlate,
|
||||
};
|
||||
|
||||
static void altera_pcie_isr(struct irq_desc *desc)
|
||||
|
@ -481,11 +480,11 @@ static void altera_pcie_isr(struct irq_desc *desc)
|
|||
|
||||
while ((status = cra_readl(pcie, P2A_INT_STATUS)
|
||||
& P2A_INT_STS_ALL) != 0) {
|
||||
for_each_set_bit(bit, &status, INTX_NUM) {
|
||||
for_each_set_bit(bit, &status, PCI_NUM_INTX) {
|
||||
/* clear interrupts */
|
||||
cra_writel(pcie, 1 << bit, P2A_INT_STATUS);
|
||||
|
||||
virq = irq_find_mapping(pcie->irq_domain, bit + 1);
|
||||
virq = irq_find_mapping(pcie->irq_domain, bit);
|
||||
if (virq)
|
||||
generic_handle_irq(virq);
|
||||
else
|
||||
|
@ -536,7 +535,7 @@ static int altera_pcie_init_irq_domain(struct altera_pcie *pcie)
|
|||
struct device_node *node = dev->of_node;
|
||||
|
||||
/* Setup INTx */
|
||||
pcie->irq_domain = irq_domain_add_linear(node, INTX_NUM + 1,
|
||||
pcie->irq_domain = irq_domain_add_linear(node, PCI_NUM_INTX,
|
||||
&intx_domain_ops, pcie);
|
||||
if (!pcie->irq_domain) {
|
||||
dev_err(dev, "Failed to get a INTx IRQ domain\n");
|
||||
|
@ -559,9 +558,9 @@ static int altera_pcie_parse_dt(struct altera_pcie *pcie)
|
|||
|
||||
/* setup IRQ */
|
||||
pcie->irq = platform_get_irq(pdev, 0);
|
||||
if (pcie->irq <= 0) {
|
||||
if (pcie->irq < 0) {
|
||||
dev_err(dev, "failed to get IRQ: %d\n", pcie->irq);
|
||||
return -EINVAL;
|
||||
return pcie->irq;
|
||||
}
|
||||
|
||||
irq_set_chained_handler_and_data(pcie->irq, altera_pcie_isr, pcie);
|
||||
|
|
|
@ -317,7 +317,6 @@ static void iproc_msi_handler(struct irq_desc *desc)
|
|||
struct irq_chip *chip = irq_desc_get_chip(desc);
|
||||
struct iproc_msi_grp *grp;
|
||||
struct iproc_msi *msi;
|
||||
struct iproc_pcie *pcie;
|
||||
u32 eq, head, tail, nr_events;
|
||||
unsigned long hwirq;
|
||||
int virq;
|
||||
|
@ -326,7 +325,6 @@ static void iproc_msi_handler(struct irq_desc *desc)
|
|||
|
||||
grp = irq_desc_get_handler_data(desc);
|
||||
msi = grp->msi;
|
||||
pcie = msi->pcie;
|
||||
eq = grp->eq;
|
||||
|
||||
/*
|
||||
|
|
|
@ -134,6 +134,13 @@ static int iproc_pcie_pltfm_remove(struct platform_device *pdev)
|
|||
return iproc_pcie_remove(pcie);
|
||||
}
|
||||
|
||||
static void iproc_pcie_pltfm_shutdown(struct platform_device *pdev)
|
||||
{
|
||||
struct iproc_pcie *pcie = platform_get_drvdata(pdev);
|
||||
|
||||
iproc_pcie_shutdown(pcie);
|
||||
}
|
||||
|
||||
static struct platform_driver iproc_pcie_pltfm_driver = {
|
||||
.driver = {
|
||||
.name = "iproc-pcie",
|
||||
|
@ -141,6 +148,7 @@ static struct platform_driver iproc_pcie_pltfm_driver = {
|
|||
},
|
||||
.probe = iproc_pcie_pltfm_probe,
|
||||
.remove = iproc_pcie_pltfm_remove,
|
||||
.shutdown = iproc_pcie_pltfm_shutdown,
|
||||
};
|
||||
module_platform_driver(iproc_pcie_pltfm_driver);
|
||||
|
||||
|
|
|
@ -31,68 +31,71 @@
|
|||
|
||||
#include "pcie-iproc.h"
|
||||
|
||||
#define EP_PERST_SOURCE_SELECT_SHIFT 2
|
||||
#define EP_PERST_SOURCE_SELECT BIT(EP_PERST_SOURCE_SELECT_SHIFT)
|
||||
#define EP_MODE_SURVIVE_PERST_SHIFT 1
|
||||
#define EP_MODE_SURVIVE_PERST BIT(EP_MODE_SURVIVE_PERST_SHIFT)
|
||||
#define RC_PCIE_RST_OUTPUT_SHIFT 0
|
||||
#define RC_PCIE_RST_OUTPUT BIT(RC_PCIE_RST_OUTPUT_SHIFT)
|
||||
#define PAXC_RESET_MASK 0x7f
|
||||
#define EP_PERST_SOURCE_SELECT_SHIFT 2
|
||||
#define EP_PERST_SOURCE_SELECT BIT(EP_PERST_SOURCE_SELECT_SHIFT)
|
||||
#define EP_MODE_SURVIVE_PERST_SHIFT 1
|
||||
#define EP_MODE_SURVIVE_PERST BIT(EP_MODE_SURVIVE_PERST_SHIFT)
|
||||
#define RC_PCIE_RST_OUTPUT_SHIFT 0
|
||||
#define RC_PCIE_RST_OUTPUT BIT(RC_PCIE_RST_OUTPUT_SHIFT)
|
||||
#define PAXC_RESET_MASK 0x7f
|
||||
|
||||
#define GIC_V3_CFG_SHIFT 0
|
||||
#define GIC_V3_CFG BIT(GIC_V3_CFG_SHIFT)
|
||||
#define GIC_V3_CFG_SHIFT 0
|
||||
#define GIC_V3_CFG BIT(GIC_V3_CFG_SHIFT)
|
||||
|
||||
#define MSI_ENABLE_CFG_SHIFT 0
|
||||
#define MSI_ENABLE_CFG BIT(MSI_ENABLE_CFG_SHIFT)
|
||||
#define MSI_ENABLE_CFG_SHIFT 0
|
||||
#define MSI_ENABLE_CFG BIT(MSI_ENABLE_CFG_SHIFT)
|
||||
|
||||
#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_CFG_TYPE_SHIFT 0
|
||||
#define CFG_ADDR_CFG_TYPE_MASK 0x00000003
|
||||
#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_CFG_TYPE_SHIFT 0
|
||||
#define CFG_ADDR_CFG_TYPE_MASK 0x00000003
|
||||
|
||||
#define SYS_RC_INTX_MASK 0xf
|
||||
#define SYS_RC_INTX_MASK 0xf
|
||||
|
||||
#define PCIE_PHYLINKUP_SHIFT 3
|
||||
#define PCIE_PHYLINKUP BIT(PCIE_PHYLINKUP_SHIFT)
|
||||
#define PCIE_DL_ACTIVE_SHIFT 2
|
||||
#define PCIE_DL_ACTIVE BIT(PCIE_DL_ACTIVE_SHIFT)
|
||||
#define PCIE_PHYLINKUP_SHIFT 3
|
||||
#define PCIE_PHYLINKUP BIT(PCIE_PHYLINKUP_SHIFT)
|
||||
#define PCIE_DL_ACTIVE_SHIFT 2
|
||||
#define PCIE_DL_ACTIVE BIT(PCIE_DL_ACTIVE_SHIFT)
|
||||
|
||||
#define APB_ERR_EN_SHIFT 0
|
||||
#define APB_ERR_EN BIT(APB_ERR_EN_SHIFT)
|
||||
#define APB_ERR_EN_SHIFT 0
|
||||
#define APB_ERR_EN BIT(APB_ERR_EN_SHIFT)
|
||||
|
||||
#define CFG_RETRY_STATUS 0xffff0001
|
||||
#define CFG_RETRY_STATUS_TIMEOUT_US 500000 /* 500 milliseconds */
|
||||
|
||||
/* derive the enum index of the outbound/inbound mapping registers */
|
||||
#define MAP_REG(base_reg, index) ((base_reg) + (index) * 2)
|
||||
#define MAP_REG(base_reg, index) ((base_reg) + (index) * 2)
|
||||
|
||||
/*
|
||||
* Maximum number of outbound mapping window sizes that can be supported by any
|
||||
* OARR/OMAP mapping pair
|
||||
*/
|
||||
#define MAX_NUM_OB_WINDOW_SIZES 4
|
||||
#define MAX_NUM_OB_WINDOW_SIZES 4
|
||||
|
||||
#define OARR_VALID_SHIFT 0
|
||||
#define OARR_VALID BIT(OARR_VALID_SHIFT)
|
||||
#define OARR_SIZE_CFG_SHIFT 1
|
||||
#define OARR_VALID_SHIFT 0
|
||||
#define OARR_VALID BIT(OARR_VALID_SHIFT)
|
||||
#define OARR_SIZE_CFG_SHIFT 1
|
||||
|
||||
/*
|
||||
* Maximum number of inbound mapping region sizes that can be supported by an
|
||||
* IARR
|
||||
*/
|
||||
#define MAX_NUM_IB_REGION_SIZES 9
|
||||
#define MAX_NUM_IB_REGION_SIZES 9
|
||||
|
||||
#define IMAP_VALID_SHIFT 0
|
||||
#define IMAP_VALID BIT(IMAP_VALID_SHIFT)
|
||||
#define IMAP_VALID_SHIFT 0
|
||||
#define IMAP_VALID BIT(IMAP_VALID_SHIFT)
|
||||
|
||||
#define PCI_EXP_CAP 0xac
|
||||
#define IPROC_PCI_EXP_CAP 0xac
|
||||
|
||||
#define IPROC_PCIE_REG_INVALID 0xffff
|
||||
#define IPROC_PCIE_REG_INVALID 0xffff
|
||||
|
||||
/**
|
||||
* iProc PCIe outbound mapping controller specific parameters
|
||||
|
@ -304,80 +307,80 @@ enum iproc_pcie_reg {
|
|||
|
||||
/* iProc PCIe PAXB BCMA registers */
|
||||
static const u16 iproc_pcie_reg_paxb_bcma[] = {
|
||||
[IPROC_PCIE_CLK_CTRL] = 0x000,
|
||||
[IPROC_PCIE_CFG_IND_ADDR] = 0x120,
|
||||
[IPROC_PCIE_CFG_IND_DATA] = 0x124,
|
||||
[IPROC_PCIE_CFG_ADDR] = 0x1f8,
|
||||
[IPROC_PCIE_CFG_DATA] = 0x1fc,
|
||||
[IPROC_PCIE_INTX_EN] = 0x330,
|
||||
[IPROC_PCIE_LINK_STATUS] = 0xf0c,
|
||||
[IPROC_PCIE_CLK_CTRL] = 0x000,
|
||||
[IPROC_PCIE_CFG_IND_ADDR] = 0x120,
|
||||
[IPROC_PCIE_CFG_IND_DATA] = 0x124,
|
||||
[IPROC_PCIE_CFG_ADDR] = 0x1f8,
|
||||
[IPROC_PCIE_CFG_DATA] = 0x1fc,
|
||||
[IPROC_PCIE_INTX_EN] = 0x330,
|
||||
[IPROC_PCIE_LINK_STATUS] = 0xf0c,
|
||||
};
|
||||
|
||||
/* iProc PCIe PAXB registers */
|
||||
static const u16 iproc_pcie_reg_paxb[] = {
|
||||
[IPROC_PCIE_CLK_CTRL] = 0x000,
|
||||
[IPROC_PCIE_CFG_IND_ADDR] = 0x120,
|
||||
[IPROC_PCIE_CFG_IND_DATA] = 0x124,
|
||||
[IPROC_PCIE_CFG_ADDR] = 0x1f8,
|
||||
[IPROC_PCIE_CFG_DATA] = 0x1fc,
|
||||
[IPROC_PCIE_INTX_EN] = 0x330,
|
||||
[IPROC_PCIE_OARR0] = 0xd20,
|
||||
[IPROC_PCIE_OMAP0] = 0xd40,
|
||||
[IPROC_PCIE_OARR1] = 0xd28,
|
||||
[IPROC_PCIE_OMAP1] = 0xd48,
|
||||
[IPROC_PCIE_LINK_STATUS] = 0xf0c,
|
||||
[IPROC_PCIE_APB_ERR_EN] = 0xf40,
|
||||
[IPROC_PCIE_CLK_CTRL] = 0x000,
|
||||
[IPROC_PCIE_CFG_IND_ADDR] = 0x120,
|
||||
[IPROC_PCIE_CFG_IND_DATA] = 0x124,
|
||||
[IPROC_PCIE_CFG_ADDR] = 0x1f8,
|
||||
[IPROC_PCIE_CFG_DATA] = 0x1fc,
|
||||
[IPROC_PCIE_INTX_EN] = 0x330,
|
||||
[IPROC_PCIE_OARR0] = 0xd20,
|
||||
[IPROC_PCIE_OMAP0] = 0xd40,
|
||||
[IPROC_PCIE_OARR1] = 0xd28,
|
||||
[IPROC_PCIE_OMAP1] = 0xd48,
|
||||
[IPROC_PCIE_LINK_STATUS] = 0xf0c,
|
||||
[IPROC_PCIE_APB_ERR_EN] = 0xf40,
|
||||
};
|
||||
|
||||
/* iProc PCIe PAXB v2 registers */
|
||||
static const u16 iproc_pcie_reg_paxb_v2[] = {
|
||||
[IPROC_PCIE_CLK_CTRL] = 0x000,
|
||||
[IPROC_PCIE_CFG_IND_ADDR] = 0x120,
|
||||
[IPROC_PCIE_CFG_IND_DATA] = 0x124,
|
||||
[IPROC_PCIE_CFG_ADDR] = 0x1f8,
|
||||
[IPROC_PCIE_CFG_DATA] = 0x1fc,
|
||||
[IPROC_PCIE_INTX_EN] = 0x330,
|
||||
[IPROC_PCIE_OARR0] = 0xd20,
|
||||
[IPROC_PCIE_OMAP0] = 0xd40,
|
||||
[IPROC_PCIE_OARR1] = 0xd28,
|
||||
[IPROC_PCIE_OMAP1] = 0xd48,
|
||||
[IPROC_PCIE_OARR2] = 0xd60,
|
||||
[IPROC_PCIE_OMAP2] = 0xd68,
|
||||
[IPROC_PCIE_OARR3] = 0xdf0,
|
||||
[IPROC_PCIE_OMAP3] = 0xdf8,
|
||||
[IPROC_PCIE_IARR0] = 0xd00,
|
||||
[IPROC_PCIE_IMAP0] = 0xc00,
|
||||
[IPROC_PCIE_IARR2] = 0xd10,
|
||||
[IPROC_PCIE_IMAP2] = 0xcc0,
|
||||
[IPROC_PCIE_IARR3] = 0xe00,
|
||||
[IPROC_PCIE_IMAP3] = 0xe08,
|
||||
[IPROC_PCIE_IARR4] = 0xe68,
|
||||
[IPROC_PCIE_IMAP4] = 0xe70,
|
||||
[IPROC_PCIE_LINK_STATUS] = 0xf0c,
|
||||
[IPROC_PCIE_APB_ERR_EN] = 0xf40,
|
||||
[IPROC_PCIE_CLK_CTRL] = 0x000,
|
||||
[IPROC_PCIE_CFG_IND_ADDR] = 0x120,
|
||||
[IPROC_PCIE_CFG_IND_DATA] = 0x124,
|
||||
[IPROC_PCIE_CFG_ADDR] = 0x1f8,
|
||||
[IPROC_PCIE_CFG_DATA] = 0x1fc,
|
||||
[IPROC_PCIE_INTX_EN] = 0x330,
|
||||
[IPROC_PCIE_OARR0] = 0xd20,
|
||||
[IPROC_PCIE_OMAP0] = 0xd40,
|
||||
[IPROC_PCIE_OARR1] = 0xd28,
|
||||
[IPROC_PCIE_OMAP1] = 0xd48,
|
||||
[IPROC_PCIE_OARR2] = 0xd60,
|
||||
[IPROC_PCIE_OMAP2] = 0xd68,
|
||||
[IPROC_PCIE_OARR3] = 0xdf0,
|
||||
[IPROC_PCIE_OMAP3] = 0xdf8,
|
||||
[IPROC_PCIE_IARR0] = 0xd00,
|
||||
[IPROC_PCIE_IMAP0] = 0xc00,
|
||||
[IPROC_PCIE_IARR2] = 0xd10,
|
||||
[IPROC_PCIE_IMAP2] = 0xcc0,
|
||||
[IPROC_PCIE_IARR3] = 0xe00,
|
||||
[IPROC_PCIE_IMAP3] = 0xe08,
|
||||
[IPROC_PCIE_IARR4] = 0xe68,
|
||||
[IPROC_PCIE_IMAP4] = 0xe70,
|
||||
[IPROC_PCIE_LINK_STATUS] = 0xf0c,
|
||||
[IPROC_PCIE_APB_ERR_EN] = 0xf40,
|
||||
};
|
||||
|
||||
/* iProc PCIe PAXC v1 registers */
|
||||
static const u16 iproc_pcie_reg_paxc[] = {
|
||||
[IPROC_PCIE_CLK_CTRL] = 0x000,
|
||||
[IPROC_PCIE_CFG_IND_ADDR] = 0x1f0,
|
||||
[IPROC_PCIE_CFG_IND_DATA] = 0x1f4,
|
||||
[IPROC_PCIE_CFG_ADDR] = 0x1f8,
|
||||
[IPROC_PCIE_CFG_DATA] = 0x1fc,
|
||||
[IPROC_PCIE_CLK_CTRL] = 0x000,
|
||||
[IPROC_PCIE_CFG_IND_ADDR] = 0x1f0,
|
||||
[IPROC_PCIE_CFG_IND_DATA] = 0x1f4,
|
||||
[IPROC_PCIE_CFG_ADDR] = 0x1f8,
|
||||
[IPROC_PCIE_CFG_DATA] = 0x1fc,
|
||||
};
|
||||
|
||||
/* iProc PCIe PAXC v2 registers */
|
||||
static const u16 iproc_pcie_reg_paxc_v2[] = {
|
||||
[IPROC_PCIE_MSI_GIC_MODE] = 0x050,
|
||||
[IPROC_PCIE_MSI_BASE_ADDR] = 0x074,
|
||||
[IPROC_PCIE_MSI_WINDOW_SIZE] = 0x078,
|
||||
[IPROC_PCIE_MSI_ADDR_LO] = 0x07c,
|
||||
[IPROC_PCIE_MSI_ADDR_HI] = 0x080,
|
||||
[IPROC_PCIE_MSI_EN_CFG] = 0x09c,
|
||||
[IPROC_PCIE_CFG_IND_ADDR] = 0x1f0,
|
||||
[IPROC_PCIE_CFG_IND_DATA] = 0x1f4,
|
||||
[IPROC_PCIE_CFG_ADDR] = 0x1f8,
|
||||
[IPROC_PCIE_CFG_DATA] = 0x1fc,
|
||||
[IPROC_PCIE_MSI_GIC_MODE] = 0x050,
|
||||
[IPROC_PCIE_MSI_BASE_ADDR] = 0x074,
|
||||
[IPROC_PCIE_MSI_WINDOW_SIZE] = 0x078,
|
||||
[IPROC_PCIE_MSI_ADDR_LO] = 0x07c,
|
||||
[IPROC_PCIE_MSI_ADDR_HI] = 0x080,
|
||||
[IPROC_PCIE_MSI_EN_CFG] = 0x09c,
|
||||
[IPROC_PCIE_CFG_IND_ADDR] = 0x1f0,
|
||||
[IPROC_PCIE_CFG_IND_DATA] = 0x1f4,
|
||||
[IPROC_PCIE_CFG_ADDR] = 0x1f8,
|
||||
[IPROC_PCIE_CFG_DATA] = 0x1fc,
|
||||
};
|
||||
|
||||
static inline struct iproc_pcie *iproc_data(struct pci_bus *bus)
|
||||
|
@ -448,18 +451,112 @@ 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,
|
||||
unsigned int busno,
|
||||
unsigned int slot,
|
||||
unsigned int fn,
|
||||
int where)
|
||||
{
|
||||
u16 offset;
|
||||
u32 val;
|
||||
|
||||
/* EP device access */
|
||||
val = (busno << CFG_ADDR_BUS_NUM_SHIFT) |
|
||||
(slot << CFG_ADDR_DEV_NUM_SHIFT) |
|
||||
(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);
|
||||
offset = iproc_pcie_reg_offset(pcie, IPROC_PCIE_CFG_DATA);
|
||||
|
||||
if (iproc_pcie_reg_is_invalid(offset))
|
||||
return NULL;
|
||||
|
||||
return (pcie->base + offset);
|
||||
}
|
||||
|
||||
static unsigned int iproc_pcie_cfg_retry(void __iomem *cfg_data_p)
|
||||
{
|
||||
int timeout = CFG_RETRY_STATUS_TIMEOUT_US;
|
||||
unsigned int data;
|
||||
|
||||
/*
|
||||
* As per PCIe spec r3.1, sec 2.3.2, CRS Software Visibility only
|
||||
* affects config reads of the Vendor ID. For config writes or any
|
||||
* other config reads, the Root may automatically reissue the
|
||||
* configuration request again as a new request.
|
||||
*
|
||||
* For config reads, this hardware returns CFG_RETRY_STATUS data
|
||||
* when it receives a CRS completion, regardless of the address of
|
||||
* the read or the CRS Software Visibility Enable bit. As a
|
||||
* partial workaround for this, we retry in software any read that
|
||||
* returns CFG_RETRY_STATUS.
|
||||
*
|
||||
* Note that a non-Vendor ID config register may have a value of
|
||||
* CFG_RETRY_STATUS. If we read that, we can't distinguish it from
|
||||
* a CRS completion, so we will incorrectly retry the read and
|
||||
* eventually return the wrong data (0xffffffff).
|
||||
*/
|
||||
data = readl(cfg_data_p);
|
||||
while (data == CFG_RETRY_STATUS && timeout--) {
|
||||
udelay(1);
|
||||
data = readl(cfg_data_p);
|
||||
}
|
||||
|
||||
if (data == CFG_RETRY_STATUS)
|
||||
data = 0xffffffff;
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
static int iproc_pcie_config_read(struct pci_bus *bus, unsigned int devfn,
|
||||
int where, int size, u32 *val)
|
||||
{
|
||||
struct iproc_pcie *pcie = iproc_data(bus);
|
||||
unsigned int slot = PCI_SLOT(devfn);
|
||||
unsigned int fn = PCI_FUNC(devfn);
|
||||
unsigned int busno = bus->number;
|
||||
void __iomem *cfg_data_p;
|
||||
unsigned int data;
|
||||
int ret;
|
||||
|
||||
/* root complex access */
|
||||
if (busno == 0) {
|
||||
ret = pci_generic_config_read32(bus, devfn, where, size, val);
|
||||
if (ret != PCIBIOS_SUCCESSFUL)
|
||||
return ret;
|
||||
|
||||
/* Don't advertise CRS SV support */
|
||||
if ((where & ~0x3) == IPROC_PCI_EXP_CAP + PCI_EXP_RTCTL)
|
||||
*val &= ~(PCI_EXP_RTCAP_CRSVIS << 16);
|
||||
return PCIBIOS_SUCCESSFUL;
|
||||
}
|
||||
|
||||
cfg_data_p = iproc_pcie_map_ep_cfg_reg(pcie, busno, slot, fn, where);
|
||||
|
||||
if (!cfg_data_p)
|
||||
return PCIBIOS_DEVICE_NOT_FOUND;
|
||||
|
||||
data = iproc_pcie_cfg_retry(cfg_data_p);
|
||||
|
||||
*val = data;
|
||||
if (size <= 2)
|
||||
*val = (data >> (8 * (where & 3))) & ((1 << (size * 8)) - 1);
|
||||
|
||||
return PCIBIOS_SUCCESSFUL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Note access to the configuration registers are protected at the higher layer
|
||||
* by 'pci_lock' in drivers/pci/access.c
|
||||
*/
|
||||
static void __iomem *iproc_pcie_map_cfg_bus(struct iproc_pcie *pcie,
|
||||
int busno,
|
||||
unsigned int devfn,
|
||||
int busno, unsigned int devfn,
|
||||
int where)
|
||||
{
|
||||
unsigned slot = PCI_SLOT(devfn);
|
||||
unsigned fn = PCI_FUNC(devfn);
|
||||
u32 val;
|
||||
u16 offset;
|
||||
|
||||
/* root complex access */
|
||||
|
@ -484,18 +581,7 @@ static void __iomem *iproc_pcie_map_cfg_bus(struct iproc_pcie *pcie,
|
|||
if (slot > 0)
|
||||
return NULL;
|
||||
|
||||
/* EP device access */
|
||||
val = (busno << CFG_ADDR_BUS_NUM_SHIFT) |
|
||||
(slot << CFG_ADDR_DEV_NUM_SHIFT) |
|
||||
(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);
|
||||
offset = iproc_pcie_reg_offset(pcie, IPROC_PCIE_CFG_DATA);
|
||||
if (iproc_pcie_reg_is_invalid(offset))
|
||||
return NULL;
|
||||
else
|
||||
return (pcie->base + offset);
|
||||
return iproc_pcie_map_ep_cfg_reg(pcie, busno, slot, fn, where);
|
||||
}
|
||||
|
||||
static void __iomem *iproc_pcie_bus_map_cfg_bus(struct pci_bus *bus,
|
||||
|
@ -554,9 +640,13 @@ static int iproc_pcie_config_read32(struct pci_bus *bus, unsigned int devfn,
|
|||
int where, int size, u32 *val)
|
||||
{
|
||||
int ret;
|
||||
struct iproc_pcie *pcie = iproc_data(bus);
|
||||
|
||||
iproc_pcie_apb_err_disable(bus, true);
|
||||
ret = pci_generic_config_read32(bus, devfn, where, size, val);
|
||||
if (pcie->type == IPROC_PCIE_PAXB_V2)
|
||||
ret = iproc_pcie_config_read(bus, devfn, where, size, val);
|
||||
else
|
||||
ret = pci_generic_config_read32(bus, devfn, where, size, val);
|
||||
iproc_pcie_apb_err_disable(bus, false);
|
||||
|
||||
return ret;
|
||||
|
@ -580,7 +670,7 @@ static struct pci_ops iproc_pcie_ops = {
|
|||
.write = iproc_pcie_config_write32,
|
||||
};
|
||||
|
||||
static void iproc_pcie_reset(struct iproc_pcie *pcie)
|
||||
static void iproc_pcie_perst_ctrl(struct iproc_pcie *pcie, bool assert)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
|
@ -592,26 +682,33 @@ static void iproc_pcie_reset(struct iproc_pcie *pcie)
|
|||
if (pcie->ep_is_internal)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Select perst_b signal as reset source. Put the device into reset,
|
||||
* and then bring it out of reset
|
||||
*/
|
||||
val = iproc_pcie_read_reg(pcie, IPROC_PCIE_CLK_CTRL);
|
||||
val &= ~EP_PERST_SOURCE_SELECT & ~EP_MODE_SURVIVE_PERST &
|
||||
~RC_PCIE_RST_OUTPUT;
|
||||
iproc_pcie_write_reg(pcie, IPROC_PCIE_CLK_CTRL, val);
|
||||
udelay(250);
|
||||
|
||||
val |= RC_PCIE_RST_OUTPUT;
|
||||
iproc_pcie_write_reg(pcie, IPROC_PCIE_CLK_CTRL, val);
|
||||
msleep(100);
|
||||
if (assert) {
|
||||
val = iproc_pcie_read_reg(pcie, IPROC_PCIE_CLK_CTRL);
|
||||
val &= ~EP_PERST_SOURCE_SELECT & ~EP_MODE_SURVIVE_PERST &
|
||||
~RC_PCIE_RST_OUTPUT;
|
||||
iproc_pcie_write_reg(pcie, IPROC_PCIE_CLK_CTRL, val);
|
||||
udelay(250);
|
||||
} else {
|
||||
val = iproc_pcie_read_reg(pcie, IPROC_PCIE_CLK_CTRL);
|
||||
val |= RC_PCIE_RST_OUTPUT;
|
||||
iproc_pcie_write_reg(pcie, IPROC_PCIE_CLK_CTRL, val);
|
||||
msleep(100);
|
||||
}
|
||||
}
|
||||
|
||||
int iproc_pcie_shutdown(struct iproc_pcie *pcie)
|
||||
{
|
||||
iproc_pcie_perst_ctrl(pcie, true);
|
||||
msleep(500);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(iproc_pcie_shutdown);
|
||||
|
||||
static int iproc_pcie_check_link(struct iproc_pcie *pcie)
|
||||
{
|
||||
struct device *dev = pcie->dev;
|
||||
u32 hdr_type, link_ctrl, link_status, class, val;
|
||||
u16 pos = PCI_EXP_CAP;
|
||||
bool link_is_active = false;
|
||||
|
||||
/*
|
||||
|
@ -628,16 +725,16 @@ static int iproc_pcie_check_link(struct iproc_pcie *pcie)
|
|||
}
|
||||
|
||||
/* make sure we are not in EP mode */
|
||||
iproc_pci_raw_config_read32(pcie, 0, PCI_HEADER_TYPE, 1, &hdr_type);
|
||||
iproc_pci_raw_config_read32(pcie, 0, PCI_HEADER_TYPE, 1, &hdr_type);
|
||||
if ((hdr_type & 0x7f) != PCI_HEADER_TYPE_BRIDGE) {
|
||||
dev_err(dev, "in EP mode, hdr=%#02x\n", hdr_type);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
/* force class to PCI_CLASS_BRIDGE_PCI (0x0604) */
|
||||
#define PCI_BRIDGE_CTRL_REG_OFFSET 0x43c
|
||||
#define PCI_CLASS_BRIDGE_MASK 0xffff00
|
||||
#define PCI_CLASS_BRIDGE_SHIFT 8
|
||||
#define PCI_BRIDGE_CTRL_REG_OFFSET 0x43c
|
||||
#define PCI_CLASS_BRIDGE_MASK 0xffff00
|
||||
#define PCI_CLASS_BRIDGE_SHIFT 8
|
||||
iproc_pci_raw_config_read32(pcie, 0, PCI_BRIDGE_CTRL_REG_OFFSET,
|
||||
4, &class);
|
||||
class &= ~PCI_CLASS_BRIDGE_MASK;
|
||||
|
@ -646,31 +743,31 @@ static int iproc_pcie_check_link(struct iproc_pcie *pcie)
|
|||
4, class);
|
||||
|
||||
/* check link status to see if link is active */
|
||||
iproc_pci_raw_config_read32(pcie, 0, pos + PCI_EXP_LNKSTA,
|
||||
iproc_pci_raw_config_read32(pcie, 0, IPROC_PCI_EXP_CAP + PCI_EXP_LNKSTA,
|
||||
2, &link_status);
|
||||
if (link_status & PCI_EXP_LNKSTA_NLW)
|
||||
link_is_active = true;
|
||||
|
||||
if (!link_is_active) {
|
||||
/* try GEN 1 link speed */
|
||||
#define PCI_TARGET_LINK_SPEED_MASK 0xf
|
||||
#define PCI_TARGET_LINK_SPEED_GEN2 0x2
|
||||
#define PCI_TARGET_LINK_SPEED_GEN1 0x1
|
||||
#define PCI_TARGET_LINK_SPEED_MASK 0xf
|
||||
#define PCI_TARGET_LINK_SPEED_GEN2 0x2
|
||||
#define PCI_TARGET_LINK_SPEED_GEN1 0x1
|
||||
iproc_pci_raw_config_read32(pcie, 0,
|
||||
pos + PCI_EXP_LNKCTL2, 4,
|
||||
&link_ctrl);
|
||||
IPROC_PCI_EXP_CAP + PCI_EXP_LNKCTL2,
|
||||
4, &link_ctrl);
|
||||
if ((link_ctrl & PCI_TARGET_LINK_SPEED_MASK) ==
|
||||
PCI_TARGET_LINK_SPEED_GEN2) {
|
||||
link_ctrl &= ~PCI_TARGET_LINK_SPEED_MASK;
|
||||
link_ctrl |= PCI_TARGET_LINK_SPEED_GEN1;
|
||||
iproc_pci_raw_config_write32(pcie, 0,
|
||||
pos + PCI_EXP_LNKCTL2,
|
||||
4, link_ctrl);
|
||||
IPROC_PCI_EXP_CAP + PCI_EXP_LNKCTL2,
|
||||
4, link_ctrl);
|
||||
msleep(100);
|
||||
|
||||
iproc_pci_raw_config_read32(pcie, 0,
|
||||
pos + PCI_EXP_LNKSTA,
|
||||
2, &link_status);
|
||||
IPROC_PCI_EXP_CAP + PCI_EXP_LNKSTA,
|
||||
2, &link_status);
|
||||
if (link_status & PCI_EXP_LNKSTA_NLW)
|
||||
link_is_active = true;
|
||||
}
|
||||
|
@ -1223,6 +1320,8 @@ static int iproc_pcie_rev_init(struct iproc_pcie *pcie)
|
|||
pcie->ib.nr_regions = ARRAY_SIZE(paxb_v2_ib_map);
|
||||
pcie->ib_map = paxb_v2_ib_map;
|
||||
pcie->need_msi_steer = true;
|
||||
dev_warn(dev, "reads of config registers that contain %#x return incorrect data\n",
|
||||
CFG_RETRY_STATUS);
|
||||
break;
|
||||
case IPROC_PCIE_PAXC:
|
||||
regs = iproc_pcie_reg_paxc;
|
||||
|
@ -1286,7 +1385,8 @@ int iproc_pcie_setup(struct iproc_pcie *pcie, struct list_head *res)
|
|||
goto err_exit_phy;
|
||||
}
|
||||
|
||||
iproc_pcie_reset(pcie);
|
||||
iproc_pcie_perst_ctrl(pcie, true);
|
||||
iproc_pcie_perst_ctrl(pcie, false);
|
||||
|
||||
if (pcie->need_ob_cfg) {
|
||||
ret = iproc_pcie_map_ranges(pcie, res);
|
||||
|
|
|
@ -110,6 +110,7 @@ struct iproc_pcie {
|
|||
|
||||
int iproc_pcie_setup(struct iproc_pcie *pcie, struct list_head *res);
|
||||
int iproc_pcie_remove(struct iproc_pcie *pcie);
|
||||
int iproc_pcie_shutdown(struct iproc_pcie *pcie);
|
||||
|
||||
#ifdef CONFIG_PCIE_IPROC_MSI
|
||||
int iproc_msi_init(struct iproc_pcie *pcie, struct device_node *node);
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
*
|
||||
* Copyright (c) 2017 MediaTek Inc.
|
||||
* Author: Ryder Lee <ryder.lee@mediatek.com>
|
||||
* Honghui Zhang <honghui.zhang@mediatek.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
|
@ -16,6 +17,9 @@
|
|||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_pci.h>
|
||||
|
@ -63,16 +67,104 @@
|
|||
#define PCIE_FC_CREDIT_MASK (GENMASK(31, 31) | GENMASK(28, 16))
|
||||
#define PCIE_FC_CREDIT_VAL(x) ((x) << 16)
|
||||
|
||||
/* PCIe V2 share registers */
|
||||
#define PCIE_SYS_CFG_V2 0x0
|
||||
#define PCIE_CSR_LTSSM_EN(x) BIT(0 + (x) * 8)
|
||||
#define PCIE_CSR_ASPM_L1_EN(x) BIT(1 + (x) * 8)
|
||||
|
||||
/* PCIe V2 per-port registers */
|
||||
#define PCIE_MSI_VECTOR 0x0c0
|
||||
#define PCIE_INT_MASK 0x420
|
||||
#define INTX_MASK GENMASK(19, 16)
|
||||
#define INTX_SHIFT 16
|
||||
#define PCIE_INT_STATUS 0x424
|
||||
#define MSI_STATUS BIT(23)
|
||||
#define PCIE_IMSI_STATUS 0x42c
|
||||
#define PCIE_IMSI_ADDR 0x430
|
||||
#define MSI_MASK BIT(23)
|
||||
#define MTK_MSI_IRQS_NUM 32
|
||||
|
||||
#define PCIE_AHB_TRANS_BASE0_L 0x438
|
||||
#define PCIE_AHB_TRANS_BASE0_H 0x43c
|
||||
#define AHB2PCIE_SIZE(x) ((x) & GENMASK(4, 0))
|
||||
#define PCIE_AXI_WINDOW0 0x448
|
||||
#define WIN_ENABLE BIT(7)
|
||||
|
||||
/* PCIe V2 configuration transaction header */
|
||||
#define PCIE_CFG_HEADER0 0x460
|
||||
#define PCIE_CFG_HEADER1 0x464
|
||||
#define PCIE_CFG_HEADER2 0x468
|
||||
#define PCIE_CFG_WDATA 0x470
|
||||
#define PCIE_APP_TLP_REQ 0x488
|
||||
#define PCIE_CFG_RDATA 0x48c
|
||||
#define APP_CFG_REQ BIT(0)
|
||||
#define APP_CPL_STATUS GENMASK(7, 5)
|
||||
|
||||
#define CFG_WRRD_TYPE_0 4
|
||||
#define CFG_WR_FMT 2
|
||||
#define CFG_RD_FMT 0
|
||||
|
||||
#define CFG_DW0_LENGTH(length) ((length) & GENMASK(9, 0))
|
||||
#define CFG_DW0_TYPE(type) (((type) << 24) & GENMASK(28, 24))
|
||||
#define CFG_DW0_FMT(fmt) (((fmt) << 29) & GENMASK(31, 29))
|
||||
#define CFG_DW2_REGN(regn) ((regn) & GENMASK(11, 2))
|
||||
#define CFG_DW2_FUN(fun) (((fun) << 16) & GENMASK(18, 16))
|
||||
#define CFG_DW2_DEV(dev) (((dev) << 19) & GENMASK(23, 19))
|
||||
#define CFG_DW2_BUS(bus) (((bus) << 24) & GENMASK(31, 24))
|
||||
#define CFG_HEADER_DW0(type, fmt) \
|
||||
(CFG_DW0_LENGTH(1) | CFG_DW0_TYPE(type) | CFG_DW0_FMT(fmt))
|
||||
#define CFG_HEADER_DW1(where, size) \
|
||||
(GENMASK(((size) - 1), 0) << ((where) & 0x3))
|
||||
#define CFG_HEADER_DW2(regn, fun, dev, bus) \
|
||||
(CFG_DW2_REGN(regn) | CFG_DW2_FUN(fun) | \
|
||||
CFG_DW2_DEV(dev) | CFG_DW2_BUS(bus))
|
||||
|
||||
#define PCIE_RST_CTRL 0x510
|
||||
#define PCIE_PHY_RSTB BIT(0)
|
||||
#define PCIE_PIPE_SRSTB BIT(1)
|
||||
#define PCIE_MAC_SRSTB BIT(2)
|
||||
#define PCIE_CRSTB BIT(3)
|
||||
#define PCIE_PERSTB BIT(8)
|
||||
#define PCIE_LINKDOWN_RST_EN GENMASK(15, 13)
|
||||
#define PCIE_LINK_STATUS_V2 0x804
|
||||
#define PCIE_PORT_LINKUP_V2 BIT(10)
|
||||
|
||||
struct mtk_pcie_port;
|
||||
|
||||
/**
|
||||
* struct mtk_pcie_soc - differentiate between host generations
|
||||
* @has_msi: whether this host supports MSI interrupts or not
|
||||
* @ops: pointer to configuration access functions
|
||||
* @startup: pointer to controller setting functions
|
||||
* @setup_irq: pointer to initialize IRQ functions
|
||||
*/
|
||||
struct mtk_pcie_soc {
|
||||
bool has_msi;
|
||||
struct pci_ops *ops;
|
||||
int (*startup)(struct mtk_pcie_port *port);
|
||||
int (*setup_irq)(struct mtk_pcie_port *port, struct device_node *node);
|
||||
};
|
||||
|
||||
/**
|
||||
* struct mtk_pcie_port - PCIe port information
|
||||
* @base: IO mapped register base
|
||||
* @list: port list
|
||||
* @pcie: pointer to PCIe host info
|
||||
* @reset: pointer to port reset control
|
||||
* @sys_ck: pointer to bus clock
|
||||
* @phy: pointer to phy control block
|
||||
* @sys_ck: pointer to transaction/data link layer clock
|
||||
* @ahb_ck: pointer to AHB slave interface operating clock for CSR access
|
||||
* and RC initiated MMIO access
|
||||
* @axi_ck: pointer to application layer MMIO channel operating clock
|
||||
* @aux_ck: pointer to pe2_mac_bridge and pe2_mac_core operating clock
|
||||
* when pcie_mac_ck/pcie_pipe_ck is turned off
|
||||
* @obff_ck: pointer to OBFF functional block operating clock
|
||||
* @pipe_ck: pointer to LTSSM and PHY/MAC layer operating clock
|
||||
* @phy: pointer to PHY control block
|
||||
* @lane: lane count
|
||||
* @index: port index
|
||||
* @slot: port slot
|
||||
* @irq_domain: legacy INTx IRQ domain
|
||||
* @msi_domain: MSI IRQ domain
|
||||
* @msi_irq_in_use: bit map for assigned MSI IRQ
|
||||
*/
|
||||
struct mtk_pcie_port {
|
||||
void __iomem *base;
|
||||
|
@ -80,9 +172,17 @@ struct mtk_pcie_port {
|
|||
struct mtk_pcie *pcie;
|
||||
struct reset_control *reset;
|
||||
struct clk *sys_ck;
|
||||
struct clk *ahb_ck;
|
||||
struct clk *axi_ck;
|
||||
struct clk *aux_ck;
|
||||
struct clk *obff_ck;
|
||||
struct clk *pipe_ck;
|
||||
struct phy *phy;
|
||||
u32 lane;
|
||||
u32 index;
|
||||
u32 slot;
|
||||
struct irq_domain *irq_domain;
|
||||
struct irq_domain *msi_domain;
|
||||
DECLARE_BITMAP(msi_irq_in_use, MTK_MSI_IRQS_NUM);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -96,6 +196,7 @@ struct mtk_pcie_port {
|
|||
* @busn: bus range
|
||||
* @offset: IO / Memory offset
|
||||
* @ports: pointer to PCIe port information
|
||||
* @soc: pointer to SoC-dependent operations
|
||||
*/
|
||||
struct mtk_pcie {
|
||||
struct device *dev;
|
||||
|
@ -111,13 +212,9 @@ struct mtk_pcie {
|
|||
resource_size_t io;
|
||||
} offset;
|
||||
struct list_head ports;
|
||||
const struct mtk_pcie_soc *soc;
|
||||
};
|
||||
|
||||
static inline bool mtk_pcie_link_up(struct mtk_pcie_port *port)
|
||||
{
|
||||
return !!(readl(port->base + PCIE_LINK_STATUS) & PCIE_PORT_LINKUP);
|
||||
}
|
||||
|
||||
static void mtk_pcie_subsys_powerdown(struct mtk_pcie *pcie)
|
||||
{
|
||||
struct device *dev = pcie->dev;
|
||||
|
@ -146,6 +243,12 @@ static void mtk_pcie_put_resources(struct mtk_pcie *pcie)
|
|||
|
||||
list_for_each_entry_safe(port, tmp, &pcie->ports, list) {
|
||||
phy_power_off(port->phy);
|
||||
phy_exit(port->phy);
|
||||
clk_disable_unprepare(port->pipe_ck);
|
||||
clk_disable_unprepare(port->obff_ck);
|
||||
clk_disable_unprepare(port->axi_ck);
|
||||
clk_disable_unprepare(port->aux_ck);
|
||||
clk_disable_unprepare(port->ahb_ck);
|
||||
clk_disable_unprepare(port->sys_ck);
|
||||
mtk_pcie_port_free(port);
|
||||
}
|
||||
|
@ -153,11 +256,412 @@ static void mtk_pcie_put_resources(struct mtk_pcie *pcie)
|
|||
mtk_pcie_subsys_powerdown(pcie);
|
||||
}
|
||||
|
||||
static int mtk_pcie_check_cfg_cpld(struct mtk_pcie_port *port)
|
||||
{
|
||||
u32 val;
|
||||
int err;
|
||||
|
||||
err = readl_poll_timeout_atomic(port->base + PCIE_APP_TLP_REQ, val,
|
||||
!(val & APP_CFG_REQ), 10,
|
||||
100 * USEC_PER_MSEC);
|
||||
if (err)
|
||||
return PCIBIOS_SET_FAILED;
|
||||
|
||||
if (readl(port->base + PCIE_APP_TLP_REQ) & APP_CPL_STATUS)
|
||||
return PCIBIOS_SET_FAILED;
|
||||
|
||||
return PCIBIOS_SUCCESSFUL;
|
||||
}
|
||||
|
||||
static int mtk_pcie_hw_rd_cfg(struct mtk_pcie_port *port, u32 bus, u32 devfn,
|
||||
int where, int size, u32 *val)
|
||||
{
|
||||
u32 tmp;
|
||||
|
||||
/* Write PCIe configuration transaction header for Cfgrd */
|
||||
writel(CFG_HEADER_DW0(CFG_WRRD_TYPE_0, CFG_RD_FMT),
|
||||
port->base + PCIE_CFG_HEADER0);
|
||||
writel(CFG_HEADER_DW1(where, size), port->base + PCIE_CFG_HEADER1);
|
||||
writel(CFG_HEADER_DW2(where, PCI_FUNC(devfn), PCI_SLOT(devfn), bus),
|
||||
port->base + PCIE_CFG_HEADER2);
|
||||
|
||||
/* Trigger h/w to transmit Cfgrd TLP */
|
||||
tmp = readl(port->base + PCIE_APP_TLP_REQ);
|
||||
tmp |= APP_CFG_REQ;
|
||||
writel(tmp, port->base + PCIE_APP_TLP_REQ);
|
||||
|
||||
/* Check completion status */
|
||||
if (mtk_pcie_check_cfg_cpld(port))
|
||||
return PCIBIOS_SET_FAILED;
|
||||
|
||||
/* Read cpld payload of Cfgrd */
|
||||
*val = readl(port->base + PCIE_CFG_RDATA);
|
||||
|
||||
if (size == 1)
|
||||
*val = (*val >> (8 * (where & 3))) & 0xff;
|
||||
else if (size == 2)
|
||||
*val = (*val >> (8 * (where & 3))) & 0xffff;
|
||||
|
||||
return PCIBIOS_SUCCESSFUL;
|
||||
}
|
||||
|
||||
static int mtk_pcie_hw_wr_cfg(struct mtk_pcie_port *port, u32 bus, u32 devfn,
|
||||
int where, int size, u32 val)
|
||||
{
|
||||
/* Write PCIe configuration transaction header for Cfgwr */
|
||||
writel(CFG_HEADER_DW0(CFG_WRRD_TYPE_0, CFG_WR_FMT),
|
||||
port->base + PCIE_CFG_HEADER0);
|
||||
writel(CFG_HEADER_DW1(where, size), port->base + PCIE_CFG_HEADER1);
|
||||
writel(CFG_HEADER_DW2(where, PCI_FUNC(devfn), PCI_SLOT(devfn), bus),
|
||||
port->base + PCIE_CFG_HEADER2);
|
||||
|
||||
/* Write Cfgwr data */
|
||||
val = val << 8 * (where & 3);
|
||||
writel(val, port->base + PCIE_CFG_WDATA);
|
||||
|
||||
/* Trigger h/w to transmit Cfgwr TLP */
|
||||
val = readl(port->base + PCIE_APP_TLP_REQ);
|
||||
val |= APP_CFG_REQ;
|
||||
writel(val, port->base + PCIE_APP_TLP_REQ);
|
||||
|
||||
/* Check completion status */
|
||||
return mtk_pcie_check_cfg_cpld(port);
|
||||
}
|
||||
|
||||
static struct mtk_pcie_port *mtk_pcie_find_port(struct pci_bus *bus,
|
||||
unsigned int devfn)
|
||||
{
|
||||
struct mtk_pcie *pcie = bus->sysdata;
|
||||
struct mtk_pcie_port *port;
|
||||
|
||||
list_for_each_entry(port, &pcie->ports, list)
|
||||
if (port->slot == PCI_SLOT(devfn))
|
||||
return port;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int mtk_pcie_config_read(struct pci_bus *bus, unsigned int devfn,
|
||||
int where, int size, u32 *val)
|
||||
{
|
||||
struct mtk_pcie_port *port;
|
||||
u32 bn = bus->number;
|
||||
int ret;
|
||||
|
||||
port = mtk_pcie_find_port(bus, devfn);
|
||||
if (!port) {
|
||||
*val = ~0;
|
||||
return PCIBIOS_DEVICE_NOT_FOUND;
|
||||
}
|
||||
|
||||
ret = mtk_pcie_hw_rd_cfg(port, bn, devfn, where, size, val);
|
||||
if (ret)
|
||||
*val = ~0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mtk_pcie_config_write(struct pci_bus *bus, unsigned int devfn,
|
||||
int where, int size, u32 val)
|
||||
{
|
||||
struct mtk_pcie_port *port;
|
||||
u32 bn = bus->number;
|
||||
|
||||
port = mtk_pcie_find_port(bus, devfn);
|
||||
if (!port)
|
||||
return PCIBIOS_DEVICE_NOT_FOUND;
|
||||
|
||||
return mtk_pcie_hw_wr_cfg(port, bn, devfn, where, size, val);
|
||||
}
|
||||
|
||||
static struct pci_ops mtk_pcie_ops_v2 = {
|
||||
.read = mtk_pcie_config_read,
|
||||
.write = mtk_pcie_config_write,
|
||||
};
|
||||
|
||||
static int mtk_pcie_startup_port_v2(struct mtk_pcie_port *port)
|
||||
{
|
||||
struct mtk_pcie *pcie = port->pcie;
|
||||
struct resource *mem = &pcie->mem;
|
||||
u32 val;
|
||||
size_t size;
|
||||
int err;
|
||||
|
||||
/* MT7622 platforms need to enable LTSSM and ASPM from PCIe subsys */
|
||||
if (pcie->base) {
|
||||
val = readl(pcie->base + PCIE_SYS_CFG_V2);
|
||||
val |= PCIE_CSR_LTSSM_EN(port->slot) |
|
||||
PCIE_CSR_ASPM_L1_EN(port->slot);
|
||||
writel(val, pcie->base + PCIE_SYS_CFG_V2);
|
||||
}
|
||||
|
||||
/* Assert all reset signals */
|
||||
writel(0, port->base + PCIE_RST_CTRL);
|
||||
|
||||
/*
|
||||
* Enable PCIe link down reset, if link status changed from link up to
|
||||
* link down, this will reset MAC control registers and configuration
|
||||
* space.
|
||||
*/
|
||||
writel(PCIE_LINKDOWN_RST_EN, port->base + PCIE_RST_CTRL);
|
||||
|
||||
/* De-assert PHY, PE, PIPE, MAC and configuration reset */
|
||||
val = readl(port->base + PCIE_RST_CTRL);
|
||||
val |= PCIE_PHY_RSTB | PCIE_PERSTB | PCIE_PIPE_SRSTB |
|
||||
PCIE_MAC_SRSTB | PCIE_CRSTB;
|
||||
writel(val, port->base + PCIE_RST_CTRL);
|
||||
|
||||
/* 100ms timeout value should be enough for Gen1/2 training */
|
||||
err = readl_poll_timeout(port->base + PCIE_LINK_STATUS_V2, val,
|
||||
!!(val & PCIE_PORT_LINKUP_V2), 20,
|
||||
100 * USEC_PER_MSEC);
|
||||
if (err)
|
||||
return -ETIMEDOUT;
|
||||
|
||||
/* Set INTx mask */
|
||||
val = readl(port->base + PCIE_INT_MASK);
|
||||
val &= ~INTX_MASK;
|
||||
writel(val, port->base + PCIE_INT_MASK);
|
||||
|
||||
/* Set AHB to PCIe translation windows */
|
||||
size = mem->end - mem->start;
|
||||
val = lower_32_bits(mem->start) | AHB2PCIE_SIZE(fls(size));
|
||||
writel(val, port->base + PCIE_AHB_TRANS_BASE0_L);
|
||||
|
||||
val = upper_32_bits(mem->start);
|
||||
writel(val, port->base + PCIE_AHB_TRANS_BASE0_H);
|
||||
|
||||
/* Set PCIe to AXI translation memory space.*/
|
||||
val = fls(0xffffffff) | WIN_ENABLE;
|
||||
writel(val, port->base + PCIE_AXI_WINDOW0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mtk_pcie_msi_alloc(struct mtk_pcie_port *port)
|
||||
{
|
||||
int msi;
|
||||
|
||||
msi = find_first_zero_bit(port->msi_irq_in_use, MTK_MSI_IRQS_NUM);
|
||||
if (msi < MTK_MSI_IRQS_NUM)
|
||||
set_bit(msi, port->msi_irq_in_use);
|
||||
else
|
||||
return -ENOSPC;
|
||||
|
||||
return msi;
|
||||
}
|
||||
|
||||
static void mtk_pcie_msi_free(struct mtk_pcie_port *port, unsigned long hwirq)
|
||||
{
|
||||
clear_bit(hwirq, port->msi_irq_in_use);
|
||||
}
|
||||
|
||||
static int mtk_pcie_msi_setup_irq(struct msi_controller *chip,
|
||||
struct pci_dev *pdev, struct msi_desc *desc)
|
||||
{
|
||||
struct mtk_pcie_port *port;
|
||||
struct msi_msg msg;
|
||||
unsigned int irq;
|
||||
int hwirq;
|
||||
phys_addr_t msg_addr;
|
||||
|
||||
port = mtk_pcie_find_port(pdev->bus, pdev->devfn);
|
||||
if (!port)
|
||||
return -EINVAL;
|
||||
|
||||
hwirq = mtk_pcie_msi_alloc(port);
|
||||
if (hwirq < 0)
|
||||
return hwirq;
|
||||
|
||||
irq = irq_create_mapping(port->msi_domain, hwirq);
|
||||
if (!irq) {
|
||||
mtk_pcie_msi_free(port, hwirq);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
chip->dev = &pdev->dev;
|
||||
|
||||
irq_set_msi_desc(irq, desc);
|
||||
|
||||
/* MT2712/MT7622 only support 32-bit MSI addresses */
|
||||
msg_addr = virt_to_phys(port->base + PCIE_MSI_VECTOR);
|
||||
msg.address_hi = 0;
|
||||
msg.address_lo = lower_32_bits(msg_addr);
|
||||
msg.data = hwirq;
|
||||
|
||||
pci_write_msi_msg(irq, &msg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mtk_msi_teardown_irq(struct msi_controller *chip, unsigned int irq)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(chip->dev);
|
||||
struct irq_data *d = irq_get_irq_data(irq);
|
||||
irq_hw_number_t hwirq = irqd_to_hwirq(d);
|
||||
struct mtk_pcie_port *port;
|
||||
|
||||
port = mtk_pcie_find_port(pdev->bus, pdev->devfn);
|
||||
if (!port)
|
||||
return;
|
||||
|
||||
irq_dispose_mapping(irq);
|
||||
mtk_pcie_msi_free(port, hwirq);
|
||||
}
|
||||
|
||||
static struct msi_controller mtk_pcie_msi_chip = {
|
||||
.setup_irq = mtk_pcie_msi_setup_irq,
|
||||
.teardown_irq = mtk_msi_teardown_irq,
|
||||
};
|
||||
|
||||
static struct irq_chip mtk_msi_irq_chip = {
|
||||
.name = "MTK PCIe MSI",
|
||||
.irq_enable = pci_msi_unmask_irq,
|
||||
.irq_disable = pci_msi_mask_irq,
|
||||
.irq_mask = pci_msi_mask_irq,
|
||||
.irq_unmask = pci_msi_unmask_irq,
|
||||
};
|
||||
|
||||
static int mtk_pcie_msi_map(struct irq_domain *domain, unsigned int irq,
|
||||
irq_hw_number_t hwirq)
|
||||
{
|
||||
irq_set_chip_and_handler(irq, &mtk_msi_irq_chip, handle_simple_irq);
|
||||
irq_set_chip_data(irq, domain->host_data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct irq_domain_ops msi_domain_ops = {
|
||||
.map = mtk_pcie_msi_map,
|
||||
};
|
||||
|
||||
static void mtk_pcie_enable_msi(struct mtk_pcie_port *port)
|
||||
{
|
||||
u32 val;
|
||||
phys_addr_t msg_addr;
|
||||
|
||||
msg_addr = virt_to_phys(port->base + PCIE_MSI_VECTOR);
|
||||
val = lower_32_bits(msg_addr);
|
||||
writel(val, port->base + PCIE_IMSI_ADDR);
|
||||
|
||||
val = readl(port->base + PCIE_INT_MASK);
|
||||
val &= ~MSI_MASK;
|
||||
writel(val, port->base + PCIE_INT_MASK);
|
||||
}
|
||||
|
||||
static int mtk_pcie_intx_map(struct irq_domain *domain, unsigned int irq,
|
||||
irq_hw_number_t hwirq)
|
||||
{
|
||||
irq_set_chip_and_handler(irq, &dummy_irq_chip, handle_simple_irq);
|
||||
irq_set_chip_data(irq, domain->host_data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct irq_domain_ops intx_domain_ops = {
|
||||
.map = mtk_pcie_intx_map,
|
||||
};
|
||||
|
||||
static int mtk_pcie_init_irq_domain(struct mtk_pcie_port *port,
|
||||
struct device_node *node)
|
||||
{
|
||||
struct device *dev = port->pcie->dev;
|
||||
struct device_node *pcie_intc_node;
|
||||
|
||||
/* Setup INTx */
|
||||
pcie_intc_node = of_get_next_child(node, NULL);
|
||||
if (!pcie_intc_node) {
|
||||
dev_err(dev, "no PCIe Intc node found\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
port->irq_domain = irq_domain_add_linear(pcie_intc_node, PCI_NUM_INTX,
|
||||
&intx_domain_ops, port);
|
||||
if (!port->irq_domain) {
|
||||
dev_err(dev, "failed to get INTx IRQ domain\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_PCI_MSI)) {
|
||||
port->msi_domain = irq_domain_add_linear(node, MTK_MSI_IRQS_NUM,
|
||||
&msi_domain_ops,
|
||||
&mtk_pcie_msi_chip);
|
||||
if (!port->msi_domain) {
|
||||
dev_err(dev, "failed to create MSI IRQ domain\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
mtk_pcie_enable_msi(port);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static irqreturn_t mtk_pcie_intr_handler(int irq, void *data)
|
||||
{
|
||||
struct mtk_pcie_port *port = (struct mtk_pcie_port *)data;
|
||||
unsigned long status;
|
||||
u32 virq;
|
||||
u32 bit = INTX_SHIFT;
|
||||
|
||||
while ((status = readl(port->base + PCIE_INT_STATUS)) & INTX_MASK) {
|
||||
for_each_set_bit_from(bit, &status, PCI_NUM_INTX + INTX_SHIFT) {
|
||||
/* Clear the INTx */
|
||||
writel(1 << bit, port->base + PCIE_INT_STATUS);
|
||||
virq = irq_find_mapping(port->irq_domain,
|
||||
bit - INTX_SHIFT);
|
||||
generic_handle_irq(virq);
|
||||
}
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_PCI_MSI)) {
|
||||
while ((status = readl(port->base + PCIE_INT_STATUS)) & MSI_STATUS) {
|
||||
unsigned long imsi_status;
|
||||
|
||||
while ((imsi_status = readl(port->base + PCIE_IMSI_STATUS))) {
|
||||
for_each_set_bit(bit, &imsi_status, MTK_MSI_IRQS_NUM) {
|
||||
/* Clear the MSI */
|
||||
writel(1 << bit, port->base + PCIE_IMSI_STATUS);
|
||||
virq = irq_find_mapping(port->msi_domain, bit);
|
||||
generic_handle_irq(virq);
|
||||
}
|
||||
}
|
||||
/* Clear MSI interrupt status */
|
||||
writel(MSI_STATUS, port->base + PCIE_INT_STATUS);
|
||||
}
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int mtk_pcie_setup_irq(struct mtk_pcie_port *port,
|
||||
struct device_node *node)
|
||||
{
|
||||
struct mtk_pcie *pcie = port->pcie;
|
||||
struct device *dev = pcie->dev;
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
int err, irq;
|
||||
|
||||
irq = platform_get_irq(pdev, port->slot);
|
||||
err = devm_request_irq(dev, irq, mtk_pcie_intr_handler,
|
||||
IRQF_SHARED, "mtk-pcie", port);
|
||||
if (err) {
|
||||
dev_err(dev, "unable to request IRQ %d\n", irq);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = mtk_pcie_init_irq_domain(port, node);
|
||||
if (err) {
|
||||
dev_err(dev, "failed to init PCIe IRQ domain\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __iomem *mtk_pcie_map_bus(struct pci_bus *bus,
|
||||
unsigned int devfn, int where)
|
||||
{
|
||||
struct pci_host_bridge *host = pci_find_host_bridge(bus);
|
||||
struct mtk_pcie *pcie = pci_host_bridge_priv(host);
|
||||
struct mtk_pcie *pcie = bus->sysdata;
|
||||
|
||||
writel(PCIE_CONF_ADDR(where, PCI_FUNC(devfn), PCI_SLOT(devfn),
|
||||
bus->number), pcie->base + PCIE_CFG_ADDR);
|
||||
|
@ -171,16 +675,34 @@ static struct pci_ops mtk_pcie_ops = {
|
|||
.write = pci_generic_config_write,
|
||||
};
|
||||
|
||||
static void mtk_pcie_configure_rc(struct mtk_pcie_port *port)
|
||||
static int mtk_pcie_startup_port(struct mtk_pcie_port *port)
|
||||
{
|
||||
struct mtk_pcie *pcie = port->pcie;
|
||||
u32 func = PCI_FUNC(port->index << 3);
|
||||
u32 slot = PCI_SLOT(port->index << 3);
|
||||
u32 func = PCI_FUNC(port->slot << 3);
|
||||
u32 slot = PCI_SLOT(port->slot << 3);
|
||||
u32 val;
|
||||
int err;
|
||||
|
||||
/* assert port PERST_N */
|
||||
val = readl(pcie->base + PCIE_SYS_CFG);
|
||||
val |= PCIE_PORT_PERST(port->slot);
|
||||
writel(val, pcie->base + PCIE_SYS_CFG);
|
||||
|
||||
/* de-assert port PERST_N */
|
||||
val = readl(pcie->base + PCIE_SYS_CFG);
|
||||
val &= ~PCIE_PORT_PERST(port->slot);
|
||||
writel(val, pcie->base + PCIE_SYS_CFG);
|
||||
|
||||
/* 100ms timeout value should be enough for Gen1/2 training */
|
||||
err = readl_poll_timeout(port->base + PCIE_LINK_STATUS, val,
|
||||
!!(val & PCIE_PORT_LINKUP), 20,
|
||||
100 * USEC_PER_MSEC);
|
||||
if (err)
|
||||
return -ETIMEDOUT;
|
||||
|
||||
/* enable interrupt */
|
||||
val = readl(pcie->base + PCIE_INT_ENABLE);
|
||||
val |= PCIE_PORT_INT_EN(port->index);
|
||||
val |= PCIE_PORT_INT_EN(port->slot);
|
||||
writel(val, pcie->base + PCIE_INT_ENABLE);
|
||||
|
||||
/* map to all DDR region. We need to set it before cfg operation. */
|
||||
|
@ -209,67 +731,94 @@ static void mtk_pcie_configure_rc(struct mtk_pcie_port *port)
|
|||
writel(PCIE_CONF_ADDR(PCIE_FTS_NUM, func, slot, 0),
|
||||
pcie->base + PCIE_CFG_ADDR);
|
||||
writel(val, pcie->base + PCIE_CFG_DATA);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mtk_pcie_assert_ports(struct mtk_pcie_port *port)
|
||||
static void mtk_pcie_enable_port(struct mtk_pcie_port *port)
|
||||
{
|
||||
struct mtk_pcie *pcie = port->pcie;
|
||||
u32 val;
|
||||
|
||||
/* assert port PERST_N */
|
||||
val = readl(pcie->base + PCIE_SYS_CFG);
|
||||
val |= PCIE_PORT_PERST(port->index);
|
||||
writel(val, pcie->base + PCIE_SYS_CFG);
|
||||
|
||||
/* de-assert port PERST_N */
|
||||
val = readl(pcie->base + PCIE_SYS_CFG);
|
||||
val &= ~PCIE_PORT_PERST(port->index);
|
||||
writel(val, pcie->base + PCIE_SYS_CFG);
|
||||
|
||||
/* PCIe v2.0 need at least 100ms delay to train from Gen1 to Gen2 */
|
||||
msleep(100);
|
||||
}
|
||||
|
||||
static void mtk_pcie_enable_ports(struct mtk_pcie_port *port)
|
||||
{
|
||||
struct device *dev = port->pcie->dev;
|
||||
struct device *dev = pcie->dev;
|
||||
int err;
|
||||
|
||||
err = clk_prepare_enable(port->sys_ck);
|
||||
if (err) {
|
||||
dev_err(dev, "failed to enable port%d clock\n", port->index);
|
||||
dev_err(dev, "failed to enable sys_ck%d clock\n", port->slot);
|
||||
goto err_sys_clk;
|
||||
}
|
||||
|
||||
err = clk_prepare_enable(port->ahb_ck);
|
||||
if (err) {
|
||||
dev_err(dev, "failed to enable ahb_ck%d\n", port->slot);
|
||||
goto err_ahb_clk;
|
||||
}
|
||||
|
||||
err = clk_prepare_enable(port->aux_ck);
|
||||
if (err) {
|
||||
dev_err(dev, "failed to enable aux_ck%d\n", port->slot);
|
||||
goto err_aux_clk;
|
||||
}
|
||||
|
||||
err = clk_prepare_enable(port->axi_ck);
|
||||
if (err) {
|
||||
dev_err(dev, "failed to enable axi_ck%d\n", port->slot);
|
||||
goto err_axi_clk;
|
||||
}
|
||||
|
||||
err = clk_prepare_enable(port->obff_ck);
|
||||
if (err) {
|
||||
dev_err(dev, "failed to enable obff_ck%d\n", port->slot);
|
||||
goto err_obff_clk;
|
||||
}
|
||||
|
||||
err = clk_prepare_enable(port->pipe_ck);
|
||||
if (err) {
|
||||
dev_err(dev, "failed to enable pipe_ck%d\n", port->slot);
|
||||
goto err_pipe_clk;
|
||||
}
|
||||
|
||||
reset_control_assert(port->reset);
|
||||
reset_control_deassert(port->reset);
|
||||
|
||||
err = phy_init(port->phy);
|
||||
if (err) {
|
||||
dev_err(dev, "failed to initialize port%d phy\n", port->slot);
|
||||
goto err_phy_init;
|
||||
}
|
||||
|
||||
err = phy_power_on(port->phy);
|
||||
if (err) {
|
||||
dev_err(dev, "failed to power on port%d phy\n", port->index);
|
||||
dev_err(dev, "failed to power on port%d phy\n", port->slot);
|
||||
goto err_phy_on;
|
||||
}
|
||||
|
||||
mtk_pcie_assert_ports(port);
|
||||
|
||||
/* if link up, then setup root port configuration space */
|
||||
if (mtk_pcie_link_up(port)) {
|
||||
mtk_pcie_configure_rc(port);
|
||||
if (!pcie->soc->startup(port))
|
||||
return;
|
||||
}
|
||||
|
||||
dev_info(dev, "Port%d link down\n", port->index);
|
||||
dev_info(dev, "Port%d link down\n", port->slot);
|
||||
|
||||
phy_power_off(port->phy);
|
||||
err_phy_on:
|
||||
phy_exit(port->phy);
|
||||
err_phy_init:
|
||||
clk_disable_unprepare(port->pipe_ck);
|
||||
err_pipe_clk:
|
||||
clk_disable_unprepare(port->obff_ck);
|
||||
err_obff_clk:
|
||||
clk_disable_unprepare(port->axi_ck);
|
||||
err_axi_clk:
|
||||
clk_disable_unprepare(port->aux_ck);
|
||||
err_aux_clk:
|
||||
clk_disable_unprepare(port->ahb_ck);
|
||||
err_ahb_clk:
|
||||
clk_disable_unprepare(port->sys_ck);
|
||||
err_sys_clk:
|
||||
mtk_pcie_port_free(port);
|
||||
}
|
||||
|
||||
static int mtk_pcie_parse_ports(struct mtk_pcie *pcie,
|
||||
struct device_node *node,
|
||||
int index)
|
||||
static int mtk_pcie_parse_port(struct mtk_pcie *pcie,
|
||||
struct device_node *node,
|
||||
int slot)
|
||||
{
|
||||
struct mtk_pcie_port *port;
|
||||
struct resource *regs;
|
||||
|
@ -288,34 +837,87 @@ static int mtk_pcie_parse_ports(struct mtk_pcie *pcie,
|
|||
return err;
|
||||
}
|
||||
|
||||
regs = platform_get_resource(pdev, IORESOURCE_MEM, index + 1);
|
||||
snprintf(name, sizeof(name), "port%d", slot);
|
||||
regs = platform_get_resource_byname(pdev, IORESOURCE_MEM, name);
|
||||
port->base = devm_ioremap_resource(dev, regs);
|
||||
if (IS_ERR(port->base)) {
|
||||
dev_err(dev, "failed to map port%d base\n", index);
|
||||
dev_err(dev, "failed to map port%d base\n", slot);
|
||||
return PTR_ERR(port->base);
|
||||
}
|
||||
|
||||
snprintf(name, sizeof(name), "sys_ck%d", index);
|
||||
snprintf(name, sizeof(name), "sys_ck%d", slot);
|
||||
port->sys_ck = devm_clk_get(dev, name);
|
||||
if (IS_ERR(port->sys_ck)) {
|
||||
dev_err(dev, "failed to get port%d clock\n", index);
|
||||
dev_err(dev, "failed to get sys_ck%d clock\n", slot);
|
||||
return PTR_ERR(port->sys_ck);
|
||||
}
|
||||
|
||||
snprintf(name, sizeof(name), "pcie-rst%d", index);
|
||||
port->reset = devm_reset_control_get_optional(dev, name);
|
||||
/* sys_ck might be divided into the following parts in some chips */
|
||||
snprintf(name, sizeof(name), "ahb_ck%d", slot);
|
||||
port->ahb_ck = devm_clk_get(dev, name);
|
||||
if (IS_ERR(port->ahb_ck)) {
|
||||
if (PTR_ERR(port->ahb_ck) == -EPROBE_DEFER)
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
port->ahb_ck = NULL;
|
||||
}
|
||||
|
||||
snprintf(name, sizeof(name), "axi_ck%d", slot);
|
||||
port->axi_ck = devm_clk_get(dev, name);
|
||||
if (IS_ERR(port->axi_ck)) {
|
||||
if (PTR_ERR(port->axi_ck) == -EPROBE_DEFER)
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
port->axi_ck = NULL;
|
||||
}
|
||||
|
||||
snprintf(name, sizeof(name), "aux_ck%d", slot);
|
||||
port->aux_ck = devm_clk_get(dev, name);
|
||||
if (IS_ERR(port->aux_ck)) {
|
||||
if (PTR_ERR(port->aux_ck) == -EPROBE_DEFER)
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
port->aux_ck = NULL;
|
||||
}
|
||||
|
||||
snprintf(name, sizeof(name), "obff_ck%d", slot);
|
||||
port->obff_ck = devm_clk_get(dev, name);
|
||||
if (IS_ERR(port->obff_ck)) {
|
||||
if (PTR_ERR(port->obff_ck) == -EPROBE_DEFER)
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
port->obff_ck = NULL;
|
||||
}
|
||||
|
||||
snprintf(name, sizeof(name), "pipe_ck%d", slot);
|
||||
port->pipe_ck = devm_clk_get(dev, name);
|
||||
if (IS_ERR(port->pipe_ck)) {
|
||||
if (PTR_ERR(port->pipe_ck) == -EPROBE_DEFER)
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
port->pipe_ck = NULL;
|
||||
}
|
||||
|
||||
snprintf(name, sizeof(name), "pcie-rst%d", slot);
|
||||
port->reset = devm_reset_control_get_optional_exclusive(dev, name);
|
||||
if (PTR_ERR(port->reset) == -EPROBE_DEFER)
|
||||
return PTR_ERR(port->reset);
|
||||
|
||||
/* some platforms may use default PHY setting */
|
||||
snprintf(name, sizeof(name), "pcie-phy%d", index);
|
||||
snprintf(name, sizeof(name), "pcie-phy%d", slot);
|
||||
port->phy = devm_phy_optional_get(dev, name);
|
||||
if (IS_ERR(port->phy))
|
||||
return PTR_ERR(port->phy);
|
||||
|
||||
port->index = index;
|
||||
port->slot = slot;
|
||||
port->pcie = pcie;
|
||||
|
||||
if (pcie->soc->setup_irq) {
|
||||
err = pcie->soc->setup_irq(port, node);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&port->list);
|
||||
list_add_tail(&port->list, &pcie->ports);
|
||||
|
||||
|
@ -329,12 +931,14 @@ static int mtk_pcie_subsys_powerup(struct mtk_pcie *pcie)
|
|||
struct resource *regs;
|
||||
int err;
|
||||
|
||||
/* get shared registers */
|
||||
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
pcie->base = devm_ioremap_resource(dev, regs);
|
||||
if (IS_ERR(pcie->base)) {
|
||||
dev_err(dev, "failed to map shared register\n");
|
||||
return PTR_ERR(pcie->base);
|
||||
/* get shared registers, which are optional */
|
||||
regs = platform_get_resource_byname(pdev, IORESOURCE_MEM, "subsys");
|
||||
if (regs) {
|
||||
pcie->base = devm_ioremap_resource(dev, regs);
|
||||
if (IS_ERR(pcie->base)) {
|
||||
dev_err(dev, "failed to map shared register\n");
|
||||
return PTR_ERR(pcie->base);
|
||||
}
|
||||
}
|
||||
|
||||
pcie->free_ck = devm_clk_get(dev, "free_ck");
|
||||
|
@ -422,7 +1026,7 @@ static int mtk_pcie_setup(struct mtk_pcie *pcie)
|
|||
}
|
||||
|
||||
for_each_available_child_of_node(node, child) {
|
||||
int index;
|
||||
int slot;
|
||||
|
||||
err = of_pci_get_devfn(child);
|
||||
if (err < 0) {
|
||||
|
@ -430,9 +1034,9 @@ static int mtk_pcie_setup(struct mtk_pcie *pcie)
|
|||
return err;
|
||||
}
|
||||
|
||||
index = PCI_SLOT(err);
|
||||
slot = PCI_SLOT(err);
|
||||
|
||||
err = mtk_pcie_parse_ports(pcie, child, index);
|
||||
err = mtk_pcie_parse_port(pcie, child, slot);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
@ -443,7 +1047,7 @@ static int mtk_pcie_setup(struct mtk_pcie *pcie)
|
|||
|
||||
/* enable each port, and then check link status */
|
||||
list_for_each_entry_safe(port, tmp, &pcie->ports, list)
|
||||
mtk_pcie_enable_ports(port);
|
||||
mtk_pcie_enable_port(port);
|
||||
|
||||
/* power down PCIe subsys if slots are all empty (link down) */
|
||||
if (list_empty(&pcie->ports))
|
||||
|
@ -480,9 +1084,12 @@ static int mtk_pcie_register_host(struct pci_host_bridge *host)
|
|||
|
||||
host->busnr = pcie->busn.start;
|
||||
host->dev.parent = pcie->dev;
|
||||
host->ops = &mtk_pcie_ops;
|
||||
host->ops = pcie->soc->ops;
|
||||
host->map_irq = of_irq_parse_and_map_pci;
|
||||
host->swizzle_irq = pci_common_swizzle;
|
||||
host->sysdata = pcie;
|
||||
if (IS_ENABLED(CONFIG_PCI_MSI) && pcie->soc->has_msi)
|
||||
host->msi = &mtk_pcie_msi_chip;
|
||||
|
||||
err = pci_scan_root_bus_bridge(host);
|
||||
if (err < 0)
|
||||
|
@ -513,6 +1120,7 @@ static int mtk_pcie_probe(struct platform_device *pdev)
|
|||
pcie = pci_host_bridge_priv(host);
|
||||
|
||||
pcie->dev = dev;
|
||||
pcie->soc = of_device_get_match_data(dev);
|
||||
platform_set_drvdata(pdev, pcie);
|
||||
INIT_LIST_HEAD(&pcie->ports);
|
||||
|
||||
|
@ -537,9 +1145,23 @@ put_resources:
|
|||
return err;
|
||||
}
|
||||
|
||||
static const struct mtk_pcie_soc mtk_pcie_soc_v1 = {
|
||||
.ops = &mtk_pcie_ops,
|
||||
.startup = mtk_pcie_startup_port,
|
||||
};
|
||||
|
||||
static const struct mtk_pcie_soc mtk_pcie_soc_v2 = {
|
||||
.has_msi = true,
|
||||
.ops = &mtk_pcie_ops_v2,
|
||||
.startup = mtk_pcie_startup_port_v2,
|
||||
.setup_irq = mtk_pcie_setup_irq,
|
||||
};
|
||||
|
||||
static const struct of_device_id mtk_pcie_ids[] = {
|
||||
{ .compatible = "mediatek,mt7623-pcie"},
|
||||
{ .compatible = "mediatek,mt2701-pcie"},
|
||||
{ .compatible = "mediatek,mt2701-pcie", .data = &mtk_pcie_soc_v1 },
|
||||
{ .compatible = "mediatek,mt7623-pcie", .data = &mtk_pcie_soc_v1 },
|
||||
{ .compatible = "mediatek,mt2712-pcie", .data = &mtk_pcie_soc_v2 },
|
||||
{ .compatible = "mediatek,mt7622-pcie", .data = &mtk_pcie_soc_v2 },
|
||||
{},
|
||||
};
|
||||
|
||||
|
|
|
@ -471,10 +471,8 @@ static int rcar_pcie_enable(struct rcar_pcie *pcie)
|
|||
bridge->msi = &pcie->msi.chip;
|
||||
|
||||
ret = pci_scan_root_bus_bridge(bridge);
|
||||
if (ret < 0) {
|
||||
kfree(bridge);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
bus = bridge->bus;
|
||||
|
||||
|
@ -1190,14 +1188,16 @@ static int rcar_pcie_probe(struct platform_device *pdev)
|
|||
|
||||
return 0;
|
||||
|
||||
err_free_bridge:
|
||||
pci_free_host_bridge(bridge);
|
||||
|
||||
err_pm_put:
|
||||
pm_runtime_put(dev);
|
||||
|
||||
err_pm_disable:
|
||||
pm_runtime_disable(dev);
|
||||
|
||||
err_free_bridge:
|
||||
pci_free_host_bridge(bridge);
|
||||
pci_free_resource_list(&pcie->resources);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue