Commit f06c6c41 authored by Shawn Lin's avatar Shawn Lin Committed by Bjorn Helgaas

PCI: rockchip: Idle inactive PHY(s)

Check the status of all lanes and idle the inactive one(s).
Tested-by: default avatarJeffy Chen <jeffy.chen@rock-chips.com>
Signed-off-by: default avatarShawn Lin <shawn.lin@rock-chips.com>
[bhelgaas: always set lanes_map, even for legacy_phy case]
Signed-off-by: default avatarBjorn Helgaas <bhelgaas@google.com>
Reviewed-by: default avatarBrian Norris <briannorris@chromium.org>
Acked-by: default avatarKishon Vijay Abraham I <kishon@ti.com>
parent 90a7612d
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
* (at your option) any later version. * (at your option) any later version.
*/ */
#include <linux/bitrev.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/gpio/consumer.h> #include <linux/gpio/consumer.h>
...@@ -112,6 +113,9 @@ ...@@ -112,6 +113,9 @@
#define PCIE_CORE_TXCREDIT_CFG1_MUI_SHIFT 16 #define PCIE_CORE_TXCREDIT_CFG1_MUI_SHIFT 16
#define PCIE_CORE_TXCREDIT_CFG1_MUI_ENCODE(x) \ #define PCIE_CORE_TXCREDIT_CFG1_MUI_ENCODE(x) \
(((x) >> 3) << PCIE_CORE_TXCREDIT_CFG1_MUI_SHIFT) (((x) >> 3) << PCIE_CORE_TXCREDIT_CFG1_MUI_SHIFT)
#define PCIE_CORE_LANE_MAP (PCIE_CORE_CTRL_MGMT_BASE + 0x200)
#define PCIE_CORE_LANE_MAP_MASK 0x0000000f
#define PCIE_CORE_LANE_MAP_REVERSE BIT(16)
#define PCIE_CORE_INT_STATUS (PCIE_CORE_CTRL_MGMT_BASE + 0x20c) #define PCIE_CORE_INT_STATUS (PCIE_CORE_CTRL_MGMT_BASE + 0x20c)
#define PCIE_CORE_INT_PRFPE BIT(0) #define PCIE_CORE_INT_PRFPE BIT(0)
#define PCIE_CORE_INT_CRFPE BIT(1) #define PCIE_CORE_INT_CRFPE BIT(1)
...@@ -230,6 +234,7 @@ struct rockchip_pcie { ...@@ -230,6 +234,7 @@ struct rockchip_pcie {
struct regulator *vpcie0v9; /* 0.9V power supply */ struct regulator *vpcie0v9; /* 0.9V power supply */
struct gpio_desc *ep_gpio; struct gpio_desc *ep_gpio;
u32 lanes; u32 lanes;
u8 lanes_map;
u8 root_bus_nr; u8 root_bus_nr;
int link_gen; int link_gen;
struct device *dev; struct device *dev;
...@@ -302,6 +307,24 @@ static int rockchip_pcie_valid_device(struct rockchip_pcie *rockchip, ...@@ -302,6 +307,24 @@ static int rockchip_pcie_valid_device(struct rockchip_pcie *rockchip,
return 1; return 1;
} }
static u8 rockchip_pcie_lane_map(struct rockchip_pcie *rockchip)
{
u32 val;
u8 map;
if (rockchip->legacy_phy)
return GENMASK(MAX_LANE_NUM - 1, 0);
val = rockchip_pcie_read(rockchip, PCIE_CORE_LANE_MAP);
map = val & PCIE_CORE_LANE_MAP_MASK;
/* The link may be using a reverse-indexed mapping. */
if (val & PCIE_CORE_LANE_MAP_REVERSE)
map = bitrev8(map) >> 4;
return map;
}
static int rockchip_pcie_rd_own_conf(struct rockchip_pcie *rockchip, static int rockchip_pcie_rd_own_conf(struct rockchip_pcie *rockchip,
int where, int size, u32 *val) int where, int size, u32 *val)
{ {
...@@ -698,6 +721,15 @@ static int rockchip_pcie_init_port(struct rockchip_pcie *rockchip) ...@@ -698,6 +721,15 @@ static int rockchip_pcie_init_port(struct rockchip_pcie *rockchip)
PCIE_CORE_PL_CONF_LANE_SHIFT); PCIE_CORE_PL_CONF_LANE_SHIFT);
dev_dbg(dev, "current link width is x%d\n", status); dev_dbg(dev, "current link width is x%d\n", status);
/* Power off unused lane(s) */
rockchip->lanes_map = rockchip_pcie_lane_map(rockchip);
for (i = 0; i < MAX_LANE_NUM; i++) {
if (!(rockchip->lanes_map & BIT(i))) {
dev_dbg(dev, "idling lane %d\n", i);
phy_power_off(rockchip->phys[i]);
}
}
rockchip_pcie_write(rockchip, ROCKCHIP_VENDOR_ID, rockchip_pcie_write(rockchip, ROCKCHIP_VENDOR_ID,
PCIE_CORE_CONFIG_VENDOR); PCIE_CORE_CONFIG_VENDOR);
rockchip_pcie_write(rockchip, rockchip_pcie_write(rockchip,
...@@ -1349,7 +1381,9 @@ static int __maybe_unused rockchip_pcie_suspend_noirq(struct device *dev) ...@@ -1349,7 +1381,9 @@ static int __maybe_unused rockchip_pcie_suspend_noirq(struct device *dev)
} }
for (i = 0; i < MAX_LANE_NUM; i++) { for (i = 0; i < MAX_LANE_NUM; i++) {
phy_power_off(rockchip->phys[i]); /* inactive lanes are already powered off */
if (rockchip->lanes_map & BIT(i))
phy_power_off(rockchip->phys[i]);
phy_exit(rockchip->phys[i]); phy_exit(rockchip->phys[i]);
} }
...@@ -1597,7 +1631,9 @@ static int rockchip_pcie_remove(struct platform_device *pdev) ...@@ -1597,7 +1631,9 @@ static int rockchip_pcie_remove(struct platform_device *pdev)
irq_domain_remove(rockchip->irq_domain); irq_domain_remove(rockchip->irq_domain);
for (i = 0; i < MAX_LANE_NUM; i++) { for (i = 0; i < MAX_LANE_NUM; i++) {
phy_power_off(rockchip->phys[i]); /* inactive lanes are already powered off */
if (rockchip->lanes_map & BIT(i))
phy_power_off(rockchip->phys[i]);
phy_exit(rockchip->phys[i]); phy_exit(rockchip->phys[i]);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment