PCI: tegra: Add support for PCIe endpoint mode in Tegra194
Add support for the endpoint mode of Synopsys DesignWare core based dual mode PCIe controllers present in Tegra194 SoC. Signed-off-by: Vidya Sagar <vidyas@nvidia.com> Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> Acked-by: Thierry Reding <treding@nvidia.com>
This commit is contained in:
parent
9f04d18b1e
commit
c57247f940
@ -248,14 +248,37 @@ config PCI_MESON
|
||||
implement the driver.
|
||||
|
||||
config PCIE_TEGRA194
|
||||
tristate "NVIDIA Tegra194 (and later) PCIe controller"
|
||||
tristate
|
||||
|
||||
config PCIE_TEGRA194_HOST
|
||||
tristate "NVIDIA Tegra194 (and later) PCIe controller - Host Mode"
|
||||
depends on ARCH_TEGRA_194_SOC || COMPILE_TEST
|
||||
depends on PCI_MSI_IRQ_DOMAIN
|
||||
select PCIE_DW_HOST
|
||||
select PHY_TEGRA194_P2U
|
||||
select PCIE_TEGRA194
|
||||
help
|
||||
Say Y here if you want support for DesignWare core based PCIe host
|
||||
controller found in NVIDIA Tegra194 SoC.
|
||||
Enables support for the PCIe controller in the NVIDIA Tegra194 SoC to
|
||||
work in host mode. There are two instances of PCIe controllers in
|
||||
Tegra194. This controller can work either as EP or RC. In order to
|
||||
enable host-specific features PCIE_TEGRA194_HOST must be selected and
|
||||
in order to enable device-specific features PCIE_TEGRA194_EP must be
|
||||
selected. This uses the DesignWare core.
|
||||
|
||||
config PCIE_TEGRA194_EP
|
||||
tristate "NVIDIA Tegra194 (and later) PCIe controller - Endpoint Mode"
|
||||
depends on ARCH_TEGRA_194_SOC || COMPILE_TEST
|
||||
depends on PCI_ENDPOINT
|
||||
select PCIE_DW_EP
|
||||
select PHY_TEGRA194_P2U
|
||||
select PCIE_TEGRA194
|
||||
help
|
||||
Enables support for the PCIe controller in the NVIDIA Tegra194 SoC to
|
||||
work in host mode. There are two instances of PCIe controllers in
|
||||
Tegra194. This controller can work either as EP or RC. In order to
|
||||
enable host-specific features PCIE_TEGRA194_HOST must be selected and
|
||||
in order to enable device-specific features PCIE_TEGRA194_EP must be
|
||||
selected. This uses the DesignWare core.
|
||||
|
||||
config PCIE_UNIPHIER
|
||||
bool "Socionext UniPhier PCIe controllers"
|
||||
|
@ -18,6 +18,7 @@ void dw_pcie_ep_linkup(struct dw_pcie_ep *ep)
|
||||
|
||||
pci_epc_linkup(epc);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dw_pcie_ep_linkup);
|
||||
|
||||
void dw_pcie_ep_init_notify(struct dw_pcie_ep *ep)
|
||||
{
|
||||
@ -25,6 +26,7 @@ void dw_pcie_ep_init_notify(struct dw_pcie_ep *ep)
|
||||
|
||||
pci_epc_init_notify(epc);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dw_pcie_ep_init_notify);
|
||||
|
||||
static void __dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar,
|
||||
int flags)
|
||||
@ -536,6 +538,7 @@ int dw_pcie_ep_init_complete(struct dw_pcie_ep *ep)
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dw_pcie_ep_init_complete);
|
||||
|
||||
int dw_pcie_ep_init(struct dw_pcie_ep *ep)
|
||||
{
|
||||
@ -630,3 +633,4 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep)
|
||||
|
||||
return dw_pcie_ep_init_complete(ep);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dw_pcie_ep_init);
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/kernel.h>
|
||||
@ -53,6 +54,7 @@
|
||||
#define APPL_INTR_EN_L0_0_LINK_STATE_INT_EN BIT(0)
|
||||
#define APPL_INTR_EN_L0_0_MSI_RCV_INT_EN BIT(4)
|
||||
#define APPL_INTR_EN_L0_0_INT_INT_EN BIT(8)
|
||||
#define APPL_INTR_EN_L0_0_PCI_CMD_EN_INT_EN BIT(15)
|
||||
#define APPL_INTR_EN_L0_0_CDM_REG_CHK_INT_EN BIT(19)
|
||||
#define APPL_INTR_EN_L0_0_SYS_INTR_EN BIT(30)
|
||||
#define APPL_INTR_EN_L0_0_SYS_MSI_INTR_EN BIT(31)
|
||||
@ -60,19 +62,26 @@
|
||||
#define APPL_INTR_STATUS_L0 0xC
|
||||
#define APPL_INTR_STATUS_L0_LINK_STATE_INT BIT(0)
|
||||
#define APPL_INTR_STATUS_L0_INT_INT BIT(8)
|
||||
#define APPL_INTR_STATUS_L0_PCI_CMD_EN_INT BIT(15)
|
||||
#define APPL_INTR_STATUS_L0_PEX_RST_INT BIT(16)
|
||||
#define APPL_INTR_STATUS_L0_CDM_REG_CHK_INT BIT(18)
|
||||
|
||||
#define APPL_INTR_EN_L1_0_0 0x1C
|
||||
#define APPL_INTR_EN_L1_0_0_LINK_REQ_RST_NOT_INT_EN BIT(1)
|
||||
#define APPL_INTR_EN_L1_0_0_RDLH_LINK_UP_INT_EN BIT(3)
|
||||
#define APPL_INTR_EN_L1_0_0_HOT_RESET_DONE_INT_EN BIT(30)
|
||||
|
||||
#define APPL_INTR_STATUS_L1_0_0 0x20
|
||||
#define APPL_INTR_STATUS_L1_0_0_LINK_REQ_RST_NOT_CHGED BIT(1)
|
||||
#define APPL_INTR_STATUS_L1_0_0_RDLH_LINK_UP_CHGED BIT(3)
|
||||
#define APPL_INTR_STATUS_L1_0_0_HOT_RESET_DONE BIT(30)
|
||||
|
||||
#define APPL_INTR_STATUS_L1_1 0x2C
|
||||
#define APPL_INTR_STATUS_L1_2 0x30
|
||||
#define APPL_INTR_STATUS_L1_3 0x34
|
||||
#define APPL_INTR_STATUS_L1_6 0x3C
|
||||
#define APPL_INTR_STATUS_L1_7 0x40
|
||||
#define APPL_INTR_STATUS_L1_15_CFG_BME_CHGED BIT(1)
|
||||
|
||||
#define APPL_INTR_EN_L1_8_0 0x44
|
||||
#define APPL_INTR_EN_L1_8_BW_MGT_INT_EN BIT(2)
|
||||
@ -103,8 +112,12 @@
|
||||
#define APPL_INTR_STATUS_L1_18_CDM_REG_CHK_CMP_ERR BIT(1)
|
||||
#define APPL_INTR_STATUS_L1_18_CDM_REG_CHK_LOGIC_ERR BIT(0)
|
||||
|
||||
#define APPL_MSI_CTRL_1 0xAC
|
||||
|
||||
#define APPL_MSI_CTRL_2 0xB0
|
||||
|
||||
#define APPL_LEGACY_INTX 0xB8
|
||||
|
||||
#define APPL_LTR_MSG_1 0xC4
|
||||
#define LTR_MSG_REQ BIT(15)
|
||||
#define LTR_MST_NO_SNOOP_SHIFT 16
|
||||
@ -205,6 +218,13 @@
|
||||
#define AMBA_ERROR_RESPONSE_CRS_OKAY_FFFFFFFF 1
|
||||
#define AMBA_ERROR_RESPONSE_CRS_OKAY_FFFF0001 2
|
||||
|
||||
#define MSIX_ADDR_MATCH_LOW_OFF 0x940
|
||||
#define MSIX_ADDR_MATCH_LOW_OFF_EN BIT(0)
|
||||
#define MSIX_ADDR_MATCH_LOW_OFF_MASK GENMASK(31, 2)
|
||||
|
||||
#define MSIX_ADDR_MATCH_HIGH_OFF 0x944
|
||||
#define MSIX_ADDR_MATCH_HIGH_OFF_MASK GENMASK(31, 0)
|
||||
|
||||
#define PORT_LOGIC_MSIX_DOORBELL 0x948
|
||||
|
||||
#define CAP_SPCIE_CAP_OFF 0x154
|
||||
@ -223,6 +243,13 @@
|
||||
#define GEN3_CORE_CLK_FREQ 250000000
|
||||
#define GEN4_CORE_CLK_FREQ 500000000
|
||||
|
||||
#define LTR_MSG_TIMEOUT (100 * 1000)
|
||||
|
||||
#define PERST_DEBOUNCE_TIME (5 * 1000)
|
||||
|
||||
#define EP_STATE_DISABLED 0
|
||||
#define EP_STATE_ENABLED 1
|
||||
|
||||
static const unsigned int pcie_gen_freq[] = {
|
||||
GEN1_CORE_CLK_FREQ,
|
||||
GEN2_CORE_CLK_FREQ,
|
||||
@ -260,6 +287,8 @@ struct tegra_pcie_dw {
|
||||
struct dw_pcie pci;
|
||||
struct tegra_bpmp *bpmp;
|
||||
|
||||
enum dw_pcie_device_mode mode;
|
||||
|
||||
bool supports_clkreq;
|
||||
bool enable_cdm_check;
|
||||
bool link_state;
|
||||
@ -283,6 +312,16 @@ struct tegra_pcie_dw {
|
||||
struct phy **phys;
|
||||
|
||||
struct dentry *debugfs;
|
||||
|
||||
/* Endpoint mode specific */
|
||||
struct gpio_desc *pex_rst_gpiod;
|
||||
struct gpio_desc *pex_refclk_sel_gpiod;
|
||||
unsigned int pex_rst_irq;
|
||||
int ep_state;
|
||||
};
|
||||
|
||||
struct tegra_pcie_dw_of_data {
|
||||
enum dw_pcie_device_mode mode;
|
||||
};
|
||||
|
||||
static inline struct tegra_pcie_dw *to_tegra_pcie(struct dw_pcie *pci)
|
||||
@ -339,8 +378,9 @@ static void apply_bad_link_workaround(struct pcie_port *pp)
|
||||
}
|
||||
}
|
||||
|
||||
static irqreturn_t tegra_pcie_rp_irq_handler(struct tegra_pcie_dw *pcie)
|
||||
static irqreturn_t tegra_pcie_rp_irq_handler(int irq, void *arg)
|
||||
{
|
||||
struct tegra_pcie_dw *pcie = arg;
|
||||
struct dw_pcie *pci = &pcie->pci;
|
||||
struct pcie_port *pp = &pci->pp;
|
||||
u32 val, tmp;
|
||||
@ -411,11 +451,121 @@ static irqreturn_t tegra_pcie_rp_irq_handler(struct tegra_pcie_dw *pcie)
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t tegra_pcie_irq_handler(int irq, void *arg)
|
||||
static void pex_ep_event_hot_rst_done(struct tegra_pcie_dw *pcie)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L0);
|
||||
appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_0_0);
|
||||
appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_1);
|
||||
appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_2);
|
||||
appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_3);
|
||||
appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_6);
|
||||
appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_7);
|
||||
appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_8_0);
|
||||
appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_9);
|
||||
appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_10);
|
||||
appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_11);
|
||||
appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_13);
|
||||
appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_14);
|
||||
appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_15);
|
||||
appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_17);
|
||||
appl_writel(pcie, 0xFFFFFFFF, APPL_MSI_CTRL_2);
|
||||
|
||||
val = appl_readl(pcie, APPL_CTRL);
|
||||
val |= APPL_CTRL_LTSSM_EN;
|
||||
appl_writel(pcie, val, APPL_CTRL);
|
||||
}
|
||||
|
||||
static irqreturn_t tegra_pcie_ep_irq_thread(int irq, void *arg)
|
||||
{
|
||||
struct tegra_pcie_dw *pcie = arg;
|
||||
struct dw_pcie *pci = &pcie->pci;
|
||||
u32 val, speed;
|
||||
|
||||
return tegra_pcie_rp_irq_handler(pcie);
|
||||
speed = dw_pcie_readw_dbi(pci, pcie->pcie_cap_base + PCI_EXP_LNKSTA) &
|
||||
PCI_EXP_LNKSTA_CLS;
|
||||
clk_set_rate(pcie->core_clk, pcie_gen_freq[speed - 1]);
|
||||
|
||||
/* If EP doesn't advertise L1SS, just return */
|
||||
val = dw_pcie_readl_dbi(pci, pcie->cfg_link_cap_l1sub);
|
||||
if (!(val & (PCI_L1SS_CAP_ASPM_L1_1 | PCI_L1SS_CAP_ASPM_L1_2)))
|
||||
return IRQ_HANDLED;
|
||||
|
||||
/* Check if BME is set to '1' */
|
||||
val = dw_pcie_readl_dbi(pci, PCI_COMMAND);
|
||||
if (val & PCI_COMMAND_MASTER) {
|
||||
ktime_t timeout;
|
||||
|
||||
/* 110us for both snoop and no-snoop */
|
||||
val = 110 | (2 << PCI_LTR_SCALE_SHIFT) | LTR_MSG_REQ;
|
||||
val |= (val << LTR_MST_NO_SNOOP_SHIFT);
|
||||
appl_writel(pcie, val, APPL_LTR_MSG_1);
|
||||
|
||||
/* Send LTR upstream */
|
||||
val = appl_readl(pcie, APPL_LTR_MSG_2);
|
||||
val |= APPL_LTR_MSG_2_LTR_MSG_REQ_STATE;
|
||||
appl_writel(pcie, val, APPL_LTR_MSG_2);
|
||||
|
||||
timeout = ktime_add_us(ktime_get(), LTR_MSG_TIMEOUT);
|
||||
for (;;) {
|
||||
val = appl_readl(pcie, APPL_LTR_MSG_2);
|
||||
if (!(val & APPL_LTR_MSG_2_LTR_MSG_REQ_STATE))
|
||||
break;
|
||||
if (ktime_after(ktime_get(), timeout))
|
||||
break;
|
||||
usleep_range(1000, 1100);
|
||||
}
|
||||
if (val & APPL_LTR_MSG_2_LTR_MSG_REQ_STATE)
|
||||
dev_err(pcie->dev, "Failed to send LTR message\n");
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t tegra_pcie_ep_hard_irq(int irq, void *arg)
|
||||
{
|
||||
struct tegra_pcie_dw *pcie = arg;
|
||||
struct dw_pcie_ep *ep = &pcie->pci.ep;
|
||||
int spurious = 1;
|
||||
u32 val, tmp;
|
||||
|
||||
val = appl_readl(pcie, APPL_INTR_STATUS_L0);
|
||||
if (val & APPL_INTR_STATUS_L0_LINK_STATE_INT) {
|
||||
val = appl_readl(pcie, APPL_INTR_STATUS_L1_0_0);
|
||||
appl_writel(pcie, val, APPL_INTR_STATUS_L1_0_0);
|
||||
|
||||
if (val & APPL_INTR_STATUS_L1_0_0_HOT_RESET_DONE)
|
||||
pex_ep_event_hot_rst_done(pcie);
|
||||
|
||||
if (val & APPL_INTR_STATUS_L1_0_0_RDLH_LINK_UP_CHGED) {
|
||||
tmp = appl_readl(pcie, APPL_LINK_STATUS);
|
||||
if (tmp & APPL_LINK_STATUS_RDLH_LINK_UP) {
|
||||
dev_dbg(pcie->dev, "Link is up with Host\n");
|
||||
dw_pcie_ep_linkup(ep);
|
||||
}
|
||||
}
|
||||
|
||||
spurious = 0;
|
||||
}
|
||||
|
||||
if (val & APPL_INTR_STATUS_L0_PCI_CMD_EN_INT) {
|
||||
val = appl_readl(pcie, APPL_INTR_STATUS_L1_15);
|
||||
appl_writel(pcie, val, APPL_INTR_STATUS_L1_15);
|
||||
|
||||
if (val & APPL_INTR_STATUS_L1_15_CFG_BME_CHGED)
|
||||
return IRQ_WAKE_THREAD;
|
||||
|
||||
spurious = 0;
|
||||
}
|
||||
|
||||
if (spurious) {
|
||||
dev_warn(pcie->dev, "Random interrupt (STATUS = 0x%08X)\n",
|
||||
val);
|
||||
appl_writel(pcie, val, APPL_INTR_STATUS_L0);
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int tegra_pcie_dw_rd_own_conf(struct pcie_port *pp, int where, int size,
|
||||
@ -884,8 +1034,26 @@ static void tegra_pcie_set_msi_vec_num(struct pcie_port *pp)
|
||||
pp->num_vectors = MAX_MSI_IRQS;
|
||||
}
|
||||
|
||||
static int tegra_pcie_dw_start_link(struct dw_pcie *pci)
|
||||
{
|
||||
struct tegra_pcie_dw *pcie = to_tegra_pcie(pci);
|
||||
|
||||
enable_irq(pcie->pex_rst_irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tegra_pcie_dw_stop_link(struct dw_pcie *pci)
|
||||
{
|
||||
struct tegra_pcie_dw *pcie = to_tegra_pcie(pci);
|
||||
|
||||
disable_irq(pcie->pex_rst_irq);
|
||||
}
|
||||
|
||||
static const struct dw_pcie_ops tegra_dw_pcie_ops = {
|
||||
.link_up = tegra_pcie_dw_link_up,
|
||||
.start_link = tegra_pcie_dw_start_link,
|
||||
.stop_link = tegra_pcie_dw_stop_link,
|
||||
};
|
||||
|
||||
static struct dw_pcie_host_ops tegra_pcie_dw_host_ops = {
|
||||
@ -986,6 +1154,26 @@ static int tegra_pcie_dw_parse_dt(struct tegra_pcie_dw *pcie)
|
||||
pcie->enable_cdm_check =
|
||||
of_property_read_bool(np, "snps,enable-cdm-check");
|
||||
|
||||
if (pcie->mode == DW_PCIE_RC_TYPE)
|
||||
return 0;
|
||||
|
||||
/* Endpoint mode specific DT entries */
|
||||
pcie->pex_rst_gpiod = devm_gpiod_get(pcie->dev, "reset", GPIOD_IN);
|
||||
if (IS_ERR(pcie->pex_rst_gpiod)) {
|
||||
dev_err(pcie->dev, "Failed to get PERST GPIO: %ld\n",
|
||||
PTR_ERR(pcie->pex_rst_gpiod));
|
||||
return PTR_ERR(pcie->pex_rst_gpiod);
|
||||
}
|
||||
|
||||
pcie->pex_refclk_sel_gpiod = devm_gpiod_get(pcie->dev,
|
||||
"nvidia,refclk-select",
|
||||
GPIOD_OUT_HIGH);
|
||||
if (IS_ERR(pcie->pex_refclk_sel_gpiod)) {
|
||||
dev_info(pcie->dev, "Failed to get REFCLK select GPIOs: %ld\n",
|
||||
PTR_ERR(pcie->pex_refclk_sel_gpiod));
|
||||
pcie->pex_refclk_sel_gpiod = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1017,6 +1205,34 @@ static int tegra_pcie_bpmp_set_ctrl_state(struct tegra_pcie_dw *pcie,
|
||||
return tegra_bpmp_transfer(pcie->bpmp, &msg);
|
||||
}
|
||||
|
||||
static int tegra_pcie_bpmp_set_pll_state(struct tegra_pcie_dw *pcie,
|
||||
bool enable)
|
||||
{
|
||||
struct mrq_uphy_response resp;
|
||||
struct tegra_bpmp_message msg;
|
||||
struct mrq_uphy_request req;
|
||||
|
||||
memset(&req, 0, sizeof(req));
|
||||
memset(&resp, 0, sizeof(resp));
|
||||
|
||||
if (enable) {
|
||||
req.cmd = CMD_UPHY_PCIE_EP_CONTROLLER_PLL_INIT;
|
||||
req.ep_ctrlr_pll_init.ep_controller = pcie->cid;
|
||||
} else {
|
||||
req.cmd = CMD_UPHY_PCIE_EP_CONTROLLER_PLL_OFF;
|
||||
req.ep_ctrlr_pll_off.ep_controller = pcie->cid;
|
||||
}
|
||||
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
msg.mrq = MRQ_UPHY;
|
||||
msg.tx.data = &req;
|
||||
msg.tx.size = sizeof(req);
|
||||
msg.rx.data = &resp;
|
||||
msg.rx.size = sizeof(resp);
|
||||
|
||||
return tegra_bpmp_transfer(pcie->bpmp, &msg);
|
||||
}
|
||||
|
||||
static void tegra_pcie_downstream_dev_to_D0(struct tegra_pcie_dw *pcie)
|
||||
{
|
||||
struct pcie_port *pp = &pcie->pci.pp;
|
||||
@ -1427,8 +1643,396 @@ fail_pm_get_sync:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void pex_ep_event_pex_rst_assert(struct tegra_pcie_dw *pcie)
|
||||
{
|
||||
u32 val;
|
||||
int ret;
|
||||
|
||||
if (pcie->ep_state == EP_STATE_DISABLED)
|
||||
return;
|
||||
|
||||
/* Disable LTSSM */
|
||||
val = appl_readl(pcie, APPL_CTRL);
|
||||
val &= ~APPL_CTRL_LTSSM_EN;
|
||||
appl_writel(pcie, val, APPL_CTRL);
|
||||
|
||||
ret = readl_poll_timeout(pcie->appl_base + APPL_DEBUG, val,
|
||||
((val & APPL_DEBUG_LTSSM_STATE_MASK) >>
|
||||
APPL_DEBUG_LTSSM_STATE_SHIFT) ==
|
||||
LTSSM_STATE_PRE_DETECT,
|
||||
1, LTSSM_TIMEOUT);
|
||||
if (ret)
|
||||
dev_err(pcie->dev, "Failed to go Detect state: %d\n", ret);
|
||||
|
||||
reset_control_assert(pcie->core_rst);
|
||||
|
||||
tegra_pcie_disable_phy(pcie);
|
||||
|
||||
reset_control_assert(pcie->core_apb_rst);
|
||||
|
||||
clk_disable_unprepare(pcie->core_clk);
|
||||
|
||||
pm_runtime_put_sync(pcie->dev);
|
||||
|
||||
ret = tegra_pcie_bpmp_set_pll_state(pcie, false);
|
||||
if (ret)
|
||||
dev_err(pcie->dev, "Failed to turn off UPHY: %d\n", ret);
|
||||
|
||||
pcie->ep_state = EP_STATE_DISABLED;
|
||||
dev_dbg(pcie->dev, "Uninitialization of endpoint is completed\n");
|
||||
}
|
||||
|
||||
static void pex_ep_event_pex_rst_deassert(struct tegra_pcie_dw *pcie)
|
||||
{
|
||||
struct dw_pcie *pci = &pcie->pci;
|
||||
struct dw_pcie_ep *ep = &pci->ep;
|
||||
struct device *dev = pcie->dev;
|
||||
u32 val;
|
||||
int ret;
|
||||
|
||||
if (pcie->ep_state == EP_STATE_ENABLED)
|
||||
return;
|
||||
|
||||
ret = pm_runtime_get_sync(dev);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Failed to get runtime sync for PCIe dev: %d\n",
|
||||
ret);
|
||||
return;
|
||||
}
|
||||
|
||||
ret = tegra_pcie_bpmp_set_pll_state(pcie, true);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to init UPHY for PCIe EP: %d\n", ret);
|
||||
goto fail_pll_init;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(pcie->core_clk);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to enable core clock: %d\n", ret);
|
||||
goto fail_core_clk_enable;
|
||||
}
|
||||
|
||||
ret = reset_control_deassert(pcie->core_apb_rst);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to deassert core APB reset: %d\n", ret);
|
||||
goto fail_core_apb_rst;
|
||||
}
|
||||
|
||||
ret = tegra_pcie_enable_phy(pcie);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to enable PHY: %d\n", ret);
|
||||
goto fail_phy;
|
||||
}
|
||||
|
||||
/* Clear any stale interrupt statuses */
|
||||
appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L0);
|
||||
appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_0_0);
|
||||
appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_1);
|
||||
appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_2);
|
||||
appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_3);
|
||||
appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_6);
|
||||
appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_7);
|
||||
appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_8_0);
|
||||
appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_9);
|
||||
appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_10);
|
||||
appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_11);
|
||||
appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_13);
|
||||
appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_14);
|
||||
appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_15);
|
||||
appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_17);
|
||||
|
||||
/* configure this core for EP mode operation */
|
||||
val = appl_readl(pcie, APPL_DM_TYPE);
|
||||
val &= ~APPL_DM_TYPE_MASK;
|
||||
val |= APPL_DM_TYPE_EP;
|
||||
appl_writel(pcie, val, APPL_DM_TYPE);
|
||||
|
||||
appl_writel(pcie, 0x0, APPL_CFG_SLCG_OVERRIDE);
|
||||
|
||||
val = appl_readl(pcie, APPL_CTRL);
|
||||
val |= APPL_CTRL_SYS_PRE_DET_STATE;
|
||||
val |= APPL_CTRL_HW_HOT_RST_EN;
|
||||
appl_writel(pcie, val, APPL_CTRL);
|
||||
|
||||
val = appl_readl(pcie, APPL_CFG_MISC);
|
||||
val |= APPL_CFG_MISC_SLV_EP_MODE;
|
||||
val |= (APPL_CFG_MISC_ARCACHE_VAL << APPL_CFG_MISC_ARCACHE_SHIFT);
|
||||
appl_writel(pcie, val, APPL_CFG_MISC);
|
||||
|
||||
val = appl_readl(pcie, APPL_PINMUX);
|
||||
val |= APPL_PINMUX_CLK_OUTPUT_IN_OVERRIDE_EN;
|
||||
val |= APPL_PINMUX_CLK_OUTPUT_IN_OVERRIDE;
|
||||
appl_writel(pcie, val, APPL_PINMUX);
|
||||
|
||||
appl_writel(pcie, pcie->dbi_res->start & APPL_CFG_BASE_ADDR_MASK,
|
||||
APPL_CFG_BASE_ADDR);
|
||||
|
||||
appl_writel(pcie, pcie->atu_dma_res->start &
|
||||
APPL_CFG_IATU_DMA_BASE_ADDR_MASK,
|
||||
APPL_CFG_IATU_DMA_BASE_ADDR);
|
||||
|
||||
val = appl_readl(pcie, APPL_INTR_EN_L0_0);
|
||||
val |= APPL_INTR_EN_L0_0_SYS_INTR_EN;
|
||||
val |= APPL_INTR_EN_L0_0_LINK_STATE_INT_EN;
|
||||
val |= APPL_INTR_EN_L0_0_PCI_CMD_EN_INT_EN;
|
||||
appl_writel(pcie, val, APPL_INTR_EN_L0_0);
|
||||
|
||||
val = appl_readl(pcie, APPL_INTR_EN_L1_0_0);
|
||||
val |= APPL_INTR_EN_L1_0_0_HOT_RESET_DONE_INT_EN;
|
||||
val |= APPL_INTR_EN_L1_0_0_RDLH_LINK_UP_INT_EN;
|
||||
appl_writel(pcie, val, APPL_INTR_EN_L1_0_0);
|
||||
|
||||
reset_control_deassert(pcie->core_rst);
|
||||
|
||||
if (pcie->update_fc_fixup) {
|
||||
val = dw_pcie_readl_dbi(pci, CFG_TIMER_CTRL_MAX_FUNC_NUM_OFF);
|
||||
val |= 0x1 << CFG_TIMER_CTRL_ACK_NAK_SHIFT;
|
||||
dw_pcie_writel_dbi(pci, CFG_TIMER_CTRL_MAX_FUNC_NUM_OFF, val);
|
||||
}
|
||||
|
||||
config_gen3_gen4_eq_presets(pcie);
|
||||
|
||||
init_host_aspm(pcie);
|
||||
|
||||
/* Disable ASPM-L1SS advertisement if there is no CLKREQ routing */
|
||||
if (!pcie->supports_clkreq) {
|
||||
disable_aspm_l11(pcie);
|
||||
disable_aspm_l12(pcie);
|
||||
}
|
||||
|
||||
val = dw_pcie_readl_dbi(pci, GEN3_RELATED_OFF);
|
||||
val &= ~GEN3_RELATED_OFF_GEN3_ZRXDC_NONCOMPL;
|
||||
dw_pcie_writel_dbi(pci, GEN3_RELATED_OFF, val);
|
||||
|
||||
/* Configure N_FTS & FTS */
|
||||
val = dw_pcie_readl_dbi(pci, PORT_LOGIC_ACK_F_ASPM_CTRL);
|
||||
val &= ~(N_FTS_MASK << N_FTS_SHIFT);
|
||||
val |= N_FTS_VAL << N_FTS_SHIFT;
|
||||
dw_pcie_writel_dbi(pci, PORT_LOGIC_ACK_F_ASPM_CTRL, val);
|
||||
|
||||
val = dw_pcie_readl_dbi(pci, PORT_LOGIC_GEN2_CTRL);
|
||||
val &= ~FTS_MASK;
|
||||
val |= FTS_VAL;
|
||||
dw_pcie_writel_dbi(pci, PORT_LOGIC_GEN2_CTRL, val);
|
||||
|
||||
/* Configure Max Speed from DT */
|
||||
if (pcie->max_speed && pcie->max_speed != -EINVAL) {
|
||||
val = dw_pcie_readl_dbi(pci, pcie->pcie_cap_base +
|
||||
PCI_EXP_LNKCAP);
|
||||
val &= ~PCI_EXP_LNKCAP_SLS;
|
||||
val |= pcie->max_speed;
|
||||
dw_pcie_writel_dbi(pci, pcie->pcie_cap_base + PCI_EXP_LNKCAP,
|
||||
val);
|
||||
}
|
||||
|
||||
pcie->pcie_cap_base = dw_pcie_find_capability(&pcie->pci,
|
||||
PCI_CAP_ID_EXP);
|
||||
clk_set_rate(pcie->core_clk, GEN4_CORE_CLK_FREQ);
|
||||
|
||||
val = (ep->msi_mem_phys & MSIX_ADDR_MATCH_LOW_OFF_MASK);
|
||||
val |= MSIX_ADDR_MATCH_LOW_OFF_EN;
|
||||
dw_pcie_writel_dbi(pci, MSIX_ADDR_MATCH_LOW_OFF, val);
|
||||
val = (lower_32_bits(ep->msi_mem_phys) & MSIX_ADDR_MATCH_HIGH_OFF_MASK);
|
||||
dw_pcie_writel_dbi(pci, MSIX_ADDR_MATCH_HIGH_OFF, val);
|
||||
|
||||
ret = dw_pcie_ep_init_complete(ep);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to complete initialization: %d\n", ret);
|
||||
goto fail_init_complete;
|
||||
}
|
||||
|
||||
dw_pcie_ep_init_notify(ep);
|
||||
|
||||
/* Enable LTSSM */
|
||||
val = appl_readl(pcie, APPL_CTRL);
|
||||
val |= APPL_CTRL_LTSSM_EN;
|
||||
appl_writel(pcie, val, APPL_CTRL);
|
||||
|
||||
pcie->ep_state = EP_STATE_ENABLED;
|
||||
dev_dbg(dev, "Initialization of endpoint is completed\n");
|
||||
|
||||
return;
|
||||
|
||||
fail_init_complete:
|
||||
reset_control_assert(pcie->core_rst);
|
||||
tegra_pcie_disable_phy(pcie);
|
||||
fail_phy:
|
||||
reset_control_assert(pcie->core_apb_rst);
|
||||
fail_core_apb_rst:
|
||||
clk_disable_unprepare(pcie->core_clk);
|
||||
fail_core_clk_enable:
|
||||
tegra_pcie_bpmp_set_pll_state(pcie, false);
|
||||
fail_pll_init:
|
||||
pm_runtime_put_sync(dev);
|
||||
}
|
||||
|
||||
static irqreturn_t tegra_pcie_ep_pex_rst_irq(int irq, void *arg)
|
||||
{
|
||||
struct tegra_pcie_dw *pcie = arg;
|
||||
|
||||
if (gpiod_get_value(pcie->pex_rst_gpiod))
|
||||
pex_ep_event_pex_rst_assert(pcie);
|
||||
else
|
||||
pex_ep_event_pex_rst_deassert(pcie);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int tegra_pcie_ep_raise_legacy_irq(struct tegra_pcie_dw *pcie, u16 irq)
|
||||
{
|
||||
/* Tegra194 supports only INTA */
|
||||
if (irq > 1)
|
||||
return -EINVAL;
|
||||
|
||||
appl_writel(pcie, 1, APPL_LEGACY_INTX);
|
||||
usleep_range(1000, 2000);
|
||||
appl_writel(pcie, 0, APPL_LEGACY_INTX);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra_pcie_ep_raise_msi_irq(struct tegra_pcie_dw *pcie, u16 irq)
|
||||
{
|
||||
if (unlikely(irq > 31))
|
||||
return -EINVAL;
|
||||
|
||||
appl_writel(pcie, (1 << irq), APPL_MSI_CTRL_1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra_pcie_ep_raise_msix_irq(struct tegra_pcie_dw *pcie, u16 irq)
|
||||
{
|
||||
struct dw_pcie_ep *ep = &pcie->pci.ep;
|
||||
|
||||
writel(irq, ep->msi_mem);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no,
|
||||
enum pci_epc_irq_type type,
|
||||
u16 interrupt_num)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
|
||||
struct tegra_pcie_dw *pcie = to_tegra_pcie(pci);
|
||||
|
||||
switch (type) {
|
||||
case PCI_EPC_IRQ_LEGACY:
|
||||
return tegra_pcie_ep_raise_legacy_irq(pcie, interrupt_num);
|
||||
|
||||
case PCI_EPC_IRQ_MSI:
|
||||
return tegra_pcie_ep_raise_msi_irq(pcie, interrupt_num);
|
||||
|
||||
case PCI_EPC_IRQ_MSIX:
|
||||
return tegra_pcie_ep_raise_msix_irq(pcie, interrupt_num);
|
||||
|
||||
default:
|
||||
dev_err(pci->dev, "Unknown IRQ type\n");
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct pci_epc_features tegra_pcie_epc_features = {
|
||||
.linkup_notifier = true,
|
||||
.core_init_notifier = true,
|
||||
.msi_capable = false,
|
||||
.msix_capable = false,
|
||||
.reserved_bar = 1 << BAR_2 | 1 << BAR_3 | 1 << BAR_4 | 1 << BAR_5,
|
||||
.bar_fixed_64bit = 1 << BAR_0,
|
||||
.bar_fixed_size[0] = SZ_1M,
|
||||
};
|
||||
|
||||
static const struct pci_epc_features*
|
||||
tegra_pcie_ep_get_features(struct dw_pcie_ep *ep)
|
||||
{
|
||||
return &tegra_pcie_epc_features;
|
||||
}
|
||||
|
||||
static struct dw_pcie_ep_ops pcie_ep_ops = {
|
||||
.raise_irq = tegra_pcie_ep_raise_irq,
|
||||
.get_features = tegra_pcie_ep_get_features,
|
||||
};
|
||||
|
||||
static int tegra_pcie_config_ep(struct tegra_pcie_dw *pcie,
|
||||
struct platform_device *pdev)
|
||||
{
|
||||
struct dw_pcie *pci = &pcie->pci;
|
||||
struct device *dev = pcie->dev;
|
||||
struct dw_pcie_ep *ep;
|
||||
struct resource *res;
|
||||
char *name;
|
||||
int ret;
|
||||
|
||||
ep = &pci->ep;
|
||||
ep->ops = &pcie_ep_ops;
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "addr_space");
|
||||
if (!res)
|
||||
return -EINVAL;
|
||||
|
||||
ep->phys_base = res->start;
|
||||
ep->addr_size = resource_size(res);
|
||||
ep->page_size = SZ_64K;
|
||||
|
||||
ret = gpiod_set_debounce(pcie->pex_rst_gpiod, PERST_DEBOUNCE_TIME);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Failed to set PERST GPIO debounce time: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = gpiod_to_irq(pcie->pex_rst_gpiod);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Failed to get IRQ for PERST GPIO: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
pcie->pex_rst_irq = (unsigned int)ret;
|
||||
|
||||
name = devm_kasprintf(dev, GFP_KERNEL, "tegra_pcie_%u_pex_rst_irq",
|
||||
pcie->cid);
|
||||
if (!name) {
|
||||
dev_err(dev, "Failed to create PERST IRQ string\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
irq_set_status_flags(pcie->pex_rst_irq, IRQ_NOAUTOEN);
|
||||
|
||||
pcie->ep_state = EP_STATE_DISABLED;
|
||||
|
||||
ret = devm_request_threaded_irq(dev, pcie->pex_rst_irq, NULL,
|
||||
tegra_pcie_ep_pex_rst_irq,
|
||||
IRQF_TRIGGER_RISING |
|
||||
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
|
||||
name, (void *)pcie);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Failed to request IRQ for PERST: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
name = devm_kasprintf(dev, GFP_KERNEL, "tegra_pcie_%u_ep_work",
|
||||
pcie->cid);
|
||||
if (!name) {
|
||||
dev_err(dev, "Failed to create PCIe EP work thread string\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
pm_runtime_enable(dev);
|
||||
|
||||
ret = dw_pcie_ep_init(ep);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to initialize DWC Endpoint subsystem: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra_pcie_dw_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct tegra_pcie_dw_of_data *data;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct resource *atu_dma_res;
|
||||
struct tegra_pcie_dw *pcie;
|
||||
@ -1440,6 +2044,8 @@ static int tegra_pcie_dw_probe(struct platform_device *pdev)
|
||||
int ret;
|
||||
u32 i;
|
||||
|
||||
data = of_device_get_match_data(dev);
|
||||
|
||||
pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL);
|
||||
if (!pcie)
|
||||
return -ENOMEM;
|
||||
@ -1449,6 +2055,7 @@ static int tegra_pcie_dw_probe(struct platform_device *pdev)
|
||||
pci->ops = &tegra_dw_pcie_ops;
|
||||
pp = &pci->pp;
|
||||
pcie->dev = &pdev->dev;
|
||||
pcie->mode = (enum dw_pcie_device_mode)data->mode;
|
||||
|
||||
ret = tegra_pcie_dw_parse_dt(pcie);
|
||||
if (ret < 0) {
|
||||
@ -1462,6 +2069,9 @@ static int tegra_pcie_dw_probe(struct platform_device *pdev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (pcie->pex_refclk_sel_gpiod)
|
||||
gpiod_set_value(pcie->pex_refclk_sel_gpiod, 1);
|
||||
|
||||
pcie->pex_ctl_supply = devm_regulator_get(dev, "vddio-pex-ctl");
|
||||
if (IS_ERR(pcie->pex_ctl_supply)) {
|
||||
ret = PTR_ERR(pcie->pex_ctl_supply);
|
||||
@ -1557,24 +2167,49 @@ static int tegra_pcie_dw_probe(struct platform_device *pdev)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = devm_request_irq(dev, pp->irq, tegra_pcie_irq_handler,
|
||||
IRQF_SHARED, "tegra-pcie-intr", pcie);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to request IRQ %d: %d\n", pp->irq, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
pcie->bpmp = tegra_bpmp_get(dev);
|
||||
if (IS_ERR(pcie->bpmp))
|
||||
return PTR_ERR(pcie->bpmp);
|
||||
|
||||
platform_set_drvdata(pdev, pcie);
|
||||
|
||||
ret = tegra_pcie_config_rp(pcie);
|
||||
if (ret && ret != -ENOMEDIUM)
|
||||
goto fail;
|
||||
else
|
||||
return 0;
|
||||
switch (pcie->mode) {
|
||||
case DW_PCIE_RC_TYPE:
|
||||
ret = devm_request_irq(dev, pp->irq, tegra_pcie_rp_irq_handler,
|
||||
IRQF_SHARED, "tegra-pcie-intr", pcie);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to request IRQ %d: %d\n", pp->irq,
|
||||
ret);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = tegra_pcie_config_rp(pcie);
|
||||
if (ret && ret != -ENOMEDIUM)
|
||||
goto fail;
|
||||
else
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case DW_PCIE_EP_TYPE:
|
||||
ret = devm_request_threaded_irq(dev, pp->irq,
|
||||
tegra_pcie_ep_hard_irq,
|
||||
tegra_pcie_ep_irq_thread,
|
||||
IRQF_SHARED | IRQF_ONESHOT,
|
||||
"tegra-pcie-ep-intr", pcie);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to request IRQ %d: %d\n", pp->irq,
|
||||
ret);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = tegra_pcie_config_ep(pcie, pdev);
|
||||
if (ret < 0)
|
||||
goto fail;
|
||||
break;
|
||||
|
||||
default:
|
||||
dev_err(dev, "Invalid PCIe device type %d\n", pcie->mode);
|
||||
}
|
||||
|
||||
fail:
|
||||
tegra_bpmp_put(pcie->bpmp);
|
||||
@ -1593,6 +2228,8 @@ static int tegra_pcie_dw_remove(struct platform_device *pdev)
|
||||
pm_runtime_put_sync(pcie->dev);
|
||||
pm_runtime_disable(pcie->dev);
|
||||
tegra_bpmp_put(pcie->bpmp);
|
||||
if (pcie->pex_refclk_sel_gpiod)
|
||||
gpiod_set_value(pcie->pex_refclk_sel_gpiod, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1697,9 +2334,22 @@ static void tegra_pcie_dw_shutdown(struct platform_device *pdev)
|
||||
__deinit_controller(pcie);
|
||||
}
|
||||
|
||||
static const struct tegra_pcie_dw_of_data tegra_pcie_dw_rc_of_data = {
|
||||
.mode = DW_PCIE_RC_TYPE,
|
||||
};
|
||||
|
||||
static const struct tegra_pcie_dw_of_data tegra_pcie_dw_ep_of_data = {
|
||||
.mode = DW_PCIE_EP_TYPE,
|
||||
};
|
||||
|
||||
static const struct of_device_id tegra_pcie_dw_of_match[] = {
|
||||
{
|
||||
.compatible = "nvidia,tegra194-pcie",
|
||||
.data = &tegra_pcie_dw_rc_of_data,
|
||||
},
|
||||
{
|
||||
.compatible = "nvidia,tegra194-pcie-ep",
|
||||
.data = &tegra_pcie_dw_ep_of_data,
|
||||
},
|
||||
{},
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user