PCI: dw: rockchip: Add rockchip,keep-power-in-suspend support

This property is used to prevent RC from calling devices to enter
D3cold if they need to keep working when system is suspended. The classic
user is wireless device and computing cards which need to work standalone
when system is suspened. Currently wireless devices deal with it by
controlling power and #PERST by themselves because they have rfkill driver
which could did it in front of the wireless driver. But computing cards couldn't.

In ACPI point of view, we could allow users to configure the D3Cold state for
each PCI device through the sysfs attribute 'sys/bus/pci/devices.../d3cold_allowed'.
Then the PCIe driver and firmware could work together to meet the requirement. But
in DT way, we have to invent a new property to cover both of these.

Signed-off-by: Shawn Lin <shawn.lin@rock-chips.com>
Change-Id: Ia755f48d11f84f292a4aede38d2653b73f8d11b8
This commit is contained in:
Shawn Lin
2024-11-19 09:27:57 +08:00
committed by Tao Huang
parent 3debfe232c
commit ad9a2b7050

View File

@@ -21,6 +21,8 @@
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <linux/reset.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/rfkill-wlan.h>
#include <linux/aspm_ext.h>
@@ -29,6 +31,7 @@
#include "../rockchip-pcie-dma.h"
#include "pcie-dw-dmatest.h"
#include "../../hotplug/gpiophp.h"
#include "../../../regulator/internal.h"
#define RK_PCIE_DBG 0
@@ -142,6 +145,7 @@ struct rk_pcie {
bool is_lpbk;
bool is_comp;
bool finish_probe;
bool keep_power_in_suspend;
struct regulator *vpcie3v3;
struct irq_domain *irq_domain;
raw_spinlock_t intx_lock;
@@ -341,6 +345,12 @@ static void rk_pcie_retrain(struct dw_pcie *pci)
}
}
static bool rk_pcie_check_keep_power_in_suspend(struct rk_pcie *rk_pcie)
{
return (!rk_pcie->in_suspend ||
(rk_pcie->in_suspend && !rk_pcie->keep_power_in_suspend));
}
static int rk_pcie_establish_link(struct dw_pcie *pci)
{
int retries, power;
@@ -772,6 +782,15 @@ retry_regulator:
return PTR_ERR(rk_pcie->phy);
}
rk_pcie->keep_power_in_suspend = device_property_present(&pdev->dev,
"rockchip,keep-power-in-suspend");
if (rk_pcie->keep_power_in_suspend) {
if (IS_ERR(rk_pcie->vpcie3v3))
dev_warn(&pdev->dev, "keep power in suspend need vpcie3v3\n");
else
regulator_suspend_enable(rk_pcie->vpcie3v3->rdev, PM_SUSPEND_MEM);
}
return 0;
}
@@ -1444,9 +1463,11 @@ static int rk_pcie_hardware_io_config(struct rk_pcie *rk_pcie)
}
}
ret = rk_pcie_enable_power(rk_pcie);
if (ret)
return ret;
if (rk_pcie_check_keep_power_in_suspend(rk_pcie)) {
ret = rk_pcie_enable_power(rk_pcie);
if (ret)
return ret;
}
reset_control_assert(rk_pcie->rsts);
udelay(10);
@@ -1502,8 +1523,10 @@ static int rk_pcie_hardware_io_unconfig(struct rk_pcie *rk_pcie)
phy_exit(rk_pcie->phy);
clk_bulk_disable_unprepare(rk_pcie->clk_cnt, rk_pcie->clks);
reset_control_assert(rk_pcie->rsts);
rk_pcie_disable_power(rk_pcie);
gpiod_set_value_cansleep(rk_pcie->rst_gpio, 0);
if (rk_pcie_check_keep_power_in_suspend(rk_pcie)) {
rk_pcie_disable_power(rk_pcie);
gpiod_set_value_cansleep(rk_pcie->rst_gpio, 0);
}
return 0;
}