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>
This commit is contained in:
Yan He 2015-01-07 22:46:13 -08:00 committed by David Keitel
parent 3b1bda734d
commit 5dbc08812b
11 changed files with 3771 additions and 0 deletions

View file

@ -0,0 +1,106 @@
MSM PCI express endpoint
Required properties:
- compatible: should be "qcom,pcie-ep".
- reg: should contain PCIe register maps.
- reg-names: indicates various resources passed to driver by name.
Should be "msi", "dm_core", "elbi", "parf", "phy", "mmio".
These correspond to different modules within the PCIe domain.
- #address-cells: Should provide a value of 0.
- interrupt-parent: Should be the PCIe device node itself here.
- interrupts: Should be in the format <0 1 2> and it is an index to the
interrupt-map that contains PCIe related interrupts.
- #interrupt-cells: Should provide a value of 1.
- #interrupt-map-mask: should provide a value of 0xffffffff.
- interrupt-map: Must create mapping for the number of interrupts
that are defined in above interrupts property.
For PCIe device node, it should define 6 mappings for
the corresponding PCIe interrupts supporting the
specification.
- interrupt-names: indicates interrupts passed to driver by name.
Should be "int_pm_turnoff", "int_dstate_change",
"int_l1sub_timeout", "int_link_up",
"int_link_down", "int_bridge_flush_n".
- perst-gpio: PERST GPIO specified by PCIe spec.
- wake-gpio: WAKE GPIO specified by PCIe spec.
- clkreq-gpio: CLKREQ GPIO specified by PCIe spec.
- <supply-name>-supply: phandle to the regulator device tree node.
Refer to the schematics for the corresponding voltage regulators.
vreg-1.8-supply: phandle to the analog supply for the PCIe controller.
vreg-0.9-supply: phandle to the analog supply for the PCIe controller.
Optional Properties:
- qcom,<supply-name>-voltage-level: specifies voltage levels for supply.
Should be specified in pairs (max, min, optimal), units uV.
- clock-names: list of names of clock inputs.
Should be "pcie_0_pipe_clk",
"pcie_0_aux_clk", "pcie_0_cfg_ahb_clk",
"pcie_0_mstr_axi_clk", "pcie_0_slv_axi_clk",
"pcie_0_ldo";
- max-clock-frequency-hz: list of the maximum operating frequencies stored
in the same order of clock names;
- qcom,pcie-phy-ver: version of PCIe PHY.
- qcom,pcie-link-speed: generation of PCIe link speed. The value could be
1, 2 or 3.
- Refer to "Documentation/devicetree/bindings/arm/msm/msm_bus.txt" for
below optional properties:
- qcom,msm-bus,name
- qcom,msm-bus,num-cases
- qcom,msm-bus,num-paths
- qcom,msm-bus,vectors-KBps
Example:
pcie_ep: qcom,pcie@bfffd000 {
compatible = "qcom,pcie-ep";
reg = <0xbfffd000 0x1000>,
<0xbfffe000 0x1000>,
<0xbffff000 0x1000>,
<0xfc520000 0x2000>,
<0xfc526000 0x1000>,
<0xfc527000 0x1000>;
reg-names = "msi", "dm_core", "elbi", "parf", "phy", "mmio";
#address-cells = <0>;
interrupt-parent = <&pcie_ep>;
interrupts = <0 1 2 3 4 5>;
#interrupt-cells = <1>;
interrupt-map-mask = <0xffffffff>;
interrupt-map = <0 &intc 0 44 0
1 &intc 0 46 0
2 &intc 0 47 0
3 &intc 0 50 0
4 &intc 0 51 0
5 &intc 0 52 0>;
interrupt-names = "int_pm_turnoff", "int_dstate_change",
"int_l1sub_timeout", "int_link_up",
"int_link_down", "int_bridge_flush_n";
perst-gpio = <&msmgpio 65 0>;
wake-gpio = <&msmgpio 61 0>;
clkreq-gpio = <&msmgpio 64 0>;
gdsc-vdd-supply = <&gdsc_pcie_0>;
vreg-1.8-supply = <&pmd9635_l8>;
vreg-0.9-supply = <&pmd9635_l4>;
qcom,vreg-1.8-voltage-level = <1800000 1800000 1000>;
qcom,vreg-0.9-voltage-level = <950000 950000 24000>;
clock-names = "pcie_0_pipe_clk",
"pcie_0_aux_clk", "pcie_0_cfg_ahb_clk",
"pcie_0_mstr_axi_clk", "pcie_0_slv_axi_clk",
"pcie_0_ldo";
max-clock-frequency-hz = <62500000>, <1000000>,
<0>, <0>, <0>, <0>;
qcom,msm-bus,name = "pcie-ep";
qcom,msm-bus,num-cases = <2>;
qcom,msm-bus,num-paths = <1>;
qcom,msm-bus,vectors-KBps =
<45 512 0 0>,
<45 512 500 800>;
qcom,pcie-link-speed = <1>;
};

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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);

View file

@ -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

File diff suppressed because it is too large Load diff

View file

@ -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);
}

View file

@ -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;
}

View file

@ -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

254
include/linux/msm_ep_pcie.h Normal file
View file

@ -0,0 +1,254 @@
/* 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 __MSM_EP_PCIE_H
#define __MSM_EP_PCIE_H
#include <linux/types.h>
enum ep_pcie_link_status {
EP_PCIE_LINK_DISABLED,
EP_PCIE_LINK_UP,
EP_PCIE_LINK_ENABLED,
};
enum ep_pcie_event {
EP_PCIE_EVENT_INVALID = 0,
EP_PCIE_EVENT_PM_D0 = 0x1,
EP_PCIE_EVENT_PM_D3_HOT = 0x2,
EP_PCIE_EVENT_PM_D3_COLD = 0x4,
EP_PCIE_EVENT_PM_RST_DEAST = 0x8,
EP_PCIE_EVENT_LINKDOWN = 0x10,
EP_PCIE_EVENT_LINKUP = 0x20,
};
enum ep_pcie_trigger {
EP_PCIE_TRIGGER_CALLBACK,
EP_PCIE_TRIGGER_COMPLETION,
};
enum ep_pcie_options {
EP_PCIE_OPT_NULL = 0,
EP_PCIE_OPT_AST_WAKE = 0x1,
EP_PCIE_OPT_POWER_ON = 0x2,
EP_PCIE_OPT_ENUM = 0x4,
EP_PCIE_OPT_ALL = 0xFFFFFFFF,
};
struct ep_pcie_notify {
enum ep_pcie_event event;
void *user;
void *data;
u32 options;
};
struct ep_pcie_register_event {
u32 events;
void *user;
enum ep_pcie_trigger mode;
void (*callback)(struct ep_pcie_notify *notify);
struct ep_pcie_notify notify;
struct completion *completion;
u32 options;
};
struct ep_pcie_iatu {
u32 start;
u32 end;
u32 tgt_lower;
u32 tgt_upper;
};
struct ep_pcie_msi_config {
u32 lower;
u32 upper;
u32 data;
u32 msg_num;
};
struct ep_pcie_db_config {
u8 base;
u8 end;
u32 tgt_addr;
};
struct ep_pcie_hw {
struct list_head node;
u32 device_id;
void **private_data;
int (*register_event)(struct ep_pcie_register_event *reg);
int (*deregister_event)(void);
enum ep_pcie_link_status (*get_linkstatus)(void);
int (*config_outbound_iatu)(struct ep_pcie_iatu entries[],
u32 num_entries);
int (*get_msi_config)(struct ep_pcie_msi_config *cfg);
int (*trigger_msi)(u32 idx);
int (*wakeup_host)(void);
int (*enable_endpoint)(enum ep_pcie_options opt);
int (*disable_endpoint)(void);
int (*config_db_routing)(struct ep_pcie_db_config chdb_cfg,
struct ep_pcie_db_config erdb_cfg);
};
/*
* ep_pcie_register_drv - register HW driver.
* @phandle: PCIe endpoint HW driver handle
*
* This function registers PCIe HW driver to PCIe endpoint service
* layer.
*
* Return: 0 on success, negative value on error
*/
int ep_pcie_register_drv(struct ep_pcie_hw *phandle);
/*
* ep_pcie_deregister_drv - deregister HW driver.
* @phandle: PCIe endpoint HW driver handle
*
* This function deregisters PCIe HW driver to PCIe endpoint service
* layer.
*
* Return: 0 on success, negative value on error
*/
int ep_pcie_deregister_drv(struct ep_pcie_hw *phandle);
/*
* ep_pcie_get_phandle - get PCIe endpoint HW driver handle.
* @id: PCIe endpoint device ID
*
* This function deregisters PCIe HW driver from PCIe endpoint service
* layer.
*
* Return: PCIe endpoint HW driver handle
*/
struct ep_pcie_hw *ep_pcie_get_phandle(u32 id);
/*
* ep_pcie_register_event - register event with PCIe driver.
* @phandle: PCIe endpoint HW driver handle
* @reg: event structure
*
* This function gives PCIe client driver an option to register
* event with PCIe driver.
*
* Return: 0 on success, negative value on error
*/
int ep_pcie_register_event(struct ep_pcie_hw *phandle,
struct ep_pcie_register_event *reg);
/*
* ep_pcie_deregister_event - deregister event with PCIe driver.
* @phandle: PCIe endpoint HW driver handle
*
* This function gives PCIe client driver an option to deregister
* existing event with PCIe driver.
*
* Return: 0 on success, negative value on error
*/
int ep_pcie_deregister_event(struct ep_pcie_hw *phandle);
/*
* ep_pcie_get_linkstatus - indicate the status of PCIe link.
* @phandle: PCIe endpoint HW driver handle
*
* This function tells PCIe client about the status of PCIe link.
*
* Return: status of PCIe link
*/
enum ep_pcie_link_status ep_pcie_get_linkstatus(struct ep_pcie_hw *phandle);
/*
* ep_pcie_config_outbound_iatu - configure outbound iATU.
* @entries: iatu entries
* @num_entries: number of iatu entries
*
* This function configures the outbound iATU for PCIe
* client's access to the regions in the host memory which
* are specified by the SW on host side.
*
* Return: 0 on success, negative value on error
*/
int ep_pcie_config_outbound_iatu(struct ep_pcie_hw *phandle,
struct ep_pcie_iatu entries[],
u32 num_entries);
/*
* ep_pcie_get_msi_config - get MSI config info.
* @phandle: PCIe endpoint HW driver handle
* @cfg: pointer to MSI config
*
* This function returns MSI config info.
*
* Return: 0 on success, negative value on error
*/
int ep_pcie_get_msi_config(struct ep_pcie_hw *phandle,
struct ep_pcie_msi_config *cfg);
/*
* ep_pcie_trigger_msi - trigger an MSI.
* @phandle: PCIe endpoint HW driver handle
* @idx: MSI index number
*
* This function allows PCIe client to trigger an MSI
* on host side.
*
* Return: 0 on success, negative value on error
*/
int ep_pcie_trigger_msi(struct ep_pcie_hw *phandle, u32 idx);
/*
* ep_pcie_wakeup_host - wake up the host.
* @phandle: PCIe endpoint HW driver handle
*
* This function asserts WAKE GPIO to wake up the host.
*
* Return: 0 on success, negative value on error
*/
int ep_pcie_wakeup_host(struct ep_pcie_hw *phandle);
/*
* ep_pcie_enable_endpoint - enable PCIe endpoint.
* @phandle: PCIe endpoint HW driver handle
* @opt: endpoint enable options
*
* This function is to enable the PCIe endpoint device.
*
* Return: 0 on success, negative value on error
*/
int ep_pcie_enable_endpoint(struct ep_pcie_hw *phandle,
enum ep_pcie_options opt);
/*
* ep_pcie_disable_endpoint - disable PCIe endpoint.
* @phandle: PCIe endpoint HW driver handle
*
* This function is to disable the PCIe endpoint device.
*
* Return: 0 on success, negative value on error
*/
int ep_pcie_disable_endpoint(struct ep_pcie_hw *phandle);
/*
* ep_pcie_config_db_routing - Configure routing of doorbells to another block.
* @phandle: PCIe endpoint HW driver handle
* @chdb_cfg: channel doorbell config
* @erdb_cfg: event ring doorbell config
*
* This function allows PCIe core to route the doorbells intended
* for another entity via a target address.
*
* Return: 0 on success, negative value on error
*/
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);
#endif