[RFC PATCH] iommu: create direct_mapping after device attached

2016-07-20 Thread honghui.zhang
From: Honghui Zhang 

For mtk iommu, the domain_finalize was called in device attatch, the mtk
iommu iopgt ops was allocated and initialized in domain_finalize, the
iommu_group_create_direct_mappings would call the map interface to
implement the map. If it's earlier than device attach, there would be NULL
dereference. Move the iommu_group_create_direct_mappings call after device
attached.

Signed-off-by: Honghui Zhang 
---
 drivers/iommu/iommu.c | 9 +++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 351..24c671c 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -427,14 +427,19 @@ rename:
 
dev->iommu_group = group;
 
-   iommu_group_create_direct_mappings(group, dev);
-
mutex_lock(&group->mutex);
list_add_tail(&device->list, &group->devices);
if (group->domain)
__iommu_attach_device(group->domain, dev);
mutex_unlock(&group->mutex);
 
+   /*
+* For some iommu driver like mtk iommu, the map callback was assigned
+* after device attached. The direct_mappings would call iommu map and
+* dereference NULL if it's called earlier than attach_device.
+*/
+   iommu_group_create_direct_mappings(group, dev);
+
/* Notify any listeners about change to group. */
blocking_notifier_call_chain(&group->notifier,
 IOMMU_GROUP_NOTIFY_ADD_DEVICE, dev);
-- 
1.8.1.1.dirty



[PATCH v4] PCI: mediatek: Add system pm support for MT2712

2018-06-20 Thread honghui.zhang
From: Honghui Zhang 

The MTCMOS of PCIe Host for MT2712 will be off when system suspend, and all
the internal control register will be reset after system resume. The PCIe
link should be re-established and the related control register values
should be re-set after system resume.

Signed-off-by: Honghui Zhang 
CC: Ryder Lee 
---
 drivers/pci/controller/pcie-mediatek.c | 60 ++
 1 file changed, 60 insertions(+)

Change since v3:
 - rebase to v4.18-rc1.

diff --git a/drivers/pci/controller/pcie-mediatek.c 
b/drivers/pci/controller/pcie-mediatek.c
index 0baabe3..1ed2ef0 100644
--- a/drivers/pci/controller/pcie-mediatek.c
+++ b/drivers/pci/controller/pcie-mediatek.c
@@ -134,12 +134,14 @@ struct mtk_pcie_port;
 /**
  * struct mtk_pcie_soc - differentiate between host generations
  * @need_fix_class_id: whether this host's class ID needed to be fixed or not
+ * @pm_support: whether the host's MTCMOS will be off when suspend
  * @ops: pointer to configuration access functions
  * @startup: pointer to controller setting functions
  * @setup_irq: pointer to initialize IRQ functions
  */
 struct mtk_pcie_soc {
bool need_fix_class_id;
+   bool pm_support;
struct pci_ops *ops;
int (*startup)(struct mtk_pcie_port *port);
int (*setup_irq)(struct mtk_pcie_port *port, struct device_node *node);
@@ -1181,12 +1183,69 @@ static int mtk_pcie_probe(struct platform_device *pdev)
return err;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int mtk_pcie_suspend_noirq(struct device *dev)
+{
+   struct mtk_pcie *pcie = dev_get_drvdata(dev);
+   const struct mtk_pcie_soc *soc = pcie->soc;
+   struct mtk_pcie_port *port;
+
+   if (!soc->pm_support)
+   return 0;
+
+   list_for_each_entry(port, &pcie->ports, list) {
+   clk_disable_unprepare(port->ahb_ck);
+   clk_disable_unprepare(port->sys_ck);
+   phy_power_off(port->phy);
+   }
+
+   return 0;
+}
+
+static int mtk_pcie_resume_noirq(struct device *dev)
+{
+   struct mtk_pcie *pcie = dev_get_drvdata(dev);
+   const struct mtk_pcie_soc *soc = pcie->soc;
+   struct mtk_pcie_port *port;
+   int ret;
+
+   if (!soc->pm_support)
+   return 0;
+
+   list_for_each_entry(port, &pcie->ports, list) {
+   phy_power_on(port->phy);
+   clk_prepare_enable(port->sys_ck);
+   clk_prepare_enable(port->ahb_ck);
+
+   ret = soc->startup(port);
+   if (ret) {
+   dev_err(dev, "Port%d link down\n", port->slot);
+   phy_power_off(port->phy);
+   clk_disable_unprepare(port->sys_ck);
+   clk_disable_unprepare(port->ahb_ck);
+   return ret;
+   }
+
+   if (IS_ENABLED(CONFIG_PCI_MSI))
+   mtk_pcie_enable_msi(port);
+   }
+
+   return 0;
+}
+#endif
+
+static const struct dev_pm_ops mtk_pcie_pm_ops = {
+   SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(mtk_pcie_suspend_noirq,
+ mtk_pcie_resume_noirq)
+};
+
 static const struct mtk_pcie_soc mtk_pcie_soc_v1 = {
.ops = &mtk_pcie_ops,
.startup = mtk_pcie_startup_port,
 };
 
 static const struct mtk_pcie_soc mtk_pcie_soc_mt2712 = {
+   .pm_support = true,
.ops = &mtk_pcie_ops_v2,
.startup = mtk_pcie_startup_port_v2,
.setup_irq = mtk_pcie_setup_irq,
@@ -1213,6 +1272,7 @@ static struct platform_driver mtk_pcie_driver = {
.name = "mtk-pcie",
.of_match_table = mtk_pcie_ids,
.suppress_bind_attrs = true,
+   .pm = &mtk_pcie_pm_ops,
},
 };
 builtin_platform_driver(mtk_pcie_driver);
-- 
2.6.4



[PATCH v5 0/9] PCI: mediatek: fixup find_port, enable_msi and add pm, module support

2018-09-28 Thread honghui.zhang
From: Honghui Zhang 

This patchset includes misc patchs:

The patch 1 fixup the mtk_pcie_find_port logic which will cause system
could not touch the EP's configuration space that connected to PCIe slot 1.

The patch 2 fixup the class type for MT7622.
The patch 6 fixup the enable msi logic, the operation to enable msi
should be after system clock is enabled. Call mtk_pcie_enable_msi in
mtk_pcie_startup_port_v2 since the clock was all enabled at that time.

The patch 7 was rebased and refactor of the v4 patch[1], changes are:
 -Add PM support for MT7622.
 -Using mtk_pcie_enable_port to re-establish the link when resumed.
 -Rebased on this patchset.

The patch 9 add loadable kernel module support.

[1] https://patchwork.kernel.org/patch/10479079

Change since v4:
 - Add patch 2 to fixup class type for MT7622.
 - Add patch 3 to remove the redundant dev->pm_domain check
 - Add patch 4 to covert to use pci_host_probe
 - Add patch 5 to re-arrange the function define, this is a prepare patch for
   fixup the enable_msi logic, no functional changed have been made by this one.
 - Add patch 8 to save the GIC IRQ in mtk_pcie_port as a prepare patch for tear
   down the irq when remove the kernel module.
 - Re-arrange the find_port flow suggest by Lorenzo to make the code parse 
easier
   for the patch 1.
 - Remove the .pm_support in mtk_pcie_soc in patch 7 since if system pm was not
   supported, then those pm callbacks will never be executed for MT7622. So the
   .pm_support is not needed.

Change since v3:
 - Remove pm_runtime_XXX ops in suspend and resume callbacks in the third patch.
 - Rebase to 4.19-rc1.

Change since v2:
 - Fix the list_for_each_entry_safe parameter error.
 - Add Ryder's Acked-by flag.

Change since v1:
 - A bit of code refact of the first patch suggested by Andy Shevchenko, and
   commit message updated.
 - Using __maybe_unused.
 - Remove the redundant list_empty check of the fourth patch.

Honghui Zhang (9):
  PCI: mediatek: Using slot's devfn for compare to fix
mtk_pcie_find_port logic
  PCI: mediatek: Fixup class ID for MT7622 as PCI_CLASS_BRIDGE_PCI
  PCI: mediatek: Remove the redundant dev->pm_domain check
  PCI: mediatek: Convert to use pci_host_probe()
  PCI: mediatek: Move the mtk_pcie_startup_port_v2 function's define
after mtk_pcie_setup_irq
  PCI: mediatek: Enable msi after clock enabled
  PCI: mediatek: Add system pm support for MT2712 and MT7622
  PCI: mediatek: Save the GIC IRQ in mtk_pcie_port
  PCI: mediatek: Add loadable kernel module support

 drivers/pci/controller/Kconfig |   2 +-
 drivers/pci/controller/pcie-mediatek.c | 326 +
 2 files changed, 210 insertions(+), 118 deletions(-)

-- 
2.6.4



[PATCH v5 1/9] PCI: mediatek: Using slot's devfn for compare to fix mtk_pcie_find_port logic

2018-09-28 Thread honghui.zhang
From: Honghui Zhang 

The Mediatek's host controller has two slots, each with it's own control
registers. The host driver need to identify which slot was connected
in order to access the device's configuration space. There's problem
for current host driver to find out which slot was connected to for
a given EP device.

Assuming each slot have connect with one EP device as below:

host bridge
  bus 0 --> __|___
   |  |
   |  |
 slot 0 slot 1
  bus 1 -->|bus 2 --> |
   |  |
 EP 0   EP 1

During PCI enumeration, system software will scan all the PCI device
starting from devfn 0. So it will get the proper port for slot0 and
slot1 device when using PCI_SLOT(devfn) for match. But it will get
the wrong slot for EP1: The devfn will be start from 0 when scanning
EP1 behind slot1, it will get port0 since the PCI_SLOT(EP1) is match
for port0's slot value. So the host driver should not using EP's devfn
but the slot's devfn(the slot which EP was connected to) for match.

This patch fix the mtk_pcie_find_port's logic by using the slot's
devfn for match if finding device connected to the subordinate bus.

Signed-off-by: Honghui Zhang 
---
 drivers/pci/controller/pcie-mediatek.c | 17 -
 1 file changed, 16 insertions(+), 1 deletion(-)

diff --git a/drivers/pci/controller/pcie-mediatek.c 
b/drivers/pci/controller/pcie-mediatek.c
index dae..264e03f 100644
--- a/drivers/pci/controller/pcie-mediatek.c
+++ b/drivers/pci/controller/pcie-mediatek.c
@@ -337,10 +337,25 @@ static struct mtk_pcie_port *mtk_pcie_find_port(struct 
pci_bus *bus,
 {
struct mtk_pcie *pcie = bus->sysdata;
struct mtk_pcie_port *port;
+   struct pci_dev *dev = NULL;
+
+   /*
+* Walk the bus hierarchy to get the devfn value
+* of the port in the root bus.
+*/
+   while (bus && bus->number) {
+   dev = bus->self;
+   bus = dev->bus;
+   }
+
+   list_for_each_entry(port, &pcie->ports, list) {
+   /* Using slot's devfn to compare for subordinary bus. */
+   if (dev)
+   devfn = dev->devfn;
 
-   list_for_each_entry(port, &pcie->ports, list)
if (port->slot == PCI_SLOT(devfn))
return port;
+   }
 
return NULL;
 }
-- 
2.6.4



[PATCH v5 6/9] PCI: mediatek: Enable msi after clock enabled

2018-09-28 Thread honghui.zhang
From: Honghui Zhang 

The clocks was not enabled when enable MSI. This patch fix this
issue by calling mtk_pcie_enable_msi in mtk_pcie_startup_port_v2
since the clock was all enabled at that time.

Signed-off-by: Honghui Zhang 
---
 drivers/pci/controller/pcie-mediatek.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/pci/controller/pcie-mediatek.c 
b/drivers/pci/controller/pcie-mediatek.c
index d150be1..be38b38 100644
--- a/drivers/pci/controller/pcie-mediatek.c
+++ b/drivers/pci/controller/pcie-mediatek.c
@@ -572,8 +572,6 @@ static int mtk_pcie_init_irq_domain(struct mtk_pcie_port 
*port,
ret = mtk_pcie_allocate_msi_domains(port);
if (ret)
return ret;
-
-   mtk_pcie_enable_msi(port);
}
 
return 0;
@@ -694,6 +692,9 @@ static int mtk_pcie_startup_port_v2(struct mtk_pcie_port 
*port)
val &= ~INTX_MASK;
writel(val, port->base + PCIE_INT_MASK);
 
+   if (IS_ENABLED(CONFIG_PCI_MSI))
+   mtk_pcie_enable_msi(port);
+
/* Set AHB to PCIe translation windows */
size = mem->end - mem->start;
val = lower_32_bits(mem->start) | AHB2PCIE_SIZE(fls(size));
-- 
2.6.4



[PATCH v5 8/9] PCI: mediatek: Save the GIC IRQ in mtk_pcie_port

2018-09-28 Thread honghui.zhang
From: Honghui Zhang 

Need to save the PCIe's GIC IRQ for dispose_irq, this is a prepare
patch for add mediatek PCIe module support to tear down the IRQ, no
functional changed.

Signed-off-by: Honghui Zhang 
---
 drivers/pci/controller/pcie-mediatek.c | 9 ++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/drivers/pci/controller/pcie-mediatek.c 
b/drivers/pci/controller/pcie-mediatek.c
index bd1bde3..d35890c 100644
--- a/drivers/pci/controller/pcie-mediatek.c
+++ b/drivers/pci/controller/pcie-mediatek.c
@@ -162,6 +162,7 @@ struct mtk_pcie_soc {
  * @phy: pointer to PHY control block
  * @lane: lane count
  * @slot: port slot
+ * @irq: GIC irq
  * @irq_domain: legacy INTx IRQ domain
  * @inner_domain: inner IRQ domain
  * @msi_domain: MSI IRQ domain
@@ -182,6 +183,7 @@ struct mtk_pcie_port {
struct phy *phy;
u32 lane;
u32 slot;
+   int irq;
struct irq_domain *irq_domain;
struct irq_domain *inner_domain;
struct irq_domain *msi_domain;
@@ -624,7 +626,7 @@ static int mtk_pcie_setup_irq(struct mtk_pcie_port *port,
struct mtk_pcie *pcie = port->pcie;
struct device *dev = pcie->dev;
struct platform_device *pdev = to_platform_device(dev);
-   int err, irq;
+   int err;
 
err = mtk_pcie_init_irq_domain(port, node);
if (err) {
@@ -632,8 +634,9 @@ static int mtk_pcie_setup_irq(struct mtk_pcie_port *port,
return err;
}
 
-   irq = platform_get_irq(pdev, port->slot);
-   irq_set_chained_handler_and_data(irq, mtk_pcie_intr_handler, port);
+   port->irq = platform_get_irq(pdev, port->slot);
+   irq_set_chained_handler_and_data(port->irq,
+mtk_pcie_intr_handler, port);
 
return 0;
 }
-- 
2.6.4



[PATCH v5 9/9] PCI: mediatek: Add loadable kernel module support

2018-09-28 Thread honghui.zhang
From: Honghui Zhang 

Implement remove callback function for Mediatek PCIe driver to add
loadable kernel module support.

Signed-off-by: Honghui Zhang 
---
 drivers/pci/controller/Kconfig |  2 +-
 drivers/pci/controller/pcie-mediatek.c | 52 +-
 2 files changed, 52 insertions(+), 2 deletions(-)

diff --git a/drivers/pci/controller/Kconfig b/drivers/pci/controller/Kconfig
index 028b287..465790f 100644
--- a/drivers/pci/controller/Kconfig
+++ b/drivers/pci/controller/Kconfig
@@ -231,7 +231,7 @@ config PCIE_ROCKCHIP_EP
  available to support GEN2 with 4 slots.
 
 config PCIE_MEDIATEK
-   bool "MediaTek PCIe controller"
+   tristate "MediaTek PCIe controller"
depends on ARCH_MEDIATEK || COMPILE_TEST
depends on OF
depends on PCI_MSI_IRQ_DOMAIN
diff --git a/drivers/pci/controller/pcie-mediatek.c 
b/drivers/pci/controller/pcie-mediatek.c
index d35890c..b8ae214 100644
--- a/drivers/pci/controller/pcie-mediatek.c
+++ b/drivers/pci/controller/pcie-mediatek.c
@@ -15,6 +15,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -536,6 +537,27 @@ static void mtk_pcie_enable_msi(struct mtk_pcie_port *port)
writel(val, port->base + PCIE_INT_MASK);
 }
 
+static void mtk_pcie_irq_teardown(struct mtk_pcie *pcie)
+{
+   struct mtk_pcie_port *port, *tmp;
+
+   list_for_each_entry_safe(port, tmp, &pcie->ports, list) {
+   irq_set_chained_handler_and_data(port->irq, NULL, NULL);
+
+   if (port->irq_domain)
+   irq_domain_remove(port->irq_domain);
+
+   if (IS_ENABLED(CONFIG_PCI_MSI)) {
+   if (port->msi_domain)
+   irq_domain_remove(port->msi_domain);
+   if (port->inner_domain)
+   irq_domain_remove(port->inner_domain);
+   }
+
+   irq_dispose_mapping(port->irq);
+   }
+}
+
 static int mtk_pcie_intx_map(struct irq_domain *domain, unsigned int irq,
 irq_hw_number_t hwirq)
 {
@@ -1175,6 +1197,32 @@ static int mtk_pcie_probe(struct platform_device *pdev)
return err;
 }
 
+
+static void mtk_pcie_free_resources(struct mtk_pcie *pcie)
+{
+   struct pci_host_bridge *host = pci_host_bridge_from_priv(pcie);
+   struct list_head *windows = &host->windows;
+
+   pci_unmap_iospace(&pcie->pio);
+   pci_free_resource_list(windows);
+}
+
+static int mtk_pcie_remove(struct platform_device *pdev)
+{
+   struct mtk_pcie *pcie = platform_get_drvdata(pdev);
+   struct pci_host_bridge *host = pci_host_bridge_from_priv(pcie);
+
+   pci_stop_root_bus(host->bus);
+   pci_remove_root_bus(host->bus);
+   mtk_pcie_free_resources(pcie);
+
+   mtk_pcie_irq_teardown(pcie);
+
+   mtk_pcie_put_resources(pcie);
+
+   return 0;
+}
+
 static int __maybe_unused mtk_pcie_suspend_noirq(struct device *dev)
 {
struct mtk_pcie *pcie = dev_get_drvdata(dev);
@@ -1252,6 +1300,7 @@ static const struct of_device_id mtk_pcie_ids[] = {
 
 static struct platform_driver mtk_pcie_driver = {
.probe = mtk_pcie_probe,
+   .remove = mtk_pcie_remove,
.driver = {
.name = "mtk-pcie",
.of_match_table = mtk_pcie_ids,
@@ -1259,4 +1308,5 @@ static struct platform_driver mtk_pcie_driver = {
.pm = &mtk_pcie_pm_ops,
},
 };
-builtin_platform_driver(mtk_pcie_driver);
+module_platform_driver(mtk_pcie_driver);
+MODULE_LICENSE("GPL v2");
-- 
2.6.4



[PATCH v5 7/9] PCI: mediatek: Add system pm support for MT2712 and MT7622

2018-09-28 Thread honghui.zhang
From: Honghui Zhang 

In order to reduce the PCIe power consuming while system suspend,
the physical layer should be gated. And the PCIe link should be
re-established and the related control register values should be
re-initialized after system resume.

Register suspend_noirq & resume_noirq callback functions to allow
PCIe to come up after resume from RAM.

Signed-off-by: Honghui Zhang 
---
 drivers/pci/controller/pcie-mediatek.c | 50 ++
 1 file changed, 50 insertions(+)

diff --git a/drivers/pci/controller/pcie-mediatek.c 
b/drivers/pci/controller/pcie-mediatek.c
index be38b38..bd1bde3 100644
--- a/drivers/pci/controller/pcie-mediatek.c
+++ b/drivers/pci/controller/pcie-mediatek.c
@@ -1172,6 +1172,55 @@ static int mtk_pcie_probe(struct platform_device *pdev)
return err;
 }
 
+static int __maybe_unused mtk_pcie_suspend_noirq(struct device *dev)
+{
+   struct mtk_pcie *pcie = dev_get_drvdata(dev);
+   struct mtk_pcie_port *port;
+
+   if (list_empty(&pcie->ports))
+   return 0;
+
+   list_for_each_entry(port, &pcie->ports, list) {
+   clk_disable_unprepare(port->pipe_ck);
+   clk_disable_unprepare(port->obff_ck);
+   clk_disable_unprepare(port->axi_ck);
+   clk_disable_unprepare(port->aux_ck);
+   clk_disable_unprepare(port->ahb_ck);
+   clk_disable_unprepare(port->sys_ck);
+   phy_power_off(port->phy);
+   phy_exit(port->phy);
+   }
+
+   clk_disable_unprepare(pcie->free_ck);
+
+   return 0;
+}
+
+static int __maybe_unused mtk_pcie_resume_noirq(struct device *dev)
+{
+   struct mtk_pcie *pcie = dev_get_drvdata(dev);
+   struct mtk_pcie_port *port, *tmp;
+
+   if (list_empty(&pcie->ports))
+   return 0;
+
+   clk_prepare_enable(pcie->free_ck);
+
+   list_for_each_entry_safe(port, tmp, &pcie->ports, list)
+   mtk_pcie_enable_port(port);
+
+   /* In case of EP was removed while system suspend. */
+   if (list_empty(&pcie->ports))
+   clk_disable_unprepare(pcie->free_ck);
+
+   return 0;
+}
+
+static const struct dev_pm_ops mtk_pcie_pm_ops = {
+   SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(mtk_pcie_suspend_noirq,
+ mtk_pcie_resume_noirq)
+};
+
 static const struct mtk_pcie_soc mtk_pcie_soc_v1 = {
.ops = &mtk_pcie_ops,
.startup = mtk_pcie_startup_port,
@@ -1204,6 +1253,7 @@ static struct platform_driver mtk_pcie_driver = {
.name = "mtk-pcie",
.of_match_table = mtk_pcie_ids,
.suppress_bind_attrs = true,
+   .pm = &mtk_pcie_pm_ops,
},
 };
 builtin_platform_driver(mtk_pcie_driver);
-- 
2.6.4



[PATCH v5 5/9] PCI: mediatek: Move the mtk_pcie_startup_port_v2 function's define after mtk_pcie_setup_irq

2018-09-28 Thread honghui.zhang
From: Honghui Zhang 

This is a prepare patch to fix enable MSI logic, move the function's
define later to avoid forward declaration of mtk_pcie_enable_msi in
the future. No functional changed.

Signed-off-by: Honghui Zhang 
---
 drivers/pci/controller/pcie-mediatek.c | 138 -
 1 file changed, 69 insertions(+), 69 deletions(-)

diff --git a/drivers/pci/controller/pcie-mediatek.c 
b/drivers/pci/controller/pcie-mediatek.c
index cbf4543..d150be1 100644
--- a/drivers/pci/controller/pcie-mediatek.c
+++ b/drivers/pci/controller/pcie-mediatek.c
@@ -396,75 +396,6 @@ static struct pci_ops mtk_pcie_ops_v2 = {
.write = mtk_pcie_config_write,
 };
 
-static int mtk_pcie_startup_port_v2(struct mtk_pcie_port *port)
-{
-   struct mtk_pcie *pcie = port->pcie;
-   struct resource *mem = &pcie->mem;
-   const struct mtk_pcie_soc *soc = port->pcie->soc;
-   u32 val;
-   size_t size;
-   int err;
-
-   /* MT7622 platforms need to enable LTSSM and ASPM from PCIe subsys */
-   if (pcie->base) {
-   val = readl(pcie->base + PCIE_SYS_CFG_V2);
-   val |= PCIE_CSR_LTSSM_EN(port->slot) |
-  PCIE_CSR_ASPM_L1_EN(port->slot);
-   writel(val, pcie->base + PCIE_SYS_CFG_V2);
-   }
-
-   /* Assert all reset signals */
-   writel(0, port->base + PCIE_RST_CTRL);
-
-   /*
-* Enable PCIe link down reset, if link status changed from link up to
-* link down, this will reset MAC control registers and configuration
-* space.
-*/
-   writel(PCIE_LINKDOWN_RST_EN, port->base + PCIE_RST_CTRL);
-
-   /* De-assert PHY, PE, PIPE, MAC and configuration reset */
-   val = readl(port->base + PCIE_RST_CTRL);
-   val |= PCIE_PHY_RSTB | PCIE_PERSTB | PCIE_PIPE_SRSTB |
-  PCIE_MAC_SRSTB | PCIE_CRSTB;
-   writel(val, port->base + PCIE_RST_CTRL);
-
-   /* Set up vendor ID and class code */
-   if (soc->need_fix_class_id) {
-   val = PCI_VENDOR_ID_MEDIATEK;
-   writew(val, port->base + PCIE_CONF_VEND_ID);
-
-   val = PCI_CLASS_BRIDGE_PCI;
-   writew(val, port->base + PCIE_CONF_CLASS_ID);
-   }
-
-   /* 100ms timeout value should be enough for Gen1/2 training */
-   err = readl_poll_timeout(port->base + PCIE_LINK_STATUS_V2, val,
-!!(val & PCIE_PORT_LINKUP_V2), 20,
-100 * USEC_PER_MSEC);
-   if (err)
-   return -ETIMEDOUT;
-
-   /* Set INTx mask */
-   val = readl(port->base + PCIE_INT_MASK);
-   val &= ~INTX_MASK;
-   writel(val, port->base + PCIE_INT_MASK);
-
-   /* Set AHB to PCIe translation windows */
-   size = mem->end - mem->start;
-   val = lower_32_bits(mem->start) | AHB2PCIE_SIZE(fls(size));
-   writel(val, port->base + PCIE_AHB_TRANS_BASE0_L);
-
-   val = upper_32_bits(mem->start);
-   writel(val, port->base + PCIE_AHB_TRANS_BASE0_H);
-
-   /* Set PCIe to AXI translation memory space.*/
-   val = fls(0x) | WIN_ENABLE;
-   writel(val, port->base + PCIE_AXI_WINDOW0);
-
-   return 0;
-}
-
 static void mtk_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
 {
struct mtk_pcie_port *port = irq_data_get_irq_chip_data(data);
@@ -709,6 +640,75 @@ static int mtk_pcie_setup_irq(struct mtk_pcie_port *port,
return 0;
 }
 
+static int mtk_pcie_startup_port_v2(struct mtk_pcie_port *port)
+{
+   struct mtk_pcie *pcie = port->pcie;
+   struct resource *mem = &pcie->mem;
+   const struct mtk_pcie_soc *soc = port->pcie->soc;
+   u32 val;
+   size_t size;
+   int err;
+
+   /* MT7622 platforms need to enable LTSSM and ASPM from PCIe subsys */
+   if (pcie->base) {
+   val = readl(pcie->base + PCIE_SYS_CFG_V2);
+   val |= PCIE_CSR_LTSSM_EN(port->slot) |
+  PCIE_CSR_ASPM_L1_EN(port->slot);
+   writel(val, pcie->base + PCIE_SYS_CFG_V2);
+   }
+
+   /* Assert all reset signals */
+   writel(0, port->base + PCIE_RST_CTRL);
+
+   /*
+* Enable PCIe link down reset, if link status changed from link up to
+* link down, this will reset MAC control registers and configuration
+* space.
+*/
+   writel(PCIE_LINKDOWN_RST_EN, port->base + PCIE_RST_CTRL);
+
+   /* De-assert PHY, PE, PIPE, MAC and configuration reset */
+   val = readl(port->base + PCIE_RST_CTRL);
+   val |= PCIE_PHY_RSTB | PCIE_PERSTB | PCIE_PIPE_SRSTB |
+  PCIE_MAC_SRSTB | PCIE_CRSTB;
+   writel(val, port->base + PCIE_RST_CTRL);
+
+   /* Set up vendor ID and class code */
+   if (soc->need_fix_class_id) {
+   val = PCI_VENDOR_ID_MEDIATEK;
+   writew(val, port->base + PCIE_CONF_VEND_ID);
+
+   val = PCI_CLASS_BRIDGE_PCI;
+   writew(val, port->base + PCIE_CONF_CLASS_ID)

[PATCH v5 4/9] PCI: mediatek: Convert to use pci_host_probe()

2018-09-28 Thread honghui.zhang
From: Honghui Zhang 

Part of mtk_pcie_register_host is an open-coded version of
pci_host_probe(). So instead of duplicating this code, use
pci_host_probe() directly and remove mtk_pcie_register_host.

Signed-off-by: Honghui Zhang 
---
 drivers/pci/controller/pcie-mediatek.c | 37 --
 1 file changed, 8 insertions(+), 29 deletions(-)

diff --git a/drivers/pci/controller/pcie-mediatek.c 
b/drivers/pci/controller/pcie-mediatek.c
index e2c4127..cbf4543 100644
--- a/drivers/pci/controller/pcie-mediatek.c
+++ b/drivers/pci/controller/pcie-mediatek.c
@@ -1125,34 +1125,6 @@ static int mtk_pcie_request_resources(struct mtk_pcie 
*pcie)
return 0;
 }
 
-static int mtk_pcie_register_host(struct pci_host_bridge *host)
-{
-   struct mtk_pcie *pcie = pci_host_bridge_priv(host);
-   struct pci_bus *child;
-   int err;
-
-   host->busnr = pcie->busn.start;
-   host->dev.parent = pcie->dev;
-   host->ops = pcie->soc->ops;
-   host->map_irq = of_irq_parse_and_map_pci;
-   host->swizzle_irq = pci_common_swizzle;
-   host->sysdata = pcie;
-
-   err = pci_scan_root_bus_bridge(host);
-   if (err < 0)
-   return err;
-
-   pci_bus_size_bridges(host->bus);
-   pci_bus_assign_resources(host->bus);
-
-   list_for_each_entry(child, &host->bus->children, node)
-   pcie_bus_configure_settings(child);
-
-   pci_bus_add_devices(host->bus);
-
-   return 0;
-}
-
 static int mtk_pcie_probe(struct platform_device *pdev)
 {
struct device *dev = &pdev->dev;
@@ -1179,7 +1151,14 @@ static int mtk_pcie_probe(struct platform_device *pdev)
if (err)
goto put_resources;
 
-   err = mtk_pcie_register_host(host);
+   host->busnr = pcie->busn.start;
+   host->dev.parent = pcie->dev;
+   host->ops = pcie->soc->ops;
+   host->map_irq = of_irq_parse_and_map_pci;
+   host->swizzle_irq = pci_common_swizzle;
+   host->sysdata = pcie;
+
+   err = pci_host_probe(host);
if (err)
goto put_resources;
 
-- 
2.6.4



[PATCH v5 3/9] PCI: mediatek: Remove the redundant dev->pm_domain check

2018-09-28 Thread honghui.zhang
From: Honghui Zhang 

It's no needed to check whether device have pm_domain attached before
calling the pm_runtime_XXX interface, remove it.

Signed-off-by: Honghui Zhang 
---
 drivers/pci/controller/pcie-mediatek.c | 18 ++
 1 file changed, 6 insertions(+), 12 deletions(-)

diff --git a/drivers/pci/controller/pcie-mediatek.c 
b/drivers/pci/controller/pcie-mediatek.c
index 3ab80d6..e2c4127 100644
--- a/drivers/pci/controller/pcie-mediatek.c
+++ b/drivers/pci/controller/pcie-mediatek.c
@@ -225,10 +225,8 @@ static void mtk_pcie_subsys_powerdown(struct mtk_pcie 
*pcie)
 
clk_disable_unprepare(pcie->free_ck);
 
-   if (dev->pm_domain) {
-   pm_runtime_put_sync(dev);
-   pm_runtime_disable(dev);
-   }
+   pm_runtime_put_sync(dev);
+   pm_runtime_disable(dev);
 }
 
 static void mtk_pcie_port_free(struct mtk_pcie_port *port)
@@ -1002,10 +1000,8 @@ static int mtk_pcie_subsys_powerup(struct mtk_pcie *pcie)
pcie->free_ck = NULL;
}
 
-   if (dev->pm_domain) {
-   pm_runtime_enable(dev);
-   pm_runtime_get_sync(dev);
-   }
+   pm_runtime_enable(dev);
+   pm_runtime_get_sync(dev);
 
/* enable top level clock */
err = clk_prepare_enable(pcie->free_ck);
@@ -1017,10 +1013,8 @@ static int mtk_pcie_subsys_powerup(struct mtk_pcie *pcie)
return 0;
 
 err_free_ck:
-   if (dev->pm_domain) {
-   pm_runtime_put_sync(dev);
-   pm_runtime_disable(dev);
-   }
+   pm_runtime_put_sync(dev);
+   pm_runtime_disable(dev);
 
return err;
 }
-- 
2.6.4



[PATCH v5 2/9] PCI: mediatek: Fixup class ID for MT7622 as PCI_CLASS_BRIDGE_PCI

2018-09-28 Thread honghui.zhang
From: Honghui Zhang 

The PCIe controller of MT7622 has TYPE 1 configuration space type, but
the HW default class type values is invalid.

The commit 101c92dc80c8 ("PCI: mediatek: Set up vendor ID and class
type for MT7622") have set the class ID for MT7622 as
PCI_CLASS_BRIDGE_HOST, but it's not workable for MT7622:

In __pci_bus_assign_resources, the framework only setup bridge's
resource window only if class type is PCI_CLASS_BRIDGE_PCI. Or it
will leave the subordinary PCIe device's MMIO window un-touched.

Fixup the class type to PCI_CLASS_BRIDGE_PCI as most of the controller
driver do.

Signed-off-by: Honghui Zhang 
---
 drivers/pci/controller/pcie-mediatek.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/pci/controller/pcie-mediatek.c 
b/drivers/pci/controller/pcie-mediatek.c
index 264e03f..3ab80d6 100644
--- a/drivers/pci/controller/pcie-mediatek.c
+++ b/drivers/pci/controller/pcie-mediatek.c
@@ -436,7 +436,7 @@ static int mtk_pcie_startup_port_v2(struct mtk_pcie_port 
*port)
val = PCI_VENDOR_ID_MEDIATEK;
writew(val, port->base + PCIE_CONF_VEND_ID);
 
-   val = PCI_CLASS_BRIDGE_HOST;
+   val = PCI_CLASS_BRIDGE_PCI;
writew(val, port->base + PCIE_CONF_CLASS_ID);
}
 
-- 
2.6.4



[PATCH v3] PCI: mediatek: Use devm_of_pci_get_host_bridge_resources() to parse DT

2018-11-29 Thread honghui.zhang
From: Honghui Zhang 

Use the devm_of_pci_get_host_bridge_resources() API in place of the PCI OF
DT parser.

Signed-off-by: Honghui Zhang 
Acked-by: Ryder Lee 
---
 drivers/pci/controller/pcie-mediatek.c | 101 +
 1 file changed, 27 insertions(+), 74 deletions(-)

diff --git a/drivers/pci/controller/pcie-mediatek.c 
b/drivers/pci/controller/pcie-mediatek.c
index 2a1f97c..6917aec 100644
--- a/drivers/pci/controller/pcie-mediatek.c
+++ b/drivers/pci/controller/pcie-mediatek.c
@@ -197,29 +197,20 @@ struct mtk_pcie_port {
  * @dev: pointer to PCIe device
  * @base: IO mapped register base
  * @free_ck: free-run reference clock
- * @io: IO resource
- * @pio: PIO resource
  * @mem: non-prefetchable memory resource
- * @busn: bus range
- * @offset: IO / Memory offset
  * @ports: pointer to PCIe port information
  * @soc: pointer to SoC-dependent operations
+ * @busnr: root bus number
  */
 struct mtk_pcie {
struct device *dev;
void __iomem *base;
struct clk *free_ck;
 
-   struct resource io;
-   struct resource pio;
struct resource mem;
-   struct resource busn;
-   struct {
-   resource_size_t mem;
-   resource_size_t io;
-   } offset;
struct list_head ports;
const struct mtk_pcie_soc *soc;
+   unsigned int busnr;
 };
 
 static void mtk_pcie_subsys_powerdown(struct mtk_pcie *pcie)
@@ -1045,55 +1036,43 @@ static int mtk_pcie_setup(struct mtk_pcie *pcie)
 {
struct device *dev = pcie->dev;
struct device_node *node = dev->of_node, *child;
-   struct of_pci_range_parser parser;
-   struct of_pci_range range;
-   struct resource res;
struct mtk_pcie_port *port, *tmp;
+   struct pci_host_bridge *host = pci_host_bridge_from_priv(pcie);
+   struct list_head *windows = &host->windows;
+   struct resource_entry *win, *tmp_win;
+   resource_size_t io_base;
int err;
 
-   if (of_pci_range_parser_init(&parser, node)) {
-   dev_err(dev, "missing \"ranges\" property\n");
-   return -EINVAL;
-   }
+   err = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff,
+   windows, &io_base);
+   if (err)
+   return err;
 
-   for_each_of_pci_range(&parser, &range) {
-   err = of_pci_range_to_resource(&range, node, &res);
-   if (err < 0)
-   return err;
+   err = devm_request_pci_bus_resources(dev, windows);
+   if (err < 0)
+   return err;
 
-   switch (res.flags & IORESOURCE_TYPE_BITS) {
+   /* Get the I/O and memory ranges from DT */
+   resource_list_for_each_entry_safe(win, tmp_win, windows) {
+   switch (resource_type(win->res)) {
case IORESOURCE_IO:
-   pcie->offset.io = res.start - range.pci_addr;
-
-   memcpy(&pcie->pio, &res, sizeof(res));
-   pcie->pio.name = node->full_name;
-
-   pcie->io.start = range.cpu_addr;
-   pcie->io.end = range.cpu_addr + range.size - 1;
-   pcie->io.flags = IORESOURCE_MEM;
-   pcie->io.name = "I/O";
-
-   memcpy(&res, &pcie->io, sizeof(res));
+   err = devm_pci_remap_iospace(dev, win->res, io_base);
+   if (err) {
+   dev_warn(dev, "error %d: failed to map resource 
%pR\n",
+err, win->res);
+   resource_list_destroy_entry(win);
+   }
break;
-
case IORESOURCE_MEM:
-   pcie->offset.mem = res.start - range.pci_addr;
-
-   memcpy(&pcie->mem, &res, sizeof(res));
+   memcpy(&pcie->mem, win->res, sizeof(*win->res));
pcie->mem.name = "non-prefetchable";
break;
+   case IORESOURCE_BUS:
+   pcie->busnr = win->res->start;
+   break;
}
}
 
-   err = of_pci_parse_bus_range(node, &pcie->busn);
-   if (err < 0) {
-   dev_err(dev, "failed to parse bus ranges property: %d\n", err);
-   pcie->busn.name = node->name;
-   pcie->busn.start = 0;
-   pcie->busn.end = 0xff;
-   pcie->busn.flags = IORESOURCE_BUS;
-   }
-
for_each_available_child_of_node(node, child) {
int slot;
 
@@ -1125,28 +1104,6 @@ static int mtk_pcie_setup(struct mtk_pcie *pcie)
return 0;
 }
 
-static int mtk_pcie_request_resources(struct mtk_pcie *pcie)
-{
-   struct pci_host_bridge *host = pci_host_bridge_from_priv(pcie);
-   struct list_head *windows = &host->windows;
-   struct device *dev = pcie->dev;
- 

[PATCH v2 2/4] PCI: mediatek: enable msi after clock enabled

2018-07-01 Thread honghui.zhang
From: Honghui Zhang 

The clocks was not enabled when enable MSI. This patch fix this
issue by calling mtk_pcie_enable_msi in mtk_pcie_startup_port_v2
since the clock was all enabled at that time.

The function of mtk_pcie_startup_port_v2's define location is
re-arranged to avoid mtk_pcie_enable_msi's forward declaration.

Signed-off-by: Honghui Zhang 
Reviewed-by: Ryder Lee 
---
 drivers/pci/controller/pcie-mediatek.c | 143 +
 1 file changed, 72 insertions(+), 71 deletions(-)

diff --git a/drivers/pci/controller/pcie-mediatek.c 
b/drivers/pci/controller/pcie-mediatek.c
index b43f41d..86918d4 100644
--- a/drivers/pci/controller/pcie-mediatek.c
+++ b/drivers/pci/controller/pcie-mediatek.c
@@ -398,75 +398,6 @@ static struct pci_ops mtk_pcie_ops_v2 = {
.write = mtk_pcie_config_write,
 };
 
-static int mtk_pcie_startup_port_v2(struct mtk_pcie_port *port)
-{
-   struct mtk_pcie *pcie = port->pcie;
-   struct resource *mem = &pcie->mem;
-   const struct mtk_pcie_soc *soc = port->pcie->soc;
-   u32 val;
-   size_t size;
-   int err;
-
-   /* MT7622 platforms need to enable LTSSM and ASPM from PCIe subsys */
-   if (pcie->base) {
-   val = readl(pcie->base + PCIE_SYS_CFG_V2);
-   val |= PCIE_CSR_LTSSM_EN(port->slot) |
-  PCIE_CSR_ASPM_L1_EN(port->slot);
-   writel(val, pcie->base + PCIE_SYS_CFG_V2);
-   }
-
-   /* Assert all reset signals */
-   writel(0, port->base + PCIE_RST_CTRL);
-
-   /*
-* Enable PCIe link down reset, if link status changed from link up to
-* link down, this will reset MAC control registers and configuration
-* space.
-*/
-   writel(PCIE_LINKDOWN_RST_EN, port->base + PCIE_RST_CTRL);
-
-   /* De-assert PHY, PE, PIPE, MAC and configuration reset */
-   val = readl(port->base + PCIE_RST_CTRL);
-   val |= PCIE_PHY_RSTB | PCIE_PERSTB | PCIE_PIPE_SRSTB |
-  PCIE_MAC_SRSTB | PCIE_CRSTB;
-   writel(val, port->base + PCIE_RST_CTRL);
-
-   /* Set up vendor ID and class code */
-   if (soc->need_fix_class_id) {
-   val = PCI_VENDOR_ID_MEDIATEK;
-   writew(val, port->base + PCIE_CONF_VEND_ID);
-
-   val = PCI_CLASS_BRIDGE_HOST;
-   writew(val, port->base + PCIE_CONF_CLASS_ID);
-   }
-
-   /* 100ms timeout value should be enough for Gen1/2 training */
-   err = readl_poll_timeout(port->base + PCIE_LINK_STATUS_V2, val,
-!!(val & PCIE_PORT_LINKUP_V2), 20,
-100 * USEC_PER_MSEC);
-   if (err)
-   return -ETIMEDOUT;
-
-   /* Set INTx mask */
-   val = readl(port->base + PCIE_INT_MASK);
-   val &= ~INTX_MASK;
-   writel(val, port->base + PCIE_INT_MASK);
-
-   /* Set AHB to PCIe translation windows */
-   size = mem->end - mem->start;
-   val = lower_32_bits(mem->start) | AHB2PCIE_SIZE(fls(size));
-   writel(val, port->base + PCIE_AHB_TRANS_BASE0_L);
-
-   val = upper_32_bits(mem->start);
-   writel(val, port->base + PCIE_AHB_TRANS_BASE0_H);
-
-   /* Set PCIe to AXI translation memory space.*/
-   val = fls(0x) | WIN_ENABLE;
-   writel(val, port->base + PCIE_AXI_WINDOW0);
-
-   return 0;
-}
-
 static void mtk_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
 {
struct mtk_pcie_port *port = irq_data_get_irq_chip_data(data);
@@ -643,8 +574,6 @@ static int mtk_pcie_init_irq_domain(struct mtk_pcie_port 
*port,
ret = mtk_pcie_allocate_msi_domains(port);
if (ret)
return ret;
-
-   mtk_pcie_enable_msi(port);
}
 
return 0;
@@ -711,6 +640,78 @@ static int mtk_pcie_setup_irq(struct mtk_pcie_port *port,
return 0;
 }
 
+static int mtk_pcie_startup_port_v2(struct mtk_pcie_port *port)
+{
+   struct mtk_pcie *pcie = port->pcie;
+   struct resource *mem = &pcie->mem;
+   const struct mtk_pcie_soc *soc = port->pcie->soc;
+   u32 val;
+   size_t size;
+   int err;
+
+   /* MT7622 platforms need to enable LTSSM and ASPM from PCIe subsys */
+   if (pcie->base) {
+   val = readl(pcie->base + PCIE_SYS_CFG_V2);
+   val |= PCIE_CSR_LTSSM_EN(port->slot) |
+  PCIE_CSR_ASPM_L1_EN(port->slot);
+   writel(val, pcie->base + PCIE_SYS_CFG_V2);
+   }
+
+   /* Assert all reset signals */
+   writel(0, port->base + PCIE_RST_CTRL);
+
+   /*
+* Enable PCIe link down reset, if link status changed from link up to
+* link down, this will reset MAC control registers and configuration
+* space.
+*/
+   writel(PCIE_LINKDOWN_RST_EN, port->base + PCIE_RST_CTRL);
+
+   /* De-assert PHY, PE, PIPE, MAC and configuration reset */
+   val = readl(port->base + PCIE_RST_CTRL);
+   val |= PCIE_

[PATCH v2 1/4] PCI: mediatek: fixup mtk_pcie_find_port logical

2018-07-01 Thread honghui.zhang
From: Honghui Zhang 

The Mediatek's host controller has two slots, each with it's own control
registers. The host driver need to identify which slot was connected
in order to access the device's configuration space. There's problem
for current host driver to find out which slot was connected to for
a given EP device.

Assuming each slot have connect with one EP device as below:

host bridge
  bus 0 --> __|___
   |  |
   |  |
 slot 0 slot 1
  bus 1 -->|bus 2 --> |
   |  |
 EP 0   EP 1

During PCI enumeration, system software will scan all the PCI device
starting from devfn 0. So it will get the proper port for slot0 and
slot1 device when using PCI_SLOT(devfn) for match. But it will get
the wrong slot for EP1: The devfn will be start from 0 when scanning
EP1 behind slot1, it will get port0 since the PCI_SLOT(EP1) is match
for port0's slot value. So the host driver should not using EP's devfn
but the slot's devfn(the slot which EP was connected to) for match.

This patch fix the mtk_pcie_find_port's logical by using the slot's
devfn for match.

Signed-off-by: Honghui Zhang 
---
 drivers/pci/controller/pcie-mediatek.c | 19 +--
 1 file changed, 17 insertions(+), 2 deletions(-)

diff --git a/drivers/pci/controller/pcie-mediatek.c 
b/drivers/pci/controller/pcie-mediatek.c
index 0baabe3..b43f41d 100644
--- a/drivers/pci/controller/pcie-mediatek.c
+++ b/drivers/pci/controller/pcie-mediatek.c
@@ -337,11 +337,26 @@ static struct mtk_pcie_port *mtk_pcie_find_port(struct 
pci_bus *bus,
 {
struct mtk_pcie *pcie = bus->sysdata;
struct mtk_pcie_port *port;
+   struct pci_dev *dev;
+   struct pci_bus *pbus;
 
-   list_for_each_entry(port, &pcie->ports, list)
-   if (port->slot == PCI_SLOT(devfn))
+   list_for_each_entry(port, &pcie->ports, list) {
+   if (!bus->number && port->slot == PCI_SLOT(devfn))
return port;
 
+   if (bus->number) {
+   pbus = bus;
+
+   while (pbus->number) {
+   dev = pbus->self;
+   pbus = dev->bus;
+   }
+
+   if (port->slot == PCI_SLOT(dev->devfn))
+   return port;
+   }
+   }
+
return NULL;
 }
 
-- 
2.6.4



[PATCH v2 4/4] PCI: mediatek: Add loadable kernel module support

2018-07-01 Thread honghui.zhang
From: Honghui Zhang 

Implement remove callback function for Mediatek PCIe driver to add
loadable kernel module support.

Signed-off-by: Honghui Zhang 
---
 drivers/pci/controller/Kconfig |  2 +-
 drivers/pci/controller/pcie-mediatek.c | 60 +++---
 2 files changed, 57 insertions(+), 5 deletions(-)

diff --git a/drivers/pci/controller/Kconfig b/drivers/pci/controller/Kconfig
index 18fa09b..6c61ac65 100644
--- a/drivers/pci/controller/Kconfig
+++ b/drivers/pci/controller/Kconfig
@@ -234,7 +234,7 @@ config PCIE_ROCKCHIP_EP
  available to support GEN2 with 4 slots.
 
 config PCIE_MEDIATEK
-   bool "MediaTek PCIe controller"
+   tristate "MediaTek PCIe controller"
depends on ARCH_MEDIATEK || COMPILE_TEST
depends on OF
depends on PCI_MSI_IRQ_DOMAIN
diff --git a/drivers/pci/controller/pcie-mediatek.c 
b/drivers/pci/controller/pcie-mediatek.c
index c530539..b17cac6 100644
--- a/drivers/pci/controller/pcie-mediatek.c
+++ b/drivers/pci/controller/pcie-mediatek.c
@@ -15,6 +15,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -184,6 +185,7 @@ struct mtk_pcie_port {
struct phy *phy;
u32 lane;
u32 slot;
+   int irq;
struct irq_domain *irq_domain;
struct irq_domain *inner_domain;
struct irq_domain *msi_domain;
@@ -538,6 +540,27 @@ static void mtk_pcie_enable_msi(struct mtk_pcie_port *port)
writel(val, port->base + PCIE_INT_MASK);
 }
 
+static void mtk_pcie_irq_teardown(struct mtk_pcie *pcie)
+{
+   struct mtk_pcie_port *port, *tmp;
+
+   list_for_each_entry_safe(port, tmp, &pcie->ports, list) {
+   irq_set_chained_handler_and_data(port->irq, NULL, NULL);
+
+   if (port->irq_domain)
+   irq_domain_remove(port->irq_domain);
+
+   if (IS_ENABLED(CONFIG_PCI_MSI)) {
+   if (port->msi_domain)
+   irq_domain_remove(port->msi_domain);
+   if (port->inner_domain)
+   irq_domain_remove(port->inner_domain);
+   }
+
+   irq_dispose_mapping(port->irq);
+   }
+}
+
 static int mtk_pcie_intx_map(struct irq_domain *domain, unsigned int irq,
 irq_hw_number_t hwirq)
 {
@@ -628,7 +651,7 @@ static int mtk_pcie_setup_irq(struct mtk_pcie_port *port,
struct mtk_pcie *pcie = port->pcie;
struct device *dev = pcie->dev;
struct platform_device *pdev = to_platform_device(dev);
-   int err, irq;
+   int err;
 
err = mtk_pcie_init_irq_domain(port, node);
if (err) {
@@ -636,8 +659,9 @@ static int mtk_pcie_setup_irq(struct mtk_pcie_port *port,
return err;
}
 
-   irq = platform_get_irq(pdev, port->slot);
-   irq_set_chained_handler_and_data(irq, mtk_pcie_intr_handler, port);
+   port->irq = platform_get_irq(pdev, port->slot);
+   irq_set_chained_handler_and_data(port->irq,
+mtk_pcie_intr_handler, port);
 
return 0;
 }
@@ -1199,6 +1223,32 @@ static int mtk_pcie_probe(struct platform_device *pdev)
return err;
 }
 
+
+static void mtk_pcie_free_resources(struct mtk_pcie *pcie)
+{
+   struct pci_host_bridge *host = pci_host_bridge_from_priv(pcie);
+   struct list_head *windows = &host->windows;
+
+   pci_unmap_iospace(&pcie->pio);
+   pci_free_resource_list(windows);
+}
+
+static int mtk_pcie_remove(struct platform_device *pdev)
+{
+   struct mtk_pcie *pcie = platform_get_drvdata(pdev);
+   struct pci_host_bridge *host = pci_host_bridge_from_priv(pcie);
+
+   pci_stop_root_bus(host->bus);
+   pci_remove_root_bus(host->bus);
+   mtk_pcie_free_resources(pcie);
+
+   mtk_pcie_irq_teardown(pcie);
+
+   mtk_pcie_put_resources(pcie);
+
+   return 0;
+}
+
 static int __maybe_unused mtk_pcie_suspend_noirq(struct device *dev)
 {
struct mtk_pcie *pcie = dev_get_drvdata(dev);
@@ -1291,6 +1341,7 @@ static const struct of_device_id mtk_pcie_ids[] = {
 
 static struct platform_driver mtk_pcie_driver = {
.probe = mtk_pcie_probe,
+   .remove = mtk_pcie_remove,
.driver = {
.name = "mtk-pcie",
.of_match_table = mtk_pcie_ids,
@@ -1298,4 +1349,5 @@ static struct platform_driver mtk_pcie_driver = {
.pm = &mtk_pcie_pm_ops,
},
 };
-builtin_platform_driver(mtk_pcie_driver);
+module_platform_driver(mtk_pcie_driver);
+MODULE_LICENSE("GPL v2");
-- 
2.6.4



[PATCH v2 0/4] PCI: mediatek: fixup find_port, enable_msi and add pm, module support

2018-07-01 Thread honghui.zhang
From: Honghui Zhang 

This patchset includes misc patchs:

The first patch fixup the mtk_pcie_find_port logical which will cause system
could not touch the EP's configuration space which was connected to PCIe slot 1.

The second patch fixup the enable msi logical, the operation to enable msi
should be after system clock is enabled. The function of 
mtk_pcie_startup_port_v2's
define location is re-arranged to avoid mtk_pcie_enable_msi's forward 
declaration.
And call mtk_pcie_enable_msi in mtk_pcie_startup_port_v2 since the clock was all
enabled at that time.

The third patch was rebased and refactor of the v4 patch[1], changes are:
 -Add PM support for MT7622.
 -Using mtk_pcie_enable_port to re-establish the link when resumed.
 -Rebase on the previous two patches.

The fourth patch add loadable kernel module support.

Some of those patches was already reviewed-by Ryder Lee 
,
so I just add the Reviewed-by tags in those patches.

[1] https://patchwork.kernel.org/patch/10479079

Change since v1:
 - A bit of code refact of the first patch suggested by Andy Shevchenko, and
   commit message updated.
 - Using __maybe_unused.
 - Remove the redundant list_empty check of the fourth patch.

Honghui Zhang (4):
  PCI: mediatek: fixup mtk_pcie_find_port logical
  PCI: mediatek: enable msi after clock enabled
  PCI: mediatek: Add system pm support for MT2712 and MT7622
  PCI: mediatek: Add loadable kernel module support

 drivers/pci/controller/Kconfig |   2 +-
 drivers/pci/controller/pcie-mediatek.c | 289 -
 2 files changed, 213 insertions(+), 78 deletions(-)

-- 
2.6.4



[PATCH v2 3/4] PCI: mediatek: Add system pm support for MT2712 and MT7622

2018-07-01 Thread honghui.zhang
From: Honghui Zhang 

The MTCMOS of PCIe Host for MT2712 and MT7622 will be off when system
suspend, and all the internal control register will be reset after system
resume. The PCIe link should be re-established and the related control
register values should be re-set after system resume.

Signed-off-by: Honghui Zhang 
---
 drivers/pci/controller/pcie-mediatek.c | 67 ++
 1 file changed, 67 insertions(+)

diff --git a/drivers/pci/controller/pcie-mediatek.c 
b/drivers/pci/controller/pcie-mediatek.c
index 86918d4..c530539 100644
--- a/drivers/pci/controller/pcie-mediatek.c
+++ b/drivers/pci/controller/pcie-mediatek.c
@@ -134,12 +134,14 @@ struct mtk_pcie_port;
 /**
  * struct mtk_pcie_soc - differentiate between host generations
  * @need_fix_class_id: whether this host's class ID needed to be fixed or not
+ * @pm_support: whether the host's MTCMOS will be off when suspend
  * @ops: pointer to configuration access functions
  * @startup: pointer to controller setting functions
  * @setup_irq: pointer to initialize IRQ functions
  */
 struct mtk_pcie_soc {
bool need_fix_class_id;
+   bool pm_support;
struct pci_ops *ops;
int (*startup)(struct mtk_pcie_port *port);
int (*setup_irq)(struct mtk_pcie_port *port, struct device_node *node);
@@ -1197,12 +1199,75 @@ static int mtk_pcie_probe(struct platform_device *pdev)
return err;
 }
 
+static int __maybe_unused mtk_pcie_suspend_noirq(struct device *dev)
+{
+   struct mtk_pcie *pcie = dev_get_drvdata(dev);
+   const struct mtk_pcie_soc *soc = pcie->soc;
+   struct mtk_pcie_port *port;
+
+   if (!soc->pm_support)
+   return 0;
+
+   if (list_empty(&pcie->ports))
+   return 0;
+
+   list_for_each_entry(port, &pcie->ports, list) {
+   clk_disable_unprepare(port->pipe_ck);
+   clk_disable_unprepare(port->obff_ck);
+   clk_disable_unprepare(port->axi_ck);
+   clk_disable_unprepare(port->aux_ck);
+   clk_disable_unprepare(port->ahb_ck);
+   clk_disable_unprepare(port->sys_ck);
+   phy_power_off(port->phy);
+   phy_exit(port->phy);
+   }
+
+   mtk_pcie_subsys_powerdown(pcie);
+
+   return 0;
+}
+
+static int __maybe_unused mtk_pcie_resume_noirq(struct device *dev)
+{
+   struct mtk_pcie *pcie = dev_get_drvdata(dev);
+   const struct mtk_pcie_soc *soc = pcie->soc;
+   struct mtk_pcie_port *port;
+
+   if (!soc->pm_support)
+   return 0;
+
+   if (list_empty(&pcie->ports))
+   return 0;
+
+   if (dev->pm_domain) {
+   pm_runtime_enable(dev);
+   pm_runtime_get_sync(dev);
+   }
+
+   clk_prepare_enable(pcie->free_ck);
+
+   list_for_each_entry_safe(port, &pcie->ports, list)
+   mtk_pcie_enable_port(port);
+
+   /* In case of EP was removed while system suspend. */
+   if (list_empty(&pcie->ports))
+   mtk_pcie_subsys_powerdown(pcie);
+
+   return 0;
+}
+
+static const struct dev_pm_ops mtk_pcie_pm_ops = {
+   SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(mtk_pcie_suspend_noirq,
+ mtk_pcie_resume_noirq)
+};
+
 static const struct mtk_pcie_soc mtk_pcie_soc_v1 = {
.ops = &mtk_pcie_ops,
.startup = mtk_pcie_startup_port,
 };
 
 static const struct mtk_pcie_soc mtk_pcie_soc_mt2712 = {
+   .pm_support = true,
.ops = &mtk_pcie_ops_v2,
.startup = mtk_pcie_startup_port_v2,
.setup_irq = mtk_pcie_setup_irq,
@@ -1210,6 +1275,7 @@ static const struct mtk_pcie_soc mtk_pcie_soc_mt2712 = {
 
 static const struct mtk_pcie_soc mtk_pcie_soc_mt7622 = {
.need_fix_class_id = true,
+   .pm_support = true,
.ops = &mtk_pcie_ops_v2,
.startup = mtk_pcie_startup_port_v2,
.setup_irq = mtk_pcie_setup_irq,
@@ -1229,6 +1295,7 @@ static struct platform_driver mtk_pcie_driver = {
.name = "mtk-pcie",
.of_match_table = mtk_pcie_ids,
.suppress_bind_attrs = true,
+   .pm = &mtk_pcie_pm_ops,
},
 };
 builtin_platform_driver(mtk_pcie_driver);
-- 
2.6.4



[PATCH v3 4/4] PCI: mediatek: Add loadable kernel module support

2018-07-02 Thread honghui.zhang
From: Honghui Zhang 

Implement remove callback function for Mediatek PCIe driver to add
loadable kernel module support.

Signed-off-by: Honghui Zhang 
Reviewed-by: Ryder Lee 
---
 drivers/pci/controller/Kconfig |  2 +-
 drivers/pci/controller/pcie-mediatek.c | 60 +++---
 2 files changed, 57 insertions(+), 5 deletions(-)

diff --git a/drivers/pci/controller/Kconfig b/drivers/pci/controller/Kconfig
index 18fa09b..6c61ac65 100644
--- a/drivers/pci/controller/Kconfig
+++ b/drivers/pci/controller/Kconfig
@@ -234,7 +234,7 @@ config PCIE_ROCKCHIP_EP
  available to support GEN2 with 4 slots.
 
 config PCIE_MEDIATEK
-   bool "MediaTek PCIe controller"
+   tristate "MediaTek PCIe controller"
depends on ARCH_MEDIATEK || COMPILE_TEST
depends on OF
depends on PCI_MSI_IRQ_DOMAIN
diff --git a/drivers/pci/controller/pcie-mediatek.c 
b/drivers/pci/controller/pcie-mediatek.c
index 175d7b6..28730b8 100644
--- a/drivers/pci/controller/pcie-mediatek.c
+++ b/drivers/pci/controller/pcie-mediatek.c
@@ -15,6 +15,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -184,6 +185,7 @@ struct mtk_pcie_port {
struct phy *phy;
u32 lane;
u32 slot;
+   int irq;
struct irq_domain *irq_domain;
struct irq_domain *inner_domain;
struct irq_domain *msi_domain;
@@ -538,6 +540,27 @@ static void mtk_pcie_enable_msi(struct mtk_pcie_port *port)
writel(val, port->base + PCIE_INT_MASK);
 }
 
+static void mtk_pcie_irq_teardown(struct mtk_pcie *pcie)
+{
+   struct mtk_pcie_port *port, *tmp;
+
+   list_for_each_entry_safe(port, tmp, &pcie->ports, list) {
+   irq_set_chained_handler_and_data(port->irq, NULL, NULL);
+
+   if (port->irq_domain)
+   irq_domain_remove(port->irq_domain);
+
+   if (IS_ENABLED(CONFIG_PCI_MSI)) {
+   if (port->msi_domain)
+   irq_domain_remove(port->msi_domain);
+   if (port->inner_domain)
+   irq_domain_remove(port->inner_domain);
+   }
+
+   irq_dispose_mapping(port->irq);
+   }
+}
+
 static int mtk_pcie_intx_map(struct irq_domain *domain, unsigned int irq,
 irq_hw_number_t hwirq)
 {
@@ -628,7 +651,7 @@ static int mtk_pcie_setup_irq(struct mtk_pcie_port *port,
struct mtk_pcie *pcie = port->pcie;
struct device *dev = pcie->dev;
struct platform_device *pdev = to_platform_device(dev);
-   int err, irq;
+   int err;
 
err = mtk_pcie_init_irq_domain(port, node);
if (err) {
@@ -636,8 +659,9 @@ static int mtk_pcie_setup_irq(struct mtk_pcie_port *port,
return err;
}
 
-   irq = platform_get_irq(pdev, port->slot);
-   irq_set_chained_handler_and_data(irq, mtk_pcie_intr_handler, port);
+   port->irq = platform_get_irq(pdev, port->slot);
+   irq_set_chained_handler_and_data(port->irq,
+mtk_pcie_intr_handler, port);
 
return 0;
 }
@@ -1199,6 +1223,32 @@ static int mtk_pcie_probe(struct platform_device *pdev)
return err;
 }
 
+
+static void mtk_pcie_free_resources(struct mtk_pcie *pcie)
+{
+   struct pci_host_bridge *host = pci_host_bridge_from_priv(pcie);
+   struct list_head *windows = &host->windows;
+
+   pci_unmap_iospace(&pcie->pio);
+   pci_free_resource_list(windows);
+}
+
+static int mtk_pcie_remove(struct platform_device *pdev)
+{
+   struct mtk_pcie *pcie = platform_get_drvdata(pdev);
+   struct pci_host_bridge *host = pci_host_bridge_from_priv(pcie);
+
+   pci_stop_root_bus(host->bus);
+   pci_remove_root_bus(host->bus);
+   mtk_pcie_free_resources(pcie);
+
+   mtk_pcie_irq_teardown(pcie);
+
+   mtk_pcie_put_resources(pcie);
+
+   return 0;
+}
+
 static int __maybe_unused mtk_pcie_suspend_noirq(struct device *dev)
 {
struct mtk_pcie *pcie = dev_get_drvdata(dev);
@@ -1291,6 +1341,7 @@ static const struct of_device_id mtk_pcie_ids[] = {
 
 static struct platform_driver mtk_pcie_driver = {
.probe = mtk_pcie_probe,
+   .remove = mtk_pcie_remove,
.driver = {
.name = "mtk-pcie",
.of_match_table = mtk_pcie_ids,
@@ -1298,4 +1349,5 @@ static struct platform_driver mtk_pcie_driver = {
.pm = &mtk_pcie_pm_ops,
},
 };
-builtin_platform_driver(mtk_pcie_driver);
+module_platform_driver(mtk_pcie_driver);
+MODULE_LICENSE("GPL v2");
-- 
2.6.4



[PATCH v3 0/4] PCI: mediatek: fixup find_port, enable_msi and add pm, module support

2018-07-02 Thread honghui.zhang
From: Honghui Zhang 

This patchset includes misc patchs:

The first patch fixup the mtk_pcie_find_port logical which will cause system
could not touch the EP's configuration space which was connected to PCIe slot 1.

The second patch fixup the enable msi logical, the operation to enable msi
should be after system clock is enabled. The function of 
mtk_pcie_startup_port_v2's
define location is re-arranged to avoid mtk_pcie_enable_msi's forward 
declaration.
And call mtk_pcie_enable_msi in mtk_pcie_startup_port_v2 since the clock was all
enabled at that time.

The third patch was rebased and refactor of the v4 patch[1], changes are:
 -Add PM support for MT7622.
 -Using mtk_pcie_enable_port to re-establish the link when resumed.
 -Rebase on the previous two patches.

The fourth patch add loadable kernel module support.

Some of those patches was already reviewed-by Ryder Lee 
,
so I just add the Reviewed-by tags in those patches.

[1] https://patchwork.kernel.org/patch/10479079

Change since v2:
 - Fix the list_for_each_entry_safe parameter error.
 - Add Ryder's Acked-by flag.

Change since v1:
 - A bit of code refact of the first patch suggested by Andy Shevchenko, and
   commit message updated.
 - Using __maybe_unused.
 - Remove the redundant list_empty check of the fourth patch.

Honghui Zhang (4):
  PCI: mediatek: fixup mtk_pcie_find_port logical
  PCI: mediatek: enable msi after clock enabled
  PCI: mediatek: Add system pm support for MT2712 and MT7622
  PCI: mediatek: Add loadable kernel module support

 drivers/pci/controller/Kconfig |   2 +-
 drivers/pci/controller/pcie-mediatek.c | 289 -
 2 files changed, 213 insertions(+), 78 deletions(-)

-- 
2.6.4



[PATCH v3 1/4] PCI: mediatek: fixup mtk_pcie_find_port logical

2018-07-02 Thread honghui.zhang
From: Honghui Zhang 

The Mediatek's host controller has two slots, each with it's own control
registers. The host driver need to identify which slot was connected
in order to access the device's configuration space. There's problem
for current host driver to find out which slot was connected to for
a given EP device.

Assuming each slot have connect with one EP device as below:

host bridge
  bus 0 --> __|___
   |  |
   |  |
 slot 0 slot 1
  bus 1 -->|bus 2 --> |
   |  |
 EP 0   EP 1

During PCI enumeration, system software will scan all the PCI device
starting from devfn 0. So it will get the proper port for slot0 and
slot1 device when using PCI_SLOT(devfn) for match. But it will get
the wrong slot for EP1: The devfn will be start from 0 when scanning
EP1 behind slot1, it will get port0 since the PCI_SLOT(EP1) is match
for port0's slot value. So the host driver should not using EP's devfn
but the slot's devfn(the slot which EP was connected to) for match.

This patch fix the mtk_pcie_find_port's logical by using the slot's
devfn for match.

Signed-off-by: Honghui Zhang 
Acked-by: Ryder Lee 
---
 drivers/pci/controller/pcie-mediatek.c | 19 +--
 1 file changed, 17 insertions(+), 2 deletions(-)

diff --git a/drivers/pci/controller/pcie-mediatek.c 
b/drivers/pci/controller/pcie-mediatek.c
index 0baabe3..b43f41d 100644
--- a/drivers/pci/controller/pcie-mediatek.c
+++ b/drivers/pci/controller/pcie-mediatek.c
@@ -337,11 +337,26 @@ static struct mtk_pcie_port *mtk_pcie_find_port(struct 
pci_bus *bus,
 {
struct mtk_pcie *pcie = bus->sysdata;
struct mtk_pcie_port *port;
+   struct pci_dev *dev;
+   struct pci_bus *pbus;
 
-   list_for_each_entry(port, &pcie->ports, list)
-   if (port->slot == PCI_SLOT(devfn))
+   list_for_each_entry(port, &pcie->ports, list) {
+   if (!bus->number && port->slot == PCI_SLOT(devfn))
return port;
 
+   if (bus->number) {
+   pbus = bus;
+
+   while (pbus->number) {
+   dev = pbus->self;
+   pbus = dev->bus;
+   }
+
+   if (port->slot == PCI_SLOT(dev->devfn))
+   return port;
+   }
+   }
+
return NULL;
 }
 
-- 
2.6.4



[PATCH v3 3/4] PCI: mediatek: Add system pm support for MT2712 and MT7622

2018-07-02 Thread honghui.zhang
From: Honghui Zhang 

The MTCMOS of PCIe Host for MT2712 and MT7622 will be off when system
suspend, and all the internal control register will be reset after system
resume. The PCIe link should be re-established and the related control
register values should be re-set after system resume.

Signed-off-by: Honghui Zhang 
Acked-by: Ryder Lee 
---
 drivers/pci/controller/pcie-mediatek.c | 67 ++
 1 file changed, 67 insertions(+)

diff --git a/drivers/pci/controller/pcie-mediatek.c 
b/drivers/pci/controller/pcie-mediatek.c
index 86918d4..175d7b6 100644
--- a/drivers/pci/controller/pcie-mediatek.c
+++ b/drivers/pci/controller/pcie-mediatek.c
@@ -134,12 +134,14 @@ struct mtk_pcie_port;
 /**
  * struct mtk_pcie_soc - differentiate between host generations
  * @need_fix_class_id: whether this host's class ID needed to be fixed or not
+ * @pm_support: whether the host's MTCMOS will be off when suspend
  * @ops: pointer to configuration access functions
  * @startup: pointer to controller setting functions
  * @setup_irq: pointer to initialize IRQ functions
  */
 struct mtk_pcie_soc {
bool need_fix_class_id;
+   bool pm_support;
struct pci_ops *ops;
int (*startup)(struct mtk_pcie_port *port);
int (*setup_irq)(struct mtk_pcie_port *port, struct device_node *node);
@@ -1197,12 +1199,75 @@ static int mtk_pcie_probe(struct platform_device *pdev)
return err;
 }
 
+static int __maybe_unused mtk_pcie_suspend_noirq(struct device *dev)
+{
+   struct mtk_pcie *pcie = dev_get_drvdata(dev);
+   const struct mtk_pcie_soc *soc = pcie->soc;
+   struct mtk_pcie_port *port;
+
+   if (!soc->pm_support)
+   return 0;
+
+   if (list_empty(&pcie->ports))
+   return 0;
+
+   list_for_each_entry(port, &pcie->ports, list) {
+   clk_disable_unprepare(port->pipe_ck);
+   clk_disable_unprepare(port->obff_ck);
+   clk_disable_unprepare(port->axi_ck);
+   clk_disable_unprepare(port->aux_ck);
+   clk_disable_unprepare(port->ahb_ck);
+   clk_disable_unprepare(port->sys_ck);
+   phy_power_off(port->phy);
+   phy_exit(port->phy);
+   }
+
+   mtk_pcie_subsys_powerdown(pcie);
+
+   return 0;
+}
+
+static int __maybe_unused mtk_pcie_resume_noirq(struct device *dev)
+{
+   struct mtk_pcie *pcie = dev_get_drvdata(dev);
+   const struct mtk_pcie_soc *soc = pcie->soc;
+   struct mtk_pcie_port *port, *tmp;
+
+   if (!soc->pm_support)
+   return 0;
+
+   if (list_empty(&pcie->ports))
+   return 0;
+
+   if (dev->pm_domain) {
+   pm_runtime_enable(dev);
+   pm_runtime_get_sync(dev);
+   }
+
+   clk_prepare_enable(pcie->free_ck);
+
+   list_for_each_entry_safe(port, tmp, &pcie->ports, list)
+   mtk_pcie_enable_port(port);
+
+   /* In case of EP was removed while system suspend. */
+   if (list_empty(&pcie->ports))
+   mtk_pcie_subsys_powerdown(pcie);
+
+   return 0;
+}
+
+static const struct dev_pm_ops mtk_pcie_pm_ops = {
+   SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(mtk_pcie_suspend_noirq,
+ mtk_pcie_resume_noirq)
+};
+
 static const struct mtk_pcie_soc mtk_pcie_soc_v1 = {
.ops = &mtk_pcie_ops,
.startup = mtk_pcie_startup_port,
 };
 
 static const struct mtk_pcie_soc mtk_pcie_soc_mt2712 = {
+   .pm_support = true,
.ops = &mtk_pcie_ops_v2,
.startup = mtk_pcie_startup_port_v2,
.setup_irq = mtk_pcie_setup_irq,
@@ -1210,6 +1275,7 @@ static const struct mtk_pcie_soc mtk_pcie_soc_mt2712 = {
 
 static const struct mtk_pcie_soc mtk_pcie_soc_mt7622 = {
.need_fix_class_id = true,
+   .pm_support = true,
.ops = &mtk_pcie_ops_v2,
.startup = mtk_pcie_startup_port_v2,
.setup_irq = mtk_pcie_setup_irq,
@@ -1229,6 +1295,7 @@ static struct platform_driver mtk_pcie_driver = {
.name = "mtk-pcie",
.of_match_table = mtk_pcie_ids,
.suppress_bind_attrs = true,
+   .pm = &mtk_pcie_pm_ops,
},
 };
 builtin_platform_driver(mtk_pcie_driver);
-- 
2.6.4



[PATCH v3 2/4] PCI: mediatek: enable msi after clock enabled

2018-07-02 Thread honghui.zhang
From: Honghui Zhang 

The clocks was not enabled when enable MSI. This patch fix this
issue by calling mtk_pcie_enable_msi in mtk_pcie_startup_port_v2
since the clock was all enabled at that time.

The function of mtk_pcie_startup_port_v2's define location is
re-arranged to avoid mtk_pcie_enable_msi's forward declaration.

Signed-off-by: Honghui Zhang 
Reviewed-by: Ryder Lee 
---
 drivers/pci/controller/pcie-mediatek.c | 143 +
 1 file changed, 72 insertions(+), 71 deletions(-)

diff --git a/drivers/pci/controller/pcie-mediatek.c 
b/drivers/pci/controller/pcie-mediatek.c
index b43f41d..86918d4 100644
--- a/drivers/pci/controller/pcie-mediatek.c
+++ b/drivers/pci/controller/pcie-mediatek.c
@@ -398,75 +398,6 @@ static struct pci_ops mtk_pcie_ops_v2 = {
.write = mtk_pcie_config_write,
 };
 
-static int mtk_pcie_startup_port_v2(struct mtk_pcie_port *port)
-{
-   struct mtk_pcie *pcie = port->pcie;
-   struct resource *mem = &pcie->mem;
-   const struct mtk_pcie_soc *soc = port->pcie->soc;
-   u32 val;
-   size_t size;
-   int err;
-
-   /* MT7622 platforms need to enable LTSSM and ASPM from PCIe subsys */
-   if (pcie->base) {
-   val = readl(pcie->base + PCIE_SYS_CFG_V2);
-   val |= PCIE_CSR_LTSSM_EN(port->slot) |
-  PCIE_CSR_ASPM_L1_EN(port->slot);
-   writel(val, pcie->base + PCIE_SYS_CFG_V2);
-   }
-
-   /* Assert all reset signals */
-   writel(0, port->base + PCIE_RST_CTRL);
-
-   /*
-* Enable PCIe link down reset, if link status changed from link up to
-* link down, this will reset MAC control registers and configuration
-* space.
-*/
-   writel(PCIE_LINKDOWN_RST_EN, port->base + PCIE_RST_CTRL);
-
-   /* De-assert PHY, PE, PIPE, MAC and configuration reset */
-   val = readl(port->base + PCIE_RST_CTRL);
-   val |= PCIE_PHY_RSTB | PCIE_PERSTB | PCIE_PIPE_SRSTB |
-  PCIE_MAC_SRSTB | PCIE_CRSTB;
-   writel(val, port->base + PCIE_RST_CTRL);
-
-   /* Set up vendor ID and class code */
-   if (soc->need_fix_class_id) {
-   val = PCI_VENDOR_ID_MEDIATEK;
-   writew(val, port->base + PCIE_CONF_VEND_ID);
-
-   val = PCI_CLASS_BRIDGE_HOST;
-   writew(val, port->base + PCIE_CONF_CLASS_ID);
-   }
-
-   /* 100ms timeout value should be enough for Gen1/2 training */
-   err = readl_poll_timeout(port->base + PCIE_LINK_STATUS_V2, val,
-!!(val & PCIE_PORT_LINKUP_V2), 20,
-100 * USEC_PER_MSEC);
-   if (err)
-   return -ETIMEDOUT;
-
-   /* Set INTx mask */
-   val = readl(port->base + PCIE_INT_MASK);
-   val &= ~INTX_MASK;
-   writel(val, port->base + PCIE_INT_MASK);
-
-   /* Set AHB to PCIe translation windows */
-   size = mem->end - mem->start;
-   val = lower_32_bits(mem->start) | AHB2PCIE_SIZE(fls(size));
-   writel(val, port->base + PCIE_AHB_TRANS_BASE0_L);
-
-   val = upper_32_bits(mem->start);
-   writel(val, port->base + PCIE_AHB_TRANS_BASE0_H);
-
-   /* Set PCIe to AXI translation memory space.*/
-   val = fls(0x) | WIN_ENABLE;
-   writel(val, port->base + PCIE_AXI_WINDOW0);
-
-   return 0;
-}
-
 static void mtk_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
 {
struct mtk_pcie_port *port = irq_data_get_irq_chip_data(data);
@@ -643,8 +574,6 @@ static int mtk_pcie_init_irq_domain(struct mtk_pcie_port 
*port,
ret = mtk_pcie_allocate_msi_domains(port);
if (ret)
return ret;
-
-   mtk_pcie_enable_msi(port);
}
 
return 0;
@@ -711,6 +640,78 @@ static int mtk_pcie_setup_irq(struct mtk_pcie_port *port,
return 0;
 }
 
+static int mtk_pcie_startup_port_v2(struct mtk_pcie_port *port)
+{
+   struct mtk_pcie *pcie = port->pcie;
+   struct resource *mem = &pcie->mem;
+   const struct mtk_pcie_soc *soc = port->pcie->soc;
+   u32 val;
+   size_t size;
+   int err;
+
+   /* MT7622 platforms need to enable LTSSM and ASPM from PCIe subsys */
+   if (pcie->base) {
+   val = readl(pcie->base + PCIE_SYS_CFG_V2);
+   val |= PCIE_CSR_LTSSM_EN(port->slot) |
+  PCIE_CSR_ASPM_L1_EN(port->slot);
+   writel(val, pcie->base + PCIE_SYS_CFG_V2);
+   }
+
+   /* Assert all reset signals */
+   writel(0, port->base + PCIE_RST_CTRL);
+
+   /*
+* Enable PCIe link down reset, if link status changed from link up to
+* link down, this will reset MAC control registers and configuration
+* space.
+*/
+   writel(PCIE_LINKDOWN_RST_EN, port->base + PCIE_RST_CTRL);
+
+   /* De-assert PHY, PE, PIPE, MAC and configuration reset */
+   val = readl(port->base + PCIE_RST_CTRL);
+   val |= PCIE_

[PATCH 0/4] PCI: mediatek: fixup find_port, enable_msi and add pm, module support

2018-06-27 Thread honghui.zhang
From: Honghui Zhang 

This patchset includes misc patchs:

The first patch fixup the mtk_pcie_find_port logical which will cause system
could not touch the EP's configuration space which was connected to PCIe slot 1.

The second patch fixup the enable msi logical, the operation to enable msi
should be after system clock is enabled. The function of 
mtk_pcie_startup_port_v2's
define location is re-arranged to avoid mtk_pcie_enable_msi's forward 
declaration.
And call mtk_pcie_enable_msi in mtk_pcie_startup_port_v2 since the clock was all
enabled at that time.

The third patch was rebased and refactor of the v4 patch[1], changes are:
 -Add PM support for MT7622.
 -Using mtk_pcie_enable_port to re-establish the link when resumed.
 -Rebase on the previous two patches.

The fourth patch add loadable kernel module support.

Those patches was already reviewed-by Ryder Lee  so
I just add the Reviewed-by tags in those patches.

[1] https://patchwork.kernel.org/patch/10479079

Honghui Zhang (4):
  PCI: mediatek: fixup mtk_pcie_find_port logical
  PCI: mediatek: enable msi after clock enabled
  PCI: mediatek: Add system pm support for MT2712 and MT7622
  PCI: mediatek: Add loadable kernel module support

 drivers/pci/controller/Kconfig |   2 +-
 drivers/pci/controller/pcie-mediatek.c | 291 -
 2 files changed, 215 insertions(+), 78 deletions(-)

-- 
2.6.4



[PATCH 2/4] PCI: mediatek: enable msi after clock enabled

2018-06-27 Thread honghui.zhang
From: Honghui Zhang 

The clocks was not enabled when enable MSI. This patch fix this
issue by calling mtk_pcie_enable_msi in mtk_pcie_startup_port_v2
since the clock was all enabled at that time.

The function of mtk_pcie_startup_port_v2's define location is
re-arranged to avoid mtk_pcie_enable_msi's forward declaration.

Signed-off-by: Honghui Zhang 
Reviewed-by: Ryder Lee 
---
 drivers/pci/controller/pcie-mediatek.c | 143 +
 1 file changed, 72 insertions(+), 71 deletions(-)

diff --git a/drivers/pci/controller/pcie-mediatek.c 
b/drivers/pci/controller/pcie-mediatek.c
index 9cf7ecf..17bf99b 100644
--- a/drivers/pci/controller/pcie-mediatek.c
+++ b/drivers/pci/controller/pcie-mediatek.c
@@ -396,75 +396,6 @@ static struct pci_ops mtk_pcie_ops_v2 = {
.write = mtk_pcie_config_write,
 };
 
-static int mtk_pcie_startup_port_v2(struct mtk_pcie_port *port)
-{
-   struct mtk_pcie *pcie = port->pcie;
-   struct resource *mem = &pcie->mem;
-   const struct mtk_pcie_soc *soc = port->pcie->soc;
-   u32 val;
-   size_t size;
-   int err;
-
-   /* MT7622 platforms need to enable LTSSM and ASPM from PCIe subsys */
-   if (pcie->base) {
-   val = readl(pcie->base + PCIE_SYS_CFG_V2);
-   val |= PCIE_CSR_LTSSM_EN(port->slot) |
-  PCIE_CSR_ASPM_L1_EN(port->slot);
-   writel(val, pcie->base + PCIE_SYS_CFG_V2);
-   }
-
-   /* Assert all reset signals */
-   writel(0, port->base + PCIE_RST_CTRL);
-
-   /*
-* Enable PCIe link down reset, if link status changed from link up to
-* link down, this will reset MAC control registers and configuration
-* space.
-*/
-   writel(PCIE_LINKDOWN_RST_EN, port->base + PCIE_RST_CTRL);
-
-   /* De-assert PHY, PE, PIPE, MAC and configuration reset */
-   val = readl(port->base + PCIE_RST_CTRL);
-   val |= PCIE_PHY_RSTB | PCIE_PERSTB | PCIE_PIPE_SRSTB |
-  PCIE_MAC_SRSTB | PCIE_CRSTB;
-   writel(val, port->base + PCIE_RST_CTRL);
-
-   /* Set up vendor ID and class code */
-   if (soc->need_fix_class_id) {
-   val = PCI_VENDOR_ID_MEDIATEK;
-   writew(val, port->base + PCIE_CONF_VEND_ID);
-
-   val = PCI_CLASS_BRIDGE_HOST;
-   writew(val, port->base + PCIE_CONF_CLASS_ID);
-   }
-
-   /* 100ms timeout value should be enough for Gen1/2 training */
-   err = readl_poll_timeout(port->base + PCIE_LINK_STATUS_V2, val,
-!!(val & PCIE_PORT_LINKUP_V2), 20,
-100 * USEC_PER_MSEC);
-   if (err)
-   return -ETIMEDOUT;
-
-   /* Set INTx mask */
-   val = readl(port->base + PCIE_INT_MASK);
-   val &= ~INTX_MASK;
-   writel(val, port->base + PCIE_INT_MASK);
-
-   /* Set AHB to PCIe translation windows */
-   size = mem->end - mem->start;
-   val = lower_32_bits(mem->start) | AHB2PCIE_SIZE(fls(size));
-   writel(val, port->base + PCIE_AHB_TRANS_BASE0_L);
-
-   val = upper_32_bits(mem->start);
-   writel(val, port->base + PCIE_AHB_TRANS_BASE0_H);
-
-   /* Set PCIe to AXI translation memory space.*/
-   val = fls(0x) | WIN_ENABLE;
-   writel(val, port->base + PCIE_AXI_WINDOW0);
-
-   return 0;
-}
-
 static void mtk_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
 {
struct mtk_pcie_port *port = irq_data_get_irq_chip_data(data);
@@ -641,8 +572,6 @@ static int mtk_pcie_init_irq_domain(struct mtk_pcie_port 
*port,
ret = mtk_pcie_allocate_msi_domains(port);
if (ret)
return ret;
-
-   mtk_pcie_enable_msi(port);
}
 
return 0;
@@ -709,6 +638,78 @@ static int mtk_pcie_setup_irq(struct mtk_pcie_port *port,
return 0;
 }
 
+static int mtk_pcie_startup_port_v2(struct mtk_pcie_port *port)
+{
+   struct mtk_pcie *pcie = port->pcie;
+   struct resource *mem = &pcie->mem;
+   const struct mtk_pcie_soc *soc = port->pcie->soc;
+   u32 val;
+   size_t size;
+   int err;
+
+   /* MT7622 platforms need to enable LTSSM and ASPM from PCIe subsys */
+   if (pcie->base) {
+   val = readl(pcie->base + PCIE_SYS_CFG_V2);
+   val |= PCIE_CSR_LTSSM_EN(port->slot) |
+  PCIE_CSR_ASPM_L1_EN(port->slot);
+   writel(val, pcie->base + PCIE_SYS_CFG_V2);
+   }
+
+   /* Assert all reset signals */
+   writel(0, port->base + PCIE_RST_CTRL);
+
+   /*
+* Enable PCIe link down reset, if link status changed from link up to
+* link down, this will reset MAC control registers and configuration
+* space.
+*/
+   writel(PCIE_LINKDOWN_RST_EN, port->base + PCIE_RST_CTRL);
+
+   /* De-assert PHY, PE, PIPE, MAC and configuration reset */
+   val = readl(port->base + PCIE_RST_CTRL);
+   val |= PCIE_

[PATCH 3/4] PCI: mediatek: Add system pm support for MT2712 and MT7622

2018-06-27 Thread honghui.zhang
From: Honghui Zhang 

The MTCMOS of PCIe Host for MT2712 and MT7622 will be off when system
suspend, and all the internal control register will be reset after system
resume. The PCIe link should be re-established and the related control
register values should be re-set after system resume.

Signed-off-by: Honghui Zhang 
Reviewed-by: Ryder Lee 
---
 drivers/pci/controller/pcie-mediatek.c | 68 ++
 1 file changed, 68 insertions(+)

diff --git a/drivers/pci/controller/pcie-mediatek.c 
b/drivers/pci/controller/pcie-mediatek.c
index 17bf99b..cac01ab 100644
--- a/drivers/pci/controller/pcie-mediatek.c
+++ b/drivers/pci/controller/pcie-mediatek.c
@@ -134,12 +134,14 @@ struct mtk_pcie_port;
 /**
  * struct mtk_pcie_soc - differentiate between host generations
  * @need_fix_class_id: whether this host's class ID needed to be fixed or not
+ * @pm_support: whether the host's MTCMOS will be off when suspend
  * @ops: pointer to configuration access functions
  * @startup: pointer to controller setting functions
  * @setup_irq: pointer to initialize IRQ functions
  */
 struct mtk_pcie_soc {
bool need_fix_class_id;
+   bool pm_support;
struct pci_ops *ops;
int (*startup)(struct mtk_pcie_port *port);
int (*setup_irq)(struct mtk_pcie_port *port, struct device_node *node);
@@ -1195,12 +1197,76 @@ static int mtk_pcie_probe(struct platform_device *pdev)
return err;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int mtk_pcie_suspend_noirq(struct device *dev)
+{
+   struct mtk_pcie *pcie = dev_get_drvdata(dev);
+   const struct mtk_pcie_soc *soc = pcie->soc;
+   struct mtk_pcie_port *port;
+
+   if (!soc->pm_support)
+   return 0;
+
+   if (list_empty(&pcie->ports))
+   return 0;
+
+   list_for_each_entry(port, &pcie->ports, list) {
+   clk_disable_unprepare(port->pipe_ck);
+   clk_disable_unprepare(port->obff_ck);
+   clk_disable_unprepare(port->axi_ck);
+   clk_disable_unprepare(port->aux_ck);
+   clk_disable_unprepare(port->ahb_ck);
+   clk_disable_unprepare(port->sys_ck);
+   phy_power_off(port->phy);
+   phy_exit(port->phy);
+   }
+
+   mtk_pcie_subsys_powerdown(pcie);
+
+   return 0;
+}
+
+static int mtk_pcie_resume_noirq(struct device *dev)
+{
+   struct mtk_pcie *pcie = dev_get_drvdata(dev);
+   const struct mtk_pcie_soc *soc = pcie->soc;
+   struct mtk_pcie_port *port;
+
+   if (!soc->pm_support)
+   return 0;
+
+   if (list_empty(&pcie->ports))
+   return 0;
+
+   if (dev->pm_domain) {
+   pm_runtime_enable(dev);
+   pm_runtime_get_sync(dev);
+   }
+
+   clk_prepare_enable(pcie->free_ck);
+
+   list_for_each_entry(port, &pcie->ports, list)
+   mtk_pcie_enable_port(port);
+
+   if (list_empty(&pcie->ports))
+   mtk_pcie_subsys_powerdown(pcie);
+
+   return 0;
+}
+#endif
+
+static const struct dev_pm_ops mtk_pcie_pm_ops = {
+   SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(mtk_pcie_suspend_noirq,
+ mtk_pcie_resume_noirq)
+};
+
 static const struct mtk_pcie_soc mtk_pcie_soc_v1 = {
.ops = &mtk_pcie_ops,
.startup = mtk_pcie_startup_port,
 };
 
 static const struct mtk_pcie_soc mtk_pcie_soc_mt2712 = {
+   .pm_support = true,
.ops = &mtk_pcie_ops_v2,
.startup = mtk_pcie_startup_port_v2,
.setup_irq = mtk_pcie_setup_irq,
@@ -1208,6 +1274,7 @@ static const struct mtk_pcie_soc mtk_pcie_soc_mt2712 = {
 
 static const struct mtk_pcie_soc mtk_pcie_soc_mt7622 = {
.need_fix_class_id = true,
+   .pm_support = true,
.ops = &mtk_pcie_ops_v2,
.startup = mtk_pcie_startup_port_v2,
.setup_irq = mtk_pcie_setup_irq,
@@ -1227,6 +1294,7 @@ static struct platform_driver mtk_pcie_driver = {
.name = "mtk-pcie",
.of_match_table = mtk_pcie_ids,
.suppress_bind_attrs = true,
+   .pm = &mtk_pcie_pm_ops,
},
 };
 builtin_platform_driver(mtk_pcie_driver);
-- 
2.6.4



[PATCH 4/4] PCI: mediatek: Add loadable kernel module support

2018-06-27 Thread honghui.zhang
From: Honghui Zhang 

Implement remove callback function for Mediatek PCIe driver to add
loadable kernel module support.

Signed-off-by: Honghui Zhang 
Reviewed-by: Ryder Lee 
---
 drivers/pci/controller/Kconfig |  2 +-
 drivers/pci/controller/pcie-mediatek.c | 63 +++---
 2 files changed, 60 insertions(+), 5 deletions(-)

diff --git a/drivers/pci/controller/Kconfig b/drivers/pci/controller/Kconfig
index 18fa09b..6c61ac65 100644
--- a/drivers/pci/controller/Kconfig
+++ b/drivers/pci/controller/Kconfig
@@ -234,7 +234,7 @@ config PCIE_ROCKCHIP_EP
  available to support GEN2 with 4 slots.
 
 config PCIE_MEDIATEK
-   bool "MediaTek PCIe controller"
+   tristate "MediaTek PCIe controller"
depends on ARCH_MEDIATEK || COMPILE_TEST
depends on OF
depends on PCI_MSI_IRQ_DOMAIN
diff --git a/drivers/pci/controller/pcie-mediatek.c 
b/drivers/pci/controller/pcie-mediatek.c
index cac01ab..5830cea 100644
--- a/drivers/pci/controller/pcie-mediatek.c
+++ b/drivers/pci/controller/pcie-mediatek.c
@@ -15,6 +15,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -184,6 +185,7 @@ struct mtk_pcie_port {
struct phy *phy;
u32 lane;
u32 slot;
+   int irq;
struct irq_domain *irq_domain;
struct irq_domain *inner_domain;
struct irq_domain *msi_domain;
@@ -536,6 +538,30 @@ static void mtk_pcie_enable_msi(struct mtk_pcie_port *port)
writel(val, port->base + PCIE_INT_MASK);
 }
 
+static void mtk_pcie_irq_teardown(struct mtk_pcie *pcie)
+{
+   struct mtk_pcie_port *port, *tmp;
+
+   if (list_empty(&pcie->ports))
+   return;
+
+   list_for_each_entry_safe(port, tmp, &pcie->ports, list) {
+   irq_set_chained_handler_and_data(port->irq, NULL, NULL);
+
+   if (port->irq_domain)
+   irq_domain_remove(port->irq_domain);
+
+   if (IS_ENABLED(CONFIG_PCI_MSI)) {
+   if (port->msi_domain)
+   irq_domain_remove(port->msi_domain);
+   if (port->inner_domain)
+   irq_domain_remove(port->inner_domain);
+   }
+
+   irq_dispose_mapping(port->irq);
+   }
+}
+
 static int mtk_pcie_intx_map(struct irq_domain *domain, unsigned int irq,
 irq_hw_number_t hwirq)
 {
@@ -626,7 +652,7 @@ static int mtk_pcie_setup_irq(struct mtk_pcie_port *port,
struct mtk_pcie *pcie = port->pcie;
struct device *dev = pcie->dev;
struct platform_device *pdev = to_platform_device(dev);
-   int err, irq;
+   int err;
 
err = mtk_pcie_init_irq_domain(port, node);
if (err) {
@@ -634,8 +660,9 @@ static int mtk_pcie_setup_irq(struct mtk_pcie_port *port,
return err;
}
 
-   irq = platform_get_irq(pdev, port->slot);
-   irq_set_chained_handler_and_data(irq, mtk_pcie_intr_handler, port);
+   port->irq = platform_get_irq(pdev, port->slot);
+   irq_set_chained_handler_and_data(port->irq,
+mtk_pcie_intr_handler, port);
 
return 0;
 }
@@ -1197,6 +1224,32 @@ static int mtk_pcie_probe(struct platform_device *pdev)
return err;
 }
 
+static void mtk_pcie_free_resources(struct mtk_pcie *pcie)
+{
+   struct pci_host_bridge *host = pci_host_bridge_from_priv(pcie);
+   struct list_head *windows = &host->windows;
+
+   pci_unmap_iospace(&pcie->pio);
+   pci_free_resource_list(windows);
+}
+
+static int mtk_pcie_remove(struct platform_device *pdev)
+{
+   struct mtk_pcie *pcie = platform_get_drvdata(pdev);
+   struct pci_host_bridge *host = pci_host_bridge_from_priv(pcie);
+
+   pci_stop_root_bus(host->bus);
+   pci_remove_root_bus(host->bus);
+   mtk_pcie_free_resources(pcie);
+
+   mtk_pcie_irq_teardown(pcie);
+
+   if (!list_empty(&pcie->ports))
+   mtk_pcie_put_resources(pcie);
+
+   return 0;
+}
+
 #ifdef CONFIG_PM_SLEEP
 static int mtk_pcie_suspend_noirq(struct device *dev)
 {
@@ -1290,6 +1343,7 @@ static const struct of_device_id mtk_pcie_ids[] = {
 
 static struct platform_driver mtk_pcie_driver = {
.probe = mtk_pcie_probe,
+   .remove = mtk_pcie_remove,
.driver = {
.name = "mtk-pcie",
.of_match_table = mtk_pcie_ids,
@@ -1297,4 +1351,5 @@ static struct platform_driver mtk_pcie_driver = {
.pm = &mtk_pcie_pm_ops,
},
 };
-builtin_platform_driver(mtk_pcie_driver);
+module_platform_driver(mtk_pcie_driver);
+MODULE_LICENSE("GPL v2");
-- 
2.6.4



[PATCH 1/4] PCI: mediatek: fixup mtk_pcie_find_port logical

2018-06-27 Thread honghui.zhang
From: Honghui Zhang 

Mediatek's host controller have two slots, each have it's own control
registers. The host driver need to identify which slot was connected
in order to access the device's configuration space. There's problem
for current host driver to find out which slot was connected to for
a given EP device.

Assuming each slot have connect with one EP device as below:

host bridge
  bus 0 --> __|___
   |  |
   |  |
 slot 0 slot 1
  bus 1 -->|bus 2 --> |
   |  |
 EP 0   EP 1

While PCI emulation, system software will scan all the PCI device
starting from devfn 0. So it will get the proper port for slot0 and
slot1 device when using PCI_SLOT(devfn) for match. But it will get
the wrong slot for EP1: The devfn will be start from 0 when scanning
EP1 behind slot1, it will get port0 since the PCI_SLOT(EP1) is match
for port0's slot value. So the host driver should not using EP's devfn
but the slot's devfn(the slot which EP was connected to) for match.

This patch fix the mtk_pcie_find_port's logical by using the slot's
devfn for match.

Signed-off-by: Honghui Zhang 
Reviewed-by: Ryder Lee 
---
 drivers/pci/controller/pcie-mediatek.c | 17 +++--
 1 file changed, 15 insertions(+), 2 deletions(-)

diff --git a/drivers/pci/controller/pcie-mediatek.c 
b/drivers/pci/controller/pcie-mediatek.c
index 0baabe3..9cf7ecf 100644
--- a/drivers/pci/controller/pcie-mediatek.c
+++ b/drivers/pci/controller/pcie-mediatek.c
@@ -337,10 +337,23 @@ static struct mtk_pcie_port *mtk_pcie_find_port(struct 
pci_bus *bus,
 {
struct mtk_pcie *pcie = bus->sysdata;
struct mtk_pcie_port *port;
+   struct pci_dev *dev;
+   struct pci_bus *pbus;
 
-   list_for_each_entry(port, &pcie->ports, list)
-   if (port->slot == PCI_SLOT(devfn))
+   list_for_each_entry(port, &pcie->ports, list) {
+   if (bus->number == 0 && port->slot == PCI_SLOT(devfn)) {
return port;
+   } else if (bus->number != 0) {
+   pbus = bus;
+   do {
+   dev = pbus->self;
+   if (port->slot == PCI_SLOT(dev->devfn))
+   return port;
+
+   pbus = dev->bus;
+   } while (dev->bus->number != 0);
+   }
+   }
 
return NULL;
 }
-- 
2.6.4



[PATCH v2] PCI: mediatek: Add system pm support for MT2712

2018-05-31 Thread honghui.zhang
From: Honghui Zhang 

The MTCMOS of PCIe Host for MT2712 will be off when system suspend, and all
the internal control register will be reset after system resume. The PCIe
link should be re-established and the related control register values
should be re-set after system resume.

Signed-off-by: Honghui Zhang 
CC: Ryder Lee 
---
 drivers/pci/host/pcie-mediatek.c | 61 
 1 file changed, 61 insertions(+)

diff --git a/drivers/pci/host/pcie-mediatek.c b/drivers/pci/host/pcie-mediatek.c
index dabf1086..6bf7f5a 100644
--- a/drivers/pci/host/pcie-mediatek.c
+++ b/drivers/pci/host/pcie-mediatek.c
@@ -132,12 +132,14 @@ struct mtk_pcie_port;
 /**
  * struct mtk_pcie_soc - differentiate between host generations
  * @need_fix_class_id: whether this host's class ID needed to be fixed or not
+ * @pm_support: whether the host's MTCMOS will be off when suspend
  * @ops: pointer to configuration access functions
  * @startup: pointer to controller setting functions
  * @setup_irq: pointer to initialize IRQ functions
  */
 struct mtk_pcie_soc {
bool need_fix_class_id;
+   bool pm_support;
struct pci_ops *ops;
int (*startup)(struct mtk_pcie_port *port);
int (*setup_irq)(struct mtk_pcie_port *port, struct device_node *node);
@@ -1179,12 +1181,70 @@ static int mtk_pcie_probe(struct platform_device *pdev)
return err;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int mtk_pcie_suspend_noirq(struct device *dev)
+{
+   struct mtk_pcie *pcie = dev_get_drvdata(dev);
+   const struct mtk_pcie_soc *soc = pcie->soc;
+   struct mtk_pcie_port *port;
+
+   if (!soc->pm_support)
+   return 0;
+
+   list_for_each_entry(port, &pcie->ports, list) {
+   clk_disable_unprepare(port->ahb_ck);
+   clk_disable_unprepare(port->sys_ck);
+   phy_power_off(port->phy);
+   }
+
+   return 0;
+}
+
+static int mtk_pcie_resume_noirq(struct device *dev)
+{
+   struct mtk_pcie *pcie = dev_get_drvdata(dev);
+   const struct mtk_pcie_soc *soc = pcie->soc;
+   struct mtk_pcie_port *port;
+   int ret;
+
+   soc = pcie->soc;
+   if (!soc->pm_support)
+   return 0;
+
+   list_for_each_entry(port, &pcie->ports, list) {
+   phy_power_on(port->phy);
+   clk_prepare_enable(port->sys_ck);
+   clk_prepare_enable(port->ahb_ck);
+
+   ret = soc->startup(port);
+   if (ret) {
+   dev_err(dev, "Port%d link down\n", port->slot);
+   phy_power_off(port->phy);
+   clk_disable_unprepare(port->sys_ck);
+   clk_disable_unprepare(port->ahb_ck);
+   return ret;
+   }
+
+   if (IS_ENABLED(CONFIG_PCI_MSI))
+   mtk_pcie_enable_msi(port);
+   }
+
+   return 0;
+}
+#endif
+
+const struct dev_pm_ops mtk_pcie_pm_ops = {
+   SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(mtk_pcie_suspend_noirq,
+ mtk_pcie_resume_noirq)
+};
+
 static const struct mtk_pcie_soc mtk_pcie_soc_v1 = {
.ops = &mtk_pcie_ops,
.startup = mtk_pcie_startup_port,
 };
 
 static const struct mtk_pcie_soc mtk_pcie_soc_mt2712 = {
+   .pm_support = true,
.ops = &mtk_pcie_ops_v2,
.startup = mtk_pcie_startup_port_v2,
.setup_irq = mtk_pcie_setup_irq,
@@ -1211,6 +1271,7 @@ static struct platform_driver mtk_pcie_driver = {
.name = "mtk-pcie",
.of_match_table = mtk_pcie_ids,
.suppress_bind_attrs = true,
+   .pm = &mtk_pcie_pm_ops,
},
 };
 builtin_platform_driver(mtk_pcie_driver);
-- 
2.6.4



[PATCH v3] PCI: mediatek: Add system pm support for MT2712

2018-05-31 Thread honghui.zhang
From: Honghui Zhang 

The MTCMOS of PCIe Host for MT2712 will be off when system suspend, and all
the internal control register will be reset after system resume. The PCIe
link should be re-established and the related control register values
should be re-set after system resume.

Signed-off-by: Honghui Zhang 
CC: Ryder Lee 
---
 drivers/pci/host/pcie-mediatek.c | 60 
 1 file changed, 60 insertions(+)

diff --git a/drivers/pci/host/pcie-mediatek.c b/drivers/pci/host/pcie-mediatek.c
index dabf1086..5363cc7 100644
--- a/drivers/pci/host/pcie-mediatek.c
+++ b/drivers/pci/host/pcie-mediatek.c
@@ -132,12 +132,14 @@ struct mtk_pcie_port;
 /**
  * struct mtk_pcie_soc - differentiate between host generations
  * @need_fix_class_id: whether this host's class ID needed to be fixed or not
+ * @pm_support: whether the host's MTCMOS will be off when suspend
  * @ops: pointer to configuration access functions
  * @startup: pointer to controller setting functions
  * @setup_irq: pointer to initialize IRQ functions
  */
 struct mtk_pcie_soc {
bool need_fix_class_id;
+   bool pm_support;
struct pci_ops *ops;
int (*startup)(struct mtk_pcie_port *port);
int (*setup_irq)(struct mtk_pcie_port *port, struct device_node *node);
@@ -1179,12 +1181,69 @@ static int mtk_pcie_probe(struct platform_device *pdev)
return err;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int mtk_pcie_suspend_noirq(struct device *dev)
+{
+   struct mtk_pcie *pcie = dev_get_drvdata(dev);
+   const struct mtk_pcie_soc *soc = pcie->soc;
+   struct mtk_pcie_port *port;
+
+   if (!soc->pm_support)
+   return 0;
+
+   list_for_each_entry(port, &pcie->ports, list) {
+   clk_disable_unprepare(port->ahb_ck);
+   clk_disable_unprepare(port->sys_ck);
+   phy_power_off(port->phy);
+   }
+
+   return 0;
+}
+
+static int mtk_pcie_resume_noirq(struct device *dev)
+{
+   struct mtk_pcie *pcie = dev_get_drvdata(dev);
+   const struct mtk_pcie_soc *soc = pcie->soc;
+   struct mtk_pcie_port *port;
+   int ret;
+
+   if (!soc->pm_support)
+   return 0;
+
+   list_for_each_entry(port, &pcie->ports, list) {
+   phy_power_on(port->phy);
+   clk_prepare_enable(port->sys_ck);
+   clk_prepare_enable(port->ahb_ck);
+
+   ret = soc->startup(port);
+   if (ret) {
+   dev_err(dev, "Port%d link down\n", port->slot);
+   phy_power_off(port->phy);
+   clk_disable_unprepare(port->sys_ck);
+   clk_disable_unprepare(port->ahb_ck);
+   return ret;
+   }
+
+   if (IS_ENABLED(CONFIG_PCI_MSI))
+   mtk_pcie_enable_msi(port);
+   }
+
+   return 0;
+}
+#endif
+
+static const struct dev_pm_ops mtk_pcie_pm_ops = {
+   SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(mtk_pcie_suspend_noirq,
+ mtk_pcie_resume_noirq)
+};
+
 static const struct mtk_pcie_soc mtk_pcie_soc_v1 = {
.ops = &mtk_pcie_ops,
.startup = mtk_pcie_startup_port,
 };
 
 static const struct mtk_pcie_soc mtk_pcie_soc_mt2712 = {
+   .pm_support = true,
.ops = &mtk_pcie_ops_v2,
.startup = mtk_pcie_startup_port_v2,
.setup_irq = mtk_pcie_setup_irq,
@@ -1211,6 +1270,7 @@ static struct platform_driver mtk_pcie_driver = {
.name = "mtk-pcie",
.of_match_table = mtk_pcie_ids,
.suppress_bind_attrs = true,
+   .pm = &mtk_pcie_pm_ops,
},
 };
 builtin_platform_driver(mtk_pcie_driver);
-- 
2.6.4



[PATCH 3/4] arm: dts: mt7623: Remove un-used property for PCIe

2018-12-13 Thread honghui.zhang
From: Honghui Zhang 

The "num-lanes" property for PCIe is not used, remove it.

Signed-off-by: Honghui Zhang 
---
 arch/arm/boot/dts/mt7623.dtsi | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/arch/arm/boot/dts/mt7623.dtsi b/arch/arm/boot/dts/mt7623.dtsi
index 1cdc346..4ca56d8 100644
--- a/arch/arm/boot/dts/mt7623.dtsi
+++ b/arch/arm/boot/dts/mt7623.dtsi
@@ -734,7 +734,6 @@
interrupt-map-mask = <0 0 0 0>;
interrupt-map = <0 0 0 0 &sysirq GIC_SPI 193 
IRQ_TYPE_LEVEL_LOW>;
ranges;
-   num-lanes = <1>;
status = "disabled";
};
 
@@ -746,7 +745,6 @@
interrupt-map-mask = <0 0 0 0>;
interrupt-map = <0 0 0 0 &sysirq GIC_SPI 194 
IRQ_TYPE_LEVEL_LOW>;
ranges;
-   num-lanes = <1>;
status = "disabled";
};
 
@@ -758,7 +756,6 @@
interrupt-map-mask = <0 0 0 0>;
interrupt-map = <0 0 0 0 &sysirq GIC_SPI 195 
IRQ_TYPE_LEVEL_LOW>;
ranges;
-   num-lanes = <1>;
status = "disabled";
};
};
-- 
2.6.4



[PATCH 0/4] Cleanup un-used variant and un-used property for MediaTek PCIe

2018-12-13 Thread honghui.zhang
From: Honghui Zhang 

The "num-lanes" property in MediaTek's PCIe device node is not used by
its driver or anyone else, cleanup those related code.

Honghui Zhang (4):
  PCI: mediatek: Remove un-used variant in struct mtk_pcie_port
  dt-bindings: PCI: MediaTek: Remove un-used property
  arm: dts: mt7623: Remove un-used property for PCIe
  arm64: dts: mt7622: Remove un-used property for PCIe

 Documentation/devicetree/bindings/pci/mediatek-pcie.txt | 8 
 arch/arm/boot/dts/mt7623.dtsi   | 3 ---
 arch/arm64/boot/dts/mediatek/mt7622.dtsi| 2 --
 drivers/pci/controller/pcie-mediatek.c  | 8 
 4 files changed, 21 deletions(-)

-- 
2.6.4



[PATCH 4/4] arm64: dts: mt7622: Remove un-used property for PCIe

2018-12-13 Thread honghui.zhang
From: Honghui Zhang 

The "num-lanes" property for PCIe is not used, remove it.

Signed-off-by: Honghui Zhang 
---
 arch/arm64/boot/dts/mediatek/mt7622.dtsi | 2 --
 1 file changed, 2 deletions(-)

diff --git a/arch/arm64/boot/dts/mediatek/mt7622.dtsi 
b/arch/arm64/boot/dts/mediatek/mt7622.dtsi
index de2c47bd..f619eb5 100644
--- a/arch/arm64/boot/dts/mediatek/mt7622.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt7622.dtsi
@@ -750,7 +750,6 @@
ranges;
status = "disabled";
 
-   num-lanes = <1>;
interrupt-map-mask = <0 0 0 7>;
interrupt-map = <0 0 0 1 &pcie_intc0 0>,
<0 0 0 2 &pcie_intc0 1>,
@@ -771,7 +770,6 @@
ranges;
status = "disabled";
 
-   num-lanes = <1>;
interrupt-map-mask = <0 0 0 7>;
interrupt-map = <0 0 0 1 &pcie_intc1 0>,
<0 0 0 2 &pcie_intc1 1>,
-- 
2.6.4



[PATCH 1/4] PCI: mediatek: Remove un-used variant in struct mtk_pcie_port

2018-12-13 Thread honghui.zhang
From: Honghui Zhang 

The "lane" variant in struct mtk_pcie_port is not used, remove it.

Signed-off-by: Honghui Zhang 
---
 drivers/pci/controller/pcie-mediatek.c | 8 
 1 file changed, 8 deletions(-)

diff --git a/drivers/pci/controller/pcie-mediatek.c 
b/drivers/pci/controller/pcie-mediatek.c
index 6917aec..e307166 100644
--- a/drivers/pci/controller/pcie-mediatek.c
+++ b/drivers/pci/controller/pcie-mediatek.c
@@ -161,7 +161,6 @@ struct mtk_pcie_soc {
  * @obff_ck: pointer to OBFF functional block operating clock
  * @pipe_ck: pointer to LTSSM and PHY/MAC layer operating clock
  * @phy: pointer to PHY control block
- * @lane: lane count
  * @slot: port slot
  * @irq: GIC irq
  * @irq_domain: legacy INTx IRQ domain
@@ -182,7 +181,6 @@ struct mtk_pcie_port {
struct clk *obff_ck;
struct clk *pipe_ck;
struct phy *phy;
-   u32 lane;
u32 slot;
int irq;
struct irq_domain *irq_domain;
@@ -895,12 +893,6 @@ static int mtk_pcie_parse_port(struct mtk_pcie *pcie,
if (!port)
return -ENOMEM;
 
-   err = of_property_read_u32(node, "num-lanes", &port->lane);
-   if (err) {
-   dev_err(dev, "missing num-lanes property\n");
-   return err;
-   }
-
snprintf(name, sizeof(name), "port%d", slot);
regs = platform_get_resource_byname(pdev, IORESOURCE_MEM, name);
port->base = devm_ioremap_resource(dev, regs);
-- 
2.6.4



[PATCH 2/4] dt-bindings: PCI: MediaTek: Remove un-used property

2018-12-13 Thread honghui.zhang
From: Honghui Zhang 

The "num-lanes" property is not used, remove it.

Signed-off-by: Honghui Zhang 
---
 Documentation/devicetree/bindings/pci/mediatek-pcie.txt | 8 
 1 file changed, 8 deletions(-)

diff --git a/Documentation/devicetree/bindings/pci/mediatek-pcie.txt 
b/Documentation/devicetree/bindings/pci/mediatek-pcie.txt
index 20227a8..92437a3 100644
--- a/Documentation/devicetree/bindings/pci/mediatek-pcie.txt
+++ b/Documentation/devicetree/bindings/pci/mediatek-pcie.txt
@@ -65,7 +65,6 @@ Required properties:
   explanation.
 - ranges: Sub-ranges distributed from the PCIe controller node. An empty
   property is sufficient.
-- num-lanes: Number of lanes to use for this port.
 
 Examples for MT7623:
 
@@ -118,7 +117,6 @@ Examples for MT7623:
interrupt-map-mask = <0 0 0 0>;
interrupt-map = <0 0 0 0 &sysirq GIC_SPI 193 
IRQ_TYPE_LEVEL_LOW>;
ranges;
-   num-lanes = <1>;
};
 
pcie@1,0 {
@@ -129,7 +127,6 @@ Examples for MT7623:
interrupt-map-mask = <0 0 0 0>;
interrupt-map = <0 0 0 0 &sysirq GIC_SPI 194 
IRQ_TYPE_LEVEL_LOW>;
ranges;
-   num-lanes = <1>;
};
 
pcie@2,0 {
@@ -140,7 +137,6 @@ Examples for MT7623:
interrupt-map-mask = <0 0 0 0>;
interrupt-map = <0 0 0 0 &sysirq GIC_SPI 195 
IRQ_TYPE_LEVEL_LOW>;
ranges;
-   num-lanes = <1>;
};
};
 
@@ -172,7 +168,6 @@ Examples for MT2712:
#size-cells = <2>;
#interrupt-cells = <1>;
ranges;
-   num-lanes = <1>;
interrupt-map-mask = <0 0 0 7>;
interrupt-map = <0 0 0 1 &pcie_intc0 0>,
<0 0 0 2 &pcie_intc0 1>,
@@ -191,7 +186,6 @@ Examples for MT2712:
#size-cells = <2>;
#interrupt-cells = <1>;
ranges;
-   num-lanes = <1>;
interrupt-map-mask = <0 0 0 7>;
interrupt-map = <0 0 0 1 &pcie_intc1 0>,
<0 0 0 2 &pcie_intc1 1>,
@@ -245,7 +239,6 @@ Examples for MT7622:
#size-cells = <2>;
#interrupt-cells = <1>;
ranges;
-   num-lanes = <1>;
interrupt-map-mask = <0 0 0 7>;
interrupt-map = <0 0 0 1 &pcie_intc0 0>,
<0 0 0 2 &pcie_intc0 1>,
@@ -264,7 +257,6 @@ Examples for MT7622:
#size-cells = <2>;
#interrupt-cells = <1>;
ranges;
-   num-lanes = <1>;
interrupt-map-mask = <0 0 0 7>;
interrupt-map = <0 0 0 1 &pcie_intc1 0>,
<0 0 0 2 &pcie_intc1 1>,
-- 
2.6.4



[RFC PATCH] PCI/portdrv: Support for subtractive decode bridge

2018-12-13 Thread honghui.zhang
From: Honghui Zhang 

The Class Code for subtractive decode PCI-to-PCI bridge is 060401h,
change the class_mask values to make portdrv support this type bridge.

Signed-off-by: Honghui Zhang 
---
 drivers/pci/pcie/portdrv_pci.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/pci/pcie/portdrv_pci.c b/drivers/pci/pcie/portdrv_pci.c
index eef22dc..86926ea 100644
--- a/drivers/pci/pcie/portdrv_pci.c
+++ b/drivers/pci/pcie/portdrv_pci.c
@@ -179,7 +179,7 @@ static void pcie_portdrv_err_resume(struct pci_dev *dev)
  */
 static const struct pci_device_id port_pci_ids[] = { {
/* handle any PCI-Express port */
-   PCI_DEVICE_CLASS(((PCI_CLASS_BRIDGE_PCI << 8) | 0x00), ~0),
+   PCI_DEVICE_CLASS(((PCI_CLASS_BRIDGE_PCI << 8) | 0x00), ~0x01),
}, { /* end: all zeroes */ }
 };
 
-- 
2.6.4



[PATCH] PCI: Mediatek: Use resource_size function on resource object

2019-01-01 Thread honghui.zhang
From: Honghui Zhang 

drivers/pci/pcie-mediatek.c:720:13-16: WARNING: Suspicious code. resource_size 
is maybe missing with mem

Generated by: scripts/coccinelle/api/resource_size.cocci

Signed-off-by: Honghui Zhang 
---
 drivers/pci/controller/pcie-mediatek.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/drivers/pci/controller/pcie-mediatek.c 
b/drivers/pci/controller/pcie-mediatek.c
index e307166..0168376 100644
--- a/drivers/pci/controller/pcie-mediatek.c
+++ b/drivers/pci/controller/pcie-mediatek.c
@@ -654,7 +654,6 @@ static int mtk_pcie_startup_port_v2(struct mtk_pcie_port 
*port)
struct resource *mem = &pcie->mem;
const struct mtk_pcie_soc *soc = port->pcie->soc;
u32 val;
-   size_t size;
int err;
 
/* MT7622 platforms need to enable LTSSM and ASPM from PCIe subsys */
@@ -706,8 +705,7 @@ static int mtk_pcie_startup_port_v2(struct mtk_pcie_port 
*port)
mtk_pcie_enable_msi(port);
 
/* Set AHB to PCIe translation windows */
-   size = mem->end - mem->start;
-   val = lower_32_bits(mem->start) | AHB2PCIE_SIZE(fls(size));
+   val = lower_32_bits(mem->start) | 
AHB2PCIE_SIZE(fls(resource_size(mem)));
writel(val, port->base + PCIE_AHB_TRANS_BASE0_L);
 
val = upper_32_bits(mem->start);
-- 
2.6.4



[PATCH v9 6/9] PCI: mediatek: Fixup enable MSI logic by enable MSI after clock enabled

2018-10-16 Thread honghui.zhang
From: Honghui Zhang 

The commit 43e6409db64d ("PCI: mediatek: Add MSI support for MT2712 and
MT7622") added MSI support but enable MSI in wrong place, clocks was not
enabled when enable MSI. This patch fix this issue by calling
mtk_pcie_enable_msi in mtk_pcie_startup_port_v2 since the clock was all
enabled at that time.

Fixes: 43e6409db64d ("PCI: mediatek: Add MSI support for MT2712 and MT7622")
Signed-off-by: Honghui Zhang 
Acked-by: Ryder Lee 
---
 drivers/pci/controller/pcie-mediatek.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/pci/controller/pcie-mediatek.c 
b/drivers/pci/controller/pcie-mediatek.c
index 6967bb7..82d3d85 100644
--- a/drivers/pci/controller/pcie-mediatek.c
+++ b/drivers/pci/controller/pcie-mediatek.c
@@ -568,8 +568,6 @@ static int mtk_pcie_init_irq_domain(struct mtk_pcie_port 
*port,
ret = mtk_pcie_allocate_msi_domains(port);
if (ret)
return ret;
-
-   mtk_pcie_enable_msi(port);
}
 
return 0;
@@ -690,6 +688,9 @@ static int mtk_pcie_startup_port_v2(struct mtk_pcie_port 
*port)
val &= ~INTX_MASK;
writel(val, port->base + PCIE_INT_MASK);
 
+   if (IS_ENABLED(CONFIG_PCI_MSI))
+   mtk_pcie_enable_msi(port);
+
/* Set AHB to PCIe translation windows */
size = mem->end - mem->start;
val = lower_32_bits(mem->start) | AHB2PCIE_SIZE(fls(size));
-- 
2.6.4



[PATCH v9 9/9] PCI: mediatek: Add loadable kernel module support

2018-10-16 Thread honghui.zhang
From: Honghui Zhang 

Implement remove callback function for Mediatek PCIe driver to add
loadable kernel module support.

Signed-off-by: Honghui Zhang 
Reviewed-by: Ryder Lee 
---
 drivers/pci/controller/Kconfig |  2 +-
 drivers/pci/controller/pcie-mediatek.c | 51 +-
 2 files changed, 51 insertions(+), 2 deletions(-)

diff --git a/drivers/pci/controller/Kconfig b/drivers/pci/controller/Kconfig
index 028b287..465790f 100644
--- a/drivers/pci/controller/Kconfig
+++ b/drivers/pci/controller/Kconfig
@@ -231,7 +231,7 @@ config PCIE_ROCKCHIP_EP
  available to support GEN2 with 4 slots.
 
 config PCIE_MEDIATEK
-   bool "MediaTek PCIe controller"
+   tristate "MediaTek PCIe controller"
depends on ARCH_MEDIATEK || COMPILE_TEST
depends on OF
depends on PCI_MSI_IRQ_DOMAIN
diff --git a/drivers/pci/controller/pcie-mediatek.c 
b/drivers/pci/controller/pcie-mediatek.c
index 7f3b8a0..2a1f97c 100644
--- a/drivers/pci/controller/pcie-mediatek.c
+++ b/drivers/pci/controller/pcie-mediatek.c
@@ -15,6 +15,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -532,6 +533,27 @@ static void mtk_pcie_enable_msi(struct mtk_pcie_port *port)
writel(val, port->base + PCIE_INT_MASK);
 }
 
+static void mtk_pcie_irq_teardown(struct mtk_pcie *pcie)
+{
+   struct mtk_pcie_port *port, *tmp;
+
+   list_for_each_entry_safe(port, tmp, &pcie->ports, list) {
+   irq_set_chained_handler_and_data(port->irq, NULL, NULL);
+
+   if (port->irq_domain)
+   irq_domain_remove(port->irq_domain);
+
+   if (IS_ENABLED(CONFIG_PCI_MSI)) {
+   if (port->msi_domain)
+   irq_domain_remove(port->msi_domain);
+   if (port->inner_domain)
+   irq_domain_remove(port->inner_domain);
+   }
+
+   irq_dispose_mapping(port->irq);
+   }
+}
+
 static int mtk_pcie_intx_map(struct irq_domain *domain, unsigned int irq,
 irq_hw_number_t hwirq)
 {
@@ -1171,6 +1193,31 @@ static int mtk_pcie_probe(struct platform_device *pdev)
return err;
 }
 
+
+static void mtk_pcie_free_resources(struct mtk_pcie *pcie)
+{
+   struct pci_host_bridge *host = pci_host_bridge_from_priv(pcie);
+   struct list_head *windows = &host->windows;
+
+   pci_free_resource_list(windows);
+}
+
+static int mtk_pcie_remove(struct platform_device *pdev)
+{
+   struct mtk_pcie *pcie = platform_get_drvdata(pdev);
+   struct pci_host_bridge *host = pci_host_bridge_from_priv(pcie);
+
+   pci_stop_root_bus(host->bus);
+   pci_remove_root_bus(host->bus);
+   mtk_pcie_free_resources(pcie);
+
+   mtk_pcie_irq_teardown(pcie);
+
+   mtk_pcie_put_resources(pcie);
+
+   return 0;
+}
+
 static int __maybe_unused mtk_pcie_suspend_noirq(struct device *dev)
 {
struct mtk_pcie *pcie = dev_get_drvdata(dev);
@@ -1248,6 +1295,7 @@ static const struct of_device_id mtk_pcie_ids[] = {
 
 static struct platform_driver mtk_pcie_driver = {
.probe = mtk_pcie_probe,
+   .remove = mtk_pcie_remove,
.driver = {
.name = "mtk-pcie",
.of_match_table = mtk_pcie_ids,
@@ -1255,4 +1303,5 @@ static struct platform_driver mtk_pcie_driver = {
.pm = &mtk_pcie_pm_ops,
},
 };
-builtin_platform_driver(mtk_pcie_driver);
+module_platform_driver(mtk_pcie_driver);
+MODULE_LICENSE("GPL v2");
-- 
2.6.4



[PATCH v9 7/9] PCI: mediatek: Add system PM support for MT2712 and MT7622

2018-10-16 Thread honghui.zhang
From: Honghui Zhang 

In order to reduce the PCIe power consuming while system suspend,
the physical layer should be gated. And the PCIe link should be
re-established and the related control register values should be
re-initialized after system resume.

Register suspend_noirq & resume_noirq callback functions to allow
PCIe to come up after resume from RAM.

Signed-off-by: Honghui Zhang 
Acked-by: Ryder Lee 
---
 drivers/pci/controller/pcie-mediatek.c | 50 ++
 1 file changed, 50 insertions(+)

diff --git a/drivers/pci/controller/pcie-mediatek.c 
b/drivers/pci/controller/pcie-mediatek.c
index 82d3d85..cf7e357 100644
--- a/drivers/pci/controller/pcie-mediatek.c
+++ b/drivers/pci/controller/pcie-mediatek.c
@@ -1168,6 +1168,55 @@ static int mtk_pcie_probe(struct platform_device *pdev)
return err;
 }
 
+static int __maybe_unused mtk_pcie_suspend_noirq(struct device *dev)
+{
+   struct mtk_pcie *pcie = dev_get_drvdata(dev);
+   struct mtk_pcie_port *port;
+
+   if (list_empty(&pcie->ports))
+   return 0;
+
+   list_for_each_entry(port, &pcie->ports, list) {
+   clk_disable_unprepare(port->pipe_ck);
+   clk_disable_unprepare(port->obff_ck);
+   clk_disable_unprepare(port->axi_ck);
+   clk_disable_unprepare(port->aux_ck);
+   clk_disable_unprepare(port->ahb_ck);
+   clk_disable_unprepare(port->sys_ck);
+   phy_power_off(port->phy);
+   phy_exit(port->phy);
+   }
+
+   clk_disable_unprepare(pcie->free_ck);
+
+   return 0;
+}
+
+static int __maybe_unused mtk_pcie_resume_noirq(struct device *dev)
+{
+   struct mtk_pcie *pcie = dev_get_drvdata(dev);
+   struct mtk_pcie_port *port, *tmp;
+
+   if (list_empty(&pcie->ports))
+   return 0;
+
+   clk_prepare_enable(pcie->free_ck);
+
+   list_for_each_entry_safe(port, tmp, &pcie->ports, list)
+   mtk_pcie_enable_port(port);
+
+   /* In case of EP was removed while system suspend. */
+   if (list_empty(&pcie->ports))
+   clk_disable_unprepare(pcie->free_ck);
+
+   return 0;
+}
+
+static const struct dev_pm_ops mtk_pcie_pm_ops = {
+   SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(mtk_pcie_suspend_noirq,
+ mtk_pcie_resume_noirq)
+};
+
 static const struct mtk_pcie_soc mtk_pcie_soc_v1 = {
.ops = &mtk_pcie_ops,
.startup = mtk_pcie_startup_port,
@@ -1200,6 +1249,7 @@ static struct platform_driver mtk_pcie_driver = {
.name = "mtk-pcie",
.of_match_table = mtk_pcie_ids,
.suppress_bind_attrs = true,
+   .pm = &mtk_pcie_pm_ops,
},
 };
 builtin_platform_driver(mtk_pcie_driver);
-- 
2.6.4



[PATCH v9 0/9] PCI: mediatek: fixup find_port, enable_msi and add PM, module support

2018-10-16 Thread honghui.zhang
From: Honghui Zhang 

This patchset includes misc patchs:

The patch 1 fixup the mtk_pcie_find_port logic which will cause system
could not touch the EP's configuration space that connected to PCIe slot 1.

The patch fixup the PCI core defect which assign resource base on device's class
type. Logically, the resource assignment should base on PCIe configuration space
layout instead of class type. So this patch using configuration header type for
resource assignment, this patch is suggested by Bjorn.

The patch 6 fixup the enable msi logic, the operation to enable MSI
should be after system clock is enabled. Call mtk_pcie_enable_msi in
mtk_pcie_startup_port_v2 since the clock was all enabled at that time.

The patch 7 was rebased and refactor of the v4 patch[1], changes are:
 -Add PM support for MT7622.
 -Using mtk_pcie_enable_port to re-establish the link when resumed.
 -Rebased on this patchset.

The patch 9 add loadable kernel module support.

[1] https://patchwork.kernel.org/patch/10479079

Change since v8:
 - Remove the patch (PCI: mediatek: Fix class type for MT7622 as 
PCI_CLASS_BRIDGE_PCI)
 - Add patch 2 (PCI: Using PCI configuration space header type instead of class 
type
   to assign resource)

Change since v7:
 - Add Acked-by tags from Ryder Lee.
 - Add Fix tags for patch 2(Fix calss type for MT7622 as PCI_CLASS_BRIDGE_PCI)
   and patch 6(Fixup enable MSI logic by enable MSI after clock enabled)

Change since v6:
 - Remove the pci_unmap_iospace when remove the device since the
   devm_pci_remap_iospace is an devm_ version.
 - Commit message changed for patch 2(Fix class type for MT7622 as 
PCI_CLASS_BRIDGE_PCI).
 - Capitilizing "MSI" and "PM" in the patch title.

Change since v5:
 - A bit improvement of mtk_pcie_find_port suggest by Lorenzo.
   MSI after clock enabled.
 - Add Acked-by tags from Ryder.

Change since v4:
 - Add patch 2 to fixup class type for MT7622.
 - Add patch 3 to remove the redundant dev->pm_domain check
 - Add patch 4 to covert to use pci_host_probe
 - Add patch 5 to re-arrange the function define, this is a prepare patch for
   fixup the enable_msi logic, no functional changed have been made by this one.
 - Add patch 8 to save the GIC IRQ in mtk_pcie_port as a prepare patch for tear
   down the irq when remove the kernel module.
 - Re-arrange the find_port flow suggest by Lorenzo to make the code parse 
easier
   for the patch 1.
 - Remove the .pm_support in mtk_pcie_soc in patch 7 since if system pm was not
   supported, then those pm callbacks will never be executed for MT7622. So the
   .pm_support is not needed.

Change since v3:
 - Remove pm_runtime_XXX ops in suspend and resume callbacks in the third patch.
 - Rebase to 4.19-rc1.

Change since v2:
 - Fix the list_for_each_entry_safe parameter error.
 - Add Ryder's Acked-by flag.

Change since v1:
 - A bit of code refact of the first patch suggested by Andy Shevchenko, and
   commit message updated.

Honghui Zhang (9):
  PCI: mediatek: Using slot's devfn for compare to fix
mtk_pcie_find_port logic
  PCI: Using PCI configuration space header type instead of class type
to assign resource
  PCI: mediatek: Remove the redundant dev->pm_domain check
  PCI: mediatek: Convert to use pci_host_probe()
  PCI: mediatek: Move the mtk_pcie_startup_port_v2 function's define
after mtk_pcie_setup_irq
  PCI: mediatek: Fixup enable MSI logic by enable MSI after clock
enabled
  PCI: mediatek: Add system PM support for MT2712 and MT7622
  PCI: mediatek: Save the GIC IRQ in mtk_pcie_port
  PCI: mediatek: Add loadable kernel module support

 drivers/pci/controller/Kconfig |   2 +-
 drivers/pci/controller/pcie-mediatek.c | 319 +
 drivers/pci/pci.c  |   3 +-
 drivers/pci/probe.c|   3 -
 drivers/pci/setup-bus.c|  20 +--
 5 files changed, 215 insertions(+), 132 deletions(-)

-- 
2.6.4



[PATCH v9 8/9] PCI: mediatek: Save the GIC IRQ in mtk_pcie_port

2018-10-16 Thread honghui.zhang
From: Honghui Zhang 

Need to save the PCIe's GIC IRQ for dispose_irq, this is a prepare
patch for add mediatek PCIe module support to tear down the IRQ, no
functional changed.

Signed-off-by: Honghui Zhang 
Acked-by: Ryder Lee 
---
 drivers/pci/controller/pcie-mediatek.c | 9 ++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/drivers/pci/controller/pcie-mediatek.c 
b/drivers/pci/controller/pcie-mediatek.c
index cf7e357..7f3b8a0 100644
--- a/drivers/pci/controller/pcie-mediatek.c
+++ b/drivers/pci/controller/pcie-mediatek.c
@@ -162,6 +162,7 @@ struct mtk_pcie_soc {
  * @phy: pointer to PHY control block
  * @lane: lane count
  * @slot: port slot
+ * @irq: GIC irq
  * @irq_domain: legacy INTx IRQ domain
  * @inner_domain: inner IRQ domain
  * @msi_domain: MSI IRQ domain
@@ -182,6 +183,7 @@ struct mtk_pcie_port {
struct phy *phy;
u32 lane;
u32 slot;
+   int irq;
struct irq_domain *irq_domain;
struct irq_domain *inner_domain;
struct irq_domain *msi_domain;
@@ -620,7 +622,7 @@ static int mtk_pcie_setup_irq(struct mtk_pcie_port *port,
struct mtk_pcie *pcie = port->pcie;
struct device *dev = pcie->dev;
struct platform_device *pdev = to_platform_device(dev);
-   int err, irq;
+   int err;
 
err = mtk_pcie_init_irq_domain(port, node);
if (err) {
@@ -628,8 +630,9 @@ static int mtk_pcie_setup_irq(struct mtk_pcie_port *port,
return err;
}
 
-   irq = platform_get_irq(pdev, port->slot);
-   irq_set_chained_handler_and_data(irq, mtk_pcie_intr_handler, port);
+   port->irq = platform_get_irq(pdev, port->slot);
+   irq_set_chained_handler_and_data(port->irq,
+mtk_pcie_intr_handler, port);
 
return 0;
 }
-- 
2.6.4



[PATCH v9 4/9] PCI: mediatek: Convert to use pci_host_probe()

2018-10-16 Thread honghui.zhang
From: Honghui Zhang 

Part of mtk_pcie_register_host is an open-coded version of
pci_host_probe(). So instead of duplicating this code, use
pci_host_probe() directly and remove mtk_pcie_register_host.

Signed-off-by: Honghui Zhang 
Acked-by: Ryder Lee 
---
 drivers/pci/controller/pcie-mediatek.c | 37 --
 1 file changed, 8 insertions(+), 29 deletions(-)

diff --git a/drivers/pci/controller/pcie-mediatek.c 
b/drivers/pci/controller/pcie-mediatek.c
index 6080b29..9f12b17 100644
--- a/drivers/pci/controller/pcie-mediatek.c
+++ b/drivers/pci/controller/pcie-mediatek.c
@@ -1121,34 +1121,6 @@ static int mtk_pcie_request_resources(struct mtk_pcie 
*pcie)
return 0;
 }
 
-static int mtk_pcie_register_host(struct pci_host_bridge *host)
-{
-   struct mtk_pcie *pcie = pci_host_bridge_priv(host);
-   struct pci_bus *child;
-   int err;
-
-   host->busnr = pcie->busn.start;
-   host->dev.parent = pcie->dev;
-   host->ops = pcie->soc->ops;
-   host->map_irq = of_irq_parse_and_map_pci;
-   host->swizzle_irq = pci_common_swizzle;
-   host->sysdata = pcie;
-
-   err = pci_scan_root_bus_bridge(host);
-   if (err < 0)
-   return err;
-
-   pci_bus_size_bridges(host->bus);
-   pci_bus_assign_resources(host->bus);
-
-   list_for_each_entry(child, &host->bus->children, node)
-   pcie_bus_configure_settings(child);
-
-   pci_bus_add_devices(host->bus);
-
-   return 0;
-}
-
 static int mtk_pcie_probe(struct platform_device *pdev)
 {
struct device *dev = &pdev->dev;
@@ -1175,7 +1147,14 @@ static int mtk_pcie_probe(struct platform_device *pdev)
if (err)
goto put_resources;
 
-   err = mtk_pcie_register_host(host);
+   host->busnr = pcie->busn.start;
+   host->dev.parent = pcie->dev;
+   host->ops = pcie->soc->ops;
+   host->map_irq = of_irq_parse_and_map_pci;
+   host->swizzle_irq = pci_common_swizzle;
+   host->sysdata = pcie;
+
+   err = pci_host_probe(host);
if (err)
goto put_resources;
 
-- 
2.6.4



[PATCH v9 5/9] PCI: mediatek: Move the mtk_pcie_startup_port_v2 function's define after mtk_pcie_setup_irq

2018-10-16 Thread honghui.zhang
From: Honghui Zhang 

This is a prepare patch to fix enable MSI logic, move the function's
define later to avoid forward declaration of mtk_pcie_enable_msi in
the future. No functional changed.

Signed-off-by: Honghui Zhang 
Acked-by: Ryder Lee 
---
 drivers/pci/controller/pcie-mediatek.c | 138 -
 1 file changed, 69 insertions(+), 69 deletions(-)

diff --git a/drivers/pci/controller/pcie-mediatek.c 
b/drivers/pci/controller/pcie-mediatek.c
index 9f12b17..6967bb7 100644
--- a/drivers/pci/controller/pcie-mediatek.c
+++ b/drivers/pci/controller/pcie-mediatek.c
@@ -392,75 +392,6 @@ static struct pci_ops mtk_pcie_ops_v2 = {
.write = mtk_pcie_config_write,
 };
 
-static int mtk_pcie_startup_port_v2(struct mtk_pcie_port *port)
-{
-   struct mtk_pcie *pcie = port->pcie;
-   struct resource *mem = &pcie->mem;
-   const struct mtk_pcie_soc *soc = port->pcie->soc;
-   u32 val;
-   size_t size;
-   int err;
-
-   /* MT7622 platforms need to enable LTSSM and ASPM from PCIe subsys */
-   if (pcie->base) {
-   val = readl(pcie->base + PCIE_SYS_CFG_V2);
-   val |= PCIE_CSR_LTSSM_EN(port->slot) |
-  PCIE_CSR_ASPM_L1_EN(port->slot);
-   writel(val, pcie->base + PCIE_SYS_CFG_V2);
-   }
-
-   /* Assert all reset signals */
-   writel(0, port->base + PCIE_RST_CTRL);
-
-   /*
-* Enable PCIe link down reset, if link status changed from link up to
-* link down, this will reset MAC control registers and configuration
-* space.
-*/
-   writel(PCIE_LINKDOWN_RST_EN, port->base + PCIE_RST_CTRL);
-
-   /* De-assert PHY, PE, PIPE, MAC and configuration reset */
-   val = readl(port->base + PCIE_RST_CTRL);
-   val |= PCIE_PHY_RSTB | PCIE_PERSTB | PCIE_PIPE_SRSTB |
-  PCIE_MAC_SRSTB | PCIE_CRSTB;
-   writel(val, port->base + PCIE_RST_CTRL);
-
-   /* Set up vendor ID and class code */
-   if (soc->need_fix_class_id) {
-   val = PCI_VENDOR_ID_MEDIATEK;
-   writew(val, port->base + PCIE_CONF_VEND_ID);
-
-   val = PCI_CLASS_BRIDGE_HOST;
-   writew(val, port->base + PCIE_CONF_CLASS_ID);
-   }
-
-   /* 100ms timeout value should be enough for Gen1/2 training */
-   err = readl_poll_timeout(port->base + PCIE_LINK_STATUS_V2, val,
-!!(val & PCIE_PORT_LINKUP_V2), 20,
-100 * USEC_PER_MSEC);
-   if (err)
-   return -ETIMEDOUT;
-
-   /* Set INTx mask */
-   val = readl(port->base + PCIE_INT_MASK);
-   val &= ~INTX_MASK;
-   writel(val, port->base + PCIE_INT_MASK);
-
-   /* Set AHB to PCIe translation windows */
-   size = mem->end - mem->start;
-   val = lower_32_bits(mem->start) | AHB2PCIE_SIZE(fls(size));
-   writel(val, port->base + PCIE_AHB_TRANS_BASE0_L);
-
-   val = upper_32_bits(mem->start);
-   writel(val, port->base + PCIE_AHB_TRANS_BASE0_H);
-
-   /* Set PCIe to AXI translation memory space.*/
-   val = fls(0x) | WIN_ENABLE;
-   writel(val, port->base + PCIE_AXI_WINDOW0);
-
-   return 0;
-}
-
 static void mtk_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
 {
struct mtk_pcie_port *port = irq_data_get_irq_chip_data(data);
@@ -705,6 +636,75 @@ static int mtk_pcie_setup_irq(struct mtk_pcie_port *port,
return 0;
 }
 
+static int mtk_pcie_startup_port_v2(struct mtk_pcie_port *port)
+{
+   struct mtk_pcie *pcie = port->pcie;
+   struct resource *mem = &pcie->mem;
+   const struct mtk_pcie_soc *soc = port->pcie->soc;
+   u32 val;
+   size_t size;
+   int err;
+
+   /* MT7622 platforms need to enable LTSSM and ASPM from PCIe subsys */
+   if (pcie->base) {
+   val = readl(pcie->base + PCIE_SYS_CFG_V2);
+   val |= PCIE_CSR_LTSSM_EN(port->slot) |
+  PCIE_CSR_ASPM_L1_EN(port->slot);
+   writel(val, pcie->base + PCIE_SYS_CFG_V2);
+   }
+
+   /* Assert all reset signals */
+   writel(0, port->base + PCIE_RST_CTRL);
+
+   /*
+* Enable PCIe link down reset, if link status changed from link up to
+* link down, this will reset MAC control registers and configuration
+* space.
+*/
+   writel(PCIE_LINKDOWN_RST_EN, port->base + PCIE_RST_CTRL);
+
+   /* De-assert PHY, PE, PIPE, MAC and configuration reset */
+   val = readl(port->base + PCIE_RST_CTRL);
+   val |= PCIE_PHY_RSTB | PCIE_PERSTB | PCIE_PIPE_SRSTB |
+  PCIE_MAC_SRSTB | PCIE_CRSTB;
+   writel(val, port->base + PCIE_RST_CTRL);
+
+   /* Set up vendor ID and class code */
+   if (soc->need_fix_class_id) {
+   val = PCI_VENDOR_ID_MEDIATEK;
+   writew(val, port->base + PCIE_CONF_VEND_ID);
+
+   val = PCI_CLASS_BRIDGE_HOST;
+   writew(val, port->bas

[PATCH v9 3/9] PCI: mediatek: Remove the redundant dev->pm_domain check

2018-10-16 Thread honghui.zhang
From: Honghui Zhang 

It's no needed to check whether device have pm_domain attached before
calling the pm_runtime_XXX interface, remove it.

Signed-off-by: Honghui Zhang 
Acked-by: Ryder Lee 
---
 drivers/pci/controller/pcie-mediatek.c | 18 ++
 1 file changed, 6 insertions(+), 12 deletions(-)

diff --git a/drivers/pci/controller/pcie-mediatek.c 
b/drivers/pci/controller/pcie-mediatek.c
index 288b8e2..6080b29 100644
--- a/drivers/pci/controller/pcie-mediatek.c
+++ b/drivers/pci/controller/pcie-mediatek.c
@@ -225,10 +225,8 @@ static void mtk_pcie_subsys_powerdown(struct mtk_pcie 
*pcie)
 
clk_disable_unprepare(pcie->free_ck);
 
-   if (dev->pm_domain) {
-   pm_runtime_put_sync(dev);
-   pm_runtime_disable(dev);
-   }
+   pm_runtime_put_sync(dev);
+   pm_runtime_disable(dev);
 }
 
 static void mtk_pcie_port_free(struct mtk_pcie_port *port)
@@ -998,10 +996,8 @@ static int mtk_pcie_subsys_powerup(struct mtk_pcie *pcie)
pcie->free_ck = NULL;
}
 
-   if (dev->pm_domain) {
-   pm_runtime_enable(dev);
-   pm_runtime_get_sync(dev);
-   }
+   pm_runtime_enable(dev);
+   pm_runtime_get_sync(dev);
 
/* enable top level clock */
err = clk_prepare_enable(pcie->free_ck);
@@ -1013,10 +1009,8 @@ static int mtk_pcie_subsys_powerup(struct mtk_pcie *pcie)
return 0;
 
 err_free_ck:
-   if (dev->pm_domain) {
-   pm_runtime_put_sync(dev);
-   pm_runtime_disable(dev);
-   }
+   pm_runtime_put_sync(dev);
+   pm_runtime_disable(dev);
 
return err;
 }
-- 
2.6.4



[PATCH v9 1/9] PCI: mediatek: Using slot's devfn for compare to fix mtk_pcie_find_port logic

2018-10-16 Thread honghui.zhang
From: Honghui Zhang 

The Mediatek's host controller has two slots, each with it's own control
registers. The host driver need to identify which slot was connected
in order to access the device's configuration space. There's problem
for current host driver to find out which slot was connected to for
a given EP device.

Assuming each slot have connect with one EP device as below:

host bridge
  bus 0 --> __|___
   |  |
   |  |
 slot 0 slot 1
  bus 1 -->|bus 2 --> |
   |  |
 EP 0   EP 1

During PCI enumeration, system software will scan all the PCI device
starting from devfn 0. So it will get the proper port for slot0 and
slot1 device when using PCI_SLOT(devfn) for match. But it will get
the wrong slot for EP1: The devfn will be start from 0 when scanning
EP1 behind slot1, it will get port0 since the PCI_SLOT(EP1) is match
for port0's slot value. So the host driver should not using EP's devfn
but the slot's devfn(the slot which EP was connected to) for match.

This patch fix the mtk_pcie_find_port's logic by using the slot's
devfn for match if finding device connected to the subordinate bus.

Signed-off-by: Honghui Zhang 
Acked-by: Ryder Lee 
---
 drivers/pci/controller/pcie-mediatek.c | 11 +++
 1 file changed, 11 insertions(+)

diff --git a/drivers/pci/controller/pcie-mediatek.c 
b/drivers/pci/controller/pcie-mediatek.c
index dae..288b8e2 100644
--- a/drivers/pci/controller/pcie-mediatek.c
+++ b/drivers/pci/controller/pcie-mediatek.c
@@ -337,6 +337,17 @@ static struct mtk_pcie_port *mtk_pcie_find_port(struct 
pci_bus *bus,
 {
struct mtk_pcie *pcie = bus->sysdata;
struct mtk_pcie_port *port;
+   struct pci_dev *dev = NULL;
+
+   /*
+* Walk the bus hierarchy to get the devfn value
+* of the port in the root bus.
+*/
+   while (bus && bus->number) {
+   dev = bus->self;
+   bus = dev->bus;
+   devfn = dev->devfn;
+   }
 
list_for_each_entry(port, &pcie->ports, list)
if (port->slot == PCI_SLOT(devfn))
-- 
2.6.4



[PATCH v9 2/9] PCI: Using PCI configuration space header type instead of class type to assign resource

2018-10-16 Thread honghui.zhang
From: Honghui Zhang 

The PCI configuration space header type defines the layout of the rest
of the header (PCI r3.0 sec 6.1, PCIe r4.0 sec 7.5.1.1.9) while the
resource assignment is based on the configuration space layout instead
of its class type. Using configuration space header type instead of
class type for the resource assignment.

Suggested-by: Bjorn Helgaas 
Signed-off-by: Honghui Zhang 
---
 drivers/pci/pci.c   |  3 +--
 drivers/pci/probe.c |  3 ---
 drivers/pci/setup-bus.c | 20 ++--
 3 files changed, 11 insertions(+), 15 deletions(-)

diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 29ff961..7d379ca 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -5908,8 +5908,7 @@ void pci_reassigndev_resource_alignment(struct pci_dev 
*dev)
 * to enable the kernel to reassign new resource
 * window later on.
 */
-   if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE &&
-   (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) {
+   if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
for (i = PCI_BRIDGE_RESOURCES; i < PCI_NUM_RESOURCES; i++) {
r = &dev->resource[i];
if (!(r->flags & IORESOURCE_MEM))
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index ec78400..29a35c1 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -1695,9 +1695,6 @@ int pci_setup_device(struct pci_dev *dev)
break;
 
case PCI_HEADER_TYPE_BRIDGE:/* bridge header */
-   if (class != PCI_CLASS_BRIDGE_PCI)
-   goto bad;
-
/*
 * The PCI-to-PCI bridge spec requires that subtractive
 * decoding (i.e. transparent) bridge must have programming
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index 79b1824..69f90f4 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -182,7 +182,7 @@ static void __dev_sort_resources(struct pci_dev *dev,
u16 class = dev->class >> 8;
 
/* Don't touch classless devices or host bridges or ioapics.  */
-   if (class == PCI_CLASS_NOT_DEFINED || class == PCI_CLASS_BRIDGE_HOST)
+   if (class == PCI_CLASS_NOT_DEFINED)
return;
 
/* Don't touch ioapic devices already enabled by firmware */
@@ -1221,12 +1221,12 @@ void __pci_bus_size_bridges(struct pci_bus *bus, struct 
list_head *realloc_head)
if (!b)
continue;
 
-   switch (dev->class >> 8) {
-   case PCI_CLASS_BRIDGE_CARDBUS:
+   switch (dev->hdr_type) {
+   case PCI_HEADER_TYPE_CARDBUS:
pci_bus_size_cardbus(b, realloc_head);
break;
 
-   case PCI_CLASS_BRIDGE_PCI:
+   case PCI_HEADER_TYPE_BRIDGE:
default:
__pci_bus_size_bridges(b, realloc_head);
break;
@@ -1237,12 +1237,12 @@ void __pci_bus_size_bridges(struct pci_bus *bus, struct 
list_head *realloc_head)
if (pci_is_root_bus(bus))
return;
 
-   switch (bus->self->class >> 8) {
-   case PCI_CLASS_BRIDGE_CARDBUS:
+   switch (bus->self->hdr_type) {
+   case PCI_HEADER_TYPE_CARDBUS:
/* don't size cardbuses yet. */
break;
 
-   case PCI_CLASS_BRIDGE_PCI:
+   case PCI_HEADER_TYPE_BRIDGE:
pci_bridge_check_ranges(bus);
if (bus->self->is_hotplug_bridge) {
additional_io_size  = pci_hotplug_io_size;
@@ -1391,13 +1391,13 @@ void __pci_bus_assign_resources(const struct pci_bus 
*bus,
 
__pci_bus_assign_resources(b, realloc_head, fail_head);
 
-   switch (dev->class >> 8) {
-   case PCI_CLASS_BRIDGE_PCI:
+   switch (dev->hdr_type) {
+   case PCI_HEADER_TYPE_BRIDGE:
if (!pci_is_enabled(dev))
pci_setup_bridge(b);
break;
 
-   case PCI_CLASS_BRIDGE_CARDBUS:
+   case PCI_HEADER_TYPE_CARDBUS:
pci_setup_cardbus(b);
break;
 
-- 
2.6.4



[PATCH] PCI: mediatek: Use devm_of_pci_get_host_bridge_resources() to parse DT

2018-10-17 Thread honghui.zhang
From: Honghui Zhang 

Use the devm_of_pci_get_host_bridge_resources() API in place of the PCI OF
DT parser.

Signed-off-by: Honghui Zhang 
---
 drivers/pci/controller/pcie-mediatek.c | 109 +
 1 file changed, 29 insertions(+), 80 deletions(-)

diff --git a/drivers/pci/controller/pcie-mediatek.c 
b/drivers/pci/controller/pcie-mediatek.c
index 2a1f97c..6632d4e 100644
--- a/drivers/pci/controller/pcie-mediatek.c
+++ b/drivers/pci/controller/pcie-mediatek.c
@@ -197,29 +197,20 @@ struct mtk_pcie_port {
  * @dev: pointer to PCIe device
  * @base: IO mapped register base
  * @free_ck: free-run reference clock
- * @io: IO resource
- * @pio: PIO resource
  * @mem: non-prefetchable memory resource
- * @busn: bus range
- * @offset: IO / Memory offset
  * @ports: pointer to PCIe port information
  * @soc: pointer to SoC-dependent operations
+ * @busnr: root bus number
  */
 struct mtk_pcie {
struct device *dev;
void __iomem *base;
struct clk *free_ck;
 
-   struct resource io;
-   struct resource pio;
struct resource mem;
-   struct resource busn;
-   struct {
-   resource_size_t mem;
-   resource_size_t io;
-   } offset;
struct list_head ports;
const struct mtk_pcie_soc *soc;
+   int busnr;
 };
 
 static void mtk_pcie_subsys_powerdown(struct mtk_pcie *pcie)
@@ -1045,55 +1036,42 @@ static int mtk_pcie_setup(struct mtk_pcie *pcie)
 {
struct device *dev = pcie->dev;
struct device_node *node = dev->of_node, *child;
-   struct of_pci_range_parser parser;
-   struct of_pci_range range;
-   struct resource res;
struct mtk_pcie_port *port, *tmp;
+   struct pci_host_bridge *host = pci_host_bridge_from_priv(pcie);
+   struct list_head *windows = &host->windows;
+   struct resource_entry *win, *tmp_win;
+   resource_size_t io_base;
int err;
 
-   if (of_pci_range_parser_init(&parser, node)) {
-   dev_err(dev, "missing \"ranges\" property\n");
-   return -EINVAL;
-   }
+   err = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff,
+   windows, &io_base);
+   if (err)
+   return err;
 
-   for_each_of_pci_range(&parser, &range) {
-   err = of_pci_range_to_resource(&range, node, &res);
-   if (err < 0)
-   return err;
+   err = devm_request_pci_bus_resources(dev, windows);
+   if (err < 0)
+   return err;
 
-   switch (res.flags & IORESOURCE_TYPE_BITS) {
+   /* Get the I/O and memory ranges from DT */
+   resource_list_for_each_entry_safe(win, tmp_win, windows) {
+   switch (resource_type(win->res)) {
case IORESOURCE_IO:
-   pcie->offset.io = res.start - range.pci_addr;
-
-   memcpy(&pcie->pio, &res, sizeof(res));
-   pcie->pio.name = node->full_name;
-
-   pcie->io.start = range.cpu_addr;
-   pcie->io.end = range.cpu_addr + range.size - 1;
-   pcie->io.flags = IORESOURCE_MEM;
-   pcie->io.name = "I/O";
-
-   memcpy(&res, &pcie->io, sizeof(res));
-   break;
-
+   err = devm_pci_remap_iospace(dev, win->res, io_base);
+   if (err) {
+   dev_warn(dev, "error %d: failed to map resource 
%pR\n",
+err, win->res);
+   resource_list_destroy_entry(win);
+   }
case IORESOURCE_MEM:
-   pcie->offset.mem = res.start - range.pci_addr;
-
-   memcpy(&pcie->mem, &res, sizeof(res));
+   memcpy(&pcie->mem, win->res, sizeof(*win->res));
pcie->mem.name = "non-prefetchable";
break;
+   case IORESOURCE_BUS:
+   pcie->busnr = win->res->start;
+   break;
}
}
 
-   err = of_pci_parse_bus_range(node, &pcie->busn);
-   if (err < 0) {
-   dev_err(dev, "failed to parse bus ranges property: %d\n", err);
-   pcie->busn.name = node->name;
-   pcie->busn.start = 0;
-   pcie->busn.end = 0xff;
-   pcie->busn.flags = IORESOURCE_BUS;
-   }
-
for_each_available_child_of_node(node, child) {
int slot;
 
@@ -1125,28 +1103,6 @@ static int mtk_pcie_setup(struct mtk_pcie *pcie)
return 0;
 }
 
-static int mtk_pcie_request_resources(struct mtk_pcie *pcie)
-{
-   struct pci_host_bridge *host = pci_host_bridge_from_priv(pcie);
-   struct list_head *windows = &host->windows;
-   struct device *dev = pcie->dev;
-   int err;
-
-   pci_add_r

[PATCH v2] PCI: mediatek: Use devm_of_pci_get_host_bridge_resources() to parse DT

2018-11-07 Thread honghui.zhang
From: Honghui Zhang 

Use the devm_of_pci_get_host_bridge_resources() API in place of the PCI OF
DT parser.

Signed-off-by: Honghui Zhang 
---
 drivers/pci/controller/pcie-mediatek.c | 98 +-
 1 file changed, 24 insertions(+), 74 deletions(-)

diff --git a/drivers/pci/controller/pcie-mediatek.c 
b/drivers/pci/controller/pcie-mediatek.c
index 2a1f97c..0590a93 100644
--- a/drivers/pci/controller/pcie-mediatek.c
+++ b/drivers/pci/controller/pcie-mediatek.c
@@ -197,11 +197,7 @@ struct mtk_pcie_port {
  * @dev: pointer to PCIe device
  * @base: IO mapped register base
  * @free_ck: free-run reference clock
- * @io: IO resource
- * @pio: PIO resource
  * @mem: non-prefetchable memory resource
- * @busn: bus range
- * @offset: IO / Memory offset
  * @ports: pointer to PCIe port information
  * @soc: pointer to SoC-dependent operations
  */
@@ -210,14 +206,7 @@ struct mtk_pcie {
void __iomem *base;
struct clk *free_ck;
 
-   struct resource io;
-   struct resource pio;
struct resource mem;
-   struct resource busn;
-   struct {
-   resource_size_t mem;
-   resource_size_t io;
-   } offset;
struct list_head ports;
const struct mtk_pcie_soc *soc;
 };
@@ -1045,55 +1034,43 @@ static int mtk_pcie_setup(struct mtk_pcie *pcie)
 {
struct device *dev = pcie->dev;
struct device_node *node = dev->of_node, *child;
-   struct of_pci_range_parser parser;
-   struct of_pci_range range;
-   struct resource res;
struct mtk_pcie_port *port, *tmp;
+   struct pci_host_bridge *host = pci_host_bridge_from_priv(pcie);
+   struct list_head *windows = &host->windows;
+   struct resource_entry *win, *tmp_win;
+   resource_size_t io_base;
int err;
 
-   if (of_pci_range_parser_init(&parser, node)) {
-   dev_err(dev, "missing \"ranges\" property\n");
-   return -EINVAL;
-   }
+   err = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff,
+   windows, &io_base);
+   if (err)
+   return err;
 
-   for_each_of_pci_range(&parser, &range) {
-   err = of_pci_range_to_resource(&range, node, &res);
-   if (err < 0)
-   return err;
+   err = devm_request_pci_bus_resources(dev, windows);
+   if (err < 0)
+   return err;
 
-   switch (res.flags & IORESOURCE_TYPE_BITS) {
+   /* Get the I/O and memory ranges from DT */
+   resource_list_for_each_entry_safe(win, tmp_win, windows) {
+   switch (resource_type(win->res)) {
case IORESOURCE_IO:
-   pcie->offset.io = res.start - range.pci_addr;
-
-   memcpy(&pcie->pio, &res, sizeof(res));
-   pcie->pio.name = node->full_name;
-
-   pcie->io.start = range.cpu_addr;
-   pcie->io.end = range.cpu_addr + range.size - 1;
-   pcie->io.flags = IORESOURCE_MEM;
-   pcie->io.name = "I/O";
-
-   memcpy(&res, &pcie->io, sizeof(res));
+   err = devm_pci_remap_iospace(dev, win->res, io_base);
+   if (err) {
+   dev_warn(dev, "error %d: failed to map resource 
%pR\n",
+err, win->res);
+   resource_list_destroy_entry(win);
+   }
break;
-
case IORESOURCE_MEM:
-   pcie->offset.mem = res.start - range.pci_addr;
-
-   memcpy(&pcie->mem, &res, sizeof(res));
+   memcpy(&pcie->mem, win->res, sizeof(*win->res));
pcie->mem.name = "non-prefetchable";
break;
+   case IORESOURCE_BUS:
+   host->busnr = win->res->start;
+   break;
}
}
 
-   err = of_pci_parse_bus_range(node, &pcie->busn);
-   if (err < 0) {
-   dev_err(dev, "failed to parse bus ranges property: %d\n", err);
-   pcie->busn.name = node->name;
-   pcie->busn.start = 0;
-   pcie->busn.end = 0xff;
-   pcie->busn.flags = IORESOURCE_BUS;
-   }
-
for_each_available_child_of_node(node, child) {
int slot;
 
@@ -1125,28 +1102,6 @@ static int mtk_pcie_setup(struct mtk_pcie *pcie)
return 0;
 }
 
-static int mtk_pcie_request_resources(struct mtk_pcie *pcie)
-{
-   struct pci_host_bridge *host = pci_host_bridge_from_priv(pcie);
-   struct list_head *windows = &host->windows;
-   struct device *dev = pcie->dev;
-   int err;
-
-   pci_add_resource_offset(windows, &pcie->pio, pcie->offset.io);
-   pci_add_resource_offset(windows, &pcie->mem, pcie->offset.

[PATCH v7 7/9] PCI: mediatek: Add system PM support for MT2712 and MT7622

2018-10-14 Thread honghui.zhang
From: Honghui Zhang 

In order to reduce the PCIe power consuming while system suspend,
the physical layer should be gated. And the PCIe link should be
re-established and the related control register values should be
re-initialized after system resume.

Register suspend_noirq & resume_noirq callback functions to allow
PCIe to come up after resume from RAM.

Signed-off-by: Honghui Zhang 
---
 drivers/pci/controller/pcie-mediatek.c | 50 ++
 1 file changed, 50 insertions(+)

diff --git a/drivers/pci/controller/pcie-mediatek.c 
b/drivers/pci/controller/pcie-mediatek.c
index d3f4694..42cf2a4 100644
--- a/drivers/pci/controller/pcie-mediatek.c
+++ b/drivers/pci/controller/pcie-mediatek.c
@@ -1168,6 +1168,55 @@ static int mtk_pcie_probe(struct platform_device *pdev)
return err;
 }
 
+static int __maybe_unused mtk_pcie_suspend_noirq(struct device *dev)
+{
+   struct mtk_pcie *pcie = dev_get_drvdata(dev);
+   struct mtk_pcie_port *port;
+
+   if (list_empty(&pcie->ports))
+   return 0;
+
+   list_for_each_entry(port, &pcie->ports, list) {
+   clk_disable_unprepare(port->pipe_ck);
+   clk_disable_unprepare(port->obff_ck);
+   clk_disable_unprepare(port->axi_ck);
+   clk_disable_unprepare(port->aux_ck);
+   clk_disable_unprepare(port->ahb_ck);
+   clk_disable_unprepare(port->sys_ck);
+   phy_power_off(port->phy);
+   phy_exit(port->phy);
+   }
+
+   clk_disable_unprepare(pcie->free_ck);
+
+   return 0;
+}
+
+static int __maybe_unused mtk_pcie_resume_noirq(struct device *dev)
+{
+   struct mtk_pcie *pcie = dev_get_drvdata(dev);
+   struct mtk_pcie_port *port, *tmp;
+
+   if (list_empty(&pcie->ports))
+   return 0;
+
+   clk_prepare_enable(pcie->free_ck);
+
+   list_for_each_entry_safe(port, tmp, &pcie->ports, list)
+   mtk_pcie_enable_port(port);
+
+   /* In case of EP was removed while system suspend. */
+   if (list_empty(&pcie->ports))
+   clk_disable_unprepare(pcie->free_ck);
+
+   return 0;
+}
+
+static const struct dev_pm_ops mtk_pcie_pm_ops = {
+   SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(mtk_pcie_suspend_noirq,
+ mtk_pcie_resume_noirq)
+};
+
 static const struct mtk_pcie_soc mtk_pcie_soc_v1 = {
.ops = &mtk_pcie_ops,
.startup = mtk_pcie_startup_port,
@@ -1200,6 +1249,7 @@ static struct platform_driver mtk_pcie_driver = {
.name = "mtk-pcie",
.of_match_table = mtk_pcie_ids,
.suppress_bind_attrs = true,
+   .pm = &mtk_pcie_pm_ops,
},
 };
 builtin_platform_driver(mtk_pcie_driver);
-- 
2.6.4



[PATCH v7 0/9] PCI: mediatek: fixup find_port, enable_msi and add PM, module support

2018-10-14 Thread honghui.zhang
From: Honghui Zhang 

This patchset includes misc patchs:

The patch 1 fixup the mtk_pcie_find_port logic which will cause system
could not touch the EP's configuration space that connected to PCIe slot 1.

The patch 2 fixup the class type for MT7622.
The patch 6 fixup the enable msi logic, the operation to enable MSI
should be after system clock is enabled. Call mtk_pcie_enable_msi in
mtk_pcie_startup_port_v2 since the clock was all enabled at that time.

The patch 7 was rebased and refactor of the v4 patch[1], changes are:
 -Add PM support for MT7622.
 -Using mtk_pcie_enable_port to re-establish the link when resumed.
 -Rebased on this patchset.

The patch 9 add loadable kernel module support.

[1] https://patchwork.kernel.org/patch/10479079

Change since v6:
 - Remove the pci_unmap_iospace when remove the device since the
   devm_pci_remap_iospace is an devm_ version.
 - Commit message changed for patch 2(Fix class type for MT7622 as 
PCI_CLASS_BRIDGE_PCI).
 - Capitilizing "MSI" and "PM" in the patch title.

Change since v5:
 - A bit improvement of mtk_pcie_find_port suggest by Lorenzo.
 - Add fixup tags of fix enable MSI logic in patch 6.
 - Add Acked-by tags from Ryder.

Change since v4:
 - Add patch 2 to fixup class type for MT7622.
 - Add patch 3 to remove the redundant dev->pm_domain check
 - Add patch 4 to covert to use pci_host_probe
 - Add patch 5 to re-arrange the function define, this is a prepare patch for
   fixup the enable_msi logic, no functional changed have been made by this one.
 - Add patch 8 to save the GIC IRQ in mtk_pcie_port as a prepare patch for tear
   down the irq when remove the kernel module.
 - Re-arrange the find_port flow suggest by Lorenzo to make the code parse 
easier
   for the patch 1.
 - Remove the .pm_support in mtk_pcie_soc in patch 7 since if system pm was not
   supported, then those pm callbacks will never be executed for MT7622. So the
   .pm_support is not needed.

Change since v3:
 - Remove pm_runtime_XXX ops in suspend and resume callbacks in the third patch.
 - Rebase to 4.19-rc1.

Change since v2:
 - Fix the list_for_each_entry_safe parameter error.
 - Add Ryder's Acked-by flag.

Change since v1:
 - A bit of code refact of the first patch suggested by Andy Shevchenko, and
   commit message updated.

Honghui Zhang (9):
  PCI: mediatek: Using slot's devfn for compare to fix
mtk_pcie_find_port logic
  PCI: mediatek: Fix class type for MT7622 as PCI_CLASS_BRIDGE_PCI
  PCI: mediatek: Remove the redundant dev->pm_domain check
  PCI: mediatek: Convert to use pci_host_probe()
  PCI: mediatek: Move the mtk_pcie_startup_port_v2 function's define
after mtk_pcie_setup_irq
  PCI: mediatek: Fixup enable MSI logic by enable MSI after clock
enabled
  PCI: mediatek: Add system PM support for MT2712 and MT7622
  PCI: mediatek: Save the GIC IRQ in mtk_pcie_port
  PCI: mediatek: Add loadable kernel module support

 drivers/pci/controller/Kconfig |   2 +-
 drivers/pci/controller/pcie-mediatek.c | 319 +
 2 files changed, 204 insertions(+), 117 deletions(-)

-- 
2.6.4



[PATCH v7 4/9] PCI: mediatek: Convert to use pci_host_probe()

2018-10-14 Thread honghui.zhang
From: Honghui Zhang 

Part of mtk_pcie_register_host is an open-coded version of
pci_host_probe(). So instead of duplicating this code, use
pci_host_probe() directly and remove mtk_pcie_register_host.

Signed-off-by: Honghui Zhang 
---
 drivers/pci/controller/pcie-mediatek.c | 37 --
 1 file changed, 8 insertions(+), 29 deletions(-)

diff --git a/drivers/pci/controller/pcie-mediatek.c 
b/drivers/pci/controller/pcie-mediatek.c
index 59fdb60..ead6005 100644
--- a/drivers/pci/controller/pcie-mediatek.c
+++ b/drivers/pci/controller/pcie-mediatek.c
@@ -1121,34 +1121,6 @@ static int mtk_pcie_request_resources(struct mtk_pcie 
*pcie)
return 0;
 }
 
-static int mtk_pcie_register_host(struct pci_host_bridge *host)
-{
-   struct mtk_pcie *pcie = pci_host_bridge_priv(host);
-   struct pci_bus *child;
-   int err;
-
-   host->busnr = pcie->busn.start;
-   host->dev.parent = pcie->dev;
-   host->ops = pcie->soc->ops;
-   host->map_irq = of_irq_parse_and_map_pci;
-   host->swizzle_irq = pci_common_swizzle;
-   host->sysdata = pcie;
-
-   err = pci_scan_root_bus_bridge(host);
-   if (err < 0)
-   return err;
-
-   pci_bus_size_bridges(host->bus);
-   pci_bus_assign_resources(host->bus);
-
-   list_for_each_entry(child, &host->bus->children, node)
-   pcie_bus_configure_settings(child);
-
-   pci_bus_add_devices(host->bus);
-
-   return 0;
-}
-
 static int mtk_pcie_probe(struct platform_device *pdev)
 {
struct device *dev = &pdev->dev;
@@ -1175,7 +1147,14 @@ static int mtk_pcie_probe(struct platform_device *pdev)
if (err)
goto put_resources;
 
-   err = mtk_pcie_register_host(host);
+   host->busnr = pcie->busn.start;
+   host->dev.parent = pcie->dev;
+   host->ops = pcie->soc->ops;
+   host->map_irq = of_irq_parse_and_map_pci;
+   host->swizzle_irq = pci_common_swizzle;
+   host->sysdata = pcie;
+
+   err = pci_host_probe(host);
if (err)
goto put_resources;
 
-- 
2.6.4



[PATCH v7 1/9] PCI: mediatek: Using slot's devfn for compare to fix mtk_pcie_find_port logic

2018-10-14 Thread honghui.zhang
From: Honghui Zhang 

The Mediatek's host controller has two slots, each with it's own control
registers. The host driver need to identify which slot was connected
in order to access the device's configuration space. There's problem
for current host driver to find out which slot was connected to for
a given EP device.

Assuming each slot have connect with one EP device as below:

host bridge
  bus 0 --> __|___
   |  |
   |  |
 slot 0 slot 1
  bus 1 -->|bus 2 --> |
   |  |
 EP 0   EP 1

During PCI enumeration, system software will scan all the PCI device
starting from devfn 0. So it will get the proper port for slot0 and
slot1 device when using PCI_SLOT(devfn) for match. But it will get
the wrong slot for EP1: The devfn will be start from 0 when scanning
EP1 behind slot1, it will get port0 since the PCI_SLOT(EP1) is match
for port0's slot value. So the host driver should not using EP's devfn
but the slot's devfn(the slot which EP was connected to) for match.

This patch fix the mtk_pcie_find_port's logic by using the slot's
devfn for match if finding device connected to the subordinate bus.

Signed-off-by: Honghui Zhang 
---
 drivers/pci/controller/pcie-mediatek.c | 11 +++
 1 file changed, 11 insertions(+)

diff --git a/drivers/pci/controller/pcie-mediatek.c 
b/drivers/pci/controller/pcie-mediatek.c
index dae..288b8e2 100644
--- a/drivers/pci/controller/pcie-mediatek.c
+++ b/drivers/pci/controller/pcie-mediatek.c
@@ -337,6 +337,17 @@ static struct mtk_pcie_port *mtk_pcie_find_port(struct 
pci_bus *bus,
 {
struct mtk_pcie *pcie = bus->sysdata;
struct mtk_pcie_port *port;
+   struct pci_dev *dev = NULL;
+
+   /*
+* Walk the bus hierarchy to get the devfn value
+* of the port in the root bus.
+*/
+   while (bus && bus->number) {
+   dev = bus->self;
+   bus = dev->bus;
+   devfn = dev->devfn;
+   }
 
list_for_each_entry(port, &pcie->ports, list)
if (port->slot == PCI_SLOT(devfn))
-- 
2.6.4



[PATCH v7 5/9] PCI: mediatek: Move the mtk_pcie_startup_port_v2 function's define after mtk_pcie_setup_irq

2018-10-14 Thread honghui.zhang
From: Honghui Zhang 

This is a prepare patch to fix enable MSI logic, move the function's
define later to avoid forward declaration of mtk_pcie_enable_msi in
the future. No functional changed.

Signed-off-by: Honghui Zhang 
---
 drivers/pci/controller/pcie-mediatek.c | 138 -
 1 file changed, 69 insertions(+), 69 deletions(-)

diff --git a/drivers/pci/controller/pcie-mediatek.c 
b/drivers/pci/controller/pcie-mediatek.c
index ead6005..654a63e 100644
--- a/drivers/pci/controller/pcie-mediatek.c
+++ b/drivers/pci/controller/pcie-mediatek.c
@@ -392,75 +392,6 @@ static struct pci_ops mtk_pcie_ops_v2 = {
.write = mtk_pcie_config_write,
 };
 
-static int mtk_pcie_startup_port_v2(struct mtk_pcie_port *port)
-{
-   struct mtk_pcie *pcie = port->pcie;
-   struct resource *mem = &pcie->mem;
-   const struct mtk_pcie_soc *soc = port->pcie->soc;
-   u32 val;
-   size_t size;
-   int err;
-
-   /* MT7622 platforms need to enable LTSSM and ASPM from PCIe subsys */
-   if (pcie->base) {
-   val = readl(pcie->base + PCIE_SYS_CFG_V2);
-   val |= PCIE_CSR_LTSSM_EN(port->slot) |
-  PCIE_CSR_ASPM_L1_EN(port->slot);
-   writel(val, pcie->base + PCIE_SYS_CFG_V2);
-   }
-
-   /* Assert all reset signals */
-   writel(0, port->base + PCIE_RST_CTRL);
-
-   /*
-* Enable PCIe link down reset, if link status changed from link up to
-* link down, this will reset MAC control registers and configuration
-* space.
-*/
-   writel(PCIE_LINKDOWN_RST_EN, port->base + PCIE_RST_CTRL);
-
-   /* De-assert PHY, PE, PIPE, MAC and configuration reset */
-   val = readl(port->base + PCIE_RST_CTRL);
-   val |= PCIE_PHY_RSTB | PCIE_PERSTB | PCIE_PIPE_SRSTB |
-  PCIE_MAC_SRSTB | PCIE_CRSTB;
-   writel(val, port->base + PCIE_RST_CTRL);
-
-   /* Set up vendor ID and class code */
-   if (soc->need_fix_class_id) {
-   val = PCI_VENDOR_ID_MEDIATEK;
-   writew(val, port->base + PCIE_CONF_VEND_ID);
-
-   val = PCI_CLASS_BRIDGE_PCI;
-   writew(val, port->base + PCIE_CONF_CLASS_ID);
-   }
-
-   /* 100ms timeout value should be enough for Gen1/2 training */
-   err = readl_poll_timeout(port->base + PCIE_LINK_STATUS_V2, val,
-!!(val & PCIE_PORT_LINKUP_V2), 20,
-100 * USEC_PER_MSEC);
-   if (err)
-   return -ETIMEDOUT;
-
-   /* Set INTx mask */
-   val = readl(port->base + PCIE_INT_MASK);
-   val &= ~INTX_MASK;
-   writel(val, port->base + PCIE_INT_MASK);
-
-   /* Set AHB to PCIe translation windows */
-   size = mem->end - mem->start;
-   val = lower_32_bits(mem->start) | AHB2PCIE_SIZE(fls(size));
-   writel(val, port->base + PCIE_AHB_TRANS_BASE0_L);
-
-   val = upper_32_bits(mem->start);
-   writel(val, port->base + PCIE_AHB_TRANS_BASE0_H);
-
-   /* Set PCIe to AXI translation memory space.*/
-   val = fls(0x) | WIN_ENABLE;
-   writel(val, port->base + PCIE_AXI_WINDOW0);
-
-   return 0;
-}
-
 static void mtk_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
 {
struct mtk_pcie_port *port = irq_data_get_irq_chip_data(data);
@@ -705,6 +636,75 @@ static int mtk_pcie_setup_irq(struct mtk_pcie_port *port,
return 0;
 }
 
+static int mtk_pcie_startup_port_v2(struct mtk_pcie_port *port)
+{
+   struct mtk_pcie *pcie = port->pcie;
+   struct resource *mem = &pcie->mem;
+   const struct mtk_pcie_soc *soc = port->pcie->soc;
+   u32 val;
+   size_t size;
+   int err;
+
+   /* MT7622 platforms need to enable LTSSM and ASPM from PCIe subsys */
+   if (pcie->base) {
+   val = readl(pcie->base + PCIE_SYS_CFG_V2);
+   val |= PCIE_CSR_LTSSM_EN(port->slot) |
+  PCIE_CSR_ASPM_L1_EN(port->slot);
+   writel(val, pcie->base + PCIE_SYS_CFG_V2);
+   }
+
+   /* Assert all reset signals */
+   writel(0, port->base + PCIE_RST_CTRL);
+
+   /*
+* Enable PCIe link down reset, if link status changed from link up to
+* link down, this will reset MAC control registers and configuration
+* space.
+*/
+   writel(PCIE_LINKDOWN_RST_EN, port->base + PCIE_RST_CTRL);
+
+   /* De-assert PHY, PE, PIPE, MAC and configuration reset */
+   val = readl(port->base + PCIE_RST_CTRL);
+   val |= PCIE_PHY_RSTB | PCIE_PERSTB | PCIE_PIPE_SRSTB |
+  PCIE_MAC_SRSTB | PCIE_CRSTB;
+   writel(val, port->base + PCIE_RST_CTRL);
+
+   /* Set up vendor ID and class code */
+   if (soc->need_fix_class_id) {
+   val = PCI_VENDOR_ID_MEDIATEK;
+   writew(val, port->base + PCIE_CONF_VEND_ID);
+
+   val = PCI_CLASS_BRIDGE_PCI;
+   writew(val, port->base + PCIE_CONF_CLASS_ID)

[PATCH v7 2/9] PCI: mediatek: Fix class type for MT7622 as PCI_CLASS_BRIDGE_PCI

2018-10-14 Thread honghui.zhang
From: Honghui Zhang 

The commit 101c92dc80c8 ("PCI: mediatek: Set up vendor ID and class
type for MT7622") have set the class type for MT7622 as un-properly
value of PCI_CLASS_BRIDGE_HOST.

The PCIe controller of MT7622 is complexed with Root Port and PCI-to-PCI
bridge, the bridge has type 1 configuration space header and related bridge
windows. The HW default value of this bridge's class type is invalid. Fix
its class type as PCI_CLASS_BRIDGE_PCI since it is HW defines.

Making the bridge visiable to PCI framework by setting its class type
properly will get its bridge windows configurated during PCI device
enumerate.

Signed-off-by: Honghui Zhang 
---
 drivers/pci/controller/pcie-mediatek.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/pci/controller/pcie-mediatek.c 
b/drivers/pci/controller/pcie-mediatek.c
index 288b8e2..bcdac9b 100644
--- a/drivers/pci/controller/pcie-mediatek.c
+++ b/drivers/pci/controller/pcie-mediatek.c
@@ -432,7 +432,7 @@ static int mtk_pcie_startup_port_v2(struct mtk_pcie_port 
*port)
val = PCI_VENDOR_ID_MEDIATEK;
writew(val, port->base + PCIE_CONF_VEND_ID);
 
-   val = PCI_CLASS_BRIDGE_HOST;
+   val = PCI_CLASS_BRIDGE_PCI;
writew(val, port->base + PCIE_CONF_CLASS_ID);
}
 
-- 
2.6.4



[PATCH v7 9/9] PCI: mediatek: Add loadable kernel module support

2018-10-14 Thread honghui.zhang
From: Honghui Zhang 

Implement remove callback function for Mediatek PCIe driver to add
loadable kernel module support.

Signed-off-by: Honghui Zhang 
Reviewed-by: Ryder Lee 
---
 drivers/pci/controller/Kconfig |  2 +-
 drivers/pci/controller/pcie-mediatek.c | 51 +-
 2 files changed, 51 insertions(+), 2 deletions(-)

diff --git a/drivers/pci/controller/Kconfig b/drivers/pci/controller/Kconfig
index 028b287..465790f 100644
--- a/drivers/pci/controller/Kconfig
+++ b/drivers/pci/controller/Kconfig
@@ -231,7 +231,7 @@ config PCIE_ROCKCHIP_EP
  available to support GEN2 with 4 slots.
 
 config PCIE_MEDIATEK
-   bool "MediaTek PCIe controller"
+   tristate "MediaTek PCIe controller"
depends on ARCH_MEDIATEK || COMPILE_TEST
depends on OF
depends on PCI_MSI_IRQ_DOMAIN
diff --git a/drivers/pci/controller/pcie-mediatek.c 
b/drivers/pci/controller/pcie-mediatek.c
index daba78f..5048adb 100644
--- a/drivers/pci/controller/pcie-mediatek.c
+++ b/drivers/pci/controller/pcie-mediatek.c
@@ -15,6 +15,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -532,6 +533,27 @@ static void mtk_pcie_enable_msi(struct mtk_pcie_port *port)
writel(val, port->base + PCIE_INT_MASK);
 }
 
+static void mtk_pcie_irq_teardown(struct mtk_pcie *pcie)
+{
+   struct mtk_pcie_port *port, *tmp;
+
+   list_for_each_entry_safe(port, tmp, &pcie->ports, list) {
+   irq_set_chained_handler_and_data(port->irq, NULL, NULL);
+
+   if (port->irq_domain)
+   irq_domain_remove(port->irq_domain);
+
+   if (IS_ENABLED(CONFIG_PCI_MSI)) {
+   if (port->msi_domain)
+   irq_domain_remove(port->msi_domain);
+   if (port->inner_domain)
+   irq_domain_remove(port->inner_domain);
+   }
+
+   irq_dispose_mapping(port->irq);
+   }
+}
+
 static int mtk_pcie_intx_map(struct irq_domain *domain, unsigned int irq,
 irq_hw_number_t hwirq)
 {
@@ -1171,6 +1193,31 @@ static int mtk_pcie_probe(struct platform_device *pdev)
return err;
 }
 
+
+static void mtk_pcie_free_resources(struct mtk_pcie *pcie)
+{
+   struct pci_host_bridge *host = pci_host_bridge_from_priv(pcie);
+   struct list_head *windows = &host->windows;
+
+   pci_free_resource_list(windows);
+}
+
+static int mtk_pcie_remove(struct platform_device *pdev)
+{
+   struct mtk_pcie *pcie = platform_get_drvdata(pdev);
+   struct pci_host_bridge *host = pci_host_bridge_from_priv(pcie);
+
+   pci_stop_root_bus(host->bus);
+   pci_remove_root_bus(host->bus);
+   mtk_pcie_free_resources(pcie);
+
+   mtk_pcie_irq_teardown(pcie);
+
+   mtk_pcie_put_resources(pcie);
+
+   return 0;
+}
+
 static int __maybe_unused mtk_pcie_suspend_noirq(struct device *dev)
 {
struct mtk_pcie *pcie = dev_get_drvdata(dev);
@@ -1248,6 +1295,7 @@ static const struct of_device_id mtk_pcie_ids[] = {
 
 static struct platform_driver mtk_pcie_driver = {
.probe = mtk_pcie_probe,
+   .remove = mtk_pcie_remove,
.driver = {
.name = "mtk-pcie",
.of_match_table = mtk_pcie_ids,
@@ -1255,4 +1303,5 @@ static struct platform_driver mtk_pcie_driver = {
.pm = &mtk_pcie_pm_ops,
},
 };
-builtin_platform_driver(mtk_pcie_driver);
+module_platform_driver(mtk_pcie_driver);
+MODULE_LICENSE("GPL v2");
-- 
2.6.4



[PATCH v7 8/9] PCI: mediatek: Save the GIC IRQ in mtk_pcie_port

2018-10-14 Thread honghui.zhang
From: Honghui Zhang 

Need to save the PCIe's GIC IRQ for dispose_irq, this is a prepare
patch for add mediatek PCIe module support to tear down the IRQ, no
functional changed.

Signed-off-by: Honghui Zhang 
---
 drivers/pci/controller/pcie-mediatek.c | 9 ++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/drivers/pci/controller/pcie-mediatek.c 
b/drivers/pci/controller/pcie-mediatek.c
index 42cf2a4..daba78f 100644
--- a/drivers/pci/controller/pcie-mediatek.c
+++ b/drivers/pci/controller/pcie-mediatek.c
@@ -162,6 +162,7 @@ struct mtk_pcie_soc {
  * @phy: pointer to PHY control block
  * @lane: lane count
  * @slot: port slot
+ * @irq: GIC irq
  * @irq_domain: legacy INTx IRQ domain
  * @inner_domain: inner IRQ domain
  * @msi_domain: MSI IRQ domain
@@ -182,6 +183,7 @@ struct mtk_pcie_port {
struct phy *phy;
u32 lane;
u32 slot;
+   int irq;
struct irq_domain *irq_domain;
struct irq_domain *inner_domain;
struct irq_domain *msi_domain;
@@ -620,7 +622,7 @@ static int mtk_pcie_setup_irq(struct mtk_pcie_port *port,
struct mtk_pcie *pcie = port->pcie;
struct device *dev = pcie->dev;
struct platform_device *pdev = to_platform_device(dev);
-   int err, irq;
+   int err;
 
err = mtk_pcie_init_irq_domain(port, node);
if (err) {
@@ -628,8 +630,9 @@ static int mtk_pcie_setup_irq(struct mtk_pcie_port *port,
return err;
}
 
-   irq = platform_get_irq(pdev, port->slot);
-   irq_set_chained_handler_and_data(irq, mtk_pcie_intr_handler, port);
+   port->irq = platform_get_irq(pdev, port->slot);
+   irq_set_chained_handler_and_data(port->irq,
+mtk_pcie_intr_handler, port);
 
return 0;
 }
-- 
2.6.4



[PATCH v7 6/9] PCI: mediatek: Fixup enable MSI logic by enable MSI after clock enabled

2018-10-14 Thread honghui.zhang
From: Honghui Zhang 

The commit 43e6409db64d ("PCI: mediatek: Add MSI support for MT2712 and
MT7622") added MSI support but enable MSI in wrong place, clocks was not
enabled when enable MSI. This patch fix this issue by calling
mtk_pcie_enable_msi in mtk_pcie_startup_port_v2 since the clock was all
enabled at that time.

Signed-off-by: Honghui Zhang 
---
 drivers/pci/controller/pcie-mediatek.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/pci/controller/pcie-mediatek.c 
b/drivers/pci/controller/pcie-mediatek.c
index 654a63e..d3f4694 100644
--- a/drivers/pci/controller/pcie-mediatek.c
+++ b/drivers/pci/controller/pcie-mediatek.c
@@ -568,8 +568,6 @@ static int mtk_pcie_init_irq_domain(struct mtk_pcie_port 
*port,
ret = mtk_pcie_allocate_msi_domains(port);
if (ret)
return ret;
-
-   mtk_pcie_enable_msi(port);
}
 
return 0;
@@ -690,6 +688,9 @@ static int mtk_pcie_startup_port_v2(struct mtk_pcie_port 
*port)
val &= ~INTX_MASK;
writel(val, port->base + PCIE_INT_MASK);
 
+   if (IS_ENABLED(CONFIG_PCI_MSI))
+   mtk_pcie_enable_msi(port);
+
/* Set AHB to PCIe translation windows */
size = mem->end - mem->start;
val = lower_32_bits(mem->start) | AHB2PCIE_SIZE(fls(size));
-- 
2.6.4



[PATCH v7 3/9] PCI: mediatek: Remove the redundant dev->pm_domain check

2018-10-14 Thread honghui.zhang
From: Honghui Zhang 

It's no needed to check whether device have pm_domain attached before
calling the pm_runtime_XXX interface, remove it.

Signed-off-by: Honghui Zhang 
---
 drivers/pci/controller/pcie-mediatek.c | 18 ++
 1 file changed, 6 insertions(+), 12 deletions(-)

diff --git a/drivers/pci/controller/pcie-mediatek.c 
b/drivers/pci/controller/pcie-mediatek.c
index bcdac9b..59fdb60 100644
--- a/drivers/pci/controller/pcie-mediatek.c
+++ b/drivers/pci/controller/pcie-mediatek.c
@@ -225,10 +225,8 @@ static void mtk_pcie_subsys_powerdown(struct mtk_pcie 
*pcie)
 
clk_disable_unprepare(pcie->free_ck);
 
-   if (dev->pm_domain) {
-   pm_runtime_put_sync(dev);
-   pm_runtime_disable(dev);
-   }
+   pm_runtime_put_sync(dev);
+   pm_runtime_disable(dev);
 }
 
 static void mtk_pcie_port_free(struct mtk_pcie_port *port)
@@ -998,10 +996,8 @@ static int mtk_pcie_subsys_powerup(struct mtk_pcie *pcie)
pcie->free_ck = NULL;
}
 
-   if (dev->pm_domain) {
-   pm_runtime_enable(dev);
-   pm_runtime_get_sync(dev);
-   }
+   pm_runtime_enable(dev);
+   pm_runtime_get_sync(dev);
 
/* enable top level clock */
err = clk_prepare_enable(pcie->free_ck);
@@ -1013,10 +1009,8 @@ static int mtk_pcie_subsys_powerup(struct mtk_pcie *pcie)
return 0;
 
 err_free_ck:
-   if (dev->pm_domain) {
-   pm_runtime_put_sync(dev);
-   pm_runtime_disable(dev);
-   }
+   pm_runtime_put_sync(dev);
+   pm_runtime_disable(dev);
 
return err;
 }
-- 
2.6.4



[PATCH v8 4/9] PCI: mediatek: Convert to use pci_host_probe()

2018-10-15 Thread honghui.zhang
From: Honghui Zhang 

Part of mtk_pcie_register_host is an open-coded version of
pci_host_probe(). So instead of duplicating this code, use
pci_host_probe() directly and remove mtk_pcie_register_host.

Signed-off-by: Honghui Zhang 
Acked-by: Ryder Lee 
---
 drivers/pci/controller/pcie-mediatek.c | 37 --
 1 file changed, 8 insertions(+), 29 deletions(-)

diff --git a/drivers/pci/controller/pcie-mediatek.c 
b/drivers/pci/controller/pcie-mediatek.c
index 59fdb60..ead6005 100644
--- a/drivers/pci/controller/pcie-mediatek.c
+++ b/drivers/pci/controller/pcie-mediatek.c
@@ -1121,34 +1121,6 @@ static int mtk_pcie_request_resources(struct mtk_pcie 
*pcie)
return 0;
 }
 
-static int mtk_pcie_register_host(struct pci_host_bridge *host)
-{
-   struct mtk_pcie *pcie = pci_host_bridge_priv(host);
-   struct pci_bus *child;
-   int err;
-
-   host->busnr = pcie->busn.start;
-   host->dev.parent = pcie->dev;
-   host->ops = pcie->soc->ops;
-   host->map_irq = of_irq_parse_and_map_pci;
-   host->swizzle_irq = pci_common_swizzle;
-   host->sysdata = pcie;
-
-   err = pci_scan_root_bus_bridge(host);
-   if (err < 0)
-   return err;
-
-   pci_bus_size_bridges(host->bus);
-   pci_bus_assign_resources(host->bus);
-
-   list_for_each_entry(child, &host->bus->children, node)
-   pcie_bus_configure_settings(child);
-
-   pci_bus_add_devices(host->bus);
-
-   return 0;
-}
-
 static int mtk_pcie_probe(struct platform_device *pdev)
 {
struct device *dev = &pdev->dev;
@@ -1175,7 +1147,14 @@ static int mtk_pcie_probe(struct platform_device *pdev)
if (err)
goto put_resources;
 
-   err = mtk_pcie_register_host(host);
+   host->busnr = pcie->busn.start;
+   host->dev.parent = pcie->dev;
+   host->ops = pcie->soc->ops;
+   host->map_irq = of_irq_parse_and_map_pci;
+   host->swizzle_irq = pci_common_swizzle;
+   host->sysdata = pcie;
+
+   err = pci_host_probe(host);
if (err)
goto put_resources;
 
-- 
2.6.4



[PATCH v8 0/9] PCI: mediatek: fixup find_port, enable_msi and add PM, module support

2018-10-15 Thread honghui.zhang
From: Honghui Zhang 

This patchset includes misc patchs:

The patch 1 fixup the mtk_pcie_find_port logic which will cause system
could not touch the EP's configuration space that connected to PCIe slot 1.

The patch 2 fixup the class type for MT7622.
The patch 6 fixup the enable msi logic, the operation to enable MSI
should be after system clock is enabled. Call mtk_pcie_enable_msi in
mtk_pcie_startup_port_v2 since the clock was all enabled at that time.

The patch 7 was rebased and refactor of the v4 patch[1], changes are:
 -Add PM support for MT7622.
 -Using mtk_pcie_enable_port to re-establish the link when resumed.
 -Rebased on this patchset.

The patch 9 add loadable kernel module support.

[1] https://patchwork.kernel.org/patch/10479079

Change since v7:
 - Add Acked-by tags from Ryder Lee.
 - Add Fix tags for patch 2(Fix calss type for MT7622 as PCI_CLASS_BRIDGE_PCI)
   and patch 6(Fixup enable MSI logic by enable MSI after clock enabled)

Change since v6:
 - Remove the pci_unmap_iospace when remove the device since the
   devm_pci_remap_iospace is an devm_ version.
 - Commit message changed for patch 2(Fix class type for MT7622 as 
PCI_CLASS_BRIDGE_PCI).
 - Capitilizing "MSI" and "PM" in the patch title.

Change since v5:
 - A bit improvement of mtk_pcie_find_port suggest by Lorenzo.
   MSI after clock enabled).
 - Add Acked-by tags from Ryder.

Change since v4:
 - Add patch 2 to fixup class type for MT7622.
 - Add patch 3 to remove the redundant dev->pm_domain check
 - Add patch 4 to covert to use pci_host_probe
 - Add patch 5 to re-arrange the function define, this is a prepare patch for
   fixup the enable_msi logic, no functional changed have been made by this one.
 - Add patch 8 to save the GIC IRQ in mtk_pcie_port as a prepare patch for tear
   down the irq when remove the kernel module.
 - Re-arrange the find_port flow suggest by Lorenzo to make the code parse 
easier
   for the patch 1.
 - Remove the .pm_support in mtk_pcie_soc in patch 7 since if system pm was not
   supported, then those pm callbacks will never be executed for MT7622. So the
   .pm_support is not needed.

Change since v3:
 - Remove pm_runtime_XXX ops in suspend and resume callbacks in the third patch.
 - Rebase to 4.19-rc1.

Change since v2:
 - Fix the list_for_each_entry_safe parameter error.
 - Add Ryder's Acked-by flag.

Change since v1:
 - A bit of code refact of the first patch suggested by Andy Shevchenko, and
   commit message updated.

Honghui Zhang (9):
  PCI: mediatek: Using slot's devfn for compare to fix
mtk_pcie_find_port logic
  PCI: mediatek: Fix class type for MT7622 as PCI_CLASS_BRIDGE_PCI
  PCI: mediatek: Remove the redundant dev->pm_domain check
  PCI: mediatek: Convert to use pci_host_probe()
  PCI: mediatek: Move the mtk_pcie_startup_port_v2 function's define
after mtk_pcie_setup_irq
  PCI: mediatek: Fixup enable MSI logic by enable MSI after clock
enabled
  PCI: mediatek: Add system PM support for MT2712 and MT7622
  PCI: mediatek: Save the GIC IRQ in mtk_pcie_port
  PCI: mediatek: Add loadable kernel module support

 drivers/pci/controller/Kconfig |   2 +-
 drivers/pci/controller/pcie-mediatek.c | 319 +
 2 files changed, 204 insertions(+), 117 deletions(-)

-- 
2.6.4



[PATCH v8 9/9] PCI: mediatek: Add loadable kernel module support

2018-10-15 Thread honghui.zhang
From: Honghui Zhang 

Implement remove callback function for Mediatek PCIe driver to add
loadable kernel module support.

Signed-off-by: Honghui Zhang 
Reviewed-by: Ryder Lee 
---
 drivers/pci/controller/Kconfig |  2 +-
 drivers/pci/controller/pcie-mediatek.c | 51 +-
 2 files changed, 51 insertions(+), 2 deletions(-)

diff --git a/drivers/pci/controller/Kconfig b/drivers/pci/controller/Kconfig
index 028b287..465790f 100644
--- a/drivers/pci/controller/Kconfig
+++ b/drivers/pci/controller/Kconfig
@@ -231,7 +231,7 @@ config PCIE_ROCKCHIP_EP
  available to support GEN2 with 4 slots.
 
 config PCIE_MEDIATEK
-   bool "MediaTek PCIe controller"
+   tristate "MediaTek PCIe controller"
depends on ARCH_MEDIATEK || COMPILE_TEST
depends on OF
depends on PCI_MSI_IRQ_DOMAIN
diff --git a/drivers/pci/controller/pcie-mediatek.c 
b/drivers/pci/controller/pcie-mediatek.c
index daba78f..5048adb 100644
--- a/drivers/pci/controller/pcie-mediatek.c
+++ b/drivers/pci/controller/pcie-mediatek.c
@@ -15,6 +15,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -532,6 +533,27 @@ static void mtk_pcie_enable_msi(struct mtk_pcie_port *port)
writel(val, port->base + PCIE_INT_MASK);
 }
 
+static void mtk_pcie_irq_teardown(struct mtk_pcie *pcie)
+{
+   struct mtk_pcie_port *port, *tmp;
+
+   list_for_each_entry_safe(port, tmp, &pcie->ports, list) {
+   irq_set_chained_handler_and_data(port->irq, NULL, NULL);
+
+   if (port->irq_domain)
+   irq_domain_remove(port->irq_domain);
+
+   if (IS_ENABLED(CONFIG_PCI_MSI)) {
+   if (port->msi_domain)
+   irq_domain_remove(port->msi_domain);
+   if (port->inner_domain)
+   irq_domain_remove(port->inner_domain);
+   }
+
+   irq_dispose_mapping(port->irq);
+   }
+}
+
 static int mtk_pcie_intx_map(struct irq_domain *domain, unsigned int irq,
 irq_hw_number_t hwirq)
 {
@@ -1171,6 +1193,31 @@ static int mtk_pcie_probe(struct platform_device *pdev)
return err;
 }
 
+
+static void mtk_pcie_free_resources(struct mtk_pcie *pcie)
+{
+   struct pci_host_bridge *host = pci_host_bridge_from_priv(pcie);
+   struct list_head *windows = &host->windows;
+
+   pci_free_resource_list(windows);
+}
+
+static int mtk_pcie_remove(struct platform_device *pdev)
+{
+   struct mtk_pcie *pcie = platform_get_drvdata(pdev);
+   struct pci_host_bridge *host = pci_host_bridge_from_priv(pcie);
+
+   pci_stop_root_bus(host->bus);
+   pci_remove_root_bus(host->bus);
+   mtk_pcie_free_resources(pcie);
+
+   mtk_pcie_irq_teardown(pcie);
+
+   mtk_pcie_put_resources(pcie);
+
+   return 0;
+}
+
 static int __maybe_unused mtk_pcie_suspend_noirq(struct device *dev)
 {
struct mtk_pcie *pcie = dev_get_drvdata(dev);
@@ -1248,6 +1295,7 @@ static const struct of_device_id mtk_pcie_ids[] = {
 
 static struct platform_driver mtk_pcie_driver = {
.probe = mtk_pcie_probe,
+   .remove = mtk_pcie_remove,
.driver = {
.name = "mtk-pcie",
.of_match_table = mtk_pcie_ids,
@@ -1255,4 +1303,5 @@ static struct platform_driver mtk_pcie_driver = {
.pm = &mtk_pcie_pm_ops,
},
 };
-builtin_platform_driver(mtk_pcie_driver);
+module_platform_driver(mtk_pcie_driver);
+MODULE_LICENSE("GPL v2");
-- 
2.6.4



[PATCH v8 3/9] PCI: mediatek: Remove the redundant dev->pm_domain check

2018-10-15 Thread honghui.zhang
From: Honghui Zhang 

It's no needed to check whether device have pm_domain attached before
calling the pm_runtime_XXX interface, remove it.

Signed-off-by: Honghui Zhang 
Acked-by: Ryder Lee 
---
 drivers/pci/controller/pcie-mediatek.c | 18 ++
 1 file changed, 6 insertions(+), 12 deletions(-)

diff --git a/drivers/pci/controller/pcie-mediatek.c 
b/drivers/pci/controller/pcie-mediatek.c
index bcdac9b..59fdb60 100644
--- a/drivers/pci/controller/pcie-mediatek.c
+++ b/drivers/pci/controller/pcie-mediatek.c
@@ -225,10 +225,8 @@ static void mtk_pcie_subsys_powerdown(struct mtk_pcie 
*pcie)
 
clk_disable_unprepare(pcie->free_ck);
 
-   if (dev->pm_domain) {
-   pm_runtime_put_sync(dev);
-   pm_runtime_disable(dev);
-   }
+   pm_runtime_put_sync(dev);
+   pm_runtime_disable(dev);
 }
 
 static void mtk_pcie_port_free(struct mtk_pcie_port *port)
@@ -998,10 +996,8 @@ static int mtk_pcie_subsys_powerup(struct mtk_pcie *pcie)
pcie->free_ck = NULL;
}
 
-   if (dev->pm_domain) {
-   pm_runtime_enable(dev);
-   pm_runtime_get_sync(dev);
-   }
+   pm_runtime_enable(dev);
+   pm_runtime_get_sync(dev);
 
/* enable top level clock */
err = clk_prepare_enable(pcie->free_ck);
@@ -1013,10 +1009,8 @@ static int mtk_pcie_subsys_powerup(struct mtk_pcie *pcie)
return 0;
 
 err_free_ck:
-   if (dev->pm_domain) {
-   pm_runtime_put_sync(dev);
-   pm_runtime_disable(dev);
-   }
+   pm_runtime_put_sync(dev);
+   pm_runtime_disable(dev);
 
return err;
 }
-- 
2.6.4



[PATCH v8 5/9] PCI: mediatek: Move the mtk_pcie_startup_port_v2 function's define after mtk_pcie_setup_irq

2018-10-15 Thread honghui.zhang
From: Honghui Zhang 

This is a prepare patch to fix enable MSI logic, move the function's
define later to avoid forward declaration of mtk_pcie_enable_msi in
the future. No functional changed.

Signed-off-by: Honghui Zhang 
Acked-by: Ryder Lee 
---
 drivers/pci/controller/pcie-mediatek.c | 138 -
 1 file changed, 69 insertions(+), 69 deletions(-)

diff --git a/drivers/pci/controller/pcie-mediatek.c 
b/drivers/pci/controller/pcie-mediatek.c
index ead6005..654a63e 100644
--- a/drivers/pci/controller/pcie-mediatek.c
+++ b/drivers/pci/controller/pcie-mediatek.c
@@ -392,75 +392,6 @@ static struct pci_ops mtk_pcie_ops_v2 = {
.write = mtk_pcie_config_write,
 };
 
-static int mtk_pcie_startup_port_v2(struct mtk_pcie_port *port)
-{
-   struct mtk_pcie *pcie = port->pcie;
-   struct resource *mem = &pcie->mem;
-   const struct mtk_pcie_soc *soc = port->pcie->soc;
-   u32 val;
-   size_t size;
-   int err;
-
-   /* MT7622 platforms need to enable LTSSM and ASPM from PCIe subsys */
-   if (pcie->base) {
-   val = readl(pcie->base + PCIE_SYS_CFG_V2);
-   val |= PCIE_CSR_LTSSM_EN(port->slot) |
-  PCIE_CSR_ASPM_L1_EN(port->slot);
-   writel(val, pcie->base + PCIE_SYS_CFG_V2);
-   }
-
-   /* Assert all reset signals */
-   writel(0, port->base + PCIE_RST_CTRL);
-
-   /*
-* Enable PCIe link down reset, if link status changed from link up to
-* link down, this will reset MAC control registers and configuration
-* space.
-*/
-   writel(PCIE_LINKDOWN_RST_EN, port->base + PCIE_RST_CTRL);
-
-   /* De-assert PHY, PE, PIPE, MAC and configuration reset */
-   val = readl(port->base + PCIE_RST_CTRL);
-   val |= PCIE_PHY_RSTB | PCIE_PERSTB | PCIE_PIPE_SRSTB |
-  PCIE_MAC_SRSTB | PCIE_CRSTB;
-   writel(val, port->base + PCIE_RST_CTRL);
-
-   /* Set up vendor ID and class code */
-   if (soc->need_fix_class_id) {
-   val = PCI_VENDOR_ID_MEDIATEK;
-   writew(val, port->base + PCIE_CONF_VEND_ID);
-
-   val = PCI_CLASS_BRIDGE_PCI;
-   writew(val, port->base + PCIE_CONF_CLASS_ID);
-   }
-
-   /* 100ms timeout value should be enough for Gen1/2 training */
-   err = readl_poll_timeout(port->base + PCIE_LINK_STATUS_V2, val,
-!!(val & PCIE_PORT_LINKUP_V2), 20,
-100 * USEC_PER_MSEC);
-   if (err)
-   return -ETIMEDOUT;
-
-   /* Set INTx mask */
-   val = readl(port->base + PCIE_INT_MASK);
-   val &= ~INTX_MASK;
-   writel(val, port->base + PCIE_INT_MASK);
-
-   /* Set AHB to PCIe translation windows */
-   size = mem->end - mem->start;
-   val = lower_32_bits(mem->start) | AHB2PCIE_SIZE(fls(size));
-   writel(val, port->base + PCIE_AHB_TRANS_BASE0_L);
-
-   val = upper_32_bits(mem->start);
-   writel(val, port->base + PCIE_AHB_TRANS_BASE0_H);
-
-   /* Set PCIe to AXI translation memory space.*/
-   val = fls(0x) | WIN_ENABLE;
-   writel(val, port->base + PCIE_AXI_WINDOW0);
-
-   return 0;
-}
-
 static void mtk_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
 {
struct mtk_pcie_port *port = irq_data_get_irq_chip_data(data);
@@ -705,6 +636,75 @@ static int mtk_pcie_setup_irq(struct mtk_pcie_port *port,
return 0;
 }
 
+static int mtk_pcie_startup_port_v2(struct mtk_pcie_port *port)
+{
+   struct mtk_pcie *pcie = port->pcie;
+   struct resource *mem = &pcie->mem;
+   const struct mtk_pcie_soc *soc = port->pcie->soc;
+   u32 val;
+   size_t size;
+   int err;
+
+   /* MT7622 platforms need to enable LTSSM and ASPM from PCIe subsys */
+   if (pcie->base) {
+   val = readl(pcie->base + PCIE_SYS_CFG_V2);
+   val |= PCIE_CSR_LTSSM_EN(port->slot) |
+  PCIE_CSR_ASPM_L1_EN(port->slot);
+   writel(val, pcie->base + PCIE_SYS_CFG_V2);
+   }
+
+   /* Assert all reset signals */
+   writel(0, port->base + PCIE_RST_CTRL);
+
+   /*
+* Enable PCIe link down reset, if link status changed from link up to
+* link down, this will reset MAC control registers and configuration
+* space.
+*/
+   writel(PCIE_LINKDOWN_RST_EN, port->base + PCIE_RST_CTRL);
+
+   /* De-assert PHY, PE, PIPE, MAC and configuration reset */
+   val = readl(port->base + PCIE_RST_CTRL);
+   val |= PCIE_PHY_RSTB | PCIE_PERSTB | PCIE_PIPE_SRSTB |
+  PCIE_MAC_SRSTB | PCIE_CRSTB;
+   writel(val, port->base + PCIE_RST_CTRL);
+
+   /* Set up vendor ID and class code */
+   if (soc->need_fix_class_id) {
+   val = PCI_VENDOR_ID_MEDIATEK;
+   writew(val, port->base + PCIE_CONF_VEND_ID);
+
+   val = PCI_CLASS_BRIDGE_PCI;
+   writew(val, port->base 

[PATCH v8 2/9] PCI: mediatek: Fix class type for MT7622 as PCI_CLASS_BRIDGE_PCI

2018-10-15 Thread honghui.zhang
From: Honghui Zhang 

The commit 101c92dc80c8 ("PCI: mediatek: Set up vendor ID and class
type for MT7622") have set the class type for MT7622 as un-properly
value of PCI_CLASS_BRIDGE_HOST.

The PCIe controller of MT7622 is complexed with Root Port and PCI-to-PCI
bridge, the bridge has type 1 configuration space header and related bridge
windows. The HW default value of this bridge's class type is invalid. Fix
its class type as PCI_CLASS_BRIDGE_PCI since it is HW defines.

Making the bridge visiable to PCI framework by setting its class type
properly will get its bridge windows configurated during PCI device
enumerate.

Fixes: 101c92dc80c8 ("PCI: mediatek: Set up vendor ID and class type for 
MT7622")
Signed-off-by: Honghui Zhang 
Acked-by: Ryder Lee 
---
 drivers/pci/controller/pcie-mediatek.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/pci/controller/pcie-mediatek.c 
b/drivers/pci/controller/pcie-mediatek.c
index 288b8e2..bcdac9b 100644
--- a/drivers/pci/controller/pcie-mediatek.c
+++ b/drivers/pci/controller/pcie-mediatek.c
@@ -432,7 +432,7 @@ static int mtk_pcie_startup_port_v2(struct mtk_pcie_port 
*port)
val = PCI_VENDOR_ID_MEDIATEK;
writew(val, port->base + PCIE_CONF_VEND_ID);
 
-   val = PCI_CLASS_BRIDGE_HOST;
+   val = PCI_CLASS_BRIDGE_PCI;
writew(val, port->base + PCIE_CONF_CLASS_ID);
}
 
-- 
2.6.4



[PATCH v8 1/9] PCI: mediatek: Using slot's devfn for compare to fix mtk_pcie_find_port logic

2018-10-15 Thread honghui.zhang
From: Honghui Zhang 

The Mediatek's host controller has two slots, each with it's own control
registers. The host driver need to identify which slot was connected
in order to access the device's configuration space. There's problem
for current host driver to find out which slot was connected to for
a given EP device.

Assuming each slot have connect with one EP device as below:

host bridge
  bus 0 --> __|___
   |  |
   |  |
 slot 0 slot 1
  bus 1 -->|bus 2 --> |
   |  |
 EP 0   EP 1

During PCI enumeration, system software will scan all the PCI device
starting from devfn 0. So it will get the proper port for slot0 and
slot1 device when using PCI_SLOT(devfn) for match. But it will get
the wrong slot for EP1: The devfn will be start from 0 when scanning
EP1 behind slot1, it will get port0 since the PCI_SLOT(EP1) is match
for port0's slot value. So the host driver should not using EP's devfn
but the slot's devfn(the slot which EP was connected to) for match.

This patch fix the mtk_pcie_find_port's logic by using the slot's
devfn for match if finding device connected to the subordinate bus.

Signed-off-by: Honghui Zhang 
Acked-by: Ryder Lee 
---
 drivers/pci/controller/pcie-mediatek.c | 11 +++
 1 file changed, 11 insertions(+)

diff --git a/drivers/pci/controller/pcie-mediatek.c 
b/drivers/pci/controller/pcie-mediatek.c
index dae..288b8e2 100644
--- a/drivers/pci/controller/pcie-mediatek.c
+++ b/drivers/pci/controller/pcie-mediatek.c
@@ -337,6 +337,17 @@ static struct mtk_pcie_port *mtk_pcie_find_port(struct 
pci_bus *bus,
 {
struct mtk_pcie *pcie = bus->sysdata;
struct mtk_pcie_port *port;
+   struct pci_dev *dev = NULL;
+
+   /*
+* Walk the bus hierarchy to get the devfn value
+* of the port in the root bus.
+*/
+   while (bus && bus->number) {
+   dev = bus->self;
+   bus = dev->bus;
+   devfn = dev->devfn;
+   }
 
list_for_each_entry(port, &pcie->ports, list)
if (port->slot == PCI_SLOT(devfn))
-- 
2.6.4



[PATCH v8 7/9] PCI: mediatek: Add system PM support for MT2712 and MT7622

2018-10-15 Thread honghui.zhang
From: Honghui Zhang 

In order to reduce the PCIe power consuming while system suspend,
the physical layer should be gated. And the PCIe link should be
re-established and the related control register values should be
re-initialized after system resume.

Register suspend_noirq & resume_noirq callback functions to allow
PCIe to come up after resume from RAM.

Signed-off-by: Honghui Zhang 
Acked-by: Ryder Lee 
---
 drivers/pci/controller/pcie-mediatek.c | 50 ++
 1 file changed, 50 insertions(+)

diff --git a/drivers/pci/controller/pcie-mediatek.c 
b/drivers/pci/controller/pcie-mediatek.c
index d3f4694..42cf2a4 100644
--- a/drivers/pci/controller/pcie-mediatek.c
+++ b/drivers/pci/controller/pcie-mediatek.c
@@ -1168,6 +1168,55 @@ static int mtk_pcie_probe(struct platform_device *pdev)
return err;
 }
 
+static int __maybe_unused mtk_pcie_suspend_noirq(struct device *dev)
+{
+   struct mtk_pcie *pcie = dev_get_drvdata(dev);
+   struct mtk_pcie_port *port;
+
+   if (list_empty(&pcie->ports))
+   return 0;
+
+   list_for_each_entry(port, &pcie->ports, list) {
+   clk_disable_unprepare(port->pipe_ck);
+   clk_disable_unprepare(port->obff_ck);
+   clk_disable_unprepare(port->axi_ck);
+   clk_disable_unprepare(port->aux_ck);
+   clk_disable_unprepare(port->ahb_ck);
+   clk_disable_unprepare(port->sys_ck);
+   phy_power_off(port->phy);
+   phy_exit(port->phy);
+   }
+
+   clk_disable_unprepare(pcie->free_ck);
+
+   return 0;
+}
+
+static int __maybe_unused mtk_pcie_resume_noirq(struct device *dev)
+{
+   struct mtk_pcie *pcie = dev_get_drvdata(dev);
+   struct mtk_pcie_port *port, *tmp;
+
+   if (list_empty(&pcie->ports))
+   return 0;
+
+   clk_prepare_enable(pcie->free_ck);
+
+   list_for_each_entry_safe(port, tmp, &pcie->ports, list)
+   mtk_pcie_enable_port(port);
+
+   /* In case of EP was removed while system suspend. */
+   if (list_empty(&pcie->ports))
+   clk_disable_unprepare(pcie->free_ck);
+
+   return 0;
+}
+
+static const struct dev_pm_ops mtk_pcie_pm_ops = {
+   SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(mtk_pcie_suspend_noirq,
+ mtk_pcie_resume_noirq)
+};
+
 static const struct mtk_pcie_soc mtk_pcie_soc_v1 = {
.ops = &mtk_pcie_ops,
.startup = mtk_pcie_startup_port,
@@ -1200,6 +1249,7 @@ static struct platform_driver mtk_pcie_driver = {
.name = "mtk-pcie",
.of_match_table = mtk_pcie_ids,
.suppress_bind_attrs = true,
+   .pm = &mtk_pcie_pm_ops,
},
 };
 builtin_platform_driver(mtk_pcie_driver);
-- 
2.6.4



[PATCH v8 8/9] PCI: mediatek: Save the GIC IRQ in mtk_pcie_port

2018-10-15 Thread honghui.zhang
From: Honghui Zhang 

Need to save the PCIe's GIC IRQ for dispose_irq, this is a prepare
patch for add mediatek PCIe module support to tear down the IRQ, no
functional changed.

Signed-off-by: Honghui Zhang 
Acked-by: Ryder Lee 
---
 drivers/pci/controller/pcie-mediatek.c | 9 ++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/drivers/pci/controller/pcie-mediatek.c 
b/drivers/pci/controller/pcie-mediatek.c
index 42cf2a4..daba78f 100644
--- a/drivers/pci/controller/pcie-mediatek.c
+++ b/drivers/pci/controller/pcie-mediatek.c
@@ -162,6 +162,7 @@ struct mtk_pcie_soc {
  * @phy: pointer to PHY control block
  * @lane: lane count
  * @slot: port slot
+ * @irq: GIC irq
  * @irq_domain: legacy INTx IRQ domain
  * @inner_domain: inner IRQ domain
  * @msi_domain: MSI IRQ domain
@@ -182,6 +183,7 @@ struct mtk_pcie_port {
struct phy *phy;
u32 lane;
u32 slot;
+   int irq;
struct irq_domain *irq_domain;
struct irq_domain *inner_domain;
struct irq_domain *msi_domain;
@@ -620,7 +622,7 @@ static int mtk_pcie_setup_irq(struct mtk_pcie_port *port,
struct mtk_pcie *pcie = port->pcie;
struct device *dev = pcie->dev;
struct platform_device *pdev = to_platform_device(dev);
-   int err, irq;
+   int err;
 
err = mtk_pcie_init_irq_domain(port, node);
if (err) {
@@ -628,8 +630,9 @@ static int mtk_pcie_setup_irq(struct mtk_pcie_port *port,
return err;
}
 
-   irq = platform_get_irq(pdev, port->slot);
-   irq_set_chained_handler_and_data(irq, mtk_pcie_intr_handler, port);
+   port->irq = platform_get_irq(pdev, port->slot);
+   irq_set_chained_handler_and_data(port->irq,
+mtk_pcie_intr_handler, port);
 
return 0;
 }
-- 
2.6.4



[PATCH v8 6/9] PCI: mediatek: Fixup enable MSI logic by enable MSI after clock enabled

2018-10-15 Thread honghui.zhang
From: Honghui Zhang 

The commit 43e6409db64d ("PCI: mediatek: Add MSI support for MT2712 and
MT7622") added MSI support but enable MSI in wrong place, clocks was not
enabled when enable MSI. This patch fix this issue by calling
mtk_pcie_enable_msi in mtk_pcie_startup_port_v2 since the clock was all
enabled at that time.

Fixes: 43e6409db64d ("PCI: mediatek: Add MSI support for MT2712 and MT7622")
Signed-off-by: Honghui Zhang 
Acked-by: Ryder Lee 
---
 drivers/pci/controller/pcie-mediatek.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/pci/controller/pcie-mediatek.c 
b/drivers/pci/controller/pcie-mediatek.c
index 654a63e..d3f4694 100644
--- a/drivers/pci/controller/pcie-mediatek.c
+++ b/drivers/pci/controller/pcie-mediatek.c
@@ -568,8 +568,6 @@ static int mtk_pcie_init_irq_domain(struct mtk_pcie_port 
*port,
ret = mtk_pcie_allocate_msi_domains(port);
if (ret)
return ret;
-
-   mtk_pcie_enable_msi(port);
}
 
return 0;
@@ -690,6 +688,9 @@ static int mtk_pcie_startup_port_v2(struct mtk_pcie_port 
*port)
val &= ~INTX_MASK;
writel(val, port->base + PCIE_INT_MASK);
 
+   if (IS_ENABLED(CONFIG_PCI_MSI))
+   mtk_pcie_enable_msi(port);
+
/* Set AHB to PCIe translation windows */
size = mem->end - mem->start;
val = lower_32_bits(mem->start) | AHB2PCIE_SIZE(fls(size));
-- 
2.6.4



[PATCH v6 5/9] PCI: mediatek: Move the mtk_pcie_startup_port_v2 function's define after mtk_pcie_setup_irq

2018-10-07 Thread honghui.zhang
From: Honghui Zhang 

This is a prepare patch to fix enable MSI logic, move the function's
define later to avoid forward declaration of mtk_pcie_enable_msi in
the future. No functional changed.

Signed-off-by: Honghui Zhang 
Acked-by: Ryder Lee 
---
 drivers/pci/controller/pcie-mediatek.c | 138 -
 1 file changed, 69 insertions(+), 69 deletions(-)

diff --git a/drivers/pci/controller/pcie-mediatek.c 
b/drivers/pci/controller/pcie-mediatek.c
index ead6005..654a63e 100644
--- a/drivers/pci/controller/pcie-mediatek.c
+++ b/drivers/pci/controller/pcie-mediatek.c
@@ -392,75 +392,6 @@ static struct pci_ops mtk_pcie_ops_v2 = {
.write = mtk_pcie_config_write,
 };
 
-static int mtk_pcie_startup_port_v2(struct mtk_pcie_port *port)
-{
-   struct mtk_pcie *pcie = port->pcie;
-   struct resource *mem = &pcie->mem;
-   const struct mtk_pcie_soc *soc = port->pcie->soc;
-   u32 val;
-   size_t size;
-   int err;
-
-   /* MT7622 platforms need to enable LTSSM and ASPM from PCIe subsys */
-   if (pcie->base) {
-   val = readl(pcie->base + PCIE_SYS_CFG_V2);
-   val |= PCIE_CSR_LTSSM_EN(port->slot) |
-  PCIE_CSR_ASPM_L1_EN(port->slot);
-   writel(val, pcie->base + PCIE_SYS_CFG_V2);
-   }
-
-   /* Assert all reset signals */
-   writel(0, port->base + PCIE_RST_CTRL);
-
-   /*
-* Enable PCIe link down reset, if link status changed from link up to
-* link down, this will reset MAC control registers and configuration
-* space.
-*/
-   writel(PCIE_LINKDOWN_RST_EN, port->base + PCIE_RST_CTRL);
-
-   /* De-assert PHY, PE, PIPE, MAC and configuration reset */
-   val = readl(port->base + PCIE_RST_CTRL);
-   val |= PCIE_PHY_RSTB | PCIE_PERSTB | PCIE_PIPE_SRSTB |
-  PCIE_MAC_SRSTB | PCIE_CRSTB;
-   writel(val, port->base + PCIE_RST_CTRL);
-
-   /* Set up vendor ID and class code */
-   if (soc->need_fix_class_id) {
-   val = PCI_VENDOR_ID_MEDIATEK;
-   writew(val, port->base + PCIE_CONF_VEND_ID);
-
-   val = PCI_CLASS_BRIDGE_PCI;
-   writew(val, port->base + PCIE_CONF_CLASS_ID);
-   }
-
-   /* 100ms timeout value should be enough for Gen1/2 training */
-   err = readl_poll_timeout(port->base + PCIE_LINK_STATUS_V2, val,
-!!(val & PCIE_PORT_LINKUP_V2), 20,
-100 * USEC_PER_MSEC);
-   if (err)
-   return -ETIMEDOUT;
-
-   /* Set INTx mask */
-   val = readl(port->base + PCIE_INT_MASK);
-   val &= ~INTX_MASK;
-   writel(val, port->base + PCIE_INT_MASK);
-
-   /* Set AHB to PCIe translation windows */
-   size = mem->end - mem->start;
-   val = lower_32_bits(mem->start) | AHB2PCIE_SIZE(fls(size));
-   writel(val, port->base + PCIE_AHB_TRANS_BASE0_L);
-
-   val = upper_32_bits(mem->start);
-   writel(val, port->base + PCIE_AHB_TRANS_BASE0_H);
-
-   /* Set PCIe to AXI translation memory space.*/
-   val = fls(0x) | WIN_ENABLE;
-   writel(val, port->base + PCIE_AXI_WINDOW0);
-
-   return 0;
-}
-
 static void mtk_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
 {
struct mtk_pcie_port *port = irq_data_get_irq_chip_data(data);
@@ -705,6 +636,75 @@ static int mtk_pcie_setup_irq(struct mtk_pcie_port *port,
return 0;
 }
 
+static int mtk_pcie_startup_port_v2(struct mtk_pcie_port *port)
+{
+   struct mtk_pcie *pcie = port->pcie;
+   struct resource *mem = &pcie->mem;
+   const struct mtk_pcie_soc *soc = port->pcie->soc;
+   u32 val;
+   size_t size;
+   int err;
+
+   /* MT7622 platforms need to enable LTSSM and ASPM from PCIe subsys */
+   if (pcie->base) {
+   val = readl(pcie->base + PCIE_SYS_CFG_V2);
+   val |= PCIE_CSR_LTSSM_EN(port->slot) |
+  PCIE_CSR_ASPM_L1_EN(port->slot);
+   writel(val, pcie->base + PCIE_SYS_CFG_V2);
+   }
+
+   /* Assert all reset signals */
+   writel(0, port->base + PCIE_RST_CTRL);
+
+   /*
+* Enable PCIe link down reset, if link status changed from link up to
+* link down, this will reset MAC control registers and configuration
+* space.
+*/
+   writel(PCIE_LINKDOWN_RST_EN, port->base + PCIE_RST_CTRL);
+
+   /* De-assert PHY, PE, PIPE, MAC and configuration reset */
+   val = readl(port->base + PCIE_RST_CTRL);
+   val |= PCIE_PHY_RSTB | PCIE_PERSTB | PCIE_PIPE_SRSTB |
+  PCIE_MAC_SRSTB | PCIE_CRSTB;
+   writel(val, port->base + PCIE_RST_CTRL);
+
+   /* Set up vendor ID and class code */
+   if (soc->need_fix_class_id) {
+   val = PCI_VENDOR_ID_MEDIATEK;
+   writew(val, port->base + PCIE_CONF_VEND_ID);
+
+   val = PCI_CLASS_BRIDGE_PCI;
+   writew(val, port->base 

[PATCH v6 1/9] PCI: mediatek: Using slot's devfn for compare to fix mtk_pcie_find_port logic

2018-10-07 Thread honghui.zhang
From: Honghui Zhang 

The Mediatek's host controller has two slots, each with it's own control
registers. The host driver need to identify which slot was connected
in order to access the device's configuration space. There's problem
for current host driver to find out which slot was connected to for
a given EP device.

Assuming each slot have connect with one EP device as below:

host bridge
  bus 0 --> __|___
   |  |
   |  |
 slot 0 slot 1
  bus 1 -->|bus 2 --> |
   |  |
 EP 0   EP 1

During PCI enumeration, system software will scan all the PCI device
starting from devfn 0. So it will get the proper port for slot0 and
slot1 device when using PCI_SLOT(devfn) for match. But it will get
the wrong slot for EP1: The devfn will be start from 0 when scanning
EP1 behind slot1, it will get port0 since the PCI_SLOT(EP1) is match
for port0's slot value. So the host driver should not using EP's devfn
but the slot's devfn(the slot which EP was connected to) for match.

This patch fix the mtk_pcie_find_port's logic by using the slot's
devfn for match if finding device connected to the subordinate bus.

Signed-off-by: Honghui Zhang 
---
 drivers/pci/controller/pcie-mediatek.c | 11 +++
 1 file changed, 11 insertions(+)

diff --git a/drivers/pci/controller/pcie-mediatek.c 
b/drivers/pci/controller/pcie-mediatek.c
index dae..288b8e2 100644
--- a/drivers/pci/controller/pcie-mediatek.c
+++ b/drivers/pci/controller/pcie-mediatek.c
@@ -337,6 +337,17 @@ static struct mtk_pcie_port *mtk_pcie_find_port(struct 
pci_bus *bus,
 {
struct mtk_pcie *pcie = bus->sysdata;
struct mtk_pcie_port *port;
+   struct pci_dev *dev = NULL;
+
+   /*
+* Walk the bus hierarchy to get the devfn value
+* of the port in the root bus.
+*/
+   while (bus && bus->number) {
+   dev = bus->self;
+   bus = dev->bus;
+   devfn = dev->devfn;
+   }
 
list_for_each_entry(port, &pcie->ports, list)
if (port->slot == PCI_SLOT(devfn))
-- 
2.6.4



[PATCH v6 8/9] PCI: mediatek: Save the GIC IRQ in mtk_pcie_port

2018-10-07 Thread honghui.zhang
From: Honghui Zhang 

Need to save the PCIe's GIC IRQ for dispose_irq, this is a prepare
patch for add mediatek PCIe module support to tear down the IRQ, no
functional changed.

Signed-off-by: Honghui Zhang 
Acked-by: Ryder Lee 
---
 drivers/pci/controller/pcie-mediatek.c | 9 ++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/drivers/pci/controller/pcie-mediatek.c 
b/drivers/pci/controller/pcie-mediatek.c
index 42cf2a4..daba78f 100644
--- a/drivers/pci/controller/pcie-mediatek.c
+++ b/drivers/pci/controller/pcie-mediatek.c
@@ -162,6 +162,7 @@ struct mtk_pcie_soc {
  * @phy: pointer to PHY control block
  * @lane: lane count
  * @slot: port slot
+ * @irq: GIC irq
  * @irq_domain: legacy INTx IRQ domain
  * @inner_domain: inner IRQ domain
  * @msi_domain: MSI IRQ domain
@@ -182,6 +183,7 @@ struct mtk_pcie_port {
struct phy *phy;
u32 lane;
u32 slot;
+   int irq;
struct irq_domain *irq_domain;
struct irq_domain *inner_domain;
struct irq_domain *msi_domain;
@@ -620,7 +622,7 @@ static int mtk_pcie_setup_irq(struct mtk_pcie_port *port,
struct mtk_pcie *pcie = port->pcie;
struct device *dev = pcie->dev;
struct platform_device *pdev = to_platform_device(dev);
-   int err, irq;
+   int err;
 
err = mtk_pcie_init_irq_domain(port, node);
if (err) {
@@ -628,8 +630,9 @@ static int mtk_pcie_setup_irq(struct mtk_pcie_port *port,
return err;
}
 
-   irq = platform_get_irq(pdev, port->slot);
-   irq_set_chained_handler_and_data(irq, mtk_pcie_intr_handler, port);
+   port->irq = platform_get_irq(pdev, port->slot);
+   irq_set_chained_handler_and_data(port->irq,
+mtk_pcie_intr_handler, port);
 
return 0;
 }
-- 
2.6.4



[PATCH v6 6/9] PCI: mediatek: Fixup enable msi logic by enable msi after clock enabled

2018-10-07 Thread honghui.zhang
From: Honghui Zhang 

The commit 43e6409db64d ("PCI: mediatek: Add MSI support for MT2712 and
MT7622") added MSI support but enable MSI in wrong place, clocks was not
enabled when enable MSI. This patch fix this issue by calling
mtk_pcie_enable_msi in mtk_pcie_startup_port_v2 since the clock was all
enabled at that time.

Signed-off-by: Honghui Zhang 
Acked-by: Ryder Lee 
---
 drivers/pci/controller/pcie-mediatek.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/pci/controller/pcie-mediatek.c 
b/drivers/pci/controller/pcie-mediatek.c
index 654a63e..d3f4694 100644
--- a/drivers/pci/controller/pcie-mediatek.c
+++ b/drivers/pci/controller/pcie-mediatek.c
@@ -568,8 +568,6 @@ static int mtk_pcie_init_irq_domain(struct mtk_pcie_port 
*port,
ret = mtk_pcie_allocate_msi_domains(port);
if (ret)
return ret;
-
-   mtk_pcie_enable_msi(port);
}
 
return 0;
@@ -690,6 +688,9 @@ static int mtk_pcie_startup_port_v2(struct mtk_pcie_port 
*port)
val &= ~INTX_MASK;
writel(val, port->base + PCIE_INT_MASK);
 
+   if (IS_ENABLED(CONFIG_PCI_MSI))
+   mtk_pcie_enable_msi(port);
+
/* Set AHB to PCIe translation windows */
size = mem->end - mem->start;
val = lower_32_bits(mem->start) | AHB2PCIE_SIZE(fls(size));
-- 
2.6.4



[PATCH v6 0/9] PCI: mediatek: fixup find_port, enable_msi and add pm, module support

2018-10-07 Thread honghui.zhang
From: Honghui Zhang 

This patchset includes misc patchs:

The patch 1 fixup the mtk_pcie_find_port logic which will cause system
could not touch the EP's configuration space that connected to PCIe slot 1.

The patch 2 fixup the class type for MT7622.
The patch 6 fixup the enable msi logic, the operation to enable msi
should be after system clock is enabled. Call mtk_pcie_enable_msi in
mtk_pcie_startup_port_v2 since the clock was all enabled at that time.

The patch 7 was rebased and refactor of the v4 patch[1], changes are:
 -Add PM support for MT7622.
 -Using mtk_pcie_enable_port to re-establish the link when resumed.
 -Rebased on this patchset.

The patch 9 add loadable kernel module support.

[1] https://patchwork.kernel.org/patch/10479079

Change since v5:
 - A bit improvement of mtk_pcie_find_port suggest by Lorenzo.
 - Add fixup tags of fix enable MSI logic in patch 6.
 - Add Acked-by tags from Ryder.

Change since v4:
 - Add patch 2 to fixup class type for MT7622.
 - Add patch 3 to remove the redundant dev->pm_domain check
 - Add patch 4 to covert to use pci_host_probe
 - Add patch 5 to re-arrange the function define, this is a prepare patch for
   fixup the enable_msi logic, no functional changed have been made by this one.
 - Add patch 8 to save the GIC IRQ in mtk_pcie_port as a prepare patch for tear
   down the irq when remove the kernel module.
 - Re-arrange the find_port flow suggest by Lorenzo to make the code parse 
easier
   for the patch 1.
 - Remove the .pm_support in mtk_pcie_soc in patch 7 since if system pm was not
   supported, then those pm callbacks will never be executed for MT7622. So the
   .pm_support is not needed.

Change since v3:
 - Remove pm_runtime_XXX ops in suspend and resume callbacks in the third patch.
 - Rebase to 4.19-rc1.

Change since v2:
 - Fix the list_for_each_entry_safe parameter error.
 - Add Ryder's Acked-by flag.

Change since v1:
 - A bit of code refact of the first patch suggested by Andy Shevchenko, and
   commit message updated.
 - Using __maybe_unused.
 - Remove the redundant list_empty check of the fourth patch.


Honghui Zhang (9):
  PCI: mediatek: Using slot's devfn for compare to fix
mtk_pcie_find_port logic
  PCI: mediatek: Fixup class ID for MT7622 as PCI_CLASS_BRIDGE_PCI
  PCI: mediatek: Remove the redundant dev->pm_domain check
  PCI: mediatek: Convert to use pci_host_probe()
  PCI: mediatek: Move the mtk_pcie_startup_port_v2 function's define
after mtk_pcie_setup_irq
  PCI: mediatek: Fixup enable msi logic by enable msi after clock
enabled
  PCI: mediatek: Add system pm support for MT2712 and MT7622
  PCI: mediatek: Save the GIC IRQ in mtk_pcie_port
  PCI: mediatek: Add loadable kernel module support

 drivers/pci/controller/Kconfig |   2 +-
 drivers/pci/controller/pcie-mediatek.c | 320 +
 2 files changed, 205 insertions(+), 117 deletions(-)

-- 
2.6.4



[PATCH v6 3/9] PCI: mediatek: Remove the redundant dev->pm_domain check

2018-10-07 Thread honghui.zhang
From: Honghui Zhang 

It's no needed to check whether device have pm_domain attached before
calling the pm_runtime_XXX interface, remove it.

Signed-off-by: Honghui Zhang 
Acked-by: Ryder Lee 
---
 drivers/pci/controller/pcie-mediatek.c | 18 ++
 1 file changed, 6 insertions(+), 12 deletions(-)

diff --git a/drivers/pci/controller/pcie-mediatek.c 
b/drivers/pci/controller/pcie-mediatek.c
index bcdac9b..59fdb60 100644
--- a/drivers/pci/controller/pcie-mediatek.c
+++ b/drivers/pci/controller/pcie-mediatek.c
@@ -225,10 +225,8 @@ static void mtk_pcie_subsys_powerdown(struct mtk_pcie 
*pcie)
 
clk_disable_unprepare(pcie->free_ck);
 
-   if (dev->pm_domain) {
-   pm_runtime_put_sync(dev);
-   pm_runtime_disable(dev);
-   }
+   pm_runtime_put_sync(dev);
+   pm_runtime_disable(dev);
 }
 
 static void mtk_pcie_port_free(struct mtk_pcie_port *port)
@@ -998,10 +996,8 @@ static int mtk_pcie_subsys_powerup(struct mtk_pcie *pcie)
pcie->free_ck = NULL;
}
 
-   if (dev->pm_domain) {
-   pm_runtime_enable(dev);
-   pm_runtime_get_sync(dev);
-   }
+   pm_runtime_enable(dev);
+   pm_runtime_get_sync(dev);
 
/* enable top level clock */
err = clk_prepare_enable(pcie->free_ck);
@@ -1013,10 +1009,8 @@ static int mtk_pcie_subsys_powerup(struct mtk_pcie *pcie)
return 0;
 
 err_free_ck:
-   if (dev->pm_domain) {
-   pm_runtime_put_sync(dev);
-   pm_runtime_disable(dev);
-   }
+   pm_runtime_put_sync(dev);
+   pm_runtime_disable(dev);
 
return err;
 }
-- 
2.6.4



[PATCH v6 4/9] PCI: mediatek: Convert to use pci_host_probe()

2018-10-07 Thread honghui.zhang
From: Honghui Zhang 

Part of mtk_pcie_register_host is an open-coded version of
pci_host_probe(). So instead of duplicating this code, use
pci_host_probe() directly and remove mtk_pcie_register_host.

Signed-off-by: Honghui Zhang 
Acked-by: Ryder Lee 
---
 drivers/pci/controller/pcie-mediatek.c | 37 --
 1 file changed, 8 insertions(+), 29 deletions(-)

diff --git a/drivers/pci/controller/pcie-mediatek.c 
b/drivers/pci/controller/pcie-mediatek.c
index 59fdb60..ead6005 100644
--- a/drivers/pci/controller/pcie-mediatek.c
+++ b/drivers/pci/controller/pcie-mediatek.c
@@ -1121,34 +1121,6 @@ static int mtk_pcie_request_resources(struct mtk_pcie 
*pcie)
return 0;
 }
 
-static int mtk_pcie_register_host(struct pci_host_bridge *host)
-{
-   struct mtk_pcie *pcie = pci_host_bridge_priv(host);
-   struct pci_bus *child;
-   int err;
-
-   host->busnr = pcie->busn.start;
-   host->dev.parent = pcie->dev;
-   host->ops = pcie->soc->ops;
-   host->map_irq = of_irq_parse_and_map_pci;
-   host->swizzle_irq = pci_common_swizzle;
-   host->sysdata = pcie;
-
-   err = pci_scan_root_bus_bridge(host);
-   if (err < 0)
-   return err;
-
-   pci_bus_size_bridges(host->bus);
-   pci_bus_assign_resources(host->bus);
-
-   list_for_each_entry(child, &host->bus->children, node)
-   pcie_bus_configure_settings(child);
-
-   pci_bus_add_devices(host->bus);
-
-   return 0;
-}
-
 static int mtk_pcie_probe(struct platform_device *pdev)
 {
struct device *dev = &pdev->dev;
@@ -1175,7 +1147,14 @@ static int mtk_pcie_probe(struct platform_device *pdev)
if (err)
goto put_resources;
 
-   err = mtk_pcie_register_host(host);
+   host->busnr = pcie->busn.start;
+   host->dev.parent = pcie->dev;
+   host->ops = pcie->soc->ops;
+   host->map_irq = of_irq_parse_and_map_pci;
+   host->swizzle_irq = pci_common_swizzle;
+   host->sysdata = pcie;
+
+   err = pci_host_probe(host);
if (err)
goto put_resources;
 
-- 
2.6.4



[PATCH v6 9/9] PCI: mediatek: Add loadable kernel module support

2018-10-07 Thread honghui.zhang
From: Honghui Zhang 

Implement remove callback function for Mediatek PCIe driver to add
loadable kernel module support.

Signed-off-by: Honghui Zhang 
Reviewed-by: Ryder Lee 
---
 drivers/pci/controller/Kconfig |  2 +-
 drivers/pci/controller/pcie-mediatek.c | 52 +-
 2 files changed, 52 insertions(+), 2 deletions(-)

diff --git a/drivers/pci/controller/Kconfig b/drivers/pci/controller/Kconfig
index 028b287..465790f 100644
--- a/drivers/pci/controller/Kconfig
+++ b/drivers/pci/controller/Kconfig
@@ -231,7 +231,7 @@ config PCIE_ROCKCHIP_EP
  available to support GEN2 with 4 slots.
 
 config PCIE_MEDIATEK
-   bool "MediaTek PCIe controller"
+   tristate "MediaTek PCIe controller"
depends on ARCH_MEDIATEK || COMPILE_TEST
depends on OF
depends on PCI_MSI_IRQ_DOMAIN
diff --git a/drivers/pci/controller/pcie-mediatek.c 
b/drivers/pci/controller/pcie-mediatek.c
index daba78f..3327c75 100644
--- a/drivers/pci/controller/pcie-mediatek.c
+++ b/drivers/pci/controller/pcie-mediatek.c
@@ -15,6 +15,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -532,6 +533,27 @@ static void mtk_pcie_enable_msi(struct mtk_pcie_port *port)
writel(val, port->base + PCIE_INT_MASK);
 }
 
+static void mtk_pcie_irq_teardown(struct mtk_pcie *pcie)
+{
+   struct mtk_pcie_port *port, *tmp;
+
+   list_for_each_entry_safe(port, tmp, &pcie->ports, list) {
+   irq_set_chained_handler_and_data(port->irq, NULL, NULL);
+
+   if (port->irq_domain)
+   irq_domain_remove(port->irq_domain);
+
+   if (IS_ENABLED(CONFIG_PCI_MSI)) {
+   if (port->msi_domain)
+   irq_domain_remove(port->msi_domain);
+   if (port->inner_domain)
+   irq_domain_remove(port->inner_domain);
+   }
+
+   irq_dispose_mapping(port->irq);
+   }
+}
+
 static int mtk_pcie_intx_map(struct irq_domain *domain, unsigned int irq,
 irq_hw_number_t hwirq)
 {
@@ -1171,6 +1193,32 @@ static int mtk_pcie_probe(struct platform_device *pdev)
return err;
 }
 
+
+static void mtk_pcie_free_resources(struct mtk_pcie *pcie)
+{
+   struct pci_host_bridge *host = pci_host_bridge_from_priv(pcie);
+   struct list_head *windows = &host->windows;
+
+   pci_unmap_iospace(&pcie->pio);
+   pci_free_resource_list(windows);
+}
+
+static int mtk_pcie_remove(struct platform_device *pdev)
+{
+   struct mtk_pcie *pcie = platform_get_drvdata(pdev);
+   struct pci_host_bridge *host = pci_host_bridge_from_priv(pcie);
+
+   pci_stop_root_bus(host->bus);
+   pci_remove_root_bus(host->bus);
+   mtk_pcie_free_resources(pcie);
+
+   mtk_pcie_irq_teardown(pcie);
+
+   mtk_pcie_put_resources(pcie);
+
+   return 0;
+}
+
 static int __maybe_unused mtk_pcie_suspend_noirq(struct device *dev)
 {
struct mtk_pcie *pcie = dev_get_drvdata(dev);
@@ -1248,6 +1296,7 @@ static const struct of_device_id mtk_pcie_ids[] = {
 
 static struct platform_driver mtk_pcie_driver = {
.probe = mtk_pcie_probe,
+   .remove = mtk_pcie_remove,
.driver = {
.name = "mtk-pcie",
.of_match_table = mtk_pcie_ids,
@@ -1255,4 +1304,5 @@ static struct platform_driver mtk_pcie_driver = {
.pm = &mtk_pcie_pm_ops,
},
 };
-builtin_platform_driver(mtk_pcie_driver);
+module_platform_driver(mtk_pcie_driver);
+MODULE_LICENSE("GPL v2");
-- 
2.6.4



[PATCH v6 7/9] PCI: mediatek: Add system pm support for MT2712 and MT7622

2018-10-07 Thread honghui.zhang
From: Honghui Zhang 

In order to reduce the PCIe power consuming while system suspend,
the physical layer should be gated. And the PCIe link should be
re-established and the related control register values should be
re-initialized after system resume.

Register suspend_noirq & resume_noirq callback functions to allow
PCIe to come up after resume from RAM.

Signed-off-by: Honghui Zhang 
Acked-by: Ryder Lee 
---
 drivers/pci/controller/pcie-mediatek.c | 50 ++
 1 file changed, 50 insertions(+)

diff --git a/drivers/pci/controller/pcie-mediatek.c 
b/drivers/pci/controller/pcie-mediatek.c
index d3f4694..42cf2a4 100644
--- a/drivers/pci/controller/pcie-mediatek.c
+++ b/drivers/pci/controller/pcie-mediatek.c
@@ -1168,6 +1168,55 @@ static int mtk_pcie_probe(struct platform_device *pdev)
return err;
 }
 
+static int __maybe_unused mtk_pcie_suspend_noirq(struct device *dev)
+{
+   struct mtk_pcie *pcie = dev_get_drvdata(dev);
+   struct mtk_pcie_port *port;
+
+   if (list_empty(&pcie->ports))
+   return 0;
+
+   list_for_each_entry(port, &pcie->ports, list) {
+   clk_disable_unprepare(port->pipe_ck);
+   clk_disable_unprepare(port->obff_ck);
+   clk_disable_unprepare(port->axi_ck);
+   clk_disable_unprepare(port->aux_ck);
+   clk_disable_unprepare(port->ahb_ck);
+   clk_disable_unprepare(port->sys_ck);
+   phy_power_off(port->phy);
+   phy_exit(port->phy);
+   }
+
+   clk_disable_unprepare(pcie->free_ck);
+
+   return 0;
+}
+
+static int __maybe_unused mtk_pcie_resume_noirq(struct device *dev)
+{
+   struct mtk_pcie *pcie = dev_get_drvdata(dev);
+   struct mtk_pcie_port *port, *tmp;
+
+   if (list_empty(&pcie->ports))
+   return 0;
+
+   clk_prepare_enable(pcie->free_ck);
+
+   list_for_each_entry_safe(port, tmp, &pcie->ports, list)
+   mtk_pcie_enable_port(port);
+
+   /* In case of EP was removed while system suspend. */
+   if (list_empty(&pcie->ports))
+   clk_disable_unprepare(pcie->free_ck);
+
+   return 0;
+}
+
+static const struct dev_pm_ops mtk_pcie_pm_ops = {
+   SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(mtk_pcie_suspend_noirq,
+ mtk_pcie_resume_noirq)
+};
+
 static const struct mtk_pcie_soc mtk_pcie_soc_v1 = {
.ops = &mtk_pcie_ops,
.startup = mtk_pcie_startup_port,
@@ -1200,6 +1249,7 @@ static struct platform_driver mtk_pcie_driver = {
.name = "mtk-pcie",
.of_match_table = mtk_pcie_ids,
.suppress_bind_attrs = true,
+   .pm = &mtk_pcie_pm_ops,
},
 };
 builtin_platform_driver(mtk_pcie_driver);
-- 
2.6.4



[PATCH v6 2/9] PCI: mediatek: Fixup class ID for MT7622 as PCI_CLASS_BRIDGE_PCI

2018-10-07 Thread honghui.zhang
From: Honghui Zhang 

The PCIe controller of MT7622 has TYPE 1 configuration space type, but
the HW default class type values is invalid.

The commit 101c92dc80c8 ("PCI: mediatek: Set up vendor ID and class
type for MT7622") have set the class ID for MT7622 as
PCI_CLASS_BRIDGE_HOST, but it's not workable for MT7622:

In __pci_bus_assign_resources, the framework only setup bridge's
resource window only if class type is PCI_CLASS_BRIDGE_PCI. Or it
will leave the subordinary PCIe device's MMIO window un-touched.

Fixup the class type to PCI_CLASS_BRIDGE_PCI as most of the controller
driver do.

Signed-off-by: Honghui Zhang 
Acked-by: Ryder Lee 
---
 drivers/pci/controller/pcie-mediatek.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/pci/controller/pcie-mediatek.c 
b/drivers/pci/controller/pcie-mediatek.c
index 288b8e2..bcdac9b 100644
--- a/drivers/pci/controller/pcie-mediatek.c
+++ b/drivers/pci/controller/pcie-mediatek.c
@@ -432,7 +432,7 @@ static int mtk_pcie_startup_port_v2(struct mtk_pcie_port 
*port)
val = PCI_VENDOR_ID_MEDIATEK;
writew(val, port->base + PCIE_CONF_VEND_ID);
 
-   val = PCI_CLASS_BRIDGE_HOST;
+   val = PCI_CLASS_BRIDGE_PCI;
writew(val, port->base + PCIE_CONF_CLASS_ID);
}
 
-- 
2.6.4



[PATCH] PCI: mediatek: Add system pm support for MT2712

2018-05-29 Thread honghui.zhang
From: Honghui Zhang 

The MTCMOS of PCIe Host for MT2712 will be off when system suspend, and all
the internel control register will be reset after system resume. The PCIe
link should be re-established and the related control register values should
be re-set after system resume.

Signed-off-by: Honghui Zhang 
CC: Ryder Lee 
---
 drivers/pci/host/pcie-mediatek.c | 82 
 1 file changed, 82 insertions(+)

diff --git a/drivers/pci/host/pcie-mediatek.c b/drivers/pci/host/pcie-mediatek.c
index dabf1086..60f98d92 100644
--- a/drivers/pci/host/pcie-mediatek.c
+++ b/drivers/pci/host/pcie-mediatek.c
@@ -132,12 +132,14 @@ struct mtk_pcie_port;
 /**
  * struct mtk_pcie_soc - differentiate between host generations
  * @need_fix_class_id: whether this host's class ID needed to be fixed or not
+ * @pm_support: whether the host's MTCMOS will be off when suspend
  * @ops: pointer to configuration access functions
  * @startup: pointer to controller setting functions
  * @setup_irq: pointer to initialize IRQ functions
  */
 struct mtk_pcie_soc {
bool need_fix_class_id;
+   bool pm_support;
struct pci_ops *ops;
int (*startup)(struct mtk_pcie_port *port);
int (*setup_irq)(struct mtk_pcie_port *port, struct device_node *node);
@@ -1179,12 +1181,91 @@ static int mtk_pcie_probe(struct platform_device *pdev)
return err;
 }
 
+static int __maybe_unused mtk_pcie_suspend_noirq(struct device *dev)
+{
+   struct platform_device *pdev;
+   struct mtk_pcie *pcie;
+   struct mtk_pcie_port *port;
+   const struct mtk_pcie_soc *soc;
+
+   pdev = to_platform_device(dev);
+   pcie = platform_get_drvdata(pdev);
+   soc = pcie->soc;
+   if (!soc->pm_support)
+   return 0;
+
+   list_for_each_entry(port, &pcie->ports, list) {
+   clk_disable_unprepare(port->ahb_ck);
+   clk_disable_unprepare(port->sys_ck);
+   phy_power_off(port->phy);
+   }
+
+   return 0;
+}
+
+static int __maybe_unused mtk_pcie_resume_noirq(struct device *dev)
+{
+   struct platform_device *pdev;
+   struct mtk_pcie *pcie;
+   struct mtk_pcie_port *port;
+   const struct mtk_pcie_soc *soc;
+   int ret;
+
+   pdev = to_platform_device(dev);
+   pcie = platform_get_drvdata(pdev);
+   soc = pcie->soc;
+   if (!soc->pm_support)
+   return 0;
+
+   list_for_each_entry(port, &pcie->ports, list) {
+   ret = phy_power_on(port->phy);
+   if (ret) {
+   dev_err(dev, "could not power on phy\n");
+   return ret;
+   }
+   ret = clk_prepare_enable(port->sys_ck);
+   if (ret) {
+   dev_err(dev, "enable sys clock error\n");
+   phy_power_off(port->phy);
+   return ret;
+   }
+
+   ret = clk_prepare_enable(port->ahb_ck);
+   if (ret) {
+   dev_err(dev, "enable ahb clock error\n");
+   phy_power_off(port->phy);
+   clk_disable_unprepare(port->sys_ck);
+   return ret;
+   }
+
+   ret = soc->startup(port);
+   if (ret) {
+   dev_err(dev, "pcie linkup failed\n");
+   phy_power_off(port->phy);
+   clk_disable_unprepare(port->sys_ck);
+   clk_disable_unprepare(port->ahb_ck);
+   return ret;
+   }
+
+   if (IS_ENABLED(CONFIG_PCI_MSI))
+   mtk_pcie_enable_msi(port);
+   }
+
+   return 0;
+}
+
+const struct dev_pm_ops mtk_pcie_pm_ops = {
+   SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(mtk_pcie_suspend_noirq,
+ mtk_pcie_resume_noirq)
+};
+
 static const struct mtk_pcie_soc mtk_pcie_soc_v1 = {
.ops = &mtk_pcie_ops,
.startup = mtk_pcie_startup_port,
 };
 
 static const struct mtk_pcie_soc mtk_pcie_soc_mt2712 = {
+   .pm_support = true,
.ops = &mtk_pcie_ops_v2,
.startup = mtk_pcie_startup_port_v2,
.setup_irq = mtk_pcie_setup_irq,
@@ -1211,6 +1292,7 @@ static struct platform_driver mtk_pcie_driver = {
.name = "mtk-pcie",
.of_match_table = mtk_pcie_ids,
.suppress_bind_attrs = true,
+   .pm = &mtk_pcie_pm_ops,
},
 };
 builtin_platform_driver(mtk_pcie_driver);
-- 
2.6.4



[PATCH 5/5] ARM: dts: mt2701: add iommu/smi dtsi node for mt2701

2016-05-09 Thread honghui.zhang
From: Honghui Zhang 

Add the dtsi node of iommu and smi for mt2701.

Signed-off-by: Honghui Zhang 
---
 arch/arm/boot/dts/mt2701.dtsi | 51 +++
 1 file changed, 51 insertions(+)

diff --git a/arch/arm/boot/dts/mt2701.dtsi b/arch/arm/boot/dts/mt2701.dtsi
index 42d5a37..363de0d 100644
--- a/arch/arm/boot/dts/mt2701.dtsi
+++ b/arch/arm/boot/dts/mt2701.dtsi
@@ -16,6 +16,7 @@
 #include 
 #include 
 #include 
+#include 
 #include "skeleton64.dtsi"
 #include "mt2701-pinfunc.h"
 
@@ -160,6 +161,16 @@
clock-names = "system-clk", "rtc-clk";
};
 
+   smi_common: smi@1000c000 {
+   compatible = "mediatek,mt2701-smi-common";
+   reg = <0 0x1000c000 0 0x1000>;
+   clocks = <&infracfg CLK_INFRA_SMI>,
+<&mmsys CLK_MM_SMI_COMMON>,
+<&infracfg CLK_INFRA_SMI>;
+   clock-names = "apb", "smi", "async";
+   power-domains = <&scpsys MT2701_POWER_DOMAIN_DISP>;
+   };
+
sysirq: interrupt-controller@10200100 {
compatible = "mediatek,mt2701-sysirq",
 "mediatek,mt6577-sysirq";
@@ -169,6 +180,16 @@
reg = <0 0x10200100 0 0x1c>;
};
 
+   iommu: mmsys_iommu@10205000 {
+   compatible = "mediatek,mt2701-m4u";
+   reg = <0 0x10205000 0 0x1000>;
+   interrupts = ;
+   clocks = <&infracfg CLK_INFRA_M4U>;
+   clock-names = "bclk";
+   mediatek,larbs = <&larb0 &larb1 &larb2>;
+   #iommu-cells = <1>;
+   };
+
apmixedsys: syscon@10209000 {
compatible = "mediatek,mt2701-apmixedsys", "syscon";
reg = <0 0x10209000 0 0x1000>;
@@ -234,6 +255,16 @@
status = "disabled";
};
 
+   larb0: larb@1401 {
+   compatible = "mediatek,mt2701-smi-larb";
+   reg = <0 0x1401 0 0x1000>;
+   mediatek,smi = <&smi_common>;
+   clocks = <&mmsys CLK_MM_SMI_LARB0>,
+<&mmsys CLK_MM_SMI_LARB0>;
+   clock-names = "apb", "smi";
+   power-domains = <&scpsys MT2701_POWER_DOMAIN_DISP>;
+   };
+
imgsys: syscon@1500 {
compatible = "mediatek,mt2701-imgsys", "syscon";
reg = <0 0x1500 0 0x1000>;
@@ -241,6 +272,16 @@
status = "disabled";
};
 
+   larb2: larb@15001000 {
+   compatible = "mediatek,mt2701-smi-larb";
+   reg = <0 0x15001000 0 0x1000>;
+   mediatek,smi = <&smi_common>;
+   clocks = <&imgsys CLK_IMG_SMI_COMM>,
+<&imgsys CLK_IMG_SMI_COMM>;
+   clock-names = "apb", "smi";
+   power-domains = <&scpsys MT2701_POWER_DOMAIN_ISP>;
+   };
+
vdecsys: syscon@1600 {
compatible = "mediatek,mt2701-vdecsys", "syscon";
reg = <0 0x1600 0 0x1000>;
@@ -248,6 +289,16 @@
status = "disabled";
};
 
+   larb1: larb@1601 {
+   compatible = "mediatek,mt2701-smi-larb";
+   reg = <0 0x1601 0 0x1000>;
+   mediatek,smi = <&smi_common>;
+   clocks = <&vdecsys CLK_VDEC_CKGEN>,
+<&vdecsys CLK_VDEC_LARB>;
+   clock-names = "apb", "smi";
+   power-domains = <&scpsys MT2701_POWER_DOMAIN_VDEC>;
+   };
+
hifsys: syscon@1a00 {
compatible = "mediatek,mt2701-hifsys", "syscon";
reg = <0 0x1a00 0 0x1000>;
-- 
1.8.1.1.dirty



[PATCH 0/5] MT2701 iommu support

2016-05-09 Thread honghui.zhang
From: Honghui Zhang 

  Mediatek's m4u(Multimedia Memory Management Unit) and SMI(Smart
Multimedia Interface)have two generations HW. They basically sharing the
same hardware block diagram, but have some difference as below:

  Generation one m4u only support one layer, flat pagetable addressing, and
only support 4K size page mapping. While generation two m4u support 2
levels of pagetable which use the ARM short-descriptor translation table
format for address translation.
They have slight different register base and register offset.
They have very different HW ports defines.

  Generaion one SMI have additional "async" clock which transform the smi
clock into emi clock domain, this clock should be prepare and enabled for
cMI generation one HW.
The register which control the iommu need to translation the address or not
for a particular port is located at smi ao base(smi always on register
base) for generation one SMI HW, but located at each larb's register base
for generation two HW.

This patch set add mt2701 iommu support, it's based on 4.6-rc1 and James
Liao's "Add clock support for Mediatek MT2701 v7[1]" and "Mediatek MT2701
SCPSYS power domain support v6[2]" patch.

[1] 
http://lists.infradead.org/pipermail/linux-mediatek/2016-February/004030.html
[2] http://www.spinics.net/lists/arm-kernel/msg497028.html

Honghui Zhang (5):
  dt-bindings: mediatek: add descriptions for mediatek mt2701 iommu and
smi
  iommu/mediatek: move the common struct into header file
  memory/mediatek: add support for mt2701
  iommu/mediatek: add support for mtk iommu generation one HW
  ARM: dts: mt2701: add iommu/smi dtsi node for mt2701

 .../devicetree/bindings/iommu/mediatek,iommu.txt   |  13 +-
 .../memory-controllers/mediatek,smi-common.txt |  21 +-
 .../memory-controllers/mediatek,smi-larb.txt   |   4 +-
 arch/arm/boot/dts/mt2701.dtsi  |  51 ++
 drivers/iommu/Kconfig  |  19 +
 drivers/iommu/Makefile |   1 +
 drivers/iommu/mtk_iommu.c  |  62 +-
 drivers/iommu/mtk_iommu.h  |  94 +++
 drivers/iommu/mtk_iommu_v1.c   | 767 +
 drivers/memory/mtk-smi.c   | 168 -
 include/dt-bindings/memory/mt2701-larb-port.h  |  85 +++
 11 files changed, 1197 insertions(+), 88 deletions(-)
 create mode 100644 drivers/iommu/mtk_iommu.h
 create mode 100644 drivers/iommu/mtk_iommu_v1.c
 create mode 100644 include/dt-bindings/memory/mt2701-larb-port.h

-- 
1.8.1.1.dirty



[PATCH 4/5] iommu/mediatek: add support for mtk iommu generation one HW

2016-05-09 Thread honghui.zhang
From: Honghui Zhang 

Mediatek SoC's M4U have two generations of HW architcture. Generation one
use flat, one layer pagetable, and was shipped with ARM architecture, it
only support 4K size page mapping. MT2701 SoC use this generation one
m4u HW. Generation two uses the ARM short-descriptor translation table
format for address translation, and was shipped with ARM64 architecture,
MT8173 use this generation two m4u HW. All the two generation iommu HW
only have one iommu domain, and all it's iommu clients share the same
iova address.

These two generation m4u HW have slit different register groups and
register offset, but most register names are the same. This patch add iommu
support for mediatek SoC mt2701.

Signed-off-by: Honghui Zhang 
---
 drivers/iommu/Kconfig|  19 ++
 drivers/iommu/Makefile   |   1 +
 drivers/iommu/mtk_iommu.h|   4 +
 drivers/iommu/mtk_iommu_v1.c | 767 +++
 4 files changed, 791 insertions(+)
 create mode 100644 drivers/iommu/mtk_iommu_v1.c

diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
index dd1dc39..2e17d70 100644
--- a/drivers/iommu/Kconfig
+++ b/drivers/iommu/Kconfig
@@ -354,4 +354,23 @@ config MTK_IOMMU
 
  If unsure, say N here.
 
+config MTK_IOMMU_V1
+   bool "MTK IOMMU Version 1 (M4U gen1) Support"
+   depends on ARM || ARM64
+   depends on ARCH_MEDIATEK || COMPILE_TEST
+   select ARM_DMA_USE_IOMMU
+   select IOMMU_API
+   select IOMMU_DMA
+   select MEMORY
+   select MTK_SMI
+   select COMMON_CLK_MT2701_MMSYS
+   select COMMON_CLK_MT2701_IMGSYS
+   select COMMON_CLK_MT2701_VDECSYS
+   help
+ Support for the M4U on certain Mediatek SoCs. M4U generation 1 HW is
+ Multimedia Memory Managememt Unit. This option enables remapping of
+ DMA memory accesses for the multimedia subsystem.
+
+ if unsure, say N here.
+
 endif # IOMMU_SUPPORT
diff --git a/drivers/iommu/Makefile b/drivers/iommu/Makefile
index c6edb31..778baf5 100644
--- a/drivers/iommu/Makefile
+++ b/drivers/iommu/Makefile
@@ -18,6 +18,7 @@ obj-$(CONFIG_INTEL_IOMMU_SVM) += intel-svm.o
 obj-$(CONFIG_IPMMU_VMSA) += ipmmu-vmsa.o
 obj-$(CONFIG_IRQ_REMAP) += intel_irq_remapping.o irq_remapping.o
 obj-$(CONFIG_MTK_IOMMU) += mtk_iommu.o
+obj-$(CONFIG_MTK_IOMMU_V1) += mtk_iommu_v1.o
 obj-$(CONFIG_OMAP_IOMMU) += omap-iommu.o
 obj-$(CONFIG_OMAP_IOMMU_DEBUG) += omap-iommu-debug.o
 obj-$(CONFIG_ROCKCHIP_IOMMU) += rockchip-iommu.o
diff --git a/drivers/iommu/mtk_iommu.h b/drivers/iommu/mtk_iommu.h
index 5656355..c894784 100644
--- a/drivers/iommu/mtk_iommu.h
+++ b/drivers/iommu/mtk_iommu.h
@@ -48,6 +48,10 @@ struct mtk_iommu_domain {
struct io_pgtable_ops   *iop;
 
struct iommu_domain domain;
+   size_t  pgt_size;
+   void*pgt_va;
+   dma_addr_t  pgt_pa;
+   void*cookie;
 };
 
 struct mtk_iommu_data {
diff --git a/drivers/iommu/mtk_iommu_v1.c b/drivers/iommu/mtk_iommu_v1.c
new file mode 100644
index 000..1fece92
--- /dev/null
+++ b/drivers/iommu/mtk_iommu_v1.c
@@ -0,0 +1,767 @@
+/*
+ * Copyright (c) 2015-2016 MediaTek Inc.
+ * Author: Yong Wu 
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include "mtk_iommu.h"
+
+#define REG_MMU_PT_BASE_ADDR   0x000
+
+#define F_ALL_INVLD0x2
+#define F_MMU_INV_RANGE0x1
+#define F_INVLD_EN0BIT(0)
+#define F_INVLD_EN1BIT(1)
+
+#define F_MMU_FAULT_VA_MSK 0xf000
+#define MTK_PROTECT_PA_ALIGN   128
+
+#define REG_MMU_CTRL_REG   0x210
+#define F_MMU_CTRL_COHERENT_EN BIT(8)
+#define REG_MMU_IVRP_PADDR 0x214
+#define REG_MMU_INT_CONTROL0x220
+#define F_INT_TRANSLATION_FAULTBIT(0)
+#define F_INT_MAIN_MULTI_HIT_FAULT BIT(1)
+#define F_INT_INVALID_PA_FAULT BIT(2)
+#define F_INT_ENTRY_REPLACEMENT_FAULT  BIT(3)
+#define F_INT_TABLE_WALK_FAULT BIT(4)
+#define F_INT_TLB_MISS_FAULT   BIT(5)
+#define F_INT_PFH_

[PATCH 1/5] dt-bindings: mediatek: add descriptions for mediatek mt2701 iommu and smi

2016-05-09 Thread honghui.zhang
From: Honghui Zhang 

This patch defines the local arbitor port IDs for mediatek SoC MT2701 and
add descriptions of binding for mediatek generation one iommu and smi.

Signed-off-by: Honghui Zhang 
---
 .../devicetree/bindings/iommu/mediatek,iommu.txt   | 13 +++-
 .../memory-controllers/mediatek,smi-common.txt | 21 +-
 .../memory-controllers/mediatek,smi-larb.txt   |  4 +-
 include/dt-bindings/memory/mt2701-larb-port.h  | 85 ++
 4 files changed, 115 insertions(+), 8 deletions(-)
 create mode 100644 include/dt-bindings/memory/mt2701-larb-port.h

diff --git a/Documentation/devicetree/bindings/iommu/mediatek,iommu.txt 
b/Documentation/devicetree/bindings/iommu/mediatek,iommu.txt
index cd1b1cd..9a4a5b5 100644
--- a/Documentation/devicetree/bindings/iommu/mediatek,iommu.txt
+++ b/Documentation/devicetree/bindings/iommu/mediatek,iommu.txt
@@ -1,7 +1,9 @@
 * Mediatek IOMMU Architecture Implementation
 
-  Some Mediatek SOCs contain a Multimedia Memory Management Unit (M4U) which
-uses the ARM Short-Descriptor translation table format for address translation.
+  Some Mediatek SOCs contain a Multimedia Memory Management Unit (M4U), and
+this M4U have two generations of HW architecture. Generation one use flat
+pagetable, and only support 4K size page mapping. Generation two uses the
+ARM Short-Descriptor translation table format for address translation.
 
   About the M4U Hardware Block Diagram, please check below:
 
@@ -36,7 +38,9 @@ in each larb. Take a example, There are many ports like MC, 
PP, VLD in the
 video decode local arbiter, all these ports are according to the video HW.
 
 Required properties:
-- compatible : must be "mediatek,mt8173-m4u".
+- compatible : must be one of the following string:
+   "mediatek,mt2701-m4u" for mt2701 which use generation one m4u HW.
+   "mediatek,mt8173-m4u" for mt8173 which use generation two m4u HW.
 - reg : m4u register base and size.
 - interrupts : the interrupt of m4u.
 - clocks : must contain one entry for each clock-names.
@@ -46,7 +50,8 @@ Required properties:
according to the local arbiter index, like larb0, larb1, larb2...
 - iommu-cells : must be 1. This is the mtk_m4u_id according to the HW.
Specifies the mtk_m4u_id as defined in
-   dt-binding/memory/mt8173-larb-port.h.
+   dt-binding/memory/mt2701-larb-port.h for mt2701 and
+   dt-binding/memory/mt8173-larb-port.h for mt8173
 
 Example:
iommu: iommu@10205000 {
diff --git 
a/Documentation/devicetree/bindings/memory-controllers/mediatek,smi-common.txt 
b/Documentation/devicetree/bindings/memory-controllers/mediatek,smi-common.txt
index 06a83ce..80c0e22 100644
--- 
a/Documentation/devicetree/bindings/memory-controllers/mediatek,smi-common.txt
+++ 
b/Documentation/devicetree/bindings/memory-controllers/mediatek,smi-common.txt
@@ -2,16 +2,31 @@ SMI (Smart Multimedia Interface) Common
 
 The hardware block diagram please check bindings/iommu/mediatek,iommu.txt
 
+Mediatek SMI have two generation HW architecture, mt8173 use the secondary
+generation of SMI HW while mt2701 use the first generation HW of SMI.
+
+There's slight differences between the two SMI, for generation 2, the
+register which control the iommu port is at each larb's register base. But
+for generation 1, the register is at smi ao base(smi always on register
+base). Besides that, the smi async clock should be prepare and enabled for
+SMI generation 1 to transform the smi clock into emi clock domain, but no
+needed for SMI generation 2.
+
 Required properties:
-- compatible : must be "mediatek,mt8173-smi-common"
+- compatible : must be one of :
+   "mediatek,mt2701-smi-common"
+   "mediatek,mt8173-smi-common"
 - reg : the register and size of the SMI block.
 - power-domains : a phandle to the power domain of this local arbiter.
 - clocks : Must contain an entry for each entry in clock-names.
-- clock-names : must contain 2 entries, as follows:
+- clock-names : must contain 3 entries for generation 1 smi HW and 2 entries
+  for generation 2 smi HW as follows:
   - "apb" : Advanced Peripheral Bus clock, It's the clock for setting
the register.
   - "smi" : It's the clock for transfer data and command.
-  They may be the same if both source clocks are the same.
+   They may be the same if both source clocks are the same.
+  - "async" : asynchronous clock, it help transform the smi clock into the emi
+ clock domain, this clock is only needed by generation 1 smi HW.
 
 Example:
smi_common: smi@14022000 {
diff --git 
a/Documentation/devicetree/bindings/memory-controllers/mediatek,smi-larb.txt 
b/Documentation/devicetree/bindings/memory-controllers/mediatek,smi-larb.txt
index 55ff3b7..21277a5 100644
--- a/Documentation/devicetree/bindings/memory-controllers/mediatek,smi-larb.txt
+++ b/Documentation/devicetree/bindings/memory-controllers/mediatek,smi-larb.txt
@@ -3,7 +3,9 @@ SMI (Smart Multimedia Interface) Local Arbiter
 The hardwa

[PATCH 3/5] memory/mediatek: add support for mt2701

2016-05-09 Thread honghui.zhang
From: Honghui Zhang 

Mediatek SMI have two generation HW architecture, mt8173 use the
secondary generation of SMI HW while mt2701 use the first generation
HW of SMI.

There's slight differences between the two generation, for generation 2,
the register which control the iommu port access PA or IOVA is at each
larb's register base. But for generation 1, the register is at smi ao
base(smi always on register base).
Besides that, the smi async clock should be prepare and enabled for SMI
generation 1 HW to transform the smi clock into emi clock domain, but no
needed for SMI generation 2.

This patch add SMI driver for mt2701 which use generation 1 SMI HW.

Signed-off-by: Honghui Zhang 
---
 drivers/memory/mtk-smi.c | 168 +--
 1 file changed, 149 insertions(+), 19 deletions(-)

diff --git a/drivers/memory/mtk-smi.c b/drivers/memory/mtk-smi.c
index 089091f..0a47382 100644
--- a/drivers/memory/mtk-smi.c
+++ b/drivers/memory/mtk-smi.c
@@ -21,19 +21,50 @@
 #include 
 #include 
 #include 
+#include 
 
 #define SMI_LARB_MMU_EN0xf00
+#define REG_SMI_SECUR_CON_BASE 0x5c0
+
+/* every register control 8 port, register offset 0x4 */
+#define REG_SMI_SECUR_CON_OFFSET(id)   (((id) >> 3) << 2)
+#define REG_SMI_SECUR_CON_ADDR(id) \
+   (REG_SMI_SECUR_CON_BASE + REG_SMI_SECUR_CON_OFFSET(id))
+
+/*
+ * every port have 4 bit to control, bit[port + 3] control virtual or physical,
+ * bit[port + 2 : port + 1] control the domain, bit[port] control the security
+ * or non-security.
+ */
+#define SMI_SECUR_CON_VAL_MSK(id)  (~(0xf << (((id) & 0x7) << 2)))
+#define SMI_SECUR_CON_VAL_VIRT(id) BITid) & 0x7) << 2) + 3)
+/* mt2701 domain should be set to 3 */
+#define SMI_SECUR_CON_VAL_DOMAIN(id)   (0x3 << id) & 0x7) << 2) + 1))
+
+struct mtk_smi_larb_gen {
+   int port_in_larb[MTK_LARB_NR_MAX + 1];
+   void (*config_port)(struct device *);
+};
 
 struct mtk_smi {
-   struct device   *dev;
-   struct clk  *clk_apb, *clk_smi;
+   struct device   *dev;
+   struct clk  *clk_apb, *clk_smi;
+   struct clk  *clk_async; /*only needed by mt2701*/
+   void __iomem*smi_ao_base;
 };
 
 struct mtk_smi_larb { /* larb: local arbiter */
-   struct mtk_smi  smi;
-   void __iomem*base;
-   struct device   *smi_common_dev;
-   u32 *mmu;
+   struct mtk_smi  smi;
+   void __iomem*base;
+   struct device   *smi_common_dev;
+   const struct mtk_smi_larb_gen   *larb_gen;
+   int larbid;
+   u32 *mmu;
+};
+
+enum mtk_smi_gen {
+   MTK_SMI_GEN1,
+   MTK_SMI_GEN2
 };
 
 static int mtk_smi_enable(const struct mtk_smi *smi)
@@ -71,6 +102,7 @@ static void mtk_smi_disable(const struct mtk_smi *smi)
 int mtk_smi_larb_get(struct device *larbdev)
 {
struct mtk_smi_larb *larb = dev_get_drvdata(larbdev);
+   const struct mtk_smi_larb_gen *larb_gen = larb->larb_gen;
struct mtk_smi *common = dev_get_drvdata(larb->smi_common_dev);
int ret;
 
@@ -87,8 +119,7 @@ int mtk_smi_larb_get(struct device *larbdev)
}
 
/* Configure the iommu info for this larb */
-   writel(*larb->mmu, larb->base + SMI_LARB_MMU_EN);
-
+   larb_gen->config_port(larbdev);
return 0;
 }
 
@@ -124,6 +155,45 @@ mtk_smi_larb_bind(struct device *dev, struct device 
*master, void *data)
return -ENODEV;
 }
 
+static void mtk_smi_larb_config_port(struct device *dev)
+{
+   struct mtk_smi_larb *larb = dev_get_drvdata(dev);
+
+   writel(*larb->mmu, larb->base + SMI_LARB_MMU_EN);
+}
+
+
+static void mtk_smi_larb_config_port_gen1(struct device *dev)
+{
+   struct mtk_smi_larb *larb = dev_get_drvdata(dev);
+   const struct mtk_smi_larb_gen *larb_gen = larb->larb_gen;
+   struct mtk_smi *common = dev_get_drvdata(larb->smi_common_dev);
+   int i, m4u_port_id, larb_port_num;
+   u32 sec_con_val, reg_val;
+
+   m4u_port_id = larb_gen->port_in_larb[larb->larbid];
+   larb_port_num = larb_gen->port_in_larb[larb->larbid + 1]
+   - larb_gen->port_in_larb[larb->larbid];
+
+   for (i = 0; i < larb_port_num; i++, m4u_port_id++) {
+   if (*larb->mmu & BIT(i)) {
+   /* bit[port + 3] controls the virtual or physical */
+   sec_con_val = SMI_SECUR_CON_VAL_VIRT(m4u_port_id);
+   } else {
+   /* do not need to enable m4u for this port */
+   continue;
+   }
+   reg_val = readl(common->smi_ao_base
+   + REG_SMI_SECUR_CON_ADDR(m4u_port_id));
+   reg_val &= SMI_SECUR_CON_VAL_MSK(m4u_port_id);
+   reg_val |= sec_con_val;
+   reg_val |= SMI_SECUR_CON_VAL_DOMAIN(m4u_p

[PATCH 2/5] iommu/mediatek: move the common struct into header file

2016-05-09 Thread honghui.zhang
From: Honghui Zhang 

Move the struct defines of mtk iommu into a new header files for
common use.

Signed-off-by: Honghui Zhang 
---
 drivers/iommu/mtk_iommu.c | 62 +---
 drivers/iommu/mtk_iommu.h | 90 +++
 2 files changed, 91 insertions(+), 61 deletions(-)
 create mode 100644 drivers/iommu/mtk_iommu.h

diff --git a/drivers/iommu/mtk_iommu.c b/drivers/iommu/mtk_iommu.c
index db74553..a6b7846 100644
--- a/drivers/iommu/mtk_iommu.c
+++ b/drivers/iommu/mtk_iommu.c
@@ -34,7 +34,7 @@
 #include 
 #include 
 
-#include "io-pgtable.h"
+#include "mtk_iommu.h"
 
 #define REG_MMU_PT_BASE_ADDR   0x000
 
@@ -93,49 +93,8 @@
 
 #define MTK_PROTECT_PA_ALIGN   128
 
-struct mtk_iommu_suspend_reg {
-   u32 standard_axi_mode;
-   u32 dcm_dis;
-   u32 ctrl_reg;
-   u32 int_control0;
-   u32 int_main_control;
-};
-
-struct mtk_iommu_client_priv {
-   struct list_headclient;
-   unsigned intmtk_m4u_id;
-   struct device   *m4udev;
-};
-
-struct mtk_iommu_domain {
-   spinlock_t  pgtlock; /* lock for page table */
-
-   struct io_pgtable_cfg   cfg;
-   struct io_pgtable_ops   *iop;
-
-   struct iommu_domain domain;
-};
-
-struct mtk_iommu_data {
-   void __iomem*base;
-   int irq;
-   struct device   *dev;
-   struct clk  *bclk;
-   phys_addr_t protect_base; /* protect memory base */
-   struct mtk_iommu_suspend_regreg;
-   struct mtk_iommu_domain *m4u_dom;
-   struct iommu_group  *m4u_group;
-   struct mtk_smi_iommusmi_imu;  /* SMI larb iommu info */
-   boolenable_4GB;
-};
-
 static struct iommu_ops mtk_iommu_ops;
 
-static struct mtk_iommu_domain *to_mtk_domain(struct iommu_domain *dom)
-{
-   return container_of(dom, struct mtk_iommu_domain, domain);
-}
-
 static void mtk_iommu_tlb_flush_all(void *cookie)
 {
struct mtk_iommu_data *data = cookie;
@@ -552,25 +511,6 @@ static int mtk_iommu_hw_init(const struct mtk_iommu_data 
*data)
return 0;
 }
 
-static int compare_of(struct device *dev, void *data)
-{
-   return dev->of_node == data;
-}
-
-static int mtk_iommu_bind(struct device *dev)
-{
-   struct mtk_iommu_data *data = dev_get_drvdata(dev);
-
-   return component_bind_all(dev, &data->smi_imu);
-}
-
-static void mtk_iommu_unbind(struct device *dev)
-{
-   struct mtk_iommu_data *data = dev_get_drvdata(dev);
-
-   component_unbind_all(dev, &data->smi_imu);
-}
-
 static const struct component_master_ops mtk_iommu_com_ops = {
.bind   = mtk_iommu_bind,
.unbind = mtk_iommu_unbind,
diff --git a/drivers/iommu/mtk_iommu.h b/drivers/iommu/mtk_iommu.h
new file mode 100644
index 000..5656355
--- /dev/null
+++ b/drivers/iommu/mtk_iommu.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2015-2016 MediaTek Inc.
+ * Author: Yong Wu 
+ *   : Honghui Zhang 
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _MTK_IOMMU_H_
+#define _MTK_IOMMU_H_
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "io-pgtable.h"
+
+struct mtk_iommu_suspend_reg {
+   u32 standard_axi_mode;
+   u32 dcm_dis;
+   u32 ctrl_reg;
+   u32 int_control0;
+   u32 int_main_control;
+};
+
+struct mtk_iommu_client_priv {
+   struct list_headclient;
+   unsigned intmtk_m4u_id;
+   struct device   *m4udev;
+};
+
+struct mtk_iommu_domain {
+   spinlock_t  pgtlock; /* lock for page table */
+
+   struct io_pgtable_cfg   cfg;
+   struct io_pgtable_ops   *iop;
+
+   struct iommu_domain domain;
+};
+
+struct mtk_iommu_data {
+   void __iomem*base;
+   int irq;
+   struct device   *dev;
+   struct clk  *bclk;
+   phys_addr_t protect_base; /* protect memory base *

[PATCH v2 0/5] MT2701 iommu support

2016-05-19 Thread honghui.zhang
From: Honghui Zhang 

  Mediatek's m4u(Multimedia Memory Management Unit) and SMI(Smart
Multimedia Interface)have two generations HW. They basically sharing the
same hardware block diagram, but have some difference as below:

  Generation one m4u only supports one layer, flat pagetable addressing,
and only supports 4K size page mapping. While generation two m4u supports 2
levels of pagetable which uses the ARM short-descriptor translation table
format for address translation.
They have slight different register base and register offset.
They have very different HW ports defines.

  Generaion one SMI has additional "async" clock which transform the smi
clock into emi clock domain, this clock should be prepared and enabled for
SMI generation one HW.
The register which control the iommu need to translation the address or not
for a particular port is located at smi ao base(smi always on register
base) for generation one SMI HW, but located at each larb's register base
for generation two HW.

This patch set add mt2701 iommu support, it's based on 4.6-rc1 and James
Liao's "Add clock support for Mediatek MT2701 v8[1]" and "Mediatek MT2701
SCPSYS power domain support v7[2]" patch.

v2:
-Fix syntax errors in dt-bindings.
-Use dma_alloc/free_coherent to allocate pagetable memory and reduce the
 streaming DMA stuff.
-Make the mtk_iommu_ops.pgsize_bitmap as ~0UL << MT2701_IOMMU_PAGE_SHIFT.
-Use macro instead of variable to indicate the pagetable size.
-Change some macro name from MTK_XXX to MT2701_XXX.

v1: http://lists.infradead.org/pipermail/linux-mediatek/2016-May/005301.html
-initial version

[1] http://lists.infradead.org/pipermail/linux-mediatek/2016-May/005439.html
[2] http://lists.infradead.org/pipermail/linux-mediatek/2016-May/005429.html

Honghui Zhang (5):
  dt-bindings: mediatek: add descriptions for mediatek mt2701 iommu and
smi
  iommu/mediatek: move the common struct into header file
  memory/mediatek: add support for mt2701
  iommu/mediatek: add support for mtk iommu generation one HW
  ARM: dts: mt2701: add iommu/smi dtsi node for mt2701

 .../devicetree/bindings/iommu/mediatek,iommu.txt   |  13 +-
 .../memory-controllers/mediatek,smi-common.txt |  21 +-
 .../memory-controllers/mediatek,smi-larb.txt   |   4 +-
 arch/arm/boot/dts/mt2701.dtsi  |  51 ++
 drivers/iommu/Kconfig  |  19 +
 drivers/iommu/Makefile |   1 +
 drivers/iommu/mtk_iommu.c  |  62 +-
 drivers/iommu/mtk_iommu.h  |  93 +++
 drivers/iommu/mtk_iommu_v1.c   | 742 +
 drivers/memory/mtk-smi.c   | 168 -
 include/dt-bindings/memory/mt2701-larb-port.h  |  85 +++
 11 files changed, 1171 insertions(+), 88 deletions(-)
 create mode 100644 drivers/iommu/mtk_iommu.h
 create mode 100644 drivers/iommu/mtk_iommu_v1.c
 create mode 100644 include/dt-bindings/memory/mt2701-larb-port.h

-- 
1.8.1.1.dirty



[PATCH v2 1/5] dt-bindings: mediatek: add descriptions for mediatek mt2701 iommu and smi

2016-05-19 Thread honghui.zhang
From: Honghui Zhang 

This patch defines the local arbitor port IDs for mediatek SoC MT2701 and
add descriptions of binding for mediatek generation one iommu and smi.

Signed-off-by: Honghui Zhang 
---
 .../devicetree/bindings/iommu/mediatek,iommu.txt   | 13 +++-
 .../memory-controllers/mediatek,smi-common.txt | 21 +-
 .../memory-controllers/mediatek,smi-larb.txt   |  4 +-
 include/dt-bindings/memory/mt2701-larb-port.h  | 85 ++
 4 files changed, 115 insertions(+), 8 deletions(-)
 create mode 100644 include/dt-bindings/memory/mt2701-larb-port.h

diff --git a/Documentation/devicetree/bindings/iommu/mediatek,iommu.txt 
b/Documentation/devicetree/bindings/iommu/mediatek,iommu.txt
index cd1b1cd..53c20ca 100644
--- a/Documentation/devicetree/bindings/iommu/mediatek,iommu.txt
+++ b/Documentation/devicetree/bindings/iommu/mediatek,iommu.txt
@@ -1,7 +1,9 @@
 * Mediatek IOMMU Architecture Implementation
 
-  Some Mediatek SOCs contain a Multimedia Memory Management Unit (M4U) which
-uses the ARM Short-Descriptor translation table format for address translation.
+  Some Mediatek SOCs contain a Multimedia Memory Management Unit (M4U), and
+this M4U have two generations of HW architecture. Generation one uses flat
+pagetable, and only supports 4K size page mapping. Generation two uses the
+ARM Short-Descriptor translation table format for address translation.
 
   About the M4U Hardware Block Diagram, please check below:
 
@@ -36,7 +38,9 @@ in each larb. Take a example, There are many ports like MC, 
PP, VLD in the
 video decode local arbiter, all these ports are according to the video HW.
 
 Required properties:
-- compatible : must be "mediatek,mt8173-m4u".
+- compatible : must be one of the following string:
+   "mediatek,mt2701-m4u" for mt2701 which uses generation one m4u HW.
+   "mediatek,mt8173-m4u" for mt8173 which uses generation two m4u HW.
 - reg : m4u register base and size.
 - interrupts : the interrupt of m4u.
 - clocks : must contain one entry for each clock-names.
@@ -46,7 +50,8 @@ Required properties:
according to the local arbiter index, like larb0, larb1, larb2...
 - iommu-cells : must be 1. This is the mtk_m4u_id according to the HW.
Specifies the mtk_m4u_id as defined in
-   dt-binding/memory/mt8173-larb-port.h.
+   dt-binding/memory/mt2701-larb-port.h for mt2701 and
+   dt-binding/memory/mt8173-larb-port.h for mt8173
 
 Example:
iommu: iommu@10205000 {
diff --git 
a/Documentation/devicetree/bindings/memory-controllers/mediatek,smi-common.txt 
b/Documentation/devicetree/bindings/memory-controllers/mediatek,smi-common.txt
index 06a83ce..aa614b2 100644
--- 
a/Documentation/devicetree/bindings/memory-controllers/mediatek,smi-common.txt
+++ 
b/Documentation/devicetree/bindings/memory-controllers/mediatek,smi-common.txt
@@ -2,16 +2,31 @@ SMI (Smart Multimedia Interface) Common
 
 The hardware block diagram please check bindings/iommu/mediatek,iommu.txt
 
+Mediatek SMI have two generations of HW architecture, mt8173 uses the second
+generation of SMI HW while mt2701 uses the first generation HW of SMI.
+
+There's slight differences between the two SMI, for generation 2, the
+register which control the iommu port is at each larb's register base. But
+for generation 1, the register is at smi ao base(smi always on register
+base). Besides that, the smi async clock should be prepared and enabled for
+SMI generation 1 to transform the smi clock into emi clock domain, but that is
+not needed for SMI generation 2.
+
 Required properties:
-- compatible : must be "mediatek,mt8173-smi-common"
+- compatible : must be one of :
+   "mediatek,mt2701-smi-common"
+   "mediatek,mt8173-smi-common"
 - reg : the register and size of the SMI block.
 - power-domains : a phandle to the power domain of this local arbiter.
 - clocks : Must contain an entry for each entry in clock-names.
-- clock-names : must contain 2 entries, as follows:
+- clock-names : must contain 3 entries for generation 1 smi HW and 2 entries
+  for generation 2 smi HW as follows:
   - "apb" : Advanced Peripheral Bus clock, It's the clock for setting
the register.
   - "smi" : It's the clock for transfer data and command.
-  They may be the same if both source clocks are the same.
+   They may be the same if both source clocks are the same.
+  - "async" : asynchronous clock, it help transform the smi clock into the emi
+ clock domain, this clock is only needed by generation 1 smi HW.
 
 Example:
smi_common: smi@14022000 {
diff --git 
a/Documentation/devicetree/bindings/memory-controllers/mediatek,smi-larb.txt 
b/Documentation/devicetree/bindings/memory-controllers/mediatek,smi-larb.txt
index 55ff3b7..21277a5 100644
--- a/Documentation/devicetree/bindings/memory-controllers/mediatek,smi-larb.txt
+++ b/Documentation/devicetree/bindings/memory-controllers/mediatek,smi-larb.txt
@@ -3,7 +3,9 @@ SMI (Smart Multimedia Interface) Local Ar

[PATCH v2 4/5] iommu/mediatek: add support for mtk iommu generation one HW

2016-05-19 Thread honghui.zhang
From: Honghui Zhang 

Mediatek SoC's M4U has two generations of HW architcture. Generation one
uses flat, one layer pagetable, and was shipped with ARM architecture, it
only supports 4K size page mapping. MT2701 SoC uses this generation one
m4u HW. Generation two uses the ARM short-descriptor translation table
format for address translation, and was shipped with ARM64 architecture,
MT8173 uses this generation two m4u HW. All the two generation iommu HW
only have one iommu domain, and all its iommu clients share the same
iova address.

These two generation m4u HW have slit different register groups and
register offset, but most register names are the same. This patch add iommu
support for mediatek SoC mt2701.

Signed-off-by: Honghui Zhang 
---
 drivers/iommu/Kconfig|  19 ++
 drivers/iommu/Makefile   |   1 +
 drivers/iommu/mtk_iommu.h|   3 +
 drivers/iommu/mtk_iommu_v1.c | 742 +++
 4 files changed, 765 insertions(+)
 create mode 100644 drivers/iommu/mtk_iommu_v1.c

diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
index dd1dc39..2e17d70 100644
--- a/drivers/iommu/Kconfig
+++ b/drivers/iommu/Kconfig
@@ -354,4 +354,23 @@ config MTK_IOMMU
 
  If unsure, say N here.
 
+config MTK_IOMMU_V1
+   bool "MTK IOMMU Version 1 (M4U gen1) Support"
+   depends on ARM || ARM64
+   depends on ARCH_MEDIATEK || COMPILE_TEST
+   select ARM_DMA_USE_IOMMU
+   select IOMMU_API
+   select IOMMU_DMA
+   select MEMORY
+   select MTK_SMI
+   select COMMON_CLK_MT2701_MMSYS
+   select COMMON_CLK_MT2701_IMGSYS
+   select COMMON_CLK_MT2701_VDECSYS
+   help
+ Support for the M4U on certain Mediatek SoCs. M4U generation 1 HW is
+ Multimedia Memory Managememt Unit. This option enables remapping of
+ DMA memory accesses for the multimedia subsystem.
+
+ if unsure, say N here.
+
 endif # IOMMU_SUPPORT
diff --git a/drivers/iommu/Makefile b/drivers/iommu/Makefile
index c6edb31..778baf5 100644
--- a/drivers/iommu/Makefile
+++ b/drivers/iommu/Makefile
@@ -18,6 +18,7 @@ obj-$(CONFIG_INTEL_IOMMU_SVM) += intel-svm.o
 obj-$(CONFIG_IPMMU_VMSA) += ipmmu-vmsa.o
 obj-$(CONFIG_IRQ_REMAP) += intel_irq_remapping.o irq_remapping.o
 obj-$(CONFIG_MTK_IOMMU) += mtk_iommu.o
+obj-$(CONFIG_MTK_IOMMU_V1) += mtk_iommu_v1.o
 obj-$(CONFIG_OMAP_IOMMU) += omap-iommu.o
 obj-$(CONFIG_OMAP_IOMMU_DEBUG) += omap-iommu-debug.o
 obj-$(CONFIG_ROCKCHIP_IOMMU) += rockchip-iommu.o
diff --git a/drivers/iommu/mtk_iommu.h b/drivers/iommu/mtk_iommu.h
index 5656355..8d60f21 100644
--- a/drivers/iommu/mtk_iommu.h
+++ b/drivers/iommu/mtk_iommu.h
@@ -48,6 +48,9 @@ struct mtk_iommu_domain {
struct io_pgtable_ops   *iop;
 
struct iommu_domain domain;
+   void*pgt_va;
+   dma_addr_t  pgt_pa;
+   void*cookie;
 };
 
 struct mtk_iommu_data {
diff --git a/drivers/iommu/mtk_iommu_v1.c b/drivers/iommu/mtk_iommu_v1.c
new file mode 100644
index 000..55023e1
--- /dev/null
+++ b/drivers/iommu/mtk_iommu_v1.c
@@ -0,0 +1,742 @@
+/*
+ * Copyright (c) 2015-2016 MediaTek Inc.
+ * Author: Yong Wu 
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include "mtk_iommu.h"
+
+#define REG_MMU_PT_BASE_ADDR   0x000
+
+#define F_ALL_INVLD0x2
+#define F_MMU_INV_RANGE0x1
+#define F_INVLD_EN0BIT(0)
+#define F_INVLD_EN1BIT(1)
+
+#define F_MMU_FAULT_VA_MSK 0xf000
+#define MTK_PROTECT_PA_ALIGN   128
+
+#define REG_MMU_CTRL_REG   0x210
+#define F_MMU_CTRL_COHERENT_EN BIT(8)
+#define REG_MMU_IVRP_PADDR 0x214
+#define REG_MMU_INT_CONTROL0x220
+#define F_INT_TRANSLATION_FAULTBIT(0)
+#define F_INT_MAIN_MULTI_HIT_FAULT BIT(1)
+#define F_INT_INVALID_PA_FAULT BIT(2)
+#define F_INT_ENTRY_REPLACEMENT_FAULT  BIT(3)
+#define F_INT_TABLE_WALK_FAULT BIT(4)
+#define F_INT_TLB_MISS_FAULT   BIT(5)
+#define F_INT_PFH_DMA_FIFO_OVERFLOWBIT(6)
+#define F_IN

[PATCH v2 2/5] iommu/mediatek: move the common struct into header file

2016-05-19 Thread honghui.zhang
From: Honghui Zhang 

Move the struct defines of mtk iommu into a new header files for
common use.

Signed-off-by: Honghui Zhang 
---
 drivers/iommu/mtk_iommu.c | 62 +---
 drivers/iommu/mtk_iommu.h | 90 +++
 2 files changed, 91 insertions(+), 61 deletions(-)
 create mode 100644 drivers/iommu/mtk_iommu.h

diff --git a/drivers/iommu/mtk_iommu.c b/drivers/iommu/mtk_iommu.c
index db74553..a6b7846 100644
--- a/drivers/iommu/mtk_iommu.c
+++ b/drivers/iommu/mtk_iommu.c
@@ -34,7 +34,7 @@
 #include 
 #include 
 
-#include "io-pgtable.h"
+#include "mtk_iommu.h"
 
 #define REG_MMU_PT_BASE_ADDR   0x000
 
@@ -93,49 +93,8 @@
 
 #define MTK_PROTECT_PA_ALIGN   128
 
-struct mtk_iommu_suspend_reg {
-   u32 standard_axi_mode;
-   u32 dcm_dis;
-   u32 ctrl_reg;
-   u32 int_control0;
-   u32 int_main_control;
-};
-
-struct mtk_iommu_client_priv {
-   struct list_headclient;
-   unsigned intmtk_m4u_id;
-   struct device   *m4udev;
-};
-
-struct mtk_iommu_domain {
-   spinlock_t  pgtlock; /* lock for page table */
-
-   struct io_pgtable_cfg   cfg;
-   struct io_pgtable_ops   *iop;
-
-   struct iommu_domain domain;
-};
-
-struct mtk_iommu_data {
-   void __iomem*base;
-   int irq;
-   struct device   *dev;
-   struct clk  *bclk;
-   phys_addr_t protect_base; /* protect memory base */
-   struct mtk_iommu_suspend_regreg;
-   struct mtk_iommu_domain *m4u_dom;
-   struct iommu_group  *m4u_group;
-   struct mtk_smi_iommusmi_imu;  /* SMI larb iommu info */
-   boolenable_4GB;
-};
-
 static struct iommu_ops mtk_iommu_ops;
 
-static struct mtk_iommu_domain *to_mtk_domain(struct iommu_domain *dom)
-{
-   return container_of(dom, struct mtk_iommu_domain, domain);
-}
-
 static void mtk_iommu_tlb_flush_all(void *cookie)
 {
struct mtk_iommu_data *data = cookie;
@@ -552,25 +511,6 @@ static int mtk_iommu_hw_init(const struct mtk_iommu_data 
*data)
return 0;
 }
 
-static int compare_of(struct device *dev, void *data)
-{
-   return dev->of_node == data;
-}
-
-static int mtk_iommu_bind(struct device *dev)
-{
-   struct mtk_iommu_data *data = dev_get_drvdata(dev);
-
-   return component_bind_all(dev, &data->smi_imu);
-}
-
-static void mtk_iommu_unbind(struct device *dev)
-{
-   struct mtk_iommu_data *data = dev_get_drvdata(dev);
-
-   component_unbind_all(dev, &data->smi_imu);
-}
-
 static const struct component_master_ops mtk_iommu_com_ops = {
.bind   = mtk_iommu_bind,
.unbind = mtk_iommu_unbind,
diff --git a/drivers/iommu/mtk_iommu.h b/drivers/iommu/mtk_iommu.h
new file mode 100644
index 000..5656355
--- /dev/null
+++ b/drivers/iommu/mtk_iommu.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2015-2016 MediaTek Inc.
+ * Author: Yong Wu 
+ *   : Honghui Zhang 
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _MTK_IOMMU_H_
+#define _MTK_IOMMU_H_
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "io-pgtable.h"
+
+struct mtk_iommu_suspend_reg {
+   u32 standard_axi_mode;
+   u32 dcm_dis;
+   u32 ctrl_reg;
+   u32 int_control0;
+   u32 int_main_control;
+};
+
+struct mtk_iommu_client_priv {
+   struct list_headclient;
+   unsigned intmtk_m4u_id;
+   struct device   *m4udev;
+};
+
+struct mtk_iommu_domain {
+   spinlock_t  pgtlock; /* lock for page table */
+
+   struct io_pgtable_cfg   cfg;
+   struct io_pgtable_ops   *iop;
+
+   struct iommu_domain domain;
+};
+
+struct mtk_iommu_data {
+   void __iomem*base;
+   int irq;
+   struct device   *dev;
+   struct clk  *bclk;
+   phys_addr_t protect_base; /* protect memory base *

[PATCH 5/5] ARM: dts: mt2701: add iommu/smi dtsi node for mt2701

2016-05-19 Thread honghui.zhang
From: Honghui Zhang 

Add the dtsi node of iommu and smi for mt2701.

Signed-off-by: Honghui Zhang 
---
 arch/arm/boot/dts/mt2701.dtsi | 51 +++
 1 file changed, 51 insertions(+)

diff --git a/arch/arm/boot/dts/mt2701.dtsi b/arch/arm/boot/dts/mt2701.dtsi
index 42d5a37..363de0d 100644
--- a/arch/arm/boot/dts/mt2701.dtsi
+++ b/arch/arm/boot/dts/mt2701.dtsi
@@ -16,6 +16,7 @@
 #include 
 #include 
 #include 
+#include 
 #include "skeleton64.dtsi"
 #include "mt2701-pinfunc.h"
 
@@ -160,6 +161,16 @@
clock-names = "system-clk", "rtc-clk";
};
 
+   smi_common: smi@1000c000 {
+   compatible = "mediatek,mt2701-smi-common";
+   reg = <0 0x1000c000 0 0x1000>;
+   clocks = <&infracfg CLK_INFRA_SMI>,
+<&mmsys CLK_MM_SMI_COMMON>,
+<&infracfg CLK_INFRA_SMI>;
+   clock-names = "apb", "smi", "async";
+   power-domains = <&scpsys MT2701_POWER_DOMAIN_DISP>;
+   };
+
sysirq: interrupt-controller@10200100 {
compatible = "mediatek,mt2701-sysirq",
 "mediatek,mt6577-sysirq";
@@ -169,6 +180,16 @@
reg = <0 0x10200100 0 0x1c>;
};
 
+   iommu: mmsys_iommu@10205000 {
+   compatible = "mediatek,mt2701-m4u";
+   reg = <0 0x10205000 0 0x1000>;
+   interrupts = ;
+   clocks = <&infracfg CLK_INFRA_M4U>;
+   clock-names = "bclk";
+   mediatek,larbs = <&larb0 &larb1 &larb2>;
+   #iommu-cells = <1>;
+   };
+
apmixedsys: syscon@10209000 {
compatible = "mediatek,mt2701-apmixedsys", "syscon";
reg = <0 0x10209000 0 0x1000>;
@@ -234,6 +255,16 @@
status = "disabled";
};
 
+   larb0: larb@1401 {
+   compatible = "mediatek,mt2701-smi-larb";
+   reg = <0 0x1401 0 0x1000>;
+   mediatek,smi = <&smi_common>;
+   clocks = <&mmsys CLK_MM_SMI_LARB0>,
+<&mmsys CLK_MM_SMI_LARB0>;
+   clock-names = "apb", "smi";
+   power-domains = <&scpsys MT2701_POWER_DOMAIN_DISP>;
+   };
+
imgsys: syscon@1500 {
compatible = "mediatek,mt2701-imgsys", "syscon";
reg = <0 0x1500 0 0x1000>;
@@ -241,6 +272,16 @@
status = "disabled";
};
 
+   larb2: larb@15001000 {
+   compatible = "mediatek,mt2701-smi-larb";
+   reg = <0 0x15001000 0 0x1000>;
+   mediatek,smi = <&smi_common>;
+   clocks = <&imgsys CLK_IMG_SMI_COMM>,
+<&imgsys CLK_IMG_SMI_COMM>;
+   clock-names = "apb", "smi";
+   power-domains = <&scpsys MT2701_POWER_DOMAIN_ISP>;
+   };
+
vdecsys: syscon@1600 {
compatible = "mediatek,mt2701-vdecsys", "syscon";
reg = <0 0x1600 0 0x1000>;
@@ -248,6 +289,16 @@
status = "disabled";
};
 
+   larb1: larb@1601 {
+   compatible = "mediatek,mt2701-smi-larb";
+   reg = <0 0x1601 0 0x1000>;
+   mediatek,smi = <&smi_common>;
+   clocks = <&vdecsys CLK_VDEC_CKGEN>,
+<&vdecsys CLK_VDEC_LARB>;
+   clock-names = "apb", "smi";
+   power-domains = <&scpsys MT2701_POWER_DOMAIN_VDEC>;
+   };
+
hifsys: syscon@1a00 {
compatible = "mediatek,mt2701-hifsys", "syscon";
reg = <0 0x1a00 0 0x1000>;
-- 
1.8.1.1.dirty



[PATCH v2 3/5] memory/mediatek: add support for mt2701

2016-05-19 Thread honghui.zhang
From: Honghui Zhang 

Mediatek SMI has two generations of HW architecture, mt8173 uses the
second generation of SMI HW while mt2701 uses the first generation
HW of SMI.

There's slight differences between the two generations, for generation 2,
the register which control the iommu port access PA or IOVA is at each
larb's register base. But for generation 1, the register is at smi ao
base(smi always on register base).
Besides that, the smi async clock should be prepared and enabled for SMI
generation 1 HW to transform the smi clock into emi clock domain, but is
not needed for SMI generation 2.

This patch add SMI driver for mt2701 which use generation 1 SMI HW.

Signed-off-by: Honghui Zhang 
---
 drivers/memory/mtk-smi.c | 168 +--
 1 file changed, 149 insertions(+), 19 deletions(-)

diff --git a/drivers/memory/mtk-smi.c b/drivers/memory/mtk-smi.c
index 089091f..0a47382 100644
--- a/drivers/memory/mtk-smi.c
+++ b/drivers/memory/mtk-smi.c
@@ -21,19 +21,50 @@
 #include 
 #include 
 #include 
+#include 
 
 #define SMI_LARB_MMU_EN0xf00
+#define REG_SMI_SECUR_CON_BASE 0x5c0
+
+/* every register control 8 port, register offset 0x4 */
+#define REG_SMI_SECUR_CON_OFFSET(id)   (((id) >> 3) << 2)
+#define REG_SMI_SECUR_CON_ADDR(id) \
+   (REG_SMI_SECUR_CON_BASE + REG_SMI_SECUR_CON_OFFSET(id))
+
+/*
+ * every port have 4 bit to control, bit[port + 3] control virtual or physical,
+ * bit[port + 2 : port + 1] control the domain, bit[port] control the security
+ * or non-security.
+ */
+#define SMI_SECUR_CON_VAL_MSK(id)  (~(0xf << (((id) & 0x7) << 2)))
+#define SMI_SECUR_CON_VAL_VIRT(id) BITid) & 0x7) << 2) + 3)
+/* mt2701 domain should be set to 3 */
+#define SMI_SECUR_CON_VAL_DOMAIN(id)   (0x3 << id) & 0x7) << 2) + 1))
+
+struct mtk_smi_larb_gen {
+   int port_in_larb[MTK_LARB_NR_MAX + 1];
+   void (*config_port)(struct device *);
+};
 
 struct mtk_smi {
-   struct device   *dev;
-   struct clk  *clk_apb, *clk_smi;
+   struct device   *dev;
+   struct clk  *clk_apb, *clk_smi;
+   struct clk  *clk_async; /*only needed by mt2701*/
+   void __iomem*smi_ao_base;
 };
 
 struct mtk_smi_larb { /* larb: local arbiter */
-   struct mtk_smi  smi;
-   void __iomem*base;
-   struct device   *smi_common_dev;
-   u32 *mmu;
+   struct mtk_smi  smi;
+   void __iomem*base;
+   struct device   *smi_common_dev;
+   const struct mtk_smi_larb_gen   *larb_gen;
+   int larbid;
+   u32 *mmu;
+};
+
+enum mtk_smi_gen {
+   MTK_SMI_GEN1,
+   MTK_SMI_GEN2
 };
 
 static int mtk_smi_enable(const struct mtk_smi *smi)
@@ -71,6 +102,7 @@ static void mtk_smi_disable(const struct mtk_smi *smi)
 int mtk_smi_larb_get(struct device *larbdev)
 {
struct mtk_smi_larb *larb = dev_get_drvdata(larbdev);
+   const struct mtk_smi_larb_gen *larb_gen = larb->larb_gen;
struct mtk_smi *common = dev_get_drvdata(larb->smi_common_dev);
int ret;
 
@@ -87,8 +119,7 @@ int mtk_smi_larb_get(struct device *larbdev)
}
 
/* Configure the iommu info for this larb */
-   writel(*larb->mmu, larb->base + SMI_LARB_MMU_EN);
-
+   larb_gen->config_port(larbdev);
return 0;
 }
 
@@ -124,6 +155,45 @@ mtk_smi_larb_bind(struct device *dev, struct device 
*master, void *data)
return -ENODEV;
 }
 
+static void mtk_smi_larb_config_port(struct device *dev)
+{
+   struct mtk_smi_larb *larb = dev_get_drvdata(dev);
+
+   writel(*larb->mmu, larb->base + SMI_LARB_MMU_EN);
+}
+
+
+static void mtk_smi_larb_config_port_gen1(struct device *dev)
+{
+   struct mtk_smi_larb *larb = dev_get_drvdata(dev);
+   const struct mtk_smi_larb_gen *larb_gen = larb->larb_gen;
+   struct mtk_smi *common = dev_get_drvdata(larb->smi_common_dev);
+   int i, m4u_port_id, larb_port_num;
+   u32 sec_con_val, reg_val;
+
+   m4u_port_id = larb_gen->port_in_larb[larb->larbid];
+   larb_port_num = larb_gen->port_in_larb[larb->larbid + 1]
+   - larb_gen->port_in_larb[larb->larbid];
+
+   for (i = 0; i < larb_port_num; i++, m4u_port_id++) {
+   if (*larb->mmu & BIT(i)) {
+   /* bit[port + 3] controls the virtual or physical */
+   sec_con_val = SMI_SECUR_CON_VAL_VIRT(m4u_port_id);
+   } else {
+   /* do not need to enable m4u for this port */
+   continue;
+   }
+   reg_val = readl(common->smi_ao_base
+   + REG_SMI_SECUR_CON_ADDR(m4u_port_id));
+   reg_val &= SMI_SECUR_CON_VAL_MSK(m4u_port_id);
+   reg_val |= sec_con_val;
+   reg_val |= SMI_SECUR_CON_VAL_DOMA

[PATCH v3 3/5] memory/mediatek: add support for mt2701

2016-05-27 Thread honghui.zhang
From: Honghui Zhang 

Mediatek SMI has two generations of HW architecture, mt8173 uses the
second generation of SMI HW while mt2701 uses the first generation
HW of SMI.

There's slight differences between the two generations, for generation 2,
the register which control the iommu port access PA or IOVA is at each
larb's register base. But for generation 1, the register is at smi ao
base(smi always on register base).
Besides that, the smi async clock should be prepared and enabled for SMI
generation 1 HW to transform the smi clock into emi clock domain, but is
not needed for SMI generation 2.

This patch add SMI driver for mt2701 which use generation 1 SMI HW.

Signed-off-by: Honghui Zhang 
---
 drivers/memory/mtk-smi.c | 168 +--
 1 file changed, 149 insertions(+), 19 deletions(-)

diff --git a/drivers/memory/mtk-smi.c b/drivers/memory/mtk-smi.c
index 089091f..0a47382 100644
--- a/drivers/memory/mtk-smi.c
+++ b/drivers/memory/mtk-smi.c
@@ -21,19 +21,50 @@
 #include 
 #include 
 #include 
+#include 
 
 #define SMI_LARB_MMU_EN0xf00
+#define REG_SMI_SECUR_CON_BASE 0x5c0
+
+/* every register control 8 port, register offset 0x4 */
+#define REG_SMI_SECUR_CON_OFFSET(id)   (((id) >> 3) << 2)
+#define REG_SMI_SECUR_CON_ADDR(id) \
+   (REG_SMI_SECUR_CON_BASE + REG_SMI_SECUR_CON_OFFSET(id))
+
+/*
+ * every port have 4 bit to control, bit[port + 3] control virtual or physical,
+ * bit[port + 2 : port + 1] control the domain, bit[port] control the security
+ * or non-security.
+ */
+#define SMI_SECUR_CON_VAL_MSK(id)  (~(0xf << (((id) & 0x7) << 2)))
+#define SMI_SECUR_CON_VAL_VIRT(id) BITid) & 0x7) << 2) + 3)
+/* mt2701 domain should be set to 3 */
+#define SMI_SECUR_CON_VAL_DOMAIN(id)   (0x3 << id) & 0x7) << 2) + 1))
+
+struct mtk_smi_larb_gen {
+   int port_in_larb[MTK_LARB_NR_MAX + 1];
+   void (*config_port)(struct device *);
+};
 
 struct mtk_smi {
-   struct device   *dev;
-   struct clk  *clk_apb, *clk_smi;
+   struct device   *dev;
+   struct clk  *clk_apb, *clk_smi;
+   struct clk  *clk_async; /*only needed by mt2701*/
+   void __iomem*smi_ao_base;
 };
 
 struct mtk_smi_larb { /* larb: local arbiter */
-   struct mtk_smi  smi;
-   void __iomem*base;
-   struct device   *smi_common_dev;
-   u32 *mmu;
+   struct mtk_smi  smi;
+   void __iomem*base;
+   struct device   *smi_common_dev;
+   const struct mtk_smi_larb_gen   *larb_gen;
+   int larbid;
+   u32 *mmu;
+};
+
+enum mtk_smi_gen {
+   MTK_SMI_GEN1,
+   MTK_SMI_GEN2
 };
 
 static int mtk_smi_enable(const struct mtk_smi *smi)
@@ -71,6 +102,7 @@ static void mtk_smi_disable(const struct mtk_smi *smi)
 int mtk_smi_larb_get(struct device *larbdev)
 {
struct mtk_smi_larb *larb = dev_get_drvdata(larbdev);
+   const struct mtk_smi_larb_gen *larb_gen = larb->larb_gen;
struct mtk_smi *common = dev_get_drvdata(larb->smi_common_dev);
int ret;
 
@@ -87,8 +119,7 @@ int mtk_smi_larb_get(struct device *larbdev)
}
 
/* Configure the iommu info for this larb */
-   writel(*larb->mmu, larb->base + SMI_LARB_MMU_EN);
-
+   larb_gen->config_port(larbdev);
return 0;
 }
 
@@ -124,6 +155,45 @@ mtk_smi_larb_bind(struct device *dev, struct device 
*master, void *data)
return -ENODEV;
 }
 
+static void mtk_smi_larb_config_port(struct device *dev)
+{
+   struct mtk_smi_larb *larb = dev_get_drvdata(dev);
+
+   writel(*larb->mmu, larb->base + SMI_LARB_MMU_EN);
+}
+
+
+static void mtk_smi_larb_config_port_gen1(struct device *dev)
+{
+   struct mtk_smi_larb *larb = dev_get_drvdata(dev);
+   const struct mtk_smi_larb_gen *larb_gen = larb->larb_gen;
+   struct mtk_smi *common = dev_get_drvdata(larb->smi_common_dev);
+   int i, m4u_port_id, larb_port_num;
+   u32 sec_con_val, reg_val;
+
+   m4u_port_id = larb_gen->port_in_larb[larb->larbid];
+   larb_port_num = larb_gen->port_in_larb[larb->larbid + 1]
+   - larb_gen->port_in_larb[larb->larbid];
+
+   for (i = 0; i < larb_port_num; i++, m4u_port_id++) {
+   if (*larb->mmu & BIT(i)) {
+   /* bit[port + 3] controls the virtual or physical */
+   sec_con_val = SMI_SECUR_CON_VAL_VIRT(m4u_port_id);
+   } else {
+   /* do not need to enable m4u for this port */
+   continue;
+   }
+   reg_val = readl(common->smi_ao_base
+   + REG_SMI_SECUR_CON_ADDR(m4u_port_id));
+   reg_val &= SMI_SECUR_CON_VAL_MSK(m4u_port_id);
+   reg_val |= sec_con_val;
+   reg_val |= SMI_SECUR_CON_VAL_DOMA

[PATCH v3 5/5] ARM: dts: mt2701: add iommu/smi dtsi node for mt2701

2016-05-27 Thread honghui.zhang
From: Honghui Zhang 

Add the dtsi node of iommu and smi for mt2701.

Signed-off-by: Honghui Zhang 
---
 arch/arm/boot/dts/mt2701.dtsi | 51 +++
 1 file changed, 51 insertions(+)

diff --git a/arch/arm/boot/dts/mt2701.dtsi b/arch/arm/boot/dts/mt2701.dtsi
index 42d5a37..363de0d 100644
--- a/arch/arm/boot/dts/mt2701.dtsi
+++ b/arch/arm/boot/dts/mt2701.dtsi
@@ -16,6 +16,7 @@
 #include 
 #include 
 #include 
+#include 
 #include "skeleton64.dtsi"
 #include "mt2701-pinfunc.h"
 
@@ -160,6 +161,16 @@
clock-names = "system-clk", "rtc-clk";
};
 
+   smi_common: smi@1000c000 {
+   compatible = "mediatek,mt2701-smi-common";
+   reg = <0 0x1000c000 0 0x1000>;
+   clocks = <&infracfg CLK_INFRA_SMI>,
+<&mmsys CLK_MM_SMI_COMMON>,
+<&infracfg CLK_INFRA_SMI>;
+   clock-names = "apb", "smi", "async";
+   power-domains = <&scpsys MT2701_POWER_DOMAIN_DISP>;
+   };
+
sysirq: interrupt-controller@10200100 {
compatible = "mediatek,mt2701-sysirq",
 "mediatek,mt6577-sysirq";
@@ -169,6 +180,16 @@
reg = <0 0x10200100 0 0x1c>;
};
 
+   iommu: mmsys_iommu@10205000 {
+   compatible = "mediatek,mt2701-m4u";
+   reg = <0 0x10205000 0 0x1000>;
+   interrupts = ;
+   clocks = <&infracfg CLK_INFRA_M4U>;
+   clock-names = "bclk";
+   mediatek,larbs = <&larb0 &larb1 &larb2>;
+   #iommu-cells = <1>;
+   };
+
apmixedsys: syscon@10209000 {
compatible = "mediatek,mt2701-apmixedsys", "syscon";
reg = <0 0x10209000 0 0x1000>;
@@ -234,6 +255,16 @@
status = "disabled";
};
 
+   larb0: larb@1401 {
+   compatible = "mediatek,mt2701-smi-larb";
+   reg = <0 0x1401 0 0x1000>;
+   mediatek,smi = <&smi_common>;
+   clocks = <&mmsys CLK_MM_SMI_LARB0>,
+<&mmsys CLK_MM_SMI_LARB0>;
+   clock-names = "apb", "smi";
+   power-domains = <&scpsys MT2701_POWER_DOMAIN_DISP>;
+   };
+
imgsys: syscon@1500 {
compatible = "mediatek,mt2701-imgsys", "syscon";
reg = <0 0x1500 0 0x1000>;
@@ -241,6 +272,16 @@
status = "disabled";
};
 
+   larb2: larb@15001000 {
+   compatible = "mediatek,mt2701-smi-larb";
+   reg = <0 0x15001000 0 0x1000>;
+   mediatek,smi = <&smi_common>;
+   clocks = <&imgsys CLK_IMG_SMI_COMM>,
+<&imgsys CLK_IMG_SMI_COMM>;
+   clock-names = "apb", "smi";
+   power-domains = <&scpsys MT2701_POWER_DOMAIN_ISP>;
+   };
+
vdecsys: syscon@1600 {
compatible = "mediatek,mt2701-vdecsys", "syscon";
reg = <0 0x1600 0 0x1000>;
@@ -248,6 +289,16 @@
status = "disabled";
};
 
+   larb1: larb@1601 {
+   compatible = "mediatek,mt2701-smi-larb";
+   reg = <0 0x1601 0 0x1000>;
+   mediatek,smi = <&smi_common>;
+   clocks = <&vdecsys CLK_VDEC_CKGEN>,
+<&vdecsys CLK_VDEC_LARB>;
+   clock-names = "apb", "smi";
+   power-domains = <&scpsys MT2701_POWER_DOMAIN_VDEC>;
+   };
+
hifsys: syscon@1a00 {
compatible = "mediatek,mt2701-hifsys", "syscon";
reg = <0 0x1a00 0 0x1000>;
-- 
1.8.1.1.dirty



[PATCH v3 4/5] iommu/mediatek: add support for mtk iommu generation one HW

2016-05-27 Thread honghui.zhang
From: Honghui Zhang 

Mediatek SoC's M4U has two generations of HW architcture. Generation one
uses flat, one layer pagetable, and was shipped with ARM architecture, it
only supports 4K size page mapping. MT2701 SoC uses this generation one
m4u HW. Generation two uses the ARM short-descriptor translation table
format for address translation, and was shipped with ARM64 architecture,
MT8173 uses this generation two m4u HW. All the two generation iommu HW
only have one iommu domain, and all its iommu clients share the same
iova address.

These two generation m4u HW have slit different register groups and
register offset, but most register names are the same. This patch add iommu
support for mediatek SoC mt2701.

Signed-off-by: Honghui Zhang 
---
 drivers/iommu/Kconfig|  18 ++
 drivers/iommu/Makefile   |   1 +
 drivers/iommu/mtk_iommu_v1.c | 728 +++
 3 files changed, 747 insertions(+)
 create mode 100644 drivers/iommu/mtk_iommu_v1.c

diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
index dd1dc39..363c1d8 100644
--- a/drivers/iommu/Kconfig
+++ b/drivers/iommu/Kconfig
@@ -354,4 +354,22 @@ config MTK_IOMMU
 
  If unsure, say N here.
 
+config MTK_IOMMU_V1
+   bool "MTK IOMMU Version 1 (M4U gen1) Support"
+   depends on ARM
+   depends on ARCH_MEDIATEK || COMPILE_TEST
+   select ARM_DMA_USE_IOMMU
+   select IOMMU_API
+   select MEMORY
+   select MTK_SMI
+   select COMMON_CLK_MT2701_MMSYS
+   select COMMON_CLK_MT2701_IMGSYS
+   select COMMON_CLK_MT2701_VDECSYS
+   help
+ Support for the M4U on certain Mediatek SoCs. M4U generation 1 HW is
+ Multimedia Memory Managememt Unit. This option enables remapping of
+ DMA memory accesses for the multimedia subsystem.
+
+ if unsure, say N here.
+
 endif # IOMMU_SUPPORT
diff --git a/drivers/iommu/Makefile b/drivers/iommu/Makefile
index c6edb31..778baf5 100644
--- a/drivers/iommu/Makefile
+++ b/drivers/iommu/Makefile
@@ -18,6 +18,7 @@ obj-$(CONFIG_INTEL_IOMMU_SVM) += intel-svm.o
 obj-$(CONFIG_IPMMU_VMSA) += ipmmu-vmsa.o
 obj-$(CONFIG_IRQ_REMAP) += intel_irq_remapping.o irq_remapping.o
 obj-$(CONFIG_MTK_IOMMU) += mtk_iommu.o
+obj-$(CONFIG_MTK_IOMMU_V1) += mtk_iommu_v1.o
 obj-$(CONFIG_OMAP_IOMMU) += omap-iommu.o
 obj-$(CONFIG_OMAP_IOMMU_DEBUG) += omap-iommu-debug.o
 obj-$(CONFIG_ROCKCHIP_IOMMU) += rockchip-iommu.o
diff --git a/drivers/iommu/mtk_iommu_v1.c b/drivers/iommu/mtk_iommu_v1.c
new file mode 100644
index 000..a2a2554
--- /dev/null
+++ b/drivers/iommu/mtk_iommu_v1.c
@@ -0,0 +1,728 @@
+/*
+ * Copyright (c) 2015-2016 MediaTek Inc.
+ * Author: Honghui Zhang 
+ *
+ * Based on driver/iommu/mtk_iommu.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include "mtk_iommu.h"
+
+#define REG_MMU_PT_BASE_ADDR   0x000
+
+#define F_ALL_INVLD0x2
+#define F_MMU_INV_RANGE0x1
+#define F_INVLD_EN0BIT(0)
+#define F_INVLD_EN1BIT(1)
+
+#define F_MMU_FAULT_VA_MSK 0xf000
+#define MTK_PROTECT_PA_ALIGN   128
+
+#define REG_MMU_CTRL_REG   0x210
+#define F_MMU_CTRL_COHERENT_EN BIT(8)
+#define REG_MMU_IVRP_PADDR 0x214
+#define REG_MMU_INT_CONTROL0x220
+#define F_INT_TRANSLATION_FAULTBIT(0)
+#define F_INT_MAIN_MULTI_HIT_FAULT BIT(1)
+#define F_INT_INVALID_PA_FAULT BIT(2)
+#define F_INT_ENTRY_REPLACEMENT_FAULT  BIT(3)
+#define F_INT_TABLE_WALK_FAULT BIT(4)
+#define F_INT_TLB_MISS_FAULT   BIT(5)
+#define F_INT_PFH_DMA_FIFO_OVERFLOWBIT(6)
+#define F_INT_MISS_DMA_FIFO_OVERFLOW   BIT(7)
+
+#define F_MMU_TF_PROTECT_SEL(prot) (((prot) & 0x3) << 5)
+#define F_INT_CLR_BIT  BIT(12)
+
+#define REG_MMU_FAULT_ST   0x224
+#define REG_MMU_FAULT_VA   0x228
+#define REG_MMU_INVLD_PA   0x22C
+#define REG_MMU_INT_ID 0x388
+#define REG_MMU_INVALIDATE 0x5c0
+#define REG_MMU_INVLD_START_A  0x5c4
+#defi

[PATCH v3 0/5] MT2701 iommu support

2016-05-27 Thread honghui.zhang
From: Honghui Zhang 

  Mediatek's m4u(Multimedia Memory Management Unit) and SMI(Smart
Multimedia Interface)have two generations HW. They basically sharing the
same hardware block diagram, but have some difference as below:

  Generation one m4u only supports one layer, flat pagetable addressing,
and only supports 4K size page mapping. While generation two m4u supports 2
levels of pagetable which uses the ARM short-descriptor translation table
format for address translation.
They have slight different register base and register offset.
They have very different HW ports defines.

  Generaion one SMI has additional "async" clock which transform the smi
clock into emi clock domain, this clock should be prepared and enabled for
SMI generation one HW.
The register which control the iommu need to translation the address or not
for a particular port is located at smi ao base(smi always on register
base) for generation one SMI HW, but located at each larb's register base
for generation two HW.

This patch set add mt2701 iommu support, it's based on 4.6-rc1 and James
Liao's "Add clock support for Mediatek MT2701 v8[1]" and "Mediatek MT2701
SCPSYS power domain support v7[2]" patch.

v3:
-Rebase on "of: Implement iterator for phandles[3]" and take use of
 of_for_each_phandle.
-Forward-declare mtk_iommu_domain and implement the struct separately.
-Free the pagetable memory in mtk_iommu_domain_free
-Roll back the mapping in error case.
-Minor cleanups.

v2: https://lists.linuxfoundation.org/pipermail/iommu/2016-May/017068.html
-Fix syntax errors in dt-bindings.
-Use dma_alloc/free_coherent to allocate pagetable memory and reduce the
 streaming DMA stuff.
-Make the mtk_iommu_ops.pgsize_bitmap as ~0UL << MT2701_IOMMU_PAGE_SHIFT.
-Use macro instead of variable to indicate the pagetable size.
-Change some macro name from MTK_XXX to MT2701_XXX.

v1: http://lists.infradead.org/pipermail/linux-mediatek/2016-May/005301.html
-initial version

[1] http://lists.infradead.org/pipermail/linux-mediatek/2016-May/005439.html
[2] http://lists.infradead.org/pipermail/linux-mediatek/2016-May/005429.html
[3] https://lists.linuxfoundation.org/pipermail/iommu/2016-April/016300.html

Honghui Zhang (5):
  dt-bindings: mediatek: add descriptions for mediatek mt2701 iommu and
smi
  iommu/mediatek: move the common struct into header file
  memory/mediatek: add support for mt2701
  iommu/mediatek: add support for mtk iommu generation one HW
  ARM: dts: mt2701: add iommu/smi dtsi node for mt2701

 .../devicetree/bindings/iommu/mediatek,iommu.txt   |  13 +-
 .../memory-controllers/mediatek,smi-common.txt |  21 +-
 .../memory-controllers/mediatek,smi-larb.txt   |   4 +-
 arch/arm/boot/dts/mt2701.dtsi  |  51 ++
 drivers/iommu/Kconfig  |  18 +
 drivers/iommu/Makefile |   1 +
 drivers/iommu/mtk_iommu.c  |  48 +-
 drivers/iommu/mtk_iommu.h  |  77 +++
 drivers/iommu/mtk_iommu_v1.c   | 728 +
 drivers/memory/mtk-smi.c   | 168 -
 include/dt-bindings/memory/mt2701-larb-port.h  |  85 +++
 11 files changed, 1140 insertions(+), 74 deletions(-)
 create mode 100644 drivers/iommu/mtk_iommu.h
 create mode 100644 drivers/iommu/mtk_iommu_v1.c
 create mode 100644 include/dt-bindings/memory/mt2701-larb-port.h

-- 
1.8.1.1.dirty



[PATCH v3 1/5] dt-bindings: mediatek: add descriptions for mediatek mt2701 iommu and smi

2016-05-27 Thread honghui.zhang
From: Honghui Zhang 

This patch defines the local arbitor port IDs for mediatek SoC MT2701 and
add descriptions of binding for mediatek generation one iommu and smi.

Signed-off-by: Honghui Zhang 
Acked-by: Rob Herring 
---
 .../devicetree/bindings/iommu/mediatek,iommu.txt   | 13 +++-
 .../memory-controllers/mediatek,smi-common.txt | 21 +-
 .../memory-controllers/mediatek,smi-larb.txt   |  4 +-
 include/dt-bindings/memory/mt2701-larb-port.h  | 85 ++
 4 files changed, 115 insertions(+), 8 deletions(-)
 create mode 100644 include/dt-bindings/memory/mt2701-larb-port.h

diff --git a/Documentation/devicetree/bindings/iommu/mediatek,iommu.txt 
b/Documentation/devicetree/bindings/iommu/mediatek,iommu.txt
index cd1b1cd..53c20ca 100644
--- a/Documentation/devicetree/bindings/iommu/mediatek,iommu.txt
+++ b/Documentation/devicetree/bindings/iommu/mediatek,iommu.txt
@@ -1,7 +1,9 @@
 * Mediatek IOMMU Architecture Implementation
 
-  Some Mediatek SOCs contain a Multimedia Memory Management Unit (M4U) which
-uses the ARM Short-Descriptor translation table format for address translation.
+  Some Mediatek SOCs contain a Multimedia Memory Management Unit (M4U), and
+this M4U have two generations of HW architecture. Generation one uses flat
+pagetable, and only supports 4K size page mapping. Generation two uses the
+ARM Short-Descriptor translation table format for address translation.
 
   About the M4U Hardware Block Diagram, please check below:
 
@@ -36,7 +38,9 @@ in each larb. Take a example, There are many ports like MC, 
PP, VLD in the
 video decode local arbiter, all these ports are according to the video HW.
 
 Required properties:
-- compatible : must be "mediatek,mt8173-m4u".
+- compatible : must be one of the following string:
+   "mediatek,mt2701-m4u" for mt2701 which uses generation one m4u HW.
+   "mediatek,mt8173-m4u" for mt8173 which uses generation two m4u HW.
 - reg : m4u register base and size.
 - interrupts : the interrupt of m4u.
 - clocks : must contain one entry for each clock-names.
@@ -46,7 +50,8 @@ Required properties:
according to the local arbiter index, like larb0, larb1, larb2...
 - iommu-cells : must be 1. This is the mtk_m4u_id according to the HW.
Specifies the mtk_m4u_id as defined in
-   dt-binding/memory/mt8173-larb-port.h.
+   dt-binding/memory/mt2701-larb-port.h for mt2701 and
+   dt-binding/memory/mt8173-larb-port.h for mt8173
 
 Example:
iommu: iommu@10205000 {
diff --git 
a/Documentation/devicetree/bindings/memory-controllers/mediatek,smi-common.txt 
b/Documentation/devicetree/bindings/memory-controllers/mediatek,smi-common.txt
index 06a83ce..aa614b2 100644
--- 
a/Documentation/devicetree/bindings/memory-controllers/mediatek,smi-common.txt
+++ 
b/Documentation/devicetree/bindings/memory-controllers/mediatek,smi-common.txt
@@ -2,16 +2,31 @@ SMI (Smart Multimedia Interface) Common
 
 The hardware block diagram please check bindings/iommu/mediatek,iommu.txt
 
+Mediatek SMI have two generations of HW architecture, mt8173 uses the second
+generation of SMI HW while mt2701 uses the first generation HW of SMI.
+
+There's slight differences between the two SMI, for generation 2, the
+register which control the iommu port is at each larb's register base. But
+for generation 1, the register is at smi ao base(smi always on register
+base). Besides that, the smi async clock should be prepared and enabled for
+SMI generation 1 to transform the smi clock into emi clock domain, but that is
+not needed for SMI generation 2.
+
 Required properties:
-- compatible : must be "mediatek,mt8173-smi-common"
+- compatible : must be one of :
+   "mediatek,mt2701-smi-common"
+   "mediatek,mt8173-smi-common"
 - reg : the register and size of the SMI block.
 - power-domains : a phandle to the power domain of this local arbiter.
 - clocks : Must contain an entry for each entry in clock-names.
-- clock-names : must contain 2 entries, as follows:
+- clock-names : must contain 3 entries for generation 1 smi HW and 2 entries
+  for generation 2 smi HW as follows:
   - "apb" : Advanced Peripheral Bus clock, It's the clock for setting
the register.
   - "smi" : It's the clock for transfer data and command.
-  They may be the same if both source clocks are the same.
+   They may be the same if both source clocks are the same.
+  - "async" : asynchronous clock, it help transform the smi clock into the emi
+ clock domain, this clock is only needed by generation 1 smi HW.
 
 Example:
smi_common: smi@14022000 {
diff --git 
a/Documentation/devicetree/bindings/memory-controllers/mediatek,smi-larb.txt 
b/Documentation/devicetree/bindings/memory-controllers/mediatek,smi-larb.txt
index 55ff3b7..21277a5 100644
--- a/Documentation/devicetree/bindings/memory-controllers/mediatek,smi-larb.txt
+++ b/Documentation/devicetree/bindings/memory-controllers/mediatek,smi-larb.txt
@@ -3,7 +3,9 @@ SMI (Smart Multime

[PATCH v3 2/5] iommu/mediatek: move the common struct into header file

2016-05-27 Thread honghui.zhang
From: Honghui Zhang 

Move the struct defines of mtk iommu into a new header files for
common use.

Signed-off-by: Honghui Zhang 
---
 drivers/iommu/mtk_iommu.c | 48 +
 drivers/iommu/mtk_iommu.h | 77 +++
 2 files changed, 78 insertions(+), 47 deletions(-)
 create mode 100644 drivers/iommu/mtk_iommu.h

diff --git a/drivers/iommu/mtk_iommu.c b/drivers/iommu/mtk_iommu.c
index db74553..f83c9bc 100644
--- a/drivers/iommu/mtk_iommu.c
+++ b/drivers/iommu/mtk_iommu.c
@@ -34,7 +34,7 @@
 #include 
 #include 
 
-#include "io-pgtable.h"
+#include "mtk_iommu.h"
 
 #define REG_MMU_PT_BASE_ADDR   0x000
 
@@ -93,20 +93,6 @@
 
 #define MTK_PROTECT_PA_ALIGN   128
 
-struct mtk_iommu_suspend_reg {
-   u32 standard_axi_mode;
-   u32 dcm_dis;
-   u32 ctrl_reg;
-   u32 int_control0;
-   u32 int_main_control;
-};
-
-struct mtk_iommu_client_priv {
-   struct list_headclient;
-   unsigned intmtk_m4u_id;
-   struct device   *m4udev;
-};
-
 struct mtk_iommu_domain {
spinlock_t  pgtlock; /* lock for page table */
 
@@ -116,19 +102,6 @@ struct mtk_iommu_domain {
struct iommu_domain domain;
 };
 
-struct mtk_iommu_data {
-   void __iomem*base;
-   int irq;
-   struct device   *dev;
-   struct clk  *bclk;
-   phys_addr_t protect_base; /* protect memory base */
-   struct mtk_iommu_suspend_regreg;
-   struct mtk_iommu_domain *m4u_dom;
-   struct iommu_group  *m4u_group;
-   struct mtk_smi_iommusmi_imu;  /* SMI larb iommu info */
-   boolenable_4GB;
-};
-
 static struct iommu_ops mtk_iommu_ops;
 
 static struct mtk_iommu_domain *to_mtk_domain(struct iommu_domain *dom)
@@ -552,25 +525,6 @@ static int mtk_iommu_hw_init(const struct mtk_iommu_data 
*data)
return 0;
 }
 
-static int compare_of(struct device *dev, void *data)
-{
-   return dev->of_node == data;
-}
-
-static int mtk_iommu_bind(struct device *dev)
-{
-   struct mtk_iommu_data *data = dev_get_drvdata(dev);
-
-   return component_bind_all(dev, &data->smi_imu);
-}
-
-static void mtk_iommu_unbind(struct device *dev)
-{
-   struct mtk_iommu_data *data = dev_get_drvdata(dev);
-
-   component_unbind_all(dev, &data->smi_imu);
-}
-
 static const struct component_master_ops mtk_iommu_com_ops = {
.bind   = mtk_iommu_bind,
.unbind = mtk_iommu_unbind,
diff --git a/drivers/iommu/mtk_iommu.h b/drivers/iommu/mtk_iommu.h
new file mode 100644
index 000..9ed0a84
--- /dev/null
+++ b/drivers/iommu/mtk_iommu.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2015-2016 MediaTek Inc.
+ * Author: Honghui Zhang 
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _MTK_IOMMU_H_
+#define _MTK_IOMMU_H_
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "io-pgtable.h"
+
+struct mtk_iommu_suspend_reg {
+   u32 standard_axi_mode;
+   u32 dcm_dis;
+   u32 ctrl_reg;
+   u32 int_control0;
+   u32 int_main_control;
+};
+
+struct mtk_iommu_client_priv {
+   struct list_headclient;
+   unsigned intmtk_m4u_id;
+   struct device   *m4udev;
+};
+
+struct mtk_iommu_domain;
+
+struct mtk_iommu_data {
+   void __iomem*base;
+   int irq;
+   struct device   *dev;
+   struct clk  *bclk;
+   phys_addr_t protect_base; /* protect memory base */
+   struct mtk_iommu_suspend_regreg;
+   struct mtk_iommu_domain *m4u_dom;
+   struct iommu_group  *m4u_group;
+   struct mtk_smi_iommusmi_imu;  /* SMI larb iommu info */
+   boolenable_4GB;
+};
+
+static int compare_of(struct device *dev, void *data)
+{
+   return dev->of_node == data;
+}
+
+static int mtk_iommu_bind(struct device *dev)
+{
+   struct mtk_iommu_data *

[PATCH] arm64: dts: mt2712: Remove un-used property for PCIe

2019-03-18 Thread honghui.zhang
From: Honghui Zhang 

The "num-lanes" property for PCIe is not used, remove it.

Signed-off-by: Honghui Zhang 
---
 arch/arm64/boot/dts/mediatek/mt2712e.dtsi | 2 --
 1 file changed, 2 deletions(-)

diff --git a/arch/arm64/boot/dts/mediatek/mt2712e.dtsi 
b/arch/arm64/boot/dts/mediatek/mt2712e.dtsi
index 976d92a..43307ba 100644
--- a/arch/arm64/boot/dts/mediatek/mt2712e.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt2712e.dtsi
@@ -819,7 +819,6 @@
#size-cells = <2>;
#interrupt-cells = <1>;
ranges;
-   num-lanes = <1>;
interrupt-map-mask = <0 0 0 7>;
interrupt-map = <0 0 0 1 &pcie_intc0 0>,
<0 0 0 2 &pcie_intc0 1>,
@@ -840,7 +839,6 @@
#size-cells = <2>;
#interrupt-cells = <1>;
ranges;
-   num-lanes = <1>;
interrupt-map-mask = <0 0 0 7>;
interrupt-map = <0 0 0 1 &pcie_intc1 0>,
<0 0 0 2 &pcie_intc1 1>,
-- 
2.6.4



[RFC PATCH v2] PCI/portdrv: Support for subtractive decode bridge

2019-02-13 Thread honghui.zhang
From: Honghui Zhang 

The Class Code for subtractive decode PCI-to-PCI bridge is 060401h,
add one entry to make portdrv support this type bridge.

Signed-off-by: Honghui Zhang 
---
 drivers/pci/pcie/portdrv_pci.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/pci/pcie/portdrv_pci.c b/drivers/pci/pcie/portdrv_pci.c
index 0acca35..c129f2f 100644
--- a/drivers/pci/pcie/portdrv_pci.c
+++ b/drivers/pci/pcie/portdrv_pci.c
@@ -185,6 +185,8 @@ static void pcie_portdrv_err_resume(struct pci_dev *dev)
 static const struct pci_device_id port_pci_ids[] = { {
/* handle any PCI-Express port */
PCI_DEVICE_CLASS(((PCI_CLASS_BRIDGE_PCI << 8) | 0x00), ~0),
+   /* subtractive decode PCI-to-PCI bridge, class type is 060401h */
+   PCI_DEVICE_CLASS(((PCI_CLASS_BRIDGE_PCI << 8) | 0x01), ~0),
}, { /* end: all zeroes */ }
 };
 
-- 
2.6.4



  1   2   >