Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCHv2 08/16] ARM: OMAP3: remove deprecated CONFIG_OMAP_IOMMU_IVA2
From: Suman Anna @ 2014-02-13 18:15 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1392315347-32967-1-git-send-email-s-anna@ti.com>

From: Florian Vaussard <florian.vaussard@epfl.ch>

CONFIG_OMAP_IOMMU_IVA2 was defined originally to avoid conflicting
usage by tidspbridge and other iommu users. The same can be achieved
by marking the DT node disabled, so remove this obsolete flag and
the corresponding hwmod data can be enabled.

Cc: Paul Walmsley <paul@pwsan.com>
Signed-off-by: Florian Vaussard <florian.vaussard@epfl.ch>
[s-anna at ti.com: revise commit log]
Signed-off-by: Suman Anna <s-anna@ti.com>
---
 arch/arm/mach-omap2/omap_hwmod_3xxx_data.c | 8 --------
 arch/arm/plat-omap/Kconfig                 | 3 ---
 2 files changed, 11 deletions(-)

diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
index 4c3b1e6..81dd071 100644
--- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
@@ -3029,8 +3029,6 @@ static struct omap_hwmod omap3xxx_mmu_isp_hwmod = {
 	.flags		= HWMOD_NO_IDLEST,
 };
 
-#ifdef CONFIG_OMAP_IOMMU_IVA2
-
 /* mmu iva */
 
 static struct omap_mmu_dev_attr mmu_iva_dev_attr = {
@@ -3082,8 +3080,6 @@ static struct omap_hwmod omap3xxx_mmu_iva_hwmod = {
 	.flags		= HWMOD_NO_IDLEST,
 };
 
-#endif
-
 /* l4_per -> gpio4 */
 static struct omap_hwmod_addr_space omap3xxx_gpio4_addrs[] = {
 	{
@@ -3855,9 +3851,7 @@ static struct omap_hwmod_ocp_if *omap34xx_hwmod_ocp_ifs[] __initdata = {
 	&omap3xxx_l4_core__hdq1w,
 	&omap3xxx_sad2d__l3,
 	&omap3xxx_l4_core__mmu_isp,
-#ifdef CONFIG_OMAP_IOMMU_IVA2
 	&omap3xxx_l3_main__mmu_iva,
-#endif
 	&omap34xx_l4_core__ssi,
 	NULL
 };
@@ -3881,9 +3875,7 @@ static struct omap_hwmod_ocp_if *omap36xx_hwmod_ocp_ifs[] __initdata = {
 	&omap3xxx_l4_core__hdq1w,
 	&omap3xxx_sad2d__l3,
 	&omap3xxx_l4_core__mmu_isp,
-#ifdef CONFIG_OMAP_IOMMU_IVA2
 	&omap3xxx_l3_main__mmu_iva,
-#endif
 	NULL
 };
 
diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig
index 436ea97..02fc10d 100644
--- a/arch/arm/plat-omap/Kconfig
+++ b/arch/arm/plat-omap/Kconfig
@@ -86,9 +86,6 @@ config OMAP_MUX_WARNINGS
 	  to change the pin multiplexing setup.	 When there are no warnings
 	  printed, it's safe to deselect OMAP_MUX for your product.
 
-config OMAP_IOMMU_IVA2
-	bool
-
 config OMAP_MPU_TIMER
 	bool "Use mpu timer"
 	depends on ARCH_OMAP1
-- 
1.8.5.3

^ permalink raw reply related

* [PATCHv2 07/16] iommu/omap: allow enable/disable even without pdata
From: Suman Anna @ 2014-02-13 18:15 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1392315347-32967-1-git-send-email-s-anna@ti.com>

From: Florian Vaussard <florian.vaussard@epfl.ch>

When booting with a devicetree, no platform data is provided.
Do not prematurely exit iommu_enable() and iommu_disable() in
such a case.

Note: As OMAP do not yet has a proper reset controller driver,
IOMMUs requiring a reset signal should use pdata-quirks as a
transitional solution.

Signed-off-by: Florian Vaussard <florian.vaussard@epfl.ch>
---
 drivers/iommu/omap-iommu.c | 10 ++--------
 1 file changed, 2 insertions(+), 8 deletions(-)

diff --git a/drivers/iommu/omap-iommu.c b/drivers/iommu/omap-iommu.c
index f6afe8f..7672eb4 100644
--- a/drivers/iommu/omap-iommu.c
+++ b/drivers/iommu/omap-iommu.c
@@ -149,13 +149,10 @@ static int iommu_enable(struct omap_iommu *obj)
 	struct platform_device *pdev = to_platform_device(obj->dev);
 	struct iommu_platform_data *pdata = pdev->dev.platform_data;
 
-	if (!pdata)
-		return -EINVAL;
-
 	if (!arch_iommu)
 		return -ENODEV;
 
-	if (pdata->deassert_reset) {
+	if (pdata && pdata->deassert_reset) {
 		err = pdata->deassert_reset(pdev, pdata->reset_name);
 		if (err) {
 			dev_err(obj->dev, "deassert_reset failed: %d\n", err);
@@ -175,14 +172,11 @@ static void iommu_disable(struct omap_iommu *obj)
 	struct platform_device *pdev = to_platform_device(obj->dev);
 	struct iommu_platform_data *pdata = pdev->dev.platform_data;
 
-	if (!pdata)
-		return;
-
 	arch_iommu->disable(obj);
 
 	pm_runtime_put_sync(obj->dev);
 
-	if (pdata->assert_reset)
+	if (pdata && pdata->assert_reset)
 		pdata->assert_reset(pdev, pdata->reset_name);
 }
 
-- 
1.8.5.3

^ permalink raw reply related

* [PATCHv2 06/16] iommu/omap: allocate archdata on the fly for DT-based devices
From: Suman Anna @ 2014-02-13 18:15 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1392315347-32967-1-git-send-email-s-anna@ti.com>

From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

The OMAP IOMMU driver locates the IOMMU associated to a device using the
IOMMU name stored in the device archdata iommu field. That field is
expected to be populated by platform code and is left unset for DT-based
devices. This results in a crash when the IOMMU driver attaches a domain
to a device.

Fix this by allocating the archdata iommu structure when devices are
added and freeing when they are removed. Devices without an OF node, and
devices without an iommus property in their OF node are ignored. The
iommu name is initialized from the IOMMU device node name.

This should be simplified when removing non-DT support completely from
the IOMMU users as the IOMMU name won't be needed anymore, and the
IOMMU device pointer could then be stored in the archdata iommu field
directly.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
[s-anna at ti.com: updated to use device name instead of OF name]
Signed-off-by: Suman Anna <s-anna@ti.com>
---
 drivers/iommu/omap-iommu.c | 45 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 45 insertions(+)

diff --git a/drivers/iommu/omap-iommu.c b/drivers/iommu/omap-iommu.c
index e64025a..f6afe8f 100644
--- a/drivers/iommu/omap-iommu.c
+++ b/drivers/iommu/omap-iommu.c
@@ -1256,6 +1256,49 @@ static int omap_iommu_domain_has_cap(struct iommu_domain *domain,
 	return 0;
 }
 
+static int omap_iommu_add_device(struct device *dev)
+{
+	struct omap_iommu_arch_data *arch_data;
+	struct device_node *np;
+
+	/*
+	 * Allocate the archdata iommu structure for DT-based devices.
+	 *
+	 * TODO: Simplify this when removing non-DT support completely from the
+	 * IOMMU users.
+	 */
+	if (!dev->of_node)
+		return 0;
+
+	np = of_parse_phandle(dev->of_node, "iommus", 0);
+	if (!np)
+		return 0;
+
+	arch_data = kzalloc(sizeof(*arch_data), GFP_KERNEL);
+	if (!arch_data) {
+		of_node_put(np);
+		return -ENOMEM;
+	}
+
+	arch_data->name = kstrdup(dev_name(dev), GFP_KERNEL);
+	dev->archdata.iommu = arch_data;
+
+	of_node_put(np);
+
+	return 0;
+}
+
+static void omap_iommu_remove_device(struct device *dev)
+{
+	struct omap_iommu_arch_data *arch_data = dev->archdata.iommu;
+
+	if (!dev->of_node || !arch_data)
+		return;
+
+	kfree(arch_data->name);
+	kfree(arch_data);
+}
+
 static struct iommu_ops omap_iommu_ops = {
 	.domain_init	= omap_iommu_domain_init,
 	.domain_destroy	= omap_iommu_domain_destroy,
@@ -1265,6 +1308,8 @@ static struct iommu_ops omap_iommu_ops = {
 	.unmap		= omap_iommu_unmap,
 	.iova_to_phys	= omap_iommu_iova_to_phys,
 	.domain_has_cap	= omap_iommu_domain_has_cap,
+	.add_device	= omap_iommu_add_device,
+	.remove_device	= omap_iommu_remove_device,
 	.pgsize_bitmap	= OMAP_IOMMU_PGSIZES,
 };
 
-- 
1.8.5.3

^ permalink raw reply related

* [PATCHv2 05/16] iommu/omap: enable bus-error back on supported iommus
From: Suman Anna @ 2014-02-13 18:15 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1392315347-32967-1-git-send-email-s-anna@ti.com>

The remoteproc MMUs in OMAP4+ SoCs have some additional debug
registers that can give out the PC value in addition to the
MMU fault address. The PC value can be extracted properly only
on the DSP cores, and is not available on the ARM processors
within the IPU sub-systems. Instead, the MMUs have been enhanced
to throw a bus-error response back to the IPU processors.

This functionality is programmable through the MMU_GP_REG register.
The cores are simply stalled if the MMU_GP_REG.BUS_ERR_BACK_EN bit
is not set. When set, a bus-error exception is raised allowing the
processor to handle it as a bus fault and provide additional debug
information. This feature is turned on by default by the driver on
iommus supporting it.

Signed-off-by: Subramaniam Chanderashekarapuram <subramaniam.ca@ti.com>
Signed-off-by: Suman Anna <s-anna@ti.com>
---
 drivers/iommu/omap-iommu.c  | 2 ++
 drivers/iommu/omap-iommu.h  | 5 +++++
 drivers/iommu/omap-iommu2.c | 3 +++
 3 files changed, 10 insertions(+)

diff --git a/drivers/iommu/omap-iommu.c b/drivers/iommu/omap-iommu.c
index 4329ab1..e64025a 100644
--- a/drivers/iommu/omap-iommu.c
+++ b/drivers/iommu/omap-iommu.c
@@ -964,6 +964,8 @@ static int omap_iommu_probe(struct platform_device *pdev)
 		if (err != 0)
 			return err;
 		obj->da_end = obj->da_start + len;
+		if (of_find_property(of, "ti,iommu-bus-err-back", NULL))
+			obj->has_bus_err_back = MMU_GP_REG_BUS_ERR_BACK_EN;
 	} else {
 		obj->nr_tlb_entries = pdata->nr_tlb_entries;
 		obj->name = pdata->name;
diff --git a/drivers/iommu/omap-iommu.h b/drivers/iommu/omap-iommu.h
index 1200842..ea920c3 100644
--- a/drivers/iommu/omap-iommu.h
+++ b/drivers/iommu/omap-iommu.h
@@ -52,6 +52,8 @@ struct omap_iommu {
 	void *ctx; /* iommu context: registres saved area */
 	u32 da_start;
 	u32 da_end;
+
+	int has_bus_err_back;
 };
 
 struct cr_regs {
@@ -130,6 +132,7 @@ static inline struct omap_iommu *dev_to_omap_iommu(struct device *dev)
 #define MMU_READ_CAM		0x68
 #define MMU_READ_RAM		0x6c
 #define MMU_EMU_FAULT_AD	0x70
+#define MMU_GP_REG		0x88
 
 #define MMU_REG_SIZE		256
 
@@ -163,6 +166,8 @@ static inline struct omap_iommu *dev_to_omap_iommu(struct device *dev)
 #define MMU_RAM_MIXED_MASK	(1 << MMU_RAM_MIXED_SHIFT)
 #define MMU_RAM_MIXED		MMU_RAM_MIXED_MASK
 
+#define MMU_GP_REG_BUS_ERR_BACK_EN	0x1
+
 /*
  * utilities for super page(16MB, 1MB, 64KB and 4KB)
  */
diff --git a/drivers/iommu/omap-iommu2.c b/drivers/iommu/omap-iommu2.c
index d745094..5e1ea3b 100644
--- a/drivers/iommu/omap-iommu2.c
+++ b/drivers/iommu/omap-iommu2.c
@@ -98,6 +98,9 @@ static int omap2_iommu_enable(struct omap_iommu *obj)
 
 	iommu_write_reg(obj, pa, MMU_TTB);
 
+	if (obj->has_bus_err_back)
+		iommu_write_reg(obj, MMU_GP_REG_BUS_ERR_BACK_EN, MMU_GP_REG);
+
 	__iommu_set_twl(obj, true);
 
 	return 0;
-- 
1.8.5.3

^ permalink raw reply related

* [PATCHv2 04/16] iommu/omap: add devicetree support
From: Suman Anna @ 2014-02-13 18:15 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1392315347-32967-1-git-send-email-s-anna@ti.com>

From: Florian Vaussard <florian.vaussard@epfl.ch>

As OMAP2+ is moving to a full DT boot for all SoC families, commit
7ce93f3 "ARM: OMAP2+: Fix more missing data for omap3.dtsi file"
adds basic DT bits for OMAP3. But the driver is not yet converted,
so this will not work and driver will not be probed. Convert it!

Signed-off-by: Florian Vaussard <florian.vaussard@epfl.ch>
[s-anna at ti.com: dev_name adaptation and improved error checking]
Signed-off-by: Suman Anna <s-anna@ti.com>
---
 arch/arm/mach-omap2/omap-iommu.c |  5 +++++
 drivers/iommu/omap-iommu.c       | 41 ++++++++++++++++++++++++++++++++++++----
 2 files changed, 42 insertions(+), 4 deletions(-)

diff --git a/arch/arm/mach-omap2/omap-iommu.c b/arch/arm/mach-omap2/omap-iommu.c
index f6daae8..f1fab56 100644
--- a/arch/arm/mach-omap2/omap-iommu.c
+++ b/arch/arm/mach-omap2/omap-iommu.c
@@ -10,6 +10,7 @@
  * published by the Free Software Foundation.
  */
 
+#include <linux/of.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/err.h>
@@ -58,6 +59,10 @@ static int __init omap_iommu_dev_init(struct omap_hwmod *oh, void *unused)
 
 static int __init omap_iommu_init(void)
 {
+	/* If dtb is there, the devices will be created dynamically */
+	if (of_have_populated_dt())
+		return -ENODEV;
+
 	return omap_hwmod_for_each_by_class("mmu", omap_iommu_dev_init, NULL);
 }
 /* must be ready before omap3isp is probed */
diff --git a/drivers/iommu/omap-iommu.c b/drivers/iommu/omap-iommu.c
index 6272c36..4329ab1 100644
--- a/drivers/iommu/omap-iommu.c
+++ b/drivers/iommu/omap-iommu.c
@@ -23,6 +23,9 @@
 #include <linux/spinlock.h>
 #include <linux/io.h>
 #include <linux/pm_runtime.h>
+#include <linux/of.h>
+#include <linux/of_iommu.h>
+#include <linux/of_irq.h>
 
 #include <asm/cacheflush.h>
 
@@ -937,20 +940,41 @@ static int omap_iommu_probe(struct platform_device *pdev)
 {
 	int err = -ENODEV;
 	int irq;
+	size_t len;
 	struct omap_iommu *obj;
 	struct resource *res;
 	struct iommu_platform_data *pdata = pdev->dev.platform_data;
+	struct device_node *of = pdev->dev.of_node;
 
 	obj = devm_kzalloc(&pdev->dev, sizeof(*obj) + MMU_REG_SIZE, GFP_KERNEL);
 	if (!obj)
 		return -ENOMEM;
 
-	obj->nr_tlb_entries = pdata->nr_tlb_entries;
-	obj->name = pdata->name;
+	if (of) {
+		obj->name = dev_name(&pdev->dev);
+		obj->nr_tlb_entries = 32;
+		err = of_property_read_u32(of, "ti,#tlb-entries",
+					   &obj->nr_tlb_entries);
+		if (err && err != -EINVAL)
+			return err;
+		if (obj->nr_tlb_entries != 32 && obj->nr_tlb_entries != 8)
+			return -EINVAL;
+		err = of_get_dma_window(of, NULL, 0, NULL, &obj->da_start,
+					&len);
+		if (err != 0)
+			return err;
+		obj->da_end = obj->da_start + len;
+	} else {
+		obj->nr_tlb_entries = pdata->nr_tlb_entries;
+		obj->name = pdata->name;
+		obj->da_start = pdata->da_start;
+		obj->da_end = pdata->da_end;
+	}
+	if (obj->da_end <= obj->da_start)
+		return -EINVAL;
+
 	obj->dev = &pdev->dev;
 	obj->ctx = (void *)obj + sizeof(*obj);
-	obj->da_start = pdata->da_start;
-	obj->da_end = pdata->da_end;
 
 	spin_lock_init(&obj->iommu_lock);
 	mutex_init(&obj->mmap_lock);
@@ -991,11 +1015,20 @@ static int omap_iommu_remove(struct platform_device *pdev)
 	return 0;
 }
 
+static struct of_device_id omap_iommu_of_match[] = {
+	{ .compatible = "ti,omap2-iommu" },
+	{ .compatible = "ti,omap4-iommu" },
+	{ .compatible = "ti,dra7-iommu"	},
+	{},
+};
+MODULE_DEVICE_TABLE(of, omap_iommu_of_match);
+
 static struct platform_driver omap_iommu_driver = {
 	.probe	= omap_iommu_probe,
 	.remove	= omap_iommu_remove,
 	.driver	= {
 		.name	= "omap-iommu",
+		.of_match_table = of_match_ptr(omap_iommu_of_match),
 	},
 };
 
-- 
1.8.5.3

^ permalink raw reply related

* [PATCHv2 03/16] Documentation: dt: add OMAP iommu bindings
From: Suman Anna @ 2014-02-13 18:15 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1392315347-32967-1-git-send-email-s-anna@ti.com>

From: Florian Vaussard <florian.vaussard@epfl.ch>

This patch adds the iommu bindings for all OMAP2+ SoCs. Apart from
the standard bindings used by OMAP peripherals, this patch uses a
'dma-window' (already used by Tegra SMMU) and adds two OMAP custom
bindings - 'ti,#tlb-entries' and 'ti,iommu-bus-err-back'.

Signed-off-by: Florian Vaussard <florian.vaussard@epfl.ch>
[s-anna at ti.com: split bindings document, add dra7 and bus error back]
Signed-off-by: Suman Anna <s-anna@ti.com>
---
 .../devicetree/bindings/iommu/ti,omap-iommu.txt    | 28 ++++++++++++++++++++++
 1 file changed, 28 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/iommu/ti,omap-iommu.txt

diff --git a/Documentation/devicetree/bindings/iommu/ti,omap-iommu.txt b/Documentation/devicetree/bindings/iommu/ti,omap-iommu.txt
new file mode 100644
index 0000000..116492d
--- /dev/null
+++ b/Documentation/devicetree/bindings/iommu/ti,omap-iommu.txt
@@ -0,0 +1,28 @@
+OMAP2+ IOMMU
+
+Required properties:
+- compatible : Should be one of,
+		"ti,omap2-iommu" for OMAP2/OMAP3 IOMMU instances
+		"ti,omap4-iommu" for OMAP4/OMAP5 IOMMU instances
+		"ti,dra7-iommu" for DRA7xx IOMMU instances
+- ti,hwmods  : Name of the hwmod associated with the IOMMU instance
+- reg        : Address space for the configuration registers
+- interrupts : Interrupt specifier for the IOMMU instance
+- dma-window : IOVA start address and length
+
+Optional properties:
+- ti,#tlb-entries : Number of entries in the translation look-aside buffer.
+                    Should be either 8 or 32 (default: 32)
+- ti,iommu-bus-err-back : Indicates the IOMMU instance supports throwing
+		          back a bus error response on MMU faults.
+
+Example:
+	/* OMAP3 ISP MMU */
+	mmu_isp: mmu at 480bd400 {
+		compatible = "ti,omap2-iommu";
+		reg = <0x480bd400 0x80>;
+		interrupts = <24>;
+		ti,hwmods = "mmu_isp";
+		ti,#tlb-entries = <8>;
+		dma-window = <0 0xfffff000>;
+	};
-- 
1.8.5.3

^ permalink raw reply related

* [PATCHv2 02/16] iommu/omap: omap_iommu_attach() should return ENODEV, not NULL
From: Suman Anna @ 2014-02-13 18:15 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1392315347-32967-1-git-send-email-s-anna@ti.com>

From: Florian Vaussard <florian.vaussard@epfl.ch>

omap_iommu_attach() returns NULL or ERR_PTR in case of error, but
omap_iommu_attach_dev() only checks for IS_ERR. Thus a NULL return value (in
case driver_find_device fails) will cause the kernel to panic when
omap_iommu_attach_dev() dereferences the pointer.

In such case, omap_iommu_attach() should return ENODEV, not NULL.

Signed-off-by: Florian Vaussard <florian.vaussard@epfl.ch>
Acked-by: Suman Anna <s-anna@ti.com>
---
 drivers/iommu/omap-iommu.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/iommu/omap-iommu.c b/drivers/iommu/omap-iommu.c
index fff2ffd..6272c36 100644
--- a/drivers/iommu/omap-iommu.c
+++ b/drivers/iommu/omap-iommu.c
@@ -863,7 +863,7 @@ static int device_match_by_alias(struct device *dev, void *data)
  **/
 static struct omap_iommu *omap_iommu_attach(const char *name, u32 *iopgd)
 {
-	int err = -ENOMEM;
+	int err = -ENODEV;
 	struct device *dev;
 	struct omap_iommu *obj;
 
@@ -871,7 +871,7 @@ static struct omap_iommu *omap_iommu_attach(const char *name, u32 *iopgd)
 				(void *)name,
 				device_match_by_alias);
 	if (!dev)
-		return NULL;
+		return ERR_PTR(err);
 
 	obj = to_iommu(dev);
 
-- 
1.8.5.3

^ permalink raw reply related

* [PATCHv2 01/16] iommu/omap: convert to devm_* interfaces
From: Suman Anna @ 2014-02-13 18:15 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1392315347-32967-1-git-send-email-s-anna@ti.com>

Use the various devm_ interfaces to simplify the cleanup in
probe and remove functions.

Signed-off-by: Florian Vaussard <florian.vaussard@epfl.ch>
Signed-off-by: Suman Anna <s-anna@ti.com>
---
 drivers/iommu/omap-iommu.c | 52 +++++++++-------------------------------------
 1 file changed, 10 insertions(+), 42 deletions(-)

diff --git a/drivers/iommu/omap-iommu.c b/drivers/iommu/omap-iommu.c
index bcd78a7..fff2ffd 100644
--- a/drivers/iommu/omap-iommu.c
+++ b/drivers/iommu/omap-iommu.c
@@ -941,7 +941,7 @@ static int omap_iommu_probe(struct platform_device *pdev)
 	struct resource *res;
 	struct iommu_platform_data *pdata = pdev->dev.platform_data;
 
-	obj = kzalloc(sizeof(*obj) + MMU_REG_SIZE, GFP_KERNEL);
+	obj = devm_kzalloc(&pdev->dev, sizeof(*obj) + MMU_REG_SIZE, GFP_KERNEL);
 	if (!obj)
 		return -ENOMEM;
 
@@ -958,33 +958,18 @@ static int omap_iommu_probe(struct platform_device *pdev)
 	INIT_LIST_HEAD(&obj->mmap);
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!res) {
-		err = -ENODEV;
-		goto err_mem;
-	}
-
-	res = request_mem_region(res->start, resource_size(res),
-				 dev_name(&pdev->dev));
-	if (!res) {
-		err = -EIO;
-		goto err_mem;
-	}
-
-	obj->regbase = ioremap(res->start, resource_size(res));
-	if (!obj->regbase) {
-		err = -ENOMEM;
-		goto err_ioremap;
-	}
+	obj->regbase = devm_ioremap_resource(obj->dev, res);
+	if (IS_ERR(obj->regbase))
+		return PTR_ERR(obj->regbase);
 
 	irq = platform_get_irq(pdev, 0);
-	if (irq < 0) {
-		err = -ENODEV;
-		goto err_irq;
-	}
-	err = request_irq(irq, iommu_fault_handler, IRQF_SHARED,
-			  dev_name(&pdev->dev), obj);
+	if (irq < 0)
+		return -ENODEV;
+
+	err = devm_request_irq(obj->dev, irq, iommu_fault_handler, IRQF_SHARED,
+			       dev_name(obj->dev), obj);
 	if (err < 0)
-		goto err_irq;
+		return err;
 	platform_set_drvdata(pdev, obj);
 
 	pm_runtime_irq_safe(obj->dev);
@@ -992,34 +977,17 @@ static int omap_iommu_probe(struct platform_device *pdev)
 
 	dev_info(&pdev->dev, "%s registered\n", obj->name);
 	return 0;
-
-err_irq:
-	iounmap(obj->regbase);
-err_ioremap:
-	release_mem_region(res->start, resource_size(res));
-err_mem:
-	kfree(obj);
-	return err;
 }
 
 static int omap_iommu_remove(struct platform_device *pdev)
 {
-	int irq;
-	struct resource *res;
 	struct omap_iommu *obj = platform_get_drvdata(pdev);
 
 	iopgtable_clear_entry_all(obj);
 
-	irq = platform_get_irq(pdev, 0);
-	free_irq(irq, obj);
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	release_mem_region(res->start, resource_size(res));
-	iounmap(obj->regbase);
-
 	pm_runtime_disable(obj->dev);
 
 	dev_info(&pdev->dev, "%s removed\n", obj->name);
-	kfree(obj);
 	return 0;
 }
 
-- 
1.8.5.3

^ permalink raw reply related

* [PATCHv2 00/16] OMAP IOMMU DT adaptation and cleanup
From: Suman Anna @ 2014-02-13 18:15 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

This is an updated series to the initial OMAP IOMMU DT driver
adaptation series [1], that primarily dealt with just the OMAP3
ISP MMU. This series is based on 3.14-rc2, and the patches were
developed in collaboration with Florian. I am hoping that the
series can make the 3.15 merge window.

This series updates the bindings for IOMMUs for all OMAP2+ SoCs
(OMAP3, OMAP4, OMAP5, DRA7), and includes new patches for adding
the support to iommus on OMAP4 and OMAP5, and IVA IOMMU on OMAP3.
The DT bindings and adaptation is done mainly in patches 3 and 4.
The differences between IOMMUs between different OMAP generations
is explained in the previous posting [1], and the differentiation
is achieved through two optional properties keeping the compatible
strings to a minimum. This could also have been achieved through
driver match data with a compatible string per sub-system, so do
let me know if that should be the preferred approach.

All the MMUs other than the OMAP3 ISP leverage omap_device reset
functions, performed through platform data ops previously. With
the removal of the legacy mode, the same functionality is achieved
for DT nodes through pdata quirks until a TI PRCM reset driver is
available.

The first 7 patches in the series are in drivers/iommu, with all the
remaining patches in the arch/arm/mach-omap2 layer.

Tony,
The last 3 patches are cleanup of the legacy mode, so IOMMU devices
cannot be instantiated after these patches. Please let me know if
legacy mode on OMAP3 needs to be supported for 3.15, in which case,
the last 3 can be dropped for now and I would have to revise the OMAP3
ISP archdata change (Patch 9) to support both legacy and DT boots.
At present, I have made the change to support OMAP3 ISP with DT-boot
only.

Detailed changes in v2:
- Cleanup of driver probe/release to use devm_ interfaces (Patch 1)
- The DT bindings are split into a separate patch, and updated based
  on discussion on v1 [1] (Patch 3)
- Updated DT adaptation patch with improved error checking, and
  support for DRA7 compatible IOMMUs in the driver (Patch 4)
- Added support for throwing a bus error response back to the processor
  cores on MMUs associated with IPUs (Patch 5)
- Added preliminary support to DT-based IOMMU users (Patch 6)
- Added preparatory patches to enable and use the hwmod for IVA MMU
  on OMAP3 (Patches 8 and 11)
- Adapt the OMAP3 ISP archdata to support DT boot (Patch 9). Legacy
  mode will not work after this patch, and this will be cleaned up
  anyway once OMAP3ISP is converted to a DT node.
- Reset functionality enablement with DT-boots using pdata quirks
  for OMAP3 IVA, OMAP4 and OMAP5 DSP & IPU MMUs (Patches 10, 13)
- Added the basic hwmod data for OMAP5 iommus (Patch 12)
- Clean up the iommu hwmod data and remove the legacy file for creating
  IOMMU devices (Patches 14, 15, 16).
- Dropped the "iommu/omap: Do bus_set_iommu() only if probe() succeeds"
  patch from previous series.
- Dropped the OMAP3 ISP MMU DTS patch (posting separately).

I have validated the functionality of all the different IOMMUs on
OMAP3, OMAP4 and OMAP5. Florian has verified the OMAP3 ISP usage as
well. The full branch including the DTS patches is here for reference, 
https://github.com/sumananna/omap-kernel/commits/iommu/3.14-rc2-dt-support-v2

v1:
- Couple of cleanup and initial DT adaptation for OMAP3 ISP.
http://marc.info/?l=linux-omap&m=138728485600624&w=2

[1] http://marc.info/?l=linux-omap&m=138782819732435&w=2


Florian Vaussard (8):
  iommu/omap: omap_iommu_attach() should return ENODEV, not NULL
  Documentation: dt: add OMAP iommu bindings
  iommu/omap: add devicetree support
  iommu/omap: allow enable/disable even without pdata
  ARM: OMAP3: remove deprecated CONFIG_OMAP_IOMMU_IVA2
  ARM: OMAP3: hwmod data: cleanup data for IOMMUs
  ARM: OMAP4: hwmod data: cleanup data for IOMMUs
  ARM: OMAP2+: Remove legacy omap-iommu.c

Laurent Pinchart (1):
  iommu/omap: allocate archdata on the fly for DT-based devices

Suman Anna (7):
  iommu/omap: convert to devm_* interfaces
  iommu/omap: enable bus-error back on supported iommus
  ARM: OMAP2+: change the ISP device archdata MMU name
  ARM: OMAP2+: use pdata quirks for iommu reset lines
  ARM: OMAP3: fix iva mmu programming issues
  ARM: OMAP5: hwmod data: add mmu data for ipu & dsp
  ARM: OMAP2+: extend iommu pdata-quirks to OMAP5

 .../devicetree/bindings/iommu/ti,omap-iommu.txt    |  28 ++++
 arch/arm/mach-omap2/Makefile                       |   3 -
 arch/arm/mach-omap2/clockdomains3xxx_data.c        |   2 +-
 arch/arm/mach-omap2/devices.c                      |   2 +-
 arch/arm/mach-omap2/omap-iommu.c                   |  74 ----------
 arch/arm/mach-omap2/omap_hwmod_3xxx_data.c         |  58 +-------
 arch/arm/mach-omap2/omap_hwmod_44xx_data.c         |  35 -----
 arch/arm/mach-omap2/omap_hwmod_54xx_data.c         |  83 +++++++++++
 arch/arm/mach-omap2/pdata-quirks.c                 |  24 ++++
 arch/arm/plat-omap/Kconfig                         |   3 -
 drivers/iommu/omap-iommu.c                         | 154 +++++++++++++--------
 drivers/iommu/omap-iommu.h                         |   5 +
 drivers/iommu/omap-iommu2.c                        |   3 +
 13 files changed, 247 insertions(+), 227 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/iommu/ti,omap-iommu.txt
 delete mode 100644 arch/arm/mach-omap2/omap-iommu.c

-- 
1.8.5.3

^ permalink raw reply

* [PATCH v2 3/3] PCI: ARM: add support for generic PCI host controller
From: Mark Rutland @ 2014-02-13 18:11 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <4110788.UI9TADVhpa@wuerfel>

[adding devicetree, Grant, Rob]

Apologies to all those who aren't too bothered about the naming, I'm
going to derail this subthread for a general device tree policy
discussion.

On Thu, Feb 13, 2014 at 04:28:20PM +0000, Arnd Bergmann wrote:
> On Thursday 13 February 2014 10:22:25 Kumar Gala wrote:
> > On Feb 13, 2014, at 5:07 AM, Will Deacon <will.deacon@arm.com> wrote:
> > > Happy to change it, but I'm also struggling for names. Maybe "linux,?"?
> >
> > I was thinking that as well, I?d say go with ?linux,?.
> 
> I see nothing linux specific in there. I would only use that namespace
> for things we don't expect to work with another OS.

Let's take a stop back. This is an instance of a wider problem, and to
be honest it's a rather trivial one. As usual, because there's been no
policy there's no consistency, and everyone's got their own favourite.

All we need is a policy for how generic bindings are named/prefixed. As
long as this is consistent and unlikely to cause problems it doesn't
really matter what that specific policy is.

Regardless, we need to support our existing bindings.

So far we have instances of (in v3.14-rc2):

A) No prefix

  $ git grep 'compatible\s*=\s*"[^,]*"' -- Documentation/devicetree | \
    awk '{ print $NF }' | sort -u | wc -l
    96

  $ git grep 'compatible\s*=\s*"[^,]*"' -- arch/*/boot/dts | \
    awk ' { print $NF }' | sort -u | wc -l
    233

  These include some commonly use bindings like "fixed-clock",
  "regulator-fixed", and (everybody's favourite) "simple-bus". The
  "ns16550" binding falls here too.
 
  There are subdivisions within this, like "simple-*" and "*-generic".
  There are three "simple-" prefixed variants, perhaps that's worth it's
  own class?
 
  There are also some dubious ones like "ldo4" that are probably only
  appearing in sub-nodes and probably don't matter that much for this
  discussion.


B) "linux," prefixed

  $ git grep 'compatible\s*=\s*"linux,.*"' -- Documentation/devicetree | \
    awk ' { print $NF }' | sort -u | wc -l
    4

  $ git grep 'compatible\s*=\s*"linux,.*"' -- arch/*/boot/dts | \
    awk ' {print $NF }' | sort -u | wc -l
    1

  These include:
  * "linux,hdmi-audio"
  * "linux,spdif-dir"
  * "linux,spdif-dit"
  * "linux,wdt-gpio"

Is there another class I've missed?

If a binding originates for Linux, a "linux," prefix doesn't seem that
bad to me. It's just a namespace, it doesn't have to mean that it's only
ever going to work for Linux, and two such bindings within Linux
shouldn't be able to collide.

As long as we choose something that reduces the possibility of name
collisions (several people might come up with incompatible "pci"
bindings) then we're fine regardless of the particular prefix or lack
thereof. A "generic," prefix feels like it's too easy to collide with if
another community also creates bindings.

Thoughts?

One final option for generic bindings would be a prefix per-author (e.g.
in this case the compatible string could be "will-deacon,pci"). That
might lead to the fewest namespace issues in future, and helps to
immortalise/demonise the original author of any binding claiming to be
generic. Patch below.

Thanks,
Mark.

---->8----
>From 6ed3e3564199ed6dbd8782a740d4067fb1e6d3b6 Mon Sep 17 00:00:00 2001
From: Mark Rutland <mark.rutland@arm.com>
Date: Thu, 13 Feb 2014 17:50:33 +0000
Subject: [PATCH] Documentation: devicetree: add vendor prefix for Will Deacon

This patch adds a vendor prefix for Will Deacon, for use in generic
hardware bindings originating from Will Deacon.

Signed-off-by: Mark Rutland <mark.rutland@arm.com>
---
 Documentation/devicetree/bindings/vendor-prefixes.txt | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index 3f900cd..b945e74 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -88,6 +88,7 @@ toumaz	Toumaz
 v3	V3 Semiconductor
 via	VIA Technologies, Inc.
 winbond Winbond Electronics corp.
+will-deacon	Will Deacon MEng
 wlf	Wolfson Microelectronics
 wm	Wondermedia Technologies, Inc.
 xlnx	Xilinx
-- 
1.8.1.1

^ permalink raw reply related

* [PATCH] Fix uses of dma_max_pfn() when converting to a limiting address
From: James Bottomley @ 2014-02-13 18:07 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20140213171117.GA30257@n2100.arm.linux.org.uk>

On Thu, 2014-02-13 at 17:11 +0000, Russell King - ARM Linux wrote:
> On Thu, Feb 13, 2014 at 08:58:10AM -0800, James Bottomley wrote:
> > This doesn't really look like the right fix.  You replaced dev->dma_mask
> > with a calculation on dev_max_pfn().  Since dev->dma_mask is always u64
> > and dev_max_pfn is supposed to be returning the pfn of the dma_mask, it
> > should unconditionally be 64 bits as well.  Either that or it should
> > return dma_addr_t.
> 
> My reasoning is that PFNs in the system are always of type "unsigned long"
> and therefore a function returning a pfn should have that type.  If we
> overflow a PFN fitting in an unsigned long, we have lots of places which
> need fixing.

It's not intuitive to people who need the dma mask that they're supposed
to use dma_max_pfn() << PAGE_SHIFT but now they have to worry about the
casting and, if they don't get it right, nothing will warn or tell them.
what about a new macro, say dma_max_mask(dev) that just returns
(u64)dma_max_pfn() << PAGE_SHIFT?

James

^ permalink raw reply

* [PATCH v2 3/3] PCI: ARM: add support for generic PCI host controller
From: Jason Gunthorpe @ 2014-02-13 18:06 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20140213110721.GC13576@mudshark.cambridge.arm.com>

On Thu, Feb 13, 2014 at 11:07:21AM +0000, Will Deacon wrote:

> Not in this case! kvmtool generates the following:

Well, the example is nice so someone can review it..
 
> 	pci {
> 		#address-cells = <0x3>;
> 		#size-cells = <0x2>;
> 		#interrupt-cells = <0x1>;
> 		compatible = "arm,pci-cam-generic";
> 		reg = <0x0 0x40000000>;
> 		ranges = <0x1000000 0x0 0x0 0x0 0x0 0x0 0x10000 0x2000000 0x0 0x41000000 0x0 0x41000000 0x0 0x3f000000>;
> 		interrupt-map = <0x0 0x0 0x0 0x1 0x1 0x0 0x4 0x1 0x800 0x0 0x0 0x1 0x1 0x0 0x5 0x1 0x1000 0x0 0x0 0x1 0x1 0x0 0x6 0x1 0x1800 0x0 0x0 0x1 0x1 0x0 0x7 0x1>;
> 		interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
> 	};


Looks like there are a few misses in the above. How about this:

pci {
    compatible = "arm,pci-cam-generic"
    device_type = "pci";
    ** ^^^^^^^^^^^^^^^^^
    ** MANDATORY for the host bridge node
    #address-cells = <3>;
    #size-cells = <2>;

    // BUS_ADDRESS(3)  CPU_PHYSICAL(2)  SIZE(2)
    ranges = <0x1000000 0x0 0x00000000  0x0 0x00000000  0x0 0x00010000>,
                                        ^^^^^^^^^^^^^^
            ** ?? Is this why you had problems with the offset? Should
	    ** be the cpu physical address of the start of the IO window.
             <0x2000000 0x0 0x41000000  0x0 0x41000000  0x0 0x3f000000>;

   
    #interrupt-cells = <0x1>;
    // PCI_DEVICE(3) INT#(1)  CONTROLLER(PHANDLE)  CONTROLLER_DATA(3)
    interrupt-map = <  0x0 0x0 0x0 0x1  0x1  0x0 0x4 0x1
                     0x800 0x0 0x0 0x1  0x1  0x0 0x5 0x1 
                    0x1000 0x0 0x0 0x1  0x1  0x0 0x6 0x1
                    0x1800 0x0 0x0 0x1  0x1  0x0 0x7 0x1>;
                 **                    ^^^^^^
                 ** This should be a phandle to the interrupt controller
    // PCI_DEVICE(3) INT#1()
    interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
}

I keep thinking of making a pcie-dt.h file with helper macros for
all this. :|

FWWI, I like to put a double space between the logically distinct
things in the lists.

Jason

^ permalink raw reply

* [BISECTED] ssh - Received disconnect from x.x.x.x: 2: Bad packet length 3149594624
From: Ivaylo Dimitrov @ 2014-02-13 18:02 UTC (permalink / raw)
  To: linux-arm-kernel

Since next-21012014 I started to receive "Received disconnect from 
x.x.x.x: 2: Bad packet length 3149594624" errors when trying to 
establish ssh session over wifi to my N900, running Maemo 5. I bisected 
and it turned out that commit dce5c9e35bc4085bd33eccdb8c9ec5a643507a14 
"ARM: 7928/1: kconfig: select HAVE_EFFICIENT_UNALIGNED_ACCESS for CPUv6+ 
&& MMU" is the first bad. There is nothing related in either dmesg or 
syslog on the device. Reverting that commit on 3.14-rc1 make those 
errors disappear.

As my knowledge on how to deal with that stops here, advises on what to 
do next to find the real problem are appreciated.

Ivo

^ permalink raw reply

* [PATCH] ARM: OMAP4: sleep: byteswap data for big-endian
From: Tony Lindgren @ 2014-02-13 17:47 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <52D5CBC9.5020201@ti.com>

* Santosh Shilimkar <santosh.shilimkar@ti.com> [140114 15:46]:
> On Tuesday 14 January 2014 04:13 PM, Nishanth Menon wrote:
> 
> I haven't looked at patch myself but as you pointed out if it adds
> dead code and makes the code un-readable then probably that something
> we shouldn't merge.

Yeah it seems the assembly parts should be done in more generic
way using macros so the same setup can then be used for other
SoCs. For the other trivial changes, let's try to get them merged
to shrink down the patchset.

Regards,

Tony

^ permalink raw reply

* [PATCH v2 0/4] tty/serial: Add helpers to use GPIOs to control modem lines
From: Greg Kroah-Hartman @ 2014-02-13 17:37 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1392140715-15295-1-git-send-email-richard.genoud@gmail.com>

On Tue, Feb 11, 2014 at 06:45:11PM +0100, Richard Genoud wrote:
> The USART controller on sam9x5 chips (and also all AT91/SAMA5 chips
> but at91rm9200) are not capable of handling DTR/DSR/DCD/RI signal.
> Moreover, even if the controller can handle CTS/RTS, the dedicated
> CTS/RTS pins are already muxed for other peripherals (LCDC/EMAC/MMC).
> 
> So this patchset adds the possibility to control those lines via GPIO,
> as it is done for RTS in the patch "switch atmel serial to use gpiolib"
> 
> As it was suggested by Alexander Shiyan, I made that available for
> every board.
> 
> This is based on 3.14-rc2 + Linus Walleij/Nicolas Ferre's patch:
>  354e57f3a0a2 ARM/serial: at91: switch atmel serial to use gpiolib
> (in Uwe's tree git://git.pengutronix.de/git/ukl/linux.git dropmachtimexh )
> and Philipp Zabel's patch:
> gpiolib: make gpiod_direction_output take a logical value, add gpiod_direction_output_raw
> (there won't be a merge conflict if this last patch is not present, the
> gpios will "just" be on the wrong direction.)
>  
> Tested on at91sam9g35, with a null modem cable between 2 serial ports,
> one with CTS/RTS controlled by the USART controller, the other via GPIO,
> full duplex transfers.
> Did some tests also with null modem cables on a PC.
> 
> Updates from v2:
> 	- Instead of controlling modem signal only on atmel board, the
> 	code is now available for every board.
> 	- The active low flag from device tree is now used.

I'm confused, how does this series relate to the previously sent 8 patch
series?

As I don't know what is going on, I'm going to drop both from my
to-apply queue, and await a new set of patches.

thanks,

greg k-h

^ permalink raw reply

* [PATCH v4 13/13] ARM: mvebu: register the cpuidle driver for the Armada XP SoCs
From: Gregory CLEMENT @ 2014-02-13 17:33 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1392312816-17657-1-git-send-email-gregory.clement@free-electrons.com>

The cpuidle is a platform driver so we have to register the device
during the initialization of the boards.

Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
---
 arch/arm/mach-mvebu/armada-370-xp.c | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/arch/arm/mach-mvebu/armada-370-xp.c b/arch/arm/mach-mvebu/armada-370-xp.c
index f6c9d1d85c14..81b42980311c 100644
--- a/arch/arm/mach-mvebu/armada-370-xp.c
+++ b/arch/arm/mach-mvebu/armada-370-xp.c
@@ -30,6 +30,11 @@
 #include "common.h"
 #include "coherency.h"
 #include "mvebu-soc-id.h"
+#include "pmsu.h"
+
+static struct platform_device armada_xp_cpuidle_device = {
+	.name = "cpuidle-armada-370-xp",
+};
 
 static void __init armada_370_xp_map_io(void)
 {
@@ -80,6 +85,13 @@ static void __init armada_370_xp_dt_init(void)
 	if (of_machine_is_compatible("plathome,openblocks-ax3-4"))
 		i2c_quirk();
 	of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
+	if (of_find_compatible_node(NULL, NULL, "marvell,armada-370-xp-pmsu")
+		&& of_find_compatible_node(NULL, NULL, "marvell,coherency-fabric")
+		&& of_machine_is_compatible("marvell,armadaxp")) {
+		armada_370_xp_pmsu_enable_l2_powerdown_onidle();
+		armada_370_xp_cpu_pm_init();
+		platform_device_register(&armada_xp_cpuidle_device);
+	}
 }
 
 static const char * const armada_370_xp_dt_compat[] = {
-- 
1.8.1.2

^ permalink raw reply related

* [PATCH v4 12/13] cpuidle: mvebu: Add initial CPU idle support for Armada 370/XP SoC
From: Gregory CLEMENT @ 2014-02-13 17:33 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1392312816-17657-1-git-send-email-gregory.clement@free-electrons.com>

Add the wfi, cpu idle and cpu deep idle power states support for the
Armada XP SoCs.

All the latencies and the power consumption values used at the
"armada_370_xp_idle_driver" structure are preliminary and will be
modified in the future after running some measurements and analysis.

Based on the work of Nadav Haklai.

Signed-off-by: Nadav Haklai <nadavh@marvell.com>
Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
---
 drivers/cpuidle/Kconfig.arm             |   5 ++
 drivers/cpuidle/Makefile                |   1 +
 drivers/cpuidle/cpuidle-armada-370-xp.c | 120 ++++++++++++++++++++++++++++++++
 3 files changed, 126 insertions(+)
 create mode 100644 drivers/cpuidle/cpuidle-armada-370-xp.c

diff --git a/drivers/cpuidle/Kconfig.arm b/drivers/cpuidle/Kconfig.arm
index d988948a89a0..f377eb0840e3 100644
--- a/drivers/cpuidle/Kconfig.arm
+++ b/drivers/cpuidle/Kconfig.arm
@@ -1,6 +1,11 @@
 #
 # ARM CPU Idle drivers
 #
+config ARM_ARMADA_370_XP_CPUIDLE
+	bool "CPU Idle Driver for Armada 370/XP family processors"
+	depends on ARCH_MVEBU
+	help
+	  Select this to enable cpuidle on Armada 370/XP processors.
 
 config ARM_BIG_LITTLE_CPUIDLE
 	bool "Support for ARM big.LITTLE processors"
diff --git a/drivers/cpuidle/Makefile b/drivers/cpuidle/Makefile
index f71ae1b373c5..9902d052bd87 100644
--- a/drivers/cpuidle/Makefile
+++ b/drivers/cpuidle/Makefile
@@ -7,6 +7,7 @@ obj-$(CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED) += coupled.o
 
 ##################################################################################
 # ARM SoC drivers
+obj-$(CONFIG_ARM_ARMADA_370_XP_CPUIDLE) += cpuidle-armada-370-xp.o
 obj-$(CONFIG_ARM_BIG_LITTLE_CPUIDLE)	+= cpuidle-big_little.o
 obj-$(CONFIG_ARM_HIGHBANK_CPUIDLE)	+= cpuidle-calxeda.o
 obj-$(CONFIG_ARM_KIRKWOOD_CPUIDLE)	+= cpuidle-kirkwood.o
diff --git a/drivers/cpuidle/cpuidle-armada-370-xp.c b/drivers/cpuidle/cpuidle-armada-370-xp.c
new file mode 100644
index 000000000000..57c69812e79d
--- /dev/null
+++ b/drivers/cpuidle/cpuidle-armada-370-xp.c
@@ -0,0 +1,120 @@
+/*
+ * Marvell Armada 370 and Armada XP SoC cpuidle driver
+ *
+ * Copyright (C) 2013 Marvell
+ *
+ * Nadav Haklai <nadavh@marvell.com>
+ * Gregory CLEMENT <gregory.clement@free-electrons.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ *
+ * Maintainer: Gregory CLEMENT <gregory.clement@free-electrons.com>
+ */
+
+#include <linux/cpu_pm.h>
+#include <linux/cpuidle.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/suspend.h>
+#include <asm/suspend.h>
+#include <linux/smp.h>
+#include <asm/cpuidle.h>
+#include <asm/smp_plat.h>
+#include <linux/platform_device.h>
+#include <asm/cp15.h>
+#include <asm/cacheflush.h>
+
+#define ARMADA_370_XP_MAX_STATES	3
+#define ARMADA_370_XP_FLAG_DEEP_IDLE	0x10000
+extern void armada_370_xp_pmsu_idle_prepare(bool deepidle);
+extern void ll_clear_cpu_coherent(void);
+extern void ll_set_cpu_coherent(void);
+
+noinline static int armada_370_xp_cpu_suspend(unsigned long deepidle)
+{
+	armada_370_xp_pmsu_idle_prepare(deepidle);
+
+	v7_exit_coherency_flush(all);
+
+	ll_clear_cpu_coherent();
+
+	dsb();
+
+	wfi();
+
+	ll_set_cpu_coherent();
+
+	asm volatile(
+	"mrc	p15, 0, %0, c1, c0, 0 \n\t"
+	"tst	%0, #(1 << 2) \n\t"
+	"orreq	r0, %0, #(1 << 2) \n\t"
+	"mcreq	p15, 0, %0, c1, c0, 0 \n\t"
+	"isb	"
+	: : "r" (0));
+
+	return 0;
+}
+
+static int armada_370_xp_enter_idle(struct cpuidle_device *dev,
+				struct cpuidle_driver *drv,
+				int index)
+{
+	bool deepidle = false;
+	cpu_pm_enter();
+
+	if (drv->states[index].flags & ARMADA_370_XP_FLAG_DEEP_IDLE)
+		deepidle = true;
+
+	cpu_suspend(deepidle, armada_370_xp_cpu_suspend);
+
+	cpu_pm_exit();
+
+	return index;
+}
+
+static struct cpuidle_driver armada_370_xp_idle_driver = {
+	.name			= "armada_370_xp_idle",
+	.states[0]		= ARM_CPUIDLE_WFI_STATE,
+	.states[1]		= {
+		.enter			= armada_370_xp_enter_idle,
+		.exit_latency		= 10,
+		.power_usage		= 50,
+		.target_residency	= 100,
+		.flags			= CPUIDLE_FLAG_TIME_VALID,
+		.name			= "MV CPU IDLE",
+		.desc			= "CPU power down",
+	},
+	.states[2]		= {
+		.enter			= armada_370_xp_enter_idle,
+		.exit_latency		= 100,
+		.power_usage		= 5,
+		.target_residency	= 1000,
+		.flags			= CPUIDLE_FLAG_TIME_VALID |
+						ARMADA_370_XP_FLAG_DEEP_IDLE,
+		.name			= "MV CPU DEEP IDLE",
+		.desc			= "CPU and L2 Fabric power down",
+	},
+	.state_count = ARMADA_370_XP_MAX_STATES,
+};
+
+static int armada_370_xp_cpuidle_probe(struct platform_device *pdev)
+{
+	return cpuidle_register(&armada_370_xp_idle_driver, NULL);
+}
+
+static struct platform_driver armada_370_xp_cpuidle_plat_driver = {
+	.driver = {
+		.name = "cpuidle-armada-370-xp",
+		.owner = THIS_MODULE,
+	},
+	.probe = armada_370_xp_cpuidle_probe,
+};
+
+module_platform_driver(armada_370_xp_cpuidle_plat_driver);
+
+MODULE_AUTHOR("Gregory CLEMENT <gregory.clement@free-electrons.com>");
+MODULE_DESCRIPTION("Armada 370/XP cpu idle driver");
+MODULE_LICENSE("GPL");
-- 
1.8.1.2

^ permalink raw reply related

* [PATCH v4 11/13] ARM: mvebu: Register notifier callback for the cpuidle transition
From: Gregory CLEMENT @ 2014-02-13 17:33 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1392312816-17657-1-git-send-email-gregory.clement@free-electrons.com>

In order to have well encapsulated code use notifier callback for
CPU_PM_ENTER and CPU_PM_EXIT inside the mvebu power management code.

Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
---
 arch/arm/mach-mvebu/pmsu.c | 24 ++++++++++++++++++++++++
 arch/arm/mach-mvebu/pmsu.h |  1 +
 2 files changed, 25 insertions(+)

diff --git a/arch/arm/mach-mvebu/pmsu.c b/arch/arm/mach-mvebu/pmsu.c
index 162ae1399f2a..0e54077c31cb 100644
--- a/arch/arm/mach-mvebu/pmsu.c
+++ b/arch/arm/mach-mvebu/pmsu.c
@@ -16,6 +16,7 @@
  * other SOC units
  */
 
+#include <linux/cpu_pm.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/of_address.h>
@@ -189,4 +190,27 @@ static noinline void armada_370_xp_pmsu_idle_restore(void)
 	writel(reg, pmsu_mp_base + PMSU_STATUS_AND_MASK(hw_cpu));
 }
 
+static int armada_370_xp_cpu_pm_notify(struct notifier_block *self,
+				    unsigned long action, void *hcpu)
+{
+	if (action == CPU_PM_ENTER) {
+		unsigned int hw_cpu = cpu_logical_map(smp_processor_id());
+		armada_370_xp_pmsu_set_start_addr(armada_370_xp_cpu_resume,
+						hw_cpu);
+	} else if (action == CPU_PM_EXIT) {
+		armada_370_xp_pmsu_idle_restore();
+	}
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block armada_370_xp_cpu_pm_notifier = {
+	.notifier_call = armada_370_xp_cpu_pm_notify,
+};
+
+int __init armada_370_xp_cpu_pm_init(void)
+{
+	return cpu_pm_register_notifier(&armada_370_xp_cpu_pm_notifier);
+}
+
 early_initcall(armada_370_xp_pmsu_init);
diff --git a/arch/arm/mach-mvebu/pmsu.h b/arch/arm/mach-mvebu/pmsu.h
index 054cdd8b0ece..e7a766fba757 100644
--- a/arch/arm/mach-mvebu/pmsu.h
+++ b/arch/arm/mach-mvebu/pmsu.h
@@ -13,5 +13,6 @@
 
 int armada_xp_boot_cpu(unsigned int cpu_id, void *phys_addr);
 void armada_370_xp_pmsu_enable_l2_powerdown_onidle(void);
+int armada_370_xp_cpu_pm_init(void);
 
 #endif	/* __MACH_370_XP_PMSU_H */
-- 
1.8.1.2

^ permalink raw reply related

* [PATCH v4 10/13] ARM: mvebu: Set the start address of a CPU in a separate function
From: Gregory CLEMENT @ 2014-02-13 17:33 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1392312816-17657-1-git-send-email-gregory.clement@free-electrons.com>

Setting the start (or boot) address of A CPU is no more used only
during SMP bring up, but will also be used by the CPU idle functions
or later by the CPU hot plug ones.

This commit moves it in a separate function.

Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
---
 arch/arm/mach-mvebu/pmsu.c | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/arch/arm/mach-mvebu/pmsu.c b/arch/arm/mach-mvebu/pmsu.c
index ec745d59fea8..162ae1399f2a 100644
--- a/arch/arm/mach-mvebu/pmsu.c
+++ b/arch/arm/mach-mvebu/pmsu.c
@@ -61,6 +61,12 @@ static struct of_device_id of_pmsu_table[] = {
 	{ /* end of list */ },
 };
 
+static void armada_370_xp_pmsu_set_start_addr(void *start_addr, int hw_cpu)
+{
+	writel(virt_to_phys(start_addr), pmsu_mp_base +
+		PMSU_BOOT_ADDR_REDIRECT_OFFSET(hw_cpu));
+}
+
 #ifdef CONFIG_SMP
 int armada_xp_boot_cpu(unsigned int cpu_id, void *boot_addr)
 {
@@ -73,8 +79,7 @@ int armada_xp_boot_cpu(unsigned int cpu_id, void *boot_addr)
 
 	hw_cpu = cpu_logical_map(cpu_id);
 
-	writel(virt_to_phys(boot_addr), pmsu_mp_base +
-			PMSU_BOOT_ADDR_REDIRECT_OFFSET(hw_cpu));
+	armada_370_xp_pmsu_set_start_addr(boot_addr, hw_cpu);
 
 	/* Release CPU from reset by clearing reset bit*/
 	reg = readl(pmsu_reset_base + PMSU_RESET_CTL_OFFSET(hw_cpu));
-- 
1.8.1.2

^ permalink raw reply related

* [PATCH v4 09/13] ARM: mvebu: Add the PMSU related part of the cpu idle functions
From: Gregory CLEMENT @ 2014-02-13 17:33 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1392312816-17657-1-git-send-email-gregory.clement@free-electrons.com>

The cpu idle support will need to access to Power Management Service
Unit. This commit adds the prepare and restore functions that will be
used in the idle path of the cpuidle driver.

Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
---
 arch/arm/mach-mvebu/pmsu.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 85 insertions(+)

diff --git a/arch/arm/mach-mvebu/pmsu.c b/arch/arm/mach-mvebu/pmsu.c
index 36d946d53f54..ec745d59fea8 100644
--- a/arch/arm/mach-mvebu/pmsu.c
+++ b/arch/arm/mach-mvebu/pmsu.c
@@ -29,6 +29,24 @@ static void __iomem *pmsu_reset_base;
 static void __iomem *pmsu_fabric_base;
 
 /* PMSU MP registers */
+#define PMSU_CONTROL_AND_CONFIG(cpu)	    ((cpu * 0x100) + 0x4)
+#define PMSU_CONTROL_AND_CONFIG_DFS_REQ		BIT(18)
+#define PMSU_CONTROL_AND_CONFIG_PWDDN_REQ	BIT(16)
+#define PMSU_CONTROL_AND_CONFIG_L2_PWDDN	BIT(20)
+
+#define PMSU_CPU_POWER_DOWN_CONTROL(cpu)    ((cpu * 0x100) + 0x8)
+
+#define PMSU_CPU_POWER_DOWN_DIS_SNP_Q_SKIP	BIT(0)
+
+#define PMSU_STATUS_AND_MASK(cpu)	    ((cpu * 0x100) + 0xc)
+#define PMSU_STATUS_AND_MASK_CPU_IDLE_WAIT	BIT(16)
+#define PMSU_STATUS_AND_MASK_SNP_Q_EMPTY_WAIT	BIT(17)
+#define PMSU_STATUS_AND_MASK_IRQ_WAKEUP		BIT(20)
+#define PMSU_STATUS_AND_MASK_FIQ_WAKEUP		BIT(21)
+#define PMSU_STATUS_AND_MASK_DBG_WAKEUP		BIT(22)
+#define PMSU_STATUS_AND_MASK_IRQ_MASK		BIT(24)
+#define PMSU_STATUS_AND_MASK_FIQ_MASK		BIT(25)
+
 #define PMSU_BOOT_ADDR_REDIRECT_OFFSET(cpu) ((cpu * 0x100) + 0x24)
 
 /* PMSU reset registers */
@@ -99,4 +117,71 @@ void armada_370_xp_pmsu_enable_l2_powerdown_onidle(void)
 	writel(reg, pmsu_fabric_base + L2C_NFABRIC_PM_CTL);
 }
 
+static void armada_370_xp_cpu_resume(void)
+{
+	asm volatile("bl    ll_set_cpu_coherent_and_smp\n\t"
+		     "b	    cpu_resume\n\t");
+}
+
+/* No locking is needed because we only access per-CPU registers */
+void armada_370_xp_pmsu_idle_prepare(bool deepidle)
+{
+	unsigned int hw_cpu = cpu_logical_map(smp_processor_id());
+	u32 reg;
+
+	if (pmsu_mp_base == NULL)
+		return;
+
+	/*
+	 * Adjust the PMSU configuration to wait for WFI signal, enable
+	 * IRQ and FIQ as wakeup events, set wait for snoop queue empty
+	 * indication and mask IRQ and FIQ from CPU
+	 */
+	reg = readl(pmsu_mp_base + PMSU_STATUS_AND_MASK(hw_cpu));
+	reg |= PMSU_STATUS_AND_MASK_CPU_IDLE_WAIT    |
+	       PMSU_STATUS_AND_MASK_IRQ_WAKEUP       |
+	       PMSU_STATUS_AND_MASK_FIQ_WAKEUP       |
+	       PMSU_STATUS_AND_MASK_SNP_Q_EMPTY_WAIT |
+	       PMSU_STATUS_AND_MASK_IRQ_MASK         |
+	       PMSU_STATUS_AND_MASK_FIQ_MASK;
+	writel(reg, pmsu_mp_base + PMSU_STATUS_AND_MASK(hw_cpu));
+
+	reg = readl(pmsu_mp_base + PMSU_CONTROL_AND_CONFIG(hw_cpu));
+	/* ask HW to power down the L2 Cache if needed */
+	if (deepidle)
+		reg |= PMSU_CONTROL_AND_CONFIG_L2_PWDDN;
+
+	/* request power down */
+	reg |= PMSU_CONTROL_AND_CONFIG_PWDDN_REQ;
+	writel(reg, pmsu_mp_base + PMSU_CONTROL_AND_CONFIG(hw_cpu));
+
+	/* Disable snoop disable by HW - SW is taking care of it */
+	reg = readl(pmsu_mp_base + PMSU_CPU_POWER_DOWN_CONTROL(hw_cpu));
+	reg |= PMSU_CPU_POWER_DOWN_DIS_SNP_Q_SKIP;
+	writel(reg, pmsu_mp_base + PMSU_CPU_POWER_DOWN_CONTROL(hw_cpu));
+}
+
+/* No locking is needed because we only access per-CPU registers */
+static noinline void armada_370_xp_pmsu_idle_restore(void)
+{
+	unsigned int hw_cpu = cpu_logical_map(smp_processor_id());
+	u32 reg;
+
+	if (pmsu_mp_base == NULL)
+		return;
+
+	/* cancel ask HW to power down the L2 Cache if possible */
+	reg = readl(pmsu_mp_base + PMSU_CONTROL_AND_CONFIG(hw_cpu));
+	reg &= ~PMSU_CONTROL_AND_CONFIG_L2_PWDDN;
+	writel(reg, pmsu_mp_base + PMSU_CONTROL_AND_CONFIG(hw_cpu));
+
+	/* cancel Enable wakeup events and mask interrupts */
+	reg = readl(pmsu_mp_base + PMSU_STATUS_AND_MASK(hw_cpu));
+	reg &= ~(PMSU_STATUS_AND_MASK_IRQ_WAKEUP | PMSU_STATUS_AND_MASK_FIQ_WAKEUP);
+	reg &= ~PMSU_STATUS_AND_MASK_CPU_IDLE_WAIT;
+	reg &= ~PMSU_STATUS_AND_MASK_SNP_Q_EMPTY_WAIT;
+	reg &= ~(PMSU_STATUS_AND_MASK_IRQ_MASK | PMSU_STATUS_AND_MASK_FIQ_MASK);
+	writel(reg, pmsu_mp_base + PMSU_STATUS_AND_MASK(hw_cpu));
+}
+
 early_initcall(armada_370_xp_pmsu_init);
-- 
1.8.1.2

^ permalink raw reply related

* [PATCH v4 08/13] ARM: mvebu: Allow to power down L2 cache controller in idle mode
From: Gregory CLEMENT @ 2014-02-13 17:33 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1392312816-17657-1-git-send-email-gregory.clement@free-electrons.com>

This commit adds an function which adjusts the PMSU configuration to
automatically power down the L2 and coherency fabric when we enter a
certain idle state.

This feature is part of the Power Management Service Unit of the
Armada 370 and Armada XP SoCs.

Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
---
 arch/arm/mach-mvebu/pmsu.c | 24 ++++++++++++++++++++++--
 arch/arm/mach-mvebu/pmsu.h |  1 +
 2 files changed, 23 insertions(+), 2 deletions(-)

diff --git a/arch/arm/mach-mvebu/pmsu.c b/arch/arm/mach-mvebu/pmsu.c
index aa5ef7439d0f..36d946d53f54 100644
--- a/arch/arm/mach-mvebu/pmsu.c
+++ b/arch/arm/mach-mvebu/pmsu.c
@@ -28,8 +28,15 @@ static void __iomem *pmsu_mp_base;
 static void __iomem *pmsu_reset_base;
 static void __iomem *pmsu_fabric_base;
 
-#define PMSU_BOOT_ADDR_REDIRECT_OFFSET(cpu)	((cpu * 0x100) + 0x24)
-#define PMSU_RESET_CTL_OFFSET(cpu)		(cpu * 0x8)
+/* PMSU MP registers */
+#define PMSU_BOOT_ADDR_REDIRECT_OFFSET(cpu) ((cpu * 0x100) + 0x24)
+
+/* PMSU reset registers */
+#define PMSU_RESET_CTL_OFFSET(cpu)	    (cpu * 0x8)
+
+/* PMSU fabric registers */
+#define L2C_NFABRIC_PM_CTL		    0x4
+#define L2C_NFABRIC_PM_CTL_PWR_DOWN		BIT(20)
 
 static struct of_device_id of_pmsu_table[] = {
 	{.compatible = "marvell,armada-370-xp-pmsu"},
@@ -79,4 +86,17 @@ static int __init armada_370_xp_pmsu_init(void)
 	return 0;
 }
 
+void armada_370_xp_pmsu_enable_l2_powerdown_onidle(void)
+{
+	u32 reg;
+
+	if (pmsu_fabric_base == NULL)
+		return;
+
+	/* Enable L2 & Fabric powerdown in Deep-Idle mode - Fabric */
+	reg = readl(pmsu_fabric_base + L2C_NFABRIC_PM_CTL);
+	reg |= L2C_NFABRIC_PM_CTL_PWR_DOWN;
+	writel(reg, pmsu_fabric_base + L2C_NFABRIC_PM_CTL);
+}
+
 early_initcall(armada_370_xp_pmsu_init);
diff --git a/arch/arm/mach-mvebu/pmsu.h b/arch/arm/mach-mvebu/pmsu.h
index 07a737c6b95d..054cdd8b0ece 100644
--- a/arch/arm/mach-mvebu/pmsu.h
+++ b/arch/arm/mach-mvebu/pmsu.h
@@ -12,5 +12,6 @@
 #define __MACH_MVEBU_PMSU_H
 
 int armada_xp_boot_cpu(unsigned int cpu_id, void *phys_addr);
+void armada_370_xp_pmsu_enable_l2_powerdown_onidle(void);
 
 #endif	/* __MACH_370_XP_PMSU_H */
-- 
1.8.1.2

^ permalink raw reply related

* [PATCH v4 07/13] ARM: dts: mvebu: Add a new set of registers to the PMSU node
From: Gregory CLEMENT @ 2014-02-13 17:33 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1392312816-17657-1-git-send-email-gregory.clement@free-electrons.com>

The Power Management Unit Service block also controls the Coherency
Fabric subsystem. This new set of registers is needed for the CPU idle
implementation for the Armada XP, it allows to enter in a deep CPU
idle state where the Coherency Fabric and the L2 cache are powerdown.

Cc: devicetree at vger.kernel.org
Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
---
 Documentation/devicetree/bindings/arm/armada-370-xp-pmsu.txt | 12 +++++++-----
 arch/arm/boot/dts/armada-xp.dtsi                             |  2 +-
 2 files changed, 8 insertions(+), 6 deletions(-)

diff --git a/Documentation/devicetree/bindings/arm/armada-370-xp-pmsu.txt b/Documentation/devicetree/bindings/arm/armada-370-xp-pmsu.txt
index 926b4d6aae7e..8a9db0c32ba5 100644
--- a/Documentation/devicetree/bindings/arm/armada-370-xp-pmsu.txt
+++ b/Documentation/devicetree/bindings/arm/armada-370-xp-pmsu.txt
@@ -7,14 +7,16 @@ Required properties:
 - compatible: "marvell,armada-370-xp-pmsu"
 
 - reg: Should contain PMSU registers location and length. First pair
-  for the per-CPU SW Reset Control registers, second pair for the
-  Power Management Service Unit.
+  for the per-CPU SW Reset Control registers, second pair for the CPU
+  Power Management Service Unit registers, third pair for the Fabric Power
+  Management Service Unit registers.
 
 Example:
 
-armada-370-xp-pmsu at d0022000 {
+armada-370-xp-pmsu at 22000 {
 	compatible = "marvell,armada-370-xp-pmsu";
-	reg = <0xd0022100 0x430>,
-	      <0xd0020800 0x20>;
+	reg = <0x22100 0x430>,
+	      <0x20800 0x20>,
+	      <0x22000 0x24>;
 };
 
diff --git a/arch/arm/boot/dts/armada-xp.dtsi b/arch/arm/boot/dts/armada-xp.dtsi
index b8b84a22f0f3..f717da4f4d97 100644
--- a/arch/arm/boot/dts/armada-xp.dtsi
+++ b/arch/arm/boot/dts/armada-xp.dtsi
@@ -113,7 +113,7 @@
 
 			armada-370-xp-pmsu at 22000 {
 				compatible = "marvell,armada-370-xp-pmsu";
-				reg = <0x22100 0x400>, <0x20800 0x20>;
+				reg = <0x22100 0x400>, <0x20800 0x20>, <0x22000 0x24>;
 			};
 
 			eth2: ethernet at 30000 {
-- 
1.8.1.2

^ permalink raw reply related

* [PATCH v4 06/13] ARM: mvebu: Add a new set of registers for pmsu
From: Gregory CLEMENT @ 2014-02-13 17:33 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1392312816-17657-1-git-send-email-gregory.clement@free-electrons.com>

The Power Management Unit Service block also controls the Coherency
Fabric subsystem. This new set of registers is needed for the CPU idle
implementation for the Armada 370/XP, it allows to enter a deep CPU
idle state where the Coherency Fabric and the L2 cache are powered
down.

This patch also adds warnings if one of the base registers set can't
be ioremapped.

Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
---
 arch/arm/mach-mvebu/pmsu.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/arch/arm/mach-mvebu/pmsu.c b/arch/arm/mach-mvebu/pmsu.c
index d71ef53107c4..aa5ef7439d0f 100644
--- a/arch/arm/mach-mvebu/pmsu.c
+++ b/arch/arm/mach-mvebu/pmsu.c
@@ -26,6 +26,7 @@
 
 static void __iomem *pmsu_mp_base;
 static void __iomem *pmsu_reset_base;
+static void __iomem *pmsu_fabric_base;
 
 #define PMSU_BOOT_ADDR_REDIRECT_OFFSET(cpu)	((cpu * 0x100) + 0x24)
 #define PMSU_RESET_CTL_OFFSET(cpu)		(cpu * 0x8)
@@ -67,7 +68,11 @@ static int __init armada_370_xp_pmsu_init(void)
 	if (np) {
 		pr_info("Initializing Power Management Service Unit\n");
 		pmsu_mp_base = of_iomap(np, 0);
+		WARN_ON(!pmsu_mp_base);
 		pmsu_reset_base = of_iomap(np, 1);
+		WARN_ON(!pmsu_reset_base);
+		pmsu_fabric_base = of_iomap(np, 2);
+		WARN_ON(!pmsu_fabric_base);
 		of_node_put(np);
 	}
 
-- 
1.8.1.2

^ permalink raw reply related

* [PATCH v4 05/13] ARM: mvebu: Low level function to disable HW coherency support
From: Gregory CLEMENT @ 2014-02-13 17:33 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1392312816-17657-1-git-send-email-gregory.clement@free-electrons.com>

When going to deep idle we need to disable the SoC snooping (aka
hardware coherency support). Playing with the coherency fabric
requires to use assembly code to be sure that the compiler doesn't
reorder the instructions nor do wrong optimization.

This commit extends the modify_coherent_reg macro in order to manage
enabling (setting a bit) and disabling (clearing the same bit) the
hardware coherency support.

This function will be called by the low level (in assembly) part of
the CPU idle functions.

Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
---
 arch/arm/mach-mvebu/coherency_ll.S | 21 +++++++++++++++++----
 1 file changed, 17 insertions(+), 4 deletions(-)

diff --git a/arch/arm/mach-mvebu/coherency_ll.S b/arch/arm/mach-mvebu/coherency_ll.S
index 7b42b4b08a80..686aba2adfc7 100644
--- a/arch/arm/mach-mvebu/coherency_ll.S
+++ b/arch/arm/mach-mvebu/coherency_ll.S
@@ -25,7 +25,7 @@
 
 	.text
 
-	.macro modify_coherent_reg join_smp
+	.macro modify_coherent_reg join_smp clear_coherency
 	mrc	p15, 0, r1, c1, c0, 0
 	tst	r1, #CR_M @ Check MMU bit enabled
 	bne	1f
@@ -61,11 +61,19 @@
 	sub	r1, r0, #ARMADA_XP_CFB_CFG_REG_OFFSET
 	.endif
 
-	/* Enable coherency on CPU - Atomic */
+	/*
+	 * Enable coherency on CPU - Atomic (or disable depending of
+	 * the clear_coherency flag)
+	 */
 	add	r0, r1, #ARMADA_XP_CFB_CTL_REG_OFFSET
+
 1:
 	ldrex	r2, [r0]
+	.if \clear_coherency == 1
+	bic	r2, r2, r3
+	.else
 	orr	r2, r2, r3
+	.endif
 	strex	r1, r2, [r0]
 	cmp	r1, #0
 	bne 1b
@@ -78,12 +86,17 @@
 
 /*  Enable coherency on CPU */
 ENTRY(ll_set_cpu_coherent)
-	modify_coherent_reg join_smp = 0
+	modify_coherent_reg join_smp = 0, clear_coherency = 0
 ENDPROC(ll_set_cpu_coherent)
 
+/*  Disable coherency on CPU */
+ENTRY(ll_clear_cpu_coherent)
+	modify_coherent_reg join_smp = 0, clear_coherency = 1
+ENDPROC(ll_clear_cpu_coherent)
+
 /* Add CPU to SMP group */
 ENTRY(ll_set_cpu_coherent_and_smp)
-	modify_coherent_reg join_smp = 1
+	modify_coherent_reg join_smp = 1, clear_coherency = 0
 ENDPROC(ll_set_cpu_coherent_and_smp)
 
 	.align 2
-- 
1.8.1.2

^ permalink raw reply related

* [PATCH v4 04/13] ARM: mvebu: Remove the unused argument of set_cpu_coherent()
From: Gregory CLEMENT @ 2014-02-13 17:33 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1392312816-17657-1-git-send-email-gregory.clement@free-electrons.com>

set_cpu_coherent() took the SMP group ID as parameter. But this
parameter was never used, and the CPU always use the SMP group 0. So
we can remove this parameter.

Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
---
 arch/arm/mach-mvebu/coherency.c    |  8 ++---
 arch/arm/mach-mvebu/coherency.h    |  2 +-
 arch/arm/mach-mvebu/coherency_ll.S | 61 ++++++++++++++++++++++++--------------
 arch/arm/mach-mvebu/headsmp.S      |  4 +--
 arch/arm/mach-mvebu/platsmp.c      |  2 +-
 5 files changed, 46 insertions(+), 31 deletions(-)

diff --git a/arch/arm/mach-mvebu/coherency.c b/arch/arm/mach-mvebu/coherency.c
index 51010dbbf7e4..931c62be2bce 100644
--- a/arch/arm/mach-mvebu/coherency.c
+++ b/arch/arm/mach-mvebu/coherency.c
@@ -44,9 +44,9 @@ static struct of_device_id of_coherency_table[] = {
 };
 
 /* Function defined in coherency_ll.S */
-int ll_set_cpu_coherent(void);
+int ll_set_cpu_coherent_and_smp(void);
 
-int set_cpu_coherent(int smp_group_id)
+int set_cpu_coherent(void)
 {
 	if (!coherency_base) {
 		pr_warn("Can't make current CPU cache coherent.\n");
@@ -54,7 +54,7 @@ int set_cpu_coherent(int smp_group_id)
 		return 1;
 	}
 
-	return ll_set_cpu_coherent();
+	return ll_set_cpu_coherent_and_smp();
 }
 
 static inline void mvebu_hwcc_sync_io_barrier(void)
@@ -140,7 +140,7 @@ int __init coherency_init(void)
 		sync_cache_w(&coherency_phys_base);
 		coherency_base = of_iomap(np, 0);
 		coherency_cpu_base = of_iomap(np, 1);
-		set_cpu_coherent(0);
+		set_cpu_coherent();
 		of_node_put(np);
 	}
 
diff --git a/arch/arm/mach-mvebu/coherency.h b/arch/arm/mach-mvebu/coherency.h
index c7e5df368d98..dff16612dd93 100644
--- a/arch/arm/mach-mvebu/coherency.h
+++ b/arch/arm/mach-mvebu/coherency.h
@@ -15,8 +15,8 @@
 #define __MACH_370_XP_COHERENCY_H
 
 extern unsigned long coherency_phys_base;
+int set_cpu_coherent(void);
 
-int set_cpu_coherent(int smp_group_id);
 int coherency_init(void);
 
 #endif	/* __MACH_370_XP_COHERENCY_H */
diff --git a/arch/arm/mach-mvebu/coherency_ll.S b/arch/arm/mach-mvebu/coherency_ll.S
index 6cb26b919787..7b42b4b08a80 100644
--- a/arch/arm/mach-mvebu/coherency_ll.S
+++ b/arch/arm/mach-mvebu/coherency_ll.S
@@ -25,52 +25,67 @@
 
 	.text
 
-ENTRY(ll_set_cpu_coherent)
+	.macro modify_coherent_reg join_smp
 	mrc	p15, 0, r1, c1, c0, 0
 	tst	r1, #CR_M @ Check MMU bit enabled
 	bne	1f
 
-	/* use physical address of the coherency register*/
-	adr	r0, 3f
-	ldr	r3, [r0]
-	ldr	r0, [r0, r3]
+	/* use physical address of the coherency register */
+	adr	r1, 3f
+	ldr	r3, [r1]
+	ldr	r1, [r1, r3]
 	b	2f
 1:
-	/* use virtual address of the coherency register*/
-	ldr	r0, =coherency_base
-	ldr	r0, [r0]
+	/* use virtual address of the coherency register */
+	ldr	r1, =coherency_base
+	ldr	r1, [r1]
 2:
 	/* Create bit by cpu index */
-	mrc	15, 0, r1, cr0, cr0, 5
-	and	r1, r1, #15
+	mrc	15, 0, r3, cr0, cr0, 5
+	and	r3, r3, #15
 	mov	r2, #(1 << 24)
-	lsl	r1, r2, r1
-	ARM_BE8(rev	r1, r1)
+	lsl	r3, r2, r3
+	ARM_BE8(rev	r3, r3)
 
-	/* Add CPU to SMP group - Atomic */
-	add	r3, r0, #ARMADA_XP_CFB_CTL_REG_OFFSET
+	.if \join_smp == 1
+	/* Add CPU to SMP group - Atomic (only if the flag is set) */
+	add	r0, r1, #ARMADA_XP_CFB_CFG_REG_OFFSET
 1:
-	ldrex	r2, [r3]
-	orr	r2, r2, r1
-	strex 	r0, r2, [r3]
-	cmp	r0, #0
+	ldrex	r2, [r0]
+	orr	r2, r2, r3
+	strex 	r1, r2, [r0]
+	cmp	r1, #0
 	bne 1b
 
+	/* get back to the base register */
+	sub	r1, r0, #ARMADA_XP_CFB_CFG_REG_OFFSET
+	.endif
+
 	/* Enable coherency on CPU - Atomic */
-	add	r3, r3, #ARMADA_XP_CFB_CFG_REG_OFFSET
+	add	r0, r1, #ARMADA_XP_CFB_CTL_REG_OFFSET
 1:
-	ldrex	r2, [r3]
-	orr	r2, r2, r1
-	strex	r0, r2, [r3]
-	cmp	r0, #0
+	ldrex	r2, [r0]
+	orr	r2, r2, r3
+	strex	r1, r2, [r0]
+	cmp	r1, #0
 	bne 1b
 
 	dsb
 
 	mov	r0, #0
 	mov	pc, lr
+	.endm
+
+/*  Enable coherency on CPU */
+ENTRY(ll_set_cpu_coherent)
+	modify_coherent_reg join_smp = 0
 ENDPROC(ll_set_cpu_coherent)
 
+/* Add CPU to SMP group */
+ENTRY(ll_set_cpu_coherent_and_smp)
+	modify_coherent_reg join_smp = 1
+ENDPROC(ll_set_cpu_coherent_and_smp)
+
 	.align 2
 3:
 	.long	coherency_phys_base - .
diff --git a/arch/arm/mach-mvebu/headsmp.S b/arch/arm/mach-mvebu/headsmp.S
index cf7abe6554f7..924fb96775c5 100644
--- a/arch/arm/mach-mvebu/headsmp.S
+++ b/arch/arm/mach-mvebu/headsmp.S
@@ -31,8 +31,8 @@
 ENTRY(armada_xp_secondary_startup)
  ARM_BE8(setend	be )			@ go BE8 if entered LE
 
-	/* Add CPU to coherency fabric */
-	bl	ll_set_cpu_coherent
+	bl	ll_set_cpu_coherent_and_smp
+
 	b	secondary_startup
 
 ENDPROC(armada_xp_secondary_startup)
diff --git a/arch/arm/mach-mvebu/platsmp.c b/arch/arm/mach-mvebu/platsmp.c
index a99d71a747f0..f2f1830063c8 100644
--- a/arch/arm/mach-mvebu/platsmp.c
+++ b/arch/arm/mach-mvebu/platsmp.c
@@ -102,7 +102,7 @@ static void __init armada_xp_smp_prepare_cpus(unsigned int max_cpus)
 
 	set_secondary_cpus_clock();
 	flush_cache_all();
-	set_cpu_coherent(0);
+	set_cpu_coherent();
 
 	/*
 	 * In order to boot the secondary CPUs we need to ensure
-- 
1.8.1.2

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox