From ee930fffee469d076998274a2ca55e13dc1efb67 Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Fri, 10 May 2024 08:50:54 +0000
Subject: [PATCH] enable tun/tap/iptables
---
kernel/drivers/pci/controller/dwc/pcie-dw-rockchip.c | 1091 +++++++++++++++++++++++++++++++++++++++++++-------------
1 files changed, 829 insertions(+), 262 deletions(-)
diff --git a/kernel/drivers/pci/controller/dwc/pcie-dw-rockchip.c b/kernel/drivers/pci/controller/dwc/pcie-dw-rockchip.c
index 33b6dc3..e22295e 100644
--- a/kernel/drivers/pci/controller/dwc/pcie-dw-rockchip.c
+++ b/kernel/drivers/pci/controller/dwc/pcie-dw-rockchip.c
@@ -8,12 +8,14 @@
* Author: Simon Xue <xxm@rock-chips.com>
*/
+#include <dt-bindings/phy/phy.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/fs.h>
#include <linux/gpio.h>
#include <linux/init.h>
#include <linux/interrupt.h>
+#include <linux/iopoll.h>
#include <linux/irq.h>
#include <linux/irqchip/chained_irq.h>
#include <linux/irqdomain.h>
@@ -29,6 +31,7 @@
#include <linux/of_pci.h>
#include <linux/pci.h>
#include <linux/phy/phy.h>
+#include <linux/phy/pcie.h>
#include <linux/platform_device.h>
#include <linux/poll.h>
#include <linux/regmap.h>
@@ -50,15 +53,11 @@
RK_PCIE_RC_TYPE,
};
-struct reset_bulk_data {
- const char *id;
- struct reset_control *rst;
-};
-
#define RK_PCIE_DBG 0
#define PCIE_DMA_OFFSET 0x380000
+#define PCIE_DMA_CTRL_OFF 0x8
#define PCIE_DMA_WR_ENB 0xc
#define PCIE_DMA_WR_CTRL_LO 0x200
#define PCIE_DMA_WR_CTRL_HI 0x204
@@ -102,6 +101,8 @@
#define PCIE_CAP_LINK_CONTROL2_LINK_STATUS 0xa0
+#define PCIE_CLIENT_INTR_STATUS_MSG_RX 0x04
+#define PME_TO_ACK (BIT(9) | BIT(25))
#define PCIE_CLIENT_INTR_STATUS_LEGACY 0x08
#define PCIE_CLIENT_INTR_STATUS_MISC 0x10
#define PCIE_CLIENT_INTR_MASK_LEGACY 0x1c
@@ -109,12 +110,21 @@
#define MASK_LEGACY_INT(x) (0x00110011 << x)
#define UNMASK_LEGACY_INT(x) (0x00110000 << x)
#define PCIE_CLIENT_INTR_MASK 0x24
+#define PCIE_CLIENT_POWER 0x2c
+#define READY_ENTER_L23 BIT(3)
+#define PCIE_CLIENT_MSG_GEN 0x34
+#define PME_TURN_OFF (BIT(4) | BIT(20))
#define PCIE_CLIENT_GENERAL_DEBUG 0x104
#define PCIE_CLIENT_HOT_RESET_CTRL 0x180
+#define PCIE_LTSSM_APP_DLY1_EN BIT(0)
+#define PCIE_LTSSM_APP_DLY2_EN BIT(1)
+#define PCIE_LTSSM_APP_DLY1_DONE BIT(2)
+#define PCIE_LTSSM_APP_DLY2_DONE BIT(3)
#define PCIE_LTSSM_ENABLE_ENHANCE BIT(4)
#define PCIE_CLIENT_LTSSM_STATUS 0x300
#define SMLH_LINKUP BIT(16)
#define RDLH_LINKUP BIT(17)
+#define PCIE_CLIENT_CDM_RASDES_TBA_INFO_CMN 0x154
#define PCIE_CLIENT_DBG_FIFO_MODE_CON 0x310
#define PCIE_CLIENT_DBG_FIFO_PTN_HIT_D0 0x320
#define PCIE_CLIENT_DBG_FIFO_PTN_HIT_D1 0x324
@@ -122,20 +132,32 @@
#define PCIE_CLIENT_DBG_FIFO_TRN_HIT_D1 0x32c
#define PCIE_CLIENT_DBG_FIFO_STATUS 0x350
#define PCIE_CLIENT_DBG_TRANSITION_DATA 0xffff0000
-#define PCIE_CLIENT_DBF_EN 0xffff0003
+#define PCIE_CLIENT_DBF_EN 0xffff0007
#define PCIE_PHY_LINKUP BIT(0)
#define PCIE_DATA_LINKUP BIT(1)
-#define PCIE_RESBAR_CTRL_REG0_REG 0x2a8
+#define PCIE_TYPE0_HDR_DBI2_OFFSET 0x100000
#define PCIE_SB_BAR0_MASK_REG 0x100010
#define PCIE_PL_ORDER_RULE_CTRL_OFF 0x8B4
+#define RK_PCIE_L2_TMOUT_US 5000
+#define RK_PCIE_HOTRESET_TMOUT_US 10000
+#define RK_PCIE_ENUM_HW_RETRYIES 2
+
+enum rk_pcie_ltssm_code {
+ S_L0 = 0x11,
+ S_L0S = 0x12,
+ S_L1_IDLE = 0x14,
+ S_L2_IDLE = 0x15,
+ S_MAX = 0x1f,
+};
struct rk_pcie {
struct dw_pcie *pci;
enum rk_pcie_device_mode mode;
enum phy_mode phy_mode;
+ int phy_sub_mode;
unsigned char bar_to_atu[6];
phys_addr_t *outbound_addr;
unsigned long *ib_window_map;
@@ -146,9 +168,10 @@
void __iomem *apb_base;
struct phy *phy;
struct clk_bulk_data *clks;
+ struct reset_control *rsts;
unsigned int clk_cnt;
- struct reset_bulk_data *rsts;
struct gpio_desc *rst_gpio;
+ u32 perst_inactive_ms;
struct gpio_desc *prsnt_gpio;
phys_addr_t mem_start;
size_t mem_size;
@@ -157,15 +180,22 @@
struct regmap *pmu_grf;
struct dma_trx_obj *dma_obj;
bool in_suspend;
- bool skip_scan_in_resume;
+ bool skip_scan_in_resume;
bool is_rk1808;
bool is_signal_test;
bool bifurcation;
+ bool supports_clkreq;
struct regulator *vpcie3v3;
struct irq_domain *irq_domain;
raw_spinlock_t intx_lock;
+ u16 aspm;
+ u32 l1ss_ctl1;
struct dentry *debugfs;
u32 msi_vector_num;
+ struct workqueue_struct *hot_rst_wq;
+ struct work_struct hot_rst_work;
+ u32 comp_prst[2];
+ u32 intx;
};
struct rk_pcie_of_data {
@@ -174,7 +204,8 @@
};
#define to_rk_pcie(x) dev_get_drvdata((x)->dev)
-static const struct dev_pm_ops rockchip_dw_pcie_pm_ops;
+static int rk_pcie_disable_power(struct rk_pcie *rk_pcie);
+static int rk_pcie_enable_power(struct rk_pcie *rk_pcie);
static int rk_pcie_read(void __iomem *addr, int size, u32 *val)
{
@@ -259,12 +290,154 @@
return 0;
}
+static void rk_pcie_writel_atu(struct dw_pcie *pci, u32 reg, u32 val)
+{
+ int ret;
+
+ if (pci->ops->write_dbi) {
+ pci->ops->write_dbi(pci, pci->atu_base, reg, 4, val);
+ return;
+ }
+
+ ret = dw_pcie_write(pci->atu_base + reg, 4, val);
+ if (ret)
+ dev_err(pci->dev, "Write ATU address failed\n");
+}
+
+static void rk_pcie_writel_ib_unroll(struct dw_pcie *pci, u32 index, u32 reg,
+ u32 val)
+{
+ u32 offset = PCIE_GET_ATU_INB_UNR_REG_OFFSET(index);
+
+ rk_pcie_writel_atu(pci, offset + reg, val);
+}
+
+static u32 rk_pcie_readl_atu(struct dw_pcie *pci, u32 reg)
+{
+ int ret;
+ u32 val;
+
+ if (pci->ops->read_dbi)
+ return pci->ops->read_dbi(pci, pci->atu_base, reg, 4);
+
+ ret = dw_pcie_read(pci->atu_base + reg, 4, &val);
+ if (ret)
+ dev_err(pci->dev, "Read ATU address failed\n");
+
+ return val;
+}
+
+static u32 rk_pcie_readl_ib_unroll(struct dw_pcie *pci, u32 index, u32 reg)
+{
+ u32 offset = PCIE_GET_ATU_INB_UNR_REG_OFFSET(index);
+
+ return rk_pcie_readl_atu(pci, offset + reg);
+}
+
+static int rk_pcie_prog_inbound_atu_unroll(struct dw_pcie *pci, u8 func_no,
+ int index, int bar, u64 cpu_addr,
+ enum dw_pcie_as_type as_type)
+{
+ int type;
+ u32 retries, val;
+
+ rk_pcie_writel_ib_unroll(pci, index, PCIE_ATU_UNR_LOWER_TARGET,
+ lower_32_bits(cpu_addr));
+ rk_pcie_writel_ib_unroll(pci, index, PCIE_ATU_UNR_UPPER_TARGET,
+ upper_32_bits(cpu_addr));
+
+ switch (as_type) {
+ case DW_PCIE_AS_MEM:
+ type = PCIE_ATU_TYPE_MEM;
+ break;
+ case DW_PCIE_AS_IO:
+ type = PCIE_ATU_TYPE_IO;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ rk_pcie_writel_ib_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1, type |
+ PCIE_ATU_FUNC_NUM(func_no));
+ rk_pcie_writel_ib_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL2,
+ PCIE_ATU_FUNC_NUM_MATCH_EN |
+ PCIE_ATU_ENABLE |
+ PCIE_ATU_BAR_MODE_ENABLE | (bar << 8));
+
+ /*
+ * Make sure ATU enable takes effect before any subsequent config
+ * and I/O accesses.
+ */
+ for (retries = 0; retries < LINK_WAIT_MAX_IATU_RETRIES; retries++) {
+ val = rk_pcie_readl_ib_unroll(pci, index,
+ PCIE_ATU_UNR_REGION_CTRL2);
+ if (val & PCIE_ATU_ENABLE)
+ return 0;
+
+ mdelay(LINK_WAIT_IATU);
+ }
+ dev_err(pci->dev, "Inbound iATU is not being enabled\n");
+
+ return -EBUSY;
+}
+
+
+static int rk_pcie_prog_inbound_atu(struct dw_pcie *pci, u8 func_no, int index,
+ int bar, u64 cpu_addr,
+ enum dw_pcie_as_type as_type)
+{
+ int type;
+ u32 retries, val;
+
+ if (pci->iatu_unroll_enabled)
+ return rk_pcie_prog_inbound_atu_unroll(pci, func_no, index, bar,
+ cpu_addr, as_type);
+
+ dw_pcie_writel_dbi(pci, PCIE_ATU_VIEWPORT, PCIE_ATU_REGION_INBOUND |
+ index);
+ dw_pcie_writel_dbi(pci, PCIE_ATU_LOWER_TARGET, lower_32_bits(cpu_addr));
+ dw_pcie_writel_dbi(pci, PCIE_ATU_UPPER_TARGET, upper_32_bits(cpu_addr));
+
+ switch (as_type) {
+ case DW_PCIE_AS_MEM:
+ type = PCIE_ATU_TYPE_MEM;
+ break;
+ case DW_PCIE_AS_IO:
+ type = PCIE_ATU_TYPE_IO;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ dw_pcie_writel_dbi(pci, PCIE_ATU_CR1, type |
+ PCIE_ATU_FUNC_NUM(func_no));
+ dw_pcie_writel_dbi(pci, PCIE_ATU_CR2, PCIE_ATU_ENABLE |
+ PCIE_ATU_FUNC_NUM_MATCH_EN |
+ PCIE_ATU_BAR_MODE_ENABLE | (bar << 8));
+
+ /*
+ * Make sure ATU enable takes effect before any subsequent config
+ * and I/O accesses.
+ */
+ for (retries = 0; retries < LINK_WAIT_MAX_IATU_RETRIES; retries++) {
+ val = dw_pcie_readl_dbi(pci, PCIE_ATU_CR2);
+ if (val & PCIE_ATU_ENABLE)
+ return 0;
+
+ mdelay(LINK_WAIT_IATU);
+ }
+ dev_err(pci->dev, "Inbound iATU is not being enabled\n");
+
+ return -EBUSY;
+}
+
static int rk_pcie_ep_inbound_atu(struct rk_pcie *rk_pcie,
enum pci_barno bar, dma_addr_t cpu_addr,
enum dw_pcie_as_type as_type)
{
int ret;
u32 free_win;
+ u8 func_no = 0x0;
if (rk_pcie->in_suspend) {
free_win = rk_pcie->bar_to_atu[bar];
@@ -277,8 +450,8 @@
}
}
- ret = dw_pcie_prog_inbound_atu(rk_pcie->pci, free_win, bar, cpu_addr,
- as_type);
+ ret = rk_pcie_prog_inbound_atu(rk_pcie->pci, func_no, free_win, bar,
+ cpu_addr, as_type);
if (ret < 0) {
dev_err(rk_pcie->pci->dev, "Failed to program IB window\n");
return ret;
@@ -291,6 +464,105 @@
set_bit(free_win, rk_pcie->ib_window_map);
return 0;
+}
+
+static void rk_pcie_writel_ob_unroll(struct dw_pcie *pci, u32 index, u32 reg,
+ u32 val)
+{
+ u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index);
+
+ rk_pcie_writel_atu(pci, offset + reg, val);
+}
+
+static u32 rk_pcie_readl_ob_unroll(struct dw_pcie *pci, u32 index, u32 reg)
+{
+ u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index);
+
+ return rk_pcie_readl_atu(pci, offset + reg);
+}
+
+static void rk_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, u8 func_no,
+ int index, int type,
+ u64 cpu_addr, u64 pci_addr,
+ u32 size)
+{
+ u32 retries, val;
+ u64 limit_addr = cpu_addr + size - 1;
+
+ rk_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LOWER_BASE,
+ lower_32_bits(cpu_addr));
+ rk_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_BASE,
+ upper_32_bits(cpu_addr));
+ rk_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LOWER_LIMIT,
+ lower_32_bits(limit_addr));
+ rk_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_LIMIT,
+ upper_32_bits(limit_addr));
+ rk_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LOWER_TARGET,
+ lower_32_bits(pci_addr));
+ rk_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_TARGET,
+ upper_32_bits(pci_addr));
+ rk_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1,
+ type | PCIE_ATU_FUNC_NUM(func_no));
+ rk_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL2,
+ PCIE_ATU_ENABLE);
+
+ /*
+ * Make sure ATU enable takes effect before any subsequent config
+ * and I/O accesses.
+ */
+ for (retries = 0; retries < LINK_WAIT_MAX_IATU_RETRIES; retries++) {
+ val = rk_pcie_readl_ob_unroll(pci, index,
+ PCIE_ATU_UNR_REGION_CTRL2);
+ if (val & PCIE_ATU_ENABLE)
+ return;
+
+ mdelay(LINK_WAIT_IATU);
+ }
+ dev_err(pci->dev, "Outbound iATU is not being enabled\n");
+}
+
+static void rk_pcie_prog_outbound_atu(struct dw_pcie *pci, int index,
+ int type, u64 cpu_addr, u64 pci_addr, u32 size)
+{
+ u32 retries, val;
+
+ if (pci->ops->cpu_addr_fixup)
+ cpu_addr = pci->ops->cpu_addr_fixup(pci, cpu_addr);
+
+ if (pci->iatu_unroll_enabled) {
+ rk_pcie_prog_outbound_atu_unroll(pci, 0x0, index, type,
+ cpu_addr, pci_addr, size);
+ return;
+ }
+
+ dw_pcie_writel_dbi(pci, PCIE_ATU_VIEWPORT,
+ PCIE_ATU_REGION_OUTBOUND | index);
+ dw_pcie_writel_dbi(pci, PCIE_ATU_LOWER_BASE,
+ lower_32_bits(cpu_addr));
+ dw_pcie_writel_dbi(pci, PCIE_ATU_UPPER_BASE,
+ upper_32_bits(cpu_addr));
+ dw_pcie_writel_dbi(pci, PCIE_ATU_LIMIT,
+ lower_32_bits(cpu_addr + size - 1));
+ dw_pcie_writel_dbi(pci, PCIE_ATU_LOWER_TARGET,
+ lower_32_bits(pci_addr));
+ dw_pcie_writel_dbi(pci, PCIE_ATU_UPPER_TARGET,
+ upper_32_bits(pci_addr));
+ dw_pcie_writel_dbi(pci, PCIE_ATU_CR1, type |
+ PCIE_ATU_FUNC_NUM(0x0));
+ dw_pcie_writel_dbi(pci, PCIE_ATU_CR2, PCIE_ATU_ENABLE);
+
+ /*
+ * Make sure ATU enable takes effect before any subsequent config
+ * and I/O accesses.
+ */
+ for (retries = 0; retries < LINK_WAIT_MAX_IATU_RETRIES; retries++) {
+ val = dw_pcie_readl_dbi(pci, PCIE_ATU_CR2);
+ if (val & PCIE_ATU_ENABLE)
+ return;
+
+ mdelay(LINK_WAIT_IATU);
+ }
+ dev_err(pci->dev, "Outbound iATU is not being enabled\n");
}
static int rk_pcie_ep_outbound_atu(struct rk_pcie *rk_pcie,
@@ -311,7 +583,7 @@
}
}
- dw_pcie_prog_outbound_atu(rk_pcie->pci, free_win, PCIE_ATU_TYPE_MEM,
+ rk_pcie_prog_outbound_atu(rk_pcie->pci, free_win, PCIE_ATU_TYPE_MEM,
phys_addr, pci_addr, size);
if (rk_pcie->in_suspend)
@@ -368,6 +640,28 @@
return 0;
}
+#if defined(CONFIG_PCIEASPM)
+static void disable_aspm_l1ss(struct rk_pcie *rk_pcie)
+{
+ u32 val, cfg_link_cap_l1sub;
+
+ val = dw_pcie_find_ext_capability(rk_pcie->pci, PCI_EXT_CAP_ID_L1SS);
+ if (!val) {
+ dev_err(rk_pcie->pci->dev, "can't find l1ss cap\n");
+
+ return;
+ }
+
+ cfg_link_cap_l1sub = val + PCI_L1SS_CAP;
+
+ val = dw_pcie_readl_dbi(rk_pcie->pci, cfg_link_cap_l1sub);
+ val &= ~(PCI_L1SS_CAP_ASPM_L1_1 | PCI_L1SS_CAP_ASPM_L1_2 | PCI_L1SS_CAP_L1_PM_SS);
+ dw_pcie_writel_dbi(rk_pcie->pci, cfg_link_cap_l1sub, val);
+}
+#else
+static inline void disable_aspm_l1ss(struct rk_pcie *rk_pcie) { return; }
+#endif
+
static inline void rk_pcie_set_mode(struct rk_pcie *rk_pcie)
{
switch (rk_pcie->mode) {
@@ -375,6 +669,14 @@
rk_pcie_writel_apb(rk_pcie, 0x0, 0xf00000);
break;
case RK_PCIE_RC_TYPE:
+ if (rk_pcie->supports_clkreq) {
+ /* Application is ready to have reference clock removed */
+ rk_pcie_writel_apb(rk_pcie, PCIE_CLIENT_POWER, 0x00010001);
+ } else {
+ /* Pull down CLKREQ# to assert the connecting CLOCK_GEN OE */
+ rk_pcie_writel_apb(rk_pcie, PCIE_CLIENT_POWER, 0x30011000);
+ disable_aspm_l1ss(rk_pcie);
+ }
rk_pcie_writel_apb(rk_pcie, 0x0, 0xf00040);
/*
* Disable order rule for CPL can't pass halted P queue.
@@ -404,28 +706,10 @@
rk_pcie_writel_apb(rk_pcie, 0x0, 0xC000C);
}
-static int rk_pcie_link_up(struct dw_pcie *pci)
-{
- struct rk_pcie *rk_pcie = to_rk_pcie(pci);
- u32 val;
-
- if (rk_pcie->is_rk1808) {
- val = rk_pcie_readl_apb(rk_pcie, PCIE_CLIENT_GENERAL_DEBUG);
- if ((val & (PCIE_PHY_LINKUP | PCIE_DATA_LINKUP)) == 0x3 &&
- ((val & GENMASK(15, 10)) >> 10) == 0x11)
- return 1;
- } else {
- val = rk_pcie_readl_apb(rk_pcie, PCIE_CLIENT_LTSSM_STATUS);
- if ((val & (RDLH_LINKUP | SMLH_LINKUP)) == 0x30000)
- return 1;
- }
-
- return 0;
-}
-
static void rk_pcie_enable_debug(struct rk_pcie *rk_pcie)
{
-#if RK_PCIE_DBG
+ if (!IS_ENABLED(CONFIG_DEBUG_FS))
+ return;
if (rk_pcie->is_rk1808 == true)
return;
@@ -439,7 +723,6 @@
PCIE_CLIENT_DBG_TRANSITION_DATA);
rk_pcie_writel_apb(rk_pcie, PCIE_CLIENT_DBG_FIFO_MODE_CON,
PCIE_CLIENT_DBF_EN);
-#endif
}
static void rk_pcie_debug_dump(struct rk_pcie *rk_pcie)
@@ -461,6 +744,8 @@
int retries, power;
struct rk_pcie *rk_pcie = to_rk_pcie(pci);
bool std_rc = rk_pcie->mode == RK_PCIE_RC_TYPE && !rk_pcie->dma_obj;
+ int hw_retries = 0;
+ u32 ltssm;
/*
* For standard RC, even if the link has been setup by firmware,
@@ -472,80 +757,113 @@
return 0;
}
- rk_pcie_disable_ltssm(rk_pcie);
- rk_pcie_link_status_clear(rk_pcie);
- rk_pcie_enable_debug(rk_pcie);
+ for (hw_retries = 0; hw_retries < RK_PCIE_ENUM_HW_RETRYIES; hw_retries++) {
+ /* Rest the device */
+ gpiod_set_value_cansleep(rk_pcie->rst_gpio, 0);
- /* Enable client reset or link down interrupt */
- rk_pcie_writel_apb(rk_pcie, PCIE_CLIENT_INTR_MASK, 0x40000);
+ rk_pcie_disable_ltssm(rk_pcie);
+ rk_pcie_link_status_clear(rk_pcie);
+ rk_pcie_enable_debug(rk_pcie);
- /* Enable LTSSM */
- rk_pcie_enable_ltssm(rk_pcie);
+ /* Enable client reset or link down interrupt */
+ rk_pcie_writel_apb(rk_pcie, PCIE_CLIENT_INTR_MASK, 0x40000);
- /*
- * In resume routine, function devices' resume function must be late after
- * controllers'. Some devices, such as Wi-Fi, need special IO setting before
- * finishing training. So there must be timeout here. These kinds of devices
- * need rescan devices by its driver when used. So no need to waste time waiting
- * for training pass.
- */
- if (rk_pcie->in_suspend && rk_pcie->skip_scan_in_resume) {
- rfkill_get_wifi_power_state(&power);
- if (!power) {
- gpiod_set_value_cansleep(rk_pcie->rst_gpio, 1);
- return 0;
+ /* Enable LTSSM */
+ rk_pcie_enable_ltssm(rk_pcie);
+
+ /*
+ * In resume routine, function devices' resume function must be late after
+ * controllers'. Some devices, such as Wi-Fi, need special IO setting before
+ * finishing training. So there must be timeout here. These kinds of devices
+ * need rescan devices by its driver when used. So no need to waste time waiting
+ * for training pass.
+ */
+ if (rk_pcie->in_suspend && rk_pcie->skip_scan_in_resume) {
+ rfkill_get_wifi_power_state(&power);
+ if (!power) {
+ gpiod_set_value_cansleep(rk_pcie->rst_gpio, 1);
+ return 0;
+ }
}
- }
- /*
- * PCIe requires the refclk to be stable for 100µs prior to releasing
- * PERST and T_PVPERL (Power stable to PERST# inactive) should be a
- * minimum of 100ms. See table 2-4 in section 2.6.2 AC, the PCI Express
- * Card Electromechanical Specification 3.0. So 100ms in total is the min
- * requuirement here. We add a 1s for sake of hoping everthings work fine.
- */
- msleep(1000);
- gpiod_set_value_cansleep(rk_pcie->rst_gpio, 1);
+ /*
+ * PCIe requires the refclk to be stable for 100µs prior to releasing
+ * PERST and T_PVPERL (Power stable to PERST# inactive) should be a
+ * minimum of 100ms. See table 2-4 in section 2.6.2 AC, the PCI Express
+ * Card Electromechanical Specification 3.0. So 100ms in total is the min
+ * requuirement here. We add a 200ms by default for sake of hoping everthings
+ * work fine. If it doesn't, please add more in DT node by add rockchip,perst-inactive-ms.
+ */
+ msleep(rk_pcie->perst_inactive_ms);
+ gpiod_set_value_cansleep(rk_pcie->rst_gpio, 1);
- /*
- * Add this 1ms delay because we observe link is always up stably after it and
- * could help us save 20ms for scanning devices.
- */
- usleep_range(1000, 1100);
+ /*
+ * Add this 1ms delay because we observe link is always up stably after it and
+ * could help us save 20ms for scanning devices.
+ */
+ usleep_range(1000, 1100);
- for (retries = 0; retries < 10; retries++) {
- if (dw_pcie_link_up(pci)) {
- /*
- * We may be here in case of L0 in Gen1. But if EP is capable
- * of Gen2 or Gen3, Gen switch may happen just in this time, but
- * we keep on accessing devices in unstable link status. Given
- * that LTSSM max timeout is 24ms per period, we can wait a bit
- * more for Gen switch.
- */
- msleep(100);
- dev_info(pci->dev, "PCIe Link up, LTSSM is 0x%x\n",
- rk_pcie_readl_apb(rk_pcie, PCIE_CLIENT_LTSSM_STATUS));
+ for (retries = 0; retries < 100; retries++) {
+ if (dw_pcie_link_up(pci)) {
+ /*
+ * We may be here in case of L0 in Gen1. But if EP is capable
+ * of Gen2 or Gen3, Gen switch may happen just in this time, but
+ * we keep on accessing devices in unstable link status. Given
+ * that LTSSM max timeout is 24ms per period, we can wait a bit
+ * more for Gen switch.
+ */
+ msleep(50);
+ /* In case link drop after linkup, double check it */
+ if (dw_pcie_link_up(pci)) {
+ dev_info(pci->dev, "PCIe Link up, LTSSM is 0x%x\n",
+ rk_pcie_readl_apb(rk_pcie, PCIE_CLIENT_LTSSM_STATUS));
+ rk_pcie_debug_dump(rk_pcie);
+ return 0;
+ }
+ }
+
+ dev_info_ratelimited(pci->dev, "PCIe Linking... LTSSM is 0x%x\n",
+ rk_pcie_readl_apb(rk_pcie, PCIE_CLIENT_LTSSM_STATUS));
rk_pcie_debug_dump(rk_pcie);
- return 0;
+ msleep(20);
}
- dev_info_ratelimited(pci->dev, "PCIe Linking... LTSSM is 0x%x\n",
- rk_pcie_readl_apb(rk_pcie, PCIE_CLIENT_LTSSM_STATUS));
- rk_pcie_debug_dump(rk_pcie);
- msleep(1000);
+ /*
+ * In response to the situation where PCIe peripherals cannot be
+ * enumerated due tosignal abnormalities, reset PERST# and reset
+ * the peripheral power supply, then restart the enumeration.
+ */
+ ltssm = rk_pcie_readl_apb(rk_pcie, PCIE_CLIENT_LTSSM_STATUS);
+ dev_err(pci->dev, "PCIe Link Fail, LTSSM is 0x%x, hw_retries=%d\n", ltssm, hw_retries);
+ if (ltssm >= 3 && !rk_pcie->is_signal_test) {
+ rk_pcie_disable_power(rk_pcie);
+ msleep(1000);
+ rk_pcie_enable_power(rk_pcie);
+ } else {
+ break;
+ }
}
-
- dev_err(pci->dev, "PCIe Link Fail\n");
return rk_pcie->is_signal_test == true ? 0 : -EINVAL;
}
+static bool rk_pcie_udma_enabled(struct rk_pcie *rk_pcie)
+{
+ return dw_pcie_readl_dbi(rk_pcie->pci, PCIE_DMA_OFFSET +
+ PCIE_DMA_CTRL_OFF);
+}
+
static int rk_pcie_init_dma_trx(struct rk_pcie *rk_pcie)
{
+ if (!rk_pcie_udma_enabled(rk_pcie))
+ return 0;
+
rk_pcie->dma_obj = rk_pcie_dma_obj_probe(rk_pcie->pci->dev);
if (IS_ERR(rk_pcie->dma_obj)) {
dev_err(rk_pcie->pci->dev, "failed to prepare dma object\n");
return -EINVAL;
+ } else if (rk_pcie->dma_obj) {
+ goto out;
}
rk_pcie->dma_obj = pcie_dw_dmatest_register(rk_pcie->pci->dev, true);
@@ -553,7 +871,7 @@
dev_err(rk_pcie->pci->dev, "failed to prepare dmatest\n");
return -EINVAL;
}
-
+out:
/* Enable client write and read interrupt */
rk_pcie_writel_apb(rk_pcie, PCIE_CLIENT_INTR_MASK, 0xc000000);
@@ -566,6 +884,76 @@
return 0;
}
+static int rk_pci_find_resbar_capability(struct rk_pcie *rk_pcie)
+{
+ u32 header;
+ int ttl;
+ int start = 0;
+ int pos = PCI_CFG_SPACE_SIZE;
+ int cap = PCI_EXT_CAP_ID_REBAR;
+
+ /* minimum 8 bytes per capability */
+ ttl = (PCI_CFG_SPACE_EXP_SIZE - PCI_CFG_SPACE_SIZE) / 8;
+
+ header = dw_pcie_readl_dbi(rk_pcie->pci, pos);
+
+ /*
+ * If we have no capabilities, this is indicated by cap ID,
+ * cap version and next pointer all being 0.
+ */
+ if (header == 0)
+ return 0;
+
+ while (ttl-- > 0) {
+ if (PCI_EXT_CAP_ID(header) == cap && pos != start)
+ return pos;
+
+ pos = PCI_EXT_CAP_NEXT(header);
+ if (pos < PCI_CFG_SPACE_SIZE)
+ break;
+
+ header = dw_pcie_readl_dbi(rk_pcie->pci, pos);
+ if (!header)
+ break;
+ }
+
+ return 0;
+}
+
+#ifdef MODULE
+void dw_pcie_write_dbi2(struct dw_pcie *pci, u32 reg, size_t size, u32 val)
+{
+ int ret;
+
+ if (pci->ops && pci->ops->write_dbi2) {
+ pci->ops->write_dbi2(pci, pci->dbi_base2, reg, size, val);
+ return;
+ }
+
+ ret = dw_pcie_write(pci->dbi_base2 + reg, size, val);
+ if (ret)
+ dev_err(pci->dev, "write DBI address failed\n");
+}
+#endif
+
+static int rk_pcie_ep_set_bar_flag(struct rk_pcie *rk_pcie, enum pci_barno barno, int flags)
+{
+ enum pci_barno bar = barno;
+ u32 reg;
+
+ reg = PCI_BASE_ADDRESS_0 + (4 * bar);
+
+ /* Disabled the upper 32bits BAR to make a 64bits bar pair */
+ if (flags & PCI_BASE_ADDRESS_MEM_TYPE_64)
+ dw_pcie_writel_dbi2(rk_pcie->pci, reg + 4, 0);
+
+ dw_pcie_writel_dbi(rk_pcie->pci, reg, flags);
+ if (flags & PCI_BASE_ADDRESS_MEM_TYPE_64)
+ dw_pcie_writel_dbi(rk_pcie->pci, reg + 4, 0);
+
+ return 0;
+}
+
static void rk_pcie_ep_setup(struct rk_pcie *rk_pcie)
{
int ret;
@@ -573,6 +961,8 @@
u32 lanes;
struct device *dev = rk_pcie->pci->dev;
struct device_node *np = dev->of_node;
+ int resbar_base;
+ int bar;
/* Enable client write and read interrupt */
rk_pcie_writel_apb(rk_pcie, PCIE_CLIENT_INTR_MASK, 0xc000000);
@@ -636,17 +1026,36 @@
/* Enable bus master and memory space */
dw_pcie_writel_dbi(rk_pcie->pci, PCIE_TYPE0_STATUS_COMMAND_REG, 0x6);
- /* Resize BAR0 to 4GB */
- /* bit13-8 set to 6 means 64MB */
- dw_pcie_writel_dbi(rk_pcie->pci, PCIE_RESBAR_CTRL_REG0_REG, 0x600);
+ resbar_base = rk_pci_find_resbar_capability(rk_pcie);
+ if (!resbar_base) {
+ dev_warn(dev, "failed to find resbar_base\n");
+ } else {
+ /* Resize BAR0 to support 512GB, BAR1 to support 8M, BAR2~5 to support 64M */
+ dw_pcie_writel_dbi(rk_pcie->pci, resbar_base + 0x4, 0xfffff0);
+ dw_pcie_writel_dbi(rk_pcie->pci, resbar_base + 0x8, 0x13c0);
+ dw_pcie_writel_dbi(rk_pcie->pci, resbar_base + 0xc, 0xfffff0);
+ dw_pcie_writel_dbi(rk_pcie->pci, resbar_base + 0x10, 0x3c0);
+ for (bar = 2; bar < 6; bar++) {
+ dw_pcie_writel_dbi(rk_pcie->pci, resbar_base + 0x4 + bar * 0x8, 0xfffff0);
+ dw_pcie_writel_dbi(rk_pcie->pci, resbar_base + 0x8 + bar * 0x8, 0x6c0);
+ }
- /* Set shadow BAR0 according 64MB */
- val = rk_pcie->mem_size - 1;
- dw_pcie_writel_dbi(rk_pcie->pci, PCIE_SB_BAR0_MASK_REG, val);
+ /* Set flags */
+ rk_pcie_ep_set_bar_flag(rk_pcie, BAR_0, PCI_BASE_ADDRESS_MEM_TYPE_32);
+ rk_pcie_ep_set_bar_flag(rk_pcie, BAR_1, PCI_BASE_ADDRESS_MEM_TYPE_32);
+ rk_pcie_ep_set_bar_flag(rk_pcie, BAR_2, PCI_BASE_ADDRESS_MEM_PREFETCH | PCI_BASE_ADDRESS_MEM_TYPE_64);
+ rk_pcie_ep_set_bar_flag(rk_pcie, BAR_4, PCI_BASE_ADDRESS_MEM_PREFETCH | PCI_BASE_ADDRESS_MEM_TYPE_64);
+ }
- /* Set reserved memory address to BAR0 */
- dw_pcie_writel_dbi(rk_pcie->pci, PCIE_TYPE0_BAR0_REG,
- rk_pcie->mem_start);
+ /* Device id and class id needed for request bar address */
+ dw_pcie_writew_dbi(rk_pcie->pci, PCI_DEVICE_ID, 0x356a);
+ dw_pcie_writew_dbi(rk_pcie->pci, PCI_CLASS_DEVICE, 0x0580);
+
+ /* Set shadow BAR0 */
+ if (rk_pcie->is_rk1808) {
+ val = rk_pcie->mem_size - 1;
+ dw_pcie_writel_dbi(rk_pcie->pci, PCIE_SB_BAR0_MASK_REG, val);
+ }
}
static int rk_pcie_ep_win_parse(struct rk_pcie *rk_pcie)
@@ -722,6 +1131,10 @@
dw_pcie_setup_rc(pp);
+ /* Disable BAR0 BAR1 */
+ dw_pcie_writel_dbi2(pci, PCI_BASE_ADDRESS_0, 0x0);
+ dw_pcie_writel_dbi2(pci, PCI_BASE_ADDRESS_1, 0x0);
+
ret = rk_pcie_establish_link(pci);
if (pp->msi_irq > 0)
@@ -754,9 +1167,6 @@
}
pp->ops = &rk_pcie_host_ops;
-
- if (device_property_read_bool(dev, "msi-map"))
- pp->msi_ext = 1;
ret = dw_pcie_host_init(pp);
if (ret) {
@@ -796,6 +1206,7 @@
return ret;
}
+ rk_pcie->pci->atu_base = rk_pcie->pci->dbi_base + DEFAULT_DBI_ATU_OFFSET;
rk_pcie->pci->iatu_unroll_enabled = rk_pcie_iatu_unroll_enabled(rk_pcie->pci);
ret = rk_pcie_ep_atu_init(rk_pcie);
@@ -812,52 +1223,24 @@
return ret;
}
- return 0;
-}
+ if (!rk_pcie_udma_enabled(rk_pcie))
+ return 0;
-static void rk_pcie_clk_deinit(struct rk_pcie *rk_pcie)
-{
- clk_bulk_disable(rk_pcie->clk_cnt, rk_pcie->clks);
- clk_bulk_unprepare(rk_pcie->clk_cnt, rk_pcie->clks);
+ return 0;
}
static int rk_pcie_clk_init(struct rk_pcie *rk_pcie)
{
struct device *dev = rk_pcie->pci->dev;
- struct property *prop;
- const char *name;
- int i = 0, ret, count;
+ int ret;
- count = of_property_count_strings(dev->of_node, "clock-names");
- if (count < 1)
+ rk_pcie->clk_cnt = devm_clk_bulk_get_all(dev, &rk_pcie->clks);
+ if (rk_pcie->clk_cnt < 1)
return -ENODEV;
- rk_pcie->clks = devm_kcalloc(dev, count,
- sizeof(struct clk_bulk_data),
- GFP_KERNEL);
- if (!rk_pcie->clks)
- return -ENOMEM;
-
- rk_pcie->clk_cnt = count;
-
- of_property_for_each_string(dev->of_node, "clock-names", prop, name) {
- rk_pcie->clks[i].id = name;
- if (!rk_pcie->clks[i].id)
- return -ENOMEM;
- i++;
- }
-
- ret = devm_clk_bulk_get(dev, count, rk_pcie->clks);
- if (ret)
- return ret;
-
- ret = clk_bulk_prepare(count, rk_pcie->clks);
- if (ret)
- return ret;
-
- ret = clk_bulk_enable(count, rk_pcie->clks);
+ ret = clk_bulk_prepare_enable(rk_pcie->clk_cnt, rk_pcie->clks);
if (ret) {
- clk_bulk_unprepare(count, rk_pcie->clks);
+ dev_err(dev, "failed to prepare enable pcie bulk clks: %d\n", ret);
return ret;
}
@@ -882,6 +1265,7 @@
return PTR_ERR(rk_pcie->dbi_base);
rk_pcie->pci->dbi_base = rk_pcie->dbi_base;
+ rk_pcie->pci->dbi_base2 = rk_pcie->pci->dbi_base + PCIE_TYPE0_HDR_DBI2_OFFSET;
apb_base = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"pcie-apb");
@@ -908,6 +1292,10 @@
return PTR_ERR(rk_pcie->rst_gpio);
}
+ if (device_property_read_u32(&pdev->dev, "rockchip,perst-inactive-ms",
+ &rk_pcie->perst_inactive_ms))
+ rk_pcie->perst_inactive_ms = 200;
+
rk_pcie->prsnt_gpio = devm_gpiod_get_optional(&pdev->dev, "prsnt", GPIOD_IN);
if (IS_ERR_OR_NULL(rk_pcie->prsnt_gpio))
dev_info(&pdev->dev, "invalid prsnt-gpios property in node\n");
@@ -920,7 +1308,7 @@
int ret;
struct device *dev = rk_pcie->pci->dev;
- rk_pcie->phy = devm_phy_get(dev, "pcie-phy");
+ rk_pcie->phy = devm_phy_optional_get(dev, "pcie-phy");
if (IS_ERR(rk_pcie->phy)) {
if (PTR_ERR(rk_pcie->phy) != -EPROBE_DEFER)
dev_info(dev, "missing phy\n");
@@ -929,23 +1317,27 @@
switch (rk_pcie->mode) {
case RK_PCIE_RC_TYPE:
- rk_pcie->phy_mode = PHY_MODE_PCIE_RC;
+ rk_pcie->phy_mode = PHY_MODE_PCIE; /* make no sense */
+ rk_pcie->phy_sub_mode = PHY_MODE_PCIE_RC;
break;
case RK_PCIE_EP_TYPE:
- rk_pcie->phy_mode = PHY_MODE_PCIE_EP;
+ rk_pcie->phy_mode = PHY_MODE_PCIE;
+ rk_pcie->phy_sub_mode = PHY_MODE_PCIE_EP;
break;
}
- ret = phy_set_mode(rk_pcie->phy, rk_pcie->phy_mode);
+ ret = phy_set_mode_ext(rk_pcie->phy, rk_pcie->phy_mode,
+ rk_pcie->phy_sub_mode);
if (ret) {
dev_err(dev, "fail to set phy to mode %s, err %d\n",
- (rk_pcie->phy_mode == PHY_MODE_PCIE_RC) ? "RC" : "EP",
+ (rk_pcie->phy_sub_mode == PHY_MODE_PCIE_RC) ? "RC" : "EP",
ret);
return ret;
}
if (rk_pcie->bifurcation)
- ret = phy_set_mode(rk_pcie->phy, PHY_MODE_PCIE_BIFURCATION);
+ phy_set_mode_ext(rk_pcie->phy, rk_pcie->phy_mode,
+ PHY_MODE_PCIE_BIFURCATION);
ret = phy_init(rk_pcie->phy);
if (ret < 0) {
@@ -954,53 +1346,6 @@
}
phy_power_on(rk_pcie->phy);
-
- return 0;
-}
-
-static int rk_pcie_reset_control_release(struct rk_pcie *rk_pcie)
-{
- struct device *dev = rk_pcie->pci->dev;
- struct property *prop;
- const char *name;
- int ret, count, i = 0;
-
- count = of_property_count_strings(dev->of_node, "reset-names");
- if (count < 1)
- return -ENODEV;
-
- rk_pcie->rsts = devm_kcalloc(dev, count,
- sizeof(struct reset_bulk_data),
- GFP_KERNEL);
- if (!rk_pcie->rsts)
- return -ENOMEM;
-
- of_property_for_each_string(dev->of_node, "reset-names",
- prop, name) {
- rk_pcie->rsts[i].id = name;
- if (!rk_pcie->rsts[i].id)
- return -ENOMEM;
- i++;
- }
-
- for (i = 0; i < count; i++) {
- rk_pcie->rsts[i].rst = devm_reset_control_get_exclusive(dev,
- rk_pcie->rsts[i].id);
- if (IS_ERR_OR_NULL(rk_pcie->rsts[i].rst)) {
- dev_err(dev, "failed to get %s\n",
- rk_pcie->clks[i].id);
- return -PTR_ERR(rk_pcie->rsts[i].rst);
- }
- }
-
- for (i = 0; i < count; i++) {
- ret = reset_control_deassert(rk_pcie->rsts[i].rst);
- if (ret) {
- dev_err(dev, "failed to release %s\n",
- rk_pcie->rsts[i].id);
- return ret;
- }
- }
return 0;
}
@@ -1105,13 +1450,37 @@
table->start.chnl = table->chn;
}
+static void rk_pcie_hot_rst_work(struct work_struct *work)
+{
+ struct rk_pcie *rk_pcie = container_of(work, struct rk_pcie, hot_rst_work);
+ u32 val, status;
+ int ret;
+
+ /* Setup command register */
+ val = dw_pcie_readl_dbi(rk_pcie->pci, PCI_COMMAND);
+ val &= 0xffff0000;
+ val |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
+ PCI_COMMAND_MASTER | PCI_COMMAND_SERR;
+ dw_pcie_writel_dbi(rk_pcie->pci, PCI_COMMAND, val);
+
+ if (rk_pcie_readl_apb(rk_pcie, PCIE_CLIENT_HOT_RESET_CTRL) & PCIE_LTSSM_APP_DLY2_EN) {
+ ret = readl_poll_timeout(rk_pcie->apb_base + PCIE_CLIENT_LTSSM_STATUS,
+ status, ((status & 0x3F) == 0), 100, RK_PCIE_HOTRESET_TMOUT_US);
+ if (ret)
+ dev_err(rk_pcie->pci->dev, "wait for detect quiet failed!\n");
+
+ rk_pcie_writel_apb(rk_pcie, PCIE_CLIENT_HOT_RESET_CTRL,
+ (PCIE_LTSSM_APP_DLY2_DONE) | ((PCIE_LTSSM_APP_DLY2_DONE) << 16));
+ }
+}
+
static irqreturn_t rk_pcie_sys_irq_handler(int irq, void *arg)
{
struct rk_pcie *rk_pcie = arg;
u32 chn;
union int_status status;
union int_clear clears;
- u32 reg, val;
+ u32 reg;
status.asdword = dw_pcie_readl_dbi(rk_pcie->pci, PCIE_DMA_OFFSET +
PCIE_DMA_WR_INT_STATUS);
@@ -1152,14 +1521,8 @@
}
reg = rk_pcie_readl_apb(rk_pcie, PCIE_CLIENT_INTR_STATUS_MISC);
- if (reg & BIT(2)) {
- /* Setup command register */
- val = dw_pcie_readl_dbi(rk_pcie->pci, PCI_COMMAND);
- val &= 0xffff0000;
- val |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
- PCI_COMMAND_MASTER | PCI_COMMAND_SERR;
- dw_pcie_writel_dbi(rk_pcie->pci, PCI_COMMAND, val);
- }
+ if (reg & BIT(2))
+ queue_work(rk_pcie->hot_rst_wq, &rk_pcie->hot_rst_work);
rk_pcie_writel_apb(rk_pcie, PCIE_CLIENT_INTR_STATUS_MISC, reg);
@@ -1215,11 +1578,23 @@
.data = &rk3528_pcie_rc_of_data,
},
{
+ .compatible = "rockchip,rk3562-pcie",
+ .data = &rk3528_pcie_rc_of_data,
+ },
+ {
.compatible = "rockchip,rk3568-pcie",
.data = &rk_pcie_rc_of_data,
},
{
.compatible = "rockchip,rk3568-pcie-ep",
+ .data = &rk_pcie_ep_of_data,
+ },
+ {
+ .compatible = "rockchip,rk3588-pcie",
+ .data = &rk_pcie_rc_of_data,
+ },
+ {
+ .compatible = "rockchip,rk3588-pcie-ep",
.data = &rk_pcie_ep_of_data,
},
{},
@@ -1229,7 +1604,6 @@
static const struct dw_pcie_ops dw_pcie_ops = {
.start_link = rk_pcie_establish_link,
- .link_up = rk_pcie_link_up,
};
static int rk1808_pcie_fixup(struct rk_pcie *rk_pcie, struct device_node *np)
@@ -1271,7 +1645,8 @@
/* LTSSM EN ctrl mode */
val = rk_pcie_readl_apb(rk_pcie, PCIE_CLIENT_HOT_RESET_CTRL);
- val |= PCIE_LTSSM_ENABLE_ENHANCE | (PCIE_LTSSM_ENABLE_ENHANCE << 16);
+ val |= (PCIE_LTSSM_ENABLE_ENHANCE | PCIE_LTSSM_APP_DLY2_EN)
+ | ((PCIE_LTSSM_APP_DLY2_EN | PCIE_LTSSM_ENABLE_ENHANCE) << 16);
rk_pcie_writel_apb(rk_pcie, PCIE_CLIENT_HOT_RESET_CTRL, val);
}
@@ -1309,7 +1684,7 @@
static int rk_pcie_intx_map(struct irq_domain *domain, unsigned int irq,
irq_hw_number_t hwirq)
{
- irq_set_chip_and_handler(irq, &rk_pcie_legacy_irq_chip, handle_simple_irq);
+ irq_set_chip_and_handler(irq, &rk_pcie_legacy_irq_chip, handle_level_irq);
irq_set_chip_data(irq, domain->host_data);
return 0;
@@ -1398,41 +1773,6 @@
return ret;
}
-static int rk_pci_find_capability(struct rk_pcie *rk_pcie, int cap)
-{
- u32 header;
- int ttl;
- int start = 0;
- int pos = PCI_CFG_SPACE_SIZE;
-
- /* minimum 8 bytes per capability */
- ttl = (PCI_CFG_SPACE_EXP_SIZE - PCI_CFG_SPACE_SIZE) / 8;
-
- header = dw_pcie_readl_dbi(rk_pcie->pci, pos);
-
- /*
- * If we have no capabilities, this is indicated by cap ID,
- * cap version and next pointer all being 0.
- */
- if (header == 0)
- return 0;
-
- while (ttl-- > 0) {
- if (PCI_EXT_CAP_ID(header) == cap && pos != start)
- return pos;
-
- pos = PCI_EXT_CAP_NEXT(header);
- if (pos < PCI_CFG_SPACE_SIZE)
- break;
-
- header = dw_pcie_readl_dbi(rk_pcie->pci, pos);
- if (!header)
- break;
- }
-
- return 0;
-}
-
#define RAS_DES_EVENT(ss, v) \
do { \
dw_pcie_writel_dbi(pcie->pci, cap_base + 8, v); \
@@ -1443,8 +1783,27 @@
{
struct rk_pcie *pcie = s->private;
int cap_base;
+ u32 val = rk_pcie_readl_apb(pcie, PCIE_CLIENT_CDM_RASDES_TBA_INFO_CMN);
+ char *pm;
- cap_base = rk_pci_find_capability(pcie, PCI_EXT_CAP_ID_VNDR);
+ if (val & BIT(6))
+ pm = "In training";
+ else if (val & BIT(5))
+ pm = "L1.2";
+ else if (val & BIT(4))
+ pm = "L1.1";
+ else if (val & BIT(3))
+ pm = "L1";
+ else if (val & BIT(2))
+ pm = "L0";
+ else if (val & 0x3)
+ pm = (val == 0x3) ? "L0s" : (val & BIT(1) ? "RX L0s" : "TX L0s");
+ else
+ pm = "Invalid";
+
+ seq_printf(s, "Common event signal status: 0x%s\n", pm);
+
+ cap_base = dw_pcie_find_ext_capability(pcie->pci, PCI_EXT_CAP_ID_VNDR);
if (!cap_base) {
dev_err(pcie->pci->dev, "Not able to find RASDES CAP!\n");
return 0;
@@ -1480,7 +1839,6 @@
return 0;
}
-
static int rockchip_pcie_rasdes_open(struct inode *inode, struct file *file)
{
return single_open(file, rockchip_pcie_rasdes_show,
@@ -1499,7 +1857,7 @@
if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
return -EFAULT;
- cap_base = rk_pci_find_capability(pcie, PCI_EXT_CAP_ID_VNDR);
+ cap_base = dw_pcie_find_ext_capability(pcie->pci, PCI_EXT_CAP_ID_VNDR);
if (!cap_base) {
dev_err(pcie->pci->dev, "Not able to find RASDES CAP!\n");
return 0;
@@ -1584,7 +1942,6 @@
const struct rk_pcie_of_data *data;
enum rk_pcie_device_mode mode;
struct device_node *np = pdev->dev.of_node;
- struct platform_driver *drv = to_platform_driver(dev->driver);
u32 val = 0;
int irq;
@@ -1633,10 +1990,13 @@
if (!IS_ERR_OR_NULL(rk_pcie->prsnt_gpio)) {
if (!gpiod_get_value(rk_pcie->prsnt_gpio)) {
+ dev_info(dev, "device isn't present\n");
ret = -ENODEV;
goto release_driver;
}
}
+
+ rk_pcie->supports_clkreq = device_property_read_bool(dev, "supports-clkreq");
retry_regulator:
/* DON'T MOVE ME: must be enable before phy init */
@@ -1667,11 +2027,14 @@
goto disable_vpcie3v3;
}
- ret = rk_pcie_reset_control_release(rk_pcie);
- if (ret) {
- dev_err(dev, "reset control init failed\n");
+ rk_pcie->rsts = devm_reset_control_array_get_exclusive(dev);
+ if (IS_ERR(rk_pcie->rsts)) {
+ ret = PTR_ERR(rk_pcie->rsts);
+ dev_err(dev, "failed to get reset lines\n");
goto disable_phy;
}
+
+ reset_control_deassert(rk_pcie->rsts);
ret = rk_pcie_request_sys_irq(rk_pcie, pdev);
if (ret) {
@@ -1723,17 +2086,39 @@
rk_pcie->is_signal_test = true;
}
- /* Force into compliance mode */
- if (device_property_read_bool(dev, "rockchip,compliance-mode")) {
- val = dw_pcie_readl_dbi(pci, PCIE_CAP_LINK_CONTROL2_LINK_STATUS);
- val |= BIT(4);
- dw_pcie_writel_dbi(pci, PCIE_CAP_LINK_CONTROL2_LINK_STATUS, val);
+ /*
+ * Force into compliance mode
+ * comp_prst is a two dimensional array of which the first element
+ * stands for speed mode, and the second one is preset value encoding:
+ * [0] 0->SMA tool control the signal switch, 1/2/3 is for manual Gen setting
+ * [1] transmitter setting for manual Gen setting, valid only if [0] isn't zero.
+ */
+ if (!device_property_read_u32_array(dev, "rockchip,compliance-mode",
+ rk_pcie->comp_prst, 2)) {
+ BUG_ON(rk_pcie->comp_prst[0] > 3 || rk_pcie->comp_prst[1] > 10);
+ if (!rk_pcie->comp_prst[0]) {
+ dev_info(dev, "Auto compliance mode for SMA tool.\n");
+ } else {
+ dev_info(dev, "compliance mode for soldered board Gen%d, P%d.\n",
+ rk_pcie->comp_prst[0], rk_pcie->comp_prst[1]);
+ val = dw_pcie_readl_dbi(pci, PCIE_CAP_LINK_CONTROL2_LINK_STATUS);
+ val |= BIT(4) | rk_pcie->comp_prst[0] | (rk_pcie->comp_prst[1] << 12);
+ dw_pcie_writel_dbi(pci, PCIE_CAP_LINK_CONTROL2_LINK_STATUS, val);
+ }
rk_pcie->is_signal_test = true;
}
/* Skip waiting for training to pass in system PM routine */
if (device_property_read_bool(dev, "rockchip,skip-scan-in-resume"))
rk_pcie->skip_scan_in_resume = true;
+
+ rk_pcie->hot_rst_wq = create_singlethread_workqueue("rk_pcie_hot_rst_wq");
+ if (!rk_pcie->hot_rst_wq) {
+ dev_err(dev, "failed to create hot_rst workqueue\n");
+ ret = -ENOMEM;
+ goto remove_irq_domain;
+ }
+ INIT_WORK(&rk_pcie->hot_rst_work, rk_pcie_hot_rst_work);
switch (rk_pcie->mode) {
case RK_PCIE_RC_TYPE:
@@ -1748,12 +2133,12 @@
return 0;
if (ret)
- goto remove_irq_domain;
+ goto remove_rst_wq;
ret = rk_pcie_init_dma_trx(rk_pcie);
if (ret) {
dev_err(dev, "failed to add dma extension\n");
- return ret;
+ goto remove_rst_wq;
}
if (rk_pcie->dma_obj) {
@@ -1765,13 +2150,15 @@
/* hold link reset grant after link-up */
ret = rk_pcie_reset_grant_ctrl(rk_pcie, false);
if (ret)
- goto remove_irq_domain;
+ goto remove_rst_wq;
}
dw_pcie_dbi_ro_wr_dis(pci);
device_init_wakeup(dev, true);
- drv->driver.pm = &rockchip_dw_pcie_pm_ops;
+
+ /* Enable async system PM for multiports SoC */
+ device_enable_async_suspend(dev);
if (IS_ENABLED(CONFIG_DEBUG_FS)) {
ret = rockchip_pcie_debugfs_init(rk_pcie);
@@ -1779,7 +2166,7 @@
dev_err(dev, "failed to setup debugfs: %d\n", ret);
/* Enable RASDES Error event by default */
- val = rk_pci_find_capability(rk_pcie, PCI_EXT_CAP_ID_VNDR);
+ val = dw_pcie_find_ext_capability(rk_pcie->pci, PCI_EXT_CAP_ID_VNDR);
if (!val) {
dev_err(dev, "Not able to find RASDES CAP!\n");
return 0;
@@ -1791,6 +2178,8 @@
return 0;
+remove_rst_wq:
+ destroy_workqueue(rk_pcie->hot_rst_wq);
remove_irq_domain:
if (rk_pcie->irq_domain)
irq_domain_remove(rk_pcie->irq_domain);
@@ -1798,10 +2187,9 @@
phy_power_off(rk_pcie->phy);
phy_exit(rk_pcie->phy);
deinit_clk:
- rk_pcie_clk_deinit(rk_pcie);
+ clk_bulk_disable_unprepare(rk_pcie->clk_cnt, rk_pcie->clks);
disable_vpcie3v3:
rk_pcie_disable_power(rk_pcie);
-
release_driver:
if (IS_ENABLED(CONFIG_PCIE_RK_THREADED_INIT))
device_release_driver(dev);
@@ -1826,13 +2214,154 @@
return rk_pcie_really_probe(pdev);
}
+#ifdef CONFIG_PCIEASPM
+static void rk_pcie_downstream_dev_to_d0(struct rk_pcie *rk_pcie, bool enable)
+{
+ struct pcie_port *pp = &rk_pcie->pci->pp;
+ struct pci_bus *child, *root_bus = NULL;
+ struct pci_dev *pdev, *bridge;
+ u32 val;
+
+ list_for_each_entry(child, &pp->bridge->bus->children, node) {
+ /* Bring downstream devices to D3 if they are not already in */
+ if (child->parent == pp->bridge->bus) {
+ root_bus = child;
+ bridge = root_bus->self;
+ break;
+ }
+ }
+
+ if (!root_bus) {
+ dev_err(rk_pcie->pci->dev, "Failed to find downstream devices\n");
+ return;
+ }
+
+ /* Save and restore root bus ASPM */
+ if (enable) {
+ if (rk_pcie->l1ss_ctl1)
+ dw_pcie_writel_dbi(rk_pcie->pci, bridge->l1ss + PCI_L1SS_CTL1, rk_pcie->l1ss_ctl1);
+
+ /* rk_pcie->aspm woule be saved in advance when enable is false */
+ dw_pcie_writel_dbi(rk_pcie->pci, bridge->pcie_cap + PCI_EXP_LNKCTL, rk_pcie->aspm);
+ } else {
+ val = dw_pcie_readl_dbi(rk_pcie->pci, bridge->l1ss + PCI_L1SS_CTL1);
+ if (val & PCI_L1SS_CTL1_L1SS_MASK)
+ rk_pcie->l1ss_ctl1 = val;
+ else
+ rk_pcie->l1ss_ctl1 = 0;
+
+ val = dw_pcie_readl_dbi(rk_pcie->pci, bridge->pcie_cap + PCI_EXP_LNKCTL);
+ rk_pcie->aspm = val & PCI_EXP_LNKCTL_ASPMC;
+ val &= ~(PCI_EXP_LNKCAP_ASPM_L1 | PCI_EXP_LNKCAP_ASPM_L0S);
+ dw_pcie_writel_dbi(rk_pcie->pci, bridge->pcie_cap + PCI_EXP_LNKCTL, val);
+ }
+
+ list_for_each_entry(pdev, &root_bus->devices, bus_list) {
+ if (PCI_SLOT(pdev->devfn) == 0) {
+ if (pci_set_power_state(pdev, PCI_D0))
+ dev_err(rk_pcie->pci->dev,
+ "Failed to transition %s to D3hot state\n",
+ dev_name(&pdev->dev));
+ if (enable) {
+ if (rk_pcie->l1ss_ctl1) {
+ pci_read_config_dword(pdev, pdev->l1ss + PCI_L1SS_CTL1, &val);
+ val &= ~PCI_L1SS_CTL1_L1SS_MASK;
+ val |= (rk_pcie->l1ss_ctl1 & PCI_L1SS_CTL1_L1SS_MASK);
+ pci_write_config_dword(pdev, pdev->l1ss + PCI_L1SS_CTL1, val);
+ }
+
+ pcie_capability_clear_and_set_word(pdev, PCI_EXP_LNKCTL,
+ PCI_EXP_LNKCTL_ASPMC, rk_pcie->aspm);
+ } else {
+ pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1);
+ }
+ }
+ }
+}
+#endif
+
static int __maybe_unused rockchip_dw_pcie_suspend(struct device *dev)
{
struct rk_pcie *rk_pcie = dev_get_drvdata(dev);
- int ret;
+ int ret = 0, power;
+ struct dw_pcie *pci = rk_pcie->pci;
+ u32 status;
+
+ /*
+ * This is as per PCI Express Base r5.0 r1.0 May 22-2019,
+ * 5.2 Link State Power Management (Page #440).
+ *
+ * L2/L3 Ready entry negotiations happen while in the L0 state.
+ * L2/L3 Ready are entered only after the negotiation completes.
+ *
+ * The following example sequence illustrates the multi-step Link state
+ * transition process leading up to entering a system sleep state:
+ * 1. System software directs all Functions of a Downstream component to D3Hot.
+ * 2. The Downstream component then initiates the transition of the Link to L1
+ * as required.
+ * 3. System software then causes the Root Complex to broadcast the PME_Turn_Off
+ * Message in preparation for removing the main power source.
+ * 4. This Message causes the subject Link to transition back to L0 in order to
+ * send it and to enable the Downstream component to respond with PME_TO_Ack.
+ * 5. After sending the PME_TO_Ack, the Downstream component initiates the L2/L3
+ * Ready transition protocol.
+ */
+
+ /* 1. All sub-devices are in D3hot by PCIe stack */
+ dw_pcie_dbi_ro_wr_dis(rk_pcie->pci);
rk_pcie_link_status_clear(rk_pcie);
+
+ /*
+ * Wlan devices will be shutdown from function driver now, so doing L2 here
+ * must fail. Skip L2 routine.
+ */
+ if (rk_pcie->skip_scan_in_resume) {
+ rfkill_get_wifi_power_state(&power);
+ if (!power)
+ goto no_l2;
+ }
+
+ /* 2. Broadcast PME_Turn_Off Message */
+ rk_pcie_writel_apb(rk_pcie, PCIE_CLIENT_MSG_GEN, PME_TURN_OFF);
+ ret = readl_poll_timeout(rk_pcie->apb_base + PCIE_CLIENT_MSG_GEN,
+ status, !(status & BIT(4)), 20, RK_PCIE_L2_TMOUT_US);
+ if (ret) {
+ dev_err(dev, "Failed to send PME_Turn_Off\n");
+ goto no_l2;
+ }
+
+ /* 3. Wait for PME_TO_Ack */
+ ret = readl_poll_timeout(rk_pcie->apb_base + PCIE_CLIENT_INTR_STATUS_MSG_RX,
+ status, status & BIT(9), 20, RK_PCIE_L2_TMOUT_US);
+ if (ret) {
+ dev_err(dev, "Failed to receive PME_TO_Ack\n");
+ goto no_l2;
+ }
+
+ /* 4. Clear PME_TO_Ack and Wait for ready to enter L23 message */
+ rk_pcie_writel_apb(rk_pcie, PCIE_CLIENT_INTR_STATUS_MSG_RX, PME_TO_ACK);
+ ret = readl_poll_timeout(rk_pcie->apb_base + PCIE_CLIENT_POWER,
+ status, status & READY_ENTER_L23, 20, RK_PCIE_L2_TMOUT_US);
+ if (ret) {
+ dev_err(dev, "Failed to ready to enter L23\n");
+ goto no_l2;
+ }
+
+ /* 5. Check we are in L2 */
+ ret = readl_poll_timeout(rk_pcie->apb_base + PCIE_CLIENT_LTSSM_STATUS,
+ status, ((status & S_MAX) == S_L2_IDLE), 20, RK_PCIE_L2_TMOUT_US);
+ if (ret)
+ dev_err(pci->dev, "Link isn't in L2 idle!\n");
+
+no_l2:
rk_pcie_disable_ltssm(rk_pcie);
+
+ ret = phy_validate(rk_pcie->phy, PHY_TYPE_PCIE, 0, NULL);
+ if (ret && ret != -EOPNOTSUPP) {
+ dev_err(dev, "PHY is reused by other controller, check the dts!\n");
+ return ret;
+ }
/* make sure assert phy success */
usleep_range(200, 300);
@@ -1840,7 +2369,9 @@
phy_power_off(rk_pcie->phy);
phy_exit(rk_pcie->phy);
- clk_bulk_disable(rk_pcie->clk_cnt, rk_pcie->clks);
+ rk_pcie->intx = rk_pcie_readl_apb(rk_pcie, PCIE_CLIENT_INTR_MASK_LEGACY);
+
+ clk_bulk_disable_unprepare(rk_pcie->clk_cnt, rk_pcie->clks);
rk_pcie->in_suspend = true;
@@ -1856,20 +2387,25 @@
bool std_rc = rk_pcie->mode == RK_PCIE_RC_TYPE && !rk_pcie->dma_obj;
int ret;
+ reset_control_assert(rk_pcie->rsts);
+ udelay(10);
+ reset_control_deassert(rk_pcie->rsts);
+
ret = rk_pcie_enable_power(rk_pcie);
if (ret)
return ret;
- ret = clk_bulk_enable(rk_pcie->clk_cnt, rk_pcie->clks);
+ ret = clk_bulk_prepare_enable(rk_pcie->clk_cnt, rk_pcie->clks);
if (ret) {
- clk_bulk_unprepare(rk_pcie->clk_cnt, rk_pcie->clks);
+ dev_err(dev, "failed to prepare enable pcie bulk clks: %d\n", ret);
return ret;
}
- ret = phy_set_mode(rk_pcie->phy, rk_pcie->phy_mode);
+ ret = phy_set_mode_ext(rk_pcie->phy, rk_pcie->phy_mode,
+ rk_pcie->phy_sub_mode);
if (ret) {
dev_err(dev, "fail to set phy to mode %s, err %d\n",
- (rk_pcie->phy_mode == PHY_MODE_PCIE_RC) ? "RC" : "EP",
+ (rk_pcie->phy_sub_mode == PHY_MODE_PCIE_RC) ? "RC" : "EP",
ret);
return ret;
}
@@ -1898,6 +2434,9 @@
if (std_rc)
dw_pcie_setup_rc(&rk_pcie->pci->pp);
+
+ rk_pcie_writel_apb(rk_pcie, PCIE_CLIENT_INTR_MASK_LEGACY,
+ rk_pcie->intx | 0xffff0000);
ret = rk_pcie_establish_link(rk_pcie->pci);
if (ret) {
@@ -1937,7 +2476,33 @@
return ret;
}
+#ifdef CONFIG_PCIEASPM
+static int rockchip_dw_pcie_prepare(struct device *dev)
+{
+ struct rk_pcie *rk_pcie = dev_get_drvdata(dev);
+
+ dw_pcie_dbi_ro_wr_en(rk_pcie->pci);
+ rk_pcie_downstream_dev_to_d0(rk_pcie, false);
+ dw_pcie_dbi_ro_wr_dis(rk_pcie->pci);
+
+ return 0;
+}
+
+static void rockchip_dw_pcie_complete(struct device *dev)
+{
+ struct rk_pcie *rk_pcie = dev_get_drvdata(dev);
+
+ dw_pcie_dbi_ro_wr_en(rk_pcie->pci);
+ rk_pcie_downstream_dev_to_d0(rk_pcie, true);
+ dw_pcie_dbi_ro_wr_dis(rk_pcie->pci);
+}
+#endif
+
static const struct dev_pm_ops rockchip_dw_pcie_pm_ops = {
+#ifdef CONFIG_PCIEASPM
+ .prepare = rockchip_dw_pcie_prepare,
+ .complete = rockchip_dw_pcie_complete,
+#endif
SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(rockchip_dw_pcie_suspend,
rockchip_dw_pcie_resume)
};
@@ -1947,10 +2512,12 @@
.name = "rk-pcie",
.of_match_table = rk_pcie_of_match,
.suppress_bind_attrs = true,
+ .pm = &rockchip_dw_pcie_pm_ops,
},
+ .probe = rk_pcie_probe,
};
-module_platform_driver_probe(rk_plat_pcie_driver, rk_pcie_probe);
+module_platform_driver(rk_plat_pcie_driver);
MODULE_AUTHOR("Simon Xue <xxm@rock-chips.com>");
MODULE_DESCRIPTION("RockChip PCIe Controller driver");
--
Gitblit v1.6.2