summaryrefslogtreecommitdiff
path: root/drivers/platform
diff options
context:
space:
mode:
authorYan He <yanhe@codeaurora.org>2015-01-07 22:46:13 -0800
committerDavid Keitel <dkeitel@codeaurora.org>2016-03-22 11:16:04 -0700
commit5dbc08812b982db7258930cb7bb2e7fc7596f150 (patch)
tree315dd876f9206c7f90be0f584062b23be1882dd1 /drivers/platform
parent3b1bda734da2c83541f49252612965673c427577 (diff)
msm: ep_pcie: add PCIe endpoint driver
The MSM PCIe endpoint driver enables the PCIe core in endpoint mode and handles the control signaling with PCIe root complex on host side. Change-Id: Ifc2735e061820762c6040eda44089a2dc26fc065 Signed-off-by: Yan He <yanhe@codeaurora.org>
Diffstat (limited to 'drivers/platform')
-rw-r--r--drivers/platform/msm/Kconfig21
-rw-r--r--drivers/platform/msm/Makefile1
-rw-r--r--drivers/platform/msm/ep_pcie/Makefile3
-rw-r--r--drivers/platform/msm/ep_pcie/ep_pcie.c232
-rw-r--r--drivers/platform/msm/ep_pcie/ep_pcie_com.h332
-rw-r--r--drivers/platform/msm/ep_pcie/ep_pcie_core.c1924
-rw-r--r--drivers/platform/msm/ep_pcie/ep_pcie_dbg.c466
-rw-r--r--drivers/platform/msm/ep_pcie/ep_pcie_phy.c81
-rw-r--r--drivers/platform/msm/ep_pcie/ep_pcie_phy.h351
9 files changed, 3411 insertions, 0 deletions
diff --git a/drivers/platform/msm/Kconfig b/drivers/platform/msm/Kconfig
index fb795960580c..0daa88715111 100644
--- a/drivers/platform/msm/Kconfig
+++ b/drivers/platform/msm/Kconfig
@@ -48,6 +48,27 @@ config SPS_SUPPORT_NDP_BAM
help
No-Data-Path BAM is used to improve BAM performance.
+config EP_PCIE
+ bool "PCIe Endpoint mode support"
+ select GENERIC_ALLOCATOR
+ help
+ PCIe controller is in endpoint mode.
+ It supports the APIs to clients as a service layer, and allows
+ clients to enable/disable PCIe link, configure the address
+ mapping for the access to host memory, trigger wake interrupt
+ on host side to wake up host, and trigger MSI to host side.
+
+config EP_PCIE_HW
+ bool "PCIe Endpoint HW driver"
+ depends on EP_PCIE
+ help
+ PCIe endpoint HW specific implementation.
+ It supports:
+ 1. link training with Root Complex.
+ 2. Address mapping.
+ 3. Sideband signaling.
+ 4. Power management.
+
config GPIO_USB_DETECT
tristate "GPIO-based USB VBUS Detection"
depends on POWER_SUPPLY
diff --git a/drivers/platform/msm/Makefile b/drivers/platform/msm/Makefile
index 879b425c43f6..ef84024ab474 100644
--- a/drivers/platform/msm/Makefile
+++ b/drivers/platform/msm/Makefile
@@ -4,4 +4,5 @@
obj-$(CONFIG_QPNP_REVID) += qpnp-revid.o
obj-$(CONFIG_QPNP_COINCELL) += qpnp-coincell.o
obj-$(CONFIG_SPS) += sps/
+obj-$(CONFIG_EP_PCIE) += ep_pcie/
obj-$(CONFIG_GPIO_USB_DETECT) += gpio-usbdetect.o
diff --git a/drivers/platform/msm/ep_pcie/Makefile b/drivers/platform/msm/ep_pcie/Makefile
new file mode 100644
index 000000000000..fcacad7bc375
--- /dev/null
+++ b/drivers/platform/msm/ep_pcie/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_EP_PCIE) += ep_pcie.o
+obj-$(CONFIG_EP_PCIE_HW) += ep_pcie_core.o ep_pcie_phy.o ep_pcie_dbg.o
+
diff --git a/drivers/platform/msm/ep_pcie/ep_pcie.c b/drivers/platform/msm/ep_pcie/ep_pcie.c
new file mode 100644
index 000000000000..59d9771ebdc7
--- /dev/null
+++ b/drivers/platform/msm/ep_pcie/ep_pcie.c
@@ -0,0 +1,232 @@
+/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * MSM PCIe endpoint service layer.
+ */
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/compiler.h>
+#include <linux/kernel.h>
+#include <linux/bitops.h>
+#include <linux/errno.h>
+#include <linux/msm_ep_pcie.h>
+
+LIST_HEAD(head);
+
+int ep_pcie_register_drv(struct ep_pcie_hw *handle)
+{
+ struct ep_pcie_hw *present;
+ bool new = true;
+
+ if (!handle) {
+ pr_err("ep_pcie:%s: the input handle is NULL.",
+ __func__);
+ return -EINVAL;
+ }
+
+ list_for_each_entry(present, &head, node) {
+ if (present->device_id == handle->device_id) {
+ new = false;
+ break;
+ }
+ }
+
+ if (new) {
+ list_add(&handle->node, &head);
+ pr_debug("ep_pcie:%s: register a new driver for device 0x%x.",
+ __func__, handle->device_id);
+ return 0;
+ } else {
+ pr_debug(
+ "ep_pcie:%s: driver to register for device 0x%x has already existed.",
+ __func__, handle->device_id);
+ return -EEXIST;
+ }
+}
+EXPORT_SYMBOL(ep_pcie_register_drv);
+
+int ep_pcie_deregister_drv(struct ep_pcie_hw *handle)
+{
+ struct ep_pcie_hw *present;
+ bool found = false;
+
+ if (!handle) {
+ pr_err("ep_pcie:%s: the input handle is NULL.",
+ __func__);
+ return -EINVAL;
+ }
+
+ list_for_each_entry(present, &head, node) {
+ if (present->device_id == handle->device_id) {
+ found = true;
+ list_del(&handle->node);
+ break;
+ }
+ }
+
+ if (found) {
+ pr_debug("ep_pcie:%s: deregistered driver for device 0x%x.",
+ __func__, handle->device_id);
+ return 0;
+ } else {
+ pr_err("ep_pcie:%s: driver for device 0x%x does not exist.",
+ __func__, handle->device_id);
+ return -EEXIST;
+ }
+}
+EXPORT_SYMBOL(ep_pcie_deregister_drv);
+
+struct ep_pcie_hw *ep_pcie_get_phandle(u32 id)
+{
+ struct ep_pcie_hw *present;
+
+ list_for_each_entry(present, &head, node) {
+ if (present->device_id == id) {
+ pr_debug("ep_pcie:%s: found driver for device 0x%x.",
+ __func__, id);
+ return present;
+ }
+ }
+
+ pr_debug("ep_pcie:%s: driver for device 0x%x does not exist.",
+ __func__, id);
+ return NULL;
+}
+EXPORT_SYMBOL(ep_pcie_get_phandle);
+
+int ep_pcie_register_event(struct ep_pcie_hw *phandle,
+ struct ep_pcie_register_event *reg)
+{
+ if (phandle) {
+ return phandle->register_event(reg);
+ } else {
+ pr_err("ep_pcie:%s: the input driver handle is NULL.",
+ __func__);
+ return -EINVAL;
+ }
+}
+EXPORT_SYMBOL(ep_pcie_register_event);
+
+int ep_pcie_deregister_event(struct ep_pcie_hw *phandle)
+{
+ if (phandle) {
+ return phandle->deregister_event();
+ } else {
+ pr_err("ep_pcie:%s: the input driver handle is NULL.",
+ __func__);
+ return -EINVAL;
+ }
+}
+EXPORT_SYMBOL(ep_pcie_deregister_event);
+
+enum ep_pcie_link_status ep_pcie_get_linkstatus(struct ep_pcie_hw *phandle)
+{
+ if (phandle) {
+ return phandle->get_linkstatus();
+ } else {
+ pr_err("ep_pcie:%s: the input driver handle is NULL.",
+ __func__);
+ return -EINVAL;
+ }
+}
+EXPORT_SYMBOL(ep_pcie_get_linkstatus);
+
+int ep_pcie_config_outbound_iatu(struct ep_pcie_hw *phandle,
+ struct ep_pcie_iatu entries[],
+ u32 num_entries)
+{
+ if (phandle) {
+ return phandle->config_outbound_iatu(entries, num_entries);
+ } else {
+ pr_err("ep_pcie:%s: the input driver handle is NULL.",
+ __func__);
+ return -EINVAL;
+ }
+}
+EXPORT_SYMBOL(ep_pcie_config_outbound_iatu);
+
+int ep_pcie_get_msi_config(struct ep_pcie_hw *phandle,
+ struct ep_pcie_msi_config *cfg)
+{
+ if (phandle) {
+ return phandle->get_msi_config(cfg);
+ } else {
+ pr_err("ep_pcie:%s: the input driver handle is NULL.",
+ __func__);
+ return -EINVAL;
+ }
+}
+EXPORT_SYMBOL(ep_pcie_get_msi_config);
+
+int ep_pcie_trigger_msi(struct ep_pcie_hw *phandle, u32 idx)
+{
+ if (phandle) {
+ return phandle->trigger_msi(idx);
+ } else {
+ pr_err("ep_pcie:%s: the input driver handle is NULL.",
+ __func__);
+ return -EINVAL;
+ }
+}
+EXPORT_SYMBOL(ep_pcie_trigger_msi);
+
+int ep_pcie_wakeup_host(struct ep_pcie_hw *phandle)
+{
+ if (phandle) {
+ return phandle->wakeup_host();
+ } else {
+ pr_err("ep_pcie:%s: the input driver handle is NULL.",
+ __func__);
+ return -EINVAL;
+ }
+}
+EXPORT_SYMBOL(ep_pcie_wakeup_host);
+
+int ep_pcie_config_db_routing(struct ep_pcie_hw *phandle,
+ struct ep_pcie_db_config chdb_cfg,
+ struct ep_pcie_db_config erdb_cfg)
+{
+ if (phandle) {
+ return phandle->config_db_routing(chdb_cfg, erdb_cfg);
+ } else {
+ pr_err("ep_pcie:%s: the input driver handle is NULL.",
+ __func__);
+ return -EINVAL;
+ }
+}
+EXPORT_SYMBOL(ep_pcie_config_db_routing);
+
+int ep_pcie_enable_endpoint(struct ep_pcie_hw *phandle,
+ enum ep_pcie_options opt)
+{
+ if (phandle) {
+ return phandle->enable_endpoint(opt);
+ } else {
+ pr_err("ep_pcie:%s: the input driver handle is NULL.",
+ __func__);
+ return -EINVAL;
+ }
+}
+EXPORT_SYMBOL(ep_pcie_enable_endpoint);
+
+int ep_pcie_disable_endpoint(struct ep_pcie_hw *phandle)
+{
+ if (phandle) {
+ return phandle->disable_endpoint();
+ } else {
+ pr_err("ep_pcie:%s: the input driver handle is NULL.",
+ __func__);
+ return -EINVAL;
+ }
+}
+EXPORT_SYMBOL(ep_pcie_disable_endpoint);
diff --git a/drivers/platform/msm/ep_pcie/ep_pcie_com.h b/drivers/platform/msm/ep_pcie/ep_pcie_com.h
new file mode 100644
index 000000000000..2561f1cc959e
--- /dev/null
+++ b/drivers/platform/msm/ep_pcie/ep_pcie_com.h
@@ -0,0 +1,332 @@
+/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __EP_PCIE_COM_H
+#define __EP_PCIE_COM_H
+
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/compiler.h>
+#include <linux/ipc_logging.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/types.h>
+#include <linux/uaccess.h>
+#include <linux/msm_ep_pcie.h>
+
+#define PCIE20_PARF_SYS_CTRL 0x00
+#define PCIE20_PARF_PM_CTRL 0x20
+#define PCIE20_PARF_PM_STTS 0x24
+#define PCIE20_PARF_PHY_CTRL 0x40
+#define PCIE20_PARF_PHY_REFCLK 0x4C
+#define PCIE20_PARF_CONFIG_BITS 0x50
+#define PCIE20_PARF_TEST_BUS 0xE4
+#define PCIE20_PARF_DBI_BASE_ADDR 0x168
+#define PCIE20_PARF_SLV_ADDR_SPACE_SIZE 0x16C
+#define PCIE20_PARF_MHI_BASE_ADDR_LOWER 0x178
+#define PCIE20_PARF_MHI_BASE_ADDR_UPPER 0x17c
+#define PCIE20_PARF_DEBUG_INT_EN 0x190
+#define PCIE20_PARF_MHI_IPA_DBS 0x198
+#define PCIE20_PARF_MHI_IPA_CDB_TARGET_LOWER 0x19C
+#define PCIE20_PARF_MHI_IPA_EDB_TARGET_LOWER 0x1A0
+#define PCIE20_PARF_AXI_MSTR_RD_HALT_NO_WRITES 0x1A4
+#define PCIE20_PARF_AXI_MSTR_WR_ADDR_HALT 0x1A8
+#define PCIE20_PARF_Q2A_FLUSH 0x1AC
+#define PCIE20_PARF_DEVICE_TYPE 0x1000
+
+#define PCIE20_ELBI_VERSION 0x00
+#define PCIE20_ELBI_SYS_CTRL 0x04
+#define PCIE20_ELBI_SYS_STTS 0x08
+#define PCIE20_ELBI_CS2_ENABLE 0xA4
+
+#define PCIE20_DEVICE_ID_VENDOR_ID 0x00
+#define PCIE20_COMMAND_STATUS 0x04
+#define PCIE20_CLASS_CODE_REVISION_ID 0x08
+#define PCIE20_BIST_HDR_TYPE 0x0C
+#define PCIE20_BAR0 0x10
+#define PCIE20_CAP_ID_NXT_PTR 0x40
+#define PCIE20_CON_STATUS 0x44
+#define PCIE20_MSI_CAP_ID_NEXT_CTRL 0x50
+#define PCIE20_MSI_LOWER 0x54
+#define PCIE20_MSI_UPPER 0x58
+#define PCIE20_MSI_DATA 0x5C
+#define PCIE20_DEVICE_CAPABILITIES 0x74
+#define PCIE20_MASK_EP_L1_ACCPT_LATENCY 0xE00
+#define PCIE20_MASK_EP_L0S_ACCPT_LATENCY 0x1C0
+#define PCIE20_LINK_CAPABILITIES 0x7C
+#define PCIE20_MASK_CLOCK_POWER_MAN 0x40000
+#define PCIE20_MASK_L1_EXIT_LATENCY 0x38000
+#define PCIE20_MASK_L0S_EXIT_LATENCY 0x7000
+#define PCIE20_CAP_LINKCTRLSTATUS 0x80
+#define PCIE20_DEVICE_CONTROL2_STATUS2 0x98
+#define PCIE20_LINK_CONTROL2_LINK_STATUS2 0xA0
+#define PCIE20_L1SUB_CAPABILITY 0x154
+#define PCIE20_L1SUB_CONTROL1 0x158
+#define PCIE20_ACK_F_ASPM_CTRL_REG 0x70C
+#define PCIE20_MASK_ACK_N_FTS 0xff00
+#define PCIE20_MISC_CONTROL_1 0x8BC
+
+#define PCIE20_PLR_IATU_VIEWPORT 0x900
+#define PCIE20_PLR_IATU_CTRL1 0x904
+#define PCIE20_PLR_IATU_CTRL2 0x908
+#define PCIE20_PLR_IATU_LBAR 0x90C
+#define PCIE20_PLR_IATU_UBAR 0x910
+#define PCIE20_PLR_IATU_LAR 0x914
+#define PCIE20_PLR_IATU_LTAR 0x918
+#define PCIE20_PLR_IATU_UTAR 0x91c
+
+#define PERST_TIMEOUT_US_MIN 5000
+#define PERST_TIMEOUT_US_MAX 5100
+#define PERST_CHECK_MAX_COUNT 2000
+#define LINK_UP_TIMEOUT_US_MIN 5000
+#define LINK_UP_TIMEOUT_US_MAX 5100
+#define LINK_UP_CHECK_MAX_COUNT 2000
+#define BME_TIMEOUT_US_MIN 5000
+#define BME_TIMEOUT_US_MAX 5100
+#define BME_CHECK_MAX_COUNT 6000
+#define PHY_STABILIZATION_DELAY_US_MIN 995
+#define PHY_STABILIZATION_DELAY_US_MAX 1005
+#define REFCLK_STABILIZATION_DELAY_US_MIN 995
+#define REFCLK_STABILIZATION_DELAY_US_MAX 1005
+#define PHY_READY_TIMEOUT_COUNT 10000
+#define XMLH_LINK_UP 0x400
+
+#define MAX_PROP_SIZE 32
+#define MAX_MSG_LEN 80
+#define MAX_NAME_LEN 80
+#define MAX_IATU_ENTRY_NUM 2
+
+#define EP_PCIE_LOG_PAGES 50
+#define EP_PCIE_MAX_VREG 2
+#define EP_PCIE_MAX_CLK 5
+#define EP_PCIE_MAX_PIPE_CLK 1
+
+#define EP_PCIE_ERROR -30655
+#define EP_PCIE_LINK_DOWN 0xFFFFFFFF
+
+#define EP_PCIE_OATU_INDEX_MSI 1
+#define EP_PCIE_OATU_INDEX_CTRL 2
+#define EP_PCIE_OATU_INDEX_DATA 3
+
+#define EP_PCIE_GEN_DBG(x...) do { \
+ if (ep_pcie_get_debug_mask()) \
+ pr_alert(x); \
+ else \
+ pr_debug(x); \
+ } while (0)
+
+#define EP_PCIE_DBG(dev, fmt, arg...) do { \
+ if ((dev)->ipc_log_sel) \
+ ipc_log_string((dev)->ipc_log_sel, \
+ "DBG1:%s: " fmt, __func__, arg); \
+ if ((dev)->ipc_log_ful) \
+ ipc_log_string((dev)->ipc_log_ful, "%s: " fmt, __func__, arg); \
+ if (ep_pcie_get_debug_mask()) \
+ pr_alert("%s: " fmt, __func__, arg); \
+ } while (0)
+
+#define EP_PCIE_DBG2(dev, fmt, arg...) do { \
+ if ((dev)->ipc_log_ful) \
+ ipc_log_string((dev)->ipc_log_ful, \
+ "DBG2:%s: " fmt, __func__, arg); \
+ if (ep_pcie_get_debug_mask()) \
+ pr_alert("%s: " fmt, __func__, arg); \
+ } while (0)
+
+#define EP_PCIE_DBG_FS(fmt, arg...) pr_alert("%s: " fmt, __func__, arg)
+
+#define EP_PCIE_DUMP(dev, fmt, arg...) do { \
+ if ((dev)->ipc_log_dump) \
+ ipc_log_string((dev)->ipc_log_dump, \
+ "DUMP:%s: " fmt, __func__, arg); \
+ if (ep_pcie_get_debug_mask()) \
+ pr_alert("%s: " fmt, __func__, arg); \
+ } while (0)
+
+#define EP_PCIE_INFO(dev, fmt, arg...) do { \
+ if ((dev)->ipc_log_sel) \
+ ipc_log_string((dev)->ipc_log_sel, \
+ "INFO:%s: " fmt, __func__, arg); \
+ if ((dev)->ipc_log_ful) \
+ ipc_log_string((dev)->ipc_log_ful, "%s: " fmt, __func__, arg); \
+ pr_info("%s: " fmt, __func__, arg); \
+ } while (0)
+
+#define EP_PCIE_ERR(dev, fmt, arg...) do { \
+ if ((dev)->ipc_log_sel) \
+ ipc_log_string((dev)->ipc_log_sel, \
+ "ERR:%s: " fmt, __func__, arg); \
+ if ((dev)->ipc_log_ful) \
+ ipc_log_string((dev)->ipc_log_ful, "%s: " fmt, __func__, arg); \
+ pr_err("%s: " fmt, __func__, arg); \
+ } while (0)
+
+enum ep_pcie_res {
+ EP_PCIE_RES_PARF,
+ EP_PCIE_RES_PHY,
+ EP_PCIE_RES_MMIO,
+ EP_PCIE_RES_MSI,
+ EP_PCIE_RES_DM_CORE,
+ EP_PCIE_RES_ELBI,
+ EP_PCIE_MAX_RES,
+};
+
+enum ep_pcie_irq {
+ EP_PCIE_INT_PM_TURNOFF,
+ EP_PCIE_INT_DSTATE_CHANGE,
+ EP_PCIE_INT_L1SUB_TIMEOUT,
+ EP_PCIE_INT_LINK_UP,
+ EP_PCIE_INT_LINK_DOWN,
+ EP_PCIE_INT_BRIDGE_FLUSH_N,
+ EP_PCIE_MAX_IRQ,
+};
+
+enum ep_pcie_gpio {
+ EP_PCIE_GPIO_PERST,
+ EP_PCIE_GPIO_WAKE,
+ EP_PCIE_GPIO_CLKREQ,
+ EP_PCIE_MAX_GPIO,
+};
+
+struct ep_pcie_gpio_info_t {
+ char *name;
+ u32 num;
+ bool out;
+ u32 on;
+ u32 init;
+};
+
+struct ep_pcie_vreg_info_t {
+ struct regulator *hdl;
+ char *name;
+ u32 max_v;
+ u32 min_v;
+ u32 opt_mode;
+ bool required;
+};
+
+struct ep_pcie_clk_info_t {
+ struct clk *hdl;
+ char *name;
+ u32 freq;
+ bool required;
+};
+
+struct ep_pcie_res_info_t {
+ char *name;
+ struct resource *resource;
+ void __iomem *base;
+};
+
+struct ep_pcie_irq_info_t {
+ char *name;
+ u32 num;
+};
+
+/* pcie endpoint device structure */
+struct ep_pcie_dev_t {
+ struct platform_device *pdev;
+ struct regulator *gdsc;
+ struct ep_pcie_vreg_info_t vreg[EP_PCIE_MAX_VREG];
+ struct ep_pcie_gpio_info_t gpio[EP_PCIE_MAX_GPIO];
+ struct ep_pcie_clk_info_t clk[EP_PCIE_MAX_CLK];
+ struct ep_pcie_clk_info_t pipeclk[EP_PCIE_MAX_PIPE_CLK];
+ struct ep_pcie_irq_info_t irq[EP_PCIE_MAX_IRQ];
+ struct ep_pcie_res_info_t res[EP_PCIE_MAX_RES];
+
+ void __iomem *parf;
+ void __iomem *phy;
+ void __iomem *mmio;
+ void __iomem *msi;
+ void __iomem *dm_core;
+ void __iomem *elbi;
+
+ struct msm_bus_scale_pdata *bus_scale_table;
+ u32 bus_client;
+ u32 link_speed;
+
+ u32 rev;
+ u32 phy_rev;
+ void *ipc_log_sel;
+ void *ipc_log_ful;
+ void *ipc_log_dump;
+ struct mutex setup_mtx;
+ struct mutex ext_mtx;
+ spinlock_t ext_lock;
+ unsigned long ext_save_flags;
+
+ spinlock_t isr_lock;
+ unsigned long isr_save_flags;
+ ulong linkdown_counter;
+ ulong linkup_counter;
+ ulong pm_to_counter;
+ ulong d0_counter;
+ ulong d3_counter;
+ ulong perst_ast_counter;
+ ulong perst_deast_counter;
+ ulong wake_counter;
+ ulong msi_counter;
+
+ bool dump_conf;
+
+ bool enumerated;
+ enum ep_pcie_link_status link_status;
+ bool perst_deast;
+ bool power_on;
+ bool suspending;
+ bool l1ss_enabled;
+ struct ep_pcie_msi_config msi_cfg;
+
+ struct ep_pcie_register_event *event_reg;
+};
+
+extern struct ep_pcie_dev_t ep_pcie_dev;
+
+static inline void ep_pcie_write_mask(void __iomem *addr,
+ u32 clear_mask, u32 set_mask)
+{
+ u32 val;
+
+ val = (readl_relaxed(addr) & ~clear_mask) | set_mask;
+ writel_relaxed(val, addr);
+ /* ensure register write goes through before next regiser operation */
+ wmb();
+}
+
+static inline void ep_pcie_write_reg(void *base, u32 offset, u32 value)
+{
+ writel_relaxed(value, base + offset);
+ /* ensure register write goes through before next regiser operation */
+ wmb();
+}
+
+static inline void ep_pcie_write_reg_field(void *base, u32 offset,
+ const u32 mask, u32 val)
+{
+ u32 shift = find_first_bit((void *)&mask, 32);
+ u32 tmp = readl_relaxed(base + offset);
+
+ tmp &= ~mask; /* clear written bits */
+ val = tmp | (val << shift);
+ writel_relaxed(val, base + offset);
+ /* ensure register write goes through before next regiser operation */
+ wmb();
+}
+
+extern int ep_pcie_get_debug_mask(void);
+extern void ep_pcie_phy_init(struct ep_pcie_dev_t *dev);
+extern bool ep_pcie_phy_is_ready(struct ep_pcie_dev_t *dev);
+extern void ep_pcie_reg_dump(struct ep_pcie_dev_t *dev, u32 sel, bool linkdown);
+extern void ep_pcie_debugfs_init(struct ep_pcie_dev_t *ep_dev);
+extern void ep_pcie_debugfs_exit(void);
+
+#endif
diff --git a/drivers/platform/msm/ep_pcie/ep_pcie_core.c b/drivers/platform/msm/ep_pcie/ep_pcie_core.c
new file mode 100644
index 000000000000..72c67c8f8e04
--- /dev/null
+++ b/drivers/platform/msm/ep_pcie/ep_pcie_core.c
@@ -0,0 +1,1924 @@
+/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * MSM PCIe endpoint core driver.
+ */
+
+#include <linux/module.h>
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/iopoll.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/of_gpio.h>
+#include <linux/clk/msm-clk.h>
+#include <linux/msm-bus.h>
+#include <linux/msm-bus-board.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <mach/irqs.h>
+#include <mach/gpiomux.h>
+#include <mach/hardware.h>
+#include <mach/msm_iomap.h>
+
+#include "ep_pcie_com.h"
+
+/* debug mask sys interface */
+static int ep_pcie_debug_mask;
+static int ep_pcie_debug_keep_resource;
+module_param_named(debug_mask, ep_pcie_debug_mask,
+ int, S_IRUGO | S_IWUSR | S_IWGRP);
+module_param_named(debug_keep_resource, ep_pcie_debug_keep_resource,
+ int, S_IRUGO | S_IWUSR | S_IWGRP);
+
+struct ep_pcie_dev_t ep_pcie_dev = {0};
+
+static struct ep_pcie_vreg_info_t ep_pcie_vreg_info[EP_PCIE_MAX_VREG] = {
+ {NULL, "vreg-1.8", 1800000, 1800000, 1000, true},
+ {NULL, "vreg-0.9", 1000000, 1000000, 24000, true}
+};
+
+static struct ep_pcie_gpio_info_t ep_pcie_gpio_info[EP_PCIE_MAX_GPIO] = {
+ {"perst-gpio", 0, 0, 0, 1},
+ {"wake-gpio", 0, 1, 0, 1},
+ {"clkreq-gpio", 0, 1, 0, 0}
+};
+
+static struct ep_pcie_clk_info_t
+ ep_pcie_clk_info[EP_PCIE_MAX_CLK] = {
+ {NULL, "pcie_0_cfg_ahb_clk", 0, true},
+ {NULL, "pcie_0_mstr_axi_clk", 0, true},
+ {NULL, "pcie_0_slv_axi_clk", 0, true},
+ {NULL, "pcie_0_aux_clk", 1000000, true},
+ {NULL, "pcie_0_ldo", 0, true}
+};
+
+static struct ep_pcie_clk_info_t
+ ep_pcie_pipe_clk_info[EP_PCIE_MAX_PIPE_CLK] = {
+ {NULL, "pcie_0_pipe_clk", 62500000, true}
+};
+
+static const struct ep_pcie_res_info_t ep_pcie_res_info[EP_PCIE_MAX_RES] = {
+ {"parf", 0, 0},
+ {"phy", 0, 0},
+ {"mmio", 0, 0},
+ {"msi", 0, 0},
+ {"dm_core", 0, 0},
+ {"elbi", 0, 0}
+};
+
+static const struct ep_pcie_irq_info_t ep_pcie_irq_info[EP_PCIE_MAX_IRQ] = {
+ {"int_pm_turnoff", 0},
+ {"int_dstate_change", 0},
+ {"int_l1sub_timeout", 0},
+ {"int_link_up", 0},
+ {"int_link_down", 0},
+ {"int_bridge_flush_n", 0}
+};
+
+int ep_pcie_get_debug_mask(void)
+{
+ return ep_pcie_debug_mask;
+}
+
+static bool ep_pcie_confirm_linkup(struct ep_pcie_dev_t *dev,
+ bool check_sw_stts)
+{
+ u32 val;
+
+ if (check_sw_stts && (dev->link_status != EP_PCIE_LINK_ENABLED)) {
+ EP_PCIE_DBG(dev, "PCIe V%d: The link is not enabled.\n",
+ dev->rev);
+ return false;
+ }
+
+ val = readl_relaxed(dev->dm_core);
+ EP_PCIE_DBG(dev, "PCIe V%d: device ID and vender ID are 0x%x.\n",
+ dev->rev, val);
+ if (val == EP_PCIE_LINK_DOWN) {
+ EP_PCIE_ERR(dev,
+ "PCIe V%d: The link is not really up; device ID and vender ID are 0x%x.\n",
+ dev->rev, val);
+ return false;
+ }
+
+ return true;
+}
+
+static int ep_pcie_gpio_init(struct ep_pcie_dev_t *dev)
+{
+ int i, rc = 0;
+ struct ep_pcie_gpio_info_t *info;
+
+ EP_PCIE_DBG(dev, "PCIe V%d\n", dev->rev);
+
+ for (i = 0; i < EP_PCIE_MAX_GPIO; i++) {
+ info = &dev->gpio[i];
+
+ if (!info->num) {
+ EP_PCIE_ERR(dev,
+ "PCIe V%d: the number of gpio %s is invalid\n",
+ dev->rev, info->name);
+ rc = -EINVAL;
+ break;
+ }
+
+ rc = gpio_request(info->num, info->name);
+ if (rc) {
+ EP_PCIE_ERR(dev, "PCIe V%d: can't get gpio %s; %d\n",
+ dev->rev, info->name, rc);
+ break;
+ }
+
+ if (info->out)
+ rc = gpio_direction_output(info->num, info->init);
+ else
+ rc = gpio_direction_input(info->num);
+ if (rc) {
+ EP_PCIE_ERR(dev,
+ "PCIe V%d: can't set direction for GPIO %s:%d\n",
+ dev->rev, info->name, rc);
+ gpio_free(info->num);
+ break;
+ }
+ }
+
+ if (rc)
+ while (i--)
+ gpio_free(dev->gpio[i].num);
+
+ return rc;
+}
+
+static void ep_pcie_gpio_deinit(struct ep_pcie_dev_t *dev)
+{
+ int i;
+
+ EP_PCIE_DBG(dev, "PCIe V%d\n", dev->rev);
+
+ for (i = 0; i < EP_PCIE_MAX_GPIO; i++)
+ gpio_free(dev->gpio[i].num);
+}
+
+static int ep_pcie_vreg_init(struct ep_pcie_dev_t *dev)
+{
+ int i, rc = 0;
+ struct regulator *vreg;
+ struct ep_pcie_vreg_info_t *info;
+
+ EP_PCIE_DBG(dev, "PCIe V%d\n", dev->rev);
+
+ for (i = 0; i < EP_PCIE_MAX_VREG; i++) {
+ info = &dev->vreg[i];
+ vreg = info->hdl;
+
+ if (!vreg) {
+ EP_PCIE_ERR(dev,
+ "PCIe V%d: handle of Vreg %s is NULL\n",
+ dev->rev, info->name);
+ rc = -EINVAL;
+ break;
+ }
+
+ EP_PCIE_DBG(dev, "PCIe V%d: Vreg %s is being enabled\n",
+ dev->rev, info->name);
+ if (info->max_v) {
+ rc = regulator_set_voltage(vreg,
+ info->min_v, info->max_v);
+ if (rc) {
+ EP_PCIE_ERR(dev,
+ "PCIe V%d: can't set voltage for %s: %d\n",
+ dev->rev, info->name, rc);
+ break;
+ }
+ }
+
+ if (info->opt_mode) {
+ rc = regulator_set_optimum_mode(vreg, info->opt_mode);
+ if (rc < 0) {
+ EP_PCIE_ERR(dev,
+ "PCIe V%d: can't set mode for %s: %d\n",
+ dev->rev, info->name, rc);
+ break;
+ }
+ }
+
+ rc = regulator_enable(vreg);
+ if (rc) {
+ EP_PCIE_ERR(dev,
+ "PCIe V%d: can't enable regulator %s: %d\n",
+ dev->rev, info->name, rc);
+ break;
+ }
+ }
+
+ if (rc)
+ while (i--) {
+ struct regulator *hdl = dev->vreg[i].hdl;
+ if (hdl)
+ regulator_disable(hdl);
+ }
+
+ return rc;
+}
+
+static void ep_pcie_vreg_deinit(struct ep_pcie_dev_t *dev)
+{
+ int i;
+
+ EP_PCIE_DBG(dev, "PCIe V%d\n", dev->rev);
+
+ for (i = EP_PCIE_MAX_VREG - 1; i >= 0; i--) {
+ if (dev->vreg[i].hdl) {
+ EP_PCIE_DBG(dev, "Vreg %s is being disabled\n",
+ dev->vreg[i].name);
+ regulator_disable(dev->vreg[i].hdl);
+ }
+ }
+}
+
+static int ep_pcie_clk_init(struct ep_pcie_dev_t *dev)
+{
+ int i, rc = 0;
+ struct ep_pcie_clk_info_t *info;
+
+ EP_PCIE_DBG(dev, "PCIe V%d\n", dev->rev);
+
+ rc = regulator_enable(dev->gdsc);
+
+ if (rc) {
+ EP_PCIE_ERR(dev, "PCIe V%d: fail to enable GDSC for %s\n",
+ dev->rev, dev->pdev->name);
+ return rc;
+ }
+
+ if (dev->bus_client) {
+ rc = msm_bus_scale_client_update_request(dev->bus_client, 1);
+ if (rc) {
+ EP_PCIE_ERR(dev,
+ "PCIe V%d: fail to set bus bandwidth:%d.\n",
+ dev->rev, rc);
+ return rc;
+ } else {
+ EP_PCIE_DBG(dev,
+ "PCIe V%d: set bus bandwidth.\n",
+ dev->rev);
+ }
+ }
+
+ for (i = 0; i < EP_PCIE_MAX_CLK; i++) {
+ info = &dev->clk[i];
+
+ if (!info->hdl) {
+ EP_PCIE_ERR(dev,
+ "PCIe V%d: handle of Clock %s is NULL\n",
+ dev->rev, info->name);
+ rc = -EINVAL;
+ break;
+ }
+
+ if (info->freq) {
+ rc = clk_set_rate(info->hdl, info->freq);
+ if (rc) {
+ EP_PCIE_ERR(dev,
+ "PCIe V%d: can't set rate for clk %s: %d.\n",
+ dev->rev, info->name, rc);
+ break;
+ } else {
+ EP_PCIE_DBG(dev,
+ "PCIe V%d: set rate for clk %s.\n",
+ dev->rev, info->name);
+ }
+ }
+
+ rc = clk_prepare_enable(info->hdl);
+
+ if (rc)
+ EP_PCIE_ERR(dev, "PCIe V%d: failed to enable clk %s\n",
+ dev->rev, info->name);
+ else
+ EP_PCIE_DBG(dev, "PCIe V%d: enable clk %s.\n",
+ dev->rev, info->name);
+ }
+
+ if (rc) {
+ EP_PCIE_DBG(dev,
+ "PCIe V%d: disable clocks for error handling.\n",
+ dev->rev);
+ while (i--) {
+ struct clk *hdl = dev->clk[i].hdl;
+ if (hdl)
+ clk_disable_unprepare(hdl);
+ }
+
+ regulator_disable(dev->gdsc);
+ }
+
+ return rc;
+}
+
+static void ep_pcie_clk_deinit(struct ep_pcie_dev_t *dev)
+{
+ int i;
+ int rc;
+
+ EP_PCIE_DBG(dev, "PCIe V%d\n", dev->rev);
+
+ for (i = EP_PCIE_MAX_CLK - 1; i >= 0; i--)
+ if (dev->clk[i].hdl)
+ clk_disable_unprepare(dev->clk[i].hdl);
+
+ if (dev->bus_client) {
+ rc = msm_bus_scale_client_update_request(dev->bus_client, 0);
+ if (rc)
+ EP_PCIE_ERR(dev,
+ "PCIe V%d: fail to relinquish bus bandwidth:%d.\n",
+ dev->rev, rc);
+ else
+ EP_PCIE_DBG(dev,
+ "PCIe V%d: relinquish bus bandwidth.\n",
+ dev->rev);
+ }
+
+ regulator_disable(dev->gdsc);
+}
+
+static int ep_pcie_pipe_clk_init(struct ep_pcie_dev_t *dev)
+{
+ int i, rc = 0;
+ struct ep_pcie_clk_info_t *info;
+
+ EP_PCIE_DBG(dev, "PCIe V%d\n", dev->rev);
+
+ for (i = 0; i < EP_PCIE_MAX_PIPE_CLK; i++) {
+ info = &dev->pipeclk[i];
+
+ if (!info->hdl) {
+ EP_PCIE_ERR(dev,
+ "PCIe V%d: handle of Pipe Clock %s is NULL\n",
+ dev->rev, info->name);
+ rc = -EINVAL;
+ break;
+ }
+
+ clk_reset(info->hdl, CLK_RESET_DEASSERT);
+
+ if (info->freq) {
+ rc = clk_set_rate(info->hdl, info->freq);
+ if (rc) {
+ EP_PCIE_ERR(dev,
+ "PCIe V%d: can't set rate for clk %s: %d.\n",
+ dev->rev, info->name, rc);
+ break;
+ } else {
+ EP_PCIE_DBG(dev,
+ "PCIe V%d: set rate for clk %s\n",
+ dev->rev, info->name);
+ }
+ }
+
+ rc = clk_prepare_enable(info->hdl);
+
+ if (rc)
+ EP_PCIE_ERR(dev, "PCIe V%d: failed to enable clk %s.\n",
+ dev->rev, info->name);
+ else
+ EP_PCIE_DBG(dev, "PCIe V%d: enabled pipe clk %s.\n",
+ dev->rev, info->name);
+ }
+
+ if (rc) {
+ EP_PCIE_DBG(dev,
+ "PCIe V%d: disable pipe clocks for error handling.\n",
+ dev->rev);
+ while (i--)
+ if (dev->pipeclk[i].hdl)
+ clk_disable_unprepare(dev->pipeclk[i].hdl);
+ }
+
+ return rc;
+}
+
+static void ep_pcie_pipe_clk_deinit(struct ep_pcie_dev_t *dev)
+{
+ int i;
+
+ EP_PCIE_DBG(dev, "PCIe V%d\n", dev->rev);
+
+ for (i = 0; i < EP_PCIE_MAX_PIPE_CLK; i++)
+ if (dev->pipeclk[i].hdl)
+ clk_disable_unprepare(
+ dev->pipeclk[i].hdl);
+}
+
+static void ep_pcie_bar_init(struct ep_pcie_dev_t *dev)
+{
+ struct resource *res = dev->res[EP_PCIE_RES_MMIO].resource;
+ u32 mask = res->end - res->start;
+ u32 properties = 0x4;
+
+ EP_PCIE_DBG(dev, "PCIe V%d: BAR mask to program is 0x%x\n",
+ dev->rev, mask);
+
+ /* Configure BAR mask via CS2 */
+ ep_pcie_write_mask(dev->elbi + PCIE20_ELBI_CS2_ENABLE, 0, BIT(0));
+ ep_pcie_write_reg(dev->dm_core, PCIE20_BAR0, mask);
+ ep_pcie_write_reg(dev->dm_core, PCIE20_BAR0 + 0x8, mask);
+ ep_pcie_write_reg(dev->dm_core, PCIE20_BAR0 + 0x10, mask);
+ ep_pcie_write_mask(dev->elbi + PCIE20_ELBI_CS2_ENABLE, BIT(0), 0);
+
+ /* Configure BAR properties via CS */
+ ep_pcie_write_mask(dev->dm_core + PCIE20_MISC_CONTROL_1, 0, BIT(0));
+ ep_pcie_write_reg(dev->dm_core, PCIE20_BAR0, properties);
+ ep_pcie_write_reg(dev->dm_core, PCIE20_BAR0 + 0x8, properties);
+ ep_pcie_write_reg(dev->dm_core, PCIE20_BAR0 + 0x10, properties);
+ ep_pcie_write_mask(dev->dm_core + PCIE20_MISC_CONTROL_1, BIT(0), 0);
+}
+
+static void ep_pcie_core_init(struct ep_pcie_dev_t *dev)
+{
+ EP_PCIE_DBG(dev, "PCIe V%d\n", dev->rev);
+
+ /* enable debug IRQ */
+ ep_pcie_write_mask(dev->parf + PCIE20_PARF_DEBUG_INT_EN,
+ 0, BIT(3) | BIT(1));
+
+ /* Configure PCIe to endpoint mode */
+ ep_pcie_write_reg(dev->parf, PCIE20_PARF_DEVICE_TYPE, 0x0);
+
+ /* adjust DBI base address */
+ writel_relaxed(0x3FFFE000, dev->parf + PCIE20_PARF_DBI_BASE_ADDR);
+
+ /* Configure PCIe core to support 1GB aperture */
+ ep_pcie_write_reg(dev->parf, PCIE20_PARF_SLV_ADDR_SPACE_SIZE,
+ 0x40000000);
+
+ /* Configure link speed */
+ ep_pcie_write_mask(dev->dm_core + PCIE20_LINK_CONTROL2_LINK_STATUS2,
+ 0xf, dev->link_speed);
+
+ /* Read halts write */
+ ep_pcie_write_mask(dev->parf + PCIE20_PARF_AXI_MSTR_RD_HALT_NO_WRITES,
+ 0, BIT(0));
+
+ /* Write after write halt */
+ ep_pcie_write_mask(dev->parf + PCIE20_PARF_AXI_MSTR_WR_ADDR_HALT,
+ 0, BIT(31));
+
+ /* Q2A flush disable */
+ writel_relaxed(0, dev->parf + PCIE20_PARF_Q2A_FLUSH);
+
+ /* Disable the DBI Wakeup */
+ ep_pcie_write_mask(dev->parf + PCIE20_PARF_SYS_CTRL, BIT(11), 0);
+
+ /* Disable core clock CGC */
+ ep_pcie_write_mask(dev->parf + PCIE20_PARF_SYS_CTRL, 0, BIT(6));
+
+ /* Set AUX power to be on */
+ ep_pcie_write_mask(dev->parf + PCIE20_PARF_SYS_CTRL, 0, BIT(4));
+
+ EP_PCIE_DBG(dev,
+ "Initial: CLASS_CODE_REVISION_ID:0x%x; HDR_TYPE:0x%x\n",
+ readl_relaxed(dev->dm_core + PCIE20_CLASS_CODE_REVISION_ID),
+ readl_relaxed(dev->dm_core + PCIE20_BIST_HDR_TYPE));
+
+ /* Enable CS for RO(CS) register writes */
+ ep_pcie_write_mask(dev->dm_core + PCIE20_MISC_CONTROL_1, 0, BIT(0));
+
+ /* Set class code and revision ID */
+ ep_pcie_write_reg(dev->dm_core, PCIE20_CLASS_CODE_REVISION_ID,
+ 0xff000000);
+
+ /* Set header type */
+ ep_pcie_write_reg(dev->dm_core, PCIE20_BIST_HDR_TYPE, 0x10);
+
+ /* Set the PMC Register - to support PME in D0, D3hot and D3cold */
+ ep_pcie_write_mask(dev->dm_core + PCIE20_CAP_ID_NXT_PTR, 0,
+ BIT(4)|BIT(3)|BIT(0));
+
+ /* Set the Endpoint L0s Acceptable Latency to 1us (max) */
+ ep_pcie_write_reg_field(dev->dm_core, PCIE20_DEVICE_CAPABILITIES,
+ PCIE20_MASK_EP_L0S_ACCPT_LATENCY, 0x7);
+
+ /* Set the Endpoint L1 Acceptable Latency to 2 us (max) */
+ ep_pcie_write_reg_field(dev->dm_core, PCIE20_DEVICE_CAPABILITIES,
+ PCIE20_MASK_EP_L1_ACCPT_LATENCY, 0x7);
+
+ /* Set the L0s Exit Latency to 2us-4us = 0x6 */
+ ep_pcie_write_reg_field(dev->dm_core, PCIE20_LINK_CAPABILITIES,
+ PCIE20_MASK_L1_EXIT_LATENCY, 0x6);
+
+ /* Set the L1 Exit Latency to be 32us-64 us = 0x6 */
+ ep_pcie_write_reg_field(dev->dm_core, PCIE20_LINK_CAPABILITIES,
+ PCIE20_MASK_L0S_EXIT_LATENCY, 0x6);
+
+ /* L1ss is not supported */
+ ep_pcie_write_mask(dev->dm_core + PCIE20_L1SUB_CAPABILITY, 0x1f, 0);
+
+ /* Enable Clock Power Management */
+ ep_pcie_write_reg_field(dev->dm_core, PCIE20_LINK_CAPABILITIES,
+ PCIE20_MASK_CLOCK_POWER_MAN, 0x1);
+
+ /* Disable CS for RO(CS) register writes */
+ ep_pcie_write_mask(dev->dm_core + PCIE20_MISC_CONTROL_1, BIT(0), 0);
+
+ /* Set FTS value to match the PHY setting */
+ ep_pcie_write_reg_field(dev->dm_core, PCIE20_ACK_F_ASPM_CTRL_REG,
+ PCIE20_MASK_ACK_N_FTS, 0x80);
+
+ EP_PCIE_DBG(dev,
+ "After program: CLASS_CODE_REVISION_ID:0x%x; HDR_TYPE:0x%x; L1SUB_CAPABILITY:0x%x; PARF_SYS_CTRL:0x%x\n",
+ readl_relaxed(dev->dm_core + PCIE20_CLASS_CODE_REVISION_ID),
+ readl_relaxed(dev->dm_core + PCIE20_BIST_HDR_TYPE),
+ readl_relaxed(dev->dm_core + PCIE20_L1SUB_CAPABILITY),
+ readl_relaxed(dev->parf + PCIE20_PARF_SYS_CTRL));
+
+ /* Configure BARs */
+ ep_pcie_bar_init(dev);
+}
+
+static void ep_pcie_config_inbound_iatu(struct ep_pcie_dev_t *dev)
+{
+ struct resource *mmio = dev->res[EP_PCIE_RES_MMIO].resource;
+ u32 lower, limit, bar;
+
+ lower = mmio->start;
+ limit = mmio->end;
+ bar = readl_relaxed(dev->dm_core + PCIE20_BAR0);
+
+ EP_PCIE_DBG(dev,
+ "PCIe V%d: BAR0 is 0x%x; MMIO[0x%x-0x%x]\n",
+ dev->rev, bar, lower, limit);
+
+ ep_pcie_write_reg(dev->parf, PCIE20_PARF_MHI_BASE_ADDR_LOWER, lower);
+ ep_pcie_write_reg(dev->parf, PCIE20_PARF_MHI_BASE_ADDR_UPPER, 0x0);
+
+ /* program inbound address translation using region 0 */
+ ep_pcie_write_reg(dev->dm_core, PCIE20_PLR_IATU_VIEWPORT, 0x80000000);
+ /* set region to mem type */
+ ep_pcie_write_reg(dev->dm_core, PCIE20_PLR_IATU_CTRL1, 0x0);
+ /* setup target address registers */
+ ep_pcie_write_reg(dev->dm_core, PCIE20_PLR_IATU_LTAR, lower);
+ ep_pcie_write_reg(dev->dm_core, PCIE20_PLR_IATU_UTAR, 0x0);
+ /* use BAR match mode for BAR0 and enable region 0 */
+ ep_pcie_write_reg(dev->dm_core, PCIE20_PLR_IATU_CTRL2, 0xc0000000);
+
+ EP_PCIE_DBG(dev, "PCIE20_PLR_IATU_VIEWPORT:0x%x\n",
+ readl_relaxed(dev->dm_core + PCIE20_PLR_IATU_VIEWPORT));
+ EP_PCIE_DBG(dev, "PCIE20_PLR_IATU_CTRL1:0x%x\n",
+ readl_relaxed(dev->dm_core + PCIE20_PLR_IATU_CTRL1));
+ EP_PCIE_DBG(dev, "PCIE20_PLR_IATU_LTAR:0x%x\n",
+ readl_relaxed(dev->dm_core + PCIE20_PLR_IATU_LTAR));
+ EP_PCIE_DBG(dev, "PCIE20_PLR_IATU_UTAR:0x%x\n",
+ readl_relaxed(dev->dm_core + PCIE20_PLR_IATU_UTAR));
+ EP_PCIE_DBG(dev, "PCIE20_PLR_IATU_CTRL2:0x%x\n",
+ readl_relaxed(dev->dm_core + PCIE20_PLR_IATU_CTRL2));
+}
+
+static void ep_pcie_config_outbound_iatu_entry(struct ep_pcie_dev_t *dev,
+ u32 region, u32 lower,
+ u32 limit, u32 tgt_lower, u32 tgt_upper)
+{
+ EP_PCIE_DBG(dev,
+ "PCIe V%d: region:%d; lower:0x%x; limit:0x%x; target_lower:0x%x; target_upper:0x%x\n",
+ dev->rev, region, lower, limit, tgt_lower, tgt_upper);
+
+ /* program outbound address translation using an input region */
+ ep_pcie_write_reg(dev->dm_core, PCIE20_PLR_IATU_VIEWPORT, region);
+ /* set region to mem type */
+ ep_pcie_write_reg(dev->dm_core, PCIE20_PLR_IATU_CTRL1, 0x0);
+ /* setup source address registers */
+ ep_pcie_write_reg(dev->dm_core, PCIE20_PLR_IATU_LBAR, lower);
+ ep_pcie_write_reg(dev->dm_core, PCIE20_PLR_IATU_UBAR, 0x0);
+ ep_pcie_write_reg(dev->dm_core, PCIE20_PLR_IATU_LAR, limit);
+ /* setup target address registers */
+ ep_pcie_write_reg(dev->dm_core, PCIE20_PLR_IATU_LTAR, tgt_lower);
+ ep_pcie_write_reg(dev->dm_core, PCIE20_PLR_IATU_UTAR, tgt_upper);
+ /* use DMA bypass mode and enable the region */
+ ep_pcie_write_mask(dev->dm_core + PCIE20_PLR_IATU_CTRL2, 0,
+ BIT(31) | BIT(27));
+
+ EP_PCIE_DBG(dev, "PCIE20_PLR_IATU_VIEWPORT:0x%x\n",
+ readl_relaxed(dev->dm_core + PCIE20_PLR_IATU_VIEWPORT));
+ EP_PCIE_DBG(dev, "PCIE20_PLR_IATU_CTRL1:0x%x\n",
+ readl_relaxed(dev->dm_core + PCIE20_PLR_IATU_CTRL1));
+ EP_PCIE_DBG(dev, "PCIE20_PLR_IATU_LBAR:0x%x\n",
+ readl_relaxed(dev->dm_core + PCIE20_PLR_IATU_LBAR));
+ EP_PCIE_DBG(dev, "PCIE20_PLR_IATU_UBAR:0x%x\n",
+ readl_relaxed(dev->dm_core + PCIE20_PLR_IATU_UBAR));
+ EP_PCIE_DBG(dev, "PCIE20_PLR_IATU_LAR:0x%x\n",
+ readl_relaxed(dev->dm_core + PCIE20_PLR_IATU_LAR));
+ EP_PCIE_DBG(dev, "PCIE20_PLR_IATU_LTAR:0x%x\n",
+ readl_relaxed(dev->dm_core + PCIE20_PLR_IATU_LTAR));
+ EP_PCIE_DBG(dev, "PCIE20_PLR_IATU_UTAR:0x%x\n",
+ readl_relaxed(dev->dm_core + PCIE20_PLR_IATU_UTAR));
+ EP_PCIE_DBG(dev, "PCIE20_PLR_IATU_CTRL2:0x%x\n",
+ readl_relaxed(dev->dm_core + PCIE20_PLR_IATU_CTRL2));
+}
+
+static void ep_pcie_notify_event(struct ep_pcie_dev_t *dev,
+ enum ep_pcie_event event)
+{
+ if (dev && dev->event_reg && dev->event_reg->callback &&
+ (dev->event_reg->events & event)) {
+ struct ep_pcie_notify *notify =
+ &dev->event_reg->notify;
+ notify->event = event;
+ notify->user = dev->event_reg->user;
+ EP_PCIE_DBG(&ep_pcie_dev,
+ "PCIe V%d: Callback client for event %d.\n",
+ dev->rev, event);
+ dev->event_reg->callback(notify);
+ } else {
+ EP_PCIE_DBG(&ep_pcie_dev,
+ "PCIe V%d: Client does not register for event %d.\n",
+ dev->rev, event);
+ }
+}
+
+static int ep_pcie_get_resources(struct ep_pcie_dev_t *dev,
+ struct platform_device *pdev)
+{
+ int i, len, cnt, ret = 0;
+ struct ep_pcie_vreg_info_t *vreg_info;
+ struct ep_pcie_gpio_info_t *gpio_info;
+ struct ep_pcie_clk_info_t *clk_info;
+ struct resource *res;
+ struct ep_pcie_res_info_t *res_info;
+ struct ep_pcie_irq_info_t *irq_info;
+ char prop_name[MAX_PROP_SIZE];
+ const __be32 *prop;
+ u32 *clkfreq = NULL;
+
+ EP_PCIE_DBG(dev, "PCIe V%d\n", dev->rev);
+
+ cnt = of_property_count_strings((&pdev->dev)->of_node,
+ "clock-names");
+ if (cnt > 0) {
+ clkfreq = kzalloc(cnt * sizeof(*clkfreq),
+ GFP_KERNEL);
+ if (!clkfreq) {
+ EP_PCIE_ERR(dev, "PCIe V%d: memory alloc failed\n",
+ dev->rev);
+ return -ENOMEM;
+ }
+ ret = of_property_read_u32_array(
+ (&pdev->dev)->of_node,
+ "max-clock-frequency-hz", clkfreq, cnt);
+ if (ret) {
+ EP_PCIE_ERR(dev,
+ "PCIe V%d: invalid max-clock-frequency-hz property:%d\n",
+ dev->rev, ret);
+ goto out;
+ }
+ }
+
+ for (i = 0; i < EP_PCIE_MAX_VREG; i++) {
+ vreg_info = &dev->vreg[i];
+ vreg_info->hdl =
+ devm_regulator_get(&pdev->dev, vreg_info->name);
+
+ if (PTR_ERR(vreg_info->hdl) == -EPROBE_DEFER) {
+ EP_PCIE_DBG(dev, "EPROBE_DEFER for VReg:%s\n",
+ vreg_info->name);
+ ret = PTR_ERR(vreg_info->hdl);
+ goto out;
+ }
+
+ if (IS_ERR(vreg_info->hdl)) {
+ if (vreg_info->required) {
+ EP_PCIE_DBG(dev, "Vreg %s doesn't exist\n",
+ vreg_info->name);
+ ret = PTR_ERR(vreg_info->hdl);
+ goto out;
+ } else {
+ EP_PCIE_DBG(dev,
+ "Optional Vreg %s doesn't exist\n",
+ vreg_info->name);
+ vreg_info->hdl = NULL;
+ }
+ } else {
+ snprintf(prop_name, MAX_PROP_SIZE,
+ "qcom,%s-voltage-level", vreg_info->name);
+ prop = of_get_property((&pdev->dev)->of_node,
+ prop_name, &len);
+ if (!prop || (len != (3 * sizeof(__be32)))) {
+ EP_PCIE_DBG(dev, "%s %s property\n",
+ prop ? "invalid format" :
+ "no", prop_name);
+ } else {
+ vreg_info->max_v = be32_to_cpup(&prop[0]);
+ vreg_info->min_v = be32_to_cpup(&prop[1]);
+ vreg_info->opt_mode =
+ be32_to_cpup(&prop[2]);
+ }
+ }
+ }
+
+ dev->gdsc = devm_regulator_get(&pdev->dev, "gdsc-vdd");
+
+ if (IS_ERR(dev->gdsc)) {
+ EP_PCIE_ERR(dev, "PCIe V%d: Failed to get %s GDSC:%ld\n",
+ dev->rev, dev->pdev->name, PTR_ERR(dev->gdsc));
+ if (PTR_ERR(dev->gdsc) == -EPROBE_DEFER)
+ EP_PCIE_DBG(dev, "PCIe V%d: EPROBE_DEFER for %s GDSC\n",
+ dev->rev, dev->pdev->name);
+ ret = PTR_ERR(dev->gdsc);
+ goto out;
+ }
+
+ for (i = 0; i < EP_PCIE_MAX_GPIO; i++) {
+ gpio_info = &dev->gpio[i];
+ ret = of_get_named_gpio((&pdev->dev)->of_node,
+ gpio_info->name, 0);
+ if (ret >= 0) {
+ gpio_info->num = ret;
+ ret = 0;
+ EP_PCIE_DBG(dev, "GPIO num for %s is %d\n",
+ gpio_info->name, gpio_info->num);
+ } else {
+ goto out;
+ }
+ }
+
+ for (i = 0; i < EP_PCIE_MAX_CLK; i++) {
+ clk_info = &dev->clk[i];
+
+ clk_info->hdl = devm_clk_get(&pdev->dev, clk_info->name);
+
+ if (IS_ERR(clk_info->hdl)) {
+ if (clk_info->required) {
+ EP_PCIE_DBG(dev,
+ "Clock %s isn't available:%ld\n",
+ clk_info->name, PTR_ERR(clk_info->hdl));
+ ret = PTR_ERR(clk_info->hdl);
+ goto out;
+ } else {
+ EP_PCIE_DBG(dev, "Ignoring Clock %s\n",
+ clk_info->name);
+ clk_info->hdl = NULL;
+ }
+ } else {
+ if (clkfreq != NULL) {
+ clk_info->freq = clkfreq[i +
+ EP_PCIE_MAX_PIPE_CLK];
+ EP_PCIE_DBG(dev, "Freq of Clock %s is:%d\n",
+ clk_info->name, clk_info->freq);
+ }
+ }
+ }
+
+ for (i = 0; i < EP_PCIE_MAX_PIPE_CLK; i++) {
+ clk_info = &dev->pipeclk[i];
+
+ clk_info->hdl = devm_clk_get(&pdev->dev, clk_info->name);
+
+ if (IS_ERR(clk_info->hdl)) {
+ if (clk_info->required) {
+ EP_PCIE_DBG(dev,
+ "Clock %s isn't available:%ld\n",
+ clk_info->name, PTR_ERR(clk_info->hdl));
+ ret = PTR_ERR(clk_info->hdl);
+ goto out;
+ } else {
+ EP_PCIE_DBG(dev, "Ignoring Clock %s\n",
+ clk_info->name);
+ clk_info->hdl = NULL;
+ }
+ } else {
+ if (clkfreq != NULL) {
+ clk_info->freq = clkfreq[i];
+ EP_PCIE_DBG(dev, "Freq of Clock %s is:%d\n",
+ clk_info->name, clk_info->freq);
+ }
+ }
+ }
+
+ dev->bus_scale_table = msm_bus_cl_get_pdata(pdev);
+ if (!dev->bus_scale_table) {
+ EP_PCIE_DBG(dev, "PCIe V%d: No bus scale table for %s\n",
+ dev->rev, dev->pdev->name);
+ dev->bus_client = 0;
+ } else {
+ dev->bus_client =
+ msm_bus_scale_register_client(dev->bus_scale_table);
+ if (!dev->bus_client) {
+ EP_PCIE_ERR(dev,
+ "PCIe V%d: Failed to register bus client for %s\n",
+ dev->rev, dev->pdev->name);
+ msm_bus_cl_clear_pdata(dev->bus_scale_table);
+ ret = -ENODEV;
+ goto out;
+ }
+ }
+
+ for (i = 0; i < EP_PCIE_MAX_RES; i++) {
+ res_info = &dev->res[i];
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ res_info->name);
+
+ if (!res) {
+ EP_PCIE_ERR(dev,
+ "PCIe V%d: can't get resource for %s.\n",
+ dev->rev, res_info->name);
+ ret = -ENOMEM;
+ goto out;
+ } else {
+ EP_PCIE_DBG(dev, "start addr for %s is %pa.\n",
+ res_info->name, &res->start);
+ }
+
+ res_info->base = devm_ioremap(&pdev->dev,
+ res->start, resource_size(res));
+ if (!res_info->base) {
+ EP_PCIE_ERR(dev, "PCIe V%d: can't remap %s.\n",
+ dev->rev, res_info->name);
+ ret = -ENOMEM;
+ goto out;
+ }
+ res_info->resource = res;
+ }
+
+ for (i = 0; i < EP_PCIE_MAX_IRQ; i++) {
+ irq_info = &dev->irq[i];
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
+ irq_info->name);
+
+ if (!res) {
+ int j;
+ for (j = 0; j < EP_PCIE_MAX_RES; j++) {
+ iounmap(dev->res[j].base);
+ dev->res[j].base = NULL;
+ }
+ EP_PCIE_ERR(dev, "PCIe V%d: can't find IRQ # for %s\n",
+ dev->rev, irq_info->name);
+ ret = -ENODEV;
+ goto out;
+ } else {
+ irq_info->num = res->start;
+ EP_PCIE_DBG(dev, "IRQ # for %s is %d.\n",
+ irq_info->name, irq_info->num);
+ }
+ }
+
+ dev->parf = dev->res[EP_PCIE_RES_PARF].base;
+ dev->phy = dev->res[EP_PCIE_RES_PHY].base;
+ dev->mmio = dev->res[EP_PCIE_RES_MMIO].base;
+ dev->msi = dev->res[EP_PCIE_RES_MSI].base;
+ dev->dm_core = dev->res[EP_PCIE_RES_DM_CORE].base;
+ dev->elbi = dev->res[EP_PCIE_RES_ELBI].base;
+
+out:
+ kfree(clkfreq);
+ return ret;
+}
+
+static void ep_pcie_release_resources(struct ep_pcie_dev_t *dev)
+{
+ dev->parf = NULL;
+ dev->elbi = NULL;
+ dev->dm_core = NULL;
+ dev->phy = NULL;
+ dev->mmio = NULL;
+ dev->msi = NULL;
+}
+
+int ep_pcie_core_enable_endpoint(enum ep_pcie_options opt)
+{
+ int ret = 0;
+ u32 val;
+ u32 retries;
+ u32 bme;
+ struct ep_pcie_dev_t *dev = &ep_pcie_dev;
+
+ EP_PCIE_DBG(dev, "PCIe V%d: options input are 0x%x.\n", dev->rev, opt);
+
+ mutex_lock(&dev->setup_mtx);
+
+ if (dev->link_status == EP_PCIE_LINK_ENABLED) {
+ EP_PCIE_ERR(dev,
+ "PCIe V%d: link is already enabled.\n",
+ dev->rev);
+ goto out;
+ }
+
+ if (dev->link_status == EP_PCIE_LINK_UP) {
+ EP_PCIE_ERR(dev,
+ "PCIe V%d: link is up but not enabled; need to disable link first.\n",
+ dev->rev);
+ ret = EP_PCIE_ERROR;
+ goto out;
+ }
+
+ if (dev->power_on && (opt & EP_PCIE_OPT_POWER_ON)) {
+ EP_PCIE_ERR(dev,
+ "PCIe V%d: request to turn on the power when link is already powered on.\n",
+ dev->rev);
+ ret = EP_PCIE_ERROR;
+ goto out;
+ }
+
+ if (opt & EP_PCIE_OPT_POWER_ON) {
+ /* enable power */
+ ret = ep_pcie_vreg_init(dev);
+ if (ret) {
+ EP_PCIE_ERR(dev, "PCIe V%d: failed to enable Vreg\n",
+ dev->rev);
+ goto out;
+ }
+
+ /* enable clocks */
+ ret = ep_pcie_clk_init(dev);
+ if (ret) {
+ EP_PCIE_ERR(dev, "PCIe V%d: failed to enable clocks\n",
+ dev->rev);
+ goto clk_fail;
+ }
+
+ /* enable pipe clock */
+ ret = ep_pcie_pipe_clk_init(dev);
+ if (ret) {
+ EP_PCIE_ERR(dev,
+ "PCIe V%d: failed to enable pipe clock\n",
+ dev->rev);
+ goto pipe_clk_fail;
+ }
+ }
+
+ if (!(opt & EP_PCIE_OPT_ENUM))
+ goto out;
+
+ if (opt & EP_PCIE_OPT_AST_WAKE) {
+ /* assert PCIe WAKE# */
+ EP_PCIE_INFO(dev, "PCIe V%d: assert PCIe WAKE#.\n",
+ dev->rev);
+ EP_PCIE_DBG(dev, "PCIe V%d: WAKE GPIO initial:%d.\n",
+ dev->rev,
+ gpio_get_value(dev->gpio[EP_PCIE_GPIO_WAKE].num));
+ gpio_set_value(dev->gpio[EP_PCIE_GPIO_WAKE].num,
+ 1 - dev->gpio[EP_PCIE_GPIO_WAKE].on);
+ EP_PCIE_DBG(dev,
+ "PCIe V%d: WAKE GPIO after deassertion:%d.\n",
+ dev->rev,
+ gpio_get_value(dev->gpio[EP_PCIE_GPIO_WAKE].num));
+ gpio_set_value(dev->gpio[EP_PCIE_GPIO_WAKE].num,
+ dev->gpio[EP_PCIE_GPIO_WAKE].on);
+ EP_PCIE_DBG(dev,
+ "PCIe V%d: WAKE GPIO after assertion:%d.\n",
+ dev->rev,
+ gpio_get_value(dev->gpio[EP_PCIE_GPIO_WAKE].num));
+ }
+
+ /* wait for host side to deassert PERST */
+ retries = 0;
+ do {
+ if (gpio_get_value(dev->gpio[EP_PCIE_GPIO_PERST].num) == 1)
+ break;
+ retries++;
+ usleep_range(PERST_TIMEOUT_US_MIN, PERST_TIMEOUT_US_MAX);
+ } while (retries < PERST_CHECK_MAX_COUNT);
+
+ EP_PCIE_DBG(dev, "PCIe V%d: number of PERST retries:%d.\n",
+ dev->rev, retries);
+
+ if (retries == PERST_CHECK_MAX_COUNT) {
+ EP_PCIE_ERR(dev,
+ "PCIe V%d: PERST is not de-asserted by host\n",
+ dev->rev);
+ ret = EP_PCIE_ERROR;
+ goto pipe_clk_fail;
+ } else {
+ dev->perst_deast = true;
+ if (opt & EP_PCIE_OPT_AST_WAKE) {
+ /* deassert PCIe WAKE# */
+ EP_PCIE_DBG(dev,
+ "PCIe V%d: deassert PCIe WAKE# after PERST# is deasserted.\n",
+ dev->rev);
+ gpio_set_value(dev->gpio[EP_PCIE_GPIO_WAKE].num,
+ 1 - dev->gpio[EP_PCIE_GPIO_WAKE].on);
+ }
+ }
+
+ /* init PCIe PHY */
+ ep_pcie_phy_init(dev);
+
+ EP_PCIE_DBG(dev, "PCIe V%d: waiting for phy ready...\n", dev->rev);
+ retries = 0;
+ do {
+ if (ep_pcie_phy_is_ready(dev))
+ break;
+ retries++;
+ if (retries % 10 == 0)
+ EP_PCIE_DBG(dev,
+ "PCIe V%d: current number of PHY retries:%d.\n",
+ dev->rev, retries);
+ usleep_range(REFCLK_STABILIZATION_DELAY_US_MIN,
+ REFCLK_STABILIZATION_DELAY_US_MAX);
+ } while (retries < PHY_READY_TIMEOUT_COUNT);
+
+ EP_PCIE_DBG(dev, "PCIe V%d: number of PHY retries:%d.\n",
+ dev->rev, retries);
+
+ if (retries == PHY_READY_TIMEOUT_COUNT) {
+ EP_PCIE_ERR(dev, "PCIe V%d: PCIe PHY failed to come up!\n",
+ dev->rev);
+ ret = EP_PCIE_ERROR;
+ ep_pcie_reg_dump(dev, BIT(EP_PCIE_RES_PHY), false);
+ goto link_fail;
+ } else {
+ EP_PCIE_INFO(dev, "PCIe V%d: PCIe PHY is ready!\n", dev->rev);
+ }
+
+ ep_pcie_core_init(dev);
+ ep_pcie_config_inbound_iatu(dev);
+
+ /* enable link training */
+ ep_pcie_write_mask(dev->elbi + PCIE20_ELBI_SYS_CTRL, 0, BIT(0));
+
+ EP_PCIE_DBG(dev, "PCIe V%d: check if link is up\n", dev->rev);
+
+ /* Wait for up to 100ms for the link to come up */
+ retries = 0;
+ do {
+ usleep_range(LINK_UP_TIMEOUT_US_MIN, LINK_UP_TIMEOUT_US_MAX);
+ val = readl_relaxed(dev->elbi + PCIE20_ELBI_SYS_STTS);
+ retries++;
+ if (retries % 5 == 0)
+ EP_PCIE_DBG(dev, "PCIe V%d: LTSSM_STATE:0x%x.\n",
+ dev->rev, (val >> 0xC) & 0x3f);
+ } while ((!(val & XMLH_LINK_UP) ||
+ !ep_pcie_confirm_linkup(dev, false))
+ && (retries < LINK_UP_CHECK_MAX_COUNT));
+
+ if (retries == LINK_UP_CHECK_MAX_COUNT) {
+ EP_PCIE_ERR(dev, "PCIe V%d: link initialization failed\n",
+ dev->rev);
+ ret = EP_PCIE_ERROR;
+ goto link_fail;
+ } else {
+ dev->link_status = EP_PCIE_LINK_UP;
+ EP_PCIE_DBG(dev,
+ "PCIe V%d: link is up after %d checkings (%d ms)\n",
+ dev->rev, retries,
+ LINK_UP_TIMEOUT_US_MIN * retries / 1000);
+ EP_PCIE_INFO(dev,
+ "PCIe V%d: link initialized for LE PCIe endpoint\n",
+ dev->rev);
+ }
+
+ /* Wait for up to 1000ms for BME to be set */
+ retries = 0;
+ bme = readl_relaxed(dev->dm_core +
+ PCIE20_COMMAND_STATUS) & BIT(2);
+ while (!bme && (retries < BME_CHECK_MAX_COUNT)) {
+ retries++;
+ usleep_range(BME_TIMEOUT_US_MIN, BME_TIMEOUT_US_MAX);
+ bme = readl_relaxed(dev->dm_core +
+ PCIE20_COMMAND_STATUS) & BIT(2);
+ }
+
+ if (bme) {
+ dev->link_status = EP_PCIE_LINK_ENABLED;
+ EP_PCIE_DBG(dev,
+ "PCIe V%d: PCIe link is up and BME is enabled after %d checkings (%d ms).\n",
+ dev->rev, retries,
+ BME_TIMEOUT_US_MIN * retries / 1000);
+ } else {
+ EP_PCIE_ERR(dev,
+ "PCIe V%d: PCIe link is up but BME is still disabled after max waiting time.\n",
+ dev->rev);
+ if (!ep_pcie_debug_keep_resource) {
+ ret = EP_PCIE_ERROR;
+ dev->link_status = EP_PCIE_LINK_DISABLED;
+ goto link_fail;
+ }
+ }
+
+ dev->power_on = true;
+ dev->suspending = false;
+ goto out;
+
+link_fail:
+ if (!ep_pcie_debug_keep_resource)
+ ep_pcie_pipe_clk_deinit(dev);
+pipe_clk_fail:
+ if (!ep_pcie_debug_keep_resource)
+ ep_pcie_clk_deinit(dev);
+clk_fail:
+ if (!ep_pcie_debug_keep_resource)
+ ep_pcie_vreg_deinit(dev);
+ else
+ ret = 0;
+out:
+ mutex_unlock(&dev->setup_mtx);
+
+ return ret;
+}
+
+int ep_pcie_core_disable_endpoint(void)
+{
+ int rc = 0;
+ struct ep_pcie_dev_t *dev = &ep_pcie_dev;
+
+ EP_PCIE_DBG(dev, "PCIe V%d\n", dev->rev);
+
+ mutex_lock(&dev->setup_mtx);
+
+ if (!dev->power_on) {
+ EP_PCIE_DBG(dev,
+ "PCIe V%d: the link is already power down.\n",
+ dev->rev);
+ goto out;
+ }
+
+ dev->link_status = EP_PCIE_LINK_DISABLED;
+ dev->power_on = false;
+
+ EP_PCIE_DBG(dev, "PCIe V%d: shut down the link.\n",
+ dev->rev);
+
+ ep_pcie_pipe_clk_deinit(dev);
+ ep_pcie_clk_deinit(dev);
+ ep_pcie_vreg_deinit(dev);
+out:
+ mutex_unlock(&dev->setup_mtx);
+ return rc;
+}
+
+static irqreturn_t ep_pcie_handle_linkdown_irq(int irq, void *data)
+{
+ struct ep_pcie_dev_t *dev = data;
+ unsigned long irqsave_flags;
+
+ spin_lock_irqsave(&dev->isr_lock, irqsave_flags);
+
+ dev->linkdown_counter++;
+ EP_PCIE_DBG(dev,
+ "PCIe V%d: No. %ld linkdown IRQ.\n",
+ dev->rev, dev->linkdown_counter);
+
+ if (!dev->enumerated || dev->link_status == EP_PCIE_LINK_DISABLED) {
+ EP_PCIE_DBG(dev,
+ "PCIe V%d:Linkdown IRQ happened when the link is disabled.\n",
+ dev->rev);
+ } else if (dev->suspending) {
+ EP_PCIE_DBG(dev,
+ "PCIe V%d:Linkdown IRQ happened when the link is suspending.\n",
+ dev->rev);
+ } else {
+ dev->link_status = EP_PCIE_LINK_DISABLED;
+ EP_PCIE_ERR(dev, "PCIe V%d:PCIe link is down for %ld times\n",
+ dev->rev, dev->linkdown_counter);
+ ep_pcie_reg_dump(dev, BIT(EP_PCIE_RES_PHY) |
+ BIT(EP_PCIE_RES_PARF), true);
+ ep_pcie_notify_event(dev, EP_PCIE_EVENT_LINKDOWN);
+ }
+
+ spin_unlock_irqrestore(&dev->isr_lock, irqsave_flags);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t ep_pcie_handle_linkup_irq(int irq, void *data)
+{
+ struct ep_pcie_dev_t *dev = data;
+ unsigned long irqsave_flags;
+
+ spin_lock_irqsave(&dev->isr_lock, irqsave_flags);
+
+ dev->linkup_counter++;
+ EP_PCIE_DBG(dev,
+ "PCIe V%d: No. %ld linkup IRQ.\n",
+ dev->rev, dev->linkup_counter);
+
+ dev->link_status = EP_PCIE_LINK_UP;
+
+ spin_unlock_irqrestore(&dev->isr_lock, irqsave_flags);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t ep_pcie_handle_pm_turnoff_irq(int irq, void *data)
+{
+ struct ep_pcie_dev_t *dev = data;
+ unsigned long irqsave_flags;
+
+ spin_lock_irqsave(&dev->isr_lock, irqsave_flags);
+
+ dev->pm_to_counter++;
+ EP_PCIE_DBG2(dev,
+ "PCIe V%d: No. %ld PM_TURNOFF is received.\n",
+ dev->rev, dev->pm_to_counter);
+ EP_PCIE_DBG2(dev, "PCIe V%d: Put the link into L23.\n", dev->rev);
+ ep_pcie_write_mask(dev->parf + PCIE20_PARF_PM_CTRL, 0, BIT(2));
+
+ spin_unlock_irqrestore(&dev->isr_lock, irqsave_flags);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t ep_pcie_handle_dstate_change_irq(int irq, void *data)
+{
+ struct ep_pcie_dev_t *dev = data;
+ unsigned long irqsave_flags;
+ u32 dstate;
+
+ spin_lock_irqsave(&dev->isr_lock, irqsave_flags);
+
+ dstate = readl_relaxed(dev->dm_core +
+ PCIE20_CON_STATUS) & 0x3;
+
+ if (dev->dump_conf)
+ ep_pcie_reg_dump(dev, BIT(EP_PCIE_RES_DM_CORE), false);
+
+ if (dstate == 3) {
+ dev->d3_counter++;
+ EP_PCIE_DBG(dev,
+ "PCIe V%d: No. %ld change to D3 state.\n",
+ dev->rev, dev->d3_counter);
+ ep_pcie_write_mask(dev->parf + PCIE20_PARF_PM_CTRL, 0, BIT(1));
+ ep_pcie_notify_event(dev, EP_PCIE_EVENT_PM_D3_HOT);
+ } else if (dstate == 0) {
+ dev->d0_counter++;
+ EP_PCIE_DBG(dev,
+ "PCIe V%d: No. %ld change to D0 state.\n",
+ dev->rev, dev->d0_counter);
+ ep_pcie_notify_event(dev, EP_PCIE_EVENT_PM_D0);
+ } else {
+ EP_PCIE_ERR(dev,
+ "PCIe V%d:invalid D state change to 0x%x.\n",
+ dev->rev, dstate);
+ }
+
+ spin_unlock_irqrestore(&dev->isr_lock, irqsave_flags);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t ep_pcie_handle_perst_irq(int irq, void *data)
+{
+ struct ep_pcie_dev_t *dev = data;
+ unsigned long irqsave_flags;
+ u32 perst;
+
+ spin_lock_irqsave(&dev->isr_lock, irqsave_flags);
+
+ perst = gpio_get_value(dev->gpio[EP_PCIE_GPIO_PERST].num);
+
+ if (!dev->enumerated) {
+ EP_PCIE_DBG(dev,
+ "PCIe V%d: PCIe is not enumerated yet; PERST is %sasserted.\n",
+ dev->rev, perst ? "de" : "");
+ goto out;
+ }
+
+ if (perst) {
+ dev->perst_deast = true;
+ dev->perst_deast_counter++;
+ EP_PCIE_DBG(dev,
+ "PCIe V%d: No. %ld PERST deassertion.\n",
+ dev->rev, dev->perst_deast_counter);
+ ep_pcie_notify_event(dev, EP_PCIE_EVENT_PM_RST_DEAST);
+ } else {
+ dev->perst_deast = false;
+ dev->perst_ast_counter++;
+ EP_PCIE_DBG(dev,
+ "PCIe V%d: No. %ld PERST assertion.\n",
+ dev->rev, dev->perst_ast_counter);
+ ep_pcie_notify_event(dev, EP_PCIE_EVENT_PM_D3_COLD);
+ }
+
+out:
+ spin_unlock_irqrestore(&dev->isr_lock, irqsave_flags);
+
+ return IRQ_HANDLED;
+}
+
+int32_t ep_pcie_irq_init(struct ep_pcie_dev_t *dev)
+{
+ int ret;
+ struct device *pdev = &dev->pdev->dev;
+ u32 perst_irq;
+
+ EP_PCIE_DBG(dev, "PCIe V%d\n", dev->rev);
+
+ /* register handler for linkdown interrupt */
+ ret = devm_request_irq(pdev,
+ dev->irq[EP_PCIE_INT_LINK_DOWN].num,
+ ep_pcie_handle_linkdown_irq,
+ IRQF_TRIGGER_RISING, dev->irq[EP_PCIE_INT_LINK_DOWN].name,
+ dev);
+ if (ret) {
+ EP_PCIE_ERR(dev,
+ "PCIe V%d: Unable to request linkdown interrupt %d\n",
+ dev->rev, dev->irq[EP_PCIE_INT_LINK_DOWN].num);
+ return ret;
+ }
+
+ /* register handler for linkup interrupt */
+ ret = devm_request_irq(pdev,
+ dev->irq[EP_PCIE_INT_LINK_UP].num, ep_pcie_handle_linkup_irq,
+ IRQF_TRIGGER_RISING, dev->irq[EP_PCIE_INT_LINK_UP].name,
+ dev);
+ if (ret) {
+ EP_PCIE_ERR(dev,
+ "PCIe V%d: Unable to request linkup interrupt %d\n",
+ dev->rev, dev->irq[EP_PCIE_INT_LINK_UP].num);
+ return ret;
+ }
+
+ /* register handler for PM_TURNOFF interrupt */
+ ret = devm_request_irq(pdev,
+ dev->irq[EP_PCIE_INT_PM_TURNOFF].num,
+ ep_pcie_handle_pm_turnoff_irq,
+ IRQF_TRIGGER_RISING, dev->irq[EP_PCIE_INT_PM_TURNOFF].name,
+ dev);
+ if (ret) {
+ EP_PCIE_ERR(dev,
+ "PCIe V%d: Unable to request PM_TURNOFF interrupt %d\n",
+ dev->rev, dev->irq[EP_PCIE_INT_PM_TURNOFF].num);
+ return ret;
+ }
+
+ /* register handler for D state change interrupt */
+ ret = devm_request_irq(pdev,
+ dev->irq[EP_PCIE_INT_DSTATE_CHANGE].num,
+ ep_pcie_handle_dstate_change_irq,
+ IRQF_TRIGGER_RISING, dev->irq[EP_PCIE_INT_DSTATE_CHANGE].name,
+ dev);
+ if (ret) {
+ EP_PCIE_ERR(dev,
+ "PCIe V%d: Unable to request D state change interrupt %d\n",
+ dev->rev, dev->irq[EP_PCIE_INT_DSTATE_CHANGE].num);
+ return ret;
+ }
+
+ /* register handler for PERST interrupt */
+ perst_irq = gpio_to_irq(dev->gpio[EP_PCIE_GPIO_PERST].num);
+ ret = devm_request_irq(pdev, perst_irq,
+ ep_pcie_handle_perst_irq,
+ IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
+ "ep_pcie_perst", dev);
+ if (ret) {
+ EP_PCIE_ERR(dev,
+ "PCIe V%d: Unable to request PERST interrupt %d\n",
+ dev->rev, perst_irq);
+ return ret;
+ }
+
+ ret = enable_irq_wake(perst_irq);
+ if (ret) {
+ EP_PCIE_ERR(dev,
+ "PCIe V%d: Unable to enable PERST interrupt %d\n",
+ dev->rev, perst_irq);
+ return ret;
+ }
+
+ return 0;
+}
+
+void ep_pcie_irq_deinit(struct ep_pcie_dev_t *dev)
+{
+ EP_PCIE_DBG(dev, "PCIe V%d\n", dev->rev);
+
+ disable_irq(gpio_to_irq(dev->gpio[EP_PCIE_GPIO_PERST].num));
+}
+
+int ep_pcie_core_register_event(struct ep_pcie_register_event *reg)
+{
+ if (!reg) {
+ EP_PCIE_ERR(&ep_pcie_dev,
+ "PCIe V%d: Event registration is NULL\n",
+ ep_pcie_dev.rev);
+ return -ENODEV;
+ }
+
+ if (!reg->user) {
+ EP_PCIE_ERR(&ep_pcie_dev,
+ "PCIe V%d: User of event registration is NULL\n",
+ ep_pcie_dev.rev);
+ return -ENODEV;
+ }
+
+ ep_pcie_dev.event_reg = reg;
+ EP_PCIE_DBG(&ep_pcie_dev,
+ "PCIe V%d: Event 0x%x is registered\n",
+ ep_pcie_dev.rev, reg->events);
+
+ return 0;
+}
+
+int ep_pcie_core_deregister_event(void)
+{
+ if (ep_pcie_dev.event_reg) {
+ EP_PCIE_DBG(&ep_pcie_dev,
+ "PCIe V%d: current registered events:0x%x; events are deregistered.\n",
+ ep_pcie_dev.rev, ep_pcie_dev.event_reg->events);
+ ep_pcie_dev.event_reg = NULL;
+ } else {
+ EP_PCIE_ERR(&ep_pcie_dev,
+ "PCIe V%d: Event registration is NULL\n",
+ ep_pcie_dev.rev);
+ }
+
+ return 0;
+}
+
+enum ep_pcie_link_status ep_pcie_core_get_linkstatus(void)
+{
+ struct ep_pcie_dev_t *dev = &ep_pcie_dev;
+
+ if (!dev->power_on || (dev->link_status == EP_PCIE_LINK_DISABLED)) {
+ EP_PCIE_DBG(dev,
+ "PCIe V%d: PCIe endpoint is not powered on.\n",
+ dev->rev);
+ return EP_PCIE_LINK_DISABLED;
+ } else {
+ u32 bme = readl_relaxed(dev->dm_core +
+ PCIE20_COMMAND_STATUS) & BIT(2);
+ if (bme) {
+ EP_PCIE_DBG(dev,
+ "PCIe V%d: PCIe link is up and BME is enabled; current SW link status:%d.\n",
+ dev->rev, dev->link_status);
+ dev->link_status = EP_PCIE_LINK_ENABLED;
+ } else {
+ EP_PCIE_DBG(dev,
+ "PCIe V%d: PCIe link is up but BME is disabled; current SW link status:%d.\n",
+ dev->rev, dev->link_status);
+ dev->link_status = EP_PCIE_LINK_UP;
+ }
+ return dev->link_status;
+ }
+}
+
+int ep_pcie_core_config_outbound_iatu(struct ep_pcie_iatu entries[],
+ u32 num_entries)
+{
+ u32 data_start = 0;
+ u32 data_end = 0;
+ u32 data_tgt_lower = 0;
+ u32 data_tgt_upper = 0;
+ u32 ctrl_start = 0;
+ u32 ctrl_end = 0;
+ u32 ctrl_tgt_lower = 0;
+ u32 ctrl_tgt_upper = 0;
+
+ if ((num_entries > MAX_IATU_ENTRY_NUM) || !num_entries) {
+ EP_PCIE_ERR(&ep_pcie_dev,
+ "PCIe V%d: Wrong iATU entry number %d.\n",
+ ep_pcie_dev.rev, num_entries);
+ return EP_PCIE_ERROR;
+ }
+
+ data_start = entries[0].start;
+ data_end = entries[0].end;
+ data_tgt_lower = entries[0].tgt_lower;
+ data_tgt_upper = entries[0].tgt_upper;
+
+ if (num_entries > 1) {
+ ctrl_start = entries[1].start;
+ ctrl_end = entries[1].end;
+ ctrl_tgt_lower = entries[1].tgt_lower;
+ ctrl_tgt_upper = entries[1].tgt_upper;
+ }
+
+ EP_PCIE_DBG(&ep_pcie_dev,
+ "PCIe V%d: data_start:0x%x; data_end:0x%x; data_tgt_lower:0x%x; data_tgt_upper:0x%x; ctrl_start:0x%x; ctrl_end:0x%x; ctrl_tgt_lower:0x%x; ctrl_tgt_upper:0x%x.\n",
+ ep_pcie_dev.rev, data_start, data_end, data_tgt_lower,
+ data_tgt_upper, ctrl_start, ctrl_end, ctrl_tgt_lower,
+ ctrl_tgt_upper);
+
+
+ if ((ctrl_end < data_start) || (data_end < ctrl_start)) {
+ EP_PCIE_DBG(&ep_pcie_dev,
+ "PCIe V%d: iATU configuration case No. 1: detached.\n",
+ ep_pcie_dev.rev);
+ ep_pcie_config_outbound_iatu_entry(&ep_pcie_dev,
+ EP_PCIE_OATU_INDEX_DATA,
+ data_start, data_end,
+ data_tgt_lower, data_tgt_upper);
+ ep_pcie_config_outbound_iatu_entry(&ep_pcie_dev,
+ EP_PCIE_OATU_INDEX_CTRL,
+ ctrl_start, ctrl_end,
+ ctrl_tgt_lower, ctrl_tgt_upper);
+ } else if ((data_start <= ctrl_start) && (ctrl_end <= data_end)) {
+ EP_PCIE_DBG(&ep_pcie_dev,
+ "PCIe V%d: iATU configuration case No. 2: included.\n",
+ ep_pcie_dev.rev);
+ ep_pcie_config_outbound_iatu_entry(&ep_pcie_dev,
+ EP_PCIE_OATU_INDEX_DATA,
+ data_start, data_end,
+ data_tgt_lower, data_tgt_upper);
+ } else {
+ EP_PCIE_DBG(&ep_pcie_dev,
+ "PCIe V%d: iATU configuration case No. 3: overlap.\n",
+ ep_pcie_dev.rev);
+ ep_pcie_config_outbound_iatu_entry(&ep_pcie_dev,
+ EP_PCIE_OATU_INDEX_CTRL,
+ ctrl_start, ctrl_end,
+ ctrl_tgt_lower, ctrl_tgt_upper);
+ ep_pcie_config_outbound_iatu_entry(&ep_pcie_dev,
+ EP_PCIE_OATU_INDEX_DATA,
+ data_start, data_end,
+ data_tgt_lower, data_tgt_upper);
+ }
+
+ return 0;
+}
+
+int ep_pcie_core_get_msi_config(struct ep_pcie_msi_config *cfg)
+{
+ u32 cap, lower, upper, data;
+ static u32 changes;
+
+ if (ep_pcie_dev.link_status == EP_PCIE_LINK_DISABLED) {
+ EP_PCIE_ERR(&ep_pcie_dev,
+ "PCIe V%d: PCIe link is currently disabled.\n",
+ ep_pcie_dev.rev);
+ return EP_PCIE_ERROR;
+ }
+
+ cap = readl_relaxed(ep_pcie_dev.dm_core + PCIE20_MSI_CAP_ID_NEXT_CTRL);
+ EP_PCIE_DBG(&ep_pcie_dev, "PCIe V%d: MSI CAP:0x%x\n",
+ ep_pcie_dev.rev, cap);
+
+ if (!(cap & BIT(16))) {
+ EP_PCIE_ERR(&ep_pcie_dev,
+ "PCIe V%d: MSI is not enabled yet.\n",
+ ep_pcie_dev.rev);
+ return EP_PCIE_ERROR;
+ }
+
+ lower = readl_relaxed(ep_pcie_dev.dm_core + PCIE20_MSI_LOWER);
+ upper = readl_relaxed(ep_pcie_dev.dm_core + PCIE20_MSI_UPPER);
+ data = readl_relaxed(ep_pcie_dev.dm_core + PCIE20_MSI_DATA);
+
+ EP_PCIE_DBG(&ep_pcie_dev,
+ "PCIe V%d: MSI info: lower:0x%x; upper:0x%x; data:0x%x.\n",
+ ep_pcie_dev.rev, lower, upper, data);
+
+ if (lower && data) {
+ struct resource *msi =
+ ep_pcie_dev.res[EP_PCIE_RES_MSI].resource;
+ ep_pcie_config_outbound_iatu_entry(&ep_pcie_dev,
+ EP_PCIE_OATU_INDEX_MSI,
+ msi->start, msi->end,
+ lower, upper);
+ cfg->lower = msi->start + (lower & 0xfff);
+ cfg->upper = 0;
+ cfg->data = data;
+ cfg->msg_num = (cap >> 20) & 0x7;
+ if ((lower != ep_pcie_dev.msi_cfg.lower)
+ || (upper != ep_pcie_dev.msi_cfg.upper)
+ || (data != ep_pcie_dev.msi_cfg.data)
+ || (cfg->msg_num != ep_pcie_dev.msi_cfg.msg_num)) {
+ changes++;
+ EP_PCIE_DBG(&ep_pcie_dev,
+ "PCIe V%d: MSI config has been changed by host side for %d time(s).\n",
+ ep_pcie_dev.rev, changes);
+ EP_PCIE_DBG(&ep_pcie_dev,
+ "PCIe V%d: old MSI cfg: lower:0x%x; upper:0x%x; data:0x%x; msg_num:0x%x.\n",
+ ep_pcie_dev.rev, ep_pcie_dev.msi_cfg.lower,
+ ep_pcie_dev.msi_cfg.upper,
+ ep_pcie_dev.msi_cfg.data,
+ ep_pcie_dev.msi_cfg.msg_num);
+ ep_pcie_dev.msi_cfg.lower = lower;
+ ep_pcie_dev.msi_cfg.upper = upper;
+ ep_pcie_dev.msi_cfg.data = data;
+ ep_pcie_dev.msi_cfg.msg_num = cfg->msg_num;
+ }
+ return 0;
+ } else {
+ EP_PCIE_ERR(&ep_pcie_dev,
+ "PCIe V%d: Wrong MSI info found when MSI is enabled: lower:0x%x; data:0x%x.\n",
+ ep_pcie_dev.rev, lower, data);
+ return EP_PCIE_ERROR;
+ }
+}
+
+int ep_pcie_core_trigger_msi(u32 idx)
+{
+ u32 addr, data;
+
+ if (ep_pcie_dev.link_status == EP_PCIE_LINK_DISABLED) {
+ EP_PCIE_ERR(&ep_pcie_dev,
+ "PCIe V%d: PCIe link is currently disabled.\n",
+ ep_pcie_dev.rev);
+ return EP_PCIE_ERROR;
+ }
+
+ addr = readl_relaxed(ep_pcie_dev.dm_core + PCIE20_MSI_LOWER);
+ data = readl_relaxed(ep_pcie_dev.dm_core + PCIE20_MSI_DATA);
+
+ if (addr && data) {
+ EP_PCIE_DUMP(&ep_pcie_dev,
+ "PCIe V%d: No. %ld MSI fired for IRQ %d; index from client:%d\n",
+ ep_pcie_dev.rev, ep_pcie_dev.msi_counter++,
+ data + idx, idx);
+ ep_pcie_write_reg(ep_pcie_dev.msi, addr & 0xfff, data + idx);
+ return 0;
+ } else {
+ EP_PCIE_ERR(&ep_pcie_dev,
+ "PCIe V%d: Wrong MSI info found. MSI addr:0x%x; data:0x%x; index from client:%d.\n",
+ ep_pcie_dev.rev, addr, data, idx);
+ return EP_PCIE_ERROR;
+ }
+}
+
+int ep_pcie_core_wakeup_host(void)
+{
+ struct ep_pcie_dev_t *dev = &ep_pcie_dev;
+
+ if (dev->perst_deast) {
+ EP_PCIE_ERR(dev,
+ "PCIe V%d: request to assert WAKE# when PERST is de-asserted.\n",
+ dev->rev);
+ return EP_PCIE_ERROR;
+ } else {
+ EP_PCIE_DBG(dev, "PCIe V%d: No. %ld to assert PCIe WAKE#.\n",
+ dev->rev, ++dev->wake_counter);
+ gpio_set_value(dev->gpio[EP_PCIE_GPIO_WAKE].num,
+ 1 - dev->gpio[EP_PCIE_GPIO_WAKE].on);
+ gpio_set_value(dev->gpio[EP_PCIE_GPIO_WAKE].num,
+ dev->gpio[EP_PCIE_GPIO_WAKE].on);
+ return 0;
+ }
+}
+
+int ep_pcie_core_config_db_routing(struct ep_pcie_db_config chdb_cfg,
+ struct ep_pcie_db_config erdb_cfg)
+{
+ u32 dbs = (erdb_cfg.end << 24) | (erdb_cfg.base << 16) |
+ (chdb_cfg.end << 8) | chdb_cfg.base;
+
+ ep_pcie_write_reg(ep_pcie_dev.parf, PCIE20_PARF_MHI_IPA_DBS, dbs);
+ ep_pcie_write_reg(ep_pcie_dev.parf,
+ PCIE20_PARF_MHI_IPA_CDB_TARGET_LOWER,
+ chdb_cfg.tgt_addr);
+ ep_pcie_write_reg(ep_pcie_dev.parf,
+ PCIE20_PARF_MHI_IPA_EDB_TARGET_LOWER,
+ erdb_cfg.tgt_addr);
+
+ EP_PCIE_DBG(&ep_pcie_dev,
+ "PCIe V%d: DB routing info: chdb_cfg.base:0x%x; chdb_cfg.end:0x%x; erdb_cfg.base:0x%x; erdb_cfg.end:0x%x; chdb_cfg.tgt_addr:0x%x; erdb_cfg.tgt_addr:0x%x.\n",
+ ep_pcie_dev.rev, chdb_cfg.base, chdb_cfg.end, erdb_cfg.base,
+ erdb_cfg.end, chdb_cfg.tgt_addr, erdb_cfg.tgt_addr);
+
+ return 0;
+}
+
+static struct ep_pcie_hw hw_drv = {
+ .register_event = ep_pcie_core_register_event,
+ .deregister_event = ep_pcie_core_deregister_event,
+ .get_linkstatus = ep_pcie_core_get_linkstatus,
+ .config_outbound_iatu = ep_pcie_core_config_outbound_iatu,
+ .get_msi_config = ep_pcie_core_get_msi_config,
+ .trigger_msi = ep_pcie_core_trigger_msi,
+ .wakeup_host = ep_pcie_core_wakeup_host,
+ .config_db_routing = ep_pcie_core_config_db_routing,
+ .enable_endpoint = ep_pcie_core_enable_endpoint,
+ .disable_endpoint = ep_pcie_core_disable_endpoint,
+};
+
+static int ep_pcie_probe(struct platform_device *pdev)
+{
+ int ret;
+
+ pr_debug("%s\n", __func__);
+
+ ep_pcie_dev.link_speed = 1;
+ ret = of_property_read_u32((&pdev->dev)->of_node,
+ "qcom,pcie-link-speed",
+ &ep_pcie_dev.link_speed);
+ if (ret)
+ EP_PCIE_DBG(&ep_pcie_dev,
+ "PCIe V%d: pcie-link-speed does not exist.\n",
+ ep_pcie_dev.rev);
+ else
+ EP_PCIE_DBG(&ep_pcie_dev, "PCIe V%d: pcie-link-speed:%d.\n",
+ ep_pcie_dev.rev, ep_pcie_dev.link_speed);
+
+ ep_pcie_dev.phy_rev = 1;
+ ret = of_property_read_u32((&pdev->dev)->of_node,
+ "qcom,pcie-phy-ver",
+ &ep_pcie_dev.phy_rev);
+ if (ret)
+ EP_PCIE_DBG(&ep_pcie_dev,
+ "PCIe V%d: pcie-phy-ver does not exist.\n",
+ ep_pcie_dev.rev);
+ else
+ EP_PCIE_DBG(&ep_pcie_dev, "PCIe V%d: pcie-phy-ver:%d.\n",
+ ep_pcie_dev.rev, ep_pcie_dev.phy_rev);
+
+ ep_pcie_dev.rev = 1503191;
+ ep_pcie_dev.pdev = pdev;
+ memcpy(ep_pcie_dev.vreg, ep_pcie_vreg_info,
+ sizeof(ep_pcie_vreg_info));
+ memcpy(ep_pcie_dev.gpio, ep_pcie_gpio_info,
+ sizeof(ep_pcie_gpio_info));
+ memcpy(ep_pcie_dev.clk, ep_pcie_clk_info,
+ sizeof(ep_pcie_clk_info));
+ memcpy(ep_pcie_dev.pipeclk, ep_pcie_pipe_clk_info,
+ sizeof(ep_pcie_pipe_clk_info));
+ memcpy(ep_pcie_dev.res, ep_pcie_res_info,
+ sizeof(ep_pcie_res_info));
+ memcpy(ep_pcie_dev.irq, ep_pcie_irq_info,
+ sizeof(ep_pcie_irq_info));
+
+ ret = ep_pcie_get_resources(&ep_pcie_dev,
+ ep_pcie_dev.pdev);
+ if (ret) {
+ EP_PCIE_ERR(&ep_pcie_dev,
+ "PCIe V%d: failed to get resources.\n",
+ ep_pcie_dev.rev);
+ goto res_failure;
+ }
+
+ ret = ep_pcie_gpio_init(&ep_pcie_dev);
+ if (ret) {
+ EP_PCIE_ERR(&ep_pcie_dev,
+ "PCIe V%d: failed to init GPIO.\n",
+ ep_pcie_dev.rev);
+ ep_pcie_release_resources(&ep_pcie_dev);
+ goto gpio_failure;
+ }
+
+ ret = ep_pcie_irq_init(&ep_pcie_dev);
+ if (ret) {
+ EP_PCIE_ERR(&ep_pcie_dev,
+ "PCIe V%d: failed to init IRQ.\n",
+ ep_pcie_dev.rev);
+ ep_pcie_release_resources(&ep_pcie_dev);
+ ep_pcie_gpio_deinit(&ep_pcie_dev);
+ goto irq_failure;
+ }
+
+ EP_PCIE_DBG(&ep_pcie_dev,
+ "PCIe V%d: %s got resources successfully; start turning on the link.\n",
+ ep_pcie_dev.rev, dev_name(&(pdev->dev)));
+
+ ret = ep_pcie_core_enable_endpoint(EP_PCIE_OPT_ALL);
+
+ if (ret) {
+ EP_PCIE_ERR(&ep_pcie_dev,
+ "PCIe V%d: PCIe link failed to be enabled during probe.\n",
+ ep_pcie_dev.rev);
+ goto ep_enable_failure;
+ } else {
+ EP_PCIE_INFO(&ep_pcie_dev,
+ "PCIe V%d: PCIe link is enabled during probe.\n",
+ ep_pcie_dev.rev);
+
+ ep_pcie_dev.enumerated = true;
+
+ hw_drv.device_id = readl_relaxed(ep_pcie_dev.dm_core);
+ EP_PCIE_DBG(&ep_pcie_dev,
+ "PCIe V%d: register driver for device 0x%x.\n",
+ ep_pcie_dev.rev, hw_drv.device_id);
+ ep_pcie_register_drv(&hw_drv);
+
+ ep_pcie_notify_event(&ep_pcie_dev, EP_PCIE_EVENT_LINKUP);
+
+ return 0;
+ }
+
+ep_enable_failure:
+ ep_pcie_irq_deinit(&ep_pcie_dev);
+irq_failure:
+ ep_pcie_gpio_deinit(&ep_pcie_dev);
+gpio_failure:
+ ep_pcie_release_resources(&ep_pcie_dev);
+res_failure:
+ EP_PCIE_ERR(&ep_pcie_dev, "PCIe V%d: Driver probe failed:%d\n",
+ ep_pcie_dev.rev, ret);
+
+ return ret;
+}
+
+static int __exit ep_pcie_remove(struct platform_device *pdev)
+{
+ pr_debug("%s\n", __func__);
+
+ ep_pcie_irq_deinit(&ep_pcie_dev);
+ ep_pcie_vreg_deinit(&ep_pcie_dev);
+ ep_pcie_pipe_clk_deinit(&ep_pcie_dev);
+ ep_pcie_clk_deinit(&ep_pcie_dev);
+ ep_pcie_gpio_deinit(&ep_pcie_dev);
+ ep_pcie_release_resources(&ep_pcie_dev);
+ ep_pcie_deregister_drv(&hw_drv);
+
+ return 0;
+}
+
+static struct of_device_id ep_pcie_match[] = {
+ { .compatible = "qcom,pcie-ep",
+ },
+ {}
+};
+
+static struct platform_driver ep_pcie_driver = {
+ .probe = ep_pcie_probe,
+ .remove = ep_pcie_remove,
+ .driver = {
+ .name = "pcie-ep",
+ .owner = THIS_MODULE,
+ .of_match_table = ep_pcie_match,
+ },
+};
+
+static int __init ep_pcie_init(void)
+{
+ int ret;
+ char logname[MAX_NAME_LEN];
+
+ pr_debug("%s\n", __func__);
+
+ snprintf(logname, MAX_NAME_LEN, "ep-pcie-long");
+ ep_pcie_dev.ipc_log_sel =
+ ipc_log_context_create(EP_PCIE_LOG_PAGES, logname);
+ if (ep_pcie_dev.ipc_log_sel == NULL)
+ pr_err("%s: unable to create IPC selected log for %s\n",
+ __func__, logname);
+ else
+ EP_PCIE_DBG(&ep_pcie_dev,
+ "PCIe V%d: IPC selected logging is enable for %s\n",
+ ep_pcie_dev.rev, logname);
+
+ snprintf(logname, MAX_NAME_LEN, "ep-pcie-short");
+ ep_pcie_dev.ipc_log_ful =
+ ipc_log_context_create(EP_PCIE_LOG_PAGES * 2, logname);
+ if (ep_pcie_dev.ipc_log_ful == NULL)
+ pr_err("%s: unable to create IPC detailed log for %s\n",
+ __func__, logname);
+ else
+ EP_PCIE_DBG(&ep_pcie_dev,
+ "PCIe V%d: IPC detailed logging is enable for %s\n",
+ ep_pcie_dev.rev, logname);
+
+ snprintf(logname, MAX_NAME_LEN, "ep-pcie-dump");
+ ep_pcie_dev.ipc_log_dump =
+ ipc_log_context_create(EP_PCIE_LOG_PAGES, logname);
+ if (ep_pcie_dev.ipc_log_dump == NULL)
+ pr_err("%s: unable to create IPC dump log for %s\n",
+ __func__, logname);
+ else
+ EP_PCIE_DBG(&ep_pcie_dev,
+ "PCIe V%d: IPC dump logging is enable for %s\n",
+ ep_pcie_dev.rev, logname);
+
+ mutex_init(&ep_pcie_dev.setup_mtx);
+ mutex_init(&ep_pcie_dev.ext_mtx);
+ spin_lock_init(&ep_pcie_dev.ext_lock);
+ spin_lock_init(&ep_pcie_dev.isr_lock);
+
+ ep_pcie_debugfs_init(&ep_pcie_dev);
+
+ ret = platform_driver_register(&ep_pcie_driver);
+
+ if (ret)
+ EP_PCIE_ERR(&ep_pcie_dev,
+ "PCIe V%d: failed register platform driver:%d\n",
+ ep_pcie_dev.rev, ret);
+ else
+ EP_PCIE_DBG(&ep_pcie_dev,
+ "PCIe V%d: platform driver is registered.\n",
+ ep_pcie_dev.rev);
+
+ return ret;
+}
+
+static void __exit ep_pcie_exit(void)
+{
+ pr_debug("%s\n", __func__);
+
+ ipc_log_context_destroy(ep_pcie_dev.ipc_log_sel);
+ ipc_log_context_destroy(ep_pcie_dev.ipc_log_ful);
+ ipc_log_context_destroy(ep_pcie_dev.ipc_log_dump);
+
+ ep_pcie_debugfs_exit();
+
+ platform_driver_unregister(&ep_pcie_driver);
+}
+
+module_init(ep_pcie_init);
+module_exit(ep_pcie_exit);
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("MSM PCIe Endpoint Driver");
diff --git a/drivers/platform/msm/ep_pcie/ep_pcie_dbg.c b/drivers/platform/msm/ep_pcie/ep_pcie_dbg.c
new file mode 100644
index 000000000000..900b33b3554d
--- /dev/null
+++ b/drivers/platform/msm/ep_pcie/ep_pcie_dbg.c
@@ -0,0 +1,466 @@
+/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * Debugging enhancement in MSM PCIe endpoint driver.
+ */
+
+#include <linux/bitops.h>
+#include <linux/kernel.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/debugfs.h>
+#include "ep_pcie_com.h"
+#include "ep_pcie_phy.h"
+
+static struct dentry *dent_ep_pcie;
+static struct dentry *dfile_case;
+static struct ep_pcie_dev_t *dev;
+
+static void ep_pcie_phy_dump(struct ep_pcie_dev_t *dev)
+{
+ int i;
+ int control_offset[6] = {0x60, 0x70, 0x80, 0xA0, 0xB0, 0xB0};
+
+ EP_PCIE_DUMP(dev, "PCIe V%d: PHY testbus\n", dev->rev);
+
+ for (i = 0; i < 6; i++) {
+ switch (i) {
+ case 3:
+ ep_pcie_write_reg(dev->phy,
+ QSERDES_COM_ATB_SEL2,
+ 0x10);
+ EP_PCIE_DUMP(dev,
+ "PCIe V%d: QSERDES_COM_ATB_SEL2: 0x%x\n",
+ dev->rev,
+ readl_relaxed(dev->phy + QSERDES_COM_ATB_SEL2));
+ break;
+ case 4:
+ ep_pcie_write_reg(dev->phy,
+ QSERDES_TX_SERDES_BYP_EN_OUT,
+ 0x10);
+ EP_PCIE_DUMP(dev,
+ "PCIe V%d: QSERDES_TX_SERDES_BYP_EN_OUT: 0x%x\n",
+ dev->rev,
+ readl_relaxed(dev->phy +
+ QSERDES_TX_SERDES_BYP_EN_OUT));
+ break;
+ case 5:
+ ep_pcie_write_reg(dev->phy,
+ QSERDES_TX_SERDES_BYP_EN_OUT,
+ 0x30);
+ EP_PCIE_DUMP(dev,
+ "PCIe V%d: QSERDES_TX_SERDES_BYP_EN_OUT: 0x%x\n",
+ dev->rev,
+ readl_relaxed(dev->phy +
+ QSERDES_TX_SERDES_BYP_EN_OUT));
+ break;
+ default:
+ break;
+ }
+
+ ep_pcie_write_reg(dev->phy, PCIE_PHY_TEST_CONTROL,
+ control_offset[i]);
+
+ EP_PCIE_DUMP(dev,
+ "PCIe V%d: PCIE_PHY_TEST_CONTROL: 0x%x\n",
+ dev->rev,
+ readl_relaxed(dev->phy + PCIE_PHY_TEST_CONTROL));
+ EP_PCIE_DUMP(dev,
+ "PCIe V%d: PCIE_PHY_DEBUG_BUS_0_STATUS: 0x%x\n",
+ dev->rev,
+ readl_relaxed(dev->phy + PCIE_PHY_DEBUG_BUS_0_STATUS));
+ EP_PCIE_DUMP(dev,
+ "PCIe V%d: PCIE_PHY_DEBUG_BUS_1_STATUS: 0x%x\n",
+ dev->rev,
+ readl_relaxed(dev->phy + PCIE_PHY_DEBUG_BUS_1_STATUS));
+ EP_PCIE_DUMP(dev,
+ "PCIe V%d: PCIE_PHY_DEBUG_BUS_2_STATUS: 0x%x\n",
+ dev->rev,
+ readl_relaxed(dev->phy + PCIE_PHY_DEBUG_BUS_2_STATUS));
+ EP_PCIE_DUMP(dev,
+ "PCIe V%d: PCIE_PHY_DEBUG_BUS_3_STATUS: 0x%x\n",
+ dev->rev,
+ readl_relaxed(dev->phy + PCIE_PHY_DEBUG_BUS_3_STATUS));
+ }
+
+ EP_PCIE_DUMP(dev, "PCIe V%d: PHY register dump\n", dev->rev);
+
+ EP_PCIE_DUMP(dev, "PCIe V%d: QSERDES_COM_PLL_VCO_HIGH: 0x%x\n",
+ dev->rev, readl_relaxed(dev->phy + QSERDES_COM_PLL_VCO_HIGH));
+ EP_PCIE_DUMP(dev, "PCIe V%d: QSERDES_COM_RESET_SM: 0x%x\n",
+ dev->rev, readl_relaxed(dev->phy + QSERDES_COM_RESET_SM));
+ EP_PCIE_DUMP(dev, "PCIe V%d: QSERDES_COM_MUXVAL: 0x%x\n",
+ dev->rev, readl_relaxed(dev->phy + QSERDES_COM_MUXVAL));
+ EP_PCIE_DUMP(dev, "PCIe V%d: QSERDES_RX_PI_CTRL1: 0x%x\n",
+ dev->rev, readl_relaxed(dev->phy + QSERDES_RX_PI_CTRL1));
+ EP_PCIE_DUMP(dev, "PCIe V%d: QSERDES_RX_PI_CTRL2: 0x%x\n",
+ dev->rev, readl_relaxed(dev->phy + QSERDES_RX_PI_CTRL2));
+ EP_PCIE_DUMP(dev, "PCIe V%d: QSERDES_RX_PI_QUAD: 0x%x\n",
+ dev->rev, readl_relaxed(dev->phy + QSERDES_RX_PI_QUAD));
+ EP_PCIE_DUMP(dev, "PCIe V%d: QSERDES_RX_IDATA1: 0x%x\n",
+ dev->rev, readl_relaxed(dev->phy + QSERDES_RX_IDATA1));
+ EP_PCIE_DUMP(dev, "PCIe V%d: QSERDES_RX_IDATA2: 0x%x\n",
+ dev->rev, readl_relaxed(dev->phy + QSERDES_RX_IDATA2));
+ EP_PCIE_DUMP(dev, "PCIe V%d: QSERDES_RX_AUX_DATA1: 0x%x\n",
+ dev->rev, readl_relaxed(dev->phy + QSERDES_RX_AUX_DATA1));
+ EP_PCIE_DUMP(dev, "PCIe V%d: QSERDES_RX_AUX_DATA2: 0x%x\n",
+ dev->rev, readl_relaxed(dev->phy + QSERDES_RX_AUX_DATA2));
+ EP_PCIE_DUMP(dev, "PCIe V%d: QSERDES_RX_AC_JTAG_OUTP: 0x%x\n",
+ dev->rev, readl_relaxed(dev->phy + QSERDES_RX_AC_JTAG_OUTP));
+ EP_PCIE_DUMP(dev, "PCIe V%d: QSERDES_RX_AC_JTAG_OUTN: 0x%x\n",
+ dev->rev, readl_relaxed(dev->phy + QSERDES_RX_AC_JTAG_OUTN));
+ EP_PCIE_DUMP(dev, "PCIe V%d: QSERDES_RX_RX_SIGDET: 0x%x\n",
+ dev->rev, readl_relaxed(dev->phy + QSERDES_RX_RX_SIGDET));
+ EP_PCIE_DUMP(dev, "PCIe V%d: QSERDES_RX_RX_VDCOFF: 0x%x\n",
+ dev->rev, readl_relaxed(dev->phy + QSERDES_RX_RX_VDCOFF));
+ EP_PCIE_DUMP(dev, "PCIe V%d: QSERDES_RX_IDAC_CAL_ON: 0x%x\n",
+ dev->rev, readl_relaxed(dev->phy + QSERDES_RX_IDAC_CAL_ON));
+ EP_PCIE_DUMP(dev, "PCIe V%d: QSERDES_RX_IDAC_STATUS_I: 0x%x\n",
+ dev->rev, readl_relaxed(dev->phy + QSERDES_RX_IDAC_STATUS_I));
+ EP_PCIE_DUMP(dev, "PCIe V%d: QSERDES_RX_IDAC_STATUS_Q: 0x%x\n",
+ dev->rev, readl_relaxed(dev->phy + QSERDES_RX_IDAC_STATUS_Q));
+ EP_PCIE_DUMP(dev, "PCIe V%d: QSERDES_RX_IDAC_STATUS_A: 0x%x\n",
+ dev->rev, readl_relaxed(dev->phy + QSERDES_RX_IDAC_STATUS_A));
+ EP_PCIE_DUMP(dev, "PCIe V%d: QSERDES_RX_CALST_STATUS_I: 0x%x\n",
+ dev->rev, readl_relaxed(dev->phy + QSERDES_RX_CALST_STATUS_I));
+ EP_PCIE_DUMP(dev, "PCIe V%d: QSERDES_RX_CALST_STATUS_Q: 0x%x\n",
+ dev->rev, readl_relaxed(dev->phy + QSERDES_RX_CALST_STATUS_Q));
+ EP_PCIE_DUMP(dev, "PCIe V%d: QSERDES_RX_CALST_STATUS_A: 0x%x\n",
+ dev->rev, readl_relaxed(dev->phy + QSERDES_RX_CALST_STATUS_A));
+ EP_PCIE_DUMP(dev, "PCIe V%d: QSERDES_RX_EOM_STATUS0: 0x%x\n",
+ dev->rev, readl_relaxed(dev->phy + QSERDES_RX_EOM_STATUS0));
+ EP_PCIE_DUMP(dev, "PCIe V%d: QSERDES_RX_EOM_STATUS1: 0x%x\n",
+ dev->rev, readl_relaxed(dev->phy + QSERDES_RX_EOM_STATUS1));
+ EP_PCIE_DUMP(dev, "PCIe V%d: QSERDES_RX_EOM_STATUS2: 0x%x\n",
+ dev->rev, readl_relaxed(dev->phy + QSERDES_RX_EOM_STATUS2));
+ EP_PCIE_DUMP(dev, "PCIe V%d: QSERDES_RX_EOM_STATUS3: 0x%x\n",
+ dev->rev, readl_relaxed(dev->phy + QSERDES_RX_EOM_STATUS3));
+ EP_PCIE_DUMP(dev, "PCIe V%d: QSERDES_RX_EOM_STATUS4: 0x%x\n",
+ dev->rev, readl_relaxed(dev->phy + QSERDES_RX_EOM_STATUS4));
+ EP_PCIE_DUMP(dev, "PCIe V%d: QSERDES_RX_EOM_STATUS5: 0x%x\n",
+ dev->rev, readl_relaxed(dev->phy + QSERDES_RX_EOM_STATUS5));
+ EP_PCIE_DUMP(dev, "PCIe V%d: QSERDES_RX_EOM_STATUS6: 0x%x\n",
+ dev->rev, readl_relaxed(dev->phy + QSERDES_RX_EOM_STATUS6));
+ EP_PCIE_DUMP(dev, "PCIe V%d: QSERDES_RX_EOM_STATUS7: 0x%x\n",
+ dev->rev, readl_relaxed(dev->phy + QSERDES_RX_EOM_STATUS7));
+ EP_PCIE_DUMP(dev, "PCIe V%d: QSERDES_RX_EOM_STATUS8: 0x%x\n",
+ dev->rev, readl_relaxed(dev->phy + QSERDES_RX_EOM_STATUS8));
+ EP_PCIE_DUMP(dev, "PCIe V%d: QSERDES_RX_EOM_STATUS9: 0x%x\n",
+ dev->rev, readl_relaxed(dev->phy + QSERDES_RX_EOM_STATUS9));
+ EP_PCIE_DUMP(dev, "PCIe V%d: QSERDES_RX_RX_ALOG_INTF_OBSV: 0x%x\n",
+ dev->rev, readl_relaxed(dev->phy + QSERDES_RX_RX_ALOG_INTF_OBSV));
+ EP_PCIE_DUMP(dev, "PCIe V%d: QSERDES_RX_READ_EQCODE: 0x%x\n",
+ dev->rev, readl_relaxed(dev->phy + QSERDES_RX_READ_EQCODE));
+ EP_PCIE_DUMP(dev, "PCIe V%d: QSERDES_RX_READ_OFFSETCODE: 0x%x\n",
+ dev->rev, readl_relaxed(dev->phy + QSERDES_RX_READ_OFFSETCODE));
+ EP_PCIE_DUMP(dev, "PCIe V%d: QSERDES_TX_BIST_STATUS: 0x%x\n",
+ dev->rev, readl_relaxed(dev->phy + QSERDES_TX_BIST_STATUS));
+ EP_PCIE_DUMP(dev, "PCIe V%d: QSERDES_TX_BIST_ERROR_COUNT1: 0x%x\n",
+ dev->rev, readl_relaxed(dev->phy + QSERDES_TX_BIST_ERROR_COUNT1));
+ EP_PCIE_DUMP(dev, "PCIe V%d: QSERDES_TX_BIST_ERROR_COUNT2: 0x%x\n",
+ dev->rev, readl_relaxed(dev->phy + QSERDES_TX_BIST_ERROR_COUNT2));
+ EP_PCIE_DUMP(dev, "PCIe V%d: QSERDES_TX_TX_ALOG_INTF_OBSV: 0x%x\n",
+ dev->rev, readl_relaxed(dev->phy + QSERDES_TX_TX_ALOG_INTF_OBSV));
+ EP_PCIE_DUMP(dev, "PCIe V%d: QSERDES_TX_PWM_DEC_STATUS: 0x%x\n",
+ dev->rev, readl_relaxed(dev->phy + QSERDES_TX_PWM_DEC_STATUS));
+ EP_PCIE_DUMP(dev, "PCIe V%d: PCIE_PHY_BIST_CHK_ERR_CNT_L: 0x%x\n",
+ dev->rev, readl_relaxed(dev->phy + PCIE_PHY_BIST_CHK_ERR_CNT_L));
+ EP_PCIE_DUMP(dev, "PCIe V%d: PCIE_PHY_BIST_CHK_ERR_CNT_H: 0x%x\n",
+ dev->rev, readl_relaxed(dev->phy + PCIE_PHY_BIST_CHK_ERR_CNT_H));
+ EP_PCIE_DUMP(dev, "PCIe V%d: PCIE_PHY_BIST_CHK_STATUS: 0x%x\n",
+ dev->rev, readl_relaxed(dev->phy + PCIE_PHY_BIST_CHK_STATUS));
+ EP_PCIE_DUMP(dev, "PCIe V%d: PCIE_PHY_LFPS_RXTERM_IRQ_SOURCE: 0x%x\n",
+ dev->rev, readl_relaxed(dev->phy + PCIE_PHY_LFPS_RXTERM_IRQ_SOURCE));
+ EP_PCIE_DUMP(dev, "PCIe V%d: PCIE_PHY_PCS_STATUS: 0x%x\n",
+ dev->rev, readl_relaxed(dev->phy + PCIE_PHY_PCS_STATUS));
+ EP_PCIE_DUMP(dev, "PCIe V%d: PCIE_PHY_PCS_STATUS2: 0x%x\n",
+ dev->rev, readl_relaxed(dev->phy + PCIE_PHY_PCS_STATUS2));
+ EP_PCIE_DUMP(dev, "PCIe V%d: PCIE_PHY_REVISION_ID0: 0x%x\n",
+ dev->rev, readl_relaxed(dev->phy + PCIE_PHY_REVISION_ID0));
+ EP_PCIE_DUMP(dev, "PCIe V%d: PCIE_PHY_REVISION_ID1: 0x%x\n",
+ dev->rev, readl_relaxed(dev->phy + PCIE_PHY_REVISION_ID1));
+ EP_PCIE_DUMP(dev, "PCIe V%d: PCIE_PHY_REVISION_ID2: 0x%x\n",
+ dev->rev, readl_relaxed(dev->phy + PCIE_PHY_REVISION_ID2));
+ EP_PCIE_DUMP(dev, "PCIe V%d: PCIE_PHY_REVISION_ID3: 0x%x\n",
+ dev->rev, readl_relaxed(dev->phy + PCIE_PHY_REVISION_ID3));
+}
+
+void ep_pcie_reg_dump(struct ep_pcie_dev_t *dev, u32 sel, bool linkdown)
+{
+ int r, i;
+ u32 original;
+ u32 size;
+
+ EP_PCIE_DBG(dev,
+ "PCIe V%d: Dump PCIe reg for 0x%x %s linkdown.\n",
+ dev->rev, sel, linkdown ? "with" : "without");
+
+ if (!dev->power_on) {
+ EP_PCIE_ERR(dev,
+ "PCIe V%d: the power is already down; can't dump registers.\n",
+ dev->rev);
+ return;
+ }
+
+ if (linkdown) {
+ EP_PCIE_DUMP(dev,
+ "PCIe V%d: dump PARF registers for linkdown case.\n",
+ dev->rev);
+
+ original = readl_relaxed(dev->parf + PCIE20_PARF_SYS_CTRL);
+ for (i = 1; i <= 0x1A; i++) {
+ ep_pcie_write_mask(dev->parf + PCIE20_PARF_SYS_CTRL,
+ 0xFF0000, i << 16);
+ EP_PCIE_DUMP(dev,
+ "PCIe V%d: PARF_SYS_CTRL:0x%x PARF_TEST_BUS:0x%x\n",
+ dev->rev,
+ readl_relaxed(dev->parf + PCIE20_PARF_SYS_CTRL),
+ readl_relaxed(dev->parf +
+ PCIE20_PARF_TEST_BUS));
+ }
+ ep_pcie_write_reg(dev->parf, PCIE20_PARF_SYS_CTRL, original);
+ }
+
+ for (r = 0; r < EP_PCIE_MAX_RES; r++) {
+ if (!(sel & BIT(r)))
+ continue;
+
+ if (r == EP_PCIE_RES_PHY)
+ ep_pcie_phy_dump(dev);
+
+ size = resource_size(dev->res[r].resource);
+ EP_PCIE_DUMP(dev,
+ "\nPCIe V%d: dump registers of %s.\n\n",
+ dev->rev, dev->res[r].name);
+
+ for (i = 0; i < size; i += 32) {
+ EP_PCIE_DUMP(dev,
+ "0x%04x %08x %08x %08x %08x %08x %08x %08x %08x\n",
+ i, readl_relaxed(dev->res[r].base + i),
+ readl_relaxed(dev->res[r].base + (i + 4)),
+ readl_relaxed(dev->res[r].base + (i + 8)),
+ readl_relaxed(dev->res[r].base + (i + 12)),
+ readl_relaxed(dev->res[r].base + (i + 16)),
+ readl_relaxed(dev->res[r].base + (i + 20)),
+ readl_relaxed(dev->res[r].base + (i + 24)),
+ readl_relaxed(dev->res[r].base + (i + 28)));
+ }
+ }
+}
+
+static void ep_pcie_show_status(struct ep_pcie_dev_t *dev)
+{
+ EP_PCIE_DBG_FS("PCIe: is %s enumerated\n",
+ dev->enumerated ? "" : "not");
+ EP_PCIE_DBG_FS("PCIe: link is %s\n",
+ (dev->link_status == EP_PCIE_LINK_ENABLED)
+ ? "enabled" : "disabled");
+ EP_PCIE_DBG_FS("the link is %s suspending\n",
+ dev->suspending ? "" : "not");
+ EP_PCIE_DBG_FS("the power is %s on\n",
+ dev->power_on ? "" : "not");
+ EP_PCIE_DBG_FS("bus_client: %d\n",
+ dev->bus_client);
+ EP_PCIE_DBG_FS("linkdown_counter: %lu\n",
+ dev->linkdown_counter);
+ EP_PCIE_DBG_FS("linkup_counter: %lu\n",
+ dev->linkup_counter);
+ EP_PCIE_DBG_FS("wake_counter: %lu\n",
+ dev->wake_counter);
+ EP_PCIE_DBG_FS("d0_counter: %lu\n",
+ dev->d0_counter);
+ EP_PCIE_DBG_FS("d3_counter: %lu\n",
+ dev->d3_counter);
+ EP_PCIE_DBG_FS("perst_ast_counter: %lu\n",
+ dev->perst_ast_counter);
+ EP_PCIE_DBG_FS("perst_deast_counter: %lu\n",
+ dev->perst_deast_counter);
+}
+
+static ssize_t ep_pcie_cmd_debug(struct file *file,
+ const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ unsigned long ret;
+ char str[MAX_MSG_LEN];
+ unsigned int testcase = 0;
+ struct ep_pcie_msi_config msi_cfg;
+ int i;
+ u32 device_id = 0;
+ struct ep_pcie_hw *phandle = NULL;
+ struct ep_pcie_iatu entries[2] = {
+ {0x80000000, 0xbe7fffff, 0, 0},
+ {0xb1440000, 0xb144ae1e, 0x31440000, 0}
+ };
+ struct ep_pcie_db_config chdb_cfg = {0x64, 0x6b, 0xfd4fa000};
+ struct ep_pcie_db_config erdb_cfg = {0x64, 0x6b, 0xfd4fa080};
+
+ if (dev->power_on) {
+ device_id = readl_relaxed(dev->dm_core);
+ phandle = ep_pcie_get_phandle(device_id);
+ }
+
+ memset(str, 0, sizeof(str));
+ ret = copy_from_user(str, buf, sizeof(str));
+ if (ret)
+ return -EFAULT;
+
+ for (i = 0; i < sizeof(str) && (str[i] >= '0') && (str[i] <= '9'); ++i)
+ testcase = (testcase * 10) + (str[i] - '0');
+
+ EP_PCIE_DBG_FS("PCIe: TEST: %d\n", testcase);
+
+
+ switch (testcase) {
+ case 0: /* output status */
+ ep_pcie_show_status(dev);
+ break;
+ case 1: /* output PHY and PARF registers */
+ ep_pcie_reg_dump(dev, BIT(EP_PCIE_RES_PHY) |
+ BIT(EP_PCIE_RES_PARF), true);
+ break;
+ case 2: /* output core registers */
+ ep_pcie_reg_dump(dev, BIT(EP_PCIE_RES_DM_CORE), false);
+ break;
+ case 3: /* output MMIO registers */
+ ep_pcie_reg_dump(dev, BIT(EP_PCIE_RES_MMIO), false);
+ break;
+ case 4: /* output ELBI registers */
+ ep_pcie_reg_dump(dev, BIT(EP_PCIE_RES_ELBI), false);
+ break;
+ case 5: /* output MSI registers */
+ ep_pcie_reg_dump(dev, BIT(EP_PCIE_RES_MSI), false);
+ break;
+ case 6: /* turn on link */
+ ep_pcie_enable_endpoint(phandle, EP_PCIE_OPT_ALL);
+ break;
+ case 7: /* enumeration */
+ ep_pcie_enable_endpoint(phandle, EP_PCIE_OPT_ENUM);
+ break;
+ case 8: /* turn off link */
+ ep_pcie_disable_endpoint(phandle);
+ break;
+ case 9: /* check MSI */
+ ep_pcie_get_msi_config(phandle, &msi_cfg);
+ break;
+ case 10: /* trigger MSI */
+ ep_pcie_trigger_msi(phandle, 0);
+ break;
+ case 11: /* indicate the status of PCIe link */
+ EP_PCIE_DBG_FS("\nPCIe: link status is %d.\n\n",
+ ep_pcie_get_linkstatus(phandle));
+ break;
+ case 12: /* configure outbound iATU */
+ ep_pcie_config_outbound_iatu(phandle, entries, 2);
+ break;
+ case 13: /* wake up the host */
+ ep_pcie_wakeup_host(phandle);
+ break;
+ case 14: /* Configure routing of doorbells */
+ ep_pcie_config_db_routing(phandle, chdb_cfg, erdb_cfg);
+ break;
+ case 21: /* write D3 */
+ EP_PCIE_DBG_FS("\nPCIe Testcase %d: write D3 to EP\n\n",
+ testcase);
+ EP_PCIE_DBG_FS("\nPCIe: 0x44 of EP is 0x%x before change\n\n",
+ readl_relaxed(dev->dm_core + 0x44));
+ ep_pcie_write_mask(dev->dm_core + 0x44, 0, 0x3);
+ EP_PCIE_DBG_FS("\nPCIe: 0x44 of EP is 0x%x now\n\n",
+ readl_relaxed(dev->dm_core + 0x44));
+ break;
+ case 22: /* write D0 */
+ EP_PCIE_DBG_FS("\nPCIe Testcase %d: write D0 to EP\n\n",
+ testcase);
+ EP_PCIE_DBG_FS("\nPCIe: 0x44 of EP is 0x%x before change\n\n",
+ readl_relaxed(dev->dm_core + 0x44));
+ ep_pcie_write_mask(dev->dm_core + 0x44, 0x3, 0);
+ EP_PCIE_DBG_FS("\nPCIe: 0x44 of EP is 0x%x now\n\n",
+ readl_relaxed(dev->dm_core + 0x44));
+ break;
+ case 23: /* assert wake */
+ EP_PCIE_DBG_FS("\nPCIe Testcase %d: assert wake\n\n",
+ testcase);
+ gpio_set_value(dev->gpio[EP_PCIE_GPIO_WAKE].num,
+ dev->gpio[EP_PCIE_GPIO_WAKE].on);
+ break;
+ case 24: /* deassert wake */
+ EP_PCIE_DBG_FS("\nPCIe Testcase %d: deassert wake\n\n",
+ testcase);
+ gpio_set_value(dev->gpio[EP_PCIE_GPIO_WAKE].num,
+ 1 - dev->gpio[EP_PCIE_GPIO_WAKE].on);
+ break;
+ case 25: /* output PERST# status */
+ EP_PCIE_DBG_FS("\nPCIe: PERST# is %d.\n\n",
+ gpio_get_value(dev->gpio[EP_PCIE_GPIO_PERST].num));
+ break;
+ case 26: /* output WAKE# status */
+ EP_PCIE_DBG_FS("\nPCIe: WAKE# is %d.\n\n",
+ gpio_get_value(dev->gpio[EP_PCIE_GPIO_WAKE].num));
+ break;
+ case 31: /* output core registers when D3 hot is set by host*/
+ dev->dump_conf = true;
+ break;
+ case 32: /* do not output core registers when D3 hot is set by host*/
+ dev->dump_conf = false;
+ break;
+ default:
+ EP_PCIE_DBG_FS("PCIe: Invalid testcase: %d.\n", testcase);
+ break;
+ }
+
+ if (ret == 0)
+ return count;
+ else
+ return -EFAULT;
+}
+
+const struct file_operations ep_pcie_cmd_debug_ops = {
+ .write = ep_pcie_cmd_debug,
+};
+
+void ep_pcie_debugfs_init(struct ep_pcie_dev_t *ep_dev)
+{
+ dev = ep_dev;
+ dent_ep_pcie = debugfs_create_dir("pcie-ep", 0);
+ if (IS_ERR(dent_ep_pcie)) {
+ EP_PCIE_ERR(dev,
+ "PCIe V%d: fail to create the folder for debug_fs.\n",
+ dev->rev);
+ return;
+ }
+
+ dfile_case = debugfs_create_file("case", 0664,
+ dent_ep_pcie, 0,
+ &ep_pcie_cmd_debug_ops);
+ if (!dfile_case || IS_ERR(dfile_case)) {
+ EP_PCIE_ERR(dev,
+ "PCIe V%d: fail to create the file for case.\n",
+ dev->rev);
+ goto case_error;
+ }
+
+ EP_PCIE_DBG2(dev,
+ "PCIe V%d: debugfs is enabled.\n",
+ dev->rev);
+
+ return;
+
+case_error:
+ debugfs_remove(dent_ep_pcie);
+}
+
+void ep_pcie_debugfs_exit(void)
+{
+ debugfs_remove(dfile_case);
+ debugfs_remove(dent_ep_pcie);
+}
diff --git a/drivers/platform/msm/ep_pcie/ep_pcie_phy.c b/drivers/platform/msm/ep_pcie/ep_pcie_phy.c
new file mode 100644
index 000000000000..e0ea00165c89
--- /dev/null
+++ b/drivers/platform/msm/ep_pcie/ep_pcie_phy.c
@@ -0,0 +1,81 @@
+/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * MSM PCIe PHY endpoint mode
+ */
+
+#include "ep_pcie_com.h"
+#include "ep_pcie_phy.h"
+
+void ep_pcie_phy_init(struct ep_pcie_dev_t *dev)
+{
+ EP_PCIE_DBG(dev,
+ "PCIe V%d: PHY V%d: Initializing 20nm QMP phy - 100MHz\n",
+ dev->rev, dev->phy_rev);
+
+ ep_pcie_write_reg(dev->phy, PCIE_PHY_POWER_DOWN_CONTROL, 0x01);
+ ep_pcie_write_reg(dev->phy, QSERDES_COM_SYS_CLK_CTRL, 0x1E);
+ ep_pcie_write_reg(dev->phy, QSERDES_COM_PLL_CP_SETI, 0x11);
+ ep_pcie_write_reg(dev->phy, QSERDES_COM_PLL_IP_SETP, 0x3F);
+ ep_pcie_write_reg(dev->phy, QSERDES_COM_PLL_CP_SETP, 0x00);
+ ep_pcie_write_reg(dev->phy, QSERDES_COM_PLL_IP_SETI, 0x3F);
+ ep_pcie_write_reg(dev->phy, QSERDES_COM_IP_TRIM, 0x0F);
+ ep_pcie_write_reg(dev->phy, QSERDES_COM_RESETSM_CNTRL, 0x90);
+ ep_pcie_write_reg(dev->phy, QSERDES_COM_RES_CODE_CAL_CSR, 0x77);
+ ep_pcie_write_reg(dev->phy, QSERDES_COM_RES_TRIM_CONTROL, 0x15);
+ ep_pcie_write_reg(dev->phy, QSERDES_TX_RCV_DETECT_LVL, 0x03);
+ ep_pcie_write_reg(dev->phy, QSERDES_RX_RX_EQ_GAIN1_LSB, 0xFF);
+ ep_pcie_write_reg(dev->phy, QSERDES_RX_RX_EQ_GAIN2_LSB, 0xFF);
+ ep_pcie_write_reg(dev->phy, QSERDES_RX_RX_EQ_GAIN2_MSB, 0x00);
+ ep_pcie_write_reg(dev->phy, QSERDES_RX_SIGDET_ENABLES, 0x40);
+ ep_pcie_write_reg(dev->phy, QSERDES_RX_SIGDET_CNTRL, 0x70);
+ ep_pcie_write_reg(dev->phy, PCIE_PHY_PWRUP_RESET_DLY_TIME_SYSCLK, 0xC8);
+ ep_pcie_write_reg(dev->phy, PCIE_PHY_POWER_STATE_CONFIG1, 0xA3);
+ ep_pcie_write_reg(dev->phy, PCIE_PHY_POWER_STATE_CONFIG2, 0x1B);
+
+ ep_pcie_write_reg(dev->phy, QSERDES_COM_PLL_VCOTAIL_EN, 0xE1);
+ ep_pcie_write_reg(dev->phy, QSERDES_COM_RESETSM_CNTRL2, 0x07);
+ ep_pcie_write_reg(dev->phy, QSERDES_COM_IE_TRIM, 0x3F);
+ ep_pcie_write_reg(dev->phy, QSERDES_COM_PLL_CNTRL, 0x46);
+ ep_pcie_write_reg(dev->phy, QSERDES_COM_PLLLOCK_CMP2, 0x05);
+ ep_pcie_write_reg(dev->phy, QSERDES_COM_PLLLOCK_CMP_EN, 0x03);
+ ep_pcie_write_reg(dev->phy, QSERDES_COM_DEC_START1, 0x99);
+ ep_pcie_write_reg(dev->phy, QSERDES_RX_CDR_CONTROL1, 0xF5);
+ ep_pcie_write_reg(dev->phy, QSERDES_RX_CDR_CONTROL_HALF, 0x2C);
+ ep_pcie_write_reg(dev->phy, QSERDES_COM_RES_CODE_START_SEG1, 0x24);
+ ep_pcie_write_reg(dev->phy, QSERDES_RX_RX_EQ_GAIN1_MSB, 0x07);
+ ep_pcie_write_reg(dev->phy, QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2, 0x1E);
+ ep_pcie_write_reg(dev->phy, QSERDES_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1,
+ 0x67);
+ ep_pcie_write_reg(dev->phy, QSERDES_RX_RX_OFFSET_ADAPTOR_CNTRL2, 0x80);
+ ep_pcie_write_reg(dev->phy, QSERDES_RX_SIGDET_DEGLITCH_CNTRL, 0x0C);
+ ep_pcie_write_reg(dev->phy, PCIE_PHY_PWRUP_RESET_DLY_TIME_AUXCLK, 0x80);
+ ep_pcie_write_reg(dev->phy, PCIE_PHY_RX_IDLE_DTCT_CNTRL, 0x4D);
+
+ if (dev->phy_rev == 1) {
+ ep_pcie_write_reg(dev->phy, QSERDES_RX_RX_RCVR_IQ_EN, 0x31);
+ ep_pcie_write_reg(dev->phy, QSERDES_COM_RESETSM_CNTRL2, 0x5);
+ ep_pcie_write_reg(dev->phy, QSERDES_COM_PLL_VCOTAIL_EN, 0x1);
+ }
+
+ ep_pcie_write_reg(dev->phy, PCIE_PHY_SW_RESET, 0x00);
+ ep_pcie_write_reg(dev->phy, PCIE_PHY_START, 0x03);
+}
+
+bool ep_pcie_phy_is_ready(struct ep_pcie_dev_t *dev)
+{
+ if (readl_relaxed(dev->phy + PCIE_PHY_PCS_STATUS) & BIT(6))
+ return false;
+ else
+ return true;
+}
diff --git a/drivers/platform/msm/ep_pcie/ep_pcie_phy.h b/drivers/platform/msm/ep_pcie/ep_pcie_phy.h
new file mode 100644
index 000000000000..e0823e408f88
--- /dev/null
+++ b/drivers/platform/msm/ep_pcie/ep_pcie_phy.h
@@ -0,0 +1,351 @@
+/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __EP_PCIE_PHY_H
+#define __EP_PCIE_PHY_H
+
+#define QSERDES_COM_SYS_CLK_CTRL 0x0
+#define QSERDES_COM_PLL_VCOTAIL_EN 0x4
+#define QSERDES_COM_CMN_MODE 0x8
+#define QSERDES_COM_IE_TRIM 0xC
+#define QSERDES_COM_IP_TRIM 0x10
+#define QSERDES_COM_PLL_CNTRL 0x14
+#define QSERDES_COM_PLL_PHSEL_CONTROL 0x18
+#define QSERDES_COM_IPTAT_TRIM_VCCA_TX_SEL 0x1C
+#define QSERDES_COM_PLL_PHSEL_DC 0x20
+#define QSERDES_COM_PLL_IP_SETI 0x24
+#define QSERDES_COM_CORE_CLK_IN_SYNC_SEL 0x28
+#define QSERDES_COM_PLL_BKG_KVCO_CAL_EN 0x2C
+#define QSERDES_COM_BIAS_EN_CLKBUFLR_EN 0x30
+#define QSERDES_COM_PLL_CP_SETI 0x34
+#define QSERDES_COM_PLL_IP_SETP 0x38
+#define QSERDES_COM_PLL_CP_SETP 0x3C
+#define QSERDES_COM_ATB_SEL1 0x40
+#define QSERDES_COM_ATB_SEL2 0x44
+#define QSERDES_COM_SYSCLK_EN_SEL_TXBAND 0x48
+#define QSERDES_COM_RESETSM_CNTRL 0x4C
+#define QSERDES_COM_RESETSM_CNTRL2 0x50
+#define QSERDES_COM_RESETSM_CNTRL3 0x54
+#define QSERDES_COM_DIV_REF1 0x58
+#define QSERDES_COM_DIV_REF2 0x5C
+#define QSERDES_COM_KVCO_COUNT1 0x60
+#define QSERDES_COM_KVCO_COUNT2 0x64
+#define QSERDES_COM_KVCO_CAL_CNTRL 0x68
+#define QSERDES_COM_KVCO_CODE 0x6C
+#define QSERDES_COM_VREF_CFG1 0x70
+#define QSERDES_COM_VREF_CFG2 0x74
+#define QSERDES_COM_VREF_CFG3 0x78
+#define QSERDES_COM_VREF_CFG4 0x7C
+#define QSERDES_COM_VREF_CFG5 0x80
+#define QSERDES_COM_VREF_CFG6 0x84
+#define QSERDES_COM_PLLLOCK_CMP1 0x88
+#define QSERDES_COM_PLLLOCK_CMP2 0x8C
+#define QSERDES_COM_PLLLOCK_CMP3 0x90
+#define QSERDES_COM_PLLLOCK_CMP_EN 0x94
+#define QSERDES_COM_BGTC 0x98
+#define QSERDES_COM_PLL_TEST_UPDN 0x9C
+#define QSERDES_COM_PLL_VCO_TUNE 0xA0
+#define QSERDES_COM_DEC_START1 0xA4
+#define QSERDES_COM_PLL_AMP_OS 0xA8
+#define QSERDES_COM_SSC_EN_CENTER 0xAC
+#define QSERDES_COM_SSC_ADJ_PER1 0xB0
+#define QSERDES_COM_SSC_ADJ_PER2 0xB4
+#define QSERDES_COM_SSC_PER1 0xB8
+#define QSERDES_COM_SSC_PER2 0xBC
+#define QSERDES_COM_SSC_STEP_SIZE1 0xC0
+#define QSERDES_COM_SSC_STEP_SIZE2 0xC4
+#define QSERDES_COM_RES_CODE_UP 0xC8
+#define QSERDES_COM_RES_CODE_DN 0xCC
+#define QSERDES_COM_RES_CODE_UP_OFFSET 0xD0
+#define QSERDES_COM_RES_CODE_DN_OFFSET 0xD4
+#define QSERDES_COM_RES_CODE_START_SEG1 0xD8
+#define QSERDES_COM_RES_CODE_START_SEG2 0xDC
+#define QSERDES_COM_RES_CODE_CAL_CSR 0xE0
+#define QSERDES_COM_RES_CODE 0xE4
+#define QSERDES_COM_RES_TRIM_CONTROL 0xE8
+#define QSERDES_COM_RES_TRIM_CONTROL2 0xEC
+#define QSERDES_COM_RES_TRIM_EN_VCOCALDONE 0xF0
+#define QSERDES_COM_FAUX_EN 0xF4
+#define QSERDES_COM_DIV_FRAC_START1 0xF8
+#define QSERDES_COM_DIV_FRAC_START2 0xFC
+#define QSERDES_COM_DIV_FRAC_START3 0x100
+#define QSERDES_COM_DEC_START2 0x104
+#define QSERDES_COM_PLL_RXTXEPCLK_EN 0x108
+#define QSERDES_COM_PLL_CRCTRL 0x10C
+#define QSERDES_COM_PLL_CLKEPDIV 0x110
+#define QSERDES_COM_PLL_FREQUPDATE 0x114
+#define QSERDES_COM_PLL_BKGCAL_TRIM_UP 0x118
+#define QSERDES_COM_PLL_BKGCAL_TRIM_DN 0x11C
+#define QSERDES_COM_PLL_BKGCAL_TRIM_MUX 0x120
+#define QSERDES_COM_PLL_BKGCAL_VREF_CFG 0x124
+#define QSERDES_COM_PLL_BKGCAL_DIV_REF1 0x128
+#define QSERDES_COM_PLL_BKGCAL_DIV_REF2 0x12C
+#define QSERDES_COM_MUXADDR 0x130
+#define QSERDES_COM_LOW_POWER_RO_CONTROL 0x134
+#define QSERDES_COM_POST_DIVIDER_CONTROL 0x138
+#define QSERDES_COM_HR_OCLK2_DIVIDER 0x13C
+#define QSERDES_COM_HR_OCLK3_DIVIDER 0x140
+#define QSERDES_COM_PLL_VCO_HIGH 0x144
+#define QSERDES_COM_RESET_SM 0x148
+#define QSERDES_COM_MUXVAL 0x14C
+#define QSERDES_TX_BIST_MODE_LANENO 0x200
+#define QSERDES_TX_CLKBUF_ENABLE 0x204
+#define QSERDES_TX_TX_EMP_POST1_LVL 0x208
+#define QSERDES_TX_TX_DRV_LVL 0x20C
+#define QSERDES_TX_RESET_TSYNC_EN 0x210
+#define QSERDES_TX_LPB_EN 0x214
+#define QSERDES_TX_RES_CODE_UP 0x218
+#define QSERDES_TX_RES_CODE_DN 0x21C
+#define QSERDES_TX_PERL_LENGTH1 0x220
+#define QSERDES_TX_PERL_LENGTH2 0x224
+#define QSERDES_TX_SERDES_BYP_EN_OUT 0x228
+#define QSERDES_TX_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN 0x22C
+#define QSERDES_TX_PARRATE_REC_DETECT_IDLE_EN 0x230
+#define QSERDES_TX_BIST_PATTERN1 0x234
+#define QSERDES_TX_BIST_PATTERN2 0x238
+#define QSERDES_TX_BIST_PATTERN3 0x23C
+#define QSERDES_TX_BIST_PATTERN4 0x240
+#define QSERDES_TX_BIST_PATTERN5 0x244
+#define QSERDES_TX_BIST_PATTERN6 0x248
+#define QSERDES_TX_BIST_PATTERN7 0x24C
+#define QSERDES_TX_BIST_PATTERN8 0x250
+#define QSERDES_TX_LANE_MODE 0x254
+#define QSERDES_TX_IDAC_CAL_LANE_MODE 0x258
+#define QSERDES_TX_IDAC_CAL_LANE_MODE_CONFIGURATION 0x25C
+#define QSERDES_TX_ATB_SEL1 0x260
+#define QSERDES_TX_ATB_SEL2 0x264
+#define QSERDES_TX_RCV_DETECT_LVL 0x268
+#define QSERDES_TX_PRBS_SEED1 0x26C
+#define QSERDES_TX_PRBS_SEED2 0x270
+#define QSERDES_TX_PRBS_SEED3 0x274
+#define QSERDES_TX_PRBS_SEED4 0x278
+#define QSERDES_TX_RESET_GEN 0x27C
+#define QSERDES_TX_TRAN_DRVR_EMP_EN 0x280
+#define QSERDES_TX_TX_INTERFACE_MODE 0x284
+#define QSERDES_TX_PWM_CTRL 0x288
+#define QSERDES_TX_PWM_DATA 0x28C
+#define QSERDES_TX_PWM_ENC_DIV_CTRL 0x290
+#define QSERDES_TX_VMODE_CTRL1 0x294
+#define QSERDES_TX_VMODE_CTRL2 0x298
+#define QSERDES_TX_VMODE_CTRL3 0x29C
+#define QSERDES_TX_VMODE_CTRL4 0x2A0
+#define QSERDES_TX_VMODE_CTRL5 0x2A4
+#define QSERDES_TX_VMODE_CTRL6 0x2A8
+#define QSERDES_TX_VMODE_CTRL7 0x2AC
+#define QSERDES_TX_TX_ALOG_INTF_OBSV_CNTL 0x2B0
+#define QSERDES_TX_BIST_STATUS 0x2B4
+#define QSERDES_TX_BIST_ERROR_COUNT1 0x2B8
+#define QSERDES_TX_BIST_ERROR_COUNT2 0x2BC
+#define QSERDES_TX_TX_ALOG_INTF_OBSV 0x2C0
+#define QSERDES_TX_PWM_DEC_STATUS 0x2C4
+#define QSERDES_RX_CDR_CONTROL1 0x400
+#define QSERDES_RX_CDR_CONTROL2 0x404
+#define QSERDES_RX_CDR_CONTROL_HALF 0x408
+#define QSERDES_RX_CDR_CONTROL_QUARTER 0x40C
+#define QSERDES_RX_CDR_CONTROL_EIGHTH 0x410
+#define QSERDES_RX_UCDR_FO_GAIN 0x414
+#define QSERDES_RX_UCDR_SO_GAIN 0x418
+#define QSERDES_RX_UCDR_SO_SATURATION_AND_ENABLE 0x41C
+#define QSERDES_RX_UCDR_FO_TO_SO_DELAY 0x420
+#define QSERDES_RX_AUX_CONTROL 0x424
+#define QSERDES_RX_AUX_DATA_TCOARSE 0x428
+#define QSERDES_RX_AUX_DATA_TFINE_LSB 0x42C
+#define QSERDES_RX_AUX_DATA_TFINE_MSB 0x430
+#define QSERDES_RX_RCLK_AUXDATA_SEL 0x434
+#define QSERDES_RX_AC_JTAG_ENABLE 0x438
+#define QSERDES_RX_AC_JTAG_INITP 0x43C
+#define QSERDES_RX_AC_JTAG_INITN 0x440
+#define QSERDES_RX_AC_JTAG_LVL 0x444
+#define QSERDES_RX_AC_JTAG_MODE 0x448
+#define QSERDES_RX_AC_JTAG_RESET 0x44C
+#define QSERDES_RX_RX_RCVR_IQ_EN 0x450
+#define QSERDES_RX_RX_IDAC_I_DC_OFFSETS 0x454
+#define QSERDES_RX_RX_IDAC_Q_DC_OFFSETS 0x458
+#define QSERDES_RX_RX_IDAC_A_DC_OFFSETS 0x45C
+#define QSERDES_RX_RX_IDAC_EN 0x460
+#define QSERDES_RX_RX_IDAC_CTRL0 0x464
+#define QSERDES_RX_RX_IDAC_CTRL1 0x468
+#define QSERDES_RX_RX_EOM_EN 0x46C
+#define QSERDES_RX_RX_EOM_CTRL0 0x470
+#define QSERDES_RX_RX_EOM_CTRL1 0x474
+#define QSERDES_RX_RX_EOM_CTRL2 0x478
+#define QSERDES_RX_RX_EOM_CTRL3 0x47C
+#define QSERDES_RX_RX_EOM_CTRL4 0x480
+#define QSERDES_RX_RX_EOM_CTRL5 0x484
+#define QSERDES_RX_RX_EOM_CTRL6 0x488
+#define QSERDES_RX_RX_EOM_CTRL7 0x48C
+#define QSERDES_RX_RX_EOM_CTRL8 0x490
+#define QSERDES_RX_RX_EOM_CTRL9 0x494
+#define QSERDES_RX_RX_EOM_CTRL10 0x498
+#define QSERDES_RX_RX_EOM_CTRL11 0x49C
+#define QSERDES_RX_RX_HIGHZ_HIGHRATE 0x4A0
+#define QSERDES_RX_RX_TERM_AC_BYPASS_DC_COUPLE_OFFSET 0x4A4
+#define QSERDES_RX_RX_EQ_GAIN1_LSB 0x4A8
+#define QSERDES_RX_RX_EQ_GAIN1_MSB 0x4AC
+#define QSERDES_RX_RX_EQ_GAIN2_LSB 0x4B0
+#define QSERDES_RX_RX_EQ_GAIN2_MSB 0x4B4
+#define QSERDES_RX_RX_EQU_ADAPTOR_CNTRL1 0x4B8
+#define QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2 0x4BC
+#define QSERDES_RX_RX_EQU_ADAPTOR_CNTRL3 0x4C0
+#define QSERDES_RX_RX_EQU_ADAPTOR_CNTRL4 0x4C4
+#define QSERDES_RX_RX_IDAC_CAL_CONFIGURATION 0x4C8
+#define QSERDES_RX_RX_IDAC_CAL_CONFIGURATION_2 0x4CC
+#define QSERDES_RX_RX_IDAC_TSETTLE_LOW 0x4D0
+#define QSERDES_RX_RX_IDAC_TSETTLE_HIGH 0x4D4
+#define QSERDES_RX_RX_IDAC_ENDSAMP_LOW 0x4D8
+#define QSERDES_RX_RX_IDAC_ENDSAMP_HIGH 0x4DC
+#define QSERDES_RX_RX_IDAC_MIDPOINT_LOW 0x4E0
+#define QSERDES_RX_RX_IDAC_MIDPOINT_HIGH 0x4E4
+#define QSERDES_RX_RX_EQ_OFFSET_LSB 0x4E8
+#define QSERDES_RX_RX_EQ_OFFSET_MSB 0x4EC
+#define QSERDES_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1 0x4F0
+#define QSERDES_RX_RX_OFFSET_ADAPTOR_CNTRL2 0x4F4
+#define QSERDES_RX_SIGDET_ENABLES 0x4F8
+#define QSERDES_RX_SIGDET_ENABLES_2 0x4FC
+#define QSERDES_RX_SIGDET_CNTRL 0x500
+#define QSERDES_RX_SIGDET_DEGLITCH_CNTRL 0x504
+#define QSERDES_RX_SIGDET_TIMER_LIMIT 0x508
+#define QSERDES_RX_RX_BAND 0x50C
+#define QSERDES_RX_CDR_FREEZE_UP_DN 0x510
+#define QSERDES_RX_RX_INTERFACE_MODE 0x514
+#define QSERDES_RX_JITTER_GEN_MODE 0x518
+#define QSERDES_RX_BUJ_AMP 0x51C
+#define QSERDES_RX_SJ_AMP1 0x520
+#define QSERDES_RX_SJ_AMP2 0x524
+#define QSERDES_RX_SJ_PER1 0x528
+#define QSERDES_RX_SJ_PER2 0x52C
+#define QSERDES_RX_BUJ_STEP_FREQ1 0x530
+#define QSERDES_RX_BUJ_STEP_FREQ2 0x534
+#define QSERDES_RX_PPM_OFFSET1 0x538
+#define QSERDES_RX_PPM_OFFSET2 0x53C
+#define QSERDES_RX_SIGN_PPM_PERIOD1 0x540
+#define QSERDES_RX_SIGN_PPM_PERIOD2 0x544
+#define QSERDES_RX_SSC_CTRL 0x548
+#define QSERDES_RX_SSC_COUNT1 0x54C
+#define QSERDES_RX_SSC_COUNT2 0x550
+#define QSERDES_RX_RX_ALOG_INTF_OBSV_CNTL 0x554
+#define QSERDES_RX_PI_CTRL1 0x558
+#define QSERDES_RX_PI_CTRL2 0x55C
+#define QSERDES_RX_PI_QUAD 0x560
+#define QSERDES_RX_IDATA1 0x564
+#define QSERDES_RX_IDATA2 0x568
+#define QSERDES_RX_AUX_DATA1 0x56C
+#define QSERDES_RX_AUX_DATA2 0x570
+#define QSERDES_RX_AC_JTAG_OUTP 0x574
+#define QSERDES_RX_AC_JTAG_OUTN 0x578
+#define QSERDES_RX_RX_SIGDET 0x57C
+#define QSERDES_RX_RX_VDCOFF 0x580
+#define QSERDES_RX_IDAC_CAL_ON 0x584
+#define QSERDES_RX_IDAC_STATUS_I 0x588
+#define QSERDES_RX_IDAC_STATUS_Q 0x58C
+#define QSERDES_RX_IDAC_STATUS_A 0x590
+#define QSERDES_RX_CALST_STATUS_I 0x594
+#define QSERDES_RX_CALST_STATUS_Q 0x598
+#define QSERDES_RX_CALST_STATUS_A 0x59C
+#define QSERDES_RX_EOM_STATUS0 0x5A0
+#define QSERDES_RX_EOM_STATUS1 0x5A4
+#define QSERDES_RX_EOM_STATUS2 0x5A8
+#define QSERDES_RX_EOM_STATUS3 0x5AC
+#define QSERDES_RX_EOM_STATUS4 0x5B0
+#define QSERDES_RX_EOM_STATUS5 0x5B4
+#define QSERDES_RX_EOM_STATUS6 0x5B8
+#define QSERDES_RX_EOM_STATUS7 0x5BC
+#define QSERDES_RX_EOM_STATUS8 0x5C0
+#define QSERDES_RX_EOM_STATUS9 0x5C4
+#define QSERDES_RX_RX_ALOG_INTF_OBSV 0x5C8
+#define QSERDES_RX_READ_EQCODE 0x5CC
+#define QSERDES_RX_READ_OFFSETCODE 0x5D0
+#define PCIE_PHY_SW_RESET 0x600
+#define PCIE_PHY_POWER_DOWN_CONTROL 0x604
+#define PCIE_PHY_START 0x608
+#define PCIE_PHY_TXMGN_V1_V0 0x60C
+#define PCIE_PHY_TXMGN_V3_V2 0x610
+#define PCIE_PHY_TXMGN_LS_V4 0x614
+#define PCIE_PHY_TXDEEMPH_M6DB_V0 0x618
+#define PCIE_PHY_TXDEEMPH_M3P5DB_V0 0x61C
+#define PCIE_PHY_TXDEEMPH_M6DB_V1 0x620
+#define PCIE_PHY_TXDEEMPH_M3P5DB_V1 0x624
+#define PCIE_PHY_TXDEEMPH_M6DB_V2 0x628
+#define PCIE_PHY_TXDEEMPH_M3P5DB_V2 0x62C
+#define PCIE_PHY_TXDEEMPH_M6DB_V3 0x630
+#define PCIE_PHY_TXDEEMPH_M3P5DB_V3 0x634
+#define PCIE_PHY_TXDEEMPH_M6DB_V4 0x638
+#define PCIE_PHY_TXDEEMPH_M3P5DB_V4 0x63C
+#define PCIE_PHY_TXDEEMPH_M6DB_LS 0x640
+#define PCIE_PHY_TXDEEMPH_M3P5DB_LS 0x644
+#define PCIE_PHY_ENDPOINT_REFCLK_DRIVE 0x648
+#define PCIE_PHY_RX_IDLE_DTCT_CNTRL 0x64C
+#define PCIE_PHY_POWER_STATE_CONFIG1 0x650
+#define PCIE_PHY_POWER_STATE_CONFIG2 0x654
+#define PCIE_PHY_POWER_STATE_CONFIG3 0x658
+#define PCIE_PHY_RCVR_DTCT_DLY_P1U2_L 0x65C
+#define PCIE_PHY_RCVR_DTCT_DLY_P1U2_H 0x660
+#define PCIE_PHY_RCVR_DTCT_DLY_U3_L 0x664
+#define PCIE_PHY_RCVR_DTCT_DLY_U3_H 0x668
+#define PCIE_PHY_LOCK_DETECT_CONFIG1 0x66C
+#define PCIE_PHY_LOCK_DETECT_CONFIG2 0x670
+#define PCIE_PHY_LOCK_DETECT_CONFIG3 0x674
+#define PCIE_PHY_TSYNC_RSYNC_TIME 0x678
+#define PCIE_PHY_SIGDET_LOW_2_IDLE_TIME 0x67C
+#define PCIE_PHY_BEACON_2_IDLE_TIME_L 0x680
+#define PCIE_PHY_BEACON_2_IDLE_TIME_H 0x684
+#define PCIE_PHY_PWRUP_RESET_DLY_TIME_SYSCLK 0x688
+#define PCIE_PHY_PWRUP_RESET_DLY_TIME_AUXCLK 0x68C
+#define PCIE_PHY_LFPS_DET_HIGH_COUNT_VAL 0x690
+#define PCIE_PHY_LFPS_TX_ECSTART_EQTLOCK 0x694
+#define PCIE_PHY_LFPS_TX_END_CNT_P2U3_START 0x698
+#define PCIE_PHY_RXEQTRAINING_WAIT_TIME 0x69C
+#define PCIE_PHY_RXEQTRAINING_RUN_TIME 0x6A0
+#define PCIE_PHY_TXONESZEROS_RUN_LENGTH 0x6A4
+#define PCIE_PHY_FLL_CNTRL1 0x6A8
+#define PCIE_PHY_FLL_CNTRL2 0x6AC
+#define PCIE_PHY_FLL_CNT_VAL_L 0x6B0
+#define PCIE_PHY_FLL_CNT_VAL_H_TOL 0x6B4
+#define PCIE_PHY_FLL_MAN_CODE 0x6B8
+#define PCIE_PHY_AUTONOMOUS_MODE_CTRL 0x6BC
+#define PCIE_PHY_LFPS_RXTERM_IRQ_CLEAR 0x6C0
+#define PCIE_PHY_ARCVR_DTCT_EN_PERIOD 0x6C4
+#define PCIE_PHY_ARCVR_DTCT_CM_DLY 0x6C8
+#define PCIE_PHY_ALFPS_DEGLITCH_VAL 0x6CC
+#define PCIE_PHY_INSIG_SW_CTRL1 0x6D0
+#define PCIE_PHY_INSIG_SW_CTRL2 0x6D4
+#define PCIE_PHY_INSIG_SW_CTRL3 0x6D8
+#define PCIE_PHY_INSIG_MX_CTRL1 0x6DC
+#define PCIE_PHY_INSIG_MX_CTRL2 0x6E0
+#define PCIE_PHY_INSIG_MX_CTRL3 0x6E4
+#define PCIE_PHY_TEST_CONTROL 0x6E8
+#define PCIE_PHY_BIST_CTRL 0x6EC
+#define PCIE_PHY_PRBS_POLY0 0x6F0
+#define PCIE_PHY_PRBS_POLY1 0x6F4
+#define PCIE_PHY_PRBS_SEED0 0x6F8
+#define PCIE_PHY_PRBS_SEED1 0x6FC
+#define PCIE_PHY_FIXED_PAT_CTRL 0x700
+#define PCIE_PHY_FIXED_PAT0 0x704
+#define PCIE_PHY_FIXED_PAT1 0x708
+#define PCIE_PHY_FIXED_PAT2 0x70C
+#define PCIE_PHY_FIXED_PAT3 0x710
+#define PCIE_PHY_SPARE1 0x714
+#define PCIE_PHY_BIST_CHK_ERR_CNT_L 0x718
+#define PCIE_PHY_BIST_CHK_ERR_CNT_H 0x71C
+#define PCIE_PHY_BIST_CHK_STATUS 0x720
+#define PCIE_PHY_LFPS_RXTERM_IRQ_SOURCE 0x724
+#define PCIE_PHY_PCS_STATUS 0x728
+#define PCIE_PHY_PCS_STATUS2 0x72C
+#define PCIE_PHY_REVISION_ID0 0x730
+#define PCIE_PHY_REVISION_ID1 0x734
+#define PCIE_PHY_REVISION_ID2 0x738
+#define PCIE_PHY_REVISION_ID3 0x73C
+#define PCIE_PHY_DEBUG_BUS_0_STATUS 0x740
+#define PCIE_PHY_DEBUG_BUS_1_STATUS 0x744
+#define PCIE_PHY_DEBUG_BUS_2_STATUS 0x748
+#define PCIE_PHY_DEBUG_BUS_3_STATUS 0x74C
+#endif