From 5fcaa0051dfcc5fe77aee95061945d80e465a027 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Thu, 9 Mar 2017 18:46:13 -0800 Subject: PCI: rockchip: Handle regulator_get_current_limit() failure correctly regulator_get_current_limit() can return negative error codes. We saved the return value in an unsigned "curr", and a subsequent check interpreted a negative error code as a positive (invalid) current limit. Save the return code as a signed value, which avoids messages like this, seen on Samsung Chromebook Plus: rockchip-pcie f8000000.pcie: invalid power supply [bhelgaas: changelog] Fixes: 4816c4c7b82b ("PCI: rockchip: Provide captured slot power limit and scale") Signed-off-by: Brian Norris Signed-off-by: Bjorn Helgaas Acked-by: Shawn Lin --- drivers/pci/host/pcie-rockchip.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/pci') diff --git a/drivers/pci/host/pcie-rockchip.c b/drivers/pci/host/pcie-rockchip.c index 26ddd3535272..d785f64ec03b 100644 --- a/drivers/pci/host/pcie-rockchip.c +++ b/drivers/pci/host/pcie-rockchip.c @@ -425,7 +425,8 @@ static struct pci_ops rockchip_pcie_ops = { static void rockchip_pcie_set_power_limit(struct rockchip_pcie *rockchip) { - u32 status, curr, scale, power; + int curr; + u32 status, scale, power; if (IS_ERR(rockchip->vpcie3v3)) return; -- cgit v1.2.3-59-g8ed1b From 73edd2b180a18024605c599074596a9e22d745d6 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Thu, 23 Mar 2017 17:21:26 -0500 Subject: PCI: rockchip: Unindent rockchip_pcie_set_power_limit() If regulator_get_current_limit() returns 0 or error, return early so the body of the function doesn't have to be indented as the body of an "if" statement. No functional change intended. Signed-off-by: Bjorn Helgaas --- drivers/pci/host/pcie-rockchip.c | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/host/pcie-rockchip.c b/drivers/pci/host/pcie-rockchip.c index d785f64ec03b..7f76ff6af0ba 100644 --- a/drivers/pci/host/pcie-rockchip.c +++ b/drivers/pci/host/pcie-rockchip.c @@ -438,24 +438,25 @@ static void rockchip_pcie_set_power_limit(struct rockchip_pcie *rockchip) * to the actual power supply. */ curr = regulator_get_current_limit(rockchip->vpcie3v3); - if (curr > 0) { - scale = 3; /* 0.001x */ - curr = curr / 1000; /* convert to mA */ - power = (curr * 3300) / 1000; /* milliwatt */ - while (power > PCIE_RC_CONFIG_DCR_CSPL_LIMIT) { - if (!scale) { - dev_warn(rockchip->dev, "invalid power supply\n"); - return; - } - scale--; - power = power / 10; - } + if (curr <= 0) + return; - status = rockchip_pcie_read(rockchip, PCIE_RC_CONFIG_DCR); - status |= (power << PCIE_RC_CONFIG_DCR_CSPL_SHIFT) | - (scale << PCIE_RC_CONFIG_DCR_CPLS_SHIFT); - rockchip_pcie_write(rockchip, status, PCIE_RC_CONFIG_DCR); + scale = 3; /* 0.001x */ + curr = curr / 1000; /* convert to mA */ + power = (curr * 3300) / 1000; /* milliwatt */ + while (power > PCIE_RC_CONFIG_DCR_CSPL_LIMIT) { + if (!scale) { + dev_warn(rockchip->dev, "invalid power supply\n"); + return; + } + scale--; + power = power / 10; } + + status = rockchip_pcie_read(rockchip, PCIE_RC_CONFIG_DCR); + status |= (power << PCIE_RC_CONFIG_DCR_CSPL_SHIFT) | + (scale << PCIE_RC_CONFIG_DCR_CPLS_SHIFT); + rockchip_pcie_write(rockchip, status, PCIE_RC_CONFIG_DCR); } /** -- cgit v1.2.3-59-g8ed1b From deb518f6ae4d5da22fb1e8d6c6a690253ffa700d Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Thu, 9 Mar 2017 18:46:14 -0800 Subject: PCI: rockchip: Make 'return 0' more obvious in probe() There's no way to get here with 'err != 0'. Just return 0 to be more obvious and prevent future changes from accidentally erroring out here without going through the right error paths. Signed-off-by: Brian Norris Signed-off-by: Bjorn Helgaas --- 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 7f76ff6af0ba..b4dfe3bd15c3 100644 --- a/drivers/pci/host/pcie-rockchip.c +++ b/drivers/pci/host/pcie-rockchip.c @@ -1399,7 +1399,7 @@ static int rockchip_pcie_probe(struct platform_device *pdev) pcie_bus_configure_settings(child); pci_bus_add_devices(bus); - return err; + return 0; err_free_res: pci_free_resource_list(&res); -- cgit v1.2.3-59-g8ed1b From 55021718b9e9d21efd47117dd0e6c1cfebd654f8 Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Mon, 20 Mar 2017 17:39:40 +0800 Subject: PCI: rockchip: Advertise 128-byte Read Completion Boundary support Rockchip Root Ports support either 64 or 128 byte Read Completion Boundary (RCB). Set the RCB bit in the Link Control register to indicate this. A 128 byte RCB significantly improves performance of NVMe with libaio. [bhelgaas: changelog] Signed-off-by: Shawn Lin Signed-off-by: Bjorn Helgaas Cc: Brian Norris Cc: Jeffy Chen --- drivers/pci/host/pcie-rockchip.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/pci') diff --git a/drivers/pci/host/pcie-rockchip.c b/drivers/pci/host/pcie-rockchip.c index b4dfe3bd15c3..a7467212ea18 100644 --- a/drivers/pci/host/pcie-rockchip.c +++ b/drivers/pci/host/pcie-rockchip.c @@ -601,6 +601,11 @@ static int rockchip_pcie_init_port(struct rockchip_pcie *rockchip) status |= PCI_EXP_LNKCTL_CCC; rockchip_pcie_write(rockchip, status, PCIE_RC_CONFIG_LCS); + /* Set RC's RCB to 128 */ + status = rockchip_pcie_read(rockchip, PCIE_RC_CONFIG_LCS); + status |= PCI_EXP_LNKCTL_RCB; + rockchip_pcie_write(rockchip, status, PCIE_RC_CONFIG_LCS); + /* Enable Gen1 training */ rockchip_pcie_write(rockchip, PCIE_CLIENT_LINK_TRAIN_ENABLE, PCIE_CLIENT_CONFIG); -- cgit v1.2.3-59-g8ed1b From 64d6ea602ce619633a6e0af979e2c73738f6aeba Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Tue, 11 Apr 2017 16:27:02 -0500 Subject: PCI: rockchip: Set PCI_EXP_LNKSTA_SLC in the Root Port All platforms using Rockchip use a common clock for the Root Port and the slot connected to it. Indicate this by setting the Slot Clock Configuration (PCI_EXP_LNKSTA_SLC) bit in the Root Port's Link Status. Per the Implementation Note in the spec (PCIe r3.1, sec 7.8.7), if the downstream component also sets PCI_EXP_LNKSTA_SLC, software may set the Common Clock Configuration (PCI_EXP_LNKCTL_CCC) bits on both ends of the Link. This is done by pcie_aspm_configure_common_clock(). Signed-off-by: Shawn Lin Cc: Brian Norris Cc: jeffy.chen --- 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 a7467212ea18..94feb7dfd8f4 100644 --- a/drivers/pci/host/pcie-rockchip.c +++ b/drivers/pci/host/pcie-rockchip.c @@ -598,7 +598,7 @@ static int rockchip_pcie_init_port(struct rockchip_pcie *rockchip) /* Set RC's clock architecture as common clock */ status = rockchip_pcie_read(rockchip, PCIE_RC_CONFIG_LCS); - status |= PCI_EXP_LNKCTL_CCC; + status |= PCI_EXP_LNKSTA_SLC << 16; rockchip_pcie_write(rockchip, status, PCIE_RC_CONFIG_LCS); /* Set RC's RCB to 128 */ -- cgit v1.2.3-59-g8ed1b From 073d3dbe9a7c38888d8dafe09df421b174a6cffa Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Thu, 9 Mar 2017 18:46:15 -0800 Subject: PCI: rockchip: Add remove() support Currently, if we try to unbind the platform device, the remove will succeed, but the removal won't undo most of the registration, leaving partially-configured PCI devices in the system. This allows, for example, a simple 'lspci' to crash the system, as it will try to touch the freed (via devm_*) driver structures, e.g., on RK3399: # echo f8000000.pcie > /sys/bus/platform/drivers/rockchip-pcie/unbind # lspci So let's implement device remove(). Signed-off-by: Brian Norris Signed-off-by: Bjorn Helgaas Acked-by: Shawn Lin --- drivers/pci/host/pcie-rockchip.c | 36 ++++++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/host/pcie-rockchip.c b/drivers/pci/host/pcie-rockchip.c index 94feb7dfd8f4..76f2edc93663 100644 --- a/drivers/pci/host/pcie-rockchip.c +++ b/drivers/pci/host/pcie-rockchip.c @@ -223,9 +223,11 @@ struct rockchip_pcie { int link_gen; struct device *dev; struct irq_domain *irq_domain; - u32 io_size; int offset; + struct pci_bus *root_bus; + struct resource *io; phys_addr_t io_bus_addr; + u32 io_size; void __iomem *msg_region; u32 mem_size; phys_addr_t msg_bus_addr; @@ -1366,6 +1368,7 @@ static int rockchip_pcie_probe(struct platform_device *pdev) err, io); continue; } + rockchip->io = io; break; case IORESOURCE_MEM: mem = win->res; @@ -1397,6 +1400,7 @@ static int rockchip_pcie_probe(struct platform_device *pdev) err = -ENOMEM; goto err_free_res; } + rockchip->root_bus = bus; pci_bus_size_bridges(bus); pci_bus_assign_resources(bus); @@ -1427,6 +1431,34 @@ err_aclk_pcie: return err; } +static int rockchip_pcie_remove(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct rockchip_pcie *rockchip = dev_get_drvdata(dev); + + 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); + + 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); + + if (!IS_ERR(rockchip->vpcie3v3)) + regulator_disable(rockchip->vpcie3v3); + if (!IS_ERR(rockchip->vpcie1v8)) + regulator_disable(rockchip->vpcie1v8); + if (!IS_ERR(rockchip->vpcie0v9)) + regulator_disable(rockchip->vpcie0v9); + + return 0; +} + static const struct dev_pm_ops rockchip_pcie_pm_ops = { SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(rockchip_pcie_suspend_noirq, rockchip_pcie_resume_noirq) @@ -1444,6 +1476,6 @@ static struct platform_driver rockchip_pcie_driver = { .pm = &rockchip_pcie_pm_ops, }, .probe = rockchip_pcie_probe, - + .remove = rockchip_pcie_remove, }; builtin_platform_driver(rockchip_pcie_driver); -- cgit v1.2.3-59-g8ed1b From f90b0875463e450c5dcb714fb887720ecb53a600 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Thu, 9 Mar 2017 18:46:16 -0800 Subject: PCI: Export pci_remap_iospace() and pci_unmap_iospace() These are useful for PCIe host drivers, and those drivers can be modules. [bhelgaas: don't remove __weak; it's removed elsewhere] Signed-off-by: Brian Norris Signed-off-by: Bjorn Helgaas Acked-by: Shawn Lin --- drivers/pci/pci.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/pci') diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 7904d02ffdb9..c87d1edf0203 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -3383,6 +3383,7 @@ int __weak pci_remap_iospace(const struct resource *res, phys_addr_t phys_addr) return -ENODEV; #endif } +EXPORT_SYMBOL(pci_remap_iospace); /** * pci_unmap_iospace - Unmap the memory mapped I/O space @@ -3400,6 +3401,7 @@ void pci_unmap_iospace(struct resource *res) unmap_kernel_range(vaddr, resource_size(res)); #endif } +EXPORT_SYMBOL(pci_unmap_iospace); static void __pci_set_master(struct pci_dev *dev, bool enable) { -- cgit v1.2.3-59-g8ed1b From b0308c5419607c77e5be3c9d388b120ed471037b Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Thu, 9 Mar 2017 18:46:17 -0800 Subject: PCI: rockchip: Modularize Now that we've exported pci_remap_iospace() and added proper remove() support, there's no reason this can't be a loadable module. Signed-off-by: Brian Norris Signed-off-by: Bjorn Helgaas Acked-by: Shawn Lin --- drivers/pci/host/Kconfig | 2 +- drivers/pci/host/pcie-rockchip.c | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig index f7c1d4d5c665..d2293ed81cf9 100644 --- a/drivers/pci/host/Kconfig +++ b/drivers/pci/host/Kconfig @@ -164,7 +164,7 @@ config PCI_HOST_THUNDER_ECAM Say Y here if you want ECAM support for CN88XX-Pass-1.x Cavium Thunder SoCs. config PCIE_ROCKCHIP - bool "Rockchip PCIe controller" + tristate "Rockchip PCIe controller" depends on ARCH_ROCKCHIP || COMPILE_TEST depends on OF depends on PCI_MSI_IRQ_DOMAIN diff --git a/drivers/pci/host/pcie-rockchip.c b/drivers/pci/host/pcie-rockchip.c index 76f2edc93663..abc7fd76b181 100644 --- a/drivers/pci/host/pcie-rockchip.c +++ b/drivers/pci/host/pcie-rockchip.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -1468,6 +1469,7 @@ static const struct of_device_id rockchip_pcie_of_match[] = { { .compatible = "rockchip,rk3399-pcie", }, {} }; +MODULE_DEVICE_TABLE(of, rockchip_pcie_of_match); static struct platform_driver rockchip_pcie_driver = { .driver = { @@ -1478,4 +1480,8 @@ static struct platform_driver rockchip_pcie_driver = { .probe = rockchip_pcie_probe, .remove = rockchip_pcie_remove, }; -builtin_platform_driver(rockchip_pcie_driver); +module_platform_driver(rockchip_pcie_driver); + +MODULE_AUTHOR("Rockchip Inc"); +MODULE_DESCRIPTION("Rockchip AXI PCIe driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3-59-g8ed1b