From b6502e0dcf7077bd05664ddfc7e30cce49bc0b0d Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Thu, 29 Jun 2017 09:22:23 +0800 Subject: PCI: rockchip: Control optional 12v power supply Get vpcie12v from DT and control it if available. Signed-off-by: Shawn Lin Signed-off-by: Bjorn Helgaas --- drivers/pci/host/pcie-rockchip.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) (limited to 'drivers/pci') diff --git a/drivers/pci/host/pcie-rockchip.c b/drivers/pci/host/pcie-rockchip.c index 7bb9870f6d8c..80b9a8814768 100644 --- a/drivers/pci/host/pcie-rockchip.c +++ b/drivers/pci/host/pcie-rockchip.c @@ -222,6 +222,7 @@ struct rockchip_pcie { struct clk *aclk_perf_pcie; struct clk *hclk_pcie; struct clk *clk_pcie_pm; + struct regulator *vpcie12v; /* 12V power supply */ struct regulator *vpcie3v3; /* 3.3V power supply */ struct regulator *vpcie1v8; /* 1.8V power supply */ struct regulator *vpcie0v9; /* 0.9V power supply */ @@ -1018,6 +1019,13 @@ static int rockchip_pcie_parse_dt(struct rockchip_pcie *rockchip) return err; } + rockchip->vpcie12v = devm_regulator_get_optional(dev, "vpcie12v"); + if (IS_ERR(rockchip->vpcie12v)) { + if (PTR_ERR(rockchip->vpcie12v) == -EPROBE_DEFER) + return -EPROBE_DEFER; + dev_info(dev, "no vpcie12v regulator found\n"); + } + rockchip->vpcie3v3 = devm_regulator_get_optional(dev, "vpcie3v3"); if (IS_ERR(rockchip->vpcie3v3)) { if (PTR_ERR(rockchip->vpcie3v3) == -EPROBE_DEFER) @@ -1047,11 +1055,19 @@ static int rockchip_pcie_set_vpcie(struct rockchip_pcie *rockchip) struct device *dev = rockchip->dev; int err; + if (!IS_ERR(rockchip->vpcie12v)) { + err = regulator_enable(rockchip->vpcie12v); + if (err) { + dev_err(dev, "fail to enable vpcie12v regulator\n"); + goto err_out; + } + } + if (!IS_ERR(rockchip->vpcie3v3)) { err = regulator_enable(rockchip->vpcie3v3); if (err) { dev_err(dev, "fail to enable vpcie3v3 regulator\n"); - goto err_out; + goto err_disable_12v; } } @@ -1079,6 +1095,9 @@ err_disable_1v8: err_disable_3v3: if (!IS_ERR(rockchip->vpcie3v3)) regulator_disable(rockchip->vpcie3v3); +err_disable_12v: + if (!IS_ERR(rockchip->vpcie12v)) + regulator_disable(rockchip->vpcie12v); err_out: return err; } @@ -1501,6 +1520,8 @@ static int rockchip_pcie_probe(struct platform_device *pdev) err_free_res: pci_free_resource_list(&res); err_vpcie: + if (!IS_ERR(rockchip->vpcie12v)) + regulator_disable(rockchip->vpcie12v); if (!IS_ERR(rockchip->vpcie3v3)) regulator_disable(rockchip->vpcie3v3); if (!IS_ERR(rockchip->vpcie1v8)) @@ -1537,6 +1558,8 @@ static int rockchip_pcie_remove(struct platform_device *pdev) clk_disable_unprepare(rockchip->aclk_perf_pcie); clk_disable_unprepare(rockchip->aclk_pcie); + if (!IS_ERR(rockchip->vpcie12v)) + regulator_disable(rockchip->vpcie12v); if (!IS_ERR(rockchip->vpcie3v3)) regulator_disable(rockchip->vpcie3v3); if (!IS_ERR(rockchip->vpcie1v8)) -- cgit v1.2.3 From 2ba5991f340b28fe467333740a01a17412ba63dc Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Wed, 19 Jul 2017 17:55:12 +0800 Subject: PCI: rockchip: Factor out rockchip_pcie_get_phys() We plan to introduce per-lane PHYs, so factor out rockchip_pcie_get_phys() to make it easier in the future. No functional change intended. Tested-by: Jeffy Chen Signed-off-by: Shawn Lin Signed-off-by: Bjorn Helgaas Reviewed-by: Brian Norris Acked-by: Kishon Vijay Abraham I --- drivers/pci/host/pcie-rockchip.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/host/pcie-rockchip.c b/drivers/pci/host/pcie-rockchip.c index 80b9a8814768..35d6f59a0a70 100644 --- a/drivers/pci/host/pcie-rockchip.c +++ b/drivers/pci/host/pcie-rockchip.c @@ -854,6 +854,19 @@ static void rockchip_pcie_legacy_int_handler(struct irq_desc *desc) chained_irq_exit(chip, desc); } +static int rockchip_pcie_get_phys(struct rockchip_pcie *rockchip) +{ + struct device *dev = rockchip->dev; + + rockchip->phy = devm_phy_get(dev, "pcie-phy"); + if (IS_ERR(rockchip->phy)) { + if (PTR_ERR(rockchip->phy) != -EPROBE_DEFER) + dev_err(dev, "missing phy\n"); + return PTR_ERR(rockchip->phy); + } + + return 0; +} /** * rockchip_pcie_parse_dt - Parse Device Tree @@ -884,12 +897,9 @@ static int rockchip_pcie_parse_dt(struct rockchip_pcie *rockchip) if (IS_ERR(rockchip->apb_base)) return PTR_ERR(rockchip->apb_base); - rockchip->phy = devm_phy_get(dev, "pcie-phy"); - if (IS_ERR(rockchip->phy)) { - if (PTR_ERR(rockchip->phy) != -EPROBE_DEFER) - dev_err(dev, "missing phy\n"); - return PTR_ERR(rockchip->phy); - } + err = rockchip_pcie_get_phys(rockchip); + if (err) + return err; rockchip->lanes = 1; err = of_property_read_u32(node, "num-lanes", &rockchip->lanes); -- cgit v1.2.3 From 9e87240c460637620d9b4b8c6475a53b48267dc6 Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Fri, 25 Aug 2017 15:59:01 -0500 Subject: PCI: rockchip: Add per-lane PHY support We distinguish the legacy PHY from newer per-lane PHYs by adding legacy_phy flag. Note that the legacy PHY is still the first option to be searched in order not to break the backward compatibility of DTB. Tested-by: Jeffy Chen Signed-off-by: Shawn Lin [bhelgaas: tidy rockchip_pcie_get_phys()] Signed-off-by: Bjorn Helgaas Reviewed-by: Brian Norris Acked-by: Kishon Vijay Abraham I --- drivers/pci/host/pcie-rockchip.c | 78 +++++++++++++++++++++++++++++----------- 1 file changed, 58 insertions(+), 20 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/host/pcie-rockchip.c b/drivers/pci/host/pcie-rockchip.c index 35d6f59a0a70..5ccbdbfa97d0 100644 --- a/drivers/pci/host/pcie-rockchip.c +++ b/drivers/pci/host/pcie-rockchip.c @@ -47,6 +47,7 @@ #define HIWORD_UPDATE_BIT(val) HIWORD_UPDATE(val, val) #define ENCODE_LANES(x) ((((x) >> 1) & 3) << 4) +#define MAX_LANE_NUM 4 #define PCIE_CLIENT_BASE 0x0 #define PCIE_CLIENT_CONFIG (PCIE_CLIENT_BASE + 0x00) @@ -210,7 +211,8 @@ struct rockchip_pcie { void __iomem *reg_base; /* DT axi-base */ void __iomem *apb_base; /* DT apb-base */ - struct phy *phy; + bool legacy_phy; + struct phy *phys[MAX_LANE_NUM]; struct reset_control *core_rst; struct reset_control *mgmt_rst; struct reset_control *mgmt_sticky_rst; @@ -515,7 +517,7 @@ static void rockchip_pcie_set_power_limit(struct rockchip_pcie *rockchip) static int rockchip_pcie_init_port(struct rockchip_pcie *rockchip) { struct device *dev = rockchip->dev; - int err; + int err, i; u32 status; gpiod_set_value(rockchip->ep_gpio, 0); @@ -538,10 +540,12 @@ static int rockchip_pcie_init_port(struct rockchip_pcie *rockchip) return err; } - err = phy_init(rockchip->phy); - if (err < 0) { - dev_err(dev, "fail to init phy, err %d\n", err); - return err; + for (i = 0; i < MAX_LANE_NUM; i++) { + err = phy_init(rockchip->phys[i]); + if (err) { + dev_err(dev, "init phy%d err %d\n", i, err); + return err; + } } err = reset_control_assert(rockchip->core_rst); @@ -603,10 +607,12 @@ static int rockchip_pcie_init_port(struct rockchip_pcie *rockchip) PCIE_CLIENT_MODE_RC, PCIE_CLIENT_CONFIG); - err = phy_power_on(rockchip->phy); - if (err) { - dev_err(dev, "fail to power on phy, err %d\n", err); - return err; + for (i = 0; i < MAX_LANE_NUM; i++) { + err = phy_power_on(rockchip->phys[i]); + if (err) { + dev_err(dev, "power on phy%d err %d\n", i, err); + return err; + } } /* @@ -857,12 +863,39 @@ static void rockchip_pcie_legacy_int_handler(struct irq_desc *desc) static int rockchip_pcie_get_phys(struct rockchip_pcie *rockchip) { struct device *dev = rockchip->dev; + struct phy *phy; + char *name; + u32 i; + + phy = devm_phy_get(dev, "pcie-phy"); + if (!IS_ERR(phy)) { + rockchip->legacy_phy = true; + rockchip->phys[0] = phy; + dev_warn(dev, "legacy phy model is deprecated!\n"); + return 0; + } + + if (PTR_ERR(phy) == -EPROBE_DEFER) + return PTR_ERR(phy); + + dev_dbg(dev, "missing legacy phy; search for per-lane PHY\n"); + + for (i = 0; i < MAX_LANE_NUM; i++) { + name = kasprintf(GFP_KERNEL, "pcie-phy-%u", i); + if (!name) + return -ENOMEM; - rockchip->phy = devm_phy_get(dev, "pcie-phy"); - if (IS_ERR(rockchip->phy)) { - if (PTR_ERR(rockchip->phy) != -EPROBE_DEFER) - dev_err(dev, "missing phy\n"); - return PTR_ERR(rockchip->phy); + phy = devm_of_phy_get(dev, dev->of_node, name); + kfree(name); + + if (IS_ERR(phy)) { + if (PTR_ERR(phy) != -EPROBE_DEFER) + dev_err(dev, "missing phy for lane %d: %ld\n", + i, PTR_ERR(phy)); + return PTR_ERR(phy); + } + + rockchip->phys[i] = phy; } return 0; @@ -1302,7 +1335,7 @@ static int rockchip_pcie_wait_l2(struct rockchip_pcie *rockchip) static int __maybe_unused rockchip_pcie_suspend_noirq(struct device *dev) { struct rockchip_pcie *rockchip = dev_get_drvdata(dev); - int ret; + int ret, i; /* disable core and cli int since we don't need to ack PME_ACK */ rockchip_pcie_write(rockchip, (PCIE_CLIENT_INT_CLI << 16) | @@ -1315,8 +1348,10 @@ static int __maybe_unused rockchip_pcie_suspend_noirq(struct device *dev) return ret; } - phy_power_off(rockchip->phy); - phy_exit(rockchip->phy); + for (i = 0; i < MAX_LANE_NUM; i++) { + phy_power_off(rockchip->phys[i]); + phy_exit(rockchip->phys[i]); + } clk_disable_unprepare(rockchip->clk_pcie_pm); clk_disable_unprepare(rockchip->hclk_pcie); @@ -1554,14 +1589,17 @@ static int rockchip_pcie_remove(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct rockchip_pcie *rockchip = dev_get_drvdata(dev); + int i; pci_stop_root_bus(rockchip->root_bus); pci_remove_root_bus(rockchip->root_bus); pci_unmap_iospace(rockchip->io); irq_domain_remove(rockchip->irq_domain); - phy_power_off(rockchip->phy); - phy_exit(rockchip->phy); + for (i = 0; i < MAX_LANE_NUM; i++) { + phy_power_off(rockchip->phys[i]); + phy_exit(rockchip->phys[i]); + } clk_disable_unprepare(rockchip->clk_pcie_pm); clk_disable_unprepare(rockchip->hclk_pcie); -- cgit v1.2.3 From f06c6c41e6ccf9c1ec61f640cc9090308b8a63fd Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Wed, 19 Jul 2017 17:55:15 +0800 Subject: PCI: rockchip: Idle inactive PHY(s) Check the status of all lanes and idle the inactive one(s). Tested-by: Jeffy Chen Signed-off-by: Shawn Lin [bhelgaas: always set lanes_map, even for legacy_phy case] Signed-off-by: Bjorn Helgaas Reviewed-by: Brian Norris Acked-by: Kishon Vijay Abraham I --- drivers/pci/host/pcie-rockchip.c | 40 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/host/pcie-rockchip.c b/drivers/pci/host/pcie-rockchip.c index 5ccbdbfa97d0..168505777533 100644 --- a/drivers/pci/host/pcie-rockchip.c +++ b/drivers/pci/host/pcie-rockchip.c @@ -15,6 +15,7 @@ * (at your option) any later version. */ +#include #include #include #include @@ -112,6 +113,9 @@ #define PCIE_CORE_TXCREDIT_CFG1_MUI_SHIFT 16 #define PCIE_CORE_TXCREDIT_CFG1_MUI_ENCODE(x) \ (((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_PRFPE BIT(0) #define PCIE_CORE_INT_CRFPE BIT(1) @@ -230,6 +234,7 @@ struct rockchip_pcie { struct regulator *vpcie0v9; /* 0.9V power supply */ struct gpio_desc *ep_gpio; u32 lanes; + u8 lanes_map; u8 root_bus_nr; int link_gen; struct device *dev; @@ -302,6 +307,24 @@ static int rockchip_pcie_valid_device(struct rockchip_pcie *rockchip, 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, int where, int size, u32 *val) { @@ -698,6 +721,15 @@ static int rockchip_pcie_init_port(struct rockchip_pcie *rockchip) PCIE_CORE_PL_CONF_LANE_SHIFT); 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, PCIE_CORE_CONFIG_VENDOR); rockchip_pcie_write(rockchip, @@ -1349,7 +1381,9 @@ static int __maybe_unused rockchip_pcie_suspend_noirq(struct device *dev) } 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]); } @@ -1597,7 +1631,9 @@ static int rockchip_pcie_remove(struct platform_device *pdev) irq_domain_remove(rockchip->irq_domain); 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]); } -- cgit v1.2.3 From 18aca19722aa8a80a5dabb01dfc24bb146d3f1f6 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Wed, 19 Jul 2017 17:25:58 +0200 Subject: PCI: rockchip: Explicitly request exclusive reset control Commit a53e35db70d1 ("reset: Ensure drivers are explicit when requesting reset lines") started to transition the reset control request API calls to explicitly state whether the driver needs exclusive or shared reset control behavior. Convert all drivers requesting exclusive resets to the explicit API call so the temporary transition helpers can be removed. No functional changes. Signed-off-by: Philipp Zabel Signed-off-by: Bjorn Helgaas Acked-by: Shawn Lin --- drivers/pci/host/pcie-rockchip.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/host/pcie-rockchip.c b/drivers/pci/host/pcie-rockchip.c index 168505777533..9c631e5adde0 100644 --- a/drivers/pci/host/pcie-rockchip.c +++ b/drivers/pci/host/pcie-rockchip.c @@ -979,49 +979,50 @@ static int rockchip_pcie_parse_dt(struct rockchip_pcie *rockchip) if (rockchip->link_gen < 0 || rockchip->link_gen > 2) rockchip->link_gen = 2; - rockchip->core_rst = devm_reset_control_get(dev, "core"); + rockchip->core_rst = devm_reset_control_get_exclusive(dev, "core"); if (IS_ERR(rockchip->core_rst)) { if (PTR_ERR(rockchip->core_rst) != -EPROBE_DEFER) dev_err(dev, "missing core reset property in node\n"); return PTR_ERR(rockchip->core_rst); } - rockchip->mgmt_rst = devm_reset_control_get(dev, "mgmt"); + rockchip->mgmt_rst = devm_reset_control_get_exclusive(dev, "mgmt"); if (IS_ERR(rockchip->mgmt_rst)) { if (PTR_ERR(rockchip->mgmt_rst) != -EPROBE_DEFER) dev_err(dev, "missing mgmt reset property in node\n"); return PTR_ERR(rockchip->mgmt_rst); } - rockchip->mgmt_sticky_rst = devm_reset_control_get(dev, "mgmt-sticky"); + rockchip->mgmt_sticky_rst = devm_reset_control_get_exclusive(dev, + "mgmt-sticky"); if (IS_ERR(rockchip->mgmt_sticky_rst)) { if (PTR_ERR(rockchip->mgmt_sticky_rst) != -EPROBE_DEFER) dev_err(dev, "missing mgmt-sticky reset property in node\n"); return PTR_ERR(rockchip->mgmt_sticky_rst); } - rockchip->pipe_rst = devm_reset_control_get(dev, "pipe"); + rockchip->pipe_rst = devm_reset_control_get_exclusive(dev, "pipe"); if (IS_ERR(rockchip->pipe_rst)) { if (PTR_ERR(rockchip->pipe_rst) != -EPROBE_DEFER) dev_err(dev, "missing pipe reset property in node\n"); return PTR_ERR(rockchip->pipe_rst); } - rockchip->pm_rst = devm_reset_control_get(dev, "pm"); + rockchip->pm_rst = devm_reset_control_get_exclusive(dev, "pm"); if (IS_ERR(rockchip->pm_rst)) { if (PTR_ERR(rockchip->pm_rst) != -EPROBE_DEFER) dev_err(dev, "missing pm reset property in node\n"); return PTR_ERR(rockchip->pm_rst); } - rockchip->pclk_rst = devm_reset_control_get(dev, "pclk"); + rockchip->pclk_rst = devm_reset_control_get_exclusive(dev, "pclk"); if (IS_ERR(rockchip->pclk_rst)) { if (PTR_ERR(rockchip->pclk_rst) != -EPROBE_DEFER) dev_err(dev, "missing pclk reset property in node\n"); return PTR_ERR(rockchip->pclk_rst); } - rockchip->aclk_rst = devm_reset_control_get(dev, "aclk"); + rockchip->aclk_rst = devm_reset_control_get_exclusive(dev, "aclk"); if (IS_ERR(rockchip->aclk_rst)) { if (PTR_ERR(rockchip->aclk_rst) != -EPROBE_DEFER) dev_err(dev, "missing aclk reset property in node\n"); -- cgit v1.2.3 From 62f9ee98e14521166954e1e0d9fc1ee4ff2a5615 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Tue, 15 Aug 2017 16:27:29 -0500 Subject: PCI: rockchip: Use PCI_NUM_INTX Use the PCI_NUM_INTX macro to indicate the number of PCI INTx interrupts rather than the magic number 4. This makes it clearer where the number comes from & what it relates to. Signed-off-by: Paul Burton Signed-off-by: Bjorn Helgaas Cc: Heiko Stuebner Cc: Shawn Lin --- drivers/pci/host/pcie-rockchip.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/pci') diff --git a/drivers/pci/host/pcie-rockchip.c b/drivers/pci/host/pcie-rockchip.c index 9c631e5adde0..9ed784360d31 100644 --- a/drivers/pci/host/pcie-rockchip.c +++ b/drivers/pci/host/pcie-rockchip.c @@ -1211,7 +1211,7 @@ static int rockchip_pcie_init_irq_domain(struct rockchip_pcie *rockchip) return -EINVAL; } - rockchip->irq_domain = irq_domain_add_linear(intc, 4, + rockchip->irq_domain = irq_domain_add_linear(intc, PCI_NUM_INTX, &intx_domain_ops, rockchip); if (!rockchip->irq_domain) { dev_err(dev, "failed to get a INTx IRQ domain\n"); -- cgit v1.2.3 From bf2b3312edf182518577d1a28636bd4e9ae00858 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Sun, 27 Aug 2017 21:25:57 -0300 Subject: PCI: rockchip: Use gpiod_set_value_cansleep() to allow reset via expanders The reset GPIO can be connected to a I2C or SPI IO expander, which may sleep, so it is safer to use the gpiod_set_value_cansleep() variant instead. Signed-off-by: Fabio Estevam Signed-off-by: Bjorn Helgaas Acked-by: Shawn Lin --- drivers/pci/host/pcie-rockchip.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/host/pcie-rockchip.c b/drivers/pci/host/pcie-rockchip.c index 9ed784360d31..c10b8987d7b3 100644 --- a/drivers/pci/host/pcie-rockchip.c +++ b/drivers/pci/host/pcie-rockchip.c @@ -543,7 +543,7 @@ static int rockchip_pcie_init_port(struct rockchip_pcie *rockchip) int err, i; u32 status; - gpiod_set_value(rockchip->ep_gpio, 0); + gpiod_set_value_cansleep(rockchip->ep_gpio, 0); err = reset_control_assert(rockchip->aclk_rst); if (err) { @@ -688,7 +688,7 @@ static int rockchip_pcie_init_port(struct rockchip_pcie *rockchip) rockchip_pcie_write(rockchip, PCIE_CLIENT_LINK_TRAIN_ENABLE, PCIE_CLIENT_CONFIG); - gpiod_set_value(rockchip->ep_gpio, 1); + gpiod_set_value_cansleep(rockchip->ep_gpio, 1); /* 500ms timeout value should be enough for Gen1/2 training */ err = readl_poll_timeout(rockchip->apb_base + PCIE_CLIENT_BASIC_STATUS1, -- cgit v1.2.3 From 6341f8052ea41c8fa9e28bb2f12864b90f470360 Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Wed, 23 Aug 2017 15:02:05 +0800 Subject: PCI: rockchip: Factor out rockchip_pcie_setup_irq() Factor out rockchip_pcie_setup_irq() to prepare for future bug fixes. No functional change intended. Signed-off-by: Shawn Lin Signed-off-by: Bjorn Helgaas --- drivers/pci/host/pcie-rockchip.c | 82 +++++++++++++++++++++++----------------- 1 file changed, 47 insertions(+), 35 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/host/pcie-rockchip.c b/drivers/pci/host/pcie-rockchip.c index c10b8987d7b3..fcb96a3494c2 100644 --- a/drivers/pci/host/pcie-rockchip.c +++ b/drivers/pci/host/pcie-rockchip.c @@ -933,6 +933,51 @@ static int rockchip_pcie_get_phys(struct rockchip_pcie *rockchip) return 0; } +static int rockchip_pcie_setup_irq(struct rockchip_pcie *rockchip) +{ + int irq, err; + struct device *dev = rockchip->dev; + struct platform_device *pdev = to_platform_device(dev); + + irq = platform_get_irq_byname(pdev, "sys"); + if (irq < 0) { + dev_err(dev, "missing sys IRQ resource\n"); + return -EINVAL; + } + + err = devm_request_irq(dev, irq, rockchip_pcie_subsys_irq_handler, + IRQF_SHARED, "pcie-sys", rockchip); + if (err) { + dev_err(dev, "failed to request PCIe subsystem IRQ\n"); + return err; + } + + irq = platform_get_irq_byname(pdev, "legacy"); + if (irq < 0) { + dev_err(dev, "missing legacy IRQ resource\n"); + return -EINVAL; + } + + irq_set_chained_handler_and_data(irq, + rockchip_pcie_legacy_int_handler, + rockchip); + + irq = platform_get_irq_byname(pdev, "client"); + if (irq < 0) { + dev_err(dev, "missing client IRQ resource\n"); + return -EINVAL; + } + + err = devm_request_irq(dev, irq, rockchip_pcie_client_irq_handler, + IRQF_SHARED, "pcie-client", rockchip); + if (err) { + dev_err(dev, "failed to request PCIe client IRQ\n"); + return err; + } + + return 0; +} + /** * rockchip_pcie_parse_dt - Parse Device Tree * @rockchip: PCIe port information @@ -945,7 +990,6 @@ static int rockchip_pcie_parse_dt(struct rockchip_pcie *rockchip) struct platform_device *pdev = to_platform_device(dev); struct device_node *node = dev->of_node; struct resource *regs; - int irq; int err; regs = platform_get_resource_byname(pdev, @@ -1059,41 +1103,9 @@ static int rockchip_pcie_parse_dt(struct rockchip_pcie *rockchip) return PTR_ERR(rockchip->clk_pcie_pm); } - irq = platform_get_irq_byname(pdev, "sys"); - if (irq < 0) { - dev_err(dev, "missing sys IRQ resource\n"); - return -EINVAL; - } - - err = devm_request_irq(dev, irq, rockchip_pcie_subsys_irq_handler, - IRQF_SHARED, "pcie-sys", rockchip); - if (err) { - dev_err(dev, "failed to request PCIe subsystem IRQ\n"); - return err; - } - - irq = platform_get_irq_byname(pdev, "legacy"); - if (irq < 0) { - dev_err(dev, "missing legacy IRQ resource\n"); - return -EINVAL; - } - - irq_set_chained_handler_and_data(irq, - rockchip_pcie_legacy_int_handler, - rockchip); - - irq = platform_get_irq_byname(pdev, "client"); - if (irq < 0) { - dev_err(dev, "missing client IRQ resource\n"); - return -EINVAL; - } - - err = devm_request_irq(dev, irq, rockchip_pcie_client_irq_handler, - IRQF_SHARED, "pcie-client", rockchip); - if (err) { - dev_err(dev, "failed to request PCIe client IRQ\n"); + err = rockchip_pcie_setup_irq(rockchip); + if (err) return err; - } rockchip->vpcie12v = devm_regulator_get_optional(dev, "vpcie12v"); if (IS_ERR(rockchip->vpcie12v)) { -- cgit v1.2.3 From 09df7bc40a15823e1b3e30135fc0f22eb97a0abb Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Wed, 23 Aug 2017 15:02:19 +0800 Subject: PCI: rockchip: Factor out rockchip_pcie_enable_clocks() Factor out rockchip_pcie_enable_clocks() so it can be reused by rockchip_pcie_resume_noirq() and rockchip_pcie_probe(). No functional change intended, but it does change the order of unpreparing clocks in the rockchip_pcie_resume_noirq() error path. Signed-off-by: Shawn Lin Signed-off-by: Bjorn Helgaas --- drivers/pci/host/pcie-rockchip.c | 90 ++++++++++++++++++++-------------------- 1 file changed, 45 insertions(+), 45 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/host/pcie-rockchip.c b/drivers/pci/host/pcie-rockchip.c index fcb96a3494c2..3b1802c39adc 100644 --- a/drivers/pci/host/pcie-rockchip.c +++ b/drivers/pci/host/pcie-rockchip.c @@ -1377,6 +1377,46 @@ static int rockchip_pcie_wait_l2(struct rockchip_pcie *rockchip) return 0; } +static int rockchip_pcie_enable_clocks(struct rockchip_pcie *rockchip) +{ + struct device *dev = rockchip->dev; + int err; + + err = clk_prepare_enable(rockchip->aclk_pcie); + if (err) { + dev_err(dev, "unable to enable aclk_pcie clock\n"); + return err; + } + + err = clk_prepare_enable(rockchip->aclk_perf_pcie); + if (err) { + dev_err(dev, "unable to enable aclk_perf_pcie clock\n"); + goto err_aclk_perf_pcie; + } + + err = clk_prepare_enable(rockchip->hclk_pcie); + if (err) { + dev_err(dev, "unable to enable hclk_pcie clock\n"); + goto err_hclk_pcie; + } + + err = clk_prepare_enable(rockchip->clk_pcie_pm); + if (err) { + dev_err(dev, "unable to enable clk_pcie_pm clock\n"); + goto err_clk_pcie_pm; + } + + return 0; + +err_clk_pcie_pm: + clk_disable_unprepare(rockchip->hclk_pcie); +err_hclk_pcie: + clk_disable_unprepare(rockchip->aclk_perf_pcie); +err_aclk_perf_pcie: + clk_disable_unprepare(rockchip->aclk_pcie); + return err; +} + static int __maybe_unused rockchip_pcie_suspend_noirq(struct device *dev) { struct rockchip_pcie *rockchip = dev_get_drvdata(dev); @@ -1424,21 +1464,9 @@ static int __maybe_unused rockchip_pcie_resume_noirq(struct device *dev) } } - err = clk_prepare_enable(rockchip->clk_pcie_pm); - if (err) - goto err_pcie_pm; - - err = clk_prepare_enable(rockchip->hclk_pcie); - if (err) - goto err_hclk_pcie; - - err = clk_prepare_enable(rockchip->aclk_perf_pcie); - if (err) - goto err_aclk_perf_pcie; - - err = clk_prepare_enable(rockchip->aclk_pcie); + err = rockchip_pcie_enable_clocks(rockchip); if (err) - goto err_aclk_pcie; + return err; err = rockchip_pcie_init_port(rockchip); if (err) @@ -1456,13 +1484,9 @@ static int __maybe_unused rockchip_pcie_resume_noirq(struct device *dev) err_pcie_resume: clk_disable_unprepare(rockchip->aclk_pcie); -err_aclk_pcie: clk_disable_unprepare(rockchip->aclk_perf_pcie); -err_aclk_perf_pcie: clk_disable_unprepare(rockchip->hclk_pcie); -err_hclk_pcie: clk_disable_unprepare(rockchip->clk_pcie_pm); -err_pcie_pm: return err; } @@ -1496,29 +1520,9 @@ static int rockchip_pcie_probe(struct platform_device *pdev) if (err) return err; - err = clk_prepare_enable(rockchip->aclk_pcie); - if (err) { - dev_err(dev, "unable to enable aclk_pcie clock\n"); - goto err_aclk_pcie; - } - - err = clk_prepare_enable(rockchip->aclk_perf_pcie); - if (err) { - dev_err(dev, "unable to enable aclk_perf_pcie clock\n"); - goto err_aclk_perf_pcie; - } - - err = clk_prepare_enable(rockchip->hclk_pcie); - if (err) { - dev_err(dev, "unable to enable hclk_pcie clock\n"); - goto err_hclk_pcie; - } - - err = clk_prepare_enable(rockchip->clk_pcie_pm); - if (err) { - dev_err(dev, "unable to enable hclk_pcie clock\n"); - goto err_pcie_pm; - } + err = rockchip_pcie_enable_clocks(rockchip); + if (err) + return err; err = rockchip_pcie_set_vpcie(rockchip); if (err) { @@ -1622,13 +1626,9 @@ err_vpcie: regulator_disable(rockchip->vpcie0v9); err_set_vpcie: clk_disable_unprepare(rockchip->clk_pcie_pm); -err_pcie_pm: clk_disable_unprepare(rockchip->hclk_pcie); -err_hclk_pcie: clk_disable_unprepare(rockchip->aclk_perf_pcie); -err_aclk_perf_pcie: clk_disable_unprepare(rockchip->aclk_pcie); -err_aclk_pcie: return err; } -- cgit v1.2.3 From 41b70b2c6f10de4a3fcf1954bf00c8e620aed67d Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Wed, 23 Aug 2017 15:02:28 +0800 Subject: PCI: rockchip: Factor out rockchip_pcie_disable_clocks() Factor out rockchip_pcie_disable_clocks() so it can be reused by other functions. No functional change intended, but it does change the order of unpreparing clocks in the rockchip_pcie_resume_noirq() error path so it matches the other paths. Signed-off-by: Shawn Lin Signed-off-by: Bjorn Helgaas --- drivers/pci/host/pcie-rockchip.c | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/host/pcie-rockchip.c b/drivers/pci/host/pcie-rockchip.c index 3b1802c39adc..1797b4ee8223 100644 --- a/drivers/pci/host/pcie-rockchip.c +++ b/drivers/pci/host/pcie-rockchip.c @@ -1417,6 +1417,16 @@ err_aclk_perf_pcie: return err; } +static void rockchip_pcie_disable_clocks(void *data) +{ + struct rockchip_pcie *rockchip = data; + + clk_disable_unprepare(rockchip->clk_pcie_pm); + clk_disable_unprepare(rockchip->hclk_pcie); + clk_disable_unprepare(rockchip->aclk_perf_pcie); + clk_disable_unprepare(rockchip->aclk_pcie); +} + static int __maybe_unused rockchip_pcie_suspend_noirq(struct device *dev) { struct rockchip_pcie *rockchip = dev_get_drvdata(dev); @@ -1440,10 +1450,7 @@ static int __maybe_unused rockchip_pcie_suspend_noirq(struct device *dev) phy_exit(rockchip->phys[i]); } - clk_disable_unprepare(rockchip->clk_pcie_pm); - clk_disable_unprepare(rockchip->hclk_pcie); - clk_disable_unprepare(rockchip->aclk_perf_pcie); - clk_disable_unprepare(rockchip->aclk_pcie); + rockchip_pcie_disable_clocks(rockchip); if (!IS_ERR(rockchip->vpcie0v9)) regulator_disable(rockchip->vpcie0v9); @@ -1483,10 +1490,7 @@ static int __maybe_unused rockchip_pcie_resume_noirq(struct device *dev) return 0; err_pcie_resume: - clk_disable_unprepare(rockchip->aclk_pcie); - clk_disable_unprepare(rockchip->aclk_perf_pcie); - clk_disable_unprepare(rockchip->hclk_pcie); - clk_disable_unprepare(rockchip->clk_pcie_pm); + rockchip_pcie_disable_clocks(rockchip); return err; } @@ -1625,10 +1629,7 @@ err_vpcie: if (!IS_ERR(rockchip->vpcie0v9)) regulator_disable(rockchip->vpcie0v9); err_set_vpcie: - clk_disable_unprepare(rockchip->clk_pcie_pm); - clk_disable_unprepare(rockchip->hclk_pcie); - clk_disable_unprepare(rockchip->aclk_perf_pcie); - clk_disable_unprepare(rockchip->aclk_pcie); + rockchip_pcie_disable_clocks(rockchip); return err; } @@ -1650,10 +1651,7 @@ static int rockchip_pcie_remove(struct platform_device *pdev) phy_exit(rockchip->phys[i]); } - clk_disable_unprepare(rockchip->clk_pcie_pm); - clk_disable_unprepare(rockchip->hclk_pcie); - clk_disable_unprepare(rockchip->aclk_perf_pcie); - clk_disable_unprepare(rockchip->aclk_pcie); + rockchip_pcie_disable_clocks(rockchip); if (!IS_ERR(rockchip->vpcie12v)) regulator_disable(rockchip->vpcie12v); -- cgit v1.2.3 From de8473f51470805cfd3132cc91598471bb9c5151 Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Wed, 23 Aug 2017 15:02:49 +0800 Subject: PCI: rockchip: Factor out rockchip_pcie_deinit_phys() Factor out rockchip_pcie_deinit_phys() so it can be reused by rockchip_pcie_suspend_noirq() and rockchip_pcie_remove(). No functional change intended. Signed-off-by: Shawn Lin Signed-off-by: Bjorn Helgaas --- drivers/pci/host/pcie-rockchip.c | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/host/pcie-rockchip.c b/drivers/pci/host/pcie-rockchip.c index 1797b4ee8223..9879a6725c3d 100644 --- a/drivers/pci/host/pcie-rockchip.c +++ b/drivers/pci/host/pcie-rockchip.c @@ -756,6 +756,18 @@ static int rockchip_pcie_init_port(struct rockchip_pcie *rockchip) return 0; } +static void rockchip_pcie_deinit_phys(struct rockchip_pcie *rockchip) +{ + int i; + + for (i = 0; i < MAX_LANE_NUM; i++) { + /* inactive lanes are already powered off */ + if (rockchip->lanes_map & BIT(i)) + phy_power_off(rockchip->phys[i]); + phy_exit(rockchip->phys[i]); + } +} + static irqreturn_t rockchip_pcie_subsys_irq_handler(int irq, void *arg) { struct rockchip_pcie *rockchip = arg; @@ -1430,7 +1442,7 @@ static void rockchip_pcie_disable_clocks(void *data) static int __maybe_unused rockchip_pcie_suspend_noirq(struct device *dev) { struct rockchip_pcie *rockchip = dev_get_drvdata(dev); - int ret, i; + int ret; /* disable core and cli int since we don't need to ack PME_ACK */ rockchip_pcie_write(rockchip, (PCIE_CLIENT_INT_CLI << 16) | @@ -1443,12 +1455,7 @@ static int __maybe_unused rockchip_pcie_suspend_noirq(struct device *dev) return ret; } - for (i = 0; i < MAX_LANE_NUM; i++) { - /* inactive lanes are already powered off */ - if (rockchip->lanes_map & BIT(i)) - phy_power_off(rockchip->phys[i]); - phy_exit(rockchip->phys[i]); - } + rockchip_pcie_deinit_phys(rockchip); rockchip_pcie_disable_clocks(rockchip); @@ -1637,19 +1644,13 @@ static int rockchip_pcie_remove(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct rockchip_pcie *rockchip = dev_get_drvdata(dev); - int i; pci_stop_root_bus(rockchip->root_bus); pci_remove_root_bus(rockchip->root_bus); pci_unmap_iospace(rockchip->io); irq_domain_remove(rockchip->irq_domain); - for (i = 0; i < MAX_LANE_NUM; i++) { - /* inactive lanes are already powered off */ - if (rockchip->lanes_map & BIT(i)) - phy_power_off(rockchip->phys[i]); - phy_exit(rockchip->phys[i]); - } + rockchip_pcie_deinit_phys(rockchip); rockchip_pcie_disable_clocks(rockchip); -- cgit v1.2.3 From 8c595dd1fd97d8e241c7a8c2f9fe9b08867b1d4a Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Wed, 23 Aug 2017 15:03:07 +0800 Subject: PCI: rockchip: Clean up PHY if driver probe or resume fails We observed that the clk_pciephy_ref is still enabled when we fail to probe the driver. root@linaro-alip:~# grep pcie /sys/kernel/debug/clk/clk_summary clk_pciephy_ref 1 1 24000000 0 0 clk_pcie_pm 0 0 24000000 0 0 clk_pcie_core_cru 0 0 125000000 0 0 clk_pciephy_ref100m 0 0 100000000 0 0 aclk_pcie 0 0 148500000 0 0 aclk_perf_pcie 0 0 148500000 0 0 pclk_pcie 0 0 37125000 0 0 clk_pcie_core 0 0 0 0 0 clk_pciephy_ref is used by the PHY driver and we need to properly disable it for this case. Add error handling in rockchip_pcie_init_port() and rockchip_pcie_resume_noirq() to fix this issue. Signed-off-by: Shawn Lin Signed-off-by: Bjorn Helgaas --- drivers/pci/host/pcie-rockchip.c | 46 +++++++++++++++++++++++++--------------- 1 file changed, 29 insertions(+), 17 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/host/pcie-rockchip.c b/drivers/pci/host/pcie-rockchip.c index 9879a6725c3d..7d7c69ac1261 100644 --- a/drivers/pci/host/pcie-rockchip.c +++ b/drivers/pci/host/pcie-rockchip.c @@ -567,32 +567,32 @@ static int rockchip_pcie_init_port(struct rockchip_pcie *rockchip) err = phy_init(rockchip->phys[i]); if (err) { dev_err(dev, "init phy%d err %d\n", i, err); - return err; + goto err_exit_phy; } } err = reset_control_assert(rockchip->core_rst); if (err) { dev_err(dev, "assert core_rst err %d\n", err); - return err; + goto err_exit_phy; } err = reset_control_assert(rockchip->mgmt_rst); if (err) { dev_err(dev, "assert mgmt_rst err %d\n", err); - return err; + goto err_exit_phy; } err = reset_control_assert(rockchip->mgmt_sticky_rst); if (err) { dev_err(dev, "assert mgmt_sticky_rst err %d\n", err); - return err; + goto err_exit_phy; } err = reset_control_assert(rockchip->pipe_rst); if (err) { dev_err(dev, "assert pipe_rst err %d\n", err); - return err; + goto err_exit_phy; } udelay(10); @@ -600,19 +600,19 @@ static int rockchip_pcie_init_port(struct rockchip_pcie *rockchip) err = reset_control_deassert(rockchip->pm_rst); if (err) { dev_err(dev, "deassert pm_rst err %d\n", err); - return err; + goto err_exit_phy; } err = reset_control_deassert(rockchip->aclk_rst); if (err) { dev_err(dev, "deassert aclk_rst err %d\n", err); - return err; + goto err_exit_phy; } err = reset_control_deassert(rockchip->pclk_rst); if (err) { dev_err(dev, "deassert pclk_rst err %d\n", err); - return err; + goto err_exit_phy; } if (rockchip->link_gen == 2) @@ -634,7 +634,7 @@ static int rockchip_pcie_init_port(struct rockchip_pcie *rockchip) err = phy_power_on(rockchip->phys[i]); if (err) { dev_err(dev, "power on phy%d err %d\n", i, err); - return err; + goto err_power_off_phy; } } @@ -645,25 +645,25 @@ static int rockchip_pcie_init_port(struct rockchip_pcie *rockchip) err = reset_control_deassert(rockchip->mgmt_sticky_rst); if (err) { dev_err(dev, "deassert mgmt_sticky_rst err %d\n", err); - return err; + goto err_power_off_phy; } err = reset_control_deassert(rockchip->core_rst); if (err) { dev_err(dev, "deassert core_rst err %d\n", err); - return err; + goto err_power_off_phy; } err = reset_control_deassert(rockchip->mgmt_rst); if (err) { dev_err(dev, "deassert mgmt_rst err %d\n", err); - return err; + goto err_power_off_phy; } err = reset_control_deassert(rockchip->pipe_rst); if (err) { dev_err(dev, "deassert pipe_rst err %d\n", err); - return err; + goto err_power_off_phy; } /* Fix the transmitted FTS count desired to exit from L0s. */ @@ -696,7 +696,7 @@ static int rockchip_pcie_init_port(struct rockchip_pcie *rockchip) 500 * USEC_PER_MSEC); if (err) { dev_err(dev, "PCIe link training gen1 timeout!\n"); - return -ETIMEDOUT; + goto err_power_off_phy; } if (rockchip->link_gen == 2) { @@ -754,6 +754,14 @@ static int rockchip_pcie_init_port(struct rockchip_pcie *rockchip) rockchip_pcie_write(rockchip, status, PCIE_RC_CONFIG_DCSR); return 0; +err_power_off_phy: + while (i--) + phy_power_off(rockchip->phys[i]); + i = MAX_LANE_NUM; +err_exit_phy: + while (i--) + phy_exit(rockchip->phys[i]); + return err; } static void rockchip_pcie_deinit_phys(struct rockchip_pcie *rockchip) @@ -1488,7 +1496,7 @@ static int __maybe_unused rockchip_pcie_resume_noirq(struct device *dev) err = rockchip_pcie_cfg_atu(rockchip); if (err) - goto err_pcie_resume; + goto err_err_deinit_port; /* Need this to enter L1 again */ rockchip_pcie_update_txcredit_mui(rockchip); @@ -1496,6 +1504,8 @@ static int __maybe_unused rockchip_pcie_resume_noirq(struct device *dev) return 0; +err_err_deinit_port: + rockchip_pcie_deinit_phys(rockchip); err_pcie_resume: rockchip_pcie_disable_clocks(rockchip); return err; @@ -1549,12 +1559,12 @@ static int rockchip_pcie_probe(struct platform_device *pdev) err = rockchip_pcie_init_irq_domain(rockchip); if (err < 0) - goto err_vpcie; + goto err_deinit_port; err = of_pci_get_host_bridge_resources(dev->of_node, 0, 0xff, &res, &io_base); if (err) - goto err_vpcie; + goto err_deinit_port; err = devm_request_pci_bus_resources(dev, &res); if (err) @@ -1626,6 +1636,8 @@ static int rockchip_pcie_probe(struct platform_device *pdev) err_free_res: pci_free_resource_list(&res); +err_deinit_port: + rockchip_pcie_deinit_phys(rockchip); err_vpcie: if (!IS_ERR(rockchip->vpcie12v)) regulator_disable(rockchip->vpcie12v); -- cgit v1.2.3 From efee827d3ddb8bd219392cbedc5e5afc6ccfd617 Mon Sep 17 00:00:00 2001 From: Jeffy Chen Date: Wed, 23 Aug 2017 15:03:17 +0800 Subject: PCI: rockchip: Disable vpcie0v9 if resume_noirq fails Disable vpcie0v9 regulator if resume_noirq fails. Signed-off-by: Jeffy Chen Signed-off-by: Shawn Lin Signed-off-by: Bjorn Helgaas --- drivers/pci/host/pcie-rockchip.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/pci') diff --git a/drivers/pci/host/pcie-rockchip.c b/drivers/pci/host/pcie-rockchip.c index 7d7c69ac1261..ac8b8e8270f7 100644 --- a/drivers/pci/host/pcie-rockchip.c +++ b/drivers/pci/host/pcie-rockchip.c @@ -1488,7 +1488,7 @@ static int __maybe_unused rockchip_pcie_resume_noirq(struct device *dev) err = rockchip_pcie_enable_clocks(rockchip); if (err) - return err; + goto err_disable_0v9; err = rockchip_pcie_init_port(rockchip); if (err) @@ -1508,6 +1508,9 @@ err_err_deinit_port: rockchip_pcie_deinit_phys(rockchip); err_pcie_resume: rockchip_pcie_disable_clocks(rockchip); +err_disable_0v9: + if (!IS_ERR(rockchip->vpcie0v9)) + regulator_disable(rockchip->vpcie0v9); return err; } -- cgit v1.2.3 From 7b15b85927d6b04d0d8f1caf217bc6312486fdd5 Mon Sep 17 00:00:00 2001 From: Jeffy Chen Date: Wed, 23 Aug 2017 15:03:31 +0800 Subject: PCI: rockchip: Remove IRQ domain if probe fails Call irq_domain_remove() to clean up if probe fails. Signed-off-by: Jeffy Chen Signed-off-by: Shawn Lin Signed-off-by: Bjorn Helgaas --- drivers/pci/host/pcie-rockchip.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/pci') diff --git a/drivers/pci/host/pcie-rockchip.c b/drivers/pci/host/pcie-rockchip.c index ac8b8e8270f7..f8763f0017d5 100644 --- a/drivers/pci/host/pcie-rockchip.c +++ b/drivers/pci/host/pcie-rockchip.c @@ -1567,7 +1567,7 @@ static int rockchip_pcie_probe(struct platform_device *pdev) err = of_pci_get_host_bridge_resources(dev->of_node, 0, 0xff, &res, &io_base); if (err) - goto err_deinit_port; + goto err_remove_irq_domain; err = devm_request_pci_bus_resources(dev, &res); if (err) @@ -1639,6 +1639,8 @@ static int rockchip_pcie_probe(struct platform_device *pdev) err_free_res: pci_free_resource_list(&res); +err_remove_irq_domain: + irq_domain_remove(rockchip->irq_domain); err_deinit_port: rockchip_pcie_deinit_phys(rockchip); err_vpcie: -- cgit v1.2.3 From cecaf5cdfcf14f83ac8f311f3822dccbcf6589e4 Mon Sep 17 00:00:00 2001 From: Jeffy Chen Date: Wed, 23 Aug 2017 15:03:39 +0800 Subject: PCI: rockchip: Umap IO space if probe fails Call pci_unmap_iospace() to clean up if probe fails. Signed-off-by: Jeffy Chen Signed-off-by: Shawn Lin Signed-off-by: Bjorn Helgaas --- drivers/pci/host/pcie-rockchip.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/host/pcie-rockchip.c b/drivers/pci/host/pcie-rockchip.c index f8763f0017d5..56c2423ea021 100644 --- a/drivers/pci/host/pcie-rockchip.c +++ b/drivers/pci/host/pcie-rockchip.c @@ -1605,12 +1605,12 @@ static int rockchip_pcie_probe(struct platform_device *pdev) err = rockchip_pcie_cfg_atu(rockchip); if (err) - goto err_free_res; + goto err_unmap_iospace; rockchip->msg_region = devm_ioremap(dev, rockchip->msg_bus_addr, SZ_1M); if (!rockchip->msg_region) { err = -ENOMEM; - goto err_free_res; + goto err_unmap_iospace; } list_splice_init(&res, &bridge->windows); @@ -1623,7 +1623,7 @@ static int rockchip_pcie_probe(struct platform_device *pdev) err = pci_scan_root_bus_bridge(bridge); if (err < 0) - goto err_free_res; + goto err_unmap_iospace; bus = bridge->bus; @@ -1637,6 +1637,8 @@ static int rockchip_pcie_probe(struct platform_device *pdev) pci_bus_add_devices(bus); return 0; +err_unmap_iospace: + pci_unmap_iospace(rockchip->io); err_free_res: pci_free_resource_list(&res); err_remove_irq_domain: -- cgit v1.2.3 From 81edd471a61474de1ea772f27a3c734a68a09cc6 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Thu, 31 Aug 2017 14:52:09 -0300 Subject: PCI: rockchip: Fix platform_get_irq() error handling When platform_get_irq() fails we should propagate the real error value instead of always returning -EINVAL. Signed-off-by: Fabio Estevam Signed-off-by: Bjorn Helgaas Cc: Shawn Lin --- drivers/pci/host/pcie-rockchip.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/host/pcie-rockchip.c b/drivers/pci/host/pcie-rockchip.c index 56c2423ea021..d205381c7ec4 100644 --- a/drivers/pci/host/pcie-rockchip.c +++ b/drivers/pci/host/pcie-rockchip.c @@ -962,7 +962,7 @@ static int rockchip_pcie_setup_irq(struct rockchip_pcie *rockchip) irq = platform_get_irq_byname(pdev, "sys"); if (irq < 0) { dev_err(dev, "missing sys IRQ resource\n"); - return -EINVAL; + return irq; } err = devm_request_irq(dev, irq, rockchip_pcie_subsys_irq_handler, @@ -975,7 +975,7 @@ static int rockchip_pcie_setup_irq(struct rockchip_pcie *rockchip) irq = platform_get_irq_byname(pdev, "legacy"); if (irq < 0) { dev_err(dev, "missing legacy IRQ resource\n"); - return -EINVAL; + return irq; } irq_set_chained_handler_and_data(irq, @@ -985,7 +985,7 @@ static int rockchip_pcie_setup_irq(struct rockchip_pcie *rockchip) irq = platform_get_irq_byname(pdev, "client"); if (irq < 0) { dev_err(dev, "missing client IRQ resource\n"); - return -EINVAL; + return irq; } err = devm_request_irq(dev, irq, rockchip_pcie_client_irq_handler, -- cgit v1.2.3