From ad9a2b7050e13b91ac9bcd08ee3ed2b426879d92 Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Tue, 19 Nov 2024 09:27:57 +0800 Subject: [PATCH] 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 Change-Id: Ia755f48d11f84f292a4aede38d2653b73f8d11b8 --- drivers/pci/controller/dwc/pcie-dw-rockchip.c | 33 ++++++++++++++++--- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-dw-rockchip.c b/drivers/pci/controller/dwc/pcie-dw-rockchip.c index f4cce281bf39..5b2ca47576de 100644 --- a/drivers/pci/controller/dwc/pcie-dw-rockchip.c +++ b/drivers/pci/controller/dwc/pcie-dw-rockchip.c @@ -21,6 +21,8 @@ #include #include #include +#include +#include #include #include @@ -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; }