Merge branch 'pci/host-rockchip' into next

* pci/host-rockchip:
  PCI: rockchip: Modularize
  PCI: Export pci_remap_iospace() and pci_unmap_iospace()
  PCI: rockchip: Add remove() support
  PCI: rockchip: Set PCI_EXP_LNKSTA_SLC in the Root Port
  PCI: rockchip: Advertise 128-byte Read Completion Boundary support
  PCI: rockchip: Make 'return 0' more obvious in probe()
  PCI: rockchip: Unindent rockchip_pcie_set_power_limit()
  PCI: rockchip: Handle regulator_get_current_limit() failure correctly
This commit is contained in:
Bjorn Helgaas 2017-04-28 10:33:10 -05:00
commit 9577367283
3 changed files with 70 additions and 23 deletions

View File

@ -170,7 +170,7 @@ config PCI_HOST_THUNDER_ECAM
Say Y here if you want ECAM support for CN88XX-Pass-1.x Cavium Thunder SoCs. Say Y here if you want ECAM support for CN88XX-Pass-1.x Cavium Thunder SoCs.
config PCIE_ROCKCHIP config PCIE_ROCKCHIP
bool "Rockchip PCIe controller" tristate "Rockchip PCIe controller"
depends on ARCH_ROCKCHIP || COMPILE_TEST depends on ARCH_ROCKCHIP || COMPILE_TEST
depends on OF depends on OF
depends on PCI_MSI_IRQ_DOMAIN depends on PCI_MSI_IRQ_DOMAIN

View File

@ -26,6 +26,7 @@
#include <linux/irqdomain.h> #include <linux/irqdomain.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/mfd/syscon.h> #include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/of_pci.h> #include <linux/of_pci.h>
@ -223,9 +224,11 @@ struct rockchip_pcie {
int link_gen; int link_gen;
struct device *dev; struct device *dev;
struct irq_domain *irq_domain; struct irq_domain *irq_domain;
u32 io_size;
int offset; int offset;
struct pci_bus *root_bus;
struct resource *io;
phys_addr_t io_bus_addr; phys_addr_t io_bus_addr;
u32 io_size;
void __iomem *msg_region; void __iomem *msg_region;
u32 mem_size; u32 mem_size;
phys_addr_t msg_bus_addr; phys_addr_t msg_bus_addr;
@ -425,7 +428,8 @@ static struct pci_ops rockchip_pcie_ops = {
static void rockchip_pcie_set_power_limit(struct rockchip_pcie *rockchip) 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)) if (IS_ERR(rockchip->vpcie3v3))
return; return;
@ -437,24 +441,25 @@ static void rockchip_pcie_set_power_limit(struct rockchip_pcie *rockchip)
* to the actual power supply. * to the actual power supply.
*/ */
curr = regulator_get_current_limit(rockchip->vpcie3v3); curr = regulator_get_current_limit(rockchip->vpcie3v3);
if (curr > 0) { if (curr <= 0)
scale = 3; /* 0.001x */ return;
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); scale = 3; /* 0.001x */
status |= (power << PCIE_RC_CONFIG_DCR_CSPL_SHIFT) | curr = curr / 1000; /* convert to mA */
(scale << PCIE_RC_CONFIG_DCR_CPLS_SHIFT); power = (curr * 3300) / 1000; /* milliwatt */
rockchip_pcie_write(rockchip, status, PCIE_RC_CONFIG_DCR); 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);
} }
/** /**
@ -596,7 +601,12 @@ static int rockchip_pcie_init_port(struct rockchip_pcie *rockchip)
/* Set RC's clock architecture as common clock */ /* Set RC's clock architecture as common clock */
status = rockchip_pcie_read(rockchip, PCIE_RC_CONFIG_LCS); 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 */
status = rockchip_pcie_read(rockchip, PCIE_RC_CONFIG_LCS);
status |= PCI_EXP_LNKCTL_RCB;
rockchip_pcie_write(rockchip, status, PCIE_RC_CONFIG_LCS); rockchip_pcie_write(rockchip, status, PCIE_RC_CONFIG_LCS);
/* Enable Gen1 training */ /* Enable Gen1 training */
@ -1359,6 +1369,7 @@ static int rockchip_pcie_probe(struct platform_device *pdev)
err, io); err, io);
continue; continue;
} }
rockchip->io = io;
break; break;
case IORESOURCE_MEM: case IORESOURCE_MEM:
mem = win->res; mem = win->res;
@ -1390,6 +1401,7 @@ static int rockchip_pcie_probe(struct platform_device *pdev)
err = -ENOMEM; err = -ENOMEM;
goto err_free_res; goto err_free_res;
} }
rockchip->root_bus = bus;
pci_bus_size_bridges(bus); pci_bus_size_bridges(bus);
pci_bus_assign_resources(bus); pci_bus_assign_resources(bus);
@ -1397,7 +1409,7 @@ static int rockchip_pcie_probe(struct platform_device *pdev)
pcie_bus_configure_settings(child); pcie_bus_configure_settings(child);
pci_bus_add_devices(bus); pci_bus_add_devices(bus);
return err; return 0;
err_free_res: err_free_res:
pci_free_resource_list(&res); pci_free_resource_list(&res);
@ -1420,6 +1432,34 @@ err_aclk_pcie:
return err; 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 = { static const struct dev_pm_ops rockchip_pcie_pm_ops = {
SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(rockchip_pcie_suspend_noirq, SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(rockchip_pcie_suspend_noirq,
rockchip_pcie_resume_noirq) rockchip_pcie_resume_noirq)
@ -1429,6 +1469,7 @@ static const struct of_device_id rockchip_pcie_of_match[] = {
{ .compatible = "rockchip,rk3399-pcie", }, { .compatible = "rockchip,rk3399-pcie", },
{} {}
}; };
MODULE_DEVICE_TABLE(of, rockchip_pcie_of_match);
static struct platform_driver rockchip_pcie_driver = { static struct platform_driver rockchip_pcie_driver = {
.driver = { .driver = {
@ -1437,6 +1478,10 @@ static struct platform_driver rockchip_pcie_driver = {
.pm = &rockchip_pcie_pm_ops, .pm = &rockchip_pcie_pm_ops,
}, },
.probe = rockchip_pcie_probe, .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");

View File

@ -3383,6 +3383,7 @@ int __weak pci_remap_iospace(const struct resource *res, phys_addr_t phys_addr)
return -ENODEV; return -ENODEV;
#endif #endif
} }
EXPORT_SYMBOL(pci_remap_iospace);
/** /**
* pci_unmap_iospace - Unmap the memory mapped I/O space * 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)); unmap_kernel_range(vaddr, resource_size(res));
#endif #endif
} }
EXPORT_SYMBOL(pci_unmap_iospace);
static void __pci_set_master(struct pci_dev *dev, bool enable) static void __pci_set_master(struct pci_dev *dev, bool enable)
{ {