summaryrefslogtreecommitdiff
path: root/drivers/platform
diff options
context:
space:
mode:
authorYimin Peng <yiminp@codeaurora.org>2018-07-11 11:59:53 +0800
committerYimin Peng <yiminp@codeaurora.org>2018-10-24 17:11:18 +0800
commitef6d23ad264c84f1af76014c040102f6f660e26d (patch)
treed4b999b91102d8dcdbbabaa3dbbe3402913b0580 /drivers/platform
parent595eeed39838e4f975fc1329e500694d8e4b83ea (diff)
msm: ep_pcie: add PCIe endpoint driver for 8996AU
The MSM PCIE core is enabled in endpoint mode and handles the link from PCIE root complex on host side. Change-Id: I5a23ea1a41fede2d57850ff032bf2b1a92d02463 Signed-off-by: Yimin Peng <yiminp@codeaurora.org>
Diffstat (limited to 'drivers/platform')
-rw-r--r--drivers/platform/msm/ep_pcie/ep_pcie_com.h25
-rw-r--r--drivers/platform/msm/ep_pcie/ep_pcie_core.c168
-rw-r--r--drivers/platform/msm/ep_pcie/ep_pcie_phy.c45
-rw-r--r--drivers/platform/msm/ep_pcie/ep_pcie_phy.h32
4 files changed, 256 insertions, 14 deletions
diff --git a/drivers/platform/msm/ep_pcie/ep_pcie_com.h b/drivers/platform/msm/ep_pcie/ep_pcie_com.h
index 4b89c8636141..0c3fb1676eea 100644
--- a/drivers/platform/msm/ep_pcie/ep_pcie_com.h
+++ b/drivers/platform/msm/ep_pcie/ep_pcie_com.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015, 2018, 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
@@ -101,6 +101,14 @@
#define PCIE20_AUX_CLK_FREQ_REG 0xB40
+#define PCIE20_MHISTATUS 0x148
+#define PCIE20_PARF_MHI_CLOCK_RESET_CTRL 0x174
+#define PCIE20_PARF_CFG_BITS 0x210
+
+#define PCIE20_BRIDGE_CTRL_INT_PIN_INT_LINE_REG 0x3C
+#define PCIE20_DEVICE_ID_VENDOR_ID_REG 0x0
+#define PCIE20_L1_SUBSTATES_REG 0xB44
+
#define PERST_TIMEOUT_US_MIN 1000
#define PERST_TIMEOUT_US_MAX 1000
#define PERST_CHECK_MAX_COUNT 30000
@@ -126,7 +134,7 @@
#define EP_PCIE_LOG_PAGES 50
#define EP_PCIE_MAX_VREG 2
-#define EP_PCIE_MAX_CLK 6
+#define EP_PCIE_MAX_CLK 8
#define EP_PCIE_MAX_PIPE_CLK 1
#define EP_PCIE_ERROR -30655
@@ -255,6 +263,12 @@ struct ep_pcie_irq_info_t {
u32 num;
};
+struct ep_pcie_phy_info_t {
+ u32 offset;
+ u32 val;
+ u32 delay;
+};
+
/* pcie endpoint device structure */
struct ep_pcie_dev_t {
struct platform_device *pdev;
@@ -278,6 +292,9 @@ struct ep_pcie_dev_t {
u32 link_speed;
bool active_config;
bool aggregated_irq;
+ u32 phy_status_reg;
+ u32 phy_len;
+ struct ep_pcie_phy_info_t *phy_sequence;
u32 rev;
u32 phy_rev;
@@ -356,5 +373,7 @@ 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);
-
+#ifdef CONFIG_ARCH_MSM8996
+extern void ep_pcie_phy_bringup_port(struct ep_pcie_dev_t *dev);
+#endif
#endif
diff --git a/drivers/platform/msm/ep_pcie/ep_pcie_core.c b/drivers/platform/msm/ep_pcie/ep_pcie_core.c
index f3cc96c271a7..f6d39031c5d5 100644
--- a/drivers/platform/msm/ep_pcie/ep_pcie_core.c
+++ b/drivers/platform/msm/ep_pcie/ep_pcie_core.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015, 2018, 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
@@ -64,7 +64,9 @@ static struct ep_pcie_clk_info_t
{NULL, "pcie_0_slv_axi_clk", 0, true},
{NULL, "pcie_0_aux_clk", 1000000, true},
{NULL, "pcie_0_ldo", 0, true},
- {NULL, "pcie_0_phy_reset", 0, false}
+ {NULL, "pcie_0_phy_reset", 0, false},
+ {NULL, "pcie_0_phy_cfg_ahb_clk", 0, false},
+ {NULL, "pcie_0_phy_aux_clk", 0, false}
};
static struct ep_pcie_clk_info_t
@@ -131,11 +133,18 @@ static int ep_pcie_gpio_init(struct ep_pcie_dev_t *dev)
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;
+ if (i == EP_PCIE_GPIO_MDM2AP) {
+ EP_PCIE_DBG(dev,
+ "PCIe V%d: gpio %s does not exist.\n",
+ dev->rev, info->name);
+ continue;
+ } else {
+ 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);
@@ -451,6 +460,109 @@ static void ep_pcie_bar_init(struct ep_pcie_dev_t *dev)
ep_pcie_write_mask(dev->dm_core + PCIE20_MISC_CONTROL_1, BIT(0), 0);
}
+#ifdef CONFIG_ARCH_MSM8996
+static void ep_pcie_core_init(struct ep_pcie_dev_t *dev)
+{
+ u32 regval;
+
+ EP_PCIE_DBG(dev, "PCIe V%d\n", dev->rev);
+
+ /* Configure PCIe to endpoint mode */
+ ep_pcie_write_reg(dev->parf, PCIE20_PARF_DEVICE_TYPE, 0x0);
+
+ /* adjust DBI base address */
+ writel_relaxed(0x0C000000, 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);
+
+ /* Disable the debouncers */
+ ep_pcie_write_reg(dev->parf, PCIE20_PARF_DB_CTRL, 0x73);
+
+ /* Enable Auxiliary Power Detect */
+ ep_pcie_write_mask(dev->parf + PCIE20_PARF_SYS_CTRL, 0x10, BIT(4));
+
+ /* Enable the bit to exit l1ss when sending LTR and MSI */
+ ep_pcie_write_mask(dev->parf + PCIE20_PARF_CFG_BITS, 0x2, BIT(1));
+
+ /* Enable CS for RO(CS) register writes */
+ ep_pcie_write_mask(dev->dm_core + PCIE20_MISC_CONTROL_1, 0, BIT(0));
+
+ /* Set the INT_LINE Register field to 0 */
+ ep_pcie_write_mask(dev->dm_core +
+ PCIE20_BRIDGE_CTRL_INT_PIN_INT_LINE_REG, 0xff, 0);
+
+ /* Set the PMC Register - to support PME in D0, D3hot and D3cold */
+ ep_pcie_write_mask(dev->dm_core + PCIE20_CAP_ID_NXT_PTR,
+ 0xF8000000, BIT(31) | BIT(30) | BIT(27));
+
+ /* Set the frequency for the AUX clock to 19.2MHz */
+ ep_pcie_write_mask(dev->dm_core + PCIE20_AUX_CLK_FREQ_REG,
+ 0x3FF, BIT(4) | BIT(2));
+
+ /* Set the Endpoint L0s Acceptable Latency to 1us (max) */
+ ep_pcie_write_mask(dev->dm_core + PCIE20_DEVICE_CAPABILITIES,
+ 0x1C0, BIT(8) | BIT(7) | BIT(6));
+
+ /* Set the Endpoint L1 Acceptable Latency to 2 us (max) */
+ ep_pcie_write_mask(dev->dm_core + PCIE20_DEVICE_CAPABILITIES,
+ 0xE00, BIT(11) | BIT(10) | BIT(9));
+
+ /* Set the L0s Exit Latency to 2us-4us = 0x6 */
+ ep_pcie_write_mask(dev->dm_core + PCIE20_LINK_CAPABILITIES,
+ 0x38000, BIT(17) | BIT(16));
+
+ /* Set the L1 Exit Latency to be 32us-64 us = 0x6 */
+ ep_pcie_write_mask(dev->dm_core + PCIE20_LINK_CAPABILITIES,
+ 0x7000, BIT(14) | BIT(13));
+
+ /* Enable Clock Power Management */
+ ep_pcie_write_mask(dev->dm_core + PCIE20_LINK_CAPABILITIES,
+ 0x40000, BIT(18));
+
+ /* Disable CS for RO(CS) register writes */
+ ep_pcie_write_mask(dev->dm_core + PCIE20_MISC_CONTROL_1, BIT(0), 0);
+
+ /* Enable writes for RO(CS2) */
+ ep_pcie_write_mask(dev->elbi + PCIE20_ELBI_CS2_ENABLE, 0, BIT(0));
+
+ /* Set the Common Clock L0s Exit Latency to 2us-4us = 0x6 */
+ ep_pcie_write_mask(dev->dm_core + PCIE20_LINK_CAPABILITIES,
+ 0x38000, BIT(17) | BIT(16));
+
+ /* Set the Common Clock L1 Exit Latency to be 32us-64 us = 0x6 */
+ ep_pcie_write_mask(dev->dm_core + PCIE20_LINK_CAPABILITIES,
+ 0x7000, BIT(14) | BIT(13));
+
+ /* Disable writes for RO(CS2) */
+ ep_pcie_write_mask(dev->elbi + PCIE20_ELBI_CS2_ENABLE, BIT(0), 0);
+
+ /* T_Power_Off */
+ ep_pcie_write_mask(dev->dm_core + PCIE20_L1_SUBSTATES_REG,
+ BIT(1) | BIT(0), 0);
+
+ /* Set Device ID and Vendor ID */
+ ep_pcie_write_mask(dev->dm_core + PCIE20_MISC_CONTROL_1, 0, BIT(0));
+ ep_pcie_write_reg(dev->dm_core, PCIE20_DEVICE_ID_VENDOR_ID_REG,
+ 0x030217cb);
+ ep_pcie_write_mask(dev->dm_core + PCIE20_MISC_CONTROL_1, BIT(0), 0);
+
+ /* Configure link speed */
+ ep_pcie_write_mask(dev->dm_core + PCIE20_LINK_CONTROL2_LINK_STATUS2,
+ 0xf, dev->link_speed);
+
+ /* Configure BARs */
+ ep_pcie_bar_init(dev);
+
+ /* Enable MHI clocks */
+ ep_pcie_write_reg(dev->parf, PCIE20_PARF_MHI_CLOCK_RESET_CTRL,
+ BIT(1) | BIT(0));
+
+ ep_pcie_write_reg(dev->mmio, PCIE20_MHISTATUS, 0x0);
+ ep_pcie_write_reg(dev->mmio, PCIE20_BHI_EXECENV, 0x2);
+}
+#else
static void ep_pcie_core_init(struct ep_pcie_dev_t *dev)
{
EP_PCIE_DBG(dev, "PCIe V%d\n", dev->rev);
@@ -578,6 +690,7 @@ static void ep_pcie_core_init(struct ep_pcie_dev_t *dev)
ep_pcie_write_reg(dev->dm_core, PCIE20_AUX_CLK_FREQ_REG, 0x14);
}
+#endif
static void ep_pcie_config_inbound_iatu(struct ep_pcie_dev_t *dev)
{
@@ -694,6 +807,32 @@ static int ep_pcie_get_resources(struct ep_pcie_dev_t *dev,
EP_PCIE_DBG(dev, "PCIe V%d\n", dev->rev);
+ of_get_property(pdev->dev.of_node, "qcom,phy-sequence", &cnt);
+ if (cnt) {
+ dev->phy_sequence = (struct ep_pcie_phy_info_t *)
+ devm_kzalloc(&pdev->dev, cnt, GFP_KERNEL);
+
+ if (dev->phy_sequence) {
+ dev->phy_len =
+ cnt / sizeof(*dev->phy_sequence);
+
+ of_property_read_u32_array(pdev->dev.of_node,
+ "qcom,phy-sequence",
+ (unsigned int *)dev->phy_sequence,
+ cnt / sizeof(dev->phy_sequence->offset));
+ } else {
+ EP_PCIE_ERR(dev,
+ "PCIe V%d: Failed to alloc mem for phy seq.\n",
+ dev->rev);
+ ret = -ENOMEM;
+ goto out;
+ }
+ } else {
+ EP_PCIE_DBG(dev,
+ "PCIe V%d: phy sequence is not present in DT.\n",
+ dev->rev);
+ }
+
cnt = of_property_count_strings((&pdev->dev)->of_node,
"clock-names");
if (cnt > 0) {
@@ -782,6 +921,7 @@ static int ep_pcie_get_resources(struct ep_pcie_dev_t *dev,
EP_PCIE_DBG(dev,
"GPIO %s is not supported in this configuration.\n",
gpio_info->name);
+ ret = 0;
}
}
@@ -1070,6 +1210,9 @@ int ep_pcie_core_enable_endpoint(enum ep_pcie_options opt)
EP_PCIE_INFO(dev, "PCIe V%d: PCIe PHY is ready!\n", dev->rev);
}
+#ifdef CONFIG_ARCH_MSM8996
+ ep_pcie_phy_bringup_port(dev);
+#endif
ep_pcie_core_init(dev);
ep_pcie_config_inbound_iatu(dev);
@@ -1977,6 +2120,17 @@ static int ep_pcie_probe(struct platform_device *pdev)
EP_PCIE_DBG(&ep_pcie_dev, "PCIe V%d: pcie-link-speed:%d.\n",
ep_pcie_dev.rev, ep_pcie_dev.link_speed);
+ ret = of_property_read_u32((&pdev->dev)->of_node,
+ "qcom,phy-status-reg",
+ &ep_pcie_dev.phy_status_reg);
+ if (ret)
+ EP_PCIE_DBG(&ep_pcie_dev,
+ "PCIe V%d: phy-status-reg does not exist.\n",
+ ep_pcie_dev.rev);
+ else
+ EP_PCIE_DBG(&ep_pcie_dev, "PCIe V%d: phy-status-reg:0x%x.\n",
+ ep_pcie_dev.rev, ep_pcie_dev.phy_status_reg);
+
ep_pcie_dev.phy_rev = 1;
ret = of_property_read_u32((&pdev->dev)->of_node,
"qcom,pcie-phy-ver",
diff --git a/drivers/platform/msm/ep_pcie/ep_pcie_phy.c b/drivers/platform/msm/ep_pcie/ep_pcie_phy.c
index 83e74f2c7ba7..3dfabd3ed81f 100644
--- a/drivers/platform/msm/ep_pcie/ep_pcie_phy.c
+++ b/drivers/platform/msm/ep_pcie/ep_pcie_phy.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015, 2018, 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
@@ -13,6 +13,7 @@
/*
* MSM PCIe PHY endpoint mode
*/
+#include <linux/delay.h>
#include "ep_pcie_com.h"
#include "ep_pcie_phy.h"
@@ -23,6 +24,28 @@ void ep_pcie_phy_init(struct ep_pcie_dev_t *dev)
"PCIe V%d: PHY V%d: Initializing 14nm QMP phy - 100MHz\n",
dev->rev, dev->phy_rev);
+ if (dev->phy_sequence) {
+ int i;
+ struct ep_pcie_phy_info_t *phy_seq;
+
+ EP_PCIE_DBG(dev,
+ "PCIe V%d: PHY V%d: process the sequence specified by DT.!\n",
+ dev->rev, dev->phy_rev);
+
+ i = dev->phy_len;
+ phy_seq = dev->phy_sequence;
+ while (i--) {
+ ep_pcie_write_reg(dev->phy,
+ phy_seq->offset,
+ phy_seq->val);
+ if (phy_seq->delay)
+ usleep_range(phy_seq->delay,
+ phy_seq->delay + 1);
+ phy_seq++;
+ }
+ return;
+ }
+
ep_pcie_write_reg(dev->phy, PCIE_PHY_SW_RESET, 0x01);
ep_pcie_write_reg(dev->phy, PCIE_PHY_POWER_DOWN_CONTROL, 0x01);
@@ -104,10 +127,26 @@ void ep_pcie_phy_init(struct ep_pcie_dev_t *dev)
ep_pcie_write_reg(dev->phy, PCIE_PHY_START_CONTROL, 0x03);
}
+#ifdef CONFIG_ARCH_MSM8996
+void ep_pcie_phy_bringup_port(struct ep_pcie_dev_t *dev)
+{
+ ep_pcie_write_reg(dev->phy, PCIE_PORT_POWER_DOWN_CONTROL, 0x03);
+ ep_pcie_write_reg(dev->phy, PCIE_PORT_SW_RESET, 0x0);
+ ep_pcie_write_reg(dev->phy, PCIE_PORT_START_CONTROL, 0x0a);
+}
+#endif
+
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;
+ u32 offset;
+
+ if (dev->phy_status_reg)
+ offset = dev->phy_status_reg;
else
+ offset = PCIE_PHY_PCS_STATUS;
+
+ if (readl_relaxed(dev->phy + offset) & BIT(0))
return true;
+ else
+ return false;
}
diff --git a/drivers/platform/msm/ep_pcie/ep_pcie_phy.h b/drivers/platform/msm/ep_pcie/ep_pcie_phy.h
index 199e0760956a..884f9fdf7dba 100644
--- a/drivers/platform/msm/ep_pcie/ep_pcie_phy.h
+++ b/drivers/platform/msm/ep_pcie/ep_pcie_phy.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015, 2018, 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
@@ -460,4 +460,34 @@
#define PCIE_PHY_LFPS_PER_TIMER_VAL 0x9EC
#define PCIE_PHY_SIGDET_STARTUP_TIMER_VAL 0x9F0
#define PCIE_PHY_LOCK_DETECT_CONFIG4 0x9F4
+#ifdef CONFIG_ARCH_MSM8996
+#define QSERDES_TX_RES_CODE_LANE_OFFSET 0x1054
+#define QSERDES_TX_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN 0x1068
+#define QSERDES_TX_LANE_MODE 0x1094
+#define QSERDES_TX_RCV_DETECT_LVL_2 0x10AC
+#define QSERDES_RX_UCDR_FO_GAIN_HALF 0x1200
+#define QSERDES_RX_UCDR_FO_GAIN 0x120C
+#define QSERDES_RX_UCDR_SO_GAIN_HALF 0x1210
+#define QSERDES_RX_UCDR_SO_GAIN 0x121C
+#define QSERDES_RX_UCDR_SO_SATURATION_AND_ENABLE 0x1248
+#define QSERDES_RX_RX_EQU_ADAPTOR_CNTRL1 0x12D4
+#define QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2 0x12D8
+#define QSERDES_RX_RX_EQU_ADAPTOR_CNTRL3 0x12DC
+#define QSERDES_RX_RX_EQU_ADAPTOR_CNTRL4 0x12E0
+#define QSERDES_RX_RX_OFFSET_ADAPTOR_CNTRL2 0x130C
+#define QSERDES_RX_SIGDET_ENABLES 0x1310
+#define QSERDES_RX_SIGDET_CNTRL 0x1314
+#define QSERDES_RX_SIGDET_LVL 0x1318
+#define QSERDES_RX_SIGDET_DEGLITCH_CNTRL 0x131C
+#define PCIE_PHY_SW_RESET 0x400
+#define PCIE_PHY_POWER_DOWN_CONTROL 0x404
+#define PCIE_PHY_START_CONTROL 0x408
+#define PCIE_PHY_ENDPOINT_REFCLK_DRIVE 0x1454
+#define PCIE_PHY_PWRUP_RESET_DLY_TIME_AUXCLK 0x14A0
+#define PCIE_PORT_ENDPOINT_REFCLK_DRIVE 0x1454
+#define PCIE_PORT_POWER_DOWN_CONTROL 0x1404
+#define PCIE_PORT_SW_RESET 0x1400
+#define PCIE_PORT_START_CONTROL 0x1408
+#define PCIE_COM_PCS_READY_STATUS 0x448
+#endif
#endif