|
@@ -26,6 +26,7 @@
|
|
|
#include <linux/irqdomain.h>
|
|
|
#include <linux/kernel.h>
|
|
|
#include <linux/mfd/syscon.h>
|
|
|
+#include <linux/module.h>
|
|
|
#include <linux/of_address.h>
|
|
|
#include <linux/of_device.h>
|
|
|
#include <linux/of_pci.h>
|
|
@@ -223,9 +224,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;
|
|
@@ -425,7 +428,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;
|
|
@@ -437,24 +441,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);
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -596,7 +601,12 @@ 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 */
|
|
|
+ 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 */
|
|
@@ -1359,6 +1369,7 @@ static int rockchip_pcie_probe(struct platform_device *pdev)
|
|
|
err, io);
|
|
|
continue;
|
|
|
}
|
|
|
+ rockchip->io = io;
|
|
|
break;
|
|
|
case IORESOURCE_MEM:
|
|
|
mem = win->res;
|
|
@@ -1390,6 +1401,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);
|
|
@@ -1397,7 +1409,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);
|
|
@@ -1420,6 +1432,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)
|
|
@@ -1429,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 = {
|
|
@@ -1437,6 +1478,10 @@ 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);
|
|
|
+module_platform_driver(rockchip_pcie_driver);
|
|
|
+
|
|
|
+MODULE_AUTHOR("Rockchip Inc");
|
|
|
+MODULE_DESCRIPTION("Rockchip AXI PCIe driver");
|
|
|
+MODULE_LICENSE("GPL v2");
|