rockchip: Add ROCKCHIP PCIe ASPM interface
This commit is contained in:
parent
7901702c49
commit
f0e7802be6
@ -513,7 +513,8 @@ CONFIG_PCI=y
|
|||||||
CONFIG_PCIEAER=y
|
CONFIG_PCIEAER=y
|
||||||
CONFIG_PCIEASPM=y
|
CONFIG_PCIEASPM=y
|
||||||
CONFIG_PCIEASPM_DEFAULT=y
|
CONFIG_PCIEASPM_DEFAULT=y
|
||||||
# CONFIG_PCIEASPM_PERFORMANCE is not set
|
CONFIG_PCIEASPM_EXT=y
|
||||||
|
CONFIG_PCIEASPM_PERFORMANCE=y
|
||||||
# CONFIG_PCIEASPM_POWERSAVE is not set
|
# CONFIG_PCIEASPM_POWERSAVE is not set
|
||||||
# CONFIG_PCIEASPM_POWER_SUPERSAVE is not set
|
# CONFIG_PCIEASPM_POWER_SUPERSAVE is not set
|
||||||
CONFIG_PCIEPORTBUS=y
|
CONFIG_PCIEPORTBUS=y
|
||||||
|
@ -529,8 +529,9 @@ CONFIG_PARTITION_PERCPU=y
|
|||||||
CONFIG_PCI=y
|
CONFIG_PCI=y
|
||||||
CONFIG_PCIEAER=y
|
CONFIG_PCIEAER=y
|
||||||
CONFIG_PCIEASPM=y
|
CONFIG_PCIEASPM=y
|
||||||
CONFIG_PCIEASPM_DEFAULT=y
|
# CONFIG_PCIEASPM_DEFAULT is not set
|
||||||
# CONFIG_PCIEASPM_PERFORMANCE is not set
|
CONFIG_PCIEASPM_EXT=y
|
||||||
|
CONFIG_PCIEASPM_PERFORMANCE=y
|
||||||
# CONFIG_PCIEASPM_POWERSAVE is not set
|
# CONFIG_PCIEASPM_POWERSAVE is not set
|
||||||
# CONFIG_PCIEASPM_POWER_SUPERSAVE is not set
|
# CONFIG_PCIEASPM_POWER_SUPERSAVE is not set
|
||||||
CONFIG_PCIEPORTBUS=y
|
CONFIG_PCIEPORTBUS=y
|
||||||
|
@ -0,0 +1,59 @@
|
|||||||
|
From 59e0ec5e5916ed4fac238a3da39aa0659831c41c Mon Sep 17 00:00:00 2001
|
||||||
|
From: Heiko Stuebner <heiko@sntech.de>
|
||||||
|
Date: Sun, 30 Oct 2022 20:34:42 +0100
|
||||||
|
Subject: [PATCH 6/7] arm64: dts: rockchip: fix spdif@fe460000 ordering on
|
||||||
|
rk356x
|
||||||
|
|
||||||
|
Move the node to its correct position, based on its
|
||||||
|
mmio-address.
|
||||||
|
|
||||||
|
Link: https://lore.kernel.org/all/20221030193708.1671069-1-heiko@sntech.de
|
||||||
|
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
|
||||||
|
---
|
||||||
|
arch/arm64/boot/dts/rockchip/rk356x.dtsi | 28 ++++++++++++------------
|
||||||
|
1 file changed, 14 insertions(+), 14 deletions(-)
|
||||||
|
|
||||||
|
--- a/arch/arm64/boot/dts/rockchip/rk356x.dtsi
|
||||||
|
+++ b/arch/arm64/boot/dts/rockchip/rk356x.dtsi
|
||||||
|
@@ -1049,20 +1049,6 @@
|
||||||
|
status = "disabled";
|
||||||
|
};
|
||||||
|
|
||||||
|
- spdif: spdif@fe460000 {
|
||||||
|
- compatible = "rockchip,rk3568-spdif";
|
||||||
|
- reg = <0x0 0xfe460000 0x0 0x1000>;
|
||||||
|
- interrupts = <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>;
|
||||||
|
- clock-names = "mclk", "hclk";
|
||||||
|
- clocks = <&cru MCLK_SPDIF_8CH>, <&cru HCLK_SPDIF_8CH>;
|
||||||
|
- dmas = <&dmac1 1>;
|
||||||
|
- dma-names = "tx";
|
||||||
|
- pinctrl-names = "default";
|
||||||
|
- pinctrl-0 = <&spdifm0_tx>;
|
||||||
|
- #sound-dai-cells = <0>;
|
||||||
|
- status = "disabled";
|
||||||
|
- };
|
||||||
|
-
|
||||||
|
i2s0_8ch: i2s@fe400000 {
|
||||||
|
compatible = "rockchip,rk3568-i2s-tdm";
|
||||||
|
reg = <0x0 0xfe400000 0x0 0x1000>;
|
||||||
|
@@ -1141,6 +1127,20 @@
|
||||||
|
#sound-dai-cells = <0>;
|
||||||
|
status = "disabled";
|
||||||
|
};
|
||||||
|
+
|
||||||
|
+ spdif: spdif@fe460000 {
|
||||||
|
+ compatible = "rockchip,rk3568-spdif";
|
||||||
|
+ reg = <0x0 0xfe460000 0x0 0x1000>;
|
||||||
|
+ interrupts = <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>;
|
||||||
|
+ clock-names = "mclk", "hclk";
|
||||||
|
+ clocks = <&cru MCLK_SPDIF_8CH>, <&cru HCLK_SPDIF_8CH>;
|
||||||
|
+ dmas = <&dmac1 1>;
|
||||||
|
+ dma-names = "tx";
|
||||||
|
+ pinctrl-names = "default";
|
||||||
|
+ pinctrl-0 = <&spdifm0_tx>;
|
||||||
|
+ #sound-dai-cells = <0>;
|
||||||
|
+ status = "disabled";
|
||||||
|
+ };
|
||||||
|
|
||||||
|
dmac0: dma-controller@fe530000 {
|
||||||
|
compatible = "arm,pl330", "arm,primecell";
|
@ -0,0 +1,45 @@
|
|||||||
|
From 6c51234cd4e1bfd637c3aab0a94893e832670fe5 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Shengyu Qu <wiagn233@outlook.com>
|
||||||
|
Date: Sun, 30 Oct 2022 01:09:04 +0800
|
||||||
|
Subject: [PATCH 7/7] arm64: dts: rockchip: RK356x: Add I2S2 device node
|
||||||
|
|
||||||
|
This patch adds I2S2 device tree node for RK3566/RK3568.
|
||||||
|
|
||||||
|
Signed-off-by: Shengyu Qu <wiagn233@outlook.com>
|
||||||
|
Link: https://lore.kernel.org/r/OS3P286MB259771C12F2B15A4DDF435FE98359@OS3P286MB2597.JPNP286.PROD.OUTLOOK.COM
|
||||||
|
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
|
||||||
|
---
|
||||||
|
arch/arm64/boot/dts/rockchip/rk356x.dtsi | 22 ++++++++++++++++++++++
|
||||||
|
1 file changed, 22 insertions(+)
|
||||||
|
|
||||||
|
--- a/arch/arm64/boot/dts/rockchip/rk356x.dtsi
|
||||||
|
+++ b/arch/arm64/boot/dts/rockchip/rk356x.dtsi
|
||||||
|
@@ -1091,6 +1091,28 @@
|
||||||
|
status = "disabled";
|
||||||
|
};
|
||||||
|
|
||||||
|
+ i2s2_2ch: i2s@fe420000 {
|
||||||
|
+ compatible = "rockchip,rk3568-i2s-tdm";
|
||||||
|
+ reg = <0x0 0xfe420000 0x0 0x1000>;
|
||||||
|
+ interrupts = <GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>;
|
||||||
|
+ assigned-clocks = <&cru CLK_I2S2_2CH_SRC>;
|
||||||
|
+ assigned-clock-rates = <1188000000>;
|
||||||
|
+ clocks = <&cru MCLK_I2S2_2CH>, <&cru MCLK_I2S2_2CH>, <&cru HCLK_I2S2_2CH>;
|
||||||
|
+ clock-names = "mclk_tx", "mclk_rx", "hclk";
|
||||||
|
+ dmas = <&dmac1 4>, <&dmac1 5>;
|
||||||
|
+ dma-names = "tx", "rx";
|
||||||
|
+ resets = <&cru SRST_M_I2S2_2CH>;
|
||||||
|
+ reset-names = "m";
|
||||||
|
+ rockchip,grf = <&grf>;
|
||||||
|
+ pinctrl-names = "default";
|
||||||
|
+ pinctrl-0 = <&i2s2m0_sclktx
|
||||||
|
+ &i2s2m0_lrcktx
|
||||||
|
+ &i2s2m0_sdi
|
||||||
|
+ &i2s2m0_sdo>;
|
||||||
|
+ #sound-dai-cells = <0>;
|
||||||
|
+ status = "disabled";
|
||||||
|
+ };
|
||||||
|
+
|
||||||
|
i2s3_2ch: i2s@fe430000 {
|
||||||
|
compatible = "rockchip,rk3568-i2s-tdm";
|
||||||
|
reg = <0x0 0xfe430000 0x0 0x1000>;
|
402
patches-6.1/220-PCI-Add-ROCKCHIP-PCIe-ASPM-interface.patch
Normal file
402
patches-6.1/220-PCI-Add-ROCKCHIP-PCIe-ASPM-interface.patch
Normal file
@ -0,0 +1,402 @@
|
|||||||
|
From d591c3f6efef5f50fc970aeeedbf9e03b7bd5d21 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Jon Lin <jon.lin@rock-chips.com>
|
||||||
|
Date: Fri, 17 Jun 2022 10:38:30 +0800
|
||||||
|
Subject: [PATCH] PCI: Add ROCKCHIP PCIe ASPM interface
|
||||||
|
|
||||||
|
Change-Id: I1156bd10e352145d745899067bf43afda92d5a30
|
||||||
|
Signed-off-by: Jon Lin <jon.lin@rock-chips.com>
|
||||||
|
---
|
||||||
|
drivers/pci/pcie/Kconfig | 6 +
|
||||||
|
drivers/pci/pcie/Makefile | 1 +
|
||||||
|
drivers/pci/pcie/aspm_ext.c | 339 ++++++++++++++++++++++++++++++++++++
|
||||||
|
include/linux/aspm_ext.h | 16 ++
|
||||||
|
4 files changed, 362 insertions(+)
|
||||||
|
create mode 100644 drivers/pci/pcie/aspm_ext.c
|
||||||
|
create mode 100644 include/linux/aspm_ext.h
|
||||||
|
|
||||||
|
--- a/drivers/pci/pcie/Kconfig
|
||||||
|
+++ b/drivers/pci/pcie/Kconfig
|
||||||
|
@@ -110,6 +110,12 @@ config PCIEASPM_PERFORMANCE
|
||||||
|
Disable PCI Express ASPM L0s and L1, even if the BIOS enabled them.
|
||||||
|
endchoice
|
||||||
|
|
||||||
|
+config PCIEASPM_EXT
|
||||||
|
+ tristate "Extend ASPM function"
|
||||||
|
+ depends on PCIEASPM
|
||||||
|
+ help
|
||||||
|
+ This enables the extensions APIs for ASPM control.
|
||||||
|
+
|
||||||
|
config PCIE_PME
|
||||||
|
def_bool y
|
||||||
|
depends on PCIEPORTBUS && PM
|
||||||
|
--- a/drivers/pci/pcie/Makefile
|
||||||
|
+++ b/drivers/pci/pcie/Makefile
|
||||||
|
@@ -7,6 +7,7 @@ pcieportdrv-y := portdrv_core.o portdr
|
||||||
|
obj-$(CONFIG_PCIEPORTBUS) += pcieportdrv.o
|
||||||
|
|
||||||
|
obj-$(CONFIG_PCIEASPM) += aspm.o
|
||||||
|
+obj-$(CONFIG_PCIEASPM_EXT) += aspm_ext.o
|
||||||
|
obj-$(CONFIG_PCIEAER) += aer.o err.o
|
||||||
|
obj-$(CONFIG_PCIEAER_INJECT) += aer_inject.o
|
||||||
|
obj-$(CONFIG_PCIE_PME) += pme.o
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/drivers/pci/pcie/aspm_ext.c
|
||||||
|
@@ -0,0 +1,339 @@
|
||||||
|
+// SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
+/*
|
||||||
|
+ * Rockchip PCIe Apis For WIFI
|
||||||
|
+ *
|
||||||
|
+ * Copyright (c) 2022 Rockchip Electronics Co., Ltd.
|
||||||
|
+ */
|
||||||
|
+
|
||||||
|
+#include <linux/kernel.h>
|
||||||
|
+#include <linux/pci.h>
|
||||||
|
+#include <linux/aspm_ext.h>
|
||||||
|
+#include <linux/errno.h>
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+static u32 rockchip_pcie_pcie_access_cap(struct pci_dev *pdev, int cap, uint offset,
|
||||||
|
+ bool is_ext, bool is_write, u32 writeval)
|
||||||
|
+{
|
||||||
|
+ int cap_ptr = 0;
|
||||||
|
+ u32 ret = -1;
|
||||||
|
+ u32 readval;
|
||||||
|
+
|
||||||
|
+ if (!(pdev)) {
|
||||||
|
+ pci_err(pdev, "%s: pdev is NULL\n", __func__);
|
||||||
|
+ return ret;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /* Find Capability offset */
|
||||||
|
+ if (is_ext) {
|
||||||
|
+ /* removing max EXT_CAP_ID check as
|
||||||
|
+ * linux kernel definition's max value is not updated yet as per spec
|
||||||
|
+ */
|
||||||
|
+ cap_ptr = pci_find_ext_capability(pdev, cap);
|
||||||
|
+
|
||||||
|
+ } else {
|
||||||
|
+ /* removing max PCI_CAP_ID_MAX check as
|
||||||
|
+ * previous kernel versions dont have this definition
|
||||||
|
+ */
|
||||||
|
+ cap_ptr = pci_find_capability(pdev, cap);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /* Return if capability with given ID not found */
|
||||||
|
+ if (cap_ptr == 0) {
|
||||||
|
+ pci_err(pdev, "%s: PCI Cap(0x%02x) not supported.\n",
|
||||||
|
+ __func__, cap);
|
||||||
|
+ return -EINVAL;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (is_write) {
|
||||||
|
+ pci_write_config_dword(pdev, (cap_ptr + offset), writeval);
|
||||||
|
+ ret = 0;
|
||||||
|
+
|
||||||
|
+ } else {
|
||||||
|
+ pci_read_config_dword(pdev, (cap_ptr + offset), &readval);
|
||||||
|
+ ret = readval;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return ret;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static bool rockchip_pcie_bus_aspm_enable_dev(char *device, struct pci_dev *dev, bool enable)
|
||||||
|
+{
|
||||||
|
+ u32 linkctrl_before;
|
||||||
|
+ u32 linkctrl_after = 0;
|
||||||
|
+ u8 linkctrl_asm;
|
||||||
|
+
|
||||||
|
+ linkctrl_before = rockchip_pcie_pcie_access_cap(dev, PCI_CAP_ID_EXP, PCI_EXP_LNKCTL,
|
||||||
|
+ false, false, 0);
|
||||||
|
+ linkctrl_asm = (linkctrl_before & PCI_EXP_LNKCTL_ASPMC);
|
||||||
|
+
|
||||||
|
+ if (enable) {
|
||||||
|
+ if (linkctrl_asm == PCI_EXP_LNKCTL_ASPM_L1) {
|
||||||
|
+ pci_err(dev, "%s: %s already enabled linkctrl: 0x%x\n",
|
||||||
|
+ __func__, device, linkctrl_before);
|
||||||
|
+ return false;
|
||||||
|
+ }
|
||||||
|
+ /* Enable only L1 ASPM (bit 1) */
|
||||||
|
+ rockchip_pcie_pcie_access_cap(dev, PCI_CAP_ID_EXP, PCI_EXP_LNKCTL, false,
|
||||||
|
+ true, (linkctrl_before | PCI_EXP_LNKCTL_ASPM_L1));
|
||||||
|
+ } else {
|
||||||
|
+ if (linkctrl_asm == 0) {
|
||||||
|
+ pci_err(dev, "%s: %s already disabled linkctrl: 0x%x\n",
|
||||||
|
+ __func__, device, linkctrl_before);
|
||||||
|
+ return false;
|
||||||
|
+ }
|
||||||
|
+ /* Disable complete ASPM (bit 1 and bit 0) */
|
||||||
|
+ rockchip_pcie_pcie_access_cap(dev, PCI_CAP_ID_EXP, PCI_EXP_LNKCTL, false,
|
||||||
|
+ true, (linkctrl_before & (~PCI_EXP_LNKCTL_ASPMC)));
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ linkctrl_after = rockchip_pcie_pcie_access_cap(dev, PCI_CAP_ID_EXP, PCI_EXP_LNKCTL,
|
||||||
|
+ false, false, 0);
|
||||||
|
+ pci_err(dev, "%s: %s %s, linkctrl_before: 0x%x linkctrl_after: 0x%x\n",
|
||||||
|
+ __func__, device, (enable ? "ENABLE " : "DISABLE"),
|
||||||
|
+ linkctrl_before, linkctrl_after);
|
||||||
|
+
|
||||||
|
+ return true;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+bool rockchip_pcie_bus_aspm_enable_rc_ep(struct pci_dev *child, struct pci_dev *parent, bool enable)
|
||||||
|
+{
|
||||||
|
+ bool ret;
|
||||||
|
+
|
||||||
|
+ if (enable) {
|
||||||
|
+ /* Enable only L1 ASPM first RC then EP */
|
||||||
|
+ ret = rockchip_pcie_bus_aspm_enable_dev("RC", parent, enable);
|
||||||
|
+ ret = rockchip_pcie_bus_aspm_enable_dev("EP", child, enable);
|
||||||
|
+ } else {
|
||||||
|
+ /* Disable complete ASPM first EP then RC */
|
||||||
|
+ ret = rockchip_pcie_bus_aspm_enable_dev("EP", child, enable);
|
||||||
|
+ ret = rockchip_pcie_bus_aspm_enable_dev("RC", parent, enable);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return ret;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void pci_clear_and_set_dword(struct pci_dev *pdev, int pos,
|
||||||
|
+ u32 clear, u32 set)
|
||||||
|
+{
|
||||||
|
+ u32 val;
|
||||||
|
+
|
||||||
|
+ pci_read_config_dword(pdev, pos, &val);
|
||||||
|
+ val &= ~clear;
|
||||||
|
+ val |= set;
|
||||||
|
+ pci_write_config_dword(pdev, pos, val);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+/* Convert L1SS T_pwr encoding to usec */
|
||||||
|
+static u32 calc_l1ss_pwron(struct pci_dev *pdev, u32 scale, u32 val)
|
||||||
|
+{
|
||||||
|
+ switch (scale) {
|
||||||
|
+ case 0:
|
||||||
|
+ return val * 2;
|
||||||
|
+ case 1:
|
||||||
|
+ return val * 10;
|
||||||
|
+ case 2:
|
||||||
|
+ return val * 100;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void encode_l12_threshold(u32 threshold_us, u32 *scale, u32 *value)
|
||||||
|
+{
|
||||||
|
+ u32 threshold_ns = threshold_us * 1000;
|
||||||
|
+
|
||||||
|
+ /* See PCIe r3.1, sec 7.33.3 and sec 6.18 */
|
||||||
|
+ if (threshold_ns < 32) {
|
||||||
|
+ *scale = 0;
|
||||||
|
+ *value = threshold_ns;
|
||||||
|
+ } else if (threshold_ns < 1024) {
|
||||||
|
+ *scale = 1;
|
||||||
|
+ *value = threshold_ns >> 5;
|
||||||
|
+ } else if (threshold_ns < 32768) {
|
||||||
|
+ *scale = 2;
|
||||||
|
+ *value = threshold_ns >> 10;
|
||||||
|
+ } else if (threshold_ns < 1048576) {
|
||||||
|
+ *scale = 3;
|
||||||
|
+ *value = threshold_ns >> 15;
|
||||||
|
+ } else if (threshold_ns < 33554432) {
|
||||||
|
+ *scale = 4;
|
||||||
|
+ *value = threshold_ns >> 20;
|
||||||
|
+ } else {
|
||||||
|
+ *scale = 5;
|
||||||
|
+ *value = threshold_ns >> 25;
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+/* Calculate L1.2 PM substate timing parameters */
|
||||||
|
+static void aspm_calc_l1ss_info(struct pci_dev *child, struct pci_dev *parent)
|
||||||
|
+{
|
||||||
|
+ u32 val1, val2, scale1, scale2;
|
||||||
|
+ u32 t_common_mode, t_power_on, l1_2_threshold, scale, value;
|
||||||
|
+ u32 ctl1 = 0, ctl2 = 0;
|
||||||
|
+ u32 pctl1, pctl2, cctl1, cctl2;
|
||||||
|
+ u32 pl1_2_enables, cl1_2_enables;
|
||||||
|
+ u32 parent_l1ss_cap, child_l1ss_cap;
|
||||||
|
+
|
||||||
|
+ /* Setup L1 substate */
|
||||||
|
+ pci_read_config_dword(parent, parent->l1ss + PCI_L1SS_CAP,
|
||||||
|
+ &parent_l1ss_cap);
|
||||||
|
+ pci_read_config_dword(child, child->l1ss + PCI_L1SS_CAP,
|
||||||
|
+ &child_l1ss_cap);
|
||||||
|
+
|
||||||
|
+ /* Choose the greater of the two Port Common_Mode_Restore_Times */
|
||||||
|
+ val1 = (parent_l1ss_cap & PCI_L1SS_CAP_CM_RESTORE_TIME) >> 8;
|
||||||
|
+ val2 = (child_l1ss_cap & PCI_L1SS_CAP_CM_RESTORE_TIME) >> 8;
|
||||||
|
+ t_common_mode = max(val1, val2);
|
||||||
|
+
|
||||||
|
+ /* Choose the greater of the two Port T_POWER_ON times */
|
||||||
|
+ val1 = (parent_l1ss_cap & PCI_L1SS_CAP_P_PWR_ON_VALUE) >> 19;
|
||||||
|
+ scale1 = (parent_l1ss_cap & PCI_L1SS_CAP_P_PWR_ON_SCALE) >> 16;
|
||||||
|
+ val2 = (child_l1ss_cap & PCI_L1SS_CAP_P_PWR_ON_VALUE) >> 19;
|
||||||
|
+ scale2 = (child_l1ss_cap & PCI_L1SS_CAP_P_PWR_ON_SCALE) >> 16;
|
||||||
|
+
|
||||||
|
+ if (calc_l1ss_pwron(parent, scale1, val1) >
|
||||||
|
+ calc_l1ss_pwron(child, scale2, val2)) {
|
||||||
|
+ ctl2 |= scale1 | (val1 << 3);
|
||||||
|
+ t_power_on = calc_l1ss_pwron(parent, scale1, val1);
|
||||||
|
+ } else {
|
||||||
|
+ ctl2 |= scale2 | (val2 << 3);
|
||||||
|
+ t_power_on = calc_l1ss_pwron(child, scale2, val2);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /* Set LTR_L1.2_THRESHOLD to the time required to transition the
|
||||||
|
+ * Link from L0 to L1.2 and back to L0 so we enter L1.2 only if
|
||||||
|
+ * downstream devices report (via LTR) that they can tolerate at
|
||||||
|
+ * least that much latency.
|
||||||
|
+ *
|
||||||
|
+ * Based on PCIe r3.1, sec 5.5.3.3.1, Figures 5-16 and 5-17, and
|
||||||
|
+ * Table 5-11. T(POWER_OFF) is at most 2us and T(L1.2) is at
|
||||||
|
+ * least 4us.
|
||||||
|
+ */
|
||||||
|
+ l1_2_threshold = 2 + 4 + t_common_mode + t_power_on;
|
||||||
|
+ encode_l12_threshold(l1_2_threshold, &scale, &value);
|
||||||
|
+ ctl1 |= t_common_mode << 8 | scale << 29 | value << 16;
|
||||||
|
+
|
||||||
|
+ pci_read_config_dword(parent, parent->l1ss + PCI_L1SS_CTL1, &pctl1);
|
||||||
|
+ pci_read_config_dword(parent, parent->l1ss + PCI_L1SS_CTL2, &pctl2);
|
||||||
|
+ pci_read_config_dword(child, child->l1ss + PCI_L1SS_CTL1, &cctl1);
|
||||||
|
+ pci_read_config_dword(child, child->l1ss + PCI_L1SS_CTL2, &cctl2);
|
||||||
|
+
|
||||||
|
+ if (ctl1 == pctl1 && ctl1 == cctl1 &&
|
||||||
|
+ ctl2 == pctl2 && ctl2 == cctl2)
|
||||||
|
+ return;
|
||||||
|
+
|
||||||
|
+ /* Disable L1.2 while updating. See PCIe r5.0, sec 5.5.4, 7.8.3.3 */
|
||||||
|
+ pl1_2_enables = pctl1 & PCI_L1SS_CTL1_L1_2_MASK;
|
||||||
|
+ cl1_2_enables = cctl1 & PCI_L1SS_CTL1_L1_2_MASK;
|
||||||
|
+
|
||||||
|
+ if (pl1_2_enables || cl1_2_enables) {
|
||||||
|
+ pci_clear_and_set_dword(child, child->l1ss + PCI_L1SS_CTL1,
|
||||||
|
+ PCI_L1SS_CTL1_L1_2_MASK, 0);
|
||||||
|
+ pci_clear_and_set_dword(parent, parent->l1ss + PCI_L1SS_CTL1,
|
||||||
|
+ PCI_L1SS_CTL1_L1_2_MASK, 0);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /* Program T_POWER_ON times in both ports */
|
||||||
|
+ pci_write_config_dword(parent, parent->l1ss + PCI_L1SS_CTL2, ctl2);
|
||||||
|
+ pci_write_config_dword(child, child->l1ss + PCI_L1SS_CTL2, ctl2);
|
||||||
|
+
|
||||||
|
+ /* Program Common_Mode_Restore_Time in upstream device */
|
||||||
|
+ pci_clear_and_set_dword(parent, parent->l1ss + PCI_L1SS_CTL1,
|
||||||
|
+ PCI_L1SS_CTL1_CM_RESTORE_TIME, ctl1);
|
||||||
|
+
|
||||||
|
+ /* Program LTR_L1.2_THRESHOLD time in both ports */
|
||||||
|
+ pci_clear_and_set_dword(parent, parent->l1ss + PCI_L1SS_CTL1,
|
||||||
|
+ PCI_L1SS_CTL1_LTR_L12_TH_VALUE |
|
||||||
|
+ PCI_L1SS_CTL1_LTR_L12_TH_SCALE, ctl1);
|
||||||
|
+ pci_clear_and_set_dword(child, child->l1ss + PCI_L1SS_CTL1,
|
||||||
|
+ PCI_L1SS_CTL1_LTR_L12_TH_VALUE |
|
||||||
|
+ PCI_L1SS_CTL1_LTR_L12_TH_SCALE, ctl1);
|
||||||
|
+
|
||||||
|
+ if (pl1_2_enables || cl1_2_enables) {
|
||||||
|
+ pci_clear_and_set_dword(parent, parent->l1ss + PCI_L1SS_CTL1, 0,
|
||||||
|
+ pl1_2_enables);
|
||||||
|
+ pci_clear_and_set_dword(child, child->l1ss + PCI_L1SS_CTL1, 0,
|
||||||
|
+ cl1_2_enables);
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void rockchip_pcie_bus_l1ss_enable_dev(char *device, struct pci_dev *dev, bool enable)
|
||||||
|
+{
|
||||||
|
+ u32 l1ssctrl_before;
|
||||||
|
+ u32 l1ssctrl_after = 0;
|
||||||
|
+ u8 l1ss_ep;
|
||||||
|
+
|
||||||
|
+ /* Extendend Capacility Reg */
|
||||||
|
+ l1ssctrl_before = rockchip_pcie_pcie_access_cap(dev, PCI_EXT_CAP_ID_L1SS,
|
||||||
|
+ PCI_L1SS_CTL1, true, false, 0);
|
||||||
|
+ l1ss_ep = (l1ssctrl_before & PCI_L1SS_CTL1_L1SS_MASK);
|
||||||
|
+
|
||||||
|
+ if (enable) {
|
||||||
|
+ if (l1ss_ep == PCI_L1SS_CTL1_L1SS_MASK) {
|
||||||
|
+ pci_err(dev, "%s: %s already enabled, l1ssctrl: 0x%x\n",
|
||||||
|
+ __func__, device, l1ssctrl_before);
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+ rockchip_pcie_pcie_access_cap(dev, PCI_EXT_CAP_ID_L1SS, PCI_L1SS_CTL1,
|
||||||
|
+ true, true, (l1ssctrl_before | PCI_L1SS_CTL1_L1SS_MASK));
|
||||||
|
+ } else {
|
||||||
|
+ if (l1ss_ep == 0) {
|
||||||
|
+ pci_err(dev, "%s: %s already disabled, l1ssctrl: 0x%x\n",
|
||||||
|
+ __func__, device, l1ssctrl_before);
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+ rockchip_pcie_pcie_access_cap(dev, PCI_EXT_CAP_ID_L1SS, PCI_L1SS_CTL1,
|
||||||
|
+ true, true, (l1ssctrl_before & (~PCI_L1SS_CTL1_L1SS_MASK)));
|
||||||
|
+ }
|
||||||
|
+ l1ssctrl_after = rockchip_pcie_pcie_access_cap(dev, PCI_EXT_CAP_ID_L1SS,
|
||||||
|
+ PCI_L1SS_CTL1, true, false, 0);
|
||||||
|
+ pci_err(dev, "%s: %s %s, l1ssctrl_before: 0x%x l1ssctrl_after: 0x%x\n",
|
||||||
|
+ __func__, device, (enable ? "ENABLE " : "DISABLE"),
|
||||||
|
+ l1ssctrl_before, l1ssctrl_after);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+bool pcie_aspm_ext_is_rc_ep_l1ss_capable(struct pci_dev *child, struct pci_dev *parent)
|
||||||
|
+{
|
||||||
|
+ u32 parent_l1ss_cap, child_l1ss_cap;
|
||||||
|
+
|
||||||
|
+ /* Setup L1 substate */
|
||||||
|
+ pci_read_config_dword(parent, parent->l1ss + PCI_L1SS_CAP,
|
||||||
|
+ &parent_l1ss_cap);
|
||||||
|
+ pci_read_config_dword(child, child->l1ss + PCI_L1SS_CAP,
|
||||||
|
+ &child_l1ss_cap);
|
||||||
|
+
|
||||||
|
+ if (!(parent_l1ss_cap & PCI_L1SS_CAP_L1_PM_SS))
|
||||||
|
+ parent_l1ss_cap = 0;
|
||||||
|
+ if (!(child_l1ss_cap & PCI_L1SS_CAP_L1_PM_SS))
|
||||||
|
+ child_l1ss_cap = 0;
|
||||||
|
+
|
||||||
|
+ if (parent_l1ss_cap && child_l1ss_cap)
|
||||||
|
+ return true;
|
||||||
|
+ else
|
||||||
|
+ return false;
|
||||||
|
+}
|
||||||
|
+EXPORT_SYMBOL(pcie_aspm_ext_is_rc_ep_l1ss_capable);
|
||||||
|
+
|
||||||
|
+void pcie_aspm_ext_l1ss_enable(struct pci_dev *child, struct pci_dev *parent, bool enable)
|
||||||
|
+{
|
||||||
|
+ bool ret;
|
||||||
|
+
|
||||||
|
+ /* Disable ASPM of RC and EP */
|
||||||
|
+ ret = rockchip_pcie_bus_aspm_enable_rc_ep(child, parent, false);
|
||||||
|
+
|
||||||
|
+ if (enable) {
|
||||||
|
+ /* Enable RC then EP */
|
||||||
|
+ aspm_calc_l1ss_info(child, parent);
|
||||||
|
+ rockchip_pcie_bus_l1ss_enable_dev("RC", parent, enable);
|
||||||
|
+ rockchip_pcie_bus_l1ss_enable_dev("EP", child, enable);
|
||||||
|
+ } else {
|
||||||
|
+ /* Disable EP then RC */
|
||||||
|
+ rockchip_pcie_bus_l1ss_enable_dev("EP", child, enable);
|
||||||
|
+ rockchip_pcie_bus_l1ss_enable_dev("RC", parent, enable);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /* Enable ASPM of RC and EP only if this API disabled */
|
||||||
|
+ if (ret)
|
||||||
|
+ rockchip_pcie_bus_aspm_enable_rc_ep(child, parent, true);
|
||||||
|
+}
|
||||||
|
+EXPORT_SYMBOL(pcie_aspm_ext_l1ss_enable);
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/include/linux/aspm_ext.h
|
||||||
|
@@ -0,0 +1,16 @@
|
||||||
|
+/* SPDX-License-Identifier: GPL-2.0 */
|
||||||
|
+
|
||||||
|
+/* Copyright (c) 2022 Rockchip Electronics Co., Ltd. */
|
||||||
|
+
|
||||||
|
+#ifndef _ASPM_EXT_H
|
||||||
|
+#define _ASPM_EXT_H
|
||||||
|
+
|
||||||
|
+#if IS_REACHABLE(CONFIG_PCIEASPM_EXT)
|
||||||
|
+bool pcie_aspm_ext_is_rc_ep_l1ss_capable(struct pci_dev *child, struct pci_dev *parent);
|
||||||
|
+void pcie_aspm_ext_l1ss_enable(struct pci_dev *child, struct pci_dev *parent, bool enable);
|
||||||
|
+#else
|
||||||
|
+static inline bool pcie_aspm_ext_is_rc_ep_l1ss_capable(struct pci_dev *child, struct pci_dev *parent) { return false; }
|
||||||
|
+static inline void pcie_aspm_ext_l1ss_enable(struct pci_dev *child, struct pci_dev *parent, bool enable) {}
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
+#endif
|
@ -0,0 +1,24 @@
|
|||||||
|
From a6c71606de486944c5fb028f47604fb22292312b Mon Sep 17 00:00:00 2001
|
||||||
|
From: Jon Lin <jon.lin@rock-chips.com>
|
||||||
|
Date: Fri, 24 Jun 2022 21:32:11 +0800
|
||||||
|
Subject: [PATCH] PCI: aspm_ext: Re-enable LRT for L1SS after power loss
|
||||||
|
|
||||||
|
Change-Id: Iedb72ee74660a8f11f38895e06766c3b77728ba3
|
||||||
|
Signed-off-by: Jon Lin <jon.lin@rock-chips.com>
|
||||||
|
---
|
||||||
|
drivers/pci/pcie/aspm_ext.c | 4 ++++
|
||||||
|
1 file changed, 4 insertions(+)
|
||||||
|
|
||||||
|
--- a/drivers/pci/pcie/aspm_ext.c
|
||||||
|
+++ b/drivers/pci/pcie/aspm_ext.c
|
||||||
|
@@ -322,6 +322,10 @@ void pcie_aspm_ext_l1ss_enable(struct pc
|
||||||
|
ret = rockchip_pcie_bus_aspm_enable_rc_ep(child, parent, false);
|
||||||
|
|
||||||
|
if (enable) {
|
||||||
|
+ /* LRT enable bits loss after wifi off, enable it after power on */
|
||||||
|
+ if (parent->ltr_path)
|
||||||
|
+ pcie_capability_set_word(parent, PCI_EXP_DEVCTL2, PCI_EXP_DEVCTL2_LTR_EN);
|
||||||
|
+
|
||||||
|
/* Enable RC then EP */
|
||||||
|
aspm_calc_l1ss_info(child, parent);
|
||||||
|
rockchip_pcie_bus_l1ss_enable_dev("RC", parent, enable);
|
@ -0,0 +1,38 @@
|
|||||||
|
From cf03561e5ec9f2f8b41a992f3b8ca19b9c3b9e47 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Tao Huang <huangtao@rock-chips.com>
|
||||||
|
Date: Fri, 15 Jul 2022 20:56:15 +0800
|
||||||
|
Subject: [PATCH] PCI: aspm_ext: Fix Add missing MODULE_LICENSE()
|
||||||
|
|
||||||
|
ERROR: modpost: missing MODULE_LICENSE() in drivers/pci/pcie/aspm_ext.o
|
||||||
|
|
||||||
|
Signed-off-by: Tao Huang <huangtao@rock-chips.com>
|
||||||
|
Change-Id: Id365aba7a73f02cc2c61882b46937250e64af01c
|
||||||
|
---
|
||||||
|
drivers/pci/pcie/aspm_ext.c | 5 ++++-
|
||||||
|
1 file changed, 4 insertions(+), 1 deletion(-)
|
||||||
|
|
||||||
|
--- a/drivers/pci/pcie/aspm_ext.c
|
||||||
|
+++ b/drivers/pci/pcie/aspm_ext.c
|
||||||
|
@@ -6,6 +6,7 @@
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
+#include <linux/module.h>
|
||||||
|
#include <linux/pci.h>
|
||||||
|
#include <linux/aspm_ext.h>
|
||||||
|
#include <linux/errno.h>
|
||||||
|
@@ -95,7 +96,7 @@ static bool rockchip_pcie_bus_aspm_enabl
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
-bool rockchip_pcie_bus_aspm_enable_rc_ep(struct pci_dev *child, struct pci_dev *parent, bool enable)
|
||||||
|
+static bool rockchip_pcie_bus_aspm_enable_rc_ep(struct pci_dev *child, struct pci_dev *parent, bool enable)
|
||||||
|
{
|
||||||
|
bool ret;
|
||||||
|
|
||||||
|
@@ -341,3 +342,5 @@ void pcie_aspm_ext_l1ss_enable(struct pc
|
||||||
|
rockchip_pcie_bus_aspm_enable_rc_ep(child, parent, true);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(pcie_aspm_ext_l1ss_enable);
|
||||||
|
+
|
||||||
|
+MODULE_LICENSE("GPL");
|
@ -0,0 +1,58 @@
|
|||||||
|
From 6e57e8b78939b4d849511fa96467d09d77ce8a26 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Shawn Lin <shawn.lin@rock-chips.com>
|
||||||
|
Date: Tue, 31 Jan 2023 08:46:29 +0800
|
||||||
|
Subject: [PATCH 1/3] mmc: sdhci-of-dwcmshc: Update DLL and pre-change delay
|
||||||
|
for rockchip platform
|
||||||
|
|
||||||
|
For Rockchip platform, DLL bypass bit and start bit need to be set if
|
||||||
|
DLL is not locked. And adjust pre-change delay to 0x3 for better signal
|
||||||
|
test result.
|
||||||
|
|
||||||
|
Signed-off-by: Shawn Lin <shawn.lin@rock-chips.com>
|
||||||
|
---
|
||||||
|
drivers/mmc/host/sdhci-of-dwcmshc.c | 13 +++++++++----
|
||||||
|
1 file changed, 9 insertions(+), 4 deletions(-)
|
||||||
|
|
||||||
|
--- a/drivers/mmc/host/sdhci-of-dwcmshc.c
|
||||||
|
+++ b/drivers/mmc/host/sdhci-of-dwcmshc.c
|
||||||
|
@@ -48,6 +48,7 @@
|
||||||
|
#define DWCMSHC_EMMC_DLL_RXCLK_SRCSEL 29
|
||||||
|
#define DWCMSHC_EMMC_DLL_START_POINT 16
|
||||||
|
#define DWCMSHC_EMMC_DLL_INC 8
|
||||||
|
+#define DWCMSHC_EMMC_DLL_BYPASS BIT(24)
|
||||||
|
#define DWCMSHC_EMMC_DLL_DLYENA BIT(27)
|
||||||
|
#define DLL_TXCLK_TAPNUM_DEFAULT 0x10
|
||||||
|
#define DLL_TXCLK_TAPNUM_90_DEGREES 0xA
|
||||||
|
@@ -60,6 +61,7 @@
|
||||||
|
#define DLL_RXCLK_NO_INVERTER 1
|
||||||
|
#define DLL_RXCLK_INVERTER 0
|
||||||
|
#define DLL_CMDOUT_TAPNUM_90_DEGREES 0x8
|
||||||
|
+#define DLL_RXCLK_ORI_GATE BIT(31)
|
||||||
|
#define DLL_CMDOUT_TAPNUM_FROM_SW BIT(24)
|
||||||
|
#define DLL_CMDOUT_SRC_CLK_NEG BIT(28)
|
||||||
|
#define DLL_CMDOUT_EN_SRC_CLK_NEG BIT(29)
|
||||||
|
@@ -234,9 +236,12 @@ static void dwcmshc_rk3568_set_clock(str
|
||||||
|
sdhci_writel(host, extra, reg);
|
||||||
|
|
||||||
|
if (clock <= 52000000) {
|
||||||
|
- /* Disable DLL and reset both of sample and drive clock */
|
||||||
|
- sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_CTRL);
|
||||||
|
- sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_RXCLK);
|
||||||
|
+ /*
|
||||||
|
+ * Disable DLL and reset both of sample and drive clock.
|
||||||
|
+ * The bypass bit and start bit need to be set if DLL is not locked.
|
||||||
|
+ */
|
||||||
|
+ sdhci_writel(host, DWCMSHC_EMMC_DLL_BYPASS | DWCMSHC_EMMC_DLL_START, DWCMSHC_EMMC_DLL_CTRL);
|
||||||
|
+ sdhci_writel(host, DLL_RXCLK_ORI_GATE, DWCMSHC_EMMC_DLL_RXCLK);
|
||||||
|
sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_TXCLK);
|
||||||
|
sdhci_writel(host, 0, DECMSHC_EMMC_DLL_CMDOUT);
|
||||||
|
/*
|
||||||
|
@@ -279,7 +284,7 @@ static void dwcmshc_rk3568_set_clock(str
|
||||||
|
}
|
||||||
|
|
||||||
|
extra = 0x1 << 16 | /* tune clock stop en */
|
||||||
|
- 0x2 << 17 | /* pre-change delay */
|
||||||
|
+ 0x3 << 17 | /* pre-change delay */
|
||||||
|
0x3 << 19; /* post-change delay */
|
||||||
|
sdhci_writel(host, extra, dwc_priv->vendor_specific_area1 + DWCMSHC_EMMC_ATCTRL);
|
||||||
|
|
@ -0,0 +1,93 @@
|
|||||||
|
From ce8180045daea68c45ba5bd2495885410b7b9dc8 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Shawn Lin <shawn.lin@rock-chips.com>
|
||||||
|
Date: Tue, 31 Jan 2023 08:46:30 +0800
|
||||||
|
Subject: [PATCH 2/3] mmc: sdhci-of-dwcmshc: Add runtime PM support
|
||||||
|
|
||||||
|
This patch adds runtime PM support.
|
||||||
|
|
||||||
|
Signed-off-by: Shawn Lin <shawn.lin@rock-chips.com>
|
||||||
|
---
|
||||||
|
drivers/mmc/host/sdhci-of-dwcmshc.c | 51 ++++++++++++++++++++++++++++-
|
||||||
|
1 file changed, 50 insertions(+), 1 deletion(-)
|
||||||
|
|
||||||
|
--- a/drivers/mmc/host/sdhci-of-dwcmshc.c
|
||||||
|
+++ b/drivers/mmc/host/sdhci-of-dwcmshc.c
|
||||||
|
@@ -15,6 +15,7 @@
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/of.h>
|
||||||
|
#include <linux/of_device.h>
|
||||||
|
+#include <linux/pm_runtime.h>
|
||||||
|
#include <linux/reset.h>
|
||||||
|
#include <linux/sizes.h>
|
||||||
|
|
||||||
|
@@ -546,6 +547,13 @@ static int dwcmshc_probe(struct platform
|
||||||
|
if (err)
|
||||||
|
goto err_setup_host;
|
||||||
|
|
||||||
|
+ pm_runtime_get_noresume(&pdev->dev);
|
||||||
|
+ pm_runtime_set_active(&pdev->dev);
|
||||||
|
+ pm_runtime_enable(&pdev->dev);
|
||||||
|
+ pm_runtime_set_autosuspend_delay(&pdev->dev, 50);
|
||||||
|
+ pm_runtime_use_autosuspend(&pdev->dev);
|
||||||
|
+ pm_runtime_put_autosuspend(&pdev->dev);
|
||||||
|
+
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
err_setup_host:
|
||||||
|
@@ -575,6 +583,11 @@ static int dwcmshc_remove(struct platfor
|
||||||
|
if (rk_priv)
|
||||||
|
clk_bulk_disable_unprepare(RK35xx_MAX_CLKS,
|
||||||
|
rk_priv->rockchip_clks);
|
||||||
|
+
|
||||||
|
+ pm_runtime_get_sync(&pdev->dev);
|
||||||
|
+ pm_runtime_disable(&pdev->dev);
|
||||||
|
+ pm_runtime_put_noidle(&pdev->dev);
|
||||||
|
+
|
||||||
|
sdhci_pltfm_free(pdev);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
@@ -633,7 +646,43 @@ static int dwcmshc_resume(struct device
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
-static SIMPLE_DEV_PM_OPS(dwcmshc_pmops, dwcmshc_suspend, dwcmshc_resume);
|
||||||
|
+#ifdef CONFIG_PM
|
||||||
|
+static int dwcmshc_runtime_suspend(struct device *dev)
|
||||||
|
+{
|
||||||
|
+ struct sdhci_host *host = dev_get_drvdata(dev);
|
||||||
|
+ u16 data;
|
||||||
|
+ int ret;
|
||||||
|
+
|
||||||
|
+ ret = sdhci_runtime_suspend_host(host);
|
||||||
|
+ if (ret)
|
||||||
|
+ return ret;
|
||||||
|
+
|
||||||
|
+ data = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
|
||||||
|
+ data &= ~SDHCI_CLOCK_CARD_EN;
|
||||||
|
+ sdhci_writew(host, data, SDHCI_CLOCK_CONTROL);
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int dwcmshc_runtime_resume(struct device *dev)
|
||||||
|
+{
|
||||||
|
+ struct sdhci_host *host = dev_get_drvdata(dev);
|
||||||
|
+ u16 data;
|
||||||
|
+
|
||||||
|
+ data = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
|
||||||
|
+ data |= SDHCI_CLOCK_CARD_EN;
|
||||||
|
+ sdhci_writew(host, data, SDHCI_CLOCK_CONTROL);
|
||||||
|
+
|
||||||
|
+ return sdhci_runtime_resume_host(host, 0);
|
||||||
|
+}
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
+static const struct dev_pm_ops dwcmshc_pmops = {
|
||||||
|
+ SET_SYSTEM_SLEEP_PM_OPS(dwcmshc_suspend,
|
||||||
|
+ dwcmshc_resume)
|
||||||
|
+ SET_RUNTIME_PM_OPS(dwcmshc_runtime_suspend,
|
||||||
|
+ dwcmshc_runtime_resume, NULL)
|
||||||
|
+};
|
||||||
|
|
||||||
|
static struct platform_driver sdhci_dwcmshc_driver = {
|
||||||
|
.driver = {
|
@ -0,0 +1,90 @@
|
|||||||
|
From 55c88b9f9ed2ba17fe5a4b095fd0fbd9c38b1c4b Mon Sep 17 00:00:00 2001
|
||||||
|
From: Shawn Lin <shawn.lin@rock-chips.com>
|
||||||
|
Date: Tue, 31 Jan 2023 08:46:31 +0800
|
||||||
|
Subject: [PATCH 3/3] mmc: sdhci-of-dwcmshc: Add host software queue support
|
||||||
|
|
||||||
|
Signed-off-by: Shawn Lin <shawn.lin@rock-chips.com>
|
||||||
|
---
|
||||||
|
drivers/mmc/host/sdhci-of-dwcmshc.c | 29 ++++++++++++++++++++++++++++-
|
||||||
|
1 file changed, 28 insertions(+), 1 deletion(-)
|
||||||
|
|
||||||
|
--- a/drivers/mmc/host/sdhci-of-dwcmshc.c
|
||||||
|
+++ b/drivers/mmc/host/sdhci-of-dwcmshc.c
|
||||||
|
@@ -20,6 +20,7 @@
|
||||||
|
#include <linux/sizes.h>
|
||||||
|
|
||||||
|
#include "sdhci-pltfm.h"
|
||||||
|
+#include "mmc_hsq.h"
|
||||||
|
|
||||||
|
#define SDHCI_DWCMSHC_ARG2_STUFF GENMASK(31, 16)
|
||||||
|
|
||||||
|
@@ -331,6 +332,14 @@ static void rk35xx_sdhci_reset(struct sd
|
||||||
|
sdhci_reset(host, mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
+static void sdhci_dwcmshc_request_done(struct sdhci_host *host, struct mmc_request *mrq)
|
||||||
|
+{
|
||||||
|
+ if (mmc_hsq_finalize_request(host->mmc, mrq))
|
||||||
|
+ return;
|
||||||
|
+
|
||||||
|
+ mmc_request_done(host->mmc, mrq);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static const struct sdhci_ops sdhci_dwcmshc_ops = {
|
||||||
|
.set_clock = sdhci_set_clock,
|
||||||
|
.set_bus_width = sdhci_set_bus_width,
|
||||||
|
@@ -347,6 +356,7 @@ static const struct sdhci_ops sdhci_dwcm
|
||||||
|
.get_max_clock = sdhci_pltfm_clk_get_max_clock,
|
||||||
|
.reset = rk35xx_sdhci_reset,
|
||||||
|
.adma_write_desc = dwcmshc_adma_write_desc,
|
||||||
|
+ .request_done = sdhci_dwcmshc_request_done,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct sdhci_pltfm_data sdhci_dwcmshc_pdata = {
|
||||||
|
@@ -462,6 +472,7 @@ static int dwcmshc_probe(struct platform
|
||||||
|
struct dwcmshc_priv *priv;
|
||||||
|
struct rk35xx_priv *rk_priv = NULL;
|
||||||
|
const struct sdhci_pltfm_data *pltfm_data;
|
||||||
|
+ struct mmc_hsq *hsq;
|
||||||
|
int err;
|
||||||
|
u32 extra;
|
||||||
|
|
||||||
|
@@ -515,6 +526,16 @@ static int dwcmshc_probe(struct platform
|
||||||
|
host->mmc_host_ops.request = dwcmshc_request;
|
||||||
|
host->mmc_host_ops.hs400_enhanced_strobe = dwcmshc_hs400_enhanced_strobe;
|
||||||
|
|
||||||
|
+ hsq = devm_kzalloc(&pdev->dev, sizeof(*hsq), GFP_KERNEL);
|
||||||
|
+ if (!hsq) {
|
||||||
|
+ err = -ENOMEM;
|
||||||
|
+ goto err_clk;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ err = mmc_hsq_init(hsq, host->mmc);
|
||||||
|
+ if (err)
|
||||||
|
+ goto err_clk;
|
||||||
|
+
|
||||||
|
if (pltfm_data == &sdhci_dwcmshc_rk35xx_pdata) {
|
||||||
|
rk_priv = devm_kzalloc(&pdev->dev, sizeof(struct rk35xx_priv), GFP_KERNEL);
|
||||||
|
if (!rk_priv) {
|
||||||
|
@@ -602,6 +623,8 @@ static int dwcmshc_suspend(struct device
|
||||||
|
struct rk35xx_priv *rk_priv = priv->priv;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
+ mmc_hsq_suspend(host->mmc);
|
||||||
|
+
|
||||||
|
ret = sdhci_suspend_host(host);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
@@ -642,7 +665,11 @@ static int dwcmshc_resume(struct device
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
- return sdhci_resume_host(host);
|
||||||
|
+ ret = sdhci_resume_host(host);
|
||||||
|
+ if (ret)
|
||||||
|
+ return ret;
|
||||||
|
+
|
||||||
|
+ return mmc_hsq_resume(host->mmc);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
402
patches-6.2/220-PCI-Add-ROCKCHIP-PCIe-ASPM-interface.patch
Normal file
402
patches-6.2/220-PCI-Add-ROCKCHIP-PCIe-ASPM-interface.patch
Normal file
@ -0,0 +1,402 @@
|
|||||||
|
From d591c3f6efef5f50fc970aeeedbf9e03b7bd5d21 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Jon Lin <jon.lin@rock-chips.com>
|
||||||
|
Date: Fri, 17 Jun 2022 10:38:30 +0800
|
||||||
|
Subject: [PATCH] PCI: Add ROCKCHIP PCIe ASPM interface
|
||||||
|
|
||||||
|
Change-Id: I1156bd10e352145d745899067bf43afda92d5a30
|
||||||
|
Signed-off-by: Jon Lin <jon.lin@rock-chips.com>
|
||||||
|
---
|
||||||
|
drivers/pci/pcie/Kconfig | 6 +
|
||||||
|
drivers/pci/pcie/Makefile | 1 +
|
||||||
|
drivers/pci/pcie/aspm_ext.c | 339 ++++++++++++++++++++++++++++++++++++
|
||||||
|
include/linux/aspm_ext.h | 16 ++
|
||||||
|
4 files changed, 362 insertions(+)
|
||||||
|
create mode 100644 drivers/pci/pcie/aspm_ext.c
|
||||||
|
create mode 100644 include/linux/aspm_ext.h
|
||||||
|
|
||||||
|
--- a/drivers/pci/pcie/Kconfig
|
||||||
|
+++ b/drivers/pci/pcie/Kconfig
|
||||||
|
@@ -114,6 +114,12 @@ config PCIEASPM_PERFORMANCE
|
||||||
|
Disable PCI Express ASPM L0s and L1, even if the BIOS enabled them.
|
||||||
|
endchoice
|
||||||
|
|
||||||
|
+config PCIEASPM_EXT
|
||||||
|
+ tristate "Extend ASPM function"
|
||||||
|
+ depends on PCIEASPM
|
||||||
|
+ help
|
||||||
|
+ This enables the extensions APIs for ASPM control.
|
||||||
|
+
|
||||||
|
config PCIE_PME
|
||||||
|
def_bool y
|
||||||
|
depends on PCIEPORTBUS && PM
|
||||||
|
--- a/drivers/pci/pcie/Makefile
|
||||||
|
+++ b/drivers/pci/pcie/Makefile
|
||||||
|
@@ -7,6 +7,7 @@ pcieportdrv-y := portdrv.o rcec.o
|
||||||
|
obj-$(CONFIG_PCIEPORTBUS) += pcieportdrv.o
|
||||||
|
|
||||||
|
obj-$(CONFIG_PCIEASPM) += aspm.o
|
||||||
|
+obj-$(CONFIG_PCIEASPM_EXT) += aspm_ext.o
|
||||||
|
obj-$(CONFIG_PCIEAER) += aer.o err.o
|
||||||
|
obj-$(CONFIG_PCIEAER_INJECT) += aer_inject.o
|
||||||
|
obj-$(CONFIG_PCIE_PME) += pme.o
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/drivers/pci/pcie/aspm_ext.c
|
||||||
|
@@ -0,0 +1,339 @@
|
||||||
|
+// SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
+/*
|
||||||
|
+ * Rockchip PCIe Apis For WIFI
|
||||||
|
+ *
|
||||||
|
+ * Copyright (c) 2022 Rockchip Electronics Co., Ltd.
|
||||||
|
+ */
|
||||||
|
+
|
||||||
|
+#include <linux/kernel.h>
|
||||||
|
+#include <linux/pci.h>
|
||||||
|
+#include <linux/aspm_ext.h>
|
||||||
|
+#include <linux/errno.h>
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+static u32 rockchip_pcie_pcie_access_cap(struct pci_dev *pdev, int cap, uint offset,
|
||||||
|
+ bool is_ext, bool is_write, u32 writeval)
|
||||||
|
+{
|
||||||
|
+ int cap_ptr = 0;
|
||||||
|
+ u32 ret = -1;
|
||||||
|
+ u32 readval;
|
||||||
|
+
|
||||||
|
+ if (!(pdev)) {
|
||||||
|
+ pci_err(pdev, "%s: pdev is NULL\n", __func__);
|
||||||
|
+ return ret;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /* Find Capability offset */
|
||||||
|
+ if (is_ext) {
|
||||||
|
+ /* removing max EXT_CAP_ID check as
|
||||||
|
+ * linux kernel definition's max value is not updated yet as per spec
|
||||||
|
+ */
|
||||||
|
+ cap_ptr = pci_find_ext_capability(pdev, cap);
|
||||||
|
+
|
||||||
|
+ } else {
|
||||||
|
+ /* removing max PCI_CAP_ID_MAX check as
|
||||||
|
+ * previous kernel versions dont have this definition
|
||||||
|
+ */
|
||||||
|
+ cap_ptr = pci_find_capability(pdev, cap);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /* Return if capability with given ID not found */
|
||||||
|
+ if (cap_ptr == 0) {
|
||||||
|
+ pci_err(pdev, "%s: PCI Cap(0x%02x) not supported.\n",
|
||||||
|
+ __func__, cap);
|
||||||
|
+ return -EINVAL;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (is_write) {
|
||||||
|
+ pci_write_config_dword(pdev, (cap_ptr + offset), writeval);
|
||||||
|
+ ret = 0;
|
||||||
|
+
|
||||||
|
+ } else {
|
||||||
|
+ pci_read_config_dword(pdev, (cap_ptr + offset), &readval);
|
||||||
|
+ ret = readval;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return ret;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static bool rockchip_pcie_bus_aspm_enable_dev(char *device, struct pci_dev *dev, bool enable)
|
||||||
|
+{
|
||||||
|
+ u32 linkctrl_before;
|
||||||
|
+ u32 linkctrl_after = 0;
|
||||||
|
+ u8 linkctrl_asm;
|
||||||
|
+
|
||||||
|
+ linkctrl_before = rockchip_pcie_pcie_access_cap(dev, PCI_CAP_ID_EXP, PCI_EXP_LNKCTL,
|
||||||
|
+ false, false, 0);
|
||||||
|
+ linkctrl_asm = (linkctrl_before & PCI_EXP_LNKCTL_ASPMC);
|
||||||
|
+
|
||||||
|
+ if (enable) {
|
||||||
|
+ if (linkctrl_asm == PCI_EXP_LNKCTL_ASPM_L1) {
|
||||||
|
+ pci_err(dev, "%s: %s already enabled linkctrl: 0x%x\n",
|
||||||
|
+ __func__, device, linkctrl_before);
|
||||||
|
+ return false;
|
||||||
|
+ }
|
||||||
|
+ /* Enable only L1 ASPM (bit 1) */
|
||||||
|
+ rockchip_pcie_pcie_access_cap(dev, PCI_CAP_ID_EXP, PCI_EXP_LNKCTL, false,
|
||||||
|
+ true, (linkctrl_before | PCI_EXP_LNKCTL_ASPM_L1));
|
||||||
|
+ } else {
|
||||||
|
+ if (linkctrl_asm == 0) {
|
||||||
|
+ pci_err(dev, "%s: %s already disabled linkctrl: 0x%x\n",
|
||||||
|
+ __func__, device, linkctrl_before);
|
||||||
|
+ return false;
|
||||||
|
+ }
|
||||||
|
+ /* Disable complete ASPM (bit 1 and bit 0) */
|
||||||
|
+ rockchip_pcie_pcie_access_cap(dev, PCI_CAP_ID_EXP, PCI_EXP_LNKCTL, false,
|
||||||
|
+ true, (linkctrl_before & (~PCI_EXP_LNKCTL_ASPMC)));
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ linkctrl_after = rockchip_pcie_pcie_access_cap(dev, PCI_CAP_ID_EXP, PCI_EXP_LNKCTL,
|
||||||
|
+ false, false, 0);
|
||||||
|
+ pci_err(dev, "%s: %s %s, linkctrl_before: 0x%x linkctrl_after: 0x%x\n",
|
||||||
|
+ __func__, device, (enable ? "ENABLE " : "DISABLE"),
|
||||||
|
+ linkctrl_before, linkctrl_after);
|
||||||
|
+
|
||||||
|
+ return true;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+bool rockchip_pcie_bus_aspm_enable_rc_ep(struct pci_dev *child, struct pci_dev *parent, bool enable)
|
||||||
|
+{
|
||||||
|
+ bool ret;
|
||||||
|
+
|
||||||
|
+ if (enable) {
|
||||||
|
+ /* Enable only L1 ASPM first RC then EP */
|
||||||
|
+ ret = rockchip_pcie_bus_aspm_enable_dev("RC", parent, enable);
|
||||||
|
+ ret = rockchip_pcie_bus_aspm_enable_dev("EP", child, enable);
|
||||||
|
+ } else {
|
||||||
|
+ /* Disable complete ASPM first EP then RC */
|
||||||
|
+ ret = rockchip_pcie_bus_aspm_enable_dev("EP", child, enable);
|
||||||
|
+ ret = rockchip_pcie_bus_aspm_enable_dev("RC", parent, enable);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return ret;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void pci_clear_and_set_dword(struct pci_dev *pdev, int pos,
|
||||||
|
+ u32 clear, u32 set)
|
||||||
|
+{
|
||||||
|
+ u32 val;
|
||||||
|
+
|
||||||
|
+ pci_read_config_dword(pdev, pos, &val);
|
||||||
|
+ val &= ~clear;
|
||||||
|
+ val |= set;
|
||||||
|
+ pci_write_config_dword(pdev, pos, val);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+/* Convert L1SS T_pwr encoding to usec */
|
||||||
|
+static u32 calc_l1ss_pwron(struct pci_dev *pdev, u32 scale, u32 val)
|
||||||
|
+{
|
||||||
|
+ switch (scale) {
|
||||||
|
+ case 0:
|
||||||
|
+ return val * 2;
|
||||||
|
+ case 1:
|
||||||
|
+ return val * 10;
|
||||||
|
+ case 2:
|
||||||
|
+ return val * 100;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void encode_l12_threshold(u32 threshold_us, u32 *scale, u32 *value)
|
||||||
|
+{
|
||||||
|
+ u32 threshold_ns = threshold_us * 1000;
|
||||||
|
+
|
||||||
|
+ /* See PCIe r3.1, sec 7.33.3 and sec 6.18 */
|
||||||
|
+ if (threshold_ns < 32) {
|
||||||
|
+ *scale = 0;
|
||||||
|
+ *value = threshold_ns;
|
||||||
|
+ } else if (threshold_ns < 1024) {
|
||||||
|
+ *scale = 1;
|
||||||
|
+ *value = threshold_ns >> 5;
|
||||||
|
+ } else if (threshold_ns < 32768) {
|
||||||
|
+ *scale = 2;
|
||||||
|
+ *value = threshold_ns >> 10;
|
||||||
|
+ } else if (threshold_ns < 1048576) {
|
||||||
|
+ *scale = 3;
|
||||||
|
+ *value = threshold_ns >> 15;
|
||||||
|
+ } else if (threshold_ns < 33554432) {
|
||||||
|
+ *scale = 4;
|
||||||
|
+ *value = threshold_ns >> 20;
|
||||||
|
+ } else {
|
||||||
|
+ *scale = 5;
|
||||||
|
+ *value = threshold_ns >> 25;
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+/* Calculate L1.2 PM substate timing parameters */
|
||||||
|
+static void aspm_calc_l1ss_info(struct pci_dev *child, struct pci_dev *parent)
|
||||||
|
+{
|
||||||
|
+ u32 val1, val2, scale1, scale2;
|
||||||
|
+ u32 t_common_mode, t_power_on, l1_2_threshold, scale, value;
|
||||||
|
+ u32 ctl1 = 0, ctl2 = 0;
|
||||||
|
+ u32 pctl1, pctl2, cctl1, cctl2;
|
||||||
|
+ u32 pl1_2_enables, cl1_2_enables;
|
||||||
|
+ u32 parent_l1ss_cap, child_l1ss_cap;
|
||||||
|
+
|
||||||
|
+ /* Setup L1 substate */
|
||||||
|
+ pci_read_config_dword(parent, parent->l1ss + PCI_L1SS_CAP,
|
||||||
|
+ &parent_l1ss_cap);
|
||||||
|
+ pci_read_config_dword(child, child->l1ss + PCI_L1SS_CAP,
|
||||||
|
+ &child_l1ss_cap);
|
||||||
|
+
|
||||||
|
+ /* Choose the greater of the two Port Common_Mode_Restore_Times */
|
||||||
|
+ val1 = (parent_l1ss_cap & PCI_L1SS_CAP_CM_RESTORE_TIME) >> 8;
|
||||||
|
+ val2 = (child_l1ss_cap & PCI_L1SS_CAP_CM_RESTORE_TIME) >> 8;
|
||||||
|
+ t_common_mode = max(val1, val2);
|
||||||
|
+
|
||||||
|
+ /* Choose the greater of the two Port T_POWER_ON times */
|
||||||
|
+ val1 = (parent_l1ss_cap & PCI_L1SS_CAP_P_PWR_ON_VALUE) >> 19;
|
||||||
|
+ scale1 = (parent_l1ss_cap & PCI_L1SS_CAP_P_PWR_ON_SCALE) >> 16;
|
||||||
|
+ val2 = (child_l1ss_cap & PCI_L1SS_CAP_P_PWR_ON_VALUE) >> 19;
|
||||||
|
+ scale2 = (child_l1ss_cap & PCI_L1SS_CAP_P_PWR_ON_SCALE) >> 16;
|
||||||
|
+
|
||||||
|
+ if (calc_l1ss_pwron(parent, scale1, val1) >
|
||||||
|
+ calc_l1ss_pwron(child, scale2, val2)) {
|
||||||
|
+ ctl2 |= scale1 | (val1 << 3);
|
||||||
|
+ t_power_on = calc_l1ss_pwron(parent, scale1, val1);
|
||||||
|
+ } else {
|
||||||
|
+ ctl2 |= scale2 | (val2 << 3);
|
||||||
|
+ t_power_on = calc_l1ss_pwron(child, scale2, val2);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /* Set LTR_L1.2_THRESHOLD to the time required to transition the
|
||||||
|
+ * Link from L0 to L1.2 and back to L0 so we enter L1.2 only if
|
||||||
|
+ * downstream devices report (via LTR) that they can tolerate at
|
||||||
|
+ * least that much latency.
|
||||||
|
+ *
|
||||||
|
+ * Based on PCIe r3.1, sec 5.5.3.3.1, Figures 5-16 and 5-17, and
|
||||||
|
+ * Table 5-11. T(POWER_OFF) is at most 2us and T(L1.2) is at
|
||||||
|
+ * least 4us.
|
||||||
|
+ */
|
||||||
|
+ l1_2_threshold = 2 + 4 + t_common_mode + t_power_on;
|
||||||
|
+ encode_l12_threshold(l1_2_threshold, &scale, &value);
|
||||||
|
+ ctl1 |= t_common_mode << 8 | scale << 29 | value << 16;
|
||||||
|
+
|
||||||
|
+ pci_read_config_dword(parent, parent->l1ss + PCI_L1SS_CTL1, &pctl1);
|
||||||
|
+ pci_read_config_dword(parent, parent->l1ss + PCI_L1SS_CTL2, &pctl2);
|
||||||
|
+ pci_read_config_dword(child, child->l1ss + PCI_L1SS_CTL1, &cctl1);
|
||||||
|
+ pci_read_config_dword(child, child->l1ss + PCI_L1SS_CTL2, &cctl2);
|
||||||
|
+
|
||||||
|
+ if (ctl1 == pctl1 && ctl1 == cctl1 &&
|
||||||
|
+ ctl2 == pctl2 && ctl2 == cctl2)
|
||||||
|
+ return;
|
||||||
|
+
|
||||||
|
+ /* Disable L1.2 while updating. See PCIe r5.0, sec 5.5.4, 7.8.3.3 */
|
||||||
|
+ pl1_2_enables = pctl1 & PCI_L1SS_CTL1_L1_2_MASK;
|
||||||
|
+ cl1_2_enables = cctl1 & PCI_L1SS_CTL1_L1_2_MASK;
|
||||||
|
+
|
||||||
|
+ if (pl1_2_enables || cl1_2_enables) {
|
||||||
|
+ pci_clear_and_set_dword(child, child->l1ss + PCI_L1SS_CTL1,
|
||||||
|
+ PCI_L1SS_CTL1_L1_2_MASK, 0);
|
||||||
|
+ pci_clear_and_set_dword(parent, parent->l1ss + PCI_L1SS_CTL1,
|
||||||
|
+ PCI_L1SS_CTL1_L1_2_MASK, 0);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /* Program T_POWER_ON times in both ports */
|
||||||
|
+ pci_write_config_dword(parent, parent->l1ss + PCI_L1SS_CTL2, ctl2);
|
||||||
|
+ pci_write_config_dword(child, child->l1ss + PCI_L1SS_CTL2, ctl2);
|
||||||
|
+
|
||||||
|
+ /* Program Common_Mode_Restore_Time in upstream device */
|
||||||
|
+ pci_clear_and_set_dword(parent, parent->l1ss + PCI_L1SS_CTL1,
|
||||||
|
+ PCI_L1SS_CTL1_CM_RESTORE_TIME, ctl1);
|
||||||
|
+
|
||||||
|
+ /* Program LTR_L1.2_THRESHOLD time in both ports */
|
||||||
|
+ pci_clear_and_set_dword(parent, parent->l1ss + PCI_L1SS_CTL1,
|
||||||
|
+ PCI_L1SS_CTL1_LTR_L12_TH_VALUE |
|
||||||
|
+ PCI_L1SS_CTL1_LTR_L12_TH_SCALE, ctl1);
|
||||||
|
+ pci_clear_and_set_dword(child, child->l1ss + PCI_L1SS_CTL1,
|
||||||
|
+ PCI_L1SS_CTL1_LTR_L12_TH_VALUE |
|
||||||
|
+ PCI_L1SS_CTL1_LTR_L12_TH_SCALE, ctl1);
|
||||||
|
+
|
||||||
|
+ if (pl1_2_enables || cl1_2_enables) {
|
||||||
|
+ pci_clear_and_set_dword(parent, parent->l1ss + PCI_L1SS_CTL1, 0,
|
||||||
|
+ pl1_2_enables);
|
||||||
|
+ pci_clear_and_set_dword(child, child->l1ss + PCI_L1SS_CTL1, 0,
|
||||||
|
+ cl1_2_enables);
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void rockchip_pcie_bus_l1ss_enable_dev(char *device, struct pci_dev *dev, bool enable)
|
||||||
|
+{
|
||||||
|
+ u32 l1ssctrl_before;
|
||||||
|
+ u32 l1ssctrl_after = 0;
|
||||||
|
+ u8 l1ss_ep;
|
||||||
|
+
|
||||||
|
+ /* Extendend Capacility Reg */
|
||||||
|
+ l1ssctrl_before = rockchip_pcie_pcie_access_cap(dev, PCI_EXT_CAP_ID_L1SS,
|
||||||
|
+ PCI_L1SS_CTL1, true, false, 0);
|
||||||
|
+ l1ss_ep = (l1ssctrl_before & PCI_L1SS_CTL1_L1SS_MASK);
|
||||||
|
+
|
||||||
|
+ if (enable) {
|
||||||
|
+ if (l1ss_ep == PCI_L1SS_CTL1_L1SS_MASK) {
|
||||||
|
+ pci_err(dev, "%s: %s already enabled, l1ssctrl: 0x%x\n",
|
||||||
|
+ __func__, device, l1ssctrl_before);
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+ rockchip_pcie_pcie_access_cap(dev, PCI_EXT_CAP_ID_L1SS, PCI_L1SS_CTL1,
|
||||||
|
+ true, true, (l1ssctrl_before | PCI_L1SS_CTL1_L1SS_MASK));
|
||||||
|
+ } else {
|
||||||
|
+ if (l1ss_ep == 0) {
|
||||||
|
+ pci_err(dev, "%s: %s already disabled, l1ssctrl: 0x%x\n",
|
||||||
|
+ __func__, device, l1ssctrl_before);
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+ rockchip_pcie_pcie_access_cap(dev, PCI_EXT_CAP_ID_L1SS, PCI_L1SS_CTL1,
|
||||||
|
+ true, true, (l1ssctrl_before & (~PCI_L1SS_CTL1_L1SS_MASK)));
|
||||||
|
+ }
|
||||||
|
+ l1ssctrl_after = rockchip_pcie_pcie_access_cap(dev, PCI_EXT_CAP_ID_L1SS,
|
||||||
|
+ PCI_L1SS_CTL1, true, false, 0);
|
||||||
|
+ pci_err(dev, "%s: %s %s, l1ssctrl_before: 0x%x l1ssctrl_after: 0x%x\n",
|
||||||
|
+ __func__, device, (enable ? "ENABLE " : "DISABLE"),
|
||||||
|
+ l1ssctrl_before, l1ssctrl_after);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+bool pcie_aspm_ext_is_rc_ep_l1ss_capable(struct pci_dev *child, struct pci_dev *parent)
|
||||||
|
+{
|
||||||
|
+ u32 parent_l1ss_cap, child_l1ss_cap;
|
||||||
|
+
|
||||||
|
+ /* Setup L1 substate */
|
||||||
|
+ pci_read_config_dword(parent, parent->l1ss + PCI_L1SS_CAP,
|
||||||
|
+ &parent_l1ss_cap);
|
||||||
|
+ pci_read_config_dword(child, child->l1ss + PCI_L1SS_CAP,
|
||||||
|
+ &child_l1ss_cap);
|
||||||
|
+
|
||||||
|
+ if (!(parent_l1ss_cap & PCI_L1SS_CAP_L1_PM_SS))
|
||||||
|
+ parent_l1ss_cap = 0;
|
||||||
|
+ if (!(child_l1ss_cap & PCI_L1SS_CAP_L1_PM_SS))
|
||||||
|
+ child_l1ss_cap = 0;
|
||||||
|
+
|
||||||
|
+ if (parent_l1ss_cap && child_l1ss_cap)
|
||||||
|
+ return true;
|
||||||
|
+ else
|
||||||
|
+ return false;
|
||||||
|
+}
|
||||||
|
+EXPORT_SYMBOL(pcie_aspm_ext_is_rc_ep_l1ss_capable);
|
||||||
|
+
|
||||||
|
+void pcie_aspm_ext_l1ss_enable(struct pci_dev *child, struct pci_dev *parent, bool enable)
|
||||||
|
+{
|
||||||
|
+ bool ret;
|
||||||
|
+
|
||||||
|
+ /* Disable ASPM of RC and EP */
|
||||||
|
+ ret = rockchip_pcie_bus_aspm_enable_rc_ep(child, parent, false);
|
||||||
|
+
|
||||||
|
+ if (enable) {
|
||||||
|
+ /* Enable RC then EP */
|
||||||
|
+ aspm_calc_l1ss_info(child, parent);
|
||||||
|
+ rockchip_pcie_bus_l1ss_enable_dev("RC", parent, enable);
|
||||||
|
+ rockchip_pcie_bus_l1ss_enable_dev("EP", child, enable);
|
||||||
|
+ } else {
|
||||||
|
+ /* Disable EP then RC */
|
||||||
|
+ rockchip_pcie_bus_l1ss_enable_dev("EP", child, enable);
|
||||||
|
+ rockchip_pcie_bus_l1ss_enable_dev("RC", parent, enable);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /* Enable ASPM of RC and EP only if this API disabled */
|
||||||
|
+ if (ret)
|
||||||
|
+ rockchip_pcie_bus_aspm_enable_rc_ep(child, parent, true);
|
||||||
|
+}
|
||||||
|
+EXPORT_SYMBOL(pcie_aspm_ext_l1ss_enable);
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/include/linux/aspm_ext.h
|
||||||
|
@@ -0,0 +1,16 @@
|
||||||
|
+/* SPDX-License-Identifier: GPL-2.0 */
|
||||||
|
+
|
||||||
|
+/* Copyright (c) 2022 Rockchip Electronics Co., Ltd. */
|
||||||
|
+
|
||||||
|
+#ifndef _ASPM_EXT_H
|
||||||
|
+#define _ASPM_EXT_H
|
||||||
|
+
|
||||||
|
+#if IS_REACHABLE(CONFIG_PCIEASPM_EXT)
|
||||||
|
+bool pcie_aspm_ext_is_rc_ep_l1ss_capable(struct pci_dev *child, struct pci_dev *parent);
|
||||||
|
+void pcie_aspm_ext_l1ss_enable(struct pci_dev *child, struct pci_dev *parent, bool enable);
|
||||||
|
+#else
|
||||||
|
+static inline bool pcie_aspm_ext_is_rc_ep_l1ss_capable(struct pci_dev *child, struct pci_dev *parent) { return false; }
|
||||||
|
+static inline void pcie_aspm_ext_l1ss_enable(struct pci_dev *child, struct pci_dev *parent, bool enable) {}
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
+#endif
|
@ -0,0 +1,24 @@
|
|||||||
|
From a6c71606de486944c5fb028f47604fb22292312b Mon Sep 17 00:00:00 2001
|
||||||
|
From: Jon Lin <jon.lin@rock-chips.com>
|
||||||
|
Date: Fri, 24 Jun 2022 21:32:11 +0800
|
||||||
|
Subject: [PATCH] PCI: aspm_ext: Re-enable LRT for L1SS after power loss
|
||||||
|
|
||||||
|
Change-Id: Iedb72ee74660a8f11f38895e06766c3b77728ba3
|
||||||
|
Signed-off-by: Jon Lin <jon.lin@rock-chips.com>
|
||||||
|
---
|
||||||
|
drivers/pci/pcie/aspm_ext.c | 4 ++++
|
||||||
|
1 file changed, 4 insertions(+)
|
||||||
|
|
||||||
|
--- a/drivers/pci/pcie/aspm_ext.c
|
||||||
|
+++ b/drivers/pci/pcie/aspm_ext.c
|
||||||
|
@@ -322,6 +322,10 @@ void pcie_aspm_ext_l1ss_enable(struct pc
|
||||||
|
ret = rockchip_pcie_bus_aspm_enable_rc_ep(child, parent, false);
|
||||||
|
|
||||||
|
if (enable) {
|
||||||
|
+ /* LRT enable bits loss after wifi off, enable it after power on */
|
||||||
|
+ if (parent->ltr_path)
|
||||||
|
+ pcie_capability_set_word(parent, PCI_EXP_DEVCTL2, PCI_EXP_DEVCTL2_LTR_EN);
|
||||||
|
+
|
||||||
|
/* Enable RC then EP */
|
||||||
|
aspm_calc_l1ss_info(child, parent);
|
||||||
|
rockchip_pcie_bus_l1ss_enable_dev("RC", parent, enable);
|
@ -0,0 +1,38 @@
|
|||||||
|
From cf03561e5ec9f2f8b41a992f3b8ca19b9c3b9e47 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Tao Huang <huangtao@rock-chips.com>
|
||||||
|
Date: Fri, 15 Jul 2022 20:56:15 +0800
|
||||||
|
Subject: [PATCH] PCI: aspm_ext: Fix Add missing MODULE_LICENSE()
|
||||||
|
|
||||||
|
ERROR: modpost: missing MODULE_LICENSE() in drivers/pci/pcie/aspm_ext.o
|
||||||
|
|
||||||
|
Signed-off-by: Tao Huang <huangtao@rock-chips.com>
|
||||||
|
Change-Id: Id365aba7a73f02cc2c61882b46937250e64af01c
|
||||||
|
---
|
||||||
|
drivers/pci/pcie/aspm_ext.c | 5 ++++-
|
||||||
|
1 file changed, 4 insertions(+), 1 deletion(-)
|
||||||
|
|
||||||
|
--- a/drivers/pci/pcie/aspm_ext.c
|
||||||
|
+++ b/drivers/pci/pcie/aspm_ext.c
|
||||||
|
@@ -6,6 +6,7 @@
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
+#include <linux/module.h>
|
||||||
|
#include <linux/pci.h>
|
||||||
|
#include <linux/aspm_ext.h>
|
||||||
|
#include <linux/errno.h>
|
||||||
|
@@ -95,7 +96,7 @@ static bool rockchip_pcie_bus_aspm_enabl
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
-bool rockchip_pcie_bus_aspm_enable_rc_ep(struct pci_dev *child, struct pci_dev *parent, bool enable)
|
||||||
|
+static bool rockchip_pcie_bus_aspm_enable_rc_ep(struct pci_dev *child, struct pci_dev *parent, bool enable)
|
||||||
|
{
|
||||||
|
bool ret;
|
||||||
|
|
||||||
|
@@ -341,3 +342,5 @@ void pcie_aspm_ext_l1ss_enable(struct pc
|
||||||
|
rockchip_pcie_bus_aspm_enable_rc_ep(child, parent, true);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(pcie_aspm_ext_l1ss_enable);
|
||||||
|
+
|
||||||
|
+MODULE_LICENSE("GPL");
|
Loading…
Reference in New Issue
Block a user