162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * PCIe host controller driver for the following SoCs 462306a36Sopenharmony_ci * Tegra194 562306a36Sopenharmony_ci * Tegra234 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Copyright (C) 2019-2022 NVIDIA Corporation. 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * Author: Vidya Sagar <vidyas@nvidia.com> 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include <linux/bitfield.h> 1362306a36Sopenharmony_ci#include <linux/clk.h> 1462306a36Sopenharmony_ci#include <linux/debugfs.h> 1562306a36Sopenharmony_ci#include <linux/delay.h> 1662306a36Sopenharmony_ci#include <linux/gpio.h> 1762306a36Sopenharmony_ci#include <linux/gpio/consumer.h> 1862306a36Sopenharmony_ci#include <linux/interconnect.h> 1962306a36Sopenharmony_ci#include <linux/interrupt.h> 2062306a36Sopenharmony_ci#include <linux/iopoll.h> 2162306a36Sopenharmony_ci#include <linux/kernel.h> 2262306a36Sopenharmony_ci#include <linux/module.h> 2362306a36Sopenharmony_ci#include <linux/of.h> 2462306a36Sopenharmony_ci#include <linux/of_gpio.h> 2562306a36Sopenharmony_ci#include <linux/of_pci.h> 2662306a36Sopenharmony_ci#include <linux/pci.h> 2762306a36Sopenharmony_ci#include <linux/phy/phy.h> 2862306a36Sopenharmony_ci#include <linux/pinctrl/consumer.h> 2962306a36Sopenharmony_ci#include <linux/platform_device.h> 3062306a36Sopenharmony_ci#include <linux/pm_runtime.h> 3162306a36Sopenharmony_ci#include <linux/random.h> 3262306a36Sopenharmony_ci#include <linux/reset.h> 3362306a36Sopenharmony_ci#include <linux/resource.h> 3462306a36Sopenharmony_ci#include <linux/types.h> 3562306a36Sopenharmony_ci#include "pcie-designware.h" 3662306a36Sopenharmony_ci#include <soc/tegra/bpmp.h> 3762306a36Sopenharmony_ci#include <soc/tegra/bpmp-abi.h> 3862306a36Sopenharmony_ci#include "../../pci.h" 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci#define TEGRA194_DWC_IP_VER 0x490A 4162306a36Sopenharmony_ci#define TEGRA234_DWC_IP_VER 0x562A 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci#define APPL_PINMUX 0x0 4462306a36Sopenharmony_ci#define APPL_PINMUX_PEX_RST BIT(0) 4562306a36Sopenharmony_ci#define APPL_PINMUX_CLKREQ_OVERRIDE_EN BIT(2) 4662306a36Sopenharmony_ci#define APPL_PINMUX_CLKREQ_OVERRIDE BIT(3) 4762306a36Sopenharmony_ci#define APPL_PINMUX_CLK_OUTPUT_IN_OVERRIDE_EN BIT(4) 4862306a36Sopenharmony_ci#define APPL_PINMUX_CLK_OUTPUT_IN_OVERRIDE BIT(5) 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci#define APPL_CTRL 0x4 5162306a36Sopenharmony_ci#define APPL_CTRL_SYS_PRE_DET_STATE BIT(6) 5262306a36Sopenharmony_ci#define APPL_CTRL_LTSSM_EN BIT(7) 5362306a36Sopenharmony_ci#define APPL_CTRL_HW_HOT_RST_EN BIT(20) 5462306a36Sopenharmony_ci#define APPL_CTRL_HW_HOT_RST_MODE_MASK GENMASK(1, 0) 5562306a36Sopenharmony_ci#define APPL_CTRL_HW_HOT_RST_MODE_SHIFT 22 5662306a36Sopenharmony_ci#define APPL_CTRL_HW_HOT_RST_MODE_IMDT_RST 0x1 5762306a36Sopenharmony_ci#define APPL_CTRL_HW_HOT_RST_MODE_IMDT_RST_LTSSM_EN 0x2 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci#define APPL_INTR_EN_L0_0 0x8 6062306a36Sopenharmony_ci#define APPL_INTR_EN_L0_0_LINK_STATE_INT_EN BIT(0) 6162306a36Sopenharmony_ci#define APPL_INTR_EN_L0_0_MSI_RCV_INT_EN BIT(4) 6262306a36Sopenharmony_ci#define APPL_INTR_EN_L0_0_INT_INT_EN BIT(8) 6362306a36Sopenharmony_ci#define APPL_INTR_EN_L0_0_PCI_CMD_EN_INT_EN BIT(15) 6462306a36Sopenharmony_ci#define APPL_INTR_EN_L0_0_CDM_REG_CHK_INT_EN BIT(19) 6562306a36Sopenharmony_ci#define APPL_INTR_EN_L0_0_SYS_INTR_EN BIT(30) 6662306a36Sopenharmony_ci#define APPL_INTR_EN_L0_0_SYS_MSI_INTR_EN BIT(31) 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci#define APPL_INTR_STATUS_L0 0xC 6962306a36Sopenharmony_ci#define APPL_INTR_STATUS_L0_LINK_STATE_INT BIT(0) 7062306a36Sopenharmony_ci#define APPL_INTR_STATUS_L0_INT_INT BIT(8) 7162306a36Sopenharmony_ci#define APPL_INTR_STATUS_L0_PCI_CMD_EN_INT BIT(15) 7262306a36Sopenharmony_ci#define APPL_INTR_STATUS_L0_PEX_RST_INT BIT(16) 7362306a36Sopenharmony_ci#define APPL_INTR_STATUS_L0_CDM_REG_CHK_INT BIT(18) 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci#define APPL_INTR_EN_L1_0_0 0x1C 7662306a36Sopenharmony_ci#define APPL_INTR_EN_L1_0_0_LINK_REQ_RST_NOT_INT_EN BIT(1) 7762306a36Sopenharmony_ci#define APPL_INTR_EN_L1_0_0_RDLH_LINK_UP_INT_EN BIT(3) 7862306a36Sopenharmony_ci#define APPL_INTR_EN_L1_0_0_HOT_RESET_DONE_INT_EN BIT(30) 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci#define APPL_INTR_STATUS_L1_0_0 0x20 8162306a36Sopenharmony_ci#define APPL_INTR_STATUS_L1_0_0_LINK_REQ_RST_NOT_CHGED BIT(1) 8262306a36Sopenharmony_ci#define APPL_INTR_STATUS_L1_0_0_RDLH_LINK_UP_CHGED BIT(3) 8362306a36Sopenharmony_ci#define APPL_INTR_STATUS_L1_0_0_HOT_RESET_DONE BIT(30) 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci#define APPL_INTR_STATUS_L1_1 0x2C 8662306a36Sopenharmony_ci#define APPL_INTR_STATUS_L1_2 0x30 8762306a36Sopenharmony_ci#define APPL_INTR_STATUS_L1_3 0x34 8862306a36Sopenharmony_ci#define APPL_INTR_STATUS_L1_6 0x3C 8962306a36Sopenharmony_ci#define APPL_INTR_STATUS_L1_7 0x40 9062306a36Sopenharmony_ci#define APPL_INTR_STATUS_L1_15_CFG_BME_CHGED BIT(1) 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci#define APPL_INTR_EN_L1_8_0 0x44 9362306a36Sopenharmony_ci#define APPL_INTR_EN_L1_8_BW_MGT_INT_EN BIT(2) 9462306a36Sopenharmony_ci#define APPL_INTR_EN_L1_8_AUTO_BW_INT_EN BIT(3) 9562306a36Sopenharmony_ci#define APPL_INTR_EN_L1_8_INTX_EN BIT(11) 9662306a36Sopenharmony_ci#define APPL_INTR_EN_L1_8_AER_INT_EN BIT(15) 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci#define APPL_INTR_STATUS_L1_8_0 0x4C 9962306a36Sopenharmony_ci#define APPL_INTR_STATUS_L1_8_0_EDMA_INT_MASK GENMASK(11, 6) 10062306a36Sopenharmony_ci#define APPL_INTR_STATUS_L1_8_0_BW_MGT_INT_STS BIT(2) 10162306a36Sopenharmony_ci#define APPL_INTR_STATUS_L1_8_0_AUTO_BW_INT_STS BIT(3) 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci#define APPL_INTR_STATUS_L1_9 0x54 10462306a36Sopenharmony_ci#define APPL_INTR_STATUS_L1_10 0x58 10562306a36Sopenharmony_ci#define APPL_INTR_STATUS_L1_11 0x64 10662306a36Sopenharmony_ci#define APPL_INTR_STATUS_L1_13 0x74 10762306a36Sopenharmony_ci#define APPL_INTR_STATUS_L1_14 0x78 10862306a36Sopenharmony_ci#define APPL_INTR_STATUS_L1_15 0x7C 10962306a36Sopenharmony_ci#define APPL_INTR_STATUS_L1_17 0x88 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci#define APPL_INTR_EN_L1_18 0x90 11262306a36Sopenharmony_ci#define APPL_INTR_EN_L1_18_CDM_REG_CHK_CMPLT BIT(2) 11362306a36Sopenharmony_ci#define APPL_INTR_EN_L1_18_CDM_REG_CHK_CMP_ERR BIT(1) 11462306a36Sopenharmony_ci#define APPL_INTR_EN_L1_18_CDM_REG_CHK_LOGIC_ERR BIT(0) 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci#define APPL_INTR_STATUS_L1_18 0x94 11762306a36Sopenharmony_ci#define APPL_INTR_STATUS_L1_18_CDM_REG_CHK_CMPLT BIT(2) 11862306a36Sopenharmony_ci#define APPL_INTR_STATUS_L1_18_CDM_REG_CHK_CMP_ERR BIT(1) 11962306a36Sopenharmony_ci#define APPL_INTR_STATUS_L1_18_CDM_REG_CHK_LOGIC_ERR BIT(0) 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci#define APPL_MSI_CTRL_1 0xAC 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci#define APPL_MSI_CTRL_2 0xB0 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci#define APPL_LEGACY_INTX 0xB8 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci#define APPL_LTR_MSG_1 0xC4 12862306a36Sopenharmony_ci#define LTR_MSG_REQ BIT(15) 12962306a36Sopenharmony_ci#define LTR_MST_NO_SNOOP_SHIFT 16 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci#define APPL_LTR_MSG_2 0xC8 13262306a36Sopenharmony_ci#define APPL_LTR_MSG_2_LTR_MSG_REQ_STATE BIT(3) 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci#define APPL_LINK_STATUS 0xCC 13562306a36Sopenharmony_ci#define APPL_LINK_STATUS_RDLH_LINK_UP BIT(0) 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci#define APPL_DEBUG 0xD0 13862306a36Sopenharmony_ci#define APPL_DEBUG_PM_LINKST_IN_L2_LAT BIT(21) 13962306a36Sopenharmony_ci#define APPL_DEBUG_PM_LINKST_IN_L0 0x11 14062306a36Sopenharmony_ci#define APPL_DEBUG_LTSSM_STATE_MASK GENMASK(8, 3) 14162306a36Sopenharmony_ci#define APPL_DEBUG_LTSSM_STATE_SHIFT 3 14262306a36Sopenharmony_ci#define LTSSM_STATE_PRE_DETECT 5 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci#define APPL_RADM_STATUS 0xE4 14562306a36Sopenharmony_ci#define APPL_PM_XMT_TURNOFF_STATE BIT(0) 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci#define APPL_DM_TYPE 0x100 14862306a36Sopenharmony_ci#define APPL_DM_TYPE_MASK GENMASK(3, 0) 14962306a36Sopenharmony_ci#define APPL_DM_TYPE_RP 0x4 15062306a36Sopenharmony_ci#define APPL_DM_TYPE_EP 0x0 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci#define APPL_CFG_BASE_ADDR 0x104 15362306a36Sopenharmony_ci#define APPL_CFG_BASE_ADDR_MASK GENMASK(31, 12) 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci#define APPL_CFG_IATU_DMA_BASE_ADDR 0x108 15662306a36Sopenharmony_ci#define APPL_CFG_IATU_DMA_BASE_ADDR_MASK GENMASK(31, 18) 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci#define APPL_CFG_MISC 0x110 15962306a36Sopenharmony_ci#define APPL_CFG_MISC_SLV_EP_MODE BIT(14) 16062306a36Sopenharmony_ci#define APPL_CFG_MISC_ARCACHE_MASK GENMASK(13, 10) 16162306a36Sopenharmony_ci#define APPL_CFG_MISC_ARCACHE_SHIFT 10 16262306a36Sopenharmony_ci#define APPL_CFG_MISC_ARCACHE_VAL 3 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci#define APPL_CFG_SLCG_OVERRIDE 0x114 16562306a36Sopenharmony_ci#define APPL_CFG_SLCG_OVERRIDE_SLCG_EN_MASTER BIT(0) 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci#define APPL_CAR_RESET_OVRD 0x12C 16862306a36Sopenharmony_ci#define APPL_CAR_RESET_OVRD_CYA_OVERRIDE_CORE_RST_N BIT(0) 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci#define IO_BASE_IO_DECODE BIT(0) 17162306a36Sopenharmony_ci#define IO_BASE_IO_DECODE_BIT8 BIT(8) 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci#define CFG_PREF_MEM_LIMIT_BASE_MEM_DECODE BIT(0) 17462306a36Sopenharmony_ci#define CFG_PREF_MEM_LIMIT_BASE_MEM_LIMIT_DECODE BIT(16) 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci#define CFG_TIMER_CTRL_MAX_FUNC_NUM_OFF 0x718 17762306a36Sopenharmony_ci#define CFG_TIMER_CTRL_ACK_NAK_SHIFT (19) 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci#define N_FTS_VAL 52 18062306a36Sopenharmony_ci#define FTS_VAL 52 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci#define GEN3_EQ_CONTROL_OFF 0x8a8 18362306a36Sopenharmony_ci#define GEN3_EQ_CONTROL_OFF_PSET_REQ_VEC_SHIFT 8 18462306a36Sopenharmony_ci#define GEN3_EQ_CONTROL_OFF_PSET_REQ_VEC_MASK GENMASK(23, 8) 18562306a36Sopenharmony_ci#define GEN3_EQ_CONTROL_OFF_FB_MODE_MASK GENMASK(3, 0) 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci#define PORT_LOGIC_AMBA_ERROR_RESPONSE_DEFAULT 0x8D0 18862306a36Sopenharmony_ci#define AMBA_ERROR_RESPONSE_CRS_SHIFT 3 18962306a36Sopenharmony_ci#define AMBA_ERROR_RESPONSE_CRS_MASK GENMASK(1, 0) 19062306a36Sopenharmony_ci#define AMBA_ERROR_RESPONSE_CRS_OKAY 0 19162306a36Sopenharmony_ci#define AMBA_ERROR_RESPONSE_CRS_OKAY_FFFFFFFF 1 19262306a36Sopenharmony_ci#define AMBA_ERROR_RESPONSE_CRS_OKAY_FFFF0001 2 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci#define MSIX_ADDR_MATCH_LOW_OFF 0x940 19562306a36Sopenharmony_ci#define MSIX_ADDR_MATCH_LOW_OFF_EN BIT(0) 19662306a36Sopenharmony_ci#define MSIX_ADDR_MATCH_LOW_OFF_MASK GENMASK(31, 2) 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci#define MSIX_ADDR_MATCH_HIGH_OFF 0x944 19962306a36Sopenharmony_ci#define MSIX_ADDR_MATCH_HIGH_OFF_MASK GENMASK(31, 0) 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci#define PORT_LOGIC_MSIX_DOORBELL 0x948 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci#define CAP_SPCIE_CAP_OFF 0x154 20462306a36Sopenharmony_ci#define CAP_SPCIE_CAP_OFF_DSP_TX_PRESET0_MASK GENMASK(3, 0) 20562306a36Sopenharmony_ci#define CAP_SPCIE_CAP_OFF_USP_TX_PRESET0_MASK GENMASK(11, 8) 20662306a36Sopenharmony_ci#define CAP_SPCIE_CAP_OFF_USP_TX_PRESET0_SHIFT 8 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci#define PME_ACK_TIMEOUT 10000 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci#define LTSSM_TIMEOUT 50000 /* 50ms */ 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci#define GEN3_GEN4_EQ_PRESET_INIT 5 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci#define GEN1_CORE_CLK_FREQ 62500000 21562306a36Sopenharmony_ci#define GEN2_CORE_CLK_FREQ 125000000 21662306a36Sopenharmony_ci#define GEN3_CORE_CLK_FREQ 250000000 21762306a36Sopenharmony_ci#define GEN4_CORE_CLK_FREQ 500000000 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci#define LTR_MSG_TIMEOUT (100 * 1000) 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci#define PERST_DEBOUNCE_TIME (5 * 1000) 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci#define EP_STATE_DISABLED 0 22462306a36Sopenharmony_ci#define EP_STATE_ENABLED 1 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_cistatic const unsigned int pcie_gen_freq[] = { 22762306a36Sopenharmony_ci GEN1_CORE_CLK_FREQ, /* PCI_EXP_LNKSTA_CLS == 0; undefined */ 22862306a36Sopenharmony_ci GEN1_CORE_CLK_FREQ, 22962306a36Sopenharmony_ci GEN2_CORE_CLK_FREQ, 23062306a36Sopenharmony_ci GEN3_CORE_CLK_FREQ, 23162306a36Sopenharmony_ci GEN4_CORE_CLK_FREQ 23262306a36Sopenharmony_ci}; 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_cistruct tegra_pcie_dw_of_data { 23562306a36Sopenharmony_ci u32 version; 23662306a36Sopenharmony_ci enum dw_pcie_device_mode mode; 23762306a36Sopenharmony_ci bool has_msix_doorbell_access_fix; 23862306a36Sopenharmony_ci bool has_sbr_reset_fix; 23962306a36Sopenharmony_ci bool has_l1ss_exit_fix; 24062306a36Sopenharmony_ci bool has_ltr_req_fix; 24162306a36Sopenharmony_ci u32 cdm_chk_int_en_bit; 24262306a36Sopenharmony_ci u32 gen4_preset_vec; 24362306a36Sopenharmony_ci u8 n_fts[2]; 24462306a36Sopenharmony_ci}; 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_cistruct tegra_pcie_dw { 24762306a36Sopenharmony_ci struct device *dev; 24862306a36Sopenharmony_ci struct resource *appl_res; 24962306a36Sopenharmony_ci struct resource *dbi_res; 25062306a36Sopenharmony_ci struct resource *atu_dma_res; 25162306a36Sopenharmony_ci void __iomem *appl_base; 25262306a36Sopenharmony_ci struct clk *core_clk; 25362306a36Sopenharmony_ci struct reset_control *core_apb_rst; 25462306a36Sopenharmony_ci struct reset_control *core_rst; 25562306a36Sopenharmony_ci struct dw_pcie pci; 25662306a36Sopenharmony_ci struct tegra_bpmp *bpmp; 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci struct tegra_pcie_dw_of_data *of_data; 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci bool supports_clkreq; 26162306a36Sopenharmony_ci bool enable_cdm_check; 26262306a36Sopenharmony_ci bool enable_srns; 26362306a36Sopenharmony_ci bool link_state; 26462306a36Sopenharmony_ci bool update_fc_fixup; 26562306a36Sopenharmony_ci bool enable_ext_refclk; 26662306a36Sopenharmony_ci u8 init_link_width; 26762306a36Sopenharmony_ci u32 msi_ctrl_int; 26862306a36Sopenharmony_ci u32 num_lanes; 26962306a36Sopenharmony_ci u32 cid; 27062306a36Sopenharmony_ci u32 cfg_link_cap_l1sub; 27162306a36Sopenharmony_ci u32 ras_des_cap; 27262306a36Sopenharmony_ci u32 pcie_cap_base; 27362306a36Sopenharmony_ci u32 aspm_cmrt; 27462306a36Sopenharmony_ci u32 aspm_pwr_on_t; 27562306a36Sopenharmony_ci u32 aspm_l0s_enter_lat; 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci struct regulator *pex_ctl_supply; 27862306a36Sopenharmony_ci struct regulator *slot_ctl_3v3; 27962306a36Sopenharmony_ci struct regulator *slot_ctl_12v; 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci unsigned int phy_count; 28262306a36Sopenharmony_ci struct phy **phys; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci struct dentry *debugfs; 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci /* Endpoint mode specific */ 28762306a36Sopenharmony_ci struct gpio_desc *pex_rst_gpiod; 28862306a36Sopenharmony_ci struct gpio_desc *pex_refclk_sel_gpiod; 28962306a36Sopenharmony_ci unsigned int pex_rst_irq; 29062306a36Sopenharmony_ci int ep_state; 29162306a36Sopenharmony_ci long link_status; 29262306a36Sopenharmony_ci struct icc_path *icc_path; 29362306a36Sopenharmony_ci}; 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_cistatic inline struct tegra_pcie_dw *to_tegra_pcie(struct dw_pcie *pci) 29662306a36Sopenharmony_ci{ 29762306a36Sopenharmony_ci return container_of(pci, struct tegra_pcie_dw, pci); 29862306a36Sopenharmony_ci} 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_cistatic inline void appl_writel(struct tegra_pcie_dw *pcie, const u32 value, 30162306a36Sopenharmony_ci const u32 reg) 30262306a36Sopenharmony_ci{ 30362306a36Sopenharmony_ci writel_relaxed(value, pcie->appl_base + reg); 30462306a36Sopenharmony_ci} 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_cistatic inline u32 appl_readl(struct tegra_pcie_dw *pcie, const u32 reg) 30762306a36Sopenharmony_ci{ 30862306a36Sopenharmony_ci return readl_relaxed(pcie->appl_base + reg); 30962306a36Sopenharmony_ci} 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_cistruct tegra_pcie_soc { 31262306a36Sopenharmony_ci enum dw_pcie_device_mode mode; 31362306a36Sopenharmony_ci}; 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_cistatic void tegra_pcie_icc_set(struct tegra_pcie_dw *pcie) 31662306a36Sopenharmony_ci{ 31762306a36Sopenharmony_ci struct dw_pcie *pci = &pcie->pci; 31862306a36Sopenharmony_ci u32 val, speed, width; 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci val = dw_pcie_readw_dbi(pci, pcie->pcie_cap_base + PCI_EXP_LNKSTA); 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci speed = FIELD_GET(PCI_EXP_LNKSTA_CLS, val); 32362306a36Sopenharmony_ci width = FIELD_GET(PCI_EXP_LNKSTA_NLW, val); 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci val = width * (PCIE_SPEED2MBS_ENC(pcie_link_speed[speed]) / BITS_PER_BYTE); 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci if (icc_set_bw(pcie->icc_path, MBps_to_icc(val), 0)) 32862306a36Sopenharmony_ci dev_err(pcie->dev, "can't set bw[%u]\n", val); 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci if (speed >= ARRAY_SIZE(pcie_gen_freq)) 33162306a36Sopenharmony_ci speed = 0; 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci clk_set_rate(pcie->core_clk, pcie_gen_freq[speed]); 33462306a36Sopenharmony_ci} 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_cistatic void apply_bad_link_workaround(struct dw_pcie_rp *pp) 33762306a36Sopenharmony_ci{ 33862306a36Sopenharmony_ci struct dw_pcie *pci = to_dw_pcie_from_pp(pp); 33962306a36Sopenharmony_ci struct tegra_pcie_dw *pcie = to_tegra_pcie(pci); 34062306a36Sopenharmony_ci u32 current_link_width; 34162306a36Sopenharmony_ci u16 val; 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci /* 34462306a36Sopenharmony_ci * NOTE:- Since this scenario is uncommon and link as such is not 34562306a36Sopenharmony_ci * stable anyway, not waiting to confirm if link is really 34662306a36Sopenharmony_ci * transitioning to Gen-2 speed 34762306a36Sopenharmony_ci */ 34862306a36Sopenharmony_ci val = dw_pcie_readw_dbi(pci, pcie->pcie_cap_base + PCI_EXP_LNKSTA); 34962306a36Sopenharmony_ci if (val & PCI_EXP_LNKSTA_LBMS) { 35062306a36Sopenharmony_ci current_link_width = FIELD_GET(PCI_EXP_LNKSTA_NLW, val); 35162306a36Sopenharmony_ci if (pcie->init_link_width > current_link_width) { 35262306a36Sopenharmony_ci dev_warn(pci->dev, "PCIe link is bad, width reduced\n"); 35362306a36Sopenharmony_ci val = dw_pcie_readw_dbi(pci, pcie->pcie_cap_base + 35462306a36Sopenharmony_ci PCI_EXP_LNKCTL2); 35562306a36Sopenharmony_ci val &= ~PCI_EXP_LNKCTL2_TLS; 35662306a36Sopenharmony_ci val |= PCI_EXP_LNKCTL2_TLS_2_5GT; 35762306a36Sopenharmony_ci dw_pcie_writew_dbi(pci, pcie->pcie_cap_base + 35862306a36Sopenharmony_ci PCI_EXP_LNKCTL2, val); 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci val = dw_pcie_readw_dbi(pci, pcie->pcie_cap_base + 36162306a36Sopenharmony_ci PCI_EXP_LNKCTL); 36262306a36Sopenharmony_ci val |= PCI_EXP_LNKCTL_RL; 36362306a36Sopenharmony_ci dw_pcie_writew_dbi(pci, pcie->pcie_cap_base + 36462306a36Sopenharmony_ci PCI_EXP_LNKCTL, val); 36562306a36Sopenharmony_ci } 36662306a36Sopenharmony_ci } 36762306a36Sopenharmony_ci} 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_cistatic irqreturn_t tegra_pcie_rp_irq_handler(int irq, void *arg) 37062306a36Sopenharmony_ci{ 37162306a36Sopenharmony_ci struct tegra_pcie_dw *pcie = arg; 37262306a36Sopenharmony_ci struct dw_pcie *pci = &pcie->pci; 37362306a36Sopenharmony_ci struct dw_pcie_rp *pp = &pci->pp; 37462306a36Sopenharmony_ci u32 val, status_l0, status_l1; 37562306a36Sopenharmony_ci u16 val_w; 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci status_l0 = appl_readl(pcie, APPL_INTR_STATUS_L0); 37862306a36Sopenharmony_ci if (status_l0 & APPL_INTR_STATUS_L0_LINK_STATE_INT) { 37962306a36Sopenharmony_ci status_l1 = appl_readl(pcie, APPL_INTR_STATUS_L1_0_0); 38062306a36Sopenharmony_ci appl_writel(pcie, status_l1, APPL_INTR_STATUS_L1_0_0); 38162306a36Sopenharmony_ci if (!pcie->of_data->has_sbr_reset_fix && 38262306a36Sopenharmony_ci status_l1 & APPL_INTR_STATUS_L1_0_0_LINK_REQ_RST_NOT_CHGED) { 38362306a36Sopenharmony_ci /* SBR & Surprise Link Down WAR */ 38462306a36Sopenharmony_ci val = appl_readl(pcie, APPL_CAR_RESET_OVRD); 38562306a36Sopenharmony_ci val &= ~APPL_CAR_RESET_OVRD_CYA_OVERRIDE_CORE_RST_N; 38662306a36Sopenharmony_ci appl_writel(pcie, val, APPL_CAR_RESET_OVRD); 38762306a36Sopenharmony_ci udelay(1); 38862306a36Sopenharmony_ci val = appl_readl(pcie, APPL_CAR_RESET_OVRD); 38962306a36Sopenharmony_ci val |= APPL_CAR_RESET_OVRD_CYA_OVERRIDE_CORE_RST_N; 39062306a36Sopenharmony_ci appl_writel(pcie, val, APPL_CAR_RESET_OVRD); 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci val = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL); 39362306a36Sopenharmony_ci val |= PORT_LOGIC_SPEED_CHANGE; 39462306a36Sopenharmony_ci dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, val); 39562306a36Sopenharmony_ci } 39662306a36Sopenharmony_ci } 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci if (status_l0 & APPL_INTR_STATUS_L0_INT_INT) { 39962306a36Sopenharmony_ci status_l1 = appl_readl(pcie, APPL_INTR_STATUS_L1_8_0); 40062306a36Sopenharmony_ci if (status_l1 & APPL_INTR_STATUS_L1_8_0_AUTO_BW_INT_STS) { 40162306a36Sopenharmony_ci appl_writel(pcie, 40262306a36Sopenharmony_ci APPL_INTR_STATUS_L1_8_0_AUTO_BW_INT_STS, 40362306a36Sopenharmony_ci APPL_INTR_STATUS_L1_8_0); 40462306a36Sopenharmony_ci apply_bad_link_workaround(pp); 40562306a36Sopenharmony_ci } 40662306a36Sopenharmony_ci if (status_l1 & APPL_INTR_STATUS_L1_8_0_BW_MGT_INT_STS) { 40762306a36Sopenharmony_ci val_w = dw_pcie_readw_dbi(pci, pcie->pcie_cap_base + 40862306a36Sopenharmony_ci PCI_EXP_LNKSTA); 40962306a36Sopenharmony_ci val_w |= PCI_EXP_LNKSTA_LBMS; 41062306a36Sopenharmony_ci dw_pcie_writew_dbi(pci, pcie->pcie_cap_base + 41162306a36Sopenharmony_ci PCI_EXP_LNKSTA, val_w); 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci appl_writel(pcie, 41462306a36Sopenharmony_ci APPL_INTR_STATUS_L1_8_0_BW_MGT_INT_STS, 41562306a36Sopenharmony_ci APPL_INTR_STATUS_L1_8_0); 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci val_w = dw_pcie_readw_dbi(pci, pcie->pcie_cap_base + 41862306a36Sopenharmony_ci PCI_EXP_LNKSTA); 41962306a36Sopenharmony_ci dev_dbg(pci->dev, "Link Speed : Gen-%u\n", val_w & 42062306a36Sopenharmony_ci PCI_EXP_LNKSTA_CLS); 42162306a36Sopenharmony_ci } 42262306a36Sopenharmony_ci } 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci if (status_l0 & APPL_INTR_STATUS_L0_CDM_REG_CHK_INT) { 42562306a36Sopenharmony_ci status_l1 = appl_readl(pcie, APPL_INTR_STATUS_L1_18); 42662306a36Sopenharmony_ci val = dw_pcie_readl_dbi(pci, PCIE_PL_CHK_REG_CONTROL_STATUS); 42762306a36Sopenharmony_ci if (status_l1 & APPL_INTR_STATUS_L1_18_CDM_REG_CHK_CMPLT) { 42862306a36Sopenharmony_ci dev_info(pci->dev, "CDM check complete\n"); 42962306a36Sopenharmony_ci val |= PCIE_PL_CHK_REG_CHK_REG_COMPLETE; 43062306a36Sopenharmony_ci } 43162306a36Sopenharmony_ci if (status_l1 & APPL_INTR_STATUS_L1_18_CDM_REG_CHK_CMP_ERR) { 43262306a36Sopenharmony_ci dev_err(pci->dev, "CDM comparison mismatch\n"); 43362306a36Sopenharmony_ci val |= PCIE_PL_CHK_REG_CHK_REG_COMPARISON_ERROR; 43462306a36Sopenharmony_ci } 43562306a36Sopenharmony_ci if (status_l1 & APPL_INTR_STATUS_L1_18_CDM_REG_CHK_LOGIC_ERR) { 43662306a36Sopenharmony_ci dev_err(pci->dev, "CDM Logic error\n"); 43762306a36Sopenharmony_ci val |= PCIE_PL_CHK_REG_CHK_REG_LOGIC_ERROR; 43862306a36Sopenharmony_ci } 43962306a36Sopenharmony_ci dw_pcie_writel_dbi(pci, PCIE_PL_CHK_REG_CONTROL_STATUS, val); 44062306a36Sopenharmony_ci val = dw_pcie_readl_dbi(pci, PCIE_PL_CHK_REG_ERR_ADDR); 44162306a36Sopenharmony_ci dev_err(pci->dev, "CDM Error Address Offset = 0x%08X\n", val); 44262306a36Sopenharmony_ci } 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci return IRQ_HANDLED; 44562306a36Sopenharmony_ci} 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_cistatic void pex_ep_event_hot_rst_done(struct tegra_pcie_dw *pcie) 44862306a36Sopenharmony_ci{ 44962306a36Sopenharmony_ci u32 val; 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L0); 45262306a36Sopenharmony_ci appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_0_0); 45362306a36Sopenharmony_ci appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_1); 45462306a36Sopenharmony_ci appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_2); 45562306a36Sopenharmony_ci appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_3); 45662306a36Sopenharmony_ci appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_6); 45762306a36Sopenharmony_ci appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_7); 45862306a36Sopenharmony_ci appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_8_0); 45962306a36Sopenharmony_ci appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_9); 46062306a36Sopenharmony_ci appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_10); 46162306a36Sopenharmony_ci appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_11); 46262306a36Sopenharmony_ci appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_13); 46362306a36Sopenharmony_ci appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_14); 46462306a36Sopenharmony_ci appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_15); 46562306a36Sopenharmony_ci appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_17); 46662306a36Sopenharmony_ci appl_writel(pcie, 0xFFFFFFFF, APPL_MSI_CTRL_2); 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci val = appl_readl(pcie, APPL_CTRL); 46962306a36Sopenharmony_ci val |= APPL_CTRL_LTSSM_EN; 47062306a36Sopenharmony_ci appl_writel(pcie, val, APPL_CTRL); 47162306a36Sopenharmony_ci} 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_cistatic irqreturn_t tegra_pcie_ep_irq_thread(int irq, void *arg) 47462306a36Sopenharmony_ci{ 47562306a36Sopenharmony_ci struct tegra_pcie_dw *pcie = arg; 47662306a36Sopenharmony_ci struct dw_pcie_ep *ep = &pcie->pci.ep; 47762306a36Sopenharmony_ci struct dw_pcie *pci = &pcie->pci; 47862306a36Sopenharmony_ci u32 val; 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci if (test_and_clear_bit(0, &pcie->link_status)) 48162306a36Sopenharmony_ci dw_pcie_ep_linkup(ep); 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci tegra_pcie_icc_set(pcie); 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci if (pcie->of_data->has_ltr_req_fix) 48662306a36Sopenharmony_ci return IRQ_HANDLED; 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci /* If EP doesn't advertise L1SS, just return */ 48962306a36Sopenharmony_ci val = dw_pcie_readl_dbi(pci, pcie->cfg_link_cap_l1sub); 49062306a36Sopenharmony_ci if (!(val & (PCI_L1SS_CAP_ASPM_L1_1 | PCI_L1SS_CAP_ASPM_L1_2))) 49162306a36Sopenharmony_ci return IRQ_HANDLED; 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci /* Check if BME is set to '1' */ 49462306a36Sopenharmony_ci val = dw_pcie_readl_dbi(pci, PCI_COMMAND); 49562306a36Sopenharmony_ci if (val & PCI_COMMAND_MASTER) { 49662306a36Sopenharmony_ci ktime_t timeout; 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci /* 110us for both snoop and no-snoop */ 49962306a36Sopenharmony_ci val = 110 | (2 << PCI_LTR_SCALE_SHIFT) | LTR_MSG_REQ; 50062306a36Sopenharmony_ci val |= (val << LTR_MST_NO_SNOOP_SHIFT); 50162306a36Sopenharmony_ci appl_writel(pcie, val, APPL_LTR_MSG_1); 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci /* Send LTR upstream */ 50462306a36Sopenharmony_ci val = appl_readl(pcie, APPL_LTR_MSG_2); 50562306a36Sopenharmony_ci val |= APPL_LTR_MSG_2_LTR_MSG_REQ_STATE; 50662306a36Sopenharmony_ci appl_writel(pcie, val, APPL_LTR_MSG_2); 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci timeout = ktime_add_us(ktime_get(), LTR_MSG_TIMEOUT); 50962306a36Sopenharmony_ci for (;;) { 51062306a36Sopenharmony_ci val = appl_readl(pcie, APPL_LTR_MSG_2); 51162306a36Sopenharmony_ci if (!(val & APPL_LTR_MSG_2_LTR_MSG_REQ_STATE)) 51262306a36Sopenharmony_ci break; 51362306a36Sopenharmony_ci if (ktime_after(ktime_get(), timeout)) 51462306a36Sopenharmony_ci break; 51562306a36Sopenharmony_ci usleep_range(1000, 1100); 51662306a36Sopenharmony_ci } 51762306a36Sopenharmony_ci if (val & APPL_LTR_MSG_2_LTR_MSG_REQ_STATE) 51862306a36Sopenharmony_ci dev_err(pcie->dev, "Failed to send LTR message\n"); 51962306a36Sopenharmony_ci } 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci return IRQ_HANDLED; 52262306a36Sopenharmony_ci} 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_cistatic irqreturn_t tegra_pcie_ep_hard_irq(int irq, void *arg) 52562306a36Sopenharmony_ci{ 52662306a36Sopenharmony_ci struct tegra_pcie_dw *pcie = arg; 52762306a36Sopenharmony_ci int spurious = 1; 52862306a36Sopenharmony_ci u32 status_l0, status_l1, link_status; 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci status_l0 = appl_readl(pcie, APPL_INTR_STATUS_L0); 53162306a36Sopenharmony_ci if (status_l0 & APPL_INTR_STATUS_L0_LINK_STATE_INT) { 53262306a36Sopenharmony_ci status_l1 = appl_readl(pcie, APPL_INTR_STATUS_L1_0_0); 53362306a36Sopenharmony_ci appl_writel(pcie, status_l1, APPL_INTR_STATUS_L1_0_0); 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci if (status_l1 & APPL_INTR_STATUS_L1_0_0_HOT_RESET_DONE) 53662306a36Sopenharmony_ci pex_ep_event_hot_rst_done(pcie); 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci if (status_l1 & APPL_INTR_STATUS_L1_0_0_RDLH_LINK_UP_CHGED) { 53962306a36Sopenharmony_ci link_status = appl_readl(pcie, APPL_LINK_STATUS); 54062306a36Sopenharmony_ci if (link_status & APPL_LINK_STATUS_RDLH_LINK_UP) { 54162306a36Sopenharmony_ci dev_dbg(pcie->dev, "Link is up with Host\n"); 54262306a36Sopenharmony_ci set_bit(0, &pcie->link_status); 54362306a36Sopenharmony_ci return IRQ_WAKE_THREAD; 54462306a36Sopenharmony_ci } 54562306a36Sopenharmony_ci } 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci spurious = 0; 54862306a36Sopenharmony_ci } 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci if (status_l0 & APPL_INTR_STATUS_L0_PCI_CMD_EN_INT) { 55162306a36Sopenharmony_ci status_l1 = appl_readl(pcie, APPL_INTR_STATUS_L1_15); 55262306a36Sopenharmony_ci appl_writel(pcie, status_l1, APPL_INTR_STATUS_L1_15); 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci if (status_l1 & APPL_INTR_STATUS_L1_15_CFG_BME_CHGED) 55562306a36Sopenharmony_ci return IRQ_WAKE_THREAD; 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci spurious = 0; 55862306a36Sopenharmony_ci } 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci if (spurious) { 56162306a36Sopenharmony_ci dev_warn(pcie->dev, "Random interrupt (STATUS = 0x%08X)\n", 56262306a36Sopenharmony_ci status_l0); 56362306a36Sopenharmony_ci appl_writel(pcie, status_l0, APPL_INTR_STATUS_L0); 56462306a36Sopenharmony_ci } 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci return IRQ_HANDLED; 56762306a36Sopenharmony_ci} 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_cistatic int tegra_pcie_dw_rd_own_conf(struct pci_bus *bus, u32 devfn, int where, 57062306a36Sopenharmony_ci int size, u32 *val) 57162306a36Sopenharmony_ci{ 57262306a36Sopenharmony_ci struct dw_pcie_rp *pp = bus->sysdata; 57362306a36Sopenharmony_ci struct dw_pcie *pci = to_dw_pcie_from_pp(pp); 57462306a36Sopenharmony_ci struct tegra_pcie_dw *pcie = to_tegra_pcie(pci); 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci /* 57762306a36Sopenharmony_ci * This is an endpoint mode specific register happen to appear even 57862306a36Sopenharmony_ci * when controller is operating in root port mode and system hangs 57962306a36Sopenharmony_ci * when it is accessed with link being in ASPM-L1 state. 58062306a36Sopenharmony_ci * So skip accessing it altogether 58162306a36Sopenharmony_ci */ 58262306a36Sopenharmony_ci if (!pcie->of_data->has_msix_doorbell_access_fix && 58362306a36Sopenharmony_ci !PCI_SLOT(devfn) && where == PORT_LOGIC_MSIX_DOORBELL) { 58462306a36Sopenharmony_ci *val = 0x00000000; 58562306a36Sopenharmony_ci return PCIBIOS_SUCCESSFUL; 58662306a36Sopenharmony_ci } 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci return pci_generic_config_read(bus, devfn, where, size, val); 58962306a36Sopenharmony_ci} 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_cistatic int tegra_pcie_dw_wr_own_conf(struct pci_bus *bus, u32 devfn, int where, 59262306a36Sopenharmony_ci int size, u32 val) 59362306a36Sopenharmony_ci{ 59462306a36Sopenharmony_ci struct dw_pcie_rp *pp = bus->sysdata; 59562306a36Sopenharmony_ci struct dw_pcie *pci = to_dw_pcie_from_pp(pp); 59662306a36Sopenharmony_ci struct tegra_pcie_dw *pcie = to_tegra_pcie(pci); 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci /* 59962306a36Sopenharmony_ci * This is an endpoint mode specific register happen to appear even 60062306a36Sopenharmony_ci * when controller is operating in root port mode and system hangs 60162306a36Sopenharmony_ci * when it is accessed with link being in ASPM-L1 state. 60262306a36Sopenharmony_ci * So skip accessing it altogether 60362306a36Sopenharmony_ci */ 60462306a36Sopenharmony_ci if (!pcie->of_data->has_msix_doorbell_access_fix && 60562306a36Sopenharmony_ci !PCI_SLOT(devfn) && where == PORT_LOGIC_MSIX_DOORBELL) 60662306a36Sopenharmony_ci return PCIBIOS_SUCCESSFUL; 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci return pci_generic_config_write(bus, devfn, where, size, val); 60962306a36Sopenharmony_ci} 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_cistatic struct pci_ops tegra_pci_ops = { 61262306a36Sopenharmony_ci .map_bus = dw_pcie_own_conf_map_bus, 61362306a36Sopenharmony_ci .read = tegra_pcie_dw_rd_own_conf, 61462306a36Sopenharmony_ci .write = tegra_pcie_dw_wr_own_conf, 61562306a36Sopenharmony_ci}; 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci#if defined(CONFIG_PCIEASPM) 61862306a36Sopenharmony_cistatic void disable_aspm_l11(struct tegra_pcie_dw *pcie) 61962306a36Sopenharmony_ci{ 62062306a36Sopenharmony_ci u32 val; 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci val = dw_pcie_readl_dbi(&pcie->pci, pcie->cfg_link_cap_l1sub); 62362306a36Sopenharmony_ci val &= ~PCI_L1SS_CAP_ASPM_L1_1; 62462306a36Sopenharmony_ci dw_pcie_writel_dbi(&pcie->pci, pcie->cfg_link_cap_l1sub, val); 62562306a36Sopenharmony_ci} 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_cistatic void disable_aspm_l12(struct tegra_pcie_dw *pcie) 62862306a36Sopenharmony_ci{ 62962306a36Sopenharmony_ci u32 val; 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci val = dw_pcie_readl_dbi(&pcie->pci, pcie->cfg_link_cap_l1sub); 63262306a36Sopenharmony_ci val &= ~PCI_L1SS_CAP_ASPM_L1_2; 63362306a36Sopenharmony_ci dw_pcie_writel_dbi(&pcie->pci, pcie->cfg_link_cap_l1sub, val); 63462306a36Sopenharmony_ci} 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_cistatic inline u32 event_counter_prog(struct tegra_pcie_dw *pcie, u32 event) 63762306a36Sopenharmony_ci{ 63862306a36Sopenharmony_ci u32 val; 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci val = dw_pcie_readl_dbi(&pcie->pci, pcie->ras_des_cap + 64162306a36Sopenharmony_ci PCIE_RAS_DES_EVENT_COUNTER_CONTROL); 64262306a36Sopenharmony_ci val &= ~(EVENT_COUNTER_EVENT_SEL_MASK << EVENT_COUNTER_EVENT_SEL_SHIFT); 64362306a36Sopenharmony_ci val |= EVENT_COUNTER_GROUP_5 << EVENT_COUNTER_GROUP_SEL_SHIFT; 64462306a36Sopenharmony_ci val |= event << EVENT_COUNTER_EVENT_SEL_SHIFT; 64562306a36Sopenharmony_ci val |= EVENT_COUNTER_ENABLE_ALL << EVENT_COUNTER_ENABLE_SHIFT; 64662306a36Sopenharmony_ci dw_pcie_writel_dbi(&pcie->pci, pcie->ras_des_cap + 64762306a36Sopenharmony_ci PCIE_RAS_DES_EVENT_COUNTER_CONTROL, val); 64862306a36Sopenharmony_ci val = dw_pcie_readl_dbi(&pcie->pci, pcie->ras_des_cap + 64962306a36Sopenharmony_ci PCIE_RAS_DES_EVENT_COUNTER_DATA); 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci return val; 65262306a36Sopenharmony_ci} 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_cistatic int aspm_state_cnt(struct seq_file *s, void *data) 65562306a36Sopenharmony_ci{ 65662306a36Sopenharmony_ci struct tegra_pcie_dw *pcie = (struct tegra_pcie_dw *) 65762306a36Sopenharmony_ci dev_get_drvdata(s->private); 65862306a36Sopenharmony_ci u32 val; 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci seq_printf(s, "Tx L0s entry count : %u\n", 66162306a36Sopenharmony_ci event_counter_prog(pcie, EVENT_COUNTER_EVENT_Tx_L0S)); 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci seq_printf(s, "Rx L0s entry count : %u\n", 66462306a36Sopenharmony_ci event_counter_prog(pcie, EVENT_COUNTER_EVENT_Rx_L0S)); 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci seq_printf(s, "Link L1 entry count : %u\n", 66762306a36Sopenharmony_ci event_counter_prog(pcie, EVENT_COUNTER_EVENT_L1)); 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci seq_printf(s, "Link L1.1 entry count : %u\n", 67062306a36Sopenharmony_ci event_counter_prog(pcie, EVENT_COUNTER_EVENT_L1_1)); 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci seq_printf(s, "Link L1.2 entry count : %u\n", 67362306a36Sopenharmony_ci event_counter_prog(pcie, EVENT_COUNTER_EVENT_L1_2)); 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci /* Clear all counters */ 67662306a36Sopenharmony_ci dw_pcie_writel_dbi(&pcie->pci, pcie->ras_des_cap + 67762306a36Sopenharmony_ci PCIE_RAS_DES_EVENT_COUNTER_CONTROL, 67862306a36Sopenharmony_ci EVENT_COUNTER_ALL_CLEAR); 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci /* Re-enable counting */ 68162306a36Sopenharmony_ci val = EVENT_COUNTER_ENABLE_ALL << EVENT_COUNTER_ENABLE_SHIFT; 68262306a36Sopenharmony_ci val |= EVENT_COUNTER_GROUP_5 << EVENT_COUNTER_GROUP_SEL_SHIFT; 68362306a36Sopenharmony_ci dw_pcie_writel_dbi(&pcie->pci, pcie->ras_des_cap + 68462306a36Sopenharmony_ci PCIE_RAS_DES_EVENT_COUNTER_CONTROL, val); 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci return 0; 68762306a36Sopenharmony_ci} 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_cistatic void init_host_aspm(struct tegra_pcie_dw *pcie) 69062306a36Sopenharmony_ci{ 69162306a36Sopenharmony_ci struct dw_pcie *pci = &pcie->pci; 69262306a36Sopenharmony_ci u32 val; 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci val = dw_pcie_find_ext_capability(pci, PCI_EXT_CAP_ID_L1SS); 69562306a36Sopenharmony_ci pcie->cfg_link_cap_l1sub = val + PCI_L1SS_CAP; 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci pcie->ras_des_cap = dw_pcie_find_ext_capability(&pcie->pci, 69862306a36Sopenharmony_ci PCI_EXT_CAP_ID_VNDR); 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci /* Enable ASPM counters */ 70162306a36Sopenharmony_ci val = EVENT_COUNTER_ENABLE_ALL << EVENT_COUNTER_ENABLE_SHIFT; 70262306a36Sopenharmony_ci val |= EVENT_COUNTER_GROUP_5 << EVENT_COUNTER_GROUP_SEL_SHIFT; 70362306a36Sopenharmony_ci dw_pcie_writel_dbi(pci, pcie->ras_des_cap + 70462306a36Sopenharmony_ci PCIE_RAS_DES_EVENT_COUNTER_CONTROL, val); 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci /* Program T_cmrt and T_pwr_on values */ 70762306a36Sopenharmony_ci val = dw_pcie_readl_dbi(pci, pcie->cfg_link_cap_l1sub); 70862306a36Sopenharmony_ci val &= ~(PCI_L1SS_CAP_CM_RESTORE_TIME | PCI_L1SS_CAP_P_PWR_ON_VALUE); 70962306a36Sopenharmony_ci val |= (pcie->aspm_cmrt << 8); 71062306a36Sopenharmony_ci val |= (pcie->aspm_pwr_on_t << 19); 71162306a36Sopenharmony_ci dw_pcie_writel_dbi(pci, pcie->cfg_link_cap_l1sub, val); 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci /* Program L0s and L1 entrance latencies */ 71462306a36Sopenharmony_ci val = dw_pcie_readl_dbi(pci, PCIE_PORT_AFR); 71562306a36Sopenharmony_ci val &= ~PORT_AFR_L0S_ENTRANCE_LAT_MASK; 71662306a36Sopenharmony_ci val |= (pcie->aspm_l0s_enter_lat << PORT_AFR_L0S_ENTRANCE_LAT_SHIFT); 71762306a36Sopenharmony_ci val |= PORT_AFR_ENTER_ASPM; 71862306a36Sopenharmony_ci dw_pcie_writel_dbi(pci, PCIE_PORT_AFR, val); 71962306a36Sopenharmony_ci} 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_cistatic void init_debugfs(struct tegra_pcie_dw *pcie) 72262306a36Sopenharmony_ci{ 72362306a36Sopenharmony_ci debugfs_create_devm_seqfile(pcie->dev, "aspm_state_cnt", pcie->debugfs, 72462306a36Sopenharmony_ci aspm_state_cnt); 72562306a36Sopenharmony_ci} 72662306a36Sopenharmony_ci#else 72762306a36Sopenharmony_cistatic inline void disable_aspm_l12(struct tegra_pcie_dw *pcie) { return; } 72862306a36Sopenharmony_cistatic inline void disable_aspm_l11(struct tegra_pcie_dw *pcie) { return; } 72962306a36Sopenharmony_cistatic inline void init_host_aspm(struct tegra_pcie_dw *pcie) { return; } 73062306a36Sopenharmony_cistatic inline void init_debugfs(struct tegra_pcie_dw *pcie) { return; } 73162306a36Sopenharmony_ci#endif 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_cistatic void tegra_pcie_enable_system_interrupts(struct dw_pcie_rp *pp) 73462306a36Sopenharmony_ci{ 73562306a36Sopenharmony_ci struct dw_pcie *pci = to_dw_pcie_from_pp(pp); 73662306a36Sopenharmony_ci struct tegra_pcie_dw *pcie = to_tegra_pcie(pci); 73762306a36Sopenharmony_ci u32 val; 73862306a36Sopenharmony_ci u16 val_w; 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci val = appl_readl(pcie, APPL_INTR_EN_L0_0); 74162306a36Sopenharmony_ci val |= APPL_INTR_EN_L0_0_LINK_STATE_INT_EN; 74262306a36Sopenharmony_ci appl_writel(pcie, val, APPL_INTR_EN_L0_0); 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci if (!pcie->of_data->has_sbr_reset_fix) { 74562306a36Sopenharmony_ci val = appl_readl(pcie, APPL_INTR_EN_L1_0_0); 74662306a36Sopenharmony_ci val |= APPL_INTR_EN_L1_0_0_LINK_REQ_RST_NOT_INT_EN; 74762306a36Sopenharmony_ci appl_writel(pcie, val, APPL_INTR_EN_L1_0_0); 74862306a36Sopenharmony_ci } 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci if (pcie->enable_cdm_check) { 75162306a36Sopenharmony_ci val = appl_readl(pcie, APPL_INTR_EN_L0_0); 75262306a36Sopenharmony_ci val |= pcie->of_data->cdm_chk_int_en_bit; 75362306a36Sopenharmony_ci appl_writel(pcie, val, APPL_INTR_EN_L0_0); 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci val = appl_readl(pcie, APPL_INTR_EN_L1_18); 75662306a36Sopenharmony_ci val |= APPL_INTR_EN_L1_18_CDM_REG_CHK_CMP_ERR; 75762306a36Sopenharmony_ci val |= APPL_INTR_EN_L1_18_CDM_REG_CHK_LOGIC_ERR; 75862306a36Sopenharmony_ci appl_writel(pcie, val, APPL_INTR_EN_L1_18); 75962306a36Sopenharmony_ci } 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci val_w = dw_pcie_readw_dbi(&pcie->pci, pcie->pcie_cap_base + 76262306a36Sopenharmony_ci PCI_EXP_LNKSTA); 76362306a36Sopenharmony_ci pcie->init_link_width = FIELD_GET(PCI_EXP_LNKSTA_NLW, val_w); 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci val_w = dw_pcie_readw_dbi(&pcie->pci, pcie->pcie_cap_base + 76662306a36Sopenharmony_ci PCI_EXP_LNKCTL); 76762306a36Sopenharmony_ci val_w |= PCI_EXP_LNKCTL_LBMIE; 76862306a36Sopenharmony_ci dw_pcie_writew_dbi(&pcie->pci, pcie->pcie_cap_base + PCI_EXP_LNKCTL, 76962306a36Sopenharmony_ci val_w); 77062306a36Sopenharmony_ci} 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_cistatic void tegra_pcie_enable_legacy_interrupts(struct dw_pcie_rp *pp) 77362306a36Sopenharmony_ci{ 77462306a36Sopenharmony_ci struct dw_pcie *pci = to_dw_pcie_from_pp(pp); 77562306a36Sopenharmony_ci struct tegra_pcie_dw *pcie = to_tegra_pcie(pci); 77662306a36Sopenharmony_ci u32 val; 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci /* Enable legacy interrupt generation */ 77962306a36Sopenharmony_ci val = appl_readl(pcie, APPL_INTR_EN_L0_0); 78062306a36Sopenharmony_ci val |= APPL_INTR_EN_L0_0_SYS_INTR_EN; 78162306a36Sopenharmony_ci val |= APPL_INTR_EN_L0_0_INT_INT_EN; 78262306a36Sopenharmony_ci appl_writel(pcie, val, APPL_INTR_EN_L0_0); 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci val = appl_readl(pcie, APPL_INTR_EN_L1_8_0); 78562306a36Sopenharmony_ci val |= APPL_INTR_EN_L1_8_INTX_EN; 78662306a36Sopenharmony_ci val |= APPL_INTR_EN_L1_8_AUTO_BW_INT_EN; 78762306a36Sopenharmony_ci val |= APPL_INTR_EN_L1_8_BW_MGT_INT_EN; 78862306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_PCIEAER)) 78962306a36Sopenharmony_ci val |= APPL_INTR_EN_L1_8_AER_INT_EN; 79062306a36Sopenharmony_ci appl_writel(pcie, val, APPL_INTR_EN_L1_8_0); 79162306a36Sopenharmony_ci} 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_cistatic void tegra_pcie_enable_msi_interrupts(struct dw_pcie_rp *pp) 79462306a36Sopenharmony_ci{ 79562306a36Sopenharmony_ci struct dw_pcie *pci = to_dw_pcie_from_pp(pp); 79662306a36Sopenharmony_ci struct tegra_pcie_dw *pcie = to_tegra_pcie(pci); 79762306a36Sopenharmony_ci u32 val; 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci /* Enable MSI interrupt generation */ 80062306a36Sopenharmony_ci val = appl_readl(pcie, APPL_INTR_EN_L0_0); 80162306a36Sopenharmony_ci val |= APPL_INTR_EN_L0_0_SYS_MSI_INTR_EN; 80262306a36Sopenharmony_ci val |= APPL_INTR_EN_L0_0_MSI_RCV_INT_EN; 80362306a36Sopenharmony_ci appl_writel(pcie, val, APPL_INTR_EN_L0_0); 80462306a36Sopenharmony_ci} 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_cistatic void tegra_pcie_enable_interrupts(struct dw_pcie_rp *pp) 80762306a36Sopenharmony_ci{ 80862306a36Sopenharmony_ci struct dw_pcie *pci = to_dw_pcie_from_pp(pp); 80962306a36Sopenharmony_ci struct tegra_pcie_dw *pcie = to_tegra_pcie(pci); 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci /* Clear interrupt statuses before enabling interrupts */ 81262306a36Sopenharmony_ci appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L0); 81362306a36Sopenharmony_ci appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_0_0); 81462306a36Sopenharmony_ci appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_1); 81562306a36Sopenharmony_ci appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_2); 81662306a36Sopenharmony_ci appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_3); 81762306a36Sopenharmony_ci appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_6); 81862306a36Sopenharmony_ci appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_7); 81962306a36Sopenharmony_ci appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_8_0); 82062306a36Sopenharmony_ci appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_9); 82162306a36Sopenharmony_ci appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_10); 82262306a36Sopenharmony_ci appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_11); 82362306a36Sopenharmony_ci appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_13); 82462306a36Sopenharmony_ci appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_14); 82562306a36Sopenharmony_ci appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_15); 82662306a36Sopenharmony_ci appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_17); 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_ci tegra_pcie_enable_system_interrupts(pp); 82962306a36Sopenharmony_ci tegra_pcie_enable_legacy_interrupts(pp); 83062306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_PCI_MSI)) 83162306a36Sopenharmony_ci tegra_pcie_enable_msi_interrupts(pp); 83262306a36Sopenharmony_ci} 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_cistatic void config_gen3_gen4_eq_presets(struct tegra_pcie_dw *pcie) 83562306a36Sopenharmony_ci{ 83662306a36Sopenharmony_ci struct dw_pcie *pci = &pcie->pci; 83762306a36Sopenharmony_ci u32 val, offset, i; 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_ci /* Program init preset */ 84062306a36Sopenharmony_ci for (i = 0; i < pcie->num_lanes; i++) { 84162306a36Sopenharmony_ci val = dw_pcie_readw_dbi(pci, CAP_SPCIE_CAP_OFF + (i * 2)); 84262306a36Sopenharmony_ci val &= ~CAP_SPCIE_CAP_OFF_DSP_TX_PRESET0_MASK; 84362306a36Sopenharmony_ci val |= GEN3_GEN4_EQ_PRESET_INIT; 84462306a36Sopenharmony_ci val &= ~CAP_SPCIE_CAP_OFF_USP_TX_PRESET0_MASK; 84562306a36Sopenharmony_ci val |= (GEN3_GEN4_EQ_PRESET_INIT << 84662306a36Sopenharmony_ci CAP_SPCIE_CAP_OFF_USP_TX_PRESET0_SHIFT); 84762306a36Sopenharmony_ci dw_pcie_writew_dbi(pci, CAP_SPCIE_CAP_OFF + (i * 2), val); 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci offset = dw_pcie_find_ext_capability(pci, 85062306a36Sopenharmony_ci PCI_EXT_CAP_ID_PL_16GT) + 85162306a36Sopenharmony_ci PCI_PL_16GT_LE_CTRL; 85262306a36Sopenharmony_ci val = dw_pcie_readb_dbi(pci, offset + i); 85362306a36Sopenharmony_ci val &= ~PCI_PL_16GT_LE_CTRL_DSP_TX_PRESET_MASK; 85462306a36Sopenharmony_ci val |= GEN3_GEN4_EQ_PRESET_INIT; 85562306a36Sopenharmony_ci val &= ~PCI_PL_16GT_LE_CTRL_USP_TX_PRESET_MASK; 85662306a36Sopenharmony_ci val |= (GEN3_GEN4_EQ_PRESET_INIT << 85762306a36Sopenharmony_ci PCI_PL_16GT_LE_CTRL_USP_TX_PRESET_SHIFT); 85862306a36Sopenharmony_ci dw_pcie_writeb_dbi(pci, offset + i, val); 85962306a36Sopenharmony_ci } 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_ci val = dw_pcie_readl_dbi(pci, GEN3_RELATED_OFF); 86262306a36Sopenharmony_ci val &= ~GEN3_RELATED_OFF_RATE_SHADOW_SEL_MASK; 86362306a36Sopenharmony_ci dw_pcie_writel_dbi(pci, GEN3_RELATED_OFF, val); 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci val = dw_pcie_readl_dbi(pci, GEN3_EQ_CONTROL_OFF); 86662306a36Sopenharmony_ci val &= ~GEN3_EQ_CONTROL_OFF_PSET_REQ_VEC_MASK; 86762306a36Sopenharmony_ci val |= (0x3ff << GEN3_EQ_CONTROL_OFF_PSET_REQ_VEC_SHIFT); 86862306a36Sopenharmony_ci val &= ~GEN3_EQ_CONTROL_OFF_FB_MODE_MASK; 86962306a36Sopenharmony_ci dw_pcie_writel_dbi(pci, GEN3_EQ_CONTROL_OFF, val); 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci val = dw_pcie_readl_dbi(pci, GEN3_RELATED_OFF); 87262306a36Sopenharmony_ci val &= ~GEN3_RELATED_OFF_RATE_SHADOW_SEL_MASK; 87362306a36Sopenharmony_ci val |= (0x1 << GEN3_RELATED_OFF_RATE_SHADOW_SEL_SHIFT); 87462306a36Sopenharmony_ci dw_pcie_writel_dbi(pci, GEN3_RELATED_OFF, val); 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci val = dw_pcie_readl_dbi(pci, GEN3_EQ_CONTROL_OFF); 87762306a36Sopenharmony_ci val &= ~GEN3_EQ_CONTROL_OFF_PSET_REQ_VEC_MASK; 87862306a36Sopenharmony_ci val |= (pcie->of_data->gen4_preset_vec << 87962306a36Sopenharmony_ci GEN3_EQ_CONTROL_OFF_PSET_REQ_VEC_SHIFT); 88062306a36Sopenharmony_ci val &= ~GEN3_EQ_CONTROL_OFF_FB_MODE_MASK; 88162306a36Sopenharmony_ci dw_pcie_writel_dbi(pci, GEN3_EQ_CONTROL_OFF, val); 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_ci val = dw_pcie_readl_dbi(pci, GEN3_RELATED_OFF); 88462306a36Sopenharmony_ci val &= ~GEN3_RELATED_OFF_RATE_SHADOW_SEL_MASK; 88562306a36Sopenharmony_ci dw_pcie_writel_dbi(pci, GEN3_RELATED_OFF, val); 88662306a36Sopenharmony_ci} 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_cistatic int tegra_pcie_dw_host_init(struct dw_pcie_rp *pp) 88962306a36Sopenharmony_ci{ 89062306a36Sopenharmony_ci struct dw_pcie *pci = to_dw_pcie_from_pp(pp); 89162306a36Sopenharmony_ci struct tegra_pcie_dw *pcie = to_tegra_pcie(pci); 89262306a36Sopenharmony_ci u32 val; 89362306a36Sopenharmony_ci u16 val_16; 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci pp->bridge->ops = &tegra_pci_ops; 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_ci if (!pcie->pcie_cap_base) 89862306a36Sopenharmony_ci pcie->pcie_cap_base = dw_pcie_find_capability(&pcie->pci, 89962306a36Sopenharmony_ci PCI_CAP_ID_EXP); 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_ci val = dw_pcie_readl_dbi(pci, PCI_IO_BASE); 90262306a36Sopenharmony_ci val &= ~(IO_BASE_IO_DECODE | IO_BASE_IO_DECODE_BIT8); 90362306a36Sopenharmony_ci dw_pcie_writel_dbi(pci, PCI_IO_BASE, val); 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_ci val = dw_pcie_readl_dbi(pci, PCI_PREF_MEMORY_BASE); 90662306a36Sopenharmony_ci val |= CFG_PREF_MEM_LIMIT_BASE_MEM_DECODE; 90762306a36Sopenharmony_ci val |= CFG_PREF_MEM_LIMIT_BASE_MEM_LIMIT_DECODE; 90862306a36Sopenharmony_ci dw_pcie_writel_dbi(pci, PCI_PREF_MEMORY_BASE, val); 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_ci dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_0, 0); 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_ci /* Enable as 0xFFFF0001 response for CRS */ 91362306a36Sopenharmony_ci val = dw_pcie_readl_dbi(pci, PORT_LOGIC_AMBA_ERROR_RESPONSE_DEFAULT); 91462306a36Sopenharmony_ci val &= ~(AMBA_ERROR_RESPONSE_CRS_MASK << AMBA_ERROR_RESPONSE_CRS_SHIFT); 91562306a36Sopenharmony_ci val |= (AMBA_ERROR_RESPONSE_CRS_OKAY_FFFF0001 << 91662306a36Sopenharmony_ci AMBA_ERROR_RESPONSE_CRS_SHIFT); 91762306a36Sopenharmony_ci dw_pcie_writel_dbi(pci, PORT_LOGIC_AMBA_ERROR_RESPONSE_DEFAULT, val); 91862306a36Sopenharmony_ci 91962306a36Sopenharmony_ci /* Configure Max lane width from DT */ 92062306a36Sopenharmony_ci val = dw_pcie_readl_dbi(pci, pcie->pcie_cap_base + PCI_EXP_LNKCAP); 92162306a36Sopenharmony_ci val &= ~PCI_EXP_LNKCAP_MLW; 92262306a36Sopenharmony_ci val |= FIELD_PREP(PCI_EXP_LNKCAP_MLW, pcie->num_lanes); 92362306a36Sopenharmony_ci dw_pcie_writel_dbi(pci, pcie->pcie_cap_base + PCI_EXP_LNKCAP, val); 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_ci /* Clear Slot Clock Configuration bit if SRNS configuration */ 92662306a36Sopenharmony_ci if (pcie->enable_srns) { 92762306a36Sopenharmony_ci val_16 = dw_pcie_readw_dbi(pci, pcie->pcie_cap_base + 92862306a36Sopenharmony_ci PCI_EXP_LNKSTA); 92962306a36Sopenharmony_ci val_16 &= ~PCI_EXP_LNKSTA_SLC; 93062306a36Sopenharmony_ci dw_pcie_writew_dbi(pci, pcie->pcie_cap_base + PCI_EXP_LNKSTA, 93162306a36Sopenharmony_ci val_16); 93262306a36Sopenharmony_ci } 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_ci config_gen3_gen4_eq_presets(pcie); 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_ci init_host_aspm(pcie); 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_ci /* Disable ASPM-L1SS advertisement if there is no CLKREQ routing */ 93962306a36Sopenharmony_ci if (!pcie->supports_clkreq) { 94062306a36Sopenharmony_ci disable_aspm_l11(pcie); 94162306a36Sopenharmony_ci disable_aspm_l12(pcie); 94262306a36Sopenharmony_ci } 94362306a36Sopenharmony_ci 94462306a36Sopenharmony_ci if (!pcie->of_data->has_l1ss_exit_fix) { 94562306a36Sopenharmony_ci val = dw_pcie_readl_dbi(pci, GEN3_RELATED_OFF); 94662306a36Sopenharmony_ci val &= ~GEN3_RELATED_OFF_GEN3_ZRXDC_NONCOMPL; 94762306a36Sopenharmony_ci dw_pcie_writel_dbi(pci, GEN3_RELATED_OFF, val); 94862306a36Sopenharmony_ci } 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_ci if (pcie->update_fc_fixup) { 95162306a36Sopenharmony_ci val = dw_pcie_readl_dbi(pci, CFG_TIMER_CTRL_MAX_FUNC_NUM_OFF); 95262306a36Sopenharmony_ci val |= 0x1 << CFG_TIMER_CTRL_ACK_NAK_SHIFT; 95362306a36Sopenharmony_ci dw_pcie_writel_dbi(pci, CFG_TIMER_CTRL_MAX_FUNC_NUM_OFF, val); 95462306a36Sopenharmony_ci } 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_ci clk_set_rate(pcie->core_clk, GEN4_CORE_CLK_FREQ); 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_ci return 0; 95962306a36Sopenharmony_ci} 96062306a36Sopenharmony_ci 96162306a36Sopenharmony_cistatic int tegra_pcie_dw_start_link(struct dw_pcie *pci) 96262306a36Sopenharmony_ci{ 96362306a36Sopenharmony_ci struct tegra_pcie_dw *pcie = to_tegra_pcie(pci); 96462306a36Sopenharmony_ci struct dw_pcie_rp *pp = &pci->pp; 96562306a36Sopenharmony_ci u32 val, offset, tmp; 96662306a36Sopenharmony_ci bool retry = true; 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_ci if (pcie->of_data->mode == DW_PCIE_EP_TYPE) { 96962306a36Sopenharmony_ci enable_irq(pcie->pex_rst_irq); 97062306a36Sopenharmony_ci return 0; 97162306a36Sopenharmony_ci } 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ciretry_link: 97462306a36Sopenharmony_ci /* Assert RST */ 97562306a36Sopenharmony_ci val = appl_readl(pcie, APPL_PINMUX); 97662306a36Sopenharmony_ci val &= ~APPL_PINMUX_PEX_RST; 97762306a36Sopenharmony_ci appl_writel(pcie, val, APPL_PINMUX); 97862306a36Sopenharmony_ci 97962306a36Sopenharmony_ci usleep_range(100, 200); 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_ci /* Enable LTSSM */ 98262306a36Sopenharmony_ci val = appl_readl(pcie, APPL_CTRL); 98362306a36Sopenharmony_ci val |= APPL_CTRL_LTSSM_EN; 98462306a36Sopenharmony_ci appl_writel(pcie, val, APPL_CTRL); 98562306a36Sopenharmony_ci 98662306a36Sopenharmony_ci /* De-assert RST */ 98762306a36Sopenharmony_ci val = appl_readl(pcie, APPL_PINMUX); 98862306a36Sopenharmony_ci val |= APPL_PINMUX_PEX_RST; 98962306a36Sopenharmony_ci appl_writel(pcie, val, APPL_PINMUX); 99062306a36Sopenharmony_ci 99162306a36Sopenharmony_ci msleep(100); 99262306a36Sopenharmony_ci 99362306a36Sopenharmony_ci if (dw_pcie_wait_for_link(pci)) { 99462306a36Sopenharmony_ci if (!retry) 99562306a36Sopenharmony_ci return 0; 99662306a36Sopenharmony_ci /* 99762306a36Sopenharmony_ci * There are some endpoints which can't get the link up if 99862306a36Sopenharmony_ci * root port has Data Link Feature (DLF) enabled. 99962306a36Sopenharmony_ci * Refer Spec rev 4.0 ver 1.0 sec 3.4.2 & 7.7.4 for more info 100062306a36Sopenharmony_ci * on Scaled Flow Control and DLF. 100162306a36Sopenharmony_ci * So, need to confirm that is indeed the case here and attempt 100262306a36Sopenharmony_ci * link up once again with DLF disabled. 100362306a36Sopenharmony_ci */ 100462306a36Sopenharmony_ci val = appl_readl(pcie, APPL_DEBUG); 100562306a36Sopenharmony_ci val &= APPL_DEBUG_LTSSM_STATE_MASK; 100662306a36Sopenharmony_ci val >>= APPL_DEBUG_LTSSM_STATE_SHIFT; 100762306a36Sopenharmony_ci tmp = appl_readl(pcie, APPL_LINK_STATUS); 100862306a36Sopenharmony_ci tmp &= APPL_LINK_STATUS_RDLH_LINK_UP; 100962306a36Sopenharmony_ci if (!(val == 0x11 && !tmp)) { 101062306a36Sopenharmony_ci /* Link is down for all good reasons */ 101162306a36Sopenharmony_ci return 0; 101262306a36Sopenharmony_ci } 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_ci dev_info(pci->dev, "Link is down in DLL"); 101562306a36Sopenharmony_ci dev_info(pci->dev, "Trying again with DLFE disabled\n"); 101662306a36Sopenharmony_ci /* Disable LTSSM */ 101762306a36Sopenharmony_ci val = appl_readl(pcie, APPL_CTRL); 101862306a36Sopenharmony_ci val &= ~APPL_CTRL_LTSSM_EN; 101962306a36Sopenharmony_ci appl_writel(pcie, val, APPL_CTRL); 102062306a36Sopenharmony_ci 102162306a36Sopenharmony_ci reset_control_assert(pcie->core_rst); 102262306a36Sopenharmony_ci reset_control_deassert(pcie->core_rst); 102362306a36Sopenharmony_ci 102462306a36Sopenharmony_ci offset = dw_pcie_find_ext_capability(pci, PCI_EXT_CAP_ID_DLF); 102562306a36Sopenharmony_ci val = dw_pcie_readl_dbi(pci, offset + PCI_DLF_CAP); 102662306a36Sopenharmony_ci val &= ~PCI_DLF_EXCHANGE_ENABLE; 102762306a36Sopenharmony_ci dw_pcie_writel_dbi(pci, offset + PCI_DLF_CAP, val); 102862306a36Sopenharmony_ci 102962306a36Sopenharmony_ci tegra_pcie_dw_host_init(pp); 103062306a36Sopenharmony_ci dw_pcie_setup_rc(pp); 103162306a36Sopenharmony_ci 103262306a36Sopenharmony_ci retry = false; 103362306a36Sopenharmony_ci goto retry_link; 103462306a36Sopenharmony_ci } 103562306a36Sopenharmony_ci 103662306a36Sopenharmony_ci tegra_pcie_icc_set(pcie); 103762306a36Sopenharmony_ci 103862306a36Sopenharmony_ci tegra_pcie_enable_interrupts(pp); 103962306a36Sopenharmony_ci 104062306a36Sopenharmony_ci return 0; 104162306a36Sopenharmony_ci} 104262306a36Sopenharmony_ci 104362306a36Sopenharmony_cistatic int tegra_pcie_dw_link_up(struct dw_pcie *pci) 104462306a36Sopenharmony_ci{ 104562306a36Sopenharmony_ci struct tegra_pcie_dw *pcie = to_tegra_pcie(pci); 104662306a36Sopenharmony_ci u32 val = dw_pcie_readw_dbi(pci, pcie->pcie_cap_base + PCI_EXP_LNKSTA); 104762306a36Sopenharmony_ci 104862306a36Sopenharmony_ci return !!(val & PCI_EXP_LNKSTA_DLLLA); 104962306a36Sopenharmony_ci} 105062306a36Sopenharmony_ci 105162306a36Sopenharmony_cistatic void tegra_pcie_dw_stop_link(struct dw_pcie *pci) 105262306a36Sopenharmony_ci{ 105362306a36Sopenharmony_ci struct tegra_pcie_dw *pcie = to_tegra_pcie(pci); 105462306a36Sopenharmony_ci 105562306a36Sopenharmony_ci disable_irq(pcie->pex_rst_irq); 105662306a36Sopenharmony_ci} 105762306a36Sopenharmony_ci 105862306a36Sopenharmony_cistatic const struct dw_pcie_ops tegra_dw_pcie_ops = { 105962306a36Sopenharmony_ci .link_up = tegra_pcie_dw_link_up, 106062306a36Sopenharmony_ci .start_link = tegra_pcie_dw_start_link, 106162306a36Sopenharmony_ci .stop_link = tegra_pcie_dw_stop_link, 106262306a36Sopenharmony_ci}; 106362306a36Sopenharmony_ci 106462306a36Sopenharmony_cistatic const struct dw_pcie_host_ops tegra_pcie_dw_host_ops = { 106562306a36Sopenharmony_ci .host_init = tegra_pcie_dw_host_init, 106662306a36Sopenharmony_ci}; 106762306a36Sopenharmony_ci 106862306a36Sopenharmony_cistatic void tegra_pcie_disable_phy(struct tegra_pcie_dw *pcie) 106962306a36Sopenharmony_ci{ 107062306a36Sopenharmony_ci unsigned int phy_count = pcie->phy_count; 107162306a36Sopenharmony_ci 107262306a36Sopenharmony_ci while (phy_count--) { 107362306a36Sopenharmony_ci phy_power_off(pcie->phys[phy_count]); 107462306a36Sopenharmony_ci phy_exit(pcie->phys[phy_count]); 107562306a36Sopenharmony_ci } 107662306a36Sopenharmony_ci} 107762306a36Sopenharmony_ci 107862306a36Sopenharmony_cistatic int tegra_pcie_enable_phy(struct tegra_pcie_dw *pcie) 107962306a36Sopenharmony_ci{ 108062306a36Sopenharmony_ci unsigned int i; 108162306a36Sopenharmony_ci int ret; 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_ci for (i = 0; i < pcie->phy_count; i++) { 108462306a36Sopenharmony_ci ret = phy_init(pcie->phys[i]); 108562306a36Sopenharmony_ci if (ret < 0) 108662306a36Sopenharmony_ci goto phy_power_off; 108762306a36Sopenharmony_ci 108862306a36Sopenharmony_ci ret = phy_power_on(pcie->phys[i]); 108962306a36Sopenharmony_ci if (ret < 0) 109062306a36Sopenharmony_ci goto phy_exit; 109162306a36Sopenharmony_ci } 109262306a36Sopenharmony_ci 109362306a36Sopenharmony_ci return 0; 109462306a36Sopenharmony_ci 109562306a36Sopenharmony_ciphy_power_off: 109662306a36Sopenharmony_ci while (i--) { 109762306a36Sopenharmony_ci phy_power_off(pcie->phys[i]); 109862306a36Sopenharmony_ciphy_exit: 109962306a36Sopenharmony_ci phy_exit(pcie->phys[i]); 110062306a36Sopenharmony_ci } 110162306a36Sopenharmony_ci 110262306a36Sopenharmony_ci return ret; 110362306a36Sopenharmony_ci} 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_cistatic int tegra_pcie_dw_parse_dt(struct tegra_pcie_dw *pcie) 110662306a36Sopenharmony_ci{ 110762306a36Sopenharmony_ci struct platform_device *pdev = to_platform_device(pcie->dev); 110862306a36Sopenharmony_ci struct device_node *np = pcie->dev->of_node; 110962306a36Sopenharmony_ci int ret; 111062306a36Sopenharmony_ci 111162306a36Sopenharmony_ci pcie->dbi_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi"); 111262306a36Sopenharmony_ci if (!pcie->dbi_res) { 111362306a36Sopenharmony_ci dev_err(pcie->dev, "Failed to find \"dbi\" region\n"); 111462306a36Sopenharmony_ci return -ENODEV; 111562306a36Sopenharmony_ci } 111662306a36Sopenharmony_ci 111762306a36Sopenharmony_ci ret = of_property_read_u32(np, "nvidia,aspm-cmrt-us", &pcie->aspm_cmrt); 111862306a36Sopenharmony_ci if (ret < 0) { 111962306a36Sopenharmony_ci dev_info(pcie->dev, "Failed to read ASPM T_cmrt: %d\n", ret); 112062306a36Sopenharmony_ci return ret; 112162306a36Sopenharmony_ci } 112262306a36Sopenharmony_ci 112362306a36Sopenharmony_ci ret = of_property_read_u32(np, "nvidia,aspm-pwr-on-t-us", 112462306a36Sopenharmony_ci &pcie->aspm_pwr_on_t); 112562306a36Sopenharmony_ci if (ret < 0) 112662306a36Sopenharmony_ci dev_info(pcie->dev, "Failed to read ASPM Power On time: %d\n", 112762306a36Sopenharmony_ci ret); 112862306a36Sopenharmony_ci 112962306a36Sopenharmony_ci ret = of_property_read_u32(np, "nvidia,aspm-l0s-entrance-latency-us", 113062306a36Sopenharmony_ci &pcie->aspm_l0s_enter_lat); 113162306a36Sopenharmony_ci if (ret < 0) 113262306a36Sopenharmony_ci dev_info(pcie->dev, 113362306a36Sopenharmony_ci "Failed to read ASPM L0s Entrance latency: %d\n", ret); 113462306a36Sopenharmony_ci 113562306a36Sopenharmony_ci ret = of_property_read_u32(np, "num-lanes", &pcie->num_lanes); 113662306a36Sopenharmony_ci if (ret < 0) { 113762306a36Sopenharmony_ci dev_err(pcie->dev, "Failed to read num-lanes: %d\n", ret); 113862306a36Sopenharmony_ci return ret; 113962306a36Sopenharmony_ci } 114062306a36Sopenharmony_ci 114162306a36Sopenharmony_ci ret = of_property_read_u32_index(np, "nvidia,bpmp", 1, &pcie->cid); 114262306a36Sopenharmony_ci if (ret) { 114362306a36Sopenharmony_ci dev_err(pcie->dev, "Failed to read Controller-ID: %d\n", ret); 114462306a36Sopenharmony_ci return ret; 114562306a36Sopenharmony_ci } 114662306a36Sopenharmony_ci 114762306a36Sopenharmony_ci ret = of_property_count_strings(np, "phy-names"); 114862306a36Sopenharmony_ci if (ret < 0) { 114962306a36Sopenharmony_ci dev_err(pcie->dev, "Failed to find PHY entries: %d\n", 115062306a36Sopenharmony_ci ret); 115162306a36Sopenharmony_ci return ret; 115262306a36Sopenharmony_ci } 115362306a36Sopenharmony_ci pcie->phy_count = ret; 115462306a36Sopenharmony_ci 115562306a36Sopenharmony_ci if (of_property_read_bool(np, "nvidia,update-fc-fixup")) 115662306a36Sopenharmony_ci pcie->update_fc_fixup = true; 115762306a36Sopenharmony_ci 115862306a36Sopenharmony_ci /* RP using an external REFCLK is supported only in Tegra234 */ 115962306a36Sopenharmony_ci if (pcie->of_data->version == TEGRA194_DWC_IP_VER) { 116062306a36Sopenharmony_ci if (pcie->of_data->mode == DW_PCIE_EP_TYPE) 116162306a36Sopenharmony_ci pcie->enable_ext_refclk = true; 116262306a36Sopenharmony_ci } else { 116362306a36Sopenharmony_ci pcie->enable_ext_refclk = 116462306a36Sopenharmony_ci of_property_read_bool(pcie->dev->of_node, 116562306a36Sopenharmony_ci "nvidia,enable-ext-refclk"); 116662306a36Sopenharmony_ci } 116762306a36Sopenharmony_ci 116862306a36Sopenharmony_ci pcie->supports_clkreq = 116962306a36Sopenharmony_ci of_property_read_bool(pcie->dev->of_node, "supports-clkreq"); 117062306a36Sopenharmony_ci 117162306a36Sopenharmony_ci pcie->enable_cdm_check = 117262306a36Sopenharmony_ci of_property_read_bool(np, "snps,enable-cdm-check"); 117362306a36Sopenharmony_ci 117462306a36Sopenharmony_ci if (pcie->of_data->version == TEGRA234_DWC_IP_VER) 117562306a36Sopenharmony_ci pcie->enable_srns = 117662306a36Sopenharmony_ci of_property_read_bool(np, "nvidia,enable-srns"); 117762306a36Sopenharmony_ci 117862306a36Sopenharmony_ci if (pcie->of_data->mode == DW_PCIE_RC_TYPE) 117962306a36Sopenharmony_ci return 0; 118062306a36Sopenharmony_ci 118162306a36Sopenharmony_ci /* Endpoint mode specific DT entries */ 118262306a36Sopenharmony_ci pcie->pex_rst_gpiod = devm_gpiod_get(pcie->dev, "reset", GPIOD_IN); 118362306a36Sopenharmony_ci if (IS_ERR(pcie->pex_rst_gpiod)) { 118462306a36Sopenharmony_ci int err = PTR_ERR(pcie->pex_rst_gpiod); 118562306a36Sopenharmony_ci const char *level = KERN_ERR; 118662306a36Sopenharmony_ci 118762306a36Sopenharmony_ci if (err == -EPROBE_DEFER) 118862306a36Sopenharmony_ci level = KERN_DEBUG; 118962306a36Sopenharmony_ci 119062306a36Sopenharmony_ci dev_printk(level, pcie->dev, 119162306a36Sopenharmony_ci dev_fmt("Failed to get PERST GPIO: %d\n"), 119262306a36Sopenharmony_ci err); 119362306a36Sopenharmony_ci return err; 119462306a36Sopenharmony_ci } 119562306a36Sopenharmony_ci 119662306a36Sopenharmony_ci pcie->pex_refclk_sel_gpiod = devm_gpiod_get(pcie->dev, 119762306a36Sopenharmony_ci "nvidia,refclk-select", 119862306a36Sopenharmony_ci GPIOD_OUT_HIGH); 119962306a36Sopenharmony_ci if (IS_ERR(pcie->pex_refclk_sel_gpiod)) { 120062306a36Sopenharmony_ci int err = PTR_ERR(pcie->pex_refclk_sel_gpiod); 120162306a36Sopenharmony_ci const char *level = KERN_ERR; 120262306a36Sopenharmony_ci 120362306a36Sopenharmony_ci if (err == -EPROBE_DEFER) 120462306a36Sopenharmony_ci level = KERN_DEBUG; 120562306a36Sopenharmony_ci 120662306a36Sopenharmony_ci dev_printk(level, pcie->dev, 120762306a36Sopenharmony_ci dev_fmt("Failed to get REFCLK select GPIOs: %d\n"), 120862306a36Sopenharmony_ci err); 120962306a36Sopenharmony_ci pcie->pex_refclk_sel_gpiod = NULL; 121062306a36Sopenharmony_ci } 121162306a36Sopenharmony_ci 121262306a36Sopenharmony_ci return 0; 121362306a36Sopenharmony_ci} 121462306a36Sopenharmony_ci 121562306a36Sopenharmony_cistatic int tegra_pcie_bpmp_set_ctrl_state(struct tegra_pcie_dw *pcie, 121662306a36Sopenharmony_ci bool enable) 121762306a36Sopenharmony_ci{ 121862306a36Sopenharmony_ci struct mrq_uphy_response resp; 121962306a36Sopenharmony_ci struct tegra_bpmp_message msg; 122062306a36Sopenharmony_ci struct mrq_uphy_request req; 122162306a36Sopenharmony_ci 122262306a36Sopenharmony_ci /* 122362306a36Sopenharmony_ci * Controller-5 doesn't need to have its state set by BPMP-FW in 122462306a36Sopenharmony_ci * Tegra194 122562306a36Sopenharmony_ci */ 122662306a36Sopenharmony_ci if (pcie->of_data->version == TEGRA194_DWC_IP_VER && pcie->cid == 5) 122762306a36Sopenharmony_ci return 0; 122862306a36Sopenharmony_ci 122962306a36Sopenharmony_ci memset(&req, 0, sizeof(req)); 123062306a36Sopenharmony_ci memset(&resp, 0, sizeof(resp)); 123162306a36Sopenharmony_ci 123262306a36Sopenharmony_ci req.cmd = CMD_UPHY_PCIE_CONTROLLER_STATE; 123362306a36Sopenharmony_ci req.controller_state.pcie_controller = pcie->cid; 123462306a36Sopenharmony_ci req.controller_state.enable = enable; 123562306a36Sopenharmony_ci 123662306a36Sopenharmony_ci memset(&msg, 0, sizeof(msg)); 123762306a36Sopenharmony_ci msg.mrq = MRQ_UPHY; 123862306a36Sopenharmony_ci msg.tx.data = &req; 123962306a36Sopenharmony_ci msg.tx.size = sizeof(req); 124062306a36Sopenharmony_ci msg.rx.data = &resp; 124162306a36Sopenharmony_ci msg.rx.size = sizeof(resp); 124262306a36Sopenharmony_ci 124362306a36Sopenharmony_ci return tegra_bpmp_transfer(pcie->bpmp, &msg); 124462306a36Sopenharmony_ci} 124562306a36Sopenharmony_ci 124662306a36Sopenharmony_cistatic int tegra_pcie_bpmp_set_pll_state(struct tegra_pcie_dw *pcie, 124762306a36Sopenharmony_ci bool enable) 124862306a36Sopenharmony_ci{ 124962306a36Sopenharmony_ci struct mrq_uphy_response resp; 125062306a36Sopenharmony_ci struct tegra_bpmp_message msg; 125162306a36Sopenharmony_ci struct mrq_uphy_request req; 125262306a36Sopenharmony_ci 125362306a36Sopenharmony_ci memset(&req, 0, sizeof(req)); 125462306a36Sopenharmony_ci memset(&resp, 0, sizeof(resp)); 125562306a36Sopenharmony_ci 125662306a36Sopenharmony_ci if (enable) { 125762306a36Sopenharmony_ci req.cmd = CMD_UPHY_PCIE_EP_CONTROLLER_PLL_INIT; 125862306a36Sopenharmony_ci req.ep_ctrlr_pll_init.ep_controller = pcie->cid; 125962306a36Sopenharmony_ci } else { 126062306a36Sopenharmony_ci req.cmd = CMD_UPHY_PCIE_EP_CONTROLLER_PLL_OFF; 126162306a36Sopenharmony_ci req.ep_ctrlr_pll_off.ep_controller = pcie->cid; 126262306a36Sopenharmony_ci } 126362306a36Sopenharmony_ci 126462306a36Sopenharmony_ci memset(&msg, 0, sizeof(msg)); 126562306a36Sopenharmony_ci msg.mrq = MRQ_UPHY; 126662306a36Sopenharmony_ci msg.tx.data = &req; 126762306a36Sopenharmony_ci msg.tx.size = sizeof(req); 126862306a36Sopenharmony_ci msg.rx.data = &resp; 126962306a36Sopenharmony_ci msg.rx.size = sizeof(resp); 127062306a36Sopenharmony_ci 127162306a36Sopenharmony_ci return tegra_bpmp_transfer(pcie->bpmp, &msg); 127262306a36Sopenharmony_ci} 127362306a36Sopenharmony_ci 127462306a36Sopenharmony_cistatic void tegra_pcie_downstream_dev_to_D0(struct tegra_pcie_dw *pcie) 127562306a36Sopenharmony_ci{ 127662306a36Sopenharmony_ci struct dw_pcie_rp *pp = &pcie->pci.pp; 127762306a36Sopenharmony_ci struct pci_bus *child, *root_bus = NULL; 127862306a36Sopenharmony_ci struct pci_dev *pdev; 127962306a36Sopenharmony_ci 128062306a36Sopenharmony_ci /* 128162306a36Sopenharmony_ci * link doesn't go into L2 state with some of the endpoints with Tegra 128262306a36Sopenharmony_ci * if they are not in D0 state. So, need to make sure that immediate 128362306a36Sopenharmony_ci * downstream devices are in D0 state before sending PME_TurnOff to put 128462306a36Sopenharmony_ci * link into L2 state. 128562306a36Sopenharmony_ci * This is as per PCI Express Base r4.0 v1.0 September 27-2017, 128662306a36Sopenharmony_ci * 5.2 Link State Power Management (Page #428). 128762306a36Sopenharmony_ci */ 128862306a36Sopenharmony_ci 128962306a36Sopenharmony_ci list_for_each_entry(child, &pp->bridge->bus->children, node) { 129062306a36Sopenharmony_ci /* Bring downstream devices to D0 if they are not already in */ 129162306a36Sopenharmony_ci if (child->parent == pp->bridge->bus) { 129262306a36Sopenharmony_ci root_bus = child; 129362306a36Sopenharmony_ci break; 129462306a36Sopenharmony_ci } 129562306a36Sopenharmony_ci } 129662306a36Sopenharmony_ci 129762306a36Sopenharmony_ci if (!root_bus) { 129862306a36Sopenharmony_ci dev_err(pcie->dev, "Failed to find downstream devices\n"); 129962306a36Sopenharmony_ci return; 130062306a36Sopenharmony_ci } 130162306a36Sopenharmony_ci 130262306a36Sopenharmony_ci list_for_each_entry(pdev, &root_bus->devices, bus_list) { 130362306a36Sopenharmony_ci if (PCI_SLOT(pdev->devfn) == 0) { 130462306a36Sopenharmony_ci if (pci_set_power_state(pdev, PCI_D0)) 130562306a36Sopenharmony_ci dev_err(pcie->dev, 130662306a36Sopenharmony_ci "Failed to transition %s to D0 state\n", 130762306a36Sopenharmony_ci dev_name(&pdev->dev)); 130862306a36Sopenharmony_ci } 130962306a36Sopenharmony_ci } 131062306a36Sopenharmony_ci} 131162306a36Sopenharmony_ci 131262306a36Sopenharmony_cistatic int tegra_pcie_get_slot_regulators(struct tegra_pcie_dw *pcie) 131362306a36Sopenharmony_ci{ 131462306a36Sopenharmony_ci pcie->slot_ctl_3v3 = devm_regulator_get_optional(pcie->dev, "vpcie3v3"); 131562306a36Sopenharmony_ci if (IS_ERR(pcie->slot_ctl_3v3)) { 131662306a36Sopenharmony_ci if (PTR_ERR(pcie->slot_ctl_3v3) != -ENODEV) 131762306a36Sopenharmony_ci return PTR_ERR(pcie->slot_ctl_3v3); 131862306a36Sopenharmony_ci 131962306a36Sopenharmony_ci pcie->slot_ctl_3v3 = NULL; 132062306a36Sopenharmony_ci } 132162306a36Sopenharmony_ci 132262306a36Sopenharmony_ci pcie->slot_ctl_12v = devm_regulator_get_optional(pcie->dev, "vpcie12v"); 132362306a36Sopenharmony_ci if (IS_ERR(pcie->slot_ctl_12v)) { 132462306a36Sopenharmony_ci if (PTR_ERR(pcie->slot_ctl_12v) != -ENODEV) 132562306a36Sopenharmony_ci return PTR_ERR(pcie->slot_ctl_12v); 132662306a36Sopenharmony_ci 132762306a36Sopenharmony_ci pcie->slot_ctl_12v = NULL; 132862306a36Sopenharmony_ci } 132962306a36Sopenharmony_ci 133062306a36Sopenharmony_ci return 0; 133162306a36Sopenharmony_ci} 133262306a36Sopenharmony_ci 133362306a36Sopenharmony_cistatic int tegra_pcie_enable_slot_regulators(struct tegra_pcie_dw *pcie) 133462306a36Sopenharmony_ci{ 133562306a36Sopenharmony_ci int ret; 133662306a36Sopenharmony_ci 133762306a36Sopenharmony_ci if (pcie->slot_ctl_3v3) { 133862306a36Sopenharmony_ci ret = regulator_enable(pcie->slot_ctl_3v3); 133962306a36Sopenharmony_ci if (ret < 0) { 134062306a36Sopenharmony_ci dev_err(pcie->dev, 134162306a36Sopenharmony_ci "Failed to enable 3.3V slot supply: %d\n", ret); 134262306a36Sopenharmony_ci return ret; 134362306a36Sopenharmony_ci } 134462306a36Sopenharmony_ci } 134562306a36Sopenharmony_ci 134662306a36Sopenharmony_ci if (pcie->slot_ctl_12v) { 134762306a36Sopenharmony_ci ret = regulator_enable(pcie->slot_ctl_12v); 134862306a36Sopenharmony_ci if (ret < 0) { 134962306a36Sopenharmony_ci dev_err(pcie->dev, 135062306a36Sopenharmony_ci "Failed to enable 12V slot supply: %d\n", ret); 135162306a36Sopenharmony_ci goto fail_12v_enable; 135262306a36Sopenharmony_ci } 135362306a36Sopenharmony_ci } 135462306a36Sopenharmony_ci 135562306a36Sopenharmony_ci /* 135662306a36Sopenharmony_ci * According to PCI Express Card Electromechanical Specification 135762306a36Sopenharmony_ci * Revision 1.1, Table-2.4, T_PVPERL (Power stable to PERST# inactive) 135862306a36Sopenharmony_ci * should be a minimum of 100ms. 135962306a36Sopenharmony_ci */ 136062306a36Sopenharmony_ci if (pcie->slot_ctl_3v3 || pcie->slot_ctl_12v) 136162306a36Sopenharmony_ci msleep(100); 136262306a36Sopenharmony_ci 136362306a36Sopenharmony_ci return 0; 136462306a36Sopenharmony_ci 136562306a36Sopenharmony_cifail_12v_enable: 136662306a36Sopenharmony_ci if (pcie->slot_ctl_3v3) 136762306a36Sopenharmony_ci regulator_disable(pcie->slot_ctl_3v3); 136862306a36Sopenharmony_ci return ret; 136962306a36Sopenharmony_ci} 137062306a36Sopenharmony_ci 137162306a36Sopenharmony_cistatic void tegra_pcie_disable_slot_regulators(struct tegra_pcie_dw *pcie) 137262306a36Sopenharmony_ci{ 137362306a36Sopenharmony_ci if (pcie->slot_ctl_12v) 137462306a36Sopenharmony_ci regulator_disable(pcie->slot_ctl_12v); 137562306a36Sopenharmony_ci if (pcie->slot_ctl_3v3) 137662306a36Sopenharmony_ci regulator_disable(pcie->slot_ctl_3v3); 137762306a36Sopenharmony_ci} 137862306a36Sopenharmony_ci 137962306a36Sopenharmony_cistatic int tegra_pcie_config_controller(struct tegra_pcie_dw *pcie, 138062306a36Sopenharmony_ci bool en_hw_hot_rst) 138162306a36Sopenharmony_ci{ 138262306a36Sopenharmony_ci int ret; 138362306a36Sopenharmony_ci u32 val; 138462306a36Sopenharmony_ci 138562306a36Sopenharmony_ci ret = tegra_pcie_bpmp_set_ctrl_state(pcie, true); 138662306a36Sopenharmony_ci if (ret) { 138762306a36Sopenharmony_ci dev_err(pcie->dev, 138862306a36Sopenharmony_ci "Failed to enable controller %u: %d\n", pcie->cid, ret); 138962306a36Sopenharmony_ci return ret; 139062306a36Sopenharmony_ci } 139162306a36Sopenharmony_ci 139262306a36Sopenharmony_ci if (pcie->enable_ext_refclk) { 139362306a36Sopenharmony_ci ret = tegra_pcie_bpmp_set_pll_state(pcie, true); 139462306a36Sopenharmony_ci if (ret) { 139562306a36Sopenharmony_ci dev_err(pcie->dev, "Failed to init UPHY: %d\n", ret); 139662306a36Sopenharmony_ci goto fail_pll_init; 139762306a36Sopenharmony_ci } 139862306a36Sopenharmony_ci } 139962306a36Sopenharmony_ci 140062306a36Sopenharmony_ci ret = tegra_pcie_enable_slot_regulators(pcie); 140162306a36Sopenharmony_ci if (ret < 0) 140262306a36Sopenharmony_ci goto fail_slot_reg_en; 140362306a36Sopenharmony_ci 140462306a36Sopenharmony_ci ret = regulator_enable(pcie->pex_ctl_supply); 140562306a36Sopenharmony_ci if (ret < 0) { 140662306a36Sopenharmony_ci dev_err(pcie->dev, "Failed to enable regulator: %d\n", ret); 140762306a36Sopenharmony_ci goto fail_reg_en; 140862306a36Sopenharmony_ci } 140962306a36Sopenharmony_ci 141062306a36Sopenharmony_ci ret = clk_prepare_enable(pcie->core_clk); 141162306a36Sopenharmony_ci if (ret) { 141262306a36Sopenharmony_ci dev_err(pcie->dev, "Failed to enable core clock: %d\n", ret); 141362306a36Sopenharmony_ci goto fail_core_clk; 141462306a36Sopenharmony_ci } 141562306a36Sopenharmony_ci 141662306a36Sopenharmony_ci ret = reset_control_deassert(pcie->core_apb_rst); 141762306a36Sopenharmony_ci if (ret) { 141862306a36Sopenharmony_ci dev_err(pcie->dev, "Failed to deassert core APB reset: %d\n", 141962306a36Sopenharmony_ci ret); 142062306a36Sopenharmony_ci goto fail_core_apb_rst; 142162306a36Sopenharmony_ci } 142262306a36Sopenharmony_ci 142362306a36Sopenharmony_ci if (en_hw_hot_rst || pcie->of_data->has_sbr_reset_fix) { 142462306a36Sopenharmony_ci /* Enable HW_HOT_RST mode */ 142562306a36Sopenharmony_ci val = appl_readl(pcie, APPL_CTRL); 142662306a36Sopenharmony_ci val &= ~(APPL_CTRL_HW_HOT_RST_MODE_MASK << 142762306a36Sopenharmony_ci APPL_CTRL_HW_HOT_RST_MODE_SHIFT); 142862306a36Sopenharmony_ci val |= (APPL_CTRL_HW_HOT_RST_MODE_IMDT_RST_LTSSM_EN << 142962306a36Sopenharmony_ci APPL_CTRL_HW_HOT_RST_MODE_SHIFT); 143062306a36Sopenharmony_ci val |= APPL_CTRL_HW_HOT_RST_EN; 143162306a36Sopenharmony_ci appl_writel(pcie, val, APPL_CTRL); 143262306a36Sopenharmony_ci } 143362306a36Sopenharmony_ci 143462306a36Sopenharmony_ci ret = tegra_pcie_enable_phy(pcie); 143562306a36Sopenharmony_ci if (ret) { 143662306a36Sopenharmony_ci dev_err(pcie->dev, "Failed to enable PHY: %d\n", ret); 143762306a36Sopenharmony_ci goto fail_phy; 143862306a36Sopenharmony_ci } 143962306a36Sopenharmony_ci 144062306a36Sopenharmony_ci /* Update CFG base address */ 144162306a36Sopenharmony_ci appl_writel(pcie, pcie->dbi_res->start & APPL_CFG_BASE_ADDR_MASK, 144262306a36Sopenharmony_ci APPL_CFG_BASE_ADDR); 144362306a36Sopenharmony_ci 144462306a36Sopenharmony_ci /* Configure this core for RP mode operation */ 144562306a36Sopenharmony_ci appl_writel(pcie, APPL_DM_TYPE_RP, APPL_DM_TYPE); 144662306a36Sopenharmony_ci 144762306a36Sopenharmony_ci appl_writel(pcie, 0x0, APPL_CFG_SLCG_OVERRIDE); 144862306a36Sopenharmony_ci 144962306a36Sopenharmony_ci val = appl_readl(pcie, APPL_CTRL); 145062306a36Sopenharmony_ci appl_writel(pcie, val | APPL_CTRL_SYS_PRE_DET_STATE, APPL_CTRL); 145162306a36Sopenharmony_ci 145262306a36Sopenharmony_ci val = appl_readl(pcie, APPL_CFG_MISC); 145362306a36Sopenharmony_ci val |= (APPL_CFG_MISC_ARCACHE_VAL << APPL_CFG_MISC_ARCACHE_SHIFT); 145462306a36Sopenharmony_ci appl_writel(pcie, val, APPL_CFG_MISC); 145562306a36Sopenharmony_ci 145662306a36Sopenharmony_ci if (pcie->enable_srns || pcie->enable_ext_refclk) { 145762306a36Sopenharmony_ci /* 145862306a36Sopenharmony_ci * When Tegra PCIe RP is using external clock, it cannot supply 145962306a36Sopenharmony_ci * same clock to its downstream hierarchy. Hence, gate PCIe RP 146062306a36Sopenharmony_ci * REFCLK out pads when RP & EP are using separate clocks or RP 146162306a36Sopenharmony_ci * is using an external REFCLK. 146262306a36Sopenharmony_ci */ 146362306a36Sopenharmony_ci val = appl_readl(pcie, APPL_PINMUX); 146462306a36Sopenharmony_ci val |= APPL_PINMUX_CLK_OUTPUT_IN_OVERRIDE_EN; 146562306a36Sopenharmony_ci val &= ~APPL_PINMUX_CLK_OUTPUT_IN_OVERRIDE; 146662306a36Sopenharmony_ci appl_writel(pcie, val, APPL_PINMUX); 146762306a36Sopenharmony_ci } 146862306a36Sopenharmony_ci 146962306a36Sopenharmony_ci if (!pcie->supports_clkreq) { 147062306a36Sopenharmony_ci val = appl_readl(pcie, APPL_PINMUX); 147162306a36Sopenharmony_ci val |= APPL_PINMUX_CLKREQ_OVERRIDE_EN; 147262306a36Sopenharmony_ci val &= ~APPL_PINMUX_CLKREQ_OVERRIDE; 147362306a36Sopenharmony_ci appl_writel(pcie, val, APPL_PINMUX); 147462306a36Sopenharmony_ci } 147562306a36Sopenharmony_ci 147662306a36Sopenharmony_ci /* Update iATU_DMA base address */ 147762306a36Sopenharmony_ci appl_writel(pcie, 147862306a36Sopenharmony_ci pcie->atu_dma_res->start & APPL_CFG_IATU_DMA_BASE_ADDR_MASK, 147962306a36Sopenharmony_ci APPL_CFG_IATU_DMA_BASE_ADDR); 148062306a36Sopenharmony_ci 148162306a36Sopenharmony_ci reset_control_deassert(pcie->core_rst); 148262306a36Sopenharmony_ci 148362306a36Sopenharmony_ci return ret; 148462306a36Sopenharmony_ci 148562306a36Sopenharmony_cifail_phy: 148662306a36Sopenharmony_ci reset_control_assert(pcie->core_apb_rst); 148762306a36Sopenharmony_cifail_core_apb_rst: 148862306a36Sopenharmony_ci clk_disable_unprepare(pcie->core_clk); 148962306a36Sopenharmony_cifail_core_clk: 149062306a36Sopenharmony_ci regulator_disable(pcie->pex_ctl_supply); 149162306a36Sopenharmony_cifail_reg_en: 149262306a36Sopenharmony_ci tegra_pcie_disable_slot_regulators(pcie); 149362306a36Sopenharmony_cifail_slot_reg_en: 149462306a36Sopenharmony_ci if (pcie->enable_ext_refclk) 149562306a36Sopenharmony_ci tegra_pcie_bpmp_set_pll_state(pcie, false); 149662306a36Sopenharmony_cifail_pll_init: 149762306a36Sopenharmony_ci tegra_pcie_bpmp_set_ctrl_state(pcie, false); 149862306a36Sopenharmony_ci 149962306a36Sopenharmony_ci return ret; 150062306a36Sopenharmony_ci} 150162306a36Sopenharmony_ci 150262306a36Sopenharmony_cistatic void tegra_pcie_unconfig_controller(struct tegra_pcie_dw *pcie) 150362306a36Sopenharmony_ci{ 150462306a36Sopenharmony_ci int ret; 150562306a36Sopenharmony_ci 150662306a36Sopenharmony_ci ret = reset_control_assert(pcie->core_rst); 150762306a36Sopenharmony_ci if (ret) 150862306a36Sopenharmony_ci dev_err(pcie->dev, "Failed to assert \"core\" reset: %d\n", ret); 150962306a36Sopenharmony_ci 151062306a36Sopenharmony_ci tegra_pcie_disable_phy(pcie); 151162306a36Sopenharmony_ci 151262306a36Sopenharmony_ci ret = reset_control_assert(pcie->core_apb_rst); 151362306a36Sopenharmony_ci if (ret) 151462306a36Sopenharmony_ci dev_err(pcie->dev, "Failed to assert APB reset: %d\n", ret); 151562306a36Sopenharmony_ci 151662306a36Sopenharmony_ci clk_disable_unprepare(pcie->core_clk); 151762306a36Sopenharmony_ci 151862306a36Sopenharmony_ci ret = regulator_disable(pcie->pex_ctl_supply); 151962306a36Sopenharmony_ci if (ret) 152062306a36Sopenharmony_ci dev_err(pcie->dev, "Failed to disable regulator: %d\n", ret); 152162306a36Sopenharmony_ci 152262306a36Sopenharmony_ci tegra_pcie_disable_slot_regulators(pcie); 152362306a36Sopenharmony_ci 152462306a36Sopenharmony_ci if (pcie->enable_ext_refclk) { 152562306a36Sopenharmony_ci ret = tegra_pcie_bpmp_set_pll_state(pcie, false); 152662306a36Sopenharmony_ci if (ret) 152762306a36Sopenharmony_ci dev_err(pcie->dev, "Failed to deinit UPHY: %d\n", ret); 152862306a36Sopenharmony_ci } 152962306a36Sopenharmony_ci 153062306a36Sopenharmony_ci ret = tegra_pcie_bpmp_set_ctrl_state(pcie, false); 153162306a36Sopenharmony_ci if (ret) 153262306a36Sopenharmony_ci dev_err(pcie->dev, "Failed to disable controller %d: %d\n", 153362306a36Sopenharmony_ci pcie->cid, ret); 153462306a36Sopenharmony_ci} 153562306a36Sopenharmony_ci 153662306a36Sopenharmony_cistatic int tegra_pcie_init_controller(struct tegra_pcie_dw *pcie) 153762306a36Sopenharmony_ci{ 153862306a36Sopenharmony_ci struct dw_pcie *pci = &pcie->pci; 153962306a36Sopenharmony_ci struct dw_pcie_rp *pp = &pci->pp; 154062306a36Sopenharmony_ci int ret; 154162306a36Sopenharmony_ci 154262306a36Sopenharmony_ci ret = tegra_pcie_config_controller(pcie, false); 154362306a36Sopenharmony_ci if (ret < 0) 154462306a36Sopenharmony_ci return ret; 154562306a36Sopenharmony_ci 154662306a36Sopenharmony_ci pp->ops = &tegra_pcie_dw_host_ops; 154762306a36Sopenharmony_ci 154862306a36Sopenharmony_ci ret = dw_pcie_host_init(pp); 154962306a36Sopenharmony_ci if (ret < 0) { 155062306a36Sopenharmony_ci dev_err(pcie->dev, "Failed to add PCIe port: %d\n", ret); 155162306a36Sopenharmony_ci goto fail_host_init; 155262306a36Sopenharmony_ci } 155362306a36Sopenharmony_ci 155462306a36Sopenharmony_ci return 0; 155562306a36Sopenharmony_ci 155662306a36Sopenharmony_cifail_host_init: 155762306a36Sopenharmony_ci tegra_pcie_unconfig_controller(pcie); 155862306a36Sopenharmony_ci return ret; 155962306a36Sopenharmony_ci} 156062306a36Sopenharmony_ci 156162306a36Sopenharmony_cistatic int tegra_pcie_try_link_l2(struct tegra_pcie_dw *pcie) 156262306a36Sopenharmony_ci{ 156362306a36Sopenharmony_ci u32 val; 156462306a36Sopenharmony_ci 156562306a36Sopenharmony_ci if (!tegra_pcie_dw_link_up(&pcie->pci)) 156662306a36Sopenharmony_ci return 0; 156762306a36Sopenharmony_ci 156862306a36Sopenharmony_ci val = appl_readl(pcie, APPL_RADM_STATUS); 156962306a36Sopenharmony_ci val |= APPL_PM_XMT_TURNOFF_STATE; 157062306a36Sopenharmony_ci appl_writel(pcie, val, APPL_RADM_STATUS); 157162306a36Sopenharmony_ci 157262306a36Sopenharmony_ci return readl_poll_timeout_atomic(pcie->appl_base + APPL_DEBUG, val, 157362306a36Sopenharmony_ci val & APPL_DEBUG_PM_LINKST_IN_L2_LAT, 157462306a36Sopenharmony_ci 1, PME_ACK_TIMEOUT); 157562306a36Sopenharmony_ci} 157662306a36Sopenharmony_ci 157762306a36Sopenharmony_cistatic void tegra_pcie_dw_pme_turnoff(struct tegra_pcie_dw *pcie) 157862306a36Sopenharmony_ci{ 157962306a36Sopenharmony_ci u32 data; 158062306a36Sopenharmony_ci int err; 158162306a36Sopenharmony_ci 158262306a36Sopenharmony_ci if (!tegra_pcie_dw_link_up(&pcie->pci)) { 158362306a36Sopenharmony_ci dev_dbg(pcie->dev, "PCIe link is not up...!\n"); 158462306a36Sopenharmony_ci return; 158562306a36Sopenharmony_ci } 158662306a36Sopenharmony_ci 158762306a36Sopenharmony_ci /* 158862306a36Sopenharmony_ci * PCIe controller exits from L2 only if reset is applied, so 158962306a36Sopenharmony_ci * controller doesn't handle interrupts. But in cases where 159062306a36Sopenharmony_ci * L2 entry fails, PERST# is asserted which can trigger surprise 159162306a36Sopenharmony_ci * link down AER. However this function call happens in 159262306a36Sopenharmony_ci * suspend_noirq(), so AER interrupt will not be processed. 159362306a36Sopenharmony_ci * Disable all interrupts to avoid such a scenario. 159462306a36Sopenharmony_ci */ 159562306a36Sopenharmony_ci appl_writel(pcie, 0x0, APPL_INTR_EN_L0_0); 159662306a36Sopenharmony_ci 159762306a36Sopenharmony_ci if (tegra_pcie_try_link_l2(pcie)) { 159862306a36Sopenharmony_ci dev_info(pcie->dev, "Link didn't transition to L2 state\n"); 159962306a36Sopenharmony_ci /* 160062306a36Sopenharmony_ci * TX lane clock freq will reset to Gen1 only if link is in L2 160162306a36Sopenharmony_ci * or detect state. 160262306a36Sopenharmony_ci * So apply pex_rst to end point to force RP to go into detect 160362306a36Sopenharmony_ci * state 160462306a36Sopenharmony_ci */ 160562306a36Sopenharmony_ci data = appl_readl(pcie, APPL_PINMUX); 160662306a36Sopenharmony_ci data &= ~APPL_PINMUX_PEX_RST; 160762306a36Sopenharmony_ci appl_writel(pcie, data, APPL_PINMUX); 160862306a36Sopenharmony_ci 160962306a36Sopenharmony_ci /* 161062306a36Sopenharmony_ci * Some cards do not go to detect state even after de-asserting 161162306a36Sopenharmony_ci * PERST#. So, de-assert LTSSM to bring link to detect state. 161262306a36Sopenharmony_ci */ 161362306a36Sopenharmony_ci data = readl(pcie->appl_base + APPL_CTRL); 161462306a36Sopenharmony_ci data &= ~APPL_CTRL_LTSSM_EN; 161562306a36Sopenharmony_ci writel(data, pcie->appl_base + APPL_CTRL); 161662306a36Sopenharmony_ci 161762306a36Sopenharmony_ci err = readl_poll_timeout_atomic(pcie->appl_base + APPL_DEBUG, 161862306a36Sopenharmony_ci data, 161962306a36Sopenharmony_ci ((data & 162062306a36Sopenharmony_ci APPL_DEBUG_LTSSM_STATE_MASK) >> 162162306a36Sopenharmony_ci APPL_DEBUG_LTSSM_STATE_SHIFT) == 162262306a36Sopenharmony_ci LTSSM_STATE_PRE_DETECT, 162362306a36Sopenharmony_ci 1, LTSSM_TIMEOUT); 162462306a36Sopenharmony_ci if (err) 162562306a36Sopenharmony_ci dev_info(pcie->dev, "Link didn't go to detect state\n"); 162662306a36Sopenharmony_ci } 162762306a36Sopenharmony_ci /* 162862306a36Sopenharmony_ci * DBI registers may not be accessible after this as PLL-E would be 162962306a36Sopenharmony_ci * down depending on how CLKREQ is pulled by end point 163062306a36Sopenharmony_ci */ 163162306a36Sopenharmony_ci data = appl_readl(pcie, APPL_PINMUX); 163262306a36Sopenharmony_ci data |= (APPL_PINMUX_CLKREQ_OVERRIDE_EN | APPL_PINMUX_CLKREQ_OVERRIDE); 163362306a36Sopenharmony_ci /* Cut REFCLK to slot */ 163462306a36Sopenharmony_ci data |= APPL_PINMUX_CLK_OUTPUT_IN_OVERRIDE_EN; 163562306a36Sopenharmony_ci data &= ~APPL_PINMUX_CLK_OUTPUT_IN_OVERRIDE; 163662306a36Sopenharmony_ci appl_writel(pcie, data, APPL_PINMUX); 163762306a36Sopenharmony_ci} 163862306a36Sopenharmony_ci 163962306a36Sopenharmony_cistatic void tegra_pcie_deinit_controller(struct tegra_pcie_dw *pcie) 164062306a36Sopenharmony_ci{ 164162306a36Sopenharmony_ci tegra_pcie_downstream_dev_to_D0(pcie); 164262306a36Sopenharmony_ci dw_pcie_host_deinit(&pcie->pci.pp); 164362306a36Sopenharmony_ci tegra_pcie_dw_pme_turnoff(pcie); 164462306a36Sopenharmony_ci tegra_pcie_unconfig_controller(pcie); 164562306a36Sopenharmony_ci} 164662306a36Sopenharmony_ci 164762306a36Sopenharmony_cistatic int tegra_pcie_config_rp(struct tegra_pcie_dw *pcie) 164862306a36Sopenharmony_ci{ 164962306a36Sopenharmony_ci struct device *dev = pcie->dev; 165062306a36Sopenharmony_ci char *name; 165162306a36Sopenharmony_ci int ret; 165262306a36Sopenharmony_ci 165362306a36Sopenharmony_ci pm_runtime_enable(dev); 165462306a36Sopenharmony_ci 165562306a36Sopenharmony_ci ret = pm_runtime_get_sync(dev); 165662306a36Sopenharmony_ci if (ret < 0) { 165762306a36Sopenharmony_ci dev_err(dev, "Failed to get runtime sync for PCIe dev: %d\n", 165862306a36Sopenharmony_ci ret); 165962306a36Sopenharmony_ci goto fail_pm_get_sync; 166062306a36Sopenharmony_ci } 166162306a36Sopenharmony_ci 166262306a36Sopenharmony_ci ret = pinctrl_pm_select_default_state(dev); 166362306a36Sopenharmony_ci if (ret < 0) { 166462306a36Sopenharmony_ci dev_err(dev, "Failed to configure sideband pins: %d\n", ret); 166562306a36Sopenharmony_ci goto fail_pm_get_sync; 166662306a36Sopenharmony_ci } 166762306a36Sopenharmony_ci 166862306a36Sopenharmony_ci ret = tegra_pcie_init_controller(pcie); 166962306a36Sopenharmony_ci if (ret < 0) { 167062306a36Sopenharmony_ci dev_err(dev, "Failed to initialize controller: %d\n", ret); 167162306a36Sopenharmony_ci goto fail_pm_get_sync; 167262306a36Sopenharmony_ci } 167362306a36Sopenharmony_ci 167462306a36Sopenharmony_ci pcie->link_state = tegra_pcie_dw_link_up(&pcie->pci); 167562306a36Sopenharmony_ci if (!pcie->link_state) { 167662306a36Sopenharmony_ci ret = -ENOMEDIUM; 167762306a36Sopenharmony_ci goto fail_host_init; 167862306a36Sopenharmony_ci } 167962306a36Sopenharmony_ci 168062306a36Sopenharmony_ci name = devm_kasprintf(dev, GFP_KERNEL, "%pOFP", dev->of_node); 168162306a36Sopenharmony_ci if (!name) { 168262306a36Sopenharmony_ci ret = -ENOMEM; 168362306a36Sopenharmony_ci goto fail_host_init; 168462306a36Sopenharmony_ci } 168562306a36Sopenharmony_ci 168662306a36Sopenharmony_ci pcie->debugfs = debugfs_create_dir(name, NULL); 168762306a36Sopenharmony_ci init_debugfs(pcie); 168862306a36Sopenharmony_ci 168962306a36Sopenharmony_ci return ret; 169062306a36Sopenharmony_ci 169162306a36Sopenharmony_cifail_host_init: 169262306a36Sopenharmony_ci tegra_pcie_deinit_controller(pcie); 169362306a36Sopenharmony_cifail_pm_get_sync: 169462306a36Sopenharmony_ci pm_runtime_put_sync(dev); 169562306a36Sopenharmony_ci pm_runtime_disable(dev); 169662306a36Sopenharmony_ci return ret; 169762306a36Sopenharmony_ci} 169862306a36Sopenharmony_ci 169962306a36Sopenharmony_cistatic void pex_ep_event_pex_rst_assert(struct tegra_pcie_dw *pcie) 170062306a36Sopenharmony_ci{ 170162306a36Sopenharmony_ci u32 val; 170262306a36Sopenharmony_ci int ret; 170362306a36Sopenharmony_ci 170462306a36Sopenharmony_ci if (pcie->ep_state == EP_STATE_DISABLED) 170562306a36Sopenharmony_ci return; 170662306a36Sopenharmony_ci 170762306a36Sopenharmony_ci /* Disable LTSSM */ 170862306a36Sopenharmony_ci val = appl_readl(pcie, APPL_CTRL); 170962306a36Sopenharmony_ci val &= ~APPL_CTRL_LTSSM_EN; 171062306a36Sopenharmony_ci appl_writel(pcie, val, APPL_CTRL); 171162306a36Sopenharmony_ci 171262306a36Sopenharmony_ci ret = readl_poll_timeout(pcie->appl_base + APPL_DEBUG, val, 171362306a36Sopenharmony_ci ((val & APPL_DEBUG_LTSSM_STATE_MASK) >> 171462306a36Sopenharmony_ci APPL_DEBUG_LTSSM_STATE_SHIFT) == 171562306a36Sopenharmony_ci LTSSM_STATE_PRE_DETECT, 171662306a36Sopenharmony_ci 1, LTSSM_TIMEOUT); 171762306a36Sopenharmony_ci if (ret) 171862306a36Sopenharmony_ci dev_err(pcie->dev, "Failed to go Detect state: %d\n", ret); 171962306a36Sopenharmony_ci 172062306a36Sopenharmony_ci reset_control_assert(pcie->core_rst); 172162306a36Sopenharmony_ci 172262306a36Sopenharmony_ci tegra_pcie_disable_phy(pcie); 172362306a36Sopenharmony_ci 172462306a36Sopenharmony_ci reset_control_assert(pcie->core_apb_rst); 172562306a36Sopenharmony_ci 172662306a36Sopenharmony_ci clk_disable_unprepare(pcie->core_clk); 172762306a36Sopenharmony_ci 172862306a36Sopenharmony_ci pm_runtime_put_sync(pcie->dev); 172962306a36Sopenharmony_ci 173062306a36Sopenharmony_ci if (pcie->enable_ext_refclk) { 173162306a36Sopenharmony_ci ret = tegra_pcie_bpmp_set_pll_state(pcie, false); 173262306a36Sopenharmony_ci if (ret) 173362306a36Sopenharmony_ci dev_err(pcie->dev, "Failed to turn off UPHY: %d\n", 173462306a36Sopenharmony_ci ret); 173562306a36Sopenharmony_ci } 173662306a36Sopenharmony_ci 173762306a36Sopenharmony_ci ret = tegra_pcie_bpmp_set_pll_state(pcie, false); 173862306a36Sopenharmony_ci if (ret) 173962306a36Sopenharmony_ci dev_err(pcie->dev, "Failed to turn off UPHY: %d\n", ret); 174062306a36Sopenharmony_ci 174162306a36Sopenharmony_ci pcie->ep_state = EP_STATE_DISABLED; 174262306a36Sopenharmony_ci dev_dbg(pcie->dev, "Uninitialization of endpoint is completed\n"); 174362306a36Sopenharmony_ci} 174462306a36Sopenharmony_ci 174562306a36Sopenharmony_cistatic void pex_ep_event_pex_rst_deassert(struct tegra_pcie_dw *pcie) 174662306a36Sopenharmony_ci{ 174762306a36Sopenharmony_ci struct dw_pcie *pci = &pcie->pci; 174862306a36Sopenharmony_ci struct dw_pcie_ep *ep = &pci->ep; 174962306a36Sopenharmony_ci struct device *dev = pcie->dev; 175062306a36Sopenharmony_ci u32 val; 175162306a36Sopenharmony_ci int ret; 175262306a36Sopenharmony_ci u16 val_16; 175362306a36Sopenharmony_ci 175462306a36Sopenharmony_ci if (pcie->ep_state == EP_STATE_ENABLED) 175562306a36Sopenharmony_ci return; 175662306a36Sopenharmony_ci 175762306a36Sopenharmony_ci ret = pm_runtime_resume_and_get(dev); 175862306a36Sopenharmony_ci if (ret < 0) { 175962306a36Sopenharmony_ci dev_err(dev, "Failed to get runtime sync for PCIe dev: %d\n", 176062306a36Sopenharmony_ci ret); 176162306a36Sopenharmony_ci return; 176262306a36Sopenharmony_ci } 176362306a36Sopenharmony_ci 176462306a36Sopenharmony_ci ret = tegra_pcie_bpmp_set_ctrl_state(pcie, true); 176562306a36Sopenharmony_ci if (ret) { 176662306a36Sopenharmony_ci dev_err(pcie->dev, "Failed to enable controller %u: %d\n", 176762306a36Sopenharmony_ci pcie->cid, ret); 176862306a36Sopenharmony_ci goto fail_set_ctrl_state; 176962306a36Sopenharmony_ci } 177062306a36Sopenharmony_ci 177162306a36Sopenharmony_ci if (pcie->enable_ext_refclk) { 177262306a36Sopenharmony_ci ret = tegra_pcie_bpmp_set_pll_state(pcie, true); 177362306a36Sopenharmony_ci if (ret) { 177462306a36Sopenharmony_ci dev_err(dev, "Failed to init UPHY for PCIe EP: %d\n", 177562306a36Sopenharmony_ci ret); 177662306a36Sopenharmony_ci goto fail_pll_init; 177762306a36Sopenharmony_ci } 177862306a36Sopenharmony_ci } 177962306a36Sopenharmony_ci 178062306a36Sopenharmony_ci ret = clk_prepare_enable(pcie->core_clk); 178162306a36Sopenharmony_ci if (ret) { 178262306a36Sopenharmony_ci dev_err(dev, "Failed to enable core clock: %d\n", ret); 178362306a36Sopenharmony_ci goto fail_core_clk_enable; 178462306a36Sopenharmony_ci } 178562306a36Sopenharmony_ci 178662306a36Sopenharmony_ci ret = reset_control_deassert(pcie->core_apb_rst); 178762306a36Sopenharmony_ci if (ret) { 178862306a36Sopenharmony_ci dev_err(dev, "Failed to deassert core APB reset: %d\n", ret); 178962306a36Sopenharmony_ci goto fail_core_apb_rst; 179062306a36Sopenharmony_ci } 179162306a36Sopenharmony_ci 179262306a36Sopenharmony_ci ret = tegra_pcie_enable_phy(pcie); 179362306a36Sopenharmony_ci if (ret) { 179462306a36Sopenharmony_ci dev_err(dev, "Failed to enable PHY: %d\n", ret); 179562306a36Sopenharmony_ci goto fail_phy; 179662306a36Sopenharmony_ci } 179762306a36Sopenharmony_ci 179862306a36Sopenharmony_ci /* Clear any stale interrupt statuses */ 179962306a36Sopenharmony_ci appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L0); 180062306a36Sopenharmony_ci appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_0_0); 180162306a36Sopenharmony_ci appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_1); 180262306a36Sopenharmony_ci appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_2); 180362306a36Sopenharmony_ci appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_3); 180462306a36Sopenharmony_ci appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_6); 180562306a36Sopenharmony_ci appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_7); 180662306a36Sopenharmony_ci appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_8_0); 180762306a36Sopenharmony_ci appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_9); 180862306a36Sopenharmony_ci appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_10); 180962306a36Sopenharmony_ci appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_11); 181062306a36Sopenharmony_ci appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_13); 181162306a36Sopenharmony_ci appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_14); 181262306a36Sopenharmony_ci appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_15); 181362306a36Sopenharmony_ci appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_17); 181462306a36Sopenharmony_ci 181562306a36Sopenharmony_ci /* configure this core for EP mode operation */ 181662306a36Sopenharmony_ci val = appl_readl(pcie, APPL_DM_TYPE); 181762306a36Sopenharmony_ci val &= ~APPL_DM_TYPE_MASK; 181862306a36Sopenharmony_ci val |= APPL_DM_TYPE_EP; 181962306a36Sopenharmony_ci appl_writel(pcie, val, APPL_DM_TYPE); 182062306a36Sopenharmony_ci 182162306a36Sopenharmony_ci appl_writel(pcie, 0x0, APPL_CFG_SLCG_OVERRIDE); 182262306a36Sopenharmony_ci 182362306a36Sopenharmony_ci val = appl_readl(pcie, APPL_CTRL); 182462306a36Sopenharmony_ci val |= APPL_CTRL_SYS_PRE_DET_STATE; 182562306a36Sopenharmony_ci val |= APPL_CTRL_HW_HOT_RST_EN; 182662306a36Sopenharmony_ci appl_writel(pcie, val, APPL_CTRL); 182762306a36Sopenharmony_ci 182862306a36Sopenharmony_ci val = appl_readl(pcie, APPL_CFG_MISC); 182962306a36Sopenharmony_ci val |= APPL_CFG_MISC_SLV_EP_MODE; 183062306a36Sopenharmony_ci val |= (APPL_CFG_MISC_ARCACHE_VAL << APPL_CFG_MISC_ARCACHE_SHIFT); 183162306a36Sopenharmony_ci appl_writel(pcie, val, APPL_CFG_MISC); 183262306a36Sopenharmony_ci 183362306a36Sopenharmony_ci val = appl_readl(pcie, APPL_PINMUX); 183462306a36Sopenharmony_ci val |= APPL_PINMUX_CLK_OUTPUT_IN_OVERRIDE_EN; 183562306a36Sopenharmony_ci val |= APPL_PINMUX_CLK_OUTPUT_IN_OVERRIDE; 183662306a36Sopenharmony_ci appl_writel(pcie, val, APPL_PINMUX); 183762306a36Sopenharmony_ci 183862306a36Sopenharmony_ci appl_writel(pcie, pcie->dbi_res->start & APPL_CFG_BASE_ADDR_MASK, 183962306a36Sopenharmony_ci APPL_CFG_BASE_ADDR); 184062306a36Sopenharmony_ci 184162306a36Sopenharmony_ci appl_writel(pcie, pcie->atu_dma_res->start & 184262306a36Sopenharmony_ci APPL_CFG_IATU_DMA_BASE_ADDR_MASK, 184362306a36Sopenharmony_ci APPL_CFG_IATU_DMA_BASE_ADDR); 184462306a36Sopenharmony_ci 184562306a36Sopenharmony_ci val = appl_readl(pcie, APPL_INTR_EN_L0_0); 184662306a36Sopenharmony_ci val |= APPL_INTR_EN_L0_0_SYS_INTR_EN; 184762306a36Sopenharmony_ci val |= APPL_INTR_EN_L0_0_LINK_STATE_INT_EN; 184862306a36Sopenharmony_ci val |= APPL_INTR_EN_L0_0_PCI_CMD_EN_INT_EN; 184962306a36Sopenharmony_ci appl_writel(pcie, val, APPL_INTR_EN_L0_0); 185062306a36Sopenharmony_ci 185162306a36Sopenharmony_ci val = appl_readl(pcie, APPL_INTR_EN_L1_0_0); 185262306a36Sopenharmony_ci val |= APPL_INTR_EN_L1_0_0_HOT_RESET_DONE_INT_EN; 185362306a36Sopenharmony_ci val |= APPL_INTR_EN_L1_0_0_RDLH_LINK_UP_INT_EN; 185462306a36Sopenharmony_ci appl_writel(pcie, val, APPL_INTR_EN_L1_0_0); 185562306a36Sopenharmony_ci 185662306a36Sopenharmony_ci reset_control_deassert(pcie->core_rst); 185762306a36Sopenharmony_ci 185862306a36Sopenharmony_ci if (pcie->update_fc_fixup) { 185962306a36Sopenharmony_ci val = dw_pcie_readl_dbi(pci, CFG_TIMER_CTRL_MAX_FUNC_NUM_OFF); 186062306a36Sopenharmony_ci val |= 0x1 << CFG_TIMER_CTRL_ACK_NAK_SHIFT; 186162306a36Sopenharmony_ci dw_pcie_writel_dbi(pci, CFG_TIMER_CTRL_MAX_FUNC_NUM_OFF, val); 186262306a36Sopenharmony_ci } 186362306a36Sopenharmony_ci 186462306a36Sopenharmony_ci config_gen3_gen4_eq_presets(pcie); 186562306a36Sopenharmony_ci 186662306a36Sopenharmony_ci init_host_aspm(pcie); 186762306a36Sopenharmony_ci 186862306a36Sopenharmony_ci /* Disable ASPM-L1SS advertisement if there is no CLKREQ routing */ 186962306a36Sopenharmony_ci if (!pcie->supports_clkreq) { 187062306a36Sopenharmony_ci disable_aspm_l11(pcie); 187162306a36Sopenharmony_ci disable_aspm_l12(pcie); 187262306a36Sopenharmony_ci } 187362306a36Sopenharmony_ci 187462306a36Sopenharmony_ci if (!pcie->of_data->has_l1ss_exit_fix) { 187562306a36Sopenharmony_ci val = dw_pcie_readl_dbi(pci, GEN3_RELATED_OFF); 187662306a36Sopenharmony_ci val &= ~GEN3_RELATED_OFF_GEN3_ZRXDC_NONCOMPL; 187762306a36Sopenharmony_ci dw_pcie_writel_dbi(pci, GEN3_RELATED_OFF, val); 187862306a36Sopenharmony_ci } 187962306a36Sopenharmony_ci 188062306a36Sopenharmony_ci pcie->pcie_cap_base = dw_pcie_find_capability(&pcie->pci, 188162306a36Sopenharmony_ci PCI_CAP_ID_EXP); 188262306a36Sopenharmony_ci 188362306a36Sopenharmony_ci /* Clear Slot Clock Configuration bit if SRNS configuration */ 188462306a36Sopenharmony_ci if (pcie->enable_srns) { 188562306a36Sopenharmony_ci val_16 = dw_pcie_readw_dbi(pci, pcie->pcie_cap_base + 188662306a36Sopenharmony_ci PCI_EXP_LNKSTA); 188762306a36Sopenharmony_ci val_16 &= ~PCI_EXP_LNKSTA_SLC; 188862306a36Sopenharmony_ci dw_pcie_writew_dbi(pci, pcie->pcie_cap_base + PCI_EXP_LNKSTA, 188962306a36Sopenharmony_ci val_16); 189062306a36Sopenharmony_ci } 189162306a36Sopenharmony_ci 189262306a36Sopenharmony_ci clk_set_rate(pcie->core_clk, GEN4_CORE_CLK_FREQ); 189362306a36Sopenharmony_ci 189462306a36Sopenharmony_ci val = (ep->msi_mem_phys & MSIX_ADDR_MATCH_LOW_OFF_MASK); 189562306a36Sopenharmony_ci val |= MSIX_ADDR_MATCH_LOW_OFF_EN; 189662306a36Sopenharmony_ci dw_pcie_writel_dbi(pci, MSIX_ADDR_MATCH_LOW_OFF, val); 189762306a36Sopenharmony_ci val = (upper_32_bits(ep->msi_mem_phys) & MSIX_ADDR_MATCH_HIGH_OFF_MASK); 189862306a36Sopenharmony_ci dw_pcie_writel_dbi(pci, MSIX_ADDR_MATCH_HIGH_OFF, val); 189962306a36Sopenharmony_ci 190062306a36Sopenharmony_ci ret = dw_pcie_ep_init_complete(ep); 190162306a36Sopenharmony_ci if (ret) { 190262306a36Sopenharmony_ci dev_err(dev, "Failed to complete initialization: %d\n", ret); 190362306a36Sopenharmony_ci goto fail_init_complete; 190462306a36Sopenharmony_ci } 190562306a36Sopenharmony_ci 190662306a36Sopenharmony_ci dw_pcie_ep_init_notify(ep); 190762306a36Sopenharmony_ci 190862306a36Sopenharmony_ci /* Program the private control to allow sending LTR upstream */ 190962306a36Sopenharmony_ci if (pcie->of_data->has_ltr_req_fix) { 191062306a36Sopenharmony_ci val = appl_readl(pcie, APPL_LTR_MSG_2); 191162306a36Sopenharmony_ci val |= APPL_LTR_MSG_2_LTR_MSG_REQ_STATE; 191262306a36Sopenharmony_ci appl_writel(pcie, val, APPL_LTR_MSG_2); 191362306a36Sopenharmony_ci } 191462306a36Sopenharmony_ci 191562306a36Sopenharmony_ci /* Enable LTSSM */ 191662306a36Sopenharmony_ci val = appl_readl(pcie, APPL_CTRL); 191762306a36Sopenharmony_ci val |= APPL_CTRL_LTSSM_EN; 191862306a36Sopenharmony_ci appl_writel(pcie, val, APPL_CTRL); 191962306a36Sopenharmony_ci 192062306a36Sopenharmony_ci pcie->ep_state = EP_STATE_ENABLED; 192162306a36Sopenharmony_ci dev_dbg(dev, "Initialization of endpoint is completed\n"); 192262306a36Sopenharmony_ci 192362306a36Sopenharmony_ci return; 192462306a36Sopenharmony_ci 192562306a36Sopenharmony_cifail_init_complete: 192662306a36Sopenharmony_ci reset_control_assert(pcie->core_rst); 192762306a36Sopenharmony_ci tegra_pcie_disable_phy(pcie); 192862306a36Sopenharmony_cifail_phy: 192962306a36Sopenharmony_ci reset_control_assert(pcie->core_apb_rst); 193062306a36Sopenharmony_cifail_core_apb_rst: 193162306a36Sopenharmony_ci clk_disable_unprepare(pcie->core_clk); 193262306a36Sopenharmony_cifail_core_clk_enable: 193362306a36Sopenharmony_ci tegra_pcie_bpmp_set_pll_state(pcie, false); 193462306a36Sopenharmony_cifail_pll_init: 193562306a36Sopenharmony_ci tegra_pcie_bpmp_set_ctrl_state(pcie, false); 193662306a36Sopenharmony_cifail_set_ctrl_state: 193762306a36Sopenharmony_ci pm_runtime_put_sync(dev); 193862306a36Sopenharmony_ci} 193962306a36Sopenharmony_ci 194062306a36Sopenharmony_cistatic irqreturn_t tegra_pcie_ep_pex_rst_irq(int irq, void *arg) 194162306a36Sopenharmony_ci{ 194262306a36Sopenharmony_ci struct tegra_pcie_dw *pcie = arg; 194362306a36Sopenharmony_ci 194462306a36Sopenharmony_ci if (gpiod_get_value(pcie->pex_rst_gpiod)) 194562306a36Sopenharmony_ci pex_ep_event_pex_rst_assert(pcie); 194662306a36Sopenharmony_ci else 194762306a36Sopenharmony_ci pex_ep_event_pex_rst_deassert(pcie); 194862306a36Sopenharmony_ci 194962306a36Sopenharmony_ci return IRQ_HANDLED; 195062306a36Sopenharmony_ci} 195162306a36Sopenharmony_ci 195262306a36Sopenharmony_cistatic int tegra_pcie_ep_raise_legacy_irq(struct tegra_pcie_dw *pcie, u16 irq) 195362306a36Sopenharmony_ci{ 195462306a36Sopenharmony_ci /* Tegra194 supports only INTA */ 195562306a36Sopenharmony_ci if (irq > 1) 195662306a36Sopenharmony_ci return -EINVAL; 195762306a36Sopenharmony_ci 195862306a36Sopenharmony_ci appl_writel(pcie, 1, APPL_LEGACY_INTX); 195962306a36Sopenharmony_ci usleep_range(1000, 2000); 196062306a36Sopenharmony_ci appl_writel(pcie, 0, APPL_LEGACY_INTX); 196162306a36Sopenharmony_ci return 0; 196262306a36Sopenharmony_ci} 196362306a36Sopenharmony_ci 196462306a36Sopenharmony_cistatic int tegra_pcie_ep_raise_msi_irq(struct tegra_pcie_dw *pcie, u16 irq) 196562306a36Sopenharmony_ci{ 196662306a36Sopenharmony_ci if (unlikely(irq > 31)) 196762306a36Sopenharmony_ci return -EINVAL; 196862306a36Sopenharmony_ci 196962306a36Sopenharmony_ci appl_writel(pcie, BIT(irq), APPL_MSI_CTRL_1); 197062306a36Sopenharmony_ci 197162306a36Sopenharmony_ci return 0; 197262306a36Sopenharmony_ci} 197362306a36Sopenharmony_ci 197462306a36Sopenharmony_cistatic int tegra_pcie_ep_raise_msix_irq(struct tegra_pcie_dw *pcie, u16 irq) 197562306a36Sopenharmony_ci{ 197662306a36Sopenharmony_ci struct dw_pcie_ep *ep = &pcie->pci.ep; 197762306a36Sopenharmony_ci 197862306a36Sopenharmony_ci writel(irq, ep->msi_mem); 197962306a36Sopenharmony_ci 198062306a36Sopenharmony_ci return 0; 198162306a36Sopenharmony_ci} 198262306a36Sopenharmony_ci 198362306a36Sopenharmony_cistatic int tegra_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no, 198462306a36Sopenharmony_ci enum pci_epc_irq_type type, 198562306a36Sopenharmony_ci u16 interrupt_num) 198662306a36Sopenharmony_ci{ 198762306a36Sopenharmony_ci struct dw_pcie *pci = to_dw_pcie_from_ep(ep); 198862306a36Sopenharmony_ci struct tegra_pcie_dw *pcie = to_tegra_pcie(pci); 198962306a36Sopenharmony_ci 199062306a36Sopenharmony_ci switch (type) { 199162306a36Sopenharmony_ci case PCI_EPC_IRQ_LEGACY: 199262306a36Sopenharmony_ci return tegra_pcie_ep_raise_legacy_irq(pcie, interrupt_num); 199362306a36Sopenharmony_ci 199462306a36Sopenharmony_ci case PCI_EPC_IRQ_MSI: 199562306a36Sopenharmony_ci return tegra_pcie_ep_raise_msi_irq(pcie, interrupt_num); 199662306a36Sopenharmony_ci 199762306a36Sopenharmony_ci case PCI_EPC_IRQ_MSIX: 199862306a36Sopenharmony_ci return tegra_pcie_ep_raise_msix_irq(pcie, interrupt_num); 199962306a36Sopenharmony_ci 200062306a36Sopenharmony_ci default: 200162306a36Sopenharmony_ci dev_err(pci->dev, "Unknown IRQ type\n"); 200262306a36Sopenharmony_ci return -EPERM; 200362306a36Sopenharmony_ci } 200462306a36Sopenharmony_ci 200562306a36Sopenharmony_ci return 0; 200662306a36Sopenharmony_ci} 200762306a36Sopenharmony_ci 200862306a36Sopenharmony_cistatic const struct pci_epc_features tegra_pcie_epc_features = { 200962306a36Sopenharmony_ci .linkup_notifier = true, 201062306a36Sopenharmony_ci .core_init_notifier = true, 201162306a36Sopenharmony_ci .msi_capable = false, 201262306a36Sopenharmony_ci .msix_capable = false, 201362306a36Sopenharmony_ci .reserved_bar = 1 << BAR_2 | 1 << BAR_3 | 1 << BAR_4 | 1 << BAR_5, 201462306a36Sopenharmony_ci .bar_fixed_64bit = 1 << BAR_0, 201562306a36Sopenharmony_ci .bar_fixed_size[0] = SZ_1M, 201662306a36Sopenharmony_ci}; 201762306a36Sopenharmony_ci 201862306a36Sopenharmony_cistatic const struct pci_epc_features* 201962306a36Sopenharmony_citegra_pcie_ep_get_features(struct dw_pcie_ep *ep) 202062306a36Sopenharmony_ci{ 202162306a36Sopenharmony_ci return &tegra_pcie_epc_features; 202262306a36Sopenharmony_ci} 202362306a36Sopenharmony_ci 202462306a36Sopenharmony_cistatic const struct dw_pcie_ep_ops pcie_ep_ops = { 202562306a36Sopenharmony_ci .raise_irq = tegra_pcie_ep_raise_irq, 202662306a36Sopenharmony_ci .get_features = tegra_pcie_ep_get_features, 202762306a36Sopenharmony_ci}; 202862306a36Sopenharmony_ci 202962306a36Sopenharmony_cistatic int tegra_pcie_config_ep(struct tegra_pcie_dw *pcie, 203062306a36Sopenharmony_ci struct platform_device *pdev) 203162306a36Sopenharmony_ci{ 203262306a36Sopenharmony_ci struct dw_pcie *pci = &pcie->pci; 203362306a36Sopenharmony_ci struct device *dev = pcie->dev; 203462306a36Sopenharmony_ci struct dw_pcie_ep *ep; 203562306a36Sopenharmony_ci char *name; 203662306a36Sopenharmony_ci int ret; 203762306a36Sopenharmony_ci 203862306a36Sopenharmony_ci ep = &pci->ep; 203962306a36Sopenharmony_ci ep->ops = &pcie_ep_ops; 204062306a36Sopenharmony_ci 204162306a36Sopenharmony_ci ep->page_size = SZ_64K; 204262306a36Sopenharmony_ci 204362306a36Sopenharmony_ci ret = gpiod_set_debounce(pcie->pex_rst_gpiod, PERST_DEBOUNCE_TIME); 204462306a36Sopenharmony_ci if (ret < 0) { 204562306a36Sopenharmony_ci dev_err(dev, "Failed to set PERST GPIO debounce time: %d\n", 204662306a36Sopenharmony_ci ret); 204762306a36Sopenharmony_ci return ret; 204862306a36Sopenharmony_ci } 204962306a36Sopenharmony_ci 205062306a36Sopenharmony_ci ret = gpiod_to_irq(pcie->pex_rst_gpiod); 205162306a36Sopenharmony_ci if (ret < 0) { 205262306a36Sopenharmony_ci dev_err(dev, "Failed to get IRQ for PERST GPIO: %d\n", ret); 205362306a36Sopenharmony_ci return ret; 205462306a36Sopenharmony_ci } 205562306a36Sopenharmony_ci pcie->pex_rst_irq = (unsigned int)ret; 205662306a36Sopenharmony_ci 205762306a36Sopenharmony_ci name = devm_kasprintf(dev, GFP_KERNEL, "tegra_pcie_%u_pex_rst_irq", 205862306a36Sopenharmony_ci pcie->cid); 205962306a36Sopenharmony_ci if (!name) { 206062306a36Sopenharmony_ci dev_err(dev, "Failed to create PERST IRQ string\n"); 206162306a36Sopenharmony_ci return -ENOMEM; 206262306a36Sopenharmony_ci } 206362306a36Sopenharmony_ci 206462306a36Sopenharmony_ci irq_set_status_flags(pcie->pex_rst_irq, IRQ_NOAUTOEN); 206562306a36Sopenharmony_ci 206662306a36Sopenharmony_ci pcie->ep_state = EP_STATE_DISABLED; 206762306a36Sopenharmony_ci 206862306a36Sopenharmony_ci ret = devm_request_threaded_irq(dev, pcie->pex_rst_irq, NULL, 206962306a36Sopenharmony_ci tegra_pcie_ep_pex_rst_irq, 207062306a36Sopenharmony_ci IRQF_TRIGGER_RISING | 207162306a36Sopenharmony_ci IRQF_TRIGGER_FALLING | IRQF_ONESHOT, 207262306a36Sopenharmony_ci name, (void *)pcie); 207362306a36Sopenharmony_ci if (ret < 0) { 207462306a36Sopenharmony_ci dev_err(dev, "Failed to request IRQ for PERST: %d\n", ret); 207562306a36Sopenharmony_ci return ret; 207662306a36Sopenharmony_ci } 207762306a36Sopenharmony_ci 207862306a36Sopenharmony_ci pm_runtime_enable(dev); 207962306a36Sopenharmony_ci 208062306a36Sopenharmony_ci ret = dw_pcie_ep_init(ep); 208162306a36Sopenharmony_ci if (ret) { 208262306a36Sopenharmony_ci dev_err(dev, "Failed to initialize DWC Endpoint subsystem: %d\n", 208362306a36Sopenharmony_ci ret); 208462306a36Sopenharmony_ci pm_runtime_disable(dev); 208562306a36Sopenharmony_ci return ret; 208662306a36Sopenharmony_ci } 208762306a36Sopenharmony_ci 208862306a36Sopenharmony_ci return 0; 208962306a36Sopenharmony_ci} 209062306a36Sopenharmony_ci 209162306a36Sopenharmony_cistatic int tegra_pcie_dw_probe(struct platform_device *pdev) 209262306a36Sopenharmony_ci{ 209362306a36Sopenharmony_ci const struct tegra_pcie_dw_of_data *data; 209462306a36Sopenharmony_ci struct device *dev = &pdev->dev; 209562306a36Sopenharmony_ci struct resource *atu_dma_res; 209662306a36Sopenharmony_ci struct tegra_pcie_dw *pcie; 209762306a36Sopenharmony_ci struct dw_pcie_rp *pp; 209862306a36Sopenharmony_ci struct dw_pcie *pci; 209962306a36Sopenharmony_ci struct phy **phys; 210062306a36Sopenharmony_ci char *name; 210162306a36Sopenharmony_ci int ret; 210262306a36Sopenharmony_ci u32 i; 210362306a36Sopenharmony_ci 210462306a36Sopenharmony_ci data = of_device_get_match_data(dev); 210562306a36Sopenharmony_ci 210662306a36Sopenharmony_ci pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL); 210762306a36Sopenharmony_ci if (!pcie) 210862306a36Sopenharmony_ci return -ENOMEM; 210962306a36Sopenharmony_ci 211062306a36Sopenharmony_ci pci = &pcie->pci; 211162306a36Sopenharmony_ci pci->dev = &pdev->dev; 211262306a36Sopenharmony_ci pci->ops = &tegra_dw_pcie_ops; 211362306a36Sopenharmony_ci pcie->dev = &pdev->dev; 211462306a36Sopenharmony_ci pcie->of_data = (struct tegra_pcie_dw_of_data *)data; 211562306a36Sopenharmony_ci pci->n_fts[0] = pcie->of_data->n_fts[0]; 211662306a36Sopenharmony_ci pci->n_fts[1] = pcie->of_data->n_fts[1]; 211762306a36Sopenharmony_ci pp = &pci->pp; 211862306a36Sopenharmony_ci pp->num_vectors = MAX_MSI_IRQS; 211962306a36Sopenharmony_ci 212062306a36Sopenharmony_ci ret = tegra_pcie_dw_parse_dt(pcie); 212162306a36Sopenharmony_ci if (ret < 0) { 212262306a36Sopenharmony_ci const char *level = KERN_ERR; 212362306a36Sopenharmony_ci 212462306a36Sopenharmony_ci if (ret == -EPROBE_DEFER) 212562306a36Sopenharmony_ci level = KERN_DEBUG; 212662306a36Sopenharmony_ci 212762306a36Sopenharmony_ci dev_printk(level, dev, 212862306a36Sopenharmony_ci dev_fmt("Failed to parse device tree: %d\n"), 212962306a36Sopenharmony_ci ret); 213062306a36Sopenharmony_ci return ret; 213162306a36Sopenharmony_ci } 213262306a36Sopenharmony_ci 213362306a36Sopenharmony_ci ret = tegra_pcie_get_slot_regulators(pcie); 213462306a36Sopenharmony_ci if (ret < 0) { 213562306a36Sopenharmony_ci const char *level = KERN_ERR; 213662306a36Sopenharmony_ci 213762306a36Sopenharmony_ci if (ret == -EPROBE_DEFER) 213862306a36Sopenharmony_ci level = KERN_DEBUG; 213962306a36Sopenharmony_ci 214062306a36Sopenharmony_ci dev_printk(level, dev, 214162306a36Sopenharmony_ci dev_fmt("Failed to get slot regulators: %d\n"), 214262306a36Sopenharmony_ci ret); 214362306a36Sopenharmony_ci return ret; 214462306a36Sopenharmony_ci } 214562306a36Sopenharmony_ci 214662306a36Sopenharmony_ci if (pcie->pex_refclk_sel_gpiod) 214762306a36Sopenharmony_ci gpiod_set_value(pcie->pex_refclk_sel_gpiod, 1); 214862306a36Sopenharmony_ci 214962306a36Sopenharmony_ci pcie->pex_ctl_supply = devm_regulator_get(dev, "vddio-pex-ctl"); 215062306a36Sopenharmony_ci if (IS_ERR(pcie->pex_ctl_supply)) { 215162306a36Sopenharmony_ci ret = PTR_ERR(pcie->pex_ctl_supply); 215262306a36Sopenharmony_ci if (ret != -EPROBE_DEFER) 215362306a36Sopenharmony_ci dev_err(dev, "Failed to get regulator: %ld\n", 215462306a36Sopenharmony_ci PTR_ERR(pcie->pex_ctl_supply)); 215562306a36Sopenharmony_ci return ret; 215662306a36Sopenharmony_ci } 215762306a36Sopenharmony_ci 215862306a36Sopenharmony_ci pcie->core_clk = devm_clk_get(dev, "core"); 215962306a36Sopenharmony_ci if (IS_ERR(pcie->core_clk)) { 216062306a36Sopenharmony_ci dev_err(dev, "Failed to get core clock: %ld\n", 216162306a36Sopenharmony_ci PTR_ERR(pcie->core_clk)); 216262306a36Sopenharmony_ci return PTR_ERR(pcie->core_clk); 216362306a36Sopenharmony_ci } 216462306a36Sopenharmony_ci 216562306a36Sopenharmony_ci pcie->appl_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, 216662306a36Sopenharmony_ci "appl"); 216762306a36Sopenharmony_ci if (!pcie->appl_res) { 216862306a36Sopenharmony_ci dev_err(dev, "Failed to find \"appl\" region\n"); 216962306a36Sopenharmony_ci return -ENODEV; 217062306a36Sopenharmony_ci } 217162306a36Sopenharmony_ci 217262306a36Sopenharmony_ci pcie->appl_base = devm_ioremap_resource(dev, pcie->appl_res); 217362306a36Sopenharmony_ci if (IS_ERR(pcie->appl_base)) 217462306a36Sopenharmony_ci return PTR_ERR(pcie->appl_base); 217562306a36Sopenharmony_ci 217662306a36Sopenharmony_ci pcie->core_apb_rst = devm_reset_control_get(dev, "apb"); 217762306a36Sopenharmony_ci if (IS_ERR(pcie->core_apb_rst)) { 217862306a36Sopenharmony_ci dev_err(dev, "Failed to get APB reset: %ld\n", 217962306a36Sopenharmony_ci PTR_ERR(pcie->core_apb_rst)); 218062306a36Sopenharmony_ci return PTR_ERR(pcie->core_apb_rst); 218162306a36Sopenharmony_ci } 218262306a36Sopenharmony_ci 218362306a36Sopenharmony_ci phys = devm_kcalloc(dev, pcie->phy_count, sizeof(*phys), GFP_KERNEL); 218462306a36Sopenharmony_ci if (!phys) 218562306a36Sopenharmony_ci return -ENOMEM; 218662306a36Sopenharmony_ci 218762306a36Sopenharmony_ci for (i = 0; i < pcie->phy_count; i++) { 218862306a36Sopenharmony_ci name = kasprintf(GFP_KERNEL, "p2u-%u", i); 218962306a36Sopenharmony_ci if (!name) { 219062306a36Sopenharmony_ci dev_err(dev, "Failed to create P2U string\n"); 219162306a36Sopenharmony_ci return -ENOMEM; 219262306a36Sopenharmony_ci } 219362306a36Sopenharmony_ci phys[i] = devm_phy_get(dev, name); 219462306a36Sopenharmony_ci kfree(name); 219562306a36Sopenharmony_ci if (IS_ERR(phys[i])) { 219662306a36Sopenharmony_ci ret = PTR_ERR(phys[i]); 219762306a36Sopenharmony_ci if (ret != -EPROBE_DEFER) 219862306a36Sopenharmony_ci dev_err(dev, "Failed to get PHY: %d\n", ret); 219962306a36Sopenharmony_ci return ret; 220062306a36Sopenharmony_ci } 220162306a36Sopenharmony_ci } 220262306a36Sopenharmony_ci 220362306a36Sopenharmony_ci pcie->phys = phys; 220462306a36Sopenharmony_ci 220562306a36Sopenharmony_ci atu_dma_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, 220662306a36Sopenharmony_ci "atu_dma"); 220762306a36Sopenharmony_ci if (!atu_dma_res) { 220862306a36Sopenharmony_ci dev_err(dev, "Failed to find \"atu_dma\" region\n"); 220962306a36Sopenharmony_ci return -ENODEV; 221062306a36Sopenharmony_ci } 221162306a36Sopenharmony_ci pcie->atu_dma_res = atu_dma_res; 221262306a36Sopenharmony_ci 221362306a36Sopenharmony_ci pci->atu_size = resource_size(atu_dma_res); 221462306a36Sopenharmony_ci pci->atu_base = devm_ioremap_resource(dev, atu_dma_res); 221562306a36Sopenharmony_ci if (IS_ERR(pci->atu_base)) 221662306a36Sopenharmony_ci return PTR_ERR(pci->atu_base); 221762306a36Sopenharmony_ci 221862306a36Sopenharmony_ci pcie->core_rst = devm_reset_control_get(dev, "core"); 221962306a36Sopenharmony_ci if (IS_ERR(pcie->core_rst)) { 222062306a36Sopenharmony_ci dev_err(dev, "Failed to get core reset: %ld\n", 222162306a36Sopenharmony_ci PTR_ERR(pcie->core_rst)); 222262306a36Sopenharmony_ci return PTR_ERR(pcie->core_rst); 222362306a36Sopenharmony_ci } 222462306a36Sopenharmony_ci 222562306a36Sopenharmony_ci pp->irq = platform_get_irq_byname(pdev, "intr"); 222662306a36Sopenharmony_ci if (pp->irq < 0) 222762306a36Sopenharmony_ci return pp->irq; 222862306a36Sopenharmony_ci 222962306a36Sopenharmony_ci pcie->bpmp = tegra_bpmp_get(dev); 223062306a36Sopenharmony_ci if (IS_ERR(pcie->bpmp)) 223162306a36Sopenharmony_ci return PTR_ERR(pcie->bpmp); 223262306a36Sopenharmony_ci 223362306a36Sopenharmony_ci platform_set_drvdata(pdev, pcie); 223462306a36Sopenharmony_ci 223562306a36Sopenharmony_ci pcie->icc_path = devm_of_icc_get(&pdev->dev, "write"); 223662306a36Sopenharmony_ci ret = PTR_ERR_OR_ZERO(pcie->icc_path); 223762306a36Sopenharmony_ci if (ret) { 223862306a36Sopenharmony_ci tegra_bpmp_put(pcie->bpmp); 223962306a36Sopenharmony_ci dev_err_probe(&pdev->dev, ret, "failed to get write interconnect\n"); 224062306a36Sopenharmony_ci return ret; 224162306a36Sopenharmony_ci } 224262306a36Sopenharmony_ci 224362306a36Sopenharmony_ci switch (pcie->of_data->mode) { 224462306a36Sopenharmony_ci case DW_PCIE_RC_TYPE: 224562306a36Sopenharmony_ci ret = devm_request_irq(dev, pp->irq, tegra_pcie_rp_irq_handler, 224662306a36Sopenharmony_ci IRQF_SHARED, "tegra-pcie-intr", pcie); 224762306a36Sopenharmony_ci if (ret) { 224862306a36Sopenharmony_ci dev_err(dev, "Failed to request IRQ %d: %d\n", pp->irq, 224962306a36Sopenharmony_ci ret); 225062306a36Sopenharmony_ci goto fail; 225162306a36Sopenharmony_ci } 225262306a36Sopenharmony_ci 225362306a36Sopenharmony_ci ret = tegra_pcie_config_rp(pcie); 225462306a36Sopenharmony_ci if (ret && ret != -ENOMEDIUM) 225562306a36Sopenharmony_ci goto fail; 225662306a36Sopenharmony_ci else 225762306a36Sopenharmony_ci return 0; 225862306a36Sopenharmony_ci break; 225962306a36Sopenharmony_ci 226062306a36Sopenharmony_ci case DW_PCIE_EP_TYPE: 226162306a36Sopenharmony_ci ret = devm_request_threaded_irq(dev, pp->irq, 226262306a36Sopenharmony_ci tegra_pcie_ep_hard_irq, 226362306a36Sopenharmony_ci tegra_pcie_ep_irq_thread, 226462306a36Sopenharmony_ci IRQF_SHARED | IRQF_ONESHOT, 226562306a36Sopenharmony_ci "tegra-pcie-ep-intr", pcie); 226662306a36Sopenharmony_ci if (ret) { 226762306a36Sopenharmony_ci dev_err(dev, "Failed to request IRQ %d: %d\n", pp->irq, 226862306a36Sopenharmony_ci ret); 226962306a36Sopenharmony_ci goto fail; 227062306a36Sopenharmony_ci } 227162306a36Sopenharmony_ci 227262306a36Sopenharmony_ci ret = tegra_pcie_config_ep(pcie, pdev); 227362306a36Sopenharmony_ci if (ret < 0) 227462306a36Sopenharmony_ci goto fail; 227562306a36Sopenharmony_ci break; 227662306a36Sopenharmony_ci 227762306a36Sopenharmony_ci default: 227862306a36Sopenharmony_ci dev_err(dev, "Invalid PCIe device type %d\n", 227962306a36Sopenharmony_ci pcie->of_data->mode); 228062306a36Sopenharmony_ci } 228162306a36Sopenharmony_ci 228262306a36Sopenharmony_cifail: 228362306a36Sopenharmony_ci tegra_bpmp_put(pcie->bpmp); 228462306a36Sopenharmony_ci return ret; 228562306a36Sopenharmony_ci} 228662306a36Sopenharmony_ci 228762306a36Sopenharmony_cistatic void tegra_pcie_dw_remove(struct platform_device *pdev) 228862306a36Sopenharmony_ci{ 228962306a36Sopenharmony_ci struct tegra_pcie_dw *pcie = platform_get_drvdata(pdev); 229062306a36Sopenharmony_ci 229162306a36Sopenharmony_ci if (pcie->of_data->mode == DW_PCIE_RC_TYPE) { 229262306a36Sopenharmony_ci if (!pcie->link_state) 229362306a36Sopenharmony_ci return; 229462306a36Sopenharmony_ci 229562306a36Sopenharmony_ci debugfs_remove_recursive(pcie->debugfs); 229662306a36Sopenharmony_ci tegra_pcie_deinit_controller(pcie); 229762306a36Sopenharmony_ci pm_runtime_put_sync(pcie->dev); 229862306a36Sopenharmony_ci } else { 229962306a36Sopenharmony_ci disable_irq(pcie->pex_rst_irq); 230062306a36Sopenharmony_ci pex_ep_event_pex_rst_assert(pcie); 230162306a36Sopenharmony_ci } 230262306a36Sopenharmony_ci 230362306a36Sopenharmony_ci pm_runtime_disable(pcie->dev); 230462306a36Sopenharmony_ci tegra_bpmp_put(pcie->bpmp); 230562306a36Sopenharmony_ci if (pcie->pex_refclk_sel_gpiod) 230662306a36Sopenharmony_ci gpiod_set_value(pcie->pex_refclk_sel_gpiod, 0); 230762306a36Sopenharmony_ci} 230862306a36Sopenharmony_ci 230962306a36Sopenharmony_cistatic int tegra_pcie_dw_suspend_late(struct device *dev) 231062306a36Sopenharmony_ci{ 231162306a36Sopenharmony_ci struct tegra_pcie_dw *pcie = dev_get_drvdata(dev); 231262306a36Sopenharmony_ci u32 val; 231362306a36Sopenharmony_ci 231462306a36Sopenharmony_ci if (pcie->of_data->mode == DW_PCIE_EP_TYPE) { 231562306a36Sopenharmony_ci dev_err(dev, "Failed to Suspend as Tegra PCIe is in EP mode\n"); 231662306a36Sopenharmony_ci return -EPERM; 231762306a36Sopenharmony_ci } 231862306a36Sopenharmony_ci 231962306a36Sopenharmony_ci if (!pcie->link_state) 232062306a36Sopenharmony_ci return 0; 232162306a36Sopenharmony_ci 232262306a36Sopenharmony_ci /* Enable HW_HOT_RST mode */ 232362306a36Sopenharmony_ci if (!pcie->of_data->has_sbr_reset_fix) { 232462306a36Sopenharmony_ci val = appl_readl(pcie, APPL_CTRL); 232562306a36Sopenharmony_ci val &= ~(APPL_CTRL_HW_HOT_RST_MODE_MASK << 232662306a36Sopenharmony_ci APPL_CTRL_HW_HOT_RST_MODE_SHIFT); 232762306a36Sopenharmony_ci val |= APPL_CTRL_HW_HOT_RST_EN; 232862306a36Sopenharmony_ci appl_writel(pcie, val, APPL_CTRL); 232962306a36Sopenharmony_ci } 233062306a36Sopenharmony_ci 233162306a36Sopenharmony_ci return 0; 233262306a36Sopenharmony_ci} 233362306a36Sopenharmony_ci 233462306a36Sopenharmony_cistatic int tegra_pcie_dw_suspend_noirq(struct device *dev) 233562306a36Sopenharmony_ci{ 233662306a36Sopenharmony_ci struct tegra_pcie_dw *pcie = dev_get_drvdata(dev); 233762306a36Sopenharmony_ci 233862306a36Sopenharmony_ci if (!pcie->link_state) 233962306a36Sopenharmony_ci return 0; 234062306a36Sopenharmony_ci 234162306a36Sopenharmony_ci tegra_pcie_downstream_dev_to_D0(pcie); 234262306a36Sopenharmony_ci tegra_pcie_dw_pme_turnoff(pcie); 234362306a36Sopenharmony_ci tegra_pcie_unconfig_controller(pcie); 234462306a36Sopenharmony_ci 234562306a36Sopenharmony_ci return 0; 234662306a36Sopenharmony_ci} 234762306a36Sopenharmony_ci 234862306a36Sopenharmony_cistatic int tegra_pcie_dw_resume_noirq(struct device *dev) 234962306a36Sopenharmony_ci{ 235062306a36Sopenharmony_ci struct tegra_pcie_dw *pcie = dev_get_drvdata(dev); 235162306a36Sopenharmony_ci int ret; 235262306a36Sopenharmony_ci 235362306a36Sopenharmony_ci if (!pcie->link_state) 235462306a36Sopenharmony_ci return 0; 235562306a36Sopenharmony_ci 235662306a36Sopenharmony_ci ret = tegra_pcie_config_controller(pcie, true); 235762306a36Sopenharmony_ci if (ret < 0) 235862306a36Sopenharmony_ci return ret; 235962306a36Sopenharmony_ci 236062306a36Sopenharmony_ci ret = tegra_pcie_dw_host_init(&pcie->pci.pp); 236162306a36Sopenharmony_ci if (ret < 0) { 236262306a36Sopenharmony_ci dev_err(dev, "Failed to init host: %d\n", ret); 236362306a36Sopenharmony_ci goto fail_host_init; 236462306a36Sopenharmony_ci } 236562306a36Sopenharmony_ci 236662306a36Sopenharmony_ci dw_pcie_setup_rc(&pcie->pci.pp); 236762306a36Sopenharmony_ci 236862306a36Sopenharmony_ci ret = tegra_pcie_dw_start_link(&pcie->pci); 236962306a36Sopenharmony_ci if (ret < 0) 237062306a36Sopenharmony_ci goto fail_host_init; 237162306a36Sopenharmony_ci 237262306a36Sopenharmony_ci return 0; 237362306a36Sopenharmony_ci 237462306a36Sopenharmony_cifail_host_init: 237562306a36Sopenharmony_ci tegra_pcie_unconfig_controller(pcie); 237662306a36Sopenharmony_ci return ret; 237762306a36Sopenharmony_ci} 237862306a36Sopenharmony_ci 237962306a36Sopenharmony_cistatic int tegra_pcie_dw_resume_early(struct device *dev) 238062306a36Sopenharmony_ci{ 238162306a36Sopenharmony_ci struct tegra_pcie_dw *pcie = dev_get_drvdata(dev); 238262306a36Sopenharmony_ci u32 val; 238362306a36Sopenharmony_ci 238462306a36Sopenharmony_ci if (pcie->of_data->mode == DW_PCIE_EP_TYPE) { 238562306a36Sopenharmony_ci dev_err(dev, "Suspend is not supported in EP mode"); 238662306a36Sopenharmony_ci return -ENOTSUPP; 238762306a36Sopenharmony_ci } 238862306a36Sopenharmony_ci 238962306a36Sopenharmony_ci if (!pcie->link_state) 239062306a36Sopenharmony_ci return 0; 239162306a36Sopenharmony_ci 239262306a36Sopenharmony_ci /* Disable HW_HOT_RST mode */ 239362306a36Sopenharmony_ci if (!pcie->of_data->has_sbr_reset_fix) { 239462306a36Sopenharmony_ci val = appl_readl(pcie, APPL_CTRL); 239562306a36Sopenharmony_ci val &= ~(APPL_CTRL_HW_HOT_RST_MODE_MASK << 239662306a36Sopenharmony_ci APPL_CTRL_HW_HOT_RST_MODE_SHIFT); 239762306a36Sopenharmony_ci val |= APPL_CTRL_HW_HOT_RST_MODE_IMDT_RST << 239862306a36Sopenharmony_ci APPL_CTRL_HW_HOT_RST_MODE_SHIFT; 239962306a36Sopenharmony_ci val &= ~APPL_CTRL_HW_HOT_RST_EN; 240062306a36Sopenharmony_ci appl_writel(pcie, val, APPL_CTRL); 240162306a36Sopenharmony_ci } 240262306a36Sopenharmony_ci 240362306a36Sopenharmony_ci return 0; 240462306a36Sopenharmony_ci} 240562306a36Sopenharmony_ci 240662306a36Sopenharmony_cistatic void tegra_pcie_dw_shutdown(struct platform_device *pdev) 240762306a36Sopenharmony_ci{ 240862306a36Sopenharmony_ci struct tegra_pcie_dw *pcie = platform_get_drvdata(pdev); 240962306a36Sopenharmony_ci 241062306a36Sopenharmony_ci if (pcie->of_data->mode == DW_PCIE_RC_TYPE) { 241162306a36Sopenharmony_ci if (!pcie->link_state) 241262306a36Sopenharmony_ci return; 241362306a36Sopenharmony_ci 241462306a36Sopenharmony_ci debugfs_remove_recursive(pcie->debugfs); 241562306a36Sopenharmony_ci tegra_pcie_downstream_dev_to_D0(pcie); 241662306a36Sopenharmony_ci 241762306a36Sopenharmony_ci disable_irq(pcie->pci.pp.irq); 241862306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_PCI_MSI)) 241962306a36Sopenharmony_ci disable_irq(pcie->pci.pp.msi_irq[0]); 242062306a36Sopenharmony_ci 242162306a36Sopenharmony_ci tegra_pcie_dw_pme_turnoff(pcie); 242262306a36Sopenharmony_ci tegra_pcie_unconfig_controller(pcie); 242362306a36Sopenharmony_ci pm_runtime_put_sync(pcie->dev); 242462306a36Sopenharmony_ci } else { 242562306a36Sopenharmony_ci disable_irq(pcie->pex_rst_irq); 242662306a36Sopenharmony_ci pex_ep_event_pex_rst_assert(pcie); 242762306a36Sopenharmony_ci } 242862306a36Sopenharmony_ci} 242962306a36Sopenharmony_ci 243062306a36Sopenharmony_cistatic const struct tegra_pcie_dw_of_data tegra194_pcie_dw_rc_of_data = { 243162306a36Sopenharmony_ci .version = TEGRA194_DWC_IP_VER, 243262306a36Sopenharmony_ci .mode = DW_PCIE_RC_TYPE, 243362306a36Sopenharmony_ci .cdm_chk_int_en_bit = BIT(19), 243462306a36Sopenharmony_ci /* Gen4 - 5, 6, 8 and 9 presets enabled */ 243562306a36Sopenharmony_ci .gen4_preset_vec = 0x360, 243662306a36Sopenharmony_ci .n_fts = { 52, 52 }, 243762306a36Sopenharmony_ci}; 243862306a36Sopenharmony_ci 243962306a36Sopenharmony_cistatic const struct tegra_pcie_dw_of_data tegra194_pcie_dw_ep_of_data = { 244062306a36Sopenharmony_ci .version = TEGRA194_DWC_IP_VER, 244162306a36Sopenharmony_ci .mode = DW_PCIE_EP_TYPE, 244262306a36Sopenharmony_ci .cdm_chk_int_en_bit = BIT(19), 244362306a36Sopenharmony_ci /* Gen4 - 5, 6, 8 and 9 presets enabled */ 244462306a36Sopenharmony_ci .gen4_preset_vec = 0x360, 244562306a36Sopenharmony_ci .n_fts = { 52, 52 }, 244662306a36Sopenharmony_ci}; 244762306a36Sopenharmony_ci 244862306a36Sopenharmony_cistatic const struct tegra_pcie_dw_of_data tegra234_pcie_dw_rc_of_data = { 244962306a36Sopenharmony_ci .version = TEGRA234_DWC_IP_VER, 245062306a36Sopenharmony_ci .mode = DW_PCIE_RC_TYPE, 245162306a36Sopenharmony_ci .has_msix_doorbell_access_fix = true, 245262306a36Sopenharmony_ci .has_sbr_reset_fix = true, 245362306a36Sopenharmony_ci .has_l1ss_exit_fix = true, 245462306a36Sopenharmony_ci .cdm_chk_int_en_bit = BIT(18), 245562306a36Sopenharmony_ci /* Gen4 - 6, 8 and 9 presets enabled */ 245662306a36Sopenharmony_ci .gen4_preset_vec = 0x340, 245762306a36Sopenharmony_ci .n_fts = { 52, 80 }, 245862306a36Sopenharmony_ci}; 245962306a36Sopenharmony_ci 246062306a36Sopenharmony_cistatic const struct tegra_pcie_dw_of_data tegra234_pcie_dw_ep_of_data = { 246162306a36Sopenharmony_ci .version = TEGRA234_DWC_IP_VER, 246262306a36Sopenharmony_ci .mode = DW_PCIE_EP_TYPE, 246362306a36Sopenharmony_ci .has_l1ss_exit_fix = true, 246462306a36Sopenharmony_ci .has_ltr_req_fix = true, 246562306a36Sopenharmony_ci .cdm_chk_int_en_bit = BIT(18), 246662306a36Sopenharmony_ci /* Gen4 - 6, 8 and 9 presets enabled */ 246762306a36Sopenharmony_ci .gen4_preset_vec = 0x340, 246862306a36Sopenharmony_ci .n_fts = { 52, 80 }, 246962306a36Sopenharmony_ci}; 247062306a36Sopenharmony_ci 247162306a36Sopenharmony_cistatic const struct of_device_id tegra_pcie_dw_of_match[] = { 247262306a36Sopenharmony_ci { 247362306a36Sopenharmony_ci .compatible = "nvidia,tegra194-pcie", 247462306a36Sopenharmony_ci .data = &tegra194_pcie_dw_rc_of_data, 247562306a36Sopenharmony_ci }, 247662306a36Sopenharmony_ci { 247762306a36Sopenharmony_ci .compatible = "nvidia,tegra194-pcie-ep", 247862306a36Sopenharmony_ci .data = &tegra194_pcie_dw_ep_of_data, 247962306a36Sopenharmony_ci }, 248062306a36Sopenharmony_ci { 248162306a36Sopenharmony_ci .compatible = "nvidia,tegra234-pcie", 248262306a36Sopenharmony_ci .data = &tegra234_pcie_dw_rc_of_data, 248362306a36Sopenharmony_ci }, 248462306a36Sopenharmony_ci { 248562306a36Sopenharmony_ci .compatible = "nvidia,tegra234-pcie-ep", 248662306a36Sopenharmony_ci .data = &tegra234_pcie_dw_ep_of_data, 248762306a36Sopenharmony_ci }, 248862306a36Sopenharmony_ci {} 248962306a36Sopenharmony_ci}; 249062306a36Sopenharmony_ci 249162306a36Sopenharmony_cistatic const struct dev_pm_ops tegra_pcie_dw_pm_ops = { 249262306a36Sopenharmony_ci .suspend_late = tegra_pcie_dw_suspend_late, 249362306a36Sopenharmony_ci .suspend_noirq = tegra_pcie_dw_suspend_noirq, 249462306a36Sopenharmony_ci .resume_noirq = tegra_pcie_dw_resume_noirq, 249562306a36Sopenharmony_ci .resume_early = tegra_pcie_dw_resume_early, 249662306a36Sopenharmony_ci}; 249762306a36Sopenharmony_ci 249862306a36Sopenharmony_cistatic struct platform_driver tegra_pcie_dw_driver = { 249962306a36Sopenharmony_ci .probe = tegra_pcie_dw_probe, 250062306a36Sopenharmony_ci .remove_new = tegra_pcie_dw_remove, 250162306a36Sopenharmony_ci .shutdown = tegra_pcie_dw_shutdown, 250262306a36Sopenharmony_ci .driver = { 250362306a36Sopenharmony_ci .name = "tegra194-pcie", 250462306a36Sopenharmony_ci .pm = &tegra_pcie_dw_pm_ops, 250562306a36Sopenharmony_ci .of_match_table = tegra_pcie_dw_of_match, 250662306a36Sopenharmony_ci }, 250762306a36Sopenharmony_ci}; 250862306a36Sopenharmony_cimodule_platform_driver(tegra_pcie_dw_driver); 250962306a36Sopenharmony_ci 251062306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, tegra_pcie_dw_of_match); 251162306a36Sopenharmony_ci 251262306a36Sopenharmony_ciMODULE_AUTHOR("Vidya Sagar <vidyas@nvidia.com>"); 251362306a36Sopenharmony_ciMODULE_DESCRIPTION("NVIDIA PCIe host controller driver"); 251462306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 2515