Merge branch 'pci/controller/rcar'
- Add generic T_PVPERL macro for the required interval between power being stable and PERST# being inactive (Yoshihiro Shimoda) - Factor out dw_pcie_link_set_max_link_width() (Yoshihiro Shimoda) - Update PCI_EXP_LNKCAP_MLW so Link Capabilities shows the correct max link width (Yoshihiro Shimoda) - Drop tegra194 PCI_EXP_LNKCAP_MLW setting since dw_pcie_setup() already does it (Yoshihiro Shimoda) - Add dwc support for different dbi and dbi2 register offsets, to be used for R-Car Gen4 controllers (Yoshihiro Shimoda) - Add EDMA_UNROLL capability flag for R-Car Gen4 controllers that don't correctly advertise unrolled mapping via their eDMA CTRL register (Yoshihiro Shimoda) - Export dw_pcie_ep_exit() for use by the modular R-Car Gen4 driver (Yoshihiro Shimoda) - Add .pre_init() and .deinit() hooks for use by R-Car Gen4 controllers (Yoshihiro Shimoda) - Increase snps,dw-pcie DT reg and reg-names maxItems for R-Car Gen4 controllers (Yoshihiro Shimoda) - Add rcar-gen4-pci host and endpoint DT bindings and drivers (Yoshihiro Shimoda) - Add Renesas R8A779F0 Device ID to pci_endpoint_test to allow testing on R-Car S4-8 (Yoshihiro Shimoda) * pci/controller/rcar: misc: pci_endpoint_test: Add Device ID for R-Car S4-8 PCIe controller MAINTAINERS: Update PCI DRIVER FOR RENESAS R-CAR for R-Car Gen4 PCI: rcar-gen4: Add endpoint mode support PCI: rcar-gen4: Add R-Car Gen4 PCIe controller support for host mode dt-bindings: PCI: renesas: Add R-Car Gen4 PCIe Endpoint dt-bindings: PCI: renesas: Add R-Car Gen4 PCIe Host dt-bindings: PCI: dwc: Update maxItems of reg and reg-names PCI: dwc: endpoint: Introduce .pre_init() and .deinit() PCI: dwc: Expose dw_pcie_write_dbi2() to module PCI: dwc: Expose dw_pcie_ep_exit() to module PCI: dwc: Add EDMA_UNROLL capability flag PCI: dwc: endpoint: Add multiple PFs support for dbi2 PCI: tegra194: Drop PCI_EXP_LNKSTA_NLW setting PCI: dwc: Add missing PCI_EXP_LNKCAP_MLW handling PCI: dwc: Add dw_pcie_link_set_max_link_width() PCI: Add T_PVPERL macro
This commit is contained in:
commit
db20113d70
115
Documentation/devicetree/bindings/pci/rcar-gen4-pci-ep.yaml
Normal file
115
Documentation/devicetree/bindings/pci/rcar-gen4-pci-ep.yaml
Normal file
@ -0,0 +1,115 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
# Copyright (C) 2022-2023 Renesas Electronics Corp.
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/pci/rcar-gen4-pci-ep.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Renesas R-Car Gen4 PCIe Endpoint
|
||||
|
||||
maintainers:
|
||||
- Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
|
||||
|
||||
allOf:
|
||||
- $ref: snps,dw-pcie-ep.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- const: renesas,r8a779f0-pcie-ep # R-Car S4-8
|
||||
- const: renesas,rcar-gen4-pcie-ep # R-Car Gen4
|
||||
|
||||
reg:
|
||||
maxItems: 7
|
||||
|
||||
reg-names:
|
||||
items:
|
||||
- const: dbi
|
||||
- const: dbi2
|
||||
- const: atu
|
||||
- const: dma
|
||||
- const: app
|
||||
- const: phy
|
||||
- const: addr_space
|
||||
|
||||
interrupts:
|
||||
maxItems: 3
|
||||
|
||||
interrupt-names:
|
||||
items:
|
||||
- const: dma
|
||||
- const: sft_ce
|
||||
- const: app
|
||||
|
||||
clocks:
|
||||
maxItems: 2
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: core
|
||||
- const: ref
|
||||
|
||||
power-domains:
|
||||
maxItems: 1
|
||||
|
||||
resets:
|
||||
maxItems: 1
|
||||
|
||||
reset-names:
|
||||
items:
|
||||
- const: pwr
|
||||
|
||||
max-link-speed:
|
||||
maximum: 4
|
||||
|
||||
num-lanes:
|
||||
maximum: 4
|
||||
|
||||
max-functions:
|
||||
maximum: 2
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- reg-names
|
||||
- interrupts
|
||||
- interrupt-names
|
||||
- clocks
|
||||
- clock-names
|
||||
- power-domains
|
||||
- resets
|
||||
- reset-names
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/r8a779f0-cpg-mssr.h>
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
#include <dt-bindings/power/r8a779f0-sysc.h>
|
||||
|
||||
soc {
|
||||
#address-cells = <2>;
|
||||
#size-cells = <2>;
|
||||
|
||||
pcie0_ep: pcie-ep@e65d0000 {
|
||||
compatible = "renesas,r8a779f0-pcie-ep", "renesas,rcar-gen4-pcie-ep";
|
||||
reg = <0 0xe65d0000 0 0x2000>, <0 0xe65d2000 0 0x1000>,
|
||||
<0 0xe65d3000 0 0x2000>, <0 0xe65d5000 0 0x1200>,
|
||||
<0 0xe65d6200 0 0x0e00>, <0 0xe65d7000 0 0x0400>,
|
||||
<0 0xfe000000 0 0x400000>;
|
||||
reg-names = "dbi", "dbi2", "atu", "dma", "app", "phy", "addr_space";
|
||||
interrupts = <GIC_SPI 417 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 418 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 422 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-names = "dma", "sft_ce", "app";
|
||||
clocks = <&cpg CPG_MOD 624>, <&pcie0_clkref>;
|
||||
clock-names = "core", "ref";
|
||||
power-domains = <&sysc R8A779F0_PD_ALWAYS_ON>;
|
||||
resets = <&cpg 624>;
|
||||
reset-names = "pwr";
|
||||
max-link-speed = <4>;
|
||||
num-lanes = <2>;
|
||||
max-functions = /bits/ 8 <2>;
|
||||
};
|
||||
};
|
127
Documentation/devicetree/bindings/pci/rcar-gen4-pci-host.yaml
Normal file
127
Documentation/devicetree/bindings/pci/rcar-gen4-pci-host.yaml
Normal file
@ -0,0 +1,127 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
# Copyright (C) 2022-2023 Renesas Electronics Corp.
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/pci/rcar-gen4-pci-host.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Renesas R-Car Gen4 PCIe Host
|
||||
|
||||
maintainers:
|
||||
- Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
|
||||
|
||||
allOf:
|
||||
- $ref: snps,dw-pcie.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- const: renesas,r8a779f0-pcie # R-Car S4-8
|
||||
- const: renesas,rcar-gen4-pcie # R-Car Gen4
|
||||
|
||||
reg:
|
||||
maxItems: 7
|
||||
|
||||
reg-names:
|
||||
items:
|
||||
- const: dbi
|
||||
- const: dbi2
|
||||
- const: atu
|
||||
- const: dma
|
||||
- const: app
|
||||
- const: phy
|
||||
- const: config
|
||||
|
||||
interrupts:
|
||||
maxItems: 4
|
||||
|
||||
interrupt-names:
|
||||
items:
|
||||
- const: msi
|
||||
- const: dma
|
||||
- const: sft_ce
|
||||
- const: app
|
||||
|
||||
clocks:
|
||||
maxItems: 2
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: core
|
||||
- const: ref
|
||||
|
||||
power-domains:
|
||||
maxItems: 1
|
||||
|
||||
resets:
|
||||
maxItems: 1
|
||||
|
||||
reset-names:
|
||||
items:
|
||||
- const: pwr
|
||||
|
||||
max-link-speed:
|
||||
maximum: 4
|
||||
|
||||
num-lanes:
|
||||
maximum: 4
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- reg-names
|
||||
- interrupts
|
||||
- interrupt-names
|
||||
- clocks
|
||||
- clock-names
|
||||
- power-domains
|
||||
- resets
|
||||
- reset-names
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/r8a779f0-cpg-mssr.h>
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
#include <dt-bindings/power/r8a779f0-sysc.h>
|
||||
|
||||
soc {
|
||||
#address-cells = <2>;
|
||||
#size-cells = <2>;
|
||||
|
||||
pcie: pcie@e65d0000 {
|
||||
compatible = "renesas,r8a779f0-pcie", "renesas,rcar-gen4-pcie";
|
||||
reg = <0 0xe65d0000 0 0x1000>, <0 0xe65d2000 0 0x0800>,
|
||||
<0 0xe65d3000 0 0x2000>, <0 0xe65d5000 0 0x1200>,
|
||||
<0 0xe65d6200 0 0x0e00>, <0 0xe65d7000 0 0x0400>,
|
||||
<0 0xfe000000 0 0x400000>;
|
||||
reg-names = "dbi", "dbi2", "atu", "dma", "app", "phy", "config";
|
||||
interrupts = <GIC_SPI 416 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 417 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 418 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 422 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-names = "msi", "dma", "sft_ce", "app";
|
||||
clocks = <&cpg CPG_MOD 624>, <&pcie0_clkref>;
|
||||
clock-names = "core", "ref";
|
||||
power-domains = <&sysc R8A779F0_PD_ALWAYS_ON>;
|
||||
resets = <&cpg 624>;
|
||||
reset-names = "pwr";
|
||||
max-link-speed = <4>;
|
||||
num-lanes = <2>;
|
||||
#address-cells = <3>;
|
||||
#size-cells = <2>;
|
||||
bus-range = <0x00 0xff>;
|
||||
device_type = "pci";
|
||||
ranges = <0x01000000 0 0x00000000 0 0xfe000000 0 0x00400000>,
|
||||
<0x02000000 0 0x30000000 0 0x30000000 0 0x10000000>;
|
||||
dma-ranges = <0x42000000 0 0x00000000 0 0x00000000 1 0x00000000>;
|
||||
#interrupt-cells = <1>;
|
||||
interrupt-map-mask = <0 0 0 7>;
|
||||
interrupt-map = <0 0 0 1 &gic GIC_SPI 416 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<0 0 0 2 &gic GIC_SPI 416 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<0 0 0 3 &gic GIC_SPI 416 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<0 0 0 4 &gic GIC_SPI 416 IRQ_TYPE_LEVEL_HIGH>;
|
||||
snps,enable-cdm-check;
|
||||
};
|
||||
};
|
@ -33,11 +33,11 @@ properties:
|
||||
specific for each activated function, while the rest of the sub-spaces
|
||||
are common for all of them (if there are more than one).
|
||||
minItems: 2
|
||||
maxItems: 6
|
||||
maxItems: 7
|
||||
|
||||
reg-names:
|
||||
minItems: 2
|
||||
maxItems: 6
|
||||
maxItems: 7
|
||||
|
||||
interrupts:
|
||||
description:
|
||||
|
@ -33,11 +33,11 @@ properties:
|
||||
normal controller functioning. iATU memory IO region is also required
|
||||
if the space is unrolled (IP-core version >= 4.80a).
|
||||
minItems: 2
|
||||
maxItems: 5
|
||||
maxItems: 7
|
||||
|
||||
reg-names:
|
||||
minItems: 2
|
||||
maxItems: 5
|
||||
maxItems: 7
|
||||
items:
|
||||
oneOf:
|
||||
- description:
|
||||
|
@ -42,11 +42,11 @@ properties:
|
||||
are required for the normal controller work. iATU memory IO region is
|
||||
also required if the space is unrolled (IP-core version >= 4.80a).
|
||||
minItems: 2
|
||||
maxItems: 5
|
||||
maxItems: 7
|
||||
|
||||
reg-names:
|
||||
minItems: 2
|
||||
maxItems: 5
|
||||
maxItems: 7
|
||||
items:
|
||||
oneOf:
|
||||
- description:
|
||||
|
@ -16424,6 +16424,7 @@ L: linux-renesas-soc@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/pci/*rcar*
|
||||
F: drivers/pci/controller/*rcar*
|
||||
F: drivers/pci/controller/dwc/*rcar*
|
||||
|
||||
PCI DRIVER FOR SAMSUNG EXYNOS
|
||||
M: Jingoo Han <jingoohan1@gmail.com>
|
||||
|
@ -81,6 +81,7 @@
|
||||
#define PCI_DEVICE_ID_RENESAS_R8A774B1 0x002b
|
||||
#define PCI_DEVICE_ID_RENESAS_R8A774C0 0x002d
|
||||
#define PCI_DEVICE_ID_RENESAS_R8A774E1 0x0025
|
||||
#define PCI_DEVICE_ID_RENESAS_R8A779F0 0x0031
|
||||
|
||||
static DEFINE_IDA(pci_endpoint_test_ida);
|
||||
|
||||
@ -990,6 +991,9 @@ static const struct pci_device_id pci_endpoint_test_tbl[] = {
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_RENESAS, PCI_DEVICE_ID_RENESAS_R8A774B1),},
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_RENESAS, PCI_DEVICE_ID_RENESAS_R8A774C0),},
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_RENESAS, PCI_DEVICE_ID_RENESAS_R8A774E1),},
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_RENESAS, PCI_DEVICE_ID_RENESAS_R8A779F0),
|
||||
.driver_data = (kernel_ulong_t)&default_data,
|
||||
},
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_J721E),
|
||||
.driver_data = (kernel_ulong_t)&j721e_data,
|
||||
},
|
||||
|
@ -286,6 +286,31 @@ config PCIE_QCOM_EP
|
||||
to work in endpoint mode. The PCIe controller uses the DesignWare core
|
||||
plus Qualcomm-specific hardware wrappers.
|
||||
|
||||
config PCIE_RCAR_GEN4
|
||||
tristate
|
||||
|
||||
config PCIE_RCAR_GEN4_HOST
|
||||
tristate "Renesas R-Car Gen4 PCIe controller (host mode)"
|
||||
depends on ARCH_RENESAS || COMPILE_TEST
|
||||
depends on PCI_MSI
|
||||
select PCIE_DW_HOST
|
||||
select PCIE_RCAR_GEN4
|
||||
help
|
||||
Say Y here if you want PCIe controller (host mode) on R-Car Gen4 SoCs.
|
||||
To compile this driver as a module, choose M here: the module will be
|
||||
called pcie-rcar-gen4.ko. This uses the DesignWare core.
|
||||
|
||||
config PCIE_RCAR_GEN4_EP
|
||||
tristate "Renesas R-Car Gen4 PCIe controller (endpoint mode)"
|
||||
depends on ARCH_RENESAS || COMPILE_TEST
|
||||
depends on PCI_ENDPOINT
|
||||
select PCIE_DW_EP
|
||||
select PCIE_RCAR_GEN4
|
||||
help
|
||||
Say Y here if you want PCIe controller (endpoint mode) on R-Car Gen4
|
||||
SoCs. To compile this driver as a module, choose M here: the module
|
||||
will be called pcie-rcar-gen4.ko. This uses the DesignWare core.
|
||||
|
||||
config PCIE_ROCKCHIP_DW_HOST
|
||||
bool "Rockchip DesignWare PCIe controller"
|
||||
select PCIE_DW
|
||||
|
@ -26,6 +26,7 @@ obj-$(CONFIG_PCIE_TEGRA194) += pcie-tegra194.o
|
||||
obj-$(CONFIG_PCIE_UNIPHIER) += pcie-uniphier.o
|
||||
obj-$(CONFIG_PCIE_UNIPHIER_EP) += pcie-uniphier-ep.o
|
||||
obj-$(CONFIG_PCIE_VISCONTI_HOST) += pcie-visconti.o
|
||||
obj-$(CONFIG_PCIE_RCAR_GEN4) += pcie-rcar-gen4.o
|
||||
|
||||
# The following drivers are for devices that use the generic ACPI
|
||||
# pci_root.c driver but don't support standard ECAM config access.
|
||||
|
@ -52,21 +52,35 @@ static unsigned int dw_pcie_ep_func_select(struct dw_pcie_ep *ep, u8 func_no)
|
||||
return func_offset;
|
||||
}
|
||||
|
||||
static unsigned int dw_pcie_ep_get_dbi2_offset(struct dw_pcie_ep *ep, u8 func_no)
|
||||
{
|
||||
unsigned int dbi2_offset = 0;
|
||||
|
||||
if (ep->ops->get_dbi2_offset)
|
||||
dbi2_offset = ep->ops->get_dbi2_offset(ep, func_no);
|
||||
else if (ep->ops->func_conf_select) /* for backward compatibility */
|
||||
dbi2_offset = ep->ops->func_conf_select(ep, func_no);
|
||||
|
||||
return dbi2_offset;
|
||||
}
|
||||
|
||||
static void __dw_pcie_ep_reset_bar(struct dw_pcie *pci, u8 func_no,
|
||||
enum pci_barno bar, int flags)
|
||||
{
|
||||
u32 reg;
|
||||
unsigned int func_offset = 0;
|
||||
unsigned int func_offset, dbi2_offset;
|
||||
struct dw_pcie_ep *ep = &pci->ep;
|
||||
u32 reg, reg_dbi2;
|
||||
|
||||
func_offset = dw_pcie_ep_func_select(ep, func_no);
|
||||
dbi2_offset = dw_pcie_ep_get_dbi2_offset(ep, func_no);
|
||||
|
||||
reg = func_offset + PCI_BASE_ADDRESS_0 + (4 * bar);
|
||||
reg_dbi2 = dbi2_offset + PCI_BASE_ADDRESS_0 + (4 * bar);
|
||||
dw_pcie_dbi_ro_wr_en(pci);
|
||||
dw_pcie_writel_dbi2(pci, reg, 0x0);
|
||||
dw_pcie_writel_dbi2(pci, reg_dbi2, 0x0);
|
||||
dw_pcie_writel_dbi(pci, reg, 0x0);
|
||||
if (flags & PCI_BASE_ADDRESS_MEM_TYPE_64) {
|
||||
dw_pcie_writel_dbi2(pci, reg + 4, 0x0);
|
||||
dw_pcie_writel_dbi2(pci, reg_dbi2 + 4, 0x0);
|
||||
dw_pcie_writel_dbi(pci, reg + 4, 0x0);
|
||||
}
|
||||
dw_pcie_dbi_ro_wr_dis(pci);
|
||||
@ -228,16 +242,18 @@ static int dw_pcie_ep_set_bar(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
|
||||
{
|
||||
struct dw_pcie_ep *ep = epc_get_drvdata(epc);
|
||||
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
|
||||
unsigned int func_offset, dbi2_offset;
|
||||
enum pci_barno bar = epf_bar->barno;
|
||||
size_t size = epf_bar->size;
|
||||
int flags = epf_bar->flags;
|
||||
unsigned int func_offset = 0;
|
||||
u32 reg, reg_dbi2;
|
||||
int ret, type;
|
||||
u32 reg;
|
||||
|
||||
func_offset = dw_pcie_ep_func_select(ep, func_no);
|
||||
dbi2_offset = dw_pcie_ep_get_dbi2_offset(ep, func_no);
|
||||
|
||||
reg = PCI_BASE_ADDRESS_0 + (4 * bar) + func_offset;
|
||||
reg_dbi2 = PCI_BASE_ADDRESS_0 + (4 * bar) + dbi2_offset;
|
||||
|
||||
if (!(flags & PCI_BASE_ADDRESS_SPACE))
|
||||
type = PCIE_ATU_TYPE_MEM;
|
||||
@ -253,11 +269,11 @@ static int dw_pcie_ep_set_bar(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
|
||||
|
||||
dw_pcie_dbi_ro_wr_en(pci);
|
||||
|
||||
dw_pcie_writel_dbi2(pci, reg, lower_32_bits(size - 1));
|
||||
dw_pcie_writel_dbi2(pci, reg_dbi2, lower_32_bits(size - 1));
|
||||
dw_pcie_writel_dbi(pci, reg, flags);
|
||||
|
||||
if (flags & PCI_BASE_ADDRESS_MEM_TYPE_64) {
|
||||
dw_pcie_writel_dbi2(pci, reg + 4, upper_32_bits(size - 1));
|
||||
dw_pcie_writel_dbi2(pci, reg_dbi2 + 4, upper_32_bits(size - 1));
|
||||
dw_pcie_writel_dbi(pci, reg + 4, 0);
|
||||
}
|
||||
|
||||
@ -621,7 +637,11 @@ void dw_pcie_ep_exit(struct dw_pcie_ep *ep)
|
||||
epc->mem->window.page_size);
|
||||
|
||||
pci_epc_mem_exit(epc);
|
||||
|
||||
if (ep->ops->deinit)
|
||||
ep->ops->deinit(ep);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dw_pcie_ep_exit);
|
||||
|
||||
static unsigned int dw_pcie_ep_find_ext_capability(struct dw_pcie *pci, int cap)
|
||||
{
|
||||
@ -723,6 +743,9 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep)
|
||||
ep->phys_base = res->start;
|
||||
ep->addr_size = resource_size(res);
|
||||
|
||||
if (ep->ops->pre_init)
|
||||
ep->ops->pre_init(ep);
|
||||
|
||||
dw_pcie_version_detect(pci);
|
||||
|
||||
dw_pcie_iatu_detect(pci);
|
||||
@ -777,7 +800,7 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep)
|
||||
ep->page_size);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Failed to initialize address space\n");
|
||||
return ret;
|
||||
goto err_ep_deinit;
|
||||
}
|
||||
|
||||
ep->msi_mem = pci_epc_mem_alloc_addr(epc, &ep->msi_mem_phys,
|
||||
@ -814,6 +837,10 @@ err_free_epc_mem:
|
||||
err_exit_epc_mem:
|
||||
pci_epc_mem_exit(epc);
|
||||
|
||||
err_ep_deinit:
|
||||
if (ep->ops->deinit)
|
||||
ep->ops->deinit(ep);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dw_pcie_ep_init);
|
||||
|
@ -365,6 +365,7 @@ void dw_pcie_write_dbi2(struct dw_pcie *pci, u32 reg, size_t size, u32 val)
|
||||
if (ret)
|
||||
dev_err(pci->dev, "write DBI address failed\n");
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dw_pcie_write_dbi2);
|
||||
|
||||
static inline void __iomem *dw_pcie_select_atu(struct dw_pcie *pci, u32 dir,
|
||||
u32 index)
|
||||
@ -732,6 +733,53 @@ static void dw_pcie_link_set_max_speed(struct dw_pcie *pci, u32 link_gen)
|
||||
|
||||
}
|
||||
|
||||
static void dw_pcie_link_set_max_link_width(struct dw_pcie *pci, u32 num_lanes)
|
||||
{
|
||||
u32 lnkcap, lwsc, plc;
|
||||
u8 cap;
|
||||
|
||||
if (!num_lanes)
|
||||
return;
|
||||
|
||||
/* Set the number of lanes */
|
||||
plc = dw_pcie_readl_dbi(pci, PCIE_PORT_LINK_CONTROL);
|
||||
plc &= ~PORT_LINK_FAST_LINK_MODE;
|
||||
plc &= ~PORT_LINK_MODE_MASK;
|
||||
|
||||
/* Set link width speed control register */
|
||||
lwsc = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL);
|
||||
lwsc &= ~PORT_LOGIC_LINK_WIDTH_MASK;
|
||||
switch (num_lanes) {
|
||||
case 1:
|
||||
plc |= PORT_LINK_MODE_1_LANES;
|
||||
lwsc |= PORT_LOGIC_LINK_WIDTH_1_LANES;
|
||||
break;
|
||||
case 2:
|
||||
plc |= PORT_LINK_MODE_2_LANES;
|
||||
lwsc |= PORT_LOGIC_LINK_WIDTH_2_LANES;
|
||||
break;
|
||||
case 4:
|
||||
plc |= PORT_LINK_MODE_4_LANES;
|
||||
lwsc |= PORT_LOGIC_LINK_WIDTH_4_LANES;
|
||||
break;
|
||||
case 8:
|
||||
plc |= PORT_LINK_MODE_8_LANES;
|
||||
lwsc |= PORT_LOGIC_LINK_WIDTH_8_LANES;
|
||||
break;
|
||||
default:
|
||||
dev_err(pci->dev, "num-lanes %u: invalid value\n", num_lanes);
|
||||
return;
|
||||
}
|
||||
dw_pcie_writel_dbi(pci, PCIE_PORT_LINK_CONTROL, plc);
|
||||
dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, lwsc);
|
||||
|
||||
cap = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
|
||||
lnkcap = dw_pcie_readl_dbi(pci, cap + PCI_EXP_LNKCAP);
|
||||
lnkcap &= ~PCI_EXP_LNKCAP_MLW;
|
||||
lnkcap |= FIELD_PREP(PCI_EXP_LNKCAP_MLW, num_lanes);
|
||||
dw_pcie_writel_dbi(pci, cap + PCI_EXP_LNKCAP, lnkcap);
|
||||
}
|
||||
|
||||
void dw_pcie_iatu_detect(struct dw_pcie *pci)
|
||||
{
|
||||
int max_region, ob, ib;
|
||||
@ -840,8 +888,14 @@ static int dw_pcie_edma_find_chip(struct dw_pcie *pci)
|
||||
* Indirect eDMA CSRs access has been completely removed since v5.40a
|
||||
* thus no space is now reserved for the eDMA channels viewport and
|
||||
* former DMA CTRL register is no longer fixed to FFs.
|
||||
*
|
||||
* Note that Renesas R-Car S4-8's PCIe controllers for unknown reason
|
||||
* have zeros in the eDMA CTRL register even though the HW-manual
|
||||
* explicitly states there must FFs if the unrolled mapping is enabled.
|
||||
* For such cases the low-level drivers are supposed to manually
|
||||
* activate the unrolled mapping to bypass the auto-detection procedure.
|
||||
*/
|
||||
if (dw_pcie_ver_is_ge(pci, 540A))
|
||||
if (dw_pcie_ver_is_ge(pci, 540A) || dw_pcie_cap_is(pci, EDMA_UNROLL))
|
||||
val = 0xFFFFFFFF;
|
||||
else
|
||||
val = dw_pcie_readl_dbi(pci, PCIE_DMA_VIEWPORT_BASE + PCIE_DMA_CTRL);
|
||||
@ -1013,49 +1067,5 @@ void dw_pcie_setup(struct dw_pcie *pci)
|
||||
val |= PORT_LINK_DLL_LINK_EN;
|
||||
dw_pcie_writel_dbi(pci, PCIE_PORT_LINK_CONTROL, val);
|
||||
|
||||
if (!pci->num_lanes) {
|
||||
dev_dbg(pci->dev, "Using h/w default number of lanes\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Set the number of lanes */
|
||||
val &= ~PORT_LINK_FAST_LINK_MODE;
|
||||
val &= ~PORT_LINK_MODE_MASK;
|
||||
switch (pci->num_lanes) {
|
||||
case 1:
|
||||
val |= PORT_LINK_MODE_1_LANES;
|
||||
break;
|
||||
case 2:
|
||||
val |= PORT_LINK_MODE_2_LANES;
|
||||
break;
|
||||
case 4:
|
||||
val |= PORT_LINK_MODE_4_LANES;
|
||||
break;
|
||||
case 8:
|
||||
val |= PORT_LINK_MODE_8_LANES;
|
||||
break;
|
||||
default:
|
||||
dev_err(pci->dev, "num-lanes %u: invalid value\n", pci->num_lanes);
|
||||
return;
|
||||
}
|
||||
dw_pcie_writel_dbi(pci, PCIE_PORT_LINK_CONTROL, val);
|
||||
|
||||
/* Set link width speed control register */
|
||||
val = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL);
|
||||
val &= ~PORT_LOGIC_LINK_WIDTH_MASK;
|
||||
switch (pci->num_lanes) {
|
||||
case 1:
|
||||
val |= PORT_LOGIC_LINK_WIDTH_1_LANES;
|
||||
break;
|
||||
case 2:
|
||||
val |= PORT_LOGIC_LINK_WIDTH_2_LANES;
|
||||
break;
|
||||
case 4:
|
||||
val |= PORT_LOGIC_LINK_WIDTH_4_LANES;
|
||||
break;
|
||||
case 8:
|
||||
val |= PORT_LOGIC_LINK_WIDTH_8_LANES;
|
||||
break;
|
||||
}
|
||||
dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, val);
|
||||
dw_pcie_link_set_max_link_width(pci, pci->num_lanes);
|
||||
}
|
||||
|
@ -51,8 +51,9 @@
|
||||
|
||||
/* DWC PCIe controller capabilities */
|
||||
#define DW_PCIE_CAP_REQ_RES 0
|
||||
#define DW_PCIE_CAP_IATU_UNROLL 1
|
||||
#define DW_PCIE_CAP_CDM_CHECK 2
|
||||
#define DW_PCIE_CAP_EDMA_UNROLL 1
|
||||
#define DW_PCIE_CAP_IATU_UNROLL 2
|
||||
#define DW_PCIE_CAP_CDM_CHECK 3
|
||||
|
||||
#define dw_pcie_cap_is(_pci, _cap) \
|
||||
test_bit(DW_PCIE_CAP_ ## _cap, &(_pci)->caps)
|
||||
@ -330,7 +331,9 @@ struct dw_pcie_rp {
|
||||
};
|
||||
|
||||
struct dw_pcie_ep_ops {
|
||||
void (*pre_init)(struct dw_pcie_ep *ep);
|
||||
void (*ep_init)(struct dw_pcie_ep *ep);
|
||||
void (*deinit)(struct dw_pcie_ep *ep);
|
||||
int (*raise_irq)(struct dw_pcie_ep *ep, u8 func_no,
|
||||
enum pci_epc_irq_type type, u16 interrupt_num);
|
||||
const struct pci_epc_features* (*get_features)(struct dw_pcie_ep *ep);
|
||||
@ -342,6 +345,7 @@ struct dw_pcie_ep_ops {
|
||||
* driver.
|
||||
*/
|
||||
unsigned int (*func_conf_select)(struct dw_pcie_ep *ep, u8 func_no);
|
||||
unsigned int (*get_dbi2_offset)(struct dw_pcie_ep *ep, u8 func_no);
|
||||
};
|
||||
|
||||
struct dw_pcie_ep_func {
|
||||
|
527
drivers/pci/controller/dwc/pcie-rcar-gen4.c
Normal file
527
drivers/pci/controller/dwc/pcie-rcar-gen4.c
Normal file
@ -0,0 +1,527 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* PCIe controller driver for Renesas R-Car Gen4 Series SoCs
|
||||
* Copyright (C) 2022-2023 Renesas Electronics Corporation
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/reset.h>
|
||||
|
||||
#include "../../pci.h"
|
||||
#include "pcie-designware.h"
|
||||
|
||||
/* Renesas-specific */
|
||||
/* PCIe Mode Setting Register 0 */
|
||||
#define PCIEMSR0 0x0000
|
||||
#define BIFUR_MOD_SET_ON BIT(0)
|
||||
#define DEVICE_TYPE_EP 0
|
||||
#define DEVICE_TYPE_RC BIT(4)
|
||||
|
||||
/* PCIe Interrupt Status 0 */
|
||||
#define PCIEINTSTS0 0x0084
|
||||
|
||||
/* PCIe Interrupt Status 0 Enable */
|
||||
#define PCIEINTSTS0EN 0x0310
|
||||
#define MSI_CTRL_INT BIT(26)
|
||||
#define SMLH_LINK_UP BIT(7)
|
||||
#define RDLH_LINK_UP BIT(6)
|
||||
|
||||
/* PCIe DMA Interrupt Status Enable */
|
||||
#define PCIEDMAINTSTSEN 0x0314
|
||||
#define PCIEDMAINTSTSEN_INIT GENMASK(15, 0)
|
||||
|
||||
/* PCIe Reset Control Register 1 */
|
||||
#define PCIERSTCTRL1 0x0014
|
||||
#define APP_HOLD_PHY_RST BIT(16)
|
||||
#define APP_LTSSM_ENABLE BIT(0)
|
||||
|
||||
#define RCAR_NUM_SPEED_CHANGE_RETRIES 10
|
||||
#define RCAR_MAX_LINK_SPEED 4
|
||||
|
||||
#define RCAR_GEN4_PCIE_EP_FUNC_DBI_OFFSET 0x1000
|
||||
#define RCAR_GEN4_PCIE_EP_FUNC_DBI2_OFFSET 0x800
|
||||
|
||||
struct rcar_gen4_pcie {
|
||||
struct dw_pcie dw;
|
||||
void __iomem *base;
|
||||
struct platform_device *pdev;
|
||||
enum dw_pcie_device_mode mode;
|
||||
};
|
||||
#define to_rcar_gen4_pcie(_dw) container_of(_dw, struct rcar_gen4_pcie, dw)
|
||||
|
||||
/* Common */
|
||||
static void rcar_gen4_pcie_ltssm_enable(struct rcar_gen4_pcie *rcar,
|
||||
bool enable)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = readl(rcar->base + PCIERSTCTRL1);
|
||||
if (enable) {
|
||||
val |= APP_LTSSM_ENABLE;
|
||||
val &= ~APP_HOLD_PHY_RST;
|
||||
} else {
|
||||
/*
|
||||
* Since the datasheet of R-Car doesn't mention how to assert
|
||||
* the APP_HOLD_PHY_RST, don't assert it again. Otherwise,
|
||||
* hang-up issue happened in the dw_edma_core_off() when
|
||||
* the controller didn't detect a PCI device.
|
||||
*/
|
||||
val &= ~APP_LTSSM_ENABLE;
|
||||
}
|
||||
writel(val, rcar->base + PCIERSTCTRL1);
|
||||
}
|
||||
|
||||
static int rcar_gen4_pcie_link_up(struct dw_pcie *dw)
|
||||
{
|
||||
struct rcar_gen4_pcie *rcar = to_rcar_gen4_pcie(dw);
|
||||
u32 val, mask;
|
||||
|
||||
val = readl(rcar->base + PCIEINTSTS0);
|
||||
mask = RDLH_LINK_UP | SMLH_LINK_UP;
|
||||
|
||||
return (val & mask) == mask;
|
||||
}
|
||||
|
||||
/*
|
||||
* Manually initiate the speed change. Return 0 if change succeeded; otherwise
|
||||
* -ETIMEDOUT.
|
||||
*/
|
||||
static int rcar_gen4_pcie_speed_change(struct dw_pcie *dw)
|
||||
{
|
||||
u32 val;
|
||||
int i;
|
||||
|
||||
val = dw_pcie_readl_dbi(dw, PCIE_LINK_WIDTH_SPEED_CONTROL);
|
||||
val &= ~PORT_LOGIC_SPEED_CHANGE;
|
||||
dw_pcie_writel_dbi(dw, PCIE_LINK_WIDTH_SPEED_CONTROL, val);
|
||||
|
||||
val = dw_pcie_readl_dbi(dw, PCIE_LINK_WIDTH_SPEED_CONTROL);
|
||||
val |= PORT_LOGIC_SPEED_CHANGE;
|
||||
dw_pcie_writel_dbi(dw, PCIE_LINK_WIDTH_SPEED_CONTROL, val);
|
||||
|
||||
for (i = 0; i < RCAR_NUM_SPEED_CHANGE_RETRIES; i++) {
|
||||
val = dw_pcie_readl_dbi(dw, PCIE_LINK_WIDTH_SPEED_CONTROL);
|
||||
if (!(val & PORT_LOGIC_SPEED_CHANGE))
|
||||
return 0;
|
||||
usleep_range(10000, 11000);
|
||||
}
|
||||
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
/*
|
||||
* Enable LTSSM of this controller and manually initiate the speed change.
|
||||
* Always return 0.
|
||||
*/
|
||||
static int rcar_gen4_pcie_start_link(struct dw_pcie *dw)
|
||||
{
|
||||
struct rcar_gen4_pcie *rcar = to_rcar_gen4_pcie(dw);
|
||||
int i, changes;
|
||||
|
||||
rcar_gen4_pcie_ltssm_enable(rcar, true);
|
||||
|
||||
/*
|
||||
* Require direct speed change with retrying here if the link_gen is
|
||||
* PCIe Gen2 or higher.
|
||||
*/
|
||||
changes = min_not_zero(dw->link_gen, RCAR_MAX_LINK_SPEED) - 1;
|
||||
|
||||
/*
|
||||
* Since dw_pcie_setup_rc() sets it once, PCIe Gen2 will be trained.
|
||||
* So, this needs remaining times for up to PCIe Gen4 if RC mode.
|
||||
*/
|
||||
if (changes && rcar->mode == DW_PCIE_RC_TYPE)
|
||||
changes--;
|
||||
|
||||
for (i = 0; i < changes; i++) {
|
||||
/* It may not be connected in EP mode yet. So, break the loop */
|
||||
if (rcar_gen4_pcie_speed_change(dw))
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rcar_gen4_pcie_stop_link(struct dw_pcie *dw)
|
||||
{
|
||||
struct rcar_gen4_pcie *rcar = to_rcar_gen4_pcie(dw);
|
||||
|
||||
rcar_gen4_pcie_ltssm_enable(rcar, false);
|
||||
}
|
||||
|
||||
static int rcar_gen4_pcie_common_init(struct rcar_gen4_pcie *rcar)
|
||||
{
|
||||
struct dw_pcie *dw = &rcar->dw;
|
||||
u32 val;
|
||||
int ret;
|
||||
|
||||
ret = clk_bulk_prepare_enable(DW_PCIE_NUM_CORE_CLKS, dw->core_clks);
|
||||
if (ret) {
|
||||
dev_err(dw->dev, "Enabling core clocks failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!reset_control_status(dw->core_rsts[DW_PCIE_PWR_RST].rstc))
|
||||
reset_control_assert(dw->core_rsts[DW_PCIE_PWR_RST].rstc);
|
||||
|
||||
val = readl(rcar->base + PCIEMSR0);
|
||||
if (rcar->mode == DW_PCIE_RC_TYPE) {
|
||||
val |= DEVICE_TYPE_RC;
|
||||
} else if (rcar->mode == DW_PCIE_EP_TYPE) {
|
||||
val |= DEVICE_TYPE_EP;
|
||||
} else {
|
||||
ret = -EINVAL;
|
||||
goto err_unprepare;
|
||||
}
|
||||
|
||||
if (dw->num_lanes < 4)
|
||||
val |= BIFUR_MOD_SET_ON;
|
||||
|
||||
writel(val, rcar->base + PCIEMSR0);
|
||||
|
||||
ret = reset_control_deassert(dw->core_rsts[DW_PCIE_PWR_RST].rstc);
|
||||
if (ret)
|
||||
goto err_unprepare;
|
||||
|
||||
return 0;
|
||||
|
||||
err_unprepare:
|
||||
clk_bulk_disable_unprepare(DW_PCIE_NUM_CORE_CLKS, dw->core_clks);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void rcar_gen4_pcie_common_deinit(struct rcar_gen4_pcie *rcar)
|
||||
{
|
||||
struct dw_pcie *dw = &rcar->dw;
|
||||
|
||||
reset_control_assert(dw->core_rsts[DW_PCIE_PWR_RST].rstc);
|
||||
clk_bulk_disable_unprepare(DW_PCIE_NUM_CORE_CLKS, dw->core_clks);
|
||||
}
|
||||
|
||||
static int rcar_gen4_pcie_prepare(struct rcar_gen4_pcie *rcar)
|
||||
{
|
||||
struct device *dev = rcar->dw.dev;
|
||||
int err;
|
||||
|
||||
pm_runtime_enable(dev);
|
||||
err = pm_runtime_resume_and_get(dev);
|
||||
if (err < 0) {
|
||||
dev_err(dev, "Runtime resume failed\n");
|
||||
pm_runtime_disable(dev);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void rcar_gen4_pcie_unprepare(struct rcar_gen4_pcie *rcar)
|
||||
{
|
||||
struct device *dev = rcar->dw.dev;
|
||||
|
||||
pm_runtime_put(dev);
|
||||
pm_runtime_disable(dev);
|
||||
}
|
||||
|
||||
static int rcar_gen4_pcie_get_resources(struct rcar_gen4_pcie *rcar)
|
||||
{
|
||||
/* Renesas-specific registers */
|
||||
rcar->base = devm_platform_ioremap_resource_byname(rcar->pdev, "app");
|
||||
|
||||
return PTR_ERR_OR_ZERO(rcar->base);
|
||||
}
|
||||
|
||||
static const struct dw_pcie_ops dw_pcie_ops = {
|
||||
.start_link = rcar_gen4_pcie_start_link,
|
||||
.stop_link = rcar_gen4_pcie_stop_link,
|
||||
.link_up = rcar_gen4_pcie_link_up,
|
||||
};
|
||||
|
||||
static struct rcar_gen4_pcie *rcar_gen4_pcie_alloc(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct rcar_gen4_pcie *rcar;
|
||||
|
||||
rcar = devm_kzalloc(dev, sizeof(*rcar), GFP_KERNEL);
|
||||
if (!rcar)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
rcar->dw.ops = &dw_pcie_ops;
|
||||
rcar->dw.dev = dev;
|
||||
rcar->pdev = pdev;
|
||||
dw_pcie_cap_set(&rcar->dw, EDMA_UNROLL);
|
||||
dw_pcie_cap_set(&rcar->dw, REQ_RES);
|
||||
platform_set_drvdata(pdev, rcar);
|
||||
|
||||
return rcar;
|
||||
}
|
||||
|
||||
/* Host mode */
|
||||
static int rcar_gen4_pcie_host_init(struct dw_pcie_rp *pp)
|
||||
{
|
||||
struct dw_pcie *dw = to_dw_pcie_from_pp(pp);
|
||||
struct rcar_gen4_pcie *rcar = to_rcar_gen4_pcie(dw);
|
||||
int ret;
|
||||
u32 val;
|
||||
|
||||
gpiod_set_value_cansleep(dw->pe_rst, 1);
|
||||
|
||||
ret = rcar_gen4_pcie_common_init(rcar);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* According to the section 3.5.7.2 "RC Mode" in DWC PCIe Dual Mode
|
||||
* Rev.5.20a and 3.5.6.1 "RC mode" in DWC PCIe RC databook v5.20a, we
|
||||
* should disable two BARs to avoid unnecessary memory assignment
|
||||
* during device enumeration.
|
||||
*/
|
||||
dw_pcie_writel_dbi2(dw, PCI_BASE_ADDRESS_0, 0x0);
|
||||
dw_pcie_writel_dbi2(dw, PCI_BASE_ADDRESS_1, 0x0);
|
||||
|
||||
/* Enable MSI interrupt signal */
|
||||
val = readl(rcar->base + PCIEINTSTS0EN);
|
||||
val |= MSI_CTRL_INT;
|
||||
writel(val, rcar->base + PCIEINTSTS0EN);
|
||||
|
||||
msleep(PCIE_T_PVPERL_MS); /* pe_rst requires 100msec delay */
|
||||
|
||||
gpiod_set_value_cansleep(dw->pe_rst, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rcar_gen4_pcie_host_deinit(struct dw_pcie_rp *pp)
|
||||
{
|
||||
struct dw_pcie *dw = to_dw_pcie_from_pp(pp);
|
||||
struct rcar_gen4_pcie *rcar = to_rcar_gen4_pcie(dw);
|
||||
|
||||
gpiod_set_value_cansleep(dw->pe_rst, 1);
|
||||
rcar_gen4_pcie_common_deinit(rcar);
|
||||
}
|
||||
|
||||
static const struct dw_pcie_host_ops rcar_gen4_pcie_host_ops = {
|
||||
.host_init = rcar_gen4_pcie_host_init,
|
||||
.host_deinit = rcar_gen4_pcie_host_deinit,
|
||||
};
|
||||
|
||||
static int rcar_gen4_add_dw_pcie_rp(struct rcar_gen4_pcie *rcar)
|
||||
{
|
||||
struct dw_pcie_rp *pp = &rcar->dw.pp;
|
||||
|
||||
if (!IS_ENABLED(CONFIG_PCIE_RCAR_GEN4_HOST))
|
||||
return -ENODEV;
|
||||
|
||||
pp->num_vectors = MAX_MSI_IRQS;
|
||||
pp->ops = &rcar_gen4_pcie_host_ops;
|
||||
|
||||
return dw_pcie_host_init(pp);
|
||||
}
|
||||
|
||||
static void rcar_gen4_remove_dw_pcie_rp(struct rcar_gen4_pcie *rcar)
|
||||
{
|
||||
dw_pcie_host_deinit(&rcar->dw.pp);
|
||||
}
|
||||
|
||||
/* Endpoint mode */
|
||||
static void rcar_gen4_pcie_ep_pre_init(struct dw_pcie_ep *ep)
|
||||
{
|
||||
struct dw_pcie *dw = to_dw_pcie_from_ep(ep);
|
||||
struct rcar_gen4_pcie *rcar = to_rcar_gen4_pcie(dw);
|
||||
int ret;
|
||||
|
||||
ret = rcar_gen4_pcie_common_init(rcar);
|
||||
if (ret)
|
||||
return;
|
||||
|
||||
writel(PCIEDMAINTSTSEN_INIT, rcar->base + PCIEDMAINTSTSEN);
|
||||
}
|
||||
|
||||
static void rcar_gen4_pcie_ep_init(struct dw_pcie_ep *ep)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
|
||||
enum pci_barno bar;
|
||||
|
||||
for (bar = 0; bar < PCI_STD_NUM_BARS; bar++)
|
||||
dw_pcie_ep_reset_bar(pci, bar);
|
||||
}
|
||||
|
||||
static void rcar_gen4_pcie_ep_deinit(struct dw_pcie_ep *ep)
|
||||
{
|
||||
struct dw_pcie *dw = to_dw_pcie_from_ep(ep);
|
||||
struct rcar_gen4_pcie *rcar = to_rcar_gen4_pcie(dw);
|
||||
|
||||
writel(0, rcar->base + PCIEDMAINTSTSEN);
|
||||
rcar_gen4_pcie_common_deinit(rcar);
|
||||
}
|
||||
|
||||
static int rcar_gen4_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no,
|
||||
enum pci_epc_irq_type type,
|
||||
u16 interrupt_num)
|
||||
{
|
||||
struct dw_pcie *dw = to_dw_pcie_from_ep(ep);
|
||||
|
||||
switch (type) {
|
||||
case PCI_EPC_IRQ_LEGACY:
|
||||
return dw_pcie_ep_raise_legacy_irq(ep, func_no);
|
||||
case PCI_EPC_IRQ_MSI:
|
||||
return dw_pcie_ep_raise_msi_irq(ep, func_no, interrupt_num);
|
||||
default:
|
||||
dev_err(dw->dev, "Unknown IRQ type\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct pci_epc_features rcar_gen4_pcie_epc_features = {
|
||||
.linkup_notifier = false,
|
||||
.msi_capable = true,
|
||||
.msix_capable = false,
|
||||
.reserved_bar = 1 << BAR_1 | 1 << BAR_3 | 1 << BAR_5,
|
||||
.align = SZ_1M,
|
||||
};
|
||||
|
||||
static const struct pci_epc_features*
|
||||
rcar_gen4_pcie_ep_get_features(struct dw_pcie_ep *ep)
|
||||
{
|
||||
return &rcar_gen4_pcie_epc_features;
|
||||
}
|
||||
|
||||
static unsigned int rcar_gen4_pcie_ep_func_conf_select(struct dw_pcie_ep *ep,
|
||||
u8 func_no)
|
||||
{
|
||||
return func_no * RCAR_GEN4_PCIE_EP_FUNC_DBI_OFFSET;
|
||||
}
|
||||
|
||||
static unsigned int rcar_gen4_pcie_ep_get_dbi2_offset(struct dw_pcie_ep *ep,
|
||||
u8 func_no)
|
||||
{
|
||||
return func_no * RCAR_GEN4_PCIE_EP_FUNC_DBI2_OFFSET;
|
||||
}
|
||||
|
||||
static const struct dw_pcie_ep_ops pcie_ep_ops = {
|
||||
.pre_init = rcar_gen4_pcie_ep_pre_init,
|
||||
.ep_init = rcar_gen4_pcie_ep_init,
|
||||
.deinit = rcar_gen4_pcie_ep_deinit,
|
||||
.raise_irq = rcar_gen4_pcie_ep_raise_irq,
|
||||
.get_features = rcar_gen4_pcie_ep_get_features,
|
||||
.func_conf_select = rcar_gen4_pcie_ep_func_conf_select,
|
||||
.get_dbi2_offset = rcar_gen4_pcie_ep_get_dbi2_offset,
|
||||
};
|
||||
|
||||
static int rcar_gen4_add_dw_pcie_ep(struct rcar_gen4_pcie *rcar)
|
||||
{
|
||||
struct dw_pcie_ep *ep = &rcar->dw.ep;
|
||||
|
||||
if (!IS_ENABLED(CONFIG_PCIE_RCAR_GEN4_EP))
|
||||
return -ENODEV;
|
||||
|
||||
ep->ops = &pcie_ep_ops;
|
||||
|
||||
return dw_pcie_ep_init(ep);
|
||||
}
|
||||
|
||||
static void rcar_gen4_remove_dw_pcie_ep(struct rcar_gen4_pcie *rcar)
|
||||
{
|
||||
dw_pcie_ep_exit(&rcar->dw.ep);
|
||||
}
|
||||
|
||||
/* Common */
|
||||
static int rcar_gen4_add_dw_pcie(struct rcar_gen4_pcie *rcar)
|
||||
{
|
||||
rcar->mode = (enum dw_pcie_device_mode)of_device_get_match_data(&rcar->pdev->dev);
|
||||
|
||||
switch (rcar->mode) {
|
||||
case DW_PCIE_RC_TYPE:
|
||||
return rcar_gen4_add_dw_pcie_rp(rcar);
|
||||
case DW_PCIE_EP_TYPE:
|
||||
return rcar_gen4_add_dw_pcie_ep(rcar);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int rcar_gen4_pcie_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct rcar_gen4_pcie *rcar;
|
||||
int err;
|
||||
|
||||
rcar = rcar_gen4_pcie_alloc(pdev);
|
||||
if (IS_ERR(rcar))
|
||||
return PTR_ERR(rcar);
|
||||
|
||||
err = rcar_gen4_pcie_get_resources(rcar);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = rcar_gen4_pcie_prepare(rcar);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = rcar_gen4_add_dw_pcie(rcar);
|
||||
if (err)
|
||||
goto err_unprepare;
|
||||
|
||||
return 0;
|
||||
|
||||
err_unprepare:
|
||||
rcar_gen4_pcie_unprepare(rcar);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void rcar_gen4_remove_dw_pcie(struct rcar_gen4_pcie *rcar)
|
||||
{
|
||||
switch (rcar->mode) {
|
||||
case DW_PCIE_RC_TYPE:
|
||||
rcar_gen4_remove_dw_pcie_rp(rcar);
|
||||
break;
|
||||
case DW_PCIE_EP_TYPE:
|
||||
rcar_gen4_remove_dw_pcie_ep(rcar);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void rcar_gen4_pcie_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct rcar_gen4_pcie *rcar = platform_get_drvdata(pdev);
|
||||
|
||||
rcar_gen4_remove_dw_pcie(rcar);
|
||||
rcar_gen4_pcie_unprepare(rcar);
|
||||
}
|
||||
|
||||
static const struct of_device_id rcar_gen4_pcie_of_match[] = {
|
||||
{
|
||||
.compatible = "renesas,rcar-gen4-pcie",
|
||||
.data = (void *)DW_PCIE_RC_TYPE,
|
||||
},
|
||||
{
|
||||
.compatible = "renesas,rcar-gen4-pcie-ep",
|
||||
.data = (void *)DW_PCIE_EP_TYPE,
|
||||
},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, rcar_gen4_pcie_of_match);
|
||||
|
||||
static struct platform_driver rcar_gen4_pcie_driver = {
|
||||
.driver = {
|
||||
.name = "pcie-rcar-gen4",
|
||||
.of_match_table = rcar_gen4_pcie_of_match,
|
||||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
},
|
||||
.probe = rcar_gen4_pcie_probe,
|
||||
.remove_new = rcar_gen4_pcie_remove,
|
||||
};
|
||||
module_platform_driver(rcar_gen4_pcie_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Renesas R-Car Gen4 PCIe controller driver");
|
||||
MODULE_LICENSE("GPL");
|
@ -917,12 +917,6 @@ static int tegra_pcie_dw_host_init(struct dw_pcie_rp *pp)
|
||||
AMBA_ERROR_RESPONSE_CRS_SHIFT);
|
||||
dw_pcie_writel_dbi(pci, PORT_LOGIC_AMBA_ERROR_RESPONSE_DEFAULT, val);
|
||||
|
||||
/* Configure Max lane width from DT */
|
||||
val = dw_pcie_readl_dbi(pci, pcie->pcie_cap_base + PCI_EXP_LNKCAP);
|
||||
val &= ~PCI_EXP_LNKCAP_MLW;
|
||||
val |= (pcie->num_lanes << PCI_EXP_LNKSTA_NLW_SHIFT);
|
||||
dw_pcie_writel_dbi(pci, pcie->pcie_cap_base + PCI_EXP_LNKCAP, val);
|
||||
|
||||
/* Clear Slot Clock Configuration bit if SRNS configuration */
|
||||
if (pcie->enable_srns) {
|
||||
val_16 = dw_pcie_readw_dbi(pci, pcie->pcie_cap_base +
|
||||
|
@ -13,6 +13,9 @@
|
||||
|
||||
#define PCIE_LINK_RETRAIN_TIMEOUT_MS 1000
|
||||
|
||||
/* Power stable to PERST# inactive from PCIe card Electromechanical Spec */
|
||||
#define PCIE_T_PVPERL_MS 100
|
||||
|
||||
/*
|
||||
* PCIe r6.0, sec 5.3.3.2.1 <PME Synchronization>
|
||||
* Recommends 1ms to 10ms timeout to check L2 ready.
|
||||
|
Loading…
x
Reference in New Issue
Block a user