SUPERH platform development
 help / color / mirror / Atom feed
* [RFC][PATCH 2/2] PM / Domains: Add default power off governor function (v2)
From: Rafael J. Wysocki @ 2011-10-21 23:11 UTC (permalink / raw)
  To: Linux PM list; +Cc: LKML, Linux-sh list, Jean Pihet, Magnus Damm
In-Reply-To: <201110220109.52991.rjw@sisk.pl>

From: Rafael J. Wysocki <rjw@sisk.pl>

Add a function deciding whether or not a given PM domain should
be powered off on the basis of that domain's devices' PM QoS
constraints.

Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---
 drivers/base/power/domain_governor.c |   96 +++++++++++++++++++++++++++++++++++
 include/linux/pm_domain.h            |    7 ++
 2 files changed, 103 insertions(+)

Index: linux/include/linux/pm_domain.h
=================================--- linux.orig/include/linux/pm_domain.h
+++ linux/include/linux/pm_domain.h
@@ -49,6 +49,10 @@ struct generic_pm_domain {
 	int (*start_device)(struct device *dev);
 	int (*stop_device)(struct device *dev);
 	bool (*active_wakeup)(struct device *dev);
+	ktime_t power_off_latency;
+	ktime_t power_on_latency;
+	s64 break_even_ns;
+	s64 min_delta_ns;
 };
 
 static inline struct generic_pm_domain *pd_to_genpd(struct dev_pm_domain *pd)
@@ -64,6 +68,9 @@ struct gpd_link {
 };
 
 struct gpd_gov_dev_data {
+	ktime_t start_latency;
+	ktime_t suspend_latency;
+	ktime_t resume_latency;
 	s64 break_even_ns;
 };
 
Index: linux/drivers/base/power/domain_governor.c
=================================--- linux.orig/drivers/base/power/domain_governor.c
+++ linux/drivers/base/power/domain_governor.c
@@ -35,6 +35,102 @@ bool default_stop_ok(struct device *dev)
 	return constraint_ns > gov_data->break_even_ns;
 }
 
+/* This routine must be executed under the PM domain's lock. */
+static bool default_power_down_ok(struct dev_pm_domain *pd)
+{
+	struct generic_pm_domain *genpd = pd_to_genpd(pd);
+	struct gpd_link *link;
+	struct pm_domain_data *pdd;
+	ktime_t off_time, on_time;
+	s64 delta_ns, min_delta_ns;
+
+	on_time = genpd->power_on_latency;
+	/* Check if slave domains can be off for enough time. */
+	delta_ns = ktime_to_ns(ktime_add(genpd->power_off_latency, on_time));
+	min_delta_ns = 0;
+	/* All slave domains have been powered off at this point. */
+	list_for_each_entry(link, &genpd->master_links, master_node) {
+		if (delta_ns > link->slave->min_delta_ns)
+			return false;
+
+		delta_ns = link->slave->min_delta_ns - delta_ns;
+		if (delta_ns < min_delta_ns)
+			min_delta_ns = delta_ns;
+	}
+
+	genpd->min_delta_ns = min_delta_ns;
+
+	/* Compute the total time needed to power off the domain. */
+	off_time = ktime_set(0, 0);
+	/* All devices have been stopped at this point. */
+	list_for_each_entry(pdd, &genpd->dev_list, list_node) {
+		struct gpd_gov_dev_data *gov_data;
+
+		if (!pdd->dev->driver)
+			continue;
+
+		gov_data = to_gpd_data(pdd)->gov_data;
+		if (!gov_data)
+			continue;
+
+		off_time = ktime_add(off_time, gov_data->suspend_latency);
+	}
+	off_time = ktime_add(off_time, genpd->power_off_latency);
+
+	/*
+	 * For each device in the domain compute the difference between the
+	 * QoS value and the total time required to bring the device back
+	 * assuming that the domain will be powered off and compute the minimum
+	 * of those.
+	 */
+	min_delta_ns = 0;
+	on_time = ktime_add(on_time, off_time);
+	list_for_each_entry(pdd, &genpd->dev_list, list_node) {
+		struct gpd_gov_dev_data *gov_data;
+		struct device *dev = pdd->dev;
+		ktime_t dev_up_time;
+		s32 constraint;
+		s64 constraint_ns;
+
+		if (!dev->driver)
+			continue;
+
+		gov_data = to_gpd_data(pdd)->gov_data;
+		if (gov_data) {
+			dev_up_time = ktime_add(on_time,
+						gov_data->resume_latency);
+			dev_up_time = ktime_add(dev_up_time,
+						gov_data->start_latency);
+		} else {
+			dev_up_time = on_time;
+		}
+
+		constraint = dev_pm_qos_read_value(dev);
+		if (constraint < 0)
+			return false;
+		else if (constraint = 0) /* 0 means "don't care" */
+			continue;
+
+		constraint_ns = constraint;
+		constraint_ns *= NSEC_PER_USEC;
+		delta_ns = constraint_ns - ktime_to_ns(dev_up_time);
+		if (min_delta_ns > delta_ns)
+			min_delta_ns = delta_ns;
+	}
+
+	/* Compare the computed delta with the break even value. */
+	if (min_delta_ns < genpd->break_even_ns)
+		return false;
+
+	/* Store the computed value for the masters to use. */
+	if (genpd->min_delta_ns > min_delta_ns)
+		genpd->min_delta_ns = min_delta_ns;
+
+	/* The domain can be powered off. */
+	return true;
+}
+
 struct dev_power_governor simple_qos_governor = {
 	.stop_ok = default_stop_ok,
+	.power_down_ok = default_power_down_ok,
 };


^ permalink raw reply

* [RFC][PATCH 1/2] PM / Domains: Add device stop governor function (v2)
From: Rafael J. Wysocki @ 2011-10-21 23:10 UTC (permalink / raw)
  To: Linux PM list; +Cc: LKML, Linux-sh list, Jean Pihet, Magnus Damm
In-Reply-To: <201110220109.52991.rjw@sisk.pl>

From: Rafael J. Wysocki <rjw@sisk.pl>

Add a function deciding whether or not devices should be
stopped in pm_genpd_runtime_suspend() depending on their
PM QoS values.

Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---
 arch/arm/mach-shmobile/pm-sh7372.c   |    4 ++-
 drivers/base/power/Makefile          |    2 -
 drivers/base/power/domain.c          |   29 ++++++++++++++++++----
 drivers/base/power/domain_governor.c |   40 +++++++++++++++++++++++++++++++
 include/linux/pm_domain.h            |   45 +++++++++++++++++++++++++++++++----
 5 files changed, 109 insertions(+), 11 deletions(-)

Index: linux/include/linux/pm_domain.h
=================================--- linux.orig/include/linux/pm_domain.h
+++ linux/include/linux/pm_domain.h
@@ -21,6 +21,7 @@ enum gpd_status {
 
 struct dev_power_governor {
 	bool (*power_down_ok)(struct dev_pm_domain *domain);
+	bool (*stop_ok)(struct device *dev);
 };
 
 struct generic_pm_domain {
@@ -62,8 +63,13 @@ struct gpd_link {
 	struct list_head slave_node;
 };
 
+struct gpd_gov_dev_data {
+	s64 break_even_ns;
+};
+
 struct generic_pm_domain_data {
 	struct pm_domain_data base;
+	struct gpd_gov_dev_data *gov_data;
 	bool need_restore;
 };
 
@@ -73,8 +79,19 @@ static inline struct generic_pm_domain_d
 }
 
 #ifdef CONFIG_PM_GENERIC_DOMAINS
-extern int pm_genpd_add_device(struct generic_pm_domain *genpd,
-			       struct device *dev);
+extern struct dev_power_governor simple_qos_governor;
+
+extern struct generic_pm_domain *dev_to_genpd(struct device *dev);
+extern int __pm_genpd_add_device(struct generic_pm_domain *genpd,
+				 struct device *dev,
+				 struct gpd_gov_dev_data *gov_data);
+
+static inline int pm_genpd_add_device(struct generic_pm_domain *genpd,
+				      struct device *dev)
+{
+	return __pm_genpd_add_device(genpd, dev, NULL);
+}
+
 extern int pm_genpd_remove_device(struct generic_pm_domain *genpd,
 				  struct device *dev);
 extern int pm_genpd_add_subdomain(struct generic_pm_domain *genpd,
@@ -83,8 +100,23 @@ extern int pm_genpd_remove_subdomain(str
 				     struct generic_pm_domain *target);
 extern void pm_genpd_init(struct generic_pm_domain *genpd,
 			  struct dev_power_governor *gov, bool is_off);
+
 extern int pm_genpd_poweron(struct generic_pm_domain *genpd);
+
+extern bool default_stop_ok(struct device *dev);
+
 #else
+
+static inline struct generic_pm_domain *dev_to_genpd(struct device *dev)
+{
+	return ERR_PTR(-ENOSYS);
+}
+static inline int __pm_genpd_add_device(struct generic_pm_domain *genpd,
+					struct device *dev,
+					struct gpd_gov_dev_data *gov_data)
+{
+	return -ENOSYS;
+}
 static inline int pm_genpd_add_device(struct generic_pm_domain *genpd,
 				      struct device *dev)
 {
@@ -105,12 +137,17 @@ static inline int pm_genpd_remove_subdom
 {
 	return -ENOSYS;
 }
-static inline void pm_genpd_init(struct generic_pm_domain *genpd,
-				 struct dev_power_governor *gov, bool is_off) {}
+static inline void pm_genpd_init(struct generic_pm_domain *genpd, bool is_off)
+{
+}
 static inline int pm_genpd_poweron(struct generic_pm_domain *genpd)
 {
 	return -ENOSYS;
 }
+static inline bool default_stop_ok(struct device *dev)
+{
+	return false;
+}
 #endif
 
 #ifdef CONFIG_PM_GENERIC_DOMAINS_RUNTIME
Index: linux/drivers/base/power/domain.c
=================================--- linux.orig/drivers/base/power/domain.c
+++ linux/drivers/base/power/domain.c
@@ -21,7 +21,7 @@ static DEFINE_MUTEX(gpd_list_lock);
 
 #ifdef CONFIG_PM
 
-static struct generic_pm_domain *dev_to_genpd(struct device *dev)
+struct generic_pm_domain *dev_to_genpd(struct device *dev)
 {
 	if (IS_ERR_OR_NULL(dev->pm_domain))
 		return ERR_PTR(-EINVAL);
@@ -403,6 +403,22 @@ static void genpd_power_off_work_fn(stru
 }
 
 /**
+ * genpd_stop_dev - Stop a given device if that's beneficial.
+ * @genpd: PM domain the device belongs to.
+ * @dev: Device to stop.
+ */
+static int genpd_stop_dev(struct generic_pm_domain *genpd, struct device *dev)
+{
+	bool (*stop_ok)(struct device *dev);
+
+	stop_ok = genpd->gov ? genpd->gov->stop_ok : NULL;
+	if (stop_ok && !stop_ok(dev))
+		return -EBUSY;
+
+	return genpd->stop_device(dev);
+}
+
+/**
  * pm_genpd_runtime_suspend - Suspend a device belonging to I/O PM domain.
  * @dev: Device to suspend.
  *
@@ -423,7 +439,7 @@ static int pm_genpd_runtime_suspend(stru
 	might_sleep_if(!genpd->dev_irq_safe);
 
 	if (genpd->stop_device) {
-		int ret = genpd->stop_device(dev);
+		int ret = genpd_stop_dev(genpd, dev);
 		if (ret)
 			return ret;
 	}
@@ -495,7 +511,7 @@ static int pm_genpd_runtime_resume(struc
 		mutex_lock(&genpd->lock);
 	}
 	finish_wait(&genpd->status_wait_queue, &wait);
-	__pm_genpd_restore_device(dev->power.subsys_data->domain_data, genpd);
+	__pm_genpd_restore_device(dev_to_psd(dev)->domain_data, genpd);
 	genpd->resume_count--;
 	genpd_set_active(genpd);
 	wake_up_all(&genpd->status_wait_queue);
@@ -1076,11 +1092,13 @@ static void pm_genpd_complete(struct dev
 #endif /* CONFIG_PM_SLEEP */
 
 /**
- * pm_genpd_add_device - Add a device to an I/O PM domain.
+ * __pm_genpd_add_device - Add a device to an I/O PM domain.
  * @genpd: PM domain to add the device to.
  * @dev: Device to be added.
+ * @gov_data: Set of PM QoS parameters to attach to the device.
  */
-int pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev)
+int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev,
+			  struct gpd_gov_dev_data *gov_data)
 {
 	struct generic_pm_domain_data *gpd_data;
 	struct pm_domain_data *pdd;
@@ -1123,6 +1141,7 @@ int pm_genpd_add_device(struct generic_p
 	gpd_data->base.dev = dev;
 	gpd_data->need_restore = false;
 	list_add_tail(&gpd_data->base.list_node, &genpd->dev_list);
+	gpd_data->gov_data = gov_data;
 
  out:
 	genpd_release_lock(genpd);
Index: linux/drivers/base/power/Makefile
=================================--- linux.orig/drivers/base/power/Makefile
+++ linux/drivers/base/power/Makefile
@@ -3,7 +3,7 @@ obj-$(CONFIG_PM_SLEEP)	+= main.o wakeup.
 obj-$(CONFIG_PM_RUNTIME)	+= runtime.o
 obj-$(CONFIG_PM_TRACE_RTC)	+= trace.o
 obj-$(CONFIG_PM_OPP)	+= opp.o
-obj-$(CONFIG_PM_GENERIC_DOMAINS)	+=  domain.o
+obj-$(CONFIG_PM_GENERIC_DOMAINS)	+=  domain.o domain_governor.o
 obj-$(CONFIG_HAVE_CLK)	+= clock_ops.o
 
 ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG
Index: linux/drivers/base/power/domain_governor.c
=================================--- /dev/null
+++ linux/drivers/base/power/domain_governor.c
@@ -0,0 +1,40 @@
+/*
+ * drivers/base/power/domain_governor.c - Governors for device PM domains.
+ *
+ * Copyright (C) 2011 Rafael J. Wysocki <rjw@sisk.pl>, Renesas Electronics Corp.
+ *
+ * This file is released under the GPLv2.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/pm_domain.h>
+#include <linux/pm_qos.h>
+
+bool default_stop_ok(struct device *dev)
+{
+	struct gpd_gov_dev_data *gov_data;
+	s64 constraint_ns;
+	s32 constraint;
+
+	dev_dbg(dev, "%s()\n", __func__);
+
+	gov_data = to_gpd_data(dev_to_psd(dev)->domain_data)->gov_data;
+	if (!gov_data)
+		return true;
+
+	constraint = dev_pm_qos_read_value(dev);
+	if (constraint < 0)
+		return false;
+	else if (constraint = 0) /* 0 means "don't care" */
+		return true;
+
+	constraint_ns = constraint;
+	constraint_ns *= NSEC_PER_USEC;
+
+	return constraint_ns > gov_data->break_even_ns;
+}
+
+struct dev_power_governor simple_qos_governor = {
+	.stop_ok = default_stop_ok,
+};
Index: linux/arch/arm/mach-shmobile/pm-sh7372.c
=================================--- linux.orig/arch/arm/mach-shmobile/pm-sh7372.c
+++ linux/arch/arm/mach-shmobile/pm-sh7372.c
@@ -161,13 +161,15 @@ static bool sh7372_power_down_forbidden(
 
 struct dev_power_governor sh7372_always_on_gov = {
 	.power_down_ok = sh7372_power_down_forbidden,
+	.stop_ok = default_stop_ok,
 };
 
 void sh7372_init_pm_domain(struct sh7372_pm_domain *sh7372_pd)
 {
 	struct generic_pm_domain *genpd = &sh7372_pd->genpd;
+	struct dev_power_governor *gov = sh7372_pd->gov;
 
-	pm_genpd_init(genpd, sh7372_pd->gov, false);
+	pm_genpd_init(genpd, gov ? : &simple_qos_governor, false);
 	genpd->stop_device = pm_clk_suspend;
 	genpd->start_device = pm_clk_resume;
 	genpd->dev_irq_safe = true;


^ permalink raw reply

* [RFC][PATCH 0/2] PM: Generic PM domains and device PM QoS (v2)
From: Rafael J. Wysocki @ 2011-10-21 23:09 UTC (permalink / raw)
  To: Linux PM list; +Cc: LKML, Linux-sh list, Jean Pihet, Magnus Damm

Hi,

This patchset is a refresh of patches introducing simple PM QoS governor
functions for PM domains.  The patches still haven't been tested properly,
although they should build.  The purpose of them is mainly to illustrate
how PM QoS may be used with PM domains to control device runtime PM.

Thanks,
Rafael


^ permalink raw reply

* Re: Possible regression in kexec on ARM ARMv6 and ARMv7 cores
From: Will Deacon @ 2011-10-21  9:15 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20111021085958.GC21850@verge.net.au>

On Fri, Oct 21, 2011 at 09:59:58AM +0100, Simon Horman wrote:
> On Fri, Oct 21, 2011 at 09:46:41AM +0100, Will Deacon wrote:
> > The more difficult case is when you want to offline the secondary CPUs into
> > a pen and then boot them in the new kernel. I did get some of this working,
> > but there are outstanding issues with whether the pen should be at a fixed
> > location or not. If not, then we need a way to tell the new kernel where it
> > is, which may involve updating the DT blob...
> 
> Is the implication that the (working) callback method does not
> give the second kernel any secondary CPUs?

What the callback does it up to you. You just need to make sure that you can
cope with the kernel disappearing later on, so you'll probably need some
hardware mechanism for offlining a CPU (for example, placing it in SRAM
or cutting the power).

Will

^ permalink raw reply

* Re: Possible regression in kexec on ARM ARMv6 and ARMv7 cores
From: Simon Horman @ 2011-10-21  8:59 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20111021084641.GA30168@mudshark.cambridge.arm.com>

On Fri, Oct 21, 2011 at 09:46:41AM +0100, Will Deacon wrote:
> On Fri, Oct 21, 2011 at 09:34:26AM +0100, Simon Horman wrote:
> > I have tested the kexec/mmu-off branch of your tree on the UP board
> > I mentioned above and kexec works :)
> 
> Hurrah! Thanks for giving it a spin.
> 
> > > You mention UP in particular, which I will test.
> > > Do you have any thoughts on SMP?
> 
> Yes. Currently [i.e. on my branch above] you can do SMP kexec using the CPU
> hotplug platform_cpu_kill callback to take down the CPUs in some
> platform-specific manner.

Thanks, I will take a look into it.

> The more difficult case is when you want to offline the secondary CPUs into
> a pen and then boot them in the new kernel. I did get some of this working,
> but there are outstanding issues with whether the pen should be at a fixed
> location or not. If not, then we need a way to tell the new kernel where it
> is, which may involve updating the DT blob...

Is the implication that the (working) callback method does not
give the second kernel any secondary CPUs?

^ permalink raw reply

* Re: Possible regression in kexec on ARM ARMv6 and ARMv7 cores
From: Will Deacon @ 2011-10-21  8:46 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20111021083426.GA16088@verge.net.au>

On Fri, Oct 21, 2011 at 09:34:26AM +0100, Simon Horman wrote:
> I have tested the kexec/mmu-off branch of your tree on the UP board
> I mentioned above and kexec works :)

Hurrah! Thanks for giving it a spin.

> > You mention UP in particular, which I will test.
> > Do you have any thoughts on SMP?

Yes. Currently [i.e. on my branch above] you can do SMP kexec using the CPU
hotplug platform_cpu_kill callback to take down the CPUs in some
platform-specific manner.

The more difficult case is when you want to offline the secondary CPUs into
a pen and then boot them in the new kernel. I did get some of this working,
but there are outstanding issues with whether the pen should be at a fixed
location or not. If not, then we need a way to tell the new kernel where it
is, which may involve updating the DT blob...

Will

^ permalink raw reply

* Re: Possible regression in kexec on ARM ARMv6 and ARMv7 cores
From: Simon Horman @ 2011-10-21  8:34 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20111020080823.GA2716@verge.net.au>

On Thu, Oct 20, 2011 at 05:08:24PM +0900, Simon Horman wrote:
> On Thu, Oct 20, 2011 at 08:01:06AM +0100, Will Deacon wrote:
> > On Thu, Oct 20, 2011 at 05:24:45AM +0100, Simon Horman wrote:
> > > Hi Will, Hi All,
> > 
> > Hi Simon,
> 
> Hi Will,
> 
> > > it appears that "ARM: proc: add definition of cpu_reset for
> > >  ARMv6 and ARMv7 cores" (f4daf06fc23b99df5ca5b3e892428b91e148cc52),
> > > which was introduced for 3.1-rc1, causes a regression and that
> > > kexec no longer works on ARM. The board that I am testing
> > > on is a Renesas Mackerel which has an SH7372 (ARMv7) processor.
> > 
> > Wow, I'm surprised the old code worked at all on an ARMv7 CPU! It's certainly
> > highly unlikely to work by the letter of the architecture, so I guess the
> > planets aligned in just the right way for your particular implementation.
> > 
> > Please can you try my kexec/mmu-off patches? They should add the bits and
> > pieces you need for kexec to work reliably on a UP system. I plan to finish
> > these off next week in Prague so hopefully they'll hit mainline in the near
> > future.
> > 
> > https://github.com/wdeacon/linux-wd/commits/kexec/mmu-off
> 
> Thanks, I will try your patches and let you know how I go.

I have tested the kexec/mmu-off branch of your tree on the UP board
I mentioned above and kexec works :)

> You mention UP in particular, which I will test.
> Do you have any thoughts on SMP?

^ permalink raw reply

* Re: Ecovec in current sh-latest
From: Kuninori Morimoto @ 2011-10-21  1:57 UTC (permalink / raw)
  To: linux-sh
In-Reply-To: <Pine.LNX.4.64.1109020025350.15166@axis700.grange>


Hi Magnus, Paul

> > > To get ecovec to run with today's sh-latest (pretty much the same with 
> > > Linux' tree) the following patches have to be reverted:
> > > 
> > > commit 794d78fea51504bad3880d14f354a9847f318f25
> > > Author: Magnus Damm <damm@opensource.se>
> > > Date:   Tue Jun 21 07:55:12 2011 +0000
> > > 
> > >     drivers: sh: late disabling of clocks V2
> > > 
> > Do we know which driver that's the problem for the ecovec case?
> 
> I see at least two drivers misbehaving: ethernet is failing to perform 
> dhcp for nfs root-mount, and LCD gets an image at boot and then slowly 
> fade out.

My renesas_usbhs driver breaks too in SH7724 ecovec board.
So I debuged it.

when my driver call pm_runtime_get_sync(),
then, arch/sh/kernel/cpu/hwblk.c :: hwblk_enable() are called,
and it enabled my driver's MSTP bit.

But clk_late_init() disabled it.

Does hwblk/pm_runtime (?) didn't care clk->usecount ?

Best regards
---
Kuninori Morimoto

^ permalink raw reply

* Re: Ecovec in current sh-latest
From: Kuninori Morimoto @ 2011-10-21  1:53 UTC (permalink / raw)
  To: linux-sh
In-Reply-To: <Pine.LNX.4.64.1109020025350.15166@axis700.grange>


Hi Magnus, Paul

> > > To get ecovec to run with today's sh-latest (pretty much the same with 
> > > Linux' tree) the following patches have to be reverted:
> > > 
> > > commit 794d78fea51504bad3880d14f354a9847f318f25
> > > Author: Magnus Damm <damm@opensource.se>
> > > Date:   Tue Jun 21 07:55:12 2011 +0000
> > > 
> > >     drivers: sh: late disabling of clocks V2
> > > 
> > Do we know which driver that's the problem for the ecovec case?
> 
> I see at least two drivers misbehaving: ethernet is failing to perform 
> dhcp for nfs root-mount, and LCD gets an image at boot and then slowly 
> fade out.

My renesas_usbhs driver breaks too in SH7724 ecovec board.
So I debuged it.

when my driver call pm_runtime_get_sync(),
then, arch/sh/kernel/cpu/hwblk.c :: hwblk_enable() are called,
and it enabled my driver's MSTP bit.

But clk_late_init() disabled it.

Does hwblk/pm_runtime (?) didn't care clk->usecount ?

Best regards
---
Kuninori Morimoto

^ permalink raw reply

* Re: Possible regression in kexec on ARM ARMv6 and ARMv7 cores
From: Simon Horman @ 2011-10-20  8:08 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20111020070105.GA28548@mudshark.cambridge.arm.com>

On Thu, Oct 20, 2011 at 08:01:06AM +0100, Will Deacon wrote:
> On Thu, Oct 20, 2011 at 05:24:45AM +0100, Simon Horman wrote:
> > Hi Will, Hi All,
> 
> Hi Simon,

Hi Will,

> > it appears that "ARM: proc: add definition of cpu_reset for
> >  ARMv6 and ARMv7 cores" (f4daf06fc23b99df5ca5b3e892428b91e148cc52),
> > which was introduced for 3.1-rc1, causes a regression and that
> > kexec no longer works on ARM. The board that I am testing
> > on is a Renesas Mackerel which has an SH7372 (ARMv7) processor.
> 
> Wow, I'm surprised the old code worked at all on an ARMv7 CPU! It's certainly
> highly unlikely to work by the letter of the architecture, so I guess the
> planets aligned in just the right way for your particular implementation.
> 
> Please can you try my kexec/mmu-off patches? They should add the bits and
> pieces you need for kexec to work reliably on a UP system. I plan to finish
> these off next week in Prague so hopefully they'll hit mainline in the near
> future.
> 
> https://github.com/wdeacon/linux-wd/commits/kexec/mmu-off

Thanks, I will try your patches and let you know how I go.

You mention UP in particular, which I will test.
Do you have any thoughts on SMP?


^ permalink raw reply

* Re: Possible regression in kexec on ARM ARMv6 and ARMv7 cores
From: Will Deacon @ 2011-10-20  7:01 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20111020042444.GA20260@verge.net.au>

On Thu, Oct 20, 2011 at 05:24:45AM +0100, Simon Horman wrote:
> Hi Will, Hi All,

Hi Simon,

> it appears that "ARM: proc: add definition of cpu_reset for
>  ARMv6 and ARMv7 cores" (f4daf06fc23b99df5ca5b3e892428b91e148cc52),
> which was introduced for 3.1-rc1, causes a regression and that
> kexec no longer works on ARM. The board that I am testing
> on is a Renesas Mackerel which has an SH7372 (ARMv7) processor.

Wow, I'm surprised the old code worked at all on an ARMv7 CPU! It's certainly
highly unlikely to work by the letter of the architecture, so I guess the
planets aligned in just the right way for your particular implementation.

Please can you try my kexec/mmu-off patches? They should add the bits and
pieces you need for kexec to work reliably on a UP system. I plan to finish
these off next week in Prague so hopefully they'll hit mainline in the near
future.

https://github.com/wdeacon/linux-wd/commits/kexec/mmu-off

Will

^ permalink raw reply

* Possible regression in kexec on ARM ARMv6 and ARMv7 cores
From: Simon Horman @ 2011-10-20  4:24 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Will, Hi All,

it appears that "ARM: proc: add definition of cpu_reset for
 ARMv6 and ARMv7 cores" (f4daf06fc23b99df5ca5b3e892428b91e148cc52),
which was introduced for 3.1-rc1, causes a regression and that
kexec no longer works on ARM. The board that I am testing
on is a Renesas Mackerel which has an SH7372 (ARMv7) processor.

I have included the patch below for reference.


commit f4daf06fc23b99df5ca5b3e892428b91e148cc52
Author: Will Deacon <will.deacon@arm.com>
Date:   Mon Jun 6 12:27:34 2011 +0100

    ARM: proc: add definition of cpu_reset for ARMv6 and ARMv7 cores
    
    This patch adds simple definitions of cpu_reset for ARMv6 and ARMv7
    cores, which disable the MMU via the SCTLR.
    
    Signed-off-by: Will Deacon <will.deacon@arm.com>

diff --git a/arch/arm/mm/proc-v6.S b/arch/arm/mm/proc-v6.S
index 5ec1543..aedf3c5 100644
--- a/arch/arm/mm/proc-v6.S
+++ b/arch/arm/mm/proc-v6.S
@@ -56,6 +56,11 @@ ENTRY(cpu_v6_proc_fin)
  */
 	.align	5
 ENTRY(cpu_v6_reset)
+	mrc	p15, 0, r1, c1, c0, 0		@ ctrl register
+	bic	r1, r1, #0x1			@ ...............m
+	mcr	p15, 0, r1, c1, c0, 0		@ disable MMU
+	mov	r1, #0
+	mcr	p15, 0, r1, c7, c5, 4		@ ISB
 	mov	pc, r0
 
 /*
diff --git a/arch/arm/mm/proc-v7.S b/arch/arm/mm/proc-v7.S
index 5932854..54d1a63 100644
--- a/arch/arm/mm/proc-v7.S
+++ b/arch/arm/mm/proc-v7.S
@@ -58,9 +58,16 @@ ENDPROC(cpu_v7_proc_fin)
  *	to what would be the reset vector.
  *
  *	- loc   - location to jump to for soft reset
+ *
+ *	This code must be executed using a flat identity mapping with
+ *      caches disabled.
  */
 	.align	5
 ENTRY(cpu_v7_reset)
+	mrc	p15, 0, r1, c1, c0, 0		@ ctrl register
+	bic	r1, r1, #0x1			@ ...............m
+	mcr	p15, 0, r1, c1, c0, 0		@ disable MMU
+	isb
 	mov	pc, r0
 ENDPROC(cpu_v7_reset)
 

^ permalink raw reply related

* [PATCH 5/5] ARM: mach-shmobile: add SMSC9221 support
From: Kuninori Morimoto @ 2011-10-20  3:02 UTC (permalink / raw)
  To: linux-sh

Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
---
 arch/arm/mach-shmobile/board-bonito.c |   34 +++++++++++++++++++++++++++++++++
 1 files changed, 34 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-shmobile/board-bonito.c b/arch/arm/mach-shmobile/board-bonito.c
index 08c3795..e93c61d 100644
--- a/arch/arm/mach-shmobile/board-bonito.c
+++ b/arch/arm/mach-shmobile/board-bonito.c
@@ -96,6 +96,8 @@
 #define FPGA_IRQ0		(FPGA_IRQ_BASE)
 #define FPGA_IRQ1		(FPGA_IRQ_BASE + 16)
 
+#define FPGA_ETH_IRQ		(FPGA_IRQ0 + 15)
+
 static u16 fpga_read(u32 offset)
 {
 	return __raw_readw(0xf0003000 + offset);
@@ -279,6 +281,37 @@ static struct platform_device lcdc0_device = {
 };
 
 /*
+ * SMSC 9221
+ */
+static struct resource smsc_resources[] = {
+	[0] = {
+		.start		= 0x18010000,
+		.end		= 0x18011000 - 1,
+		.flags		= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start		= FPGA_ETH_IRQ,
+		.flags		= IORESOURCE_IRQ,
+	},
+};
+
+static struct smsc911x_platform_config smsc_platdata = {
+	.flags		= SMSC911X_USE_16BIT,
+	.phy_interface	= PHY_INTERFACE_MODE_MII,
+	.irq_polarity	= SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
+	.irq_type	= SMSC911X_IRQ_TYPE_PUSH_PULL,
+};
+
+static struct platform_device smsc_device = {
+	.name		= "smsc911x",
+	.dev  = {
+		.platform_data = &smsc_platdata,
+	},
+	.resource	= smsc_resources,
+	.num_resources	= ARRAY_SIZE(smsc_resources),
+};
+
+/*
  * core board devices
  */
 static struct platform_device *bonito_core_devices[] __initdata = {
@@ -289,6 +322,7 @@ static struct platform_device *bonito_core_devices[] __initdata = {
  */
 static struct platform_device *bonito_base_devices[] __initdata = {
 	&lcdc0_device,
+	&smsc_device,
 };
 
 /*
-- 
1.7.4.1


^ permalink raw reply related

* [PATCH 4/5] ARM: mach-shmobile: add FPGA irq demux
From: Kuninori Morimoto @ 2011-10-20  3:02 UTC (permalink / raw)
  To: linux-sh

Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
---
 arch/arm/mach-shmobile/board-bonito.c |   81 ++++++++++++++++++++++++++++++++-
 1 files changed, 80 insertions(+), 1 deletions(-)

diff --git a/arch/arm/mach-shmobile/board-bonito.c b/arch/arm/mach-shmobile/board-bonito.c
index 64eea4b..08c3795 100644
--- a/arch/arm/mach-shmobile/board-bonito.c
+++ b/arch/arm/mach-shmobile/board-bonito.c
@@ -26,6 +26,7 @@
 #include <linux/irq.h>
 #include <linux/platform_device.h>
 #include <linux/gpio.h>
+#include <linux/smsc911x.h>
 #include <mach/common.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -75,14 +76,26 @@
 /*
  * FPGA
  */
+
+#define IRQSR0		0x0020
+#define IRQSR1		0x0022
+#define IRQMR0		0x0030
+#define IRQMR1		0x0032
 #define BUSSWMR1	0x0070
 #define BUSSWMR2	0x0072
 #define BUSSWMR3	0x0074
 #define BUSSWMR4	0x0076
-
 #define LCDCR		0x10B4
+#define DEVRSTCR1	0x10D0
+#define DEVRSTCR2	0x10D2
 #define A1MDSR		0x10E0
 #define BVERR		0x1100
+
+/* FPGA IRQ */
+#define FPGA_IRQ_BASE		(512)
+#define FPGA_IRQ0		(FPGA_IRQ_BASE)
+#define FPGA_IRQ1		(FPGA_IRQ_BASE + 16)
+
 static u16 fpga_read(u32 offset)
 {
 	return __raw_readw(0xf0003000 + offset);
@@ -93,6 +106,71 @@ static void fpga_write(u32 offset, u16 val)
 	__raw_writew(val, 0xf0003000 + offset);
 }
 
+static void fpga_irq_disable(struct irq_data *data)
+{
+	unsigned int irq = data->irq;
+	u32 addr = (irq < 1016) ? IRQMR0 : IRQMR1;
+	int shift = irq % 16;
+
+	fpga_write(addr, fpga_read(addr) | (1 << shift));
+}
+
+static void fpga_irq_enable(struct irq_data *data)
+{
+	unsigned int irq = data->irq;
+	u32 addr = (irq < 1016) ? IRQMR0 : IRQMR1;
+	int shift = irq % 16;
+
+	fpga_write(addr, fpga_read(addr) & ~(1 << shift));
+}
+
+static struct irq_chip fpga_irq_chip __read_mostly = {
+	.name		= "bonito FPGA",
+	.irq_mask	= fpga_irq_disable,
+	.irq_unmask	= fpga_irq_enable,
+};
+
+static void fpga_irq_demux(unsigned int irq, struct irq_desc *desc)
+{
+	u32 val =  fpga_read(IRQSR1) << 16 |
+		   fpga_read(IRQSR0);
+	u32 mask = fpga_read(IRQMR1) << 16 |
+		   fpga_read(IRQMR0);
+
+	int i;
+
+	val &= ~mask;
+
+	for (i = 0; i < 32; i++) {
+		if (!(val & (1 << i)))
+			continue;
+
+		generic_handle_irq(FPGA_IRQ_BASE + i);
+	}
+}
+
+static void fpga_init(void)
+{
+	int i;
+
+	fpga_write(IRQMR0, 0xffff); /* mask all */
+	fpga_write(IRQMR1, 0xffff); /* mask all */
+
+	/* Device reset */
+	fpga_write(DEVRSTCR1,
+		   (1 << 2));	/* Eth */
+
+	/* FPGA irq require special handling */
+	for (i = FPGA_IRQ_BASE; i < FPGA_IRQ_BASE + 32; i++) {
+		irq_set_chip_and_handler_name(i, &fpga_irq_chip,
+					      handle_level_irq, "level");
+		set_irq_flags(i, IRQF_VALID); /* yuck */
+	}
+
+	irq_set_chained_handler(evt2irq(0x0340), fpga_irq_demux);
+	irq_set_irq_type(evt2irq(0x0340), IRQ_TYPE_LEVEL_LOW);
+}
+
 /*
 * PMIC settings
 *
@@ -274,6 +352,7 @@ static void __init bonito_init(void)
 	u16 val;
 
 	r8a7740_pinmux_init();
+	fpga_init();
 
 	pmic_settings = pmic_do_2A;
 
-- 
1.7.4.1


^ permalink raw reply related

* [PATCH 3/5] ARM: mach-shmobile: bonito: fixup fpga_write()
From: Kuninori Morimoto @ 2011-10-20  3:02 UTC (permalink / raw)
  To: linux-sh

mask of fpga_write() was a puzzling parameter.

Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
---
 arch/arm/mach-shmobile/board-bonito.c |   10 +++-------
 1 files changed, 3 insertions(+), 7 deletions(-)

diff --git a/arch/arm/mach-shmobile/board-bonito.c b/arch/arm/mach-shmobile/board-bonito.c
index 3a91e9c..64eea4b 100644
--- a/arch/arm/mach-shmobile/board-bonito.c
+++ b/arch/arm/mach-shmobile/board-bonito.c
@@ -88,13 +88,9 @@ static u16 fpga_read(u32 offset)
 	return __raw_readw(0xf0003000 + offset);
 }
 
-static void fpga_write(u32 offset, u16 val, u16 mask)
+static void fpga_write(u32 offset, u16 val)
 {
-	u16 tmp;
-
-	tmp = fpga_read(offset);
-	tmp = (tmp & ~mask) | (val & mask);
-	__raw_writew(tmp, 0xf0003000 + offset);
+	__raw_writew(val, 0xf0003000 + offset);
 }
 
 /*
@@ -372,7 +368,7 @@ static void __init bonito_init(void)
 			gpio_direction_output(GPIO_PORT61, 1);
 
 			/* backlight on */
-			fpga_write(LCDCR, 1, 1);
+			fpga_write(LCDCR, 1);
 
 			/*  drivability Max */
 			__raw_writew(0x00FF , VCCQ1LCDCR);
-- 
1.7.4.1


^ permalink raw reply related

* [PATCH 2/5] ARM: mach-shmobile: bonito: make sure static function
From: Kuninori Morimoto @ 2011-10-20  3:01 UTC (permalink / raw)
  To: linux-sh

fpga_xxx() were static functions

Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
---
 arch/arm/mach-shmobile/board-bonito.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/arm/mach-shmobile/board-bonito.c b/arch/arm/mach-shmobile/board-bonito.c
index a00de29..3a91e9c 100644
--- a/arch/arm/mach-shmobile/board-bonito.c
+++ b/arch/arm/mach-shmobile/board-bonito.c
@@ -83,12 +83,12 @@
 #define LCDCR		0x10B4
 #define A1MDSR		0x10E0
 #define BVERR		0x1100
-u16 fpga_read(u32 offset)
+static u16 fpga_read(u32 offset)
 {
 	return __raw_readw(0xf0003000 + offset);
 }
 
-void fpga_write(u32 offset, u16 val, u16 mask)
+static void fpga_write(u32 offset, u16 val, u16 mask)
 {
 	u16 tmp;
 
-- 
1.7.4.1


^ permalink raw reply related

* [PATCH 1/5] ARM: mach-shmobile: r8a7740: use INTC instead of GIC
From: Kuninori Morimoto @ 2011-10-20  3:01 UTC (permalink / raw)
  To: linux-sh

R8A7740 GIC can not get external IRQx interrupt directly
without GIC - INTC demux support.

Current AG5 is using GIC - INTCS demux with
special irq relocation. but GIC - INTCA demux
is still not supported and it needs irq number re-mapping.

OTOH, normal INTC support as before is very enough,
because R8A7740 is not SMP.
This patch adds INTCA/INTCS support instead of GIC.

it is based on v0.1b manual

Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
---
 arch/arm/mach-shmobile/Kconfig         |    1 -
 arch/arm/mach-shmobile/Makefile        |    2 +-
 arch/arm/mach-shmobile/board-bonito.c  |   21 +-
 arch/arm/mach-shmobile/intc-r8a7740.c  |  612 +++++++++++++++++++++++++++++++-
 arch/arm/mach-shmobile/setup-r8a7740.c |   46 ++--
 5 files changed, 625 insertions(+), 57 deletions(-)

diff --git a/arch/arm/mach-shmobile/Kconfig b/arch/arm/mach-shmobile/Kconfig
index 37a13e2..8e65062 100644
--- a/arch/arm/mach-shmobile/Kconfig
+++ b/arch/arm/mach-shmobile/Kconfig
@@ -32,7 +32,6 @@ config ARCH_R8A7740
 	select CPU_V7
 	select SH_CLK_CPG
 	select ARCH_WANT_OPTIONAL_GPIOLIB
-	select ARM_GIC
 
 comment "SH-Mobile Board Type"
 
diff --git a/arch/arm/mach-shmobile/Makefile b/arch/arm/mach-shmobile/Makefile
index 1dd1eb9..abdae89 100644
--- a/arch/arm/mach-shmobile/Makefile
+++ b/arch/arm/mach-shmobile/Makefile
@@ -31,7 +31,7 @@ obj-$(CONFIG_ARCH_SH7367)	+= entry-intc.o
 obj-$(CONFIG_ARCH_SH7377)	+= entry-intc.o
 obj-$(CONFIG_ARCH_SH7372)	+= entry-intc.o
 obj-$(CONFIG_ARCH_SH73A0)	+= entry-gic.o
-obj-$(CONFIG_ARCH_R8A7740)	+= entry-gic.o
+obj-$(CONFIG_ARCH_R8A7740)	+= entry-intc.o
 
 # PM objects
 obj-$(CONFIG_SUSPEND)		+= suspend.o
diff --git a/arch/arm/mach-shmobile/board-bonito.c b/arch/arm/mach-shmobile/board-bonito.c
index c697f9f..a00de29 100644
--- a/arch/arm/mach-shmobile/board-bonito.c
+++ b/arch/arm/mach-shmobile/board-bonito.c
@@ -188,7 +188,7 @@ static struct resource lcdc0_resources[] = {
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= gic_spi(177),
+		.start	= intcs_evt2irq(0x0580),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -231,23 +231,6 @@ static struct map_desc bonito_io_desc[] __initdata = {
 		.length		= 160 << 20,
 		.type		= MT_DEVICE_NONSHARED
 	},
-	/*
-	 * for gic_dist_base/gic_cpu_base
-	 * 0xc2000000-0xc2001000 -> 0xf0000000-0xf0001000
-	 * 0xc2800000-0xc2801000 -> 0xf0001000-0xf0002000
-	 * */
-	{
-		.virtual	= 0xf0000000,
-		.pfn		= __phys_to_pfn(0xc2000000),
-		.length		= PAGE_SIZE,
-		.type		= MT_DEVICE_NONSHARED
-	},
-	{
-		.virtual	= 0xf0001000,
-		.pfn		= __phys_to_pfn(0xc2800000),
-		.length		= PAGE_SIZE,
-		.type		= MT_DEVICE_NONSHARED
-	},
 #ifdef CONFIG_CACHE_L2X0
 	/*
 	 * for l2x0_init()
@@ -426,7 +409,7 @@ struct sys_timer bonito_timer = {
 MACHINE_START(BONITO, "bonito")
 	.map_io		= bonito_map_io,
 	.init_irq	= r8a7740_init_irq,
-	.handle_irq	= shmobile_handle_irq_gic,
+	.handle_irq	= shmobile_handle_irq_intc,
 	.init_machine	= bonito_init,
 	.timer		= &bonito_timer,
 MACHINE_END
diff --git a/arch/arm/mach-shmobile/intc-r8a7740.c b/arch/arm/mach-shmobile/intc-r8a7740.c
index c62a205..272c84c 100644
--- a/arch/arm/mach-shmobile/intc-r8a7740.c
+++ b/arch/arm/mach-shmobile/intc-r8a7740.c
@@ -18,28 +18,614 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/io.h>
-#include <asm/hardware/gic.h>
+#include <linux/sh_intc.h>
+#include <mach/intc.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
 
-#define INTA_CTRL	0xe605807c
+/*
+ *		INTCA
+ */
+enum {
+	UNUSED_INTCA = 0,
+
+	/* interrupt sources INTCA */
+	DIRC,
+	ATAPI,
+	IIC1_ALI, IIC1_TACKI, IIC1_WAITI, IIC1_DTEI,
+	AP_ARM_COMMTX, AP_ARM_COMMRX,
+	MFI, MFIS,
+	BBIF1, BBIF2,
+	USBHSDMAC,
+	USBF_OUL_SOF, USBF_IXL_INT,
+	SGX540,
+	CMT1_0, CMT1_1, CMT1_2, CMT1_3,
+	CMT2,
+	CMT3,
+	KEYSC,
+	SCIFA0, SCIFA1, SCIFA2, SCIFA3,
+	MSIOF2, MSIOF1,
+	SCIFA4, SCIFA5, SCIFB,
+	FLCTL_FLSTEI, FLCTL_FLTENDI, FLCTL_FLTREQ0I, FLCTL_FLTREQ1I,
+	SDHI0_0, SDHI0_1, SDHI0_2, SDHI0_3,
+	SDHI1_0, SDHI1_1, SDHI1_2, SDHI1_3,
+	AP_ARM_L2CINT,
+	IRDA,
+	TPU0,
+	SCIFA6, SCIFA7,
+	GbEther,
+	ICBS0,
+	DDM,
+	SDHI2_0, SDHI2_1, SDHI2_2, SDHI2_3,
+	RWDT0,
+	DMAC1_1_DEI0, DMAC1_1_DEI1, DMAC1_1_DEI2, DMAC1_1_DEI3,
+	DMAC1_2_DEI4, DMAC1_2_DEI5, DMAC1_2_DADERR,
+	DMAC2_1_DEI0, DMAC2_1_DEI1, DMAC2_1_DEI2, DMAC2_1_DEI3,
+	DMAC2_2_DEI4, DMAC2_2_DEI5, DMAC2_2_DADERR,
+	DMAC3_1_DEI0, DMAC3_1_DEI1, DMAC3_1_DEI2, DMAC3_1_DEI3,
+	DMAC3_2_DEI4, DMAC3_2_DEI5, DMAC3_2_DADERR,
+	SHWYSTAT_RT, SHWYSTAT_HS, SHWYSTAT_COM,
+	USBH_INT, USBH_OHCI, USBH_EHCI, USBH_PME, USBH_BIND,
+	RSPI_OVRF, RSPI_SPTEF, RSPI_SPRF,
+	SPU2_0, SPU2_1,
+	FSI, FMSI,
+	IPMMU,
+	AP_ARM_CTIIRQ, AP_ARM_PMURQ,
+	MFIS2,
+	CPORTR2S,
+	CMT14, CMT15,
+	MMCIF_0, MMCIF_1, MMCIF_2,
+	SIM_ERI, SIM_RXI, SIM_TXI, SIM_TEI,
+	STPRO_0, STPRO_1, STPRO_2, STPRO_3, STPRO_4,
+
+	/* interrupt groups INTCA */
+	DMAC1_1, DMAC1_2,
+	DMAC2_1, DMAC2_2,
+	DMAC3_1, DMAC3_2,
+	AP_ARM1, AP_ARM2,
+	SDHI0, SDHI1, SDHI2,
+	SHWYSTAT,
+	USBF, USBH1, USBH2,
+	RSPI, SPU2, FLCTL, IIC1,
+};
+
+static struct intc_vect intca_vectors[] __initdata = {
+	INTC_VECT(DIRC,			0x0560),
+	INTC_VECT(ATAPI,		0x05E0),
+	INTC_VECT(IIC1_ALI,		0x0780),
+	INTC_VECT(IIC1_TACKI,		0x07A0),
+	INTC_VECT(IIC1_WAITI,		0x07C0),
+	INTC_VECT(IIC1_DTEI,		0x07E0),
+	INTC_VECT(AP_ARM_COMMTX,	0x0840),
+	INTC_VECT(AP_ARM_COMMRX,	0x0860),
+	INTC_VECT(MFI,			0x0900),
+	INTC_VECT(MFIS,			0x0920),
+	INTC_VECT(BBIF1,		0x0940),
+	INTC_VECT(BBIF2,		0x0960),
+	INTC_VECT(USBHSDMAC,		0x0A00),
+	INTC_VECT(USBF_OUL_SOF,		0x0A20),
+	INTC_VECT(USBF_IXL_INT,		0x0A40),
+	INTC_VECT(SGX540,		0x0A60),
+	INTC_VECT(CMT1_0,		0x0B00),
+	INTC_VECT(CMT1_1,		0x0B20),
+	INTC_VECT(CMT1_2,		0x0B40),
+	INTC_VECT(CMT1_3,		0x0B60),
+	INTC_VECT(CMT2,			0x0B80),
+	INTC_VECT(CMT3,			0x0BA0),
+	INTC_VECT(KEYSC,		0x0BE0),
+	INTC_VECT(SCIFA0,		0x0C00),
+	INTC_VECT(SCIFA1,		0x0C20),
+	INTC_VECT(SCIFA2,		0x0C40),
+	INTC_VECT(SCIFA3,		0x0C60),
+	INTC_VECT(MSIOF2,		0x0C80),
+	INTC_VECT(MSIOF1,		0x0D00),
+	INTC_VECT(SCIFA4,		0x0D20),
+	INTC_VECT(SCIFA5,		0x0D40),
+	INTC_VECT(SCIFB,		0x0D60),
+	INTC_VECT(FLCTL_FLSTEI,		0x0D80),
+	INTC_VECT(FLCTL_FLTENDI,	0x0DA0),
+	INTC_VECT(FLCTL_FLTREQ0I,	0x0DC0),
+	INTC_VECT(FLCTL_FLTREQ1I,	0x0DE0),
+	INTC_VECT(SDHI0_0,		0x0E00),
+	INTC_VECT(SDHI0_1,		0x0E20),
+	INTC_VECT(SDHI0_2,		0x0E40),
+	INTC_VECT(SDHI0_3,		0x0E60),
+	INTC_VECT(SDHI1_0,		0x0E80),
+	INTC_VECT(SDHI1_1,		0x0EA0),
+	INTC_VECT(SDHI1_2,		0x0EC0),
+	INTC_VECT(SDHI1_3,		0x0EE0),
+	INTC_VECT(AP_ARM_L2CINT,	0x0FA0),
+	INTC_VECT(IRDA,			0x0480),
+	INTC_VECT(TPU0,			0x04A0),
+	INTC_VECT(SCIFA6,		0x04C0),
+	INTC_VECT(SCIFA7,		0x04E0),
+	INTC_VECT(GbEther,		0x0500),
+	INTC_VECT(ICBS0,		0x0540),
+	INTC_VECT(DDM,			0x1140),
+	INTC_VECT(SDHI2_0,		0x1200),
+	INTC_VECT(SDHI2_1,		0x1220),
+	INTC_VECT(SDHI2_2,		0x1240),
+	INTC_VECT(SDHI2_3,		0x1260),
+	INTC_VECT(RWDT0,		0x1280),
+	INTC_VECT(DMAC1_1_DEI0,		0x2000),
+	INTC_VECT(DMAC1_1_DEI1,		0x2020),
+	INTC_VECT(DMAC1_1_DEI2,		0x2040),
+	INTC_VECT(DMAC1_1_DEI3,		0x2060),
+	INTC_VECT(DMAC1_2_DEI4,		0x2080),
+	INTC_VECT(DMAC1_2_DEI5,		0x20A0),
+	INTC_VECT(DMAC1_2_DADERR,	0x20C0),
+	INTC_VECT(DMAC2_1_DEI0,		0x2100),
+	INTC_VECT(DMAC2_1_DEI1,		0x2120),
+	INTC_VECT(DMAC2_1_DEI2,		0x2140),
+	INTC_VECT(DMAC2_1_DEI3,		0x2160),
+	INTC_VECT(DMAC2_2_DEI4,		0x2180),
+	INTC_VECT(DMAC2_2_DEI5,		0x21A0),
+	INTC_VECT(DMAC2_2_DADERR,	0x21C0),
+	INTC_VECT(DMAC3_1_DEI0,		0x2200),
+	INTC_VECT(DMAC3_1_DEI1,		0x2220),
+	INTC_VECT(DMAC3_1_DEI2,		0x2240),
+	INTC_VECT(DMAC3_1_DEI3,		0x2260),
+	INTC_VECT(DMAC3_2_DEI4,		0x2280),
+	INTC_VECT(DMAC3_2_DEI5,		0x22A0),
+	INTC_VECT(DMAC3_2_DADERR,	0x22C0),
+	INTC_VECT(SHWYSTAT_RT,		0x1300),
+	INTC_VECT(SHWYSTAT_HS,		0x1320),
+	INTC_VECT(SHWYSTAT_COM,		0x1340),
+	INTC_VECT(USBH_INT,		0x1540),
+	INTC_VECT(USBH_OHCI,		0x1560),
+	INTC_VECT(USBH_EHCI,		0x1580),
+	INTC_VECT(USBH_PME,		0x15A0),
+	INTC_VECT(USBH_BIND,		0x15C0),
+	INTC_VECT(RSPI_OVRF,		0x1780),
+	INTC_VECT(RSPI_SPTEF,		0x17A0),
+	INTC_VECT(RSPI_SPRF,		0x17C0),
+	INTC_VECT(SPU2_0,		0x1800),
+	INTC_VECT(SPU2_1,		0x1820),
+	INTC_VECT(FSI,			0x1840),
+	INTC_VECT(FMSI,			0x1860),
+	INTC_VECT(IPMMU,		0x1920),
+	INTC_VECT(AP_ARM_CTIIRQ,	0x1980),
+	INTC_VECT(AP_ARM_PMURQ,		0x19A0),
+	INTC_VECT(MFIS2,		0x1A00),
+	INTC_VECT(CPORTR2S,		0x1A20),
+	INTC_VECT(CMT14,		0x1A40),
+	INTC_VECT(CMT15,		0x1A60),
+	INTC_VECT(MMCIF_0,		0x1AA0),
+	INTC_VECT(MMCIF_1,		0x1AC0),
+	INTC_VECT(MMCIF_2,		0x1AE0),
+	INTC_VECT(SIM_ERI,		0x1C00),
+	INTC_VECT(SIM_RXI,		0x1C20),
+	INTC_VECT(SIM_TXI,		0x1C40),
+	INTC_VECT(SIM_TEI,		0x1C60),
+	INTC_VECT(STPRO_0,		0x1C80),
+	INTC_VECT(STPRO_1,		0x1CA0),
+	INTC_VECT(STPRO_2,		0x1CC0),
+	INTC_VECT(STPRO_3,		0x1CE0),
+	INTC_VECT(STPRO_4,		0x1D00),
+};
+
+static struct intc_group intca_groups[] __initdata = {
+	INTC_GROUP(DMAC1_1,
+		   DMAC1_1_DEI0, DMAC1_1_DEI1, DMAC1_1_DEI2, DMAC1_1_DEI3),
+	INTC_GROUP(DMAC1_2,
+		   DMAC1_2_DEI4, DMAC1_2_DEI5, DMAC1_2_DADERR),
+	INTC_GROUP(DMAC2_1,
+		   DMAC2_1_DEI0, DMAC2_1_DEI1, DMAC2_1_DEI2, DMAC2_1_DEI3),
+	INTC_GROUP(DMAC2_2,
+		   DMAC2_2_DEI4, DMAC2_2_DEI5, DMAC2_2_DADERR),
+	INTC_GROUP(DMAC3_1,
+		   DMAC3_1_DEI0, DMAC3_1_DEI1, DMAC3_1_DEI2, DMAC3_1_DEI3),
+	INTC_GROUP(DMAC3_2,
+		   DMAC3_2_DEI4, DMAC3_2_DEI5, DMAC3_2_DADERR),
+	INTC_GROUP(AP_ARM1,
+		   AP_ARM_COMMTX, AP_ARM_COMMRX),
+	INTC_GROUP(AP_ARM2,
+		   AP_ARM_CTIIRQ, AP_ARM_PMURQ),
+	INTC_GROUP(USBF,
+		   USBF_OUL_SOF, USBF_IXL_INT),
+	INTC_GROUP(SDHI0,
+		   SDHI0_0, SDHI0_1, SDHI0_2, SDHI0_3),
+	INTC_GROUP(SDHI1,
+		   SDHI1_0, SDHI1_1, SDHI1_2, SDHI1_3),
+	INTC_GROUP(SDHI2,
+		   SDHI2_0, SDHI2_1, SDHI2_2, SDHI2_3),
+	INTC_GROUP(SHWYSTAT,
+		   SHWYSTAT_RT, SHWYSTAT_HS, SHWYSTAT_COM),
+	INTC_GROUP(USBH1, /* FIXME */
+		   USBH_INT, USBH_OHCI),
+	INTC_GROUP(USBH2, /* FIXME */
+		   USBH_EHCI,
+		   USBH_PME, USBH_BIND),
+	INTC_GROUP(RSPI,
+		   RSPI_OVRF, RSPI_SPTEF, RSPI_SPRF),
+	INTC_GROUP(SPU2,
+		   SPU2_0, SPU2_1),
+	INTC_GROUP(FLCTL,
+		   FLCTL_FLSTEI, FLCTL_FLTENDI, FLCTL_FLTREQ0I, FLCTL_FLTREQ1I),
+	INTC_GROUP(IIC1,
+		   IIC1_ALI, IIC1_TACKI, IIC1_WAITI, IIC1_DTEI),
+};
+
+static struct intc_mask_reg intca_mask_registers[] __initdata = {
+	{ /* IMR0A / IMCR0A */ 0xe6940080, 0xe69400c0, 8,
+	  { DMAC2_1_DEI3, DMAC2_1_DEI2, DMAC2_1_DEI1, DMAC2_1_DEI0,
+	    0, 0, AP_ARM_COMMTX, AP_ARM_COMMRX } },
+	{ /* IMR1A / IMCR1A */ 0xe6940084, 0xe69400c4, 8,
+	  { ATAPI, 0, DIRC, 0,
+	    DMAC1_1_DEI3, DMAC1_1_DEI2, DMAC1_1_DEI1, DMAC1_1_DEI0 } },
+	{ /* IMR2A / IMCR2A */ 0xe6940088, 0xe69400c8, 8,
+	  { 0, 0, 0, 0,
+	    BBIF1, BBIF2, MFIS, MFI } },
+	{ /* IMR3A / IMCR3A */ 0xe694008c, 0xe69400cc, 8,
+	  { DMAC3_1_DEI3, DMAC3_1_DEI2, DMAC3_1_DEI1, DMAC3_1_DEI0,
+	    DMAC3_2_DADERR, DMAC3_2_DEI5, DMAC3_2_DEI4, IRDA } },
+	{ /* IMR4A / IMCR4A */ 0xe6940090, 0xe69400d0, 8,
+	  { DDM, 0, 0, 0,
+	    0, 0, 0, 0 } },
+	{ /* IMR5A / IMCR5A */ 0xe6940094, 0xe69400d4, 8,
+	  { KEYSC, DMAC1_2_DADERR, DMAC1_2_DEI5, DMAC1_2_DEI4,
+	    SCIFA3, SCIFA2, SCIFA1, SCIFA0 } },
+	{ /* IMR6A / IMCR6A */ 0xe6940098, 0xe69400d8, 8,
+	  { SCIFB, SCIFA5, SCIFA4, MSIOF1,
+	    0, 0, MSIOF2, 0 } },
+	{ /* IMR7A / IMCR7A */ 0xe694009c, 0xe69400dc, 8,
+	  { SDHI0_3, SDHI0_2, SDHI0_1, SDHI0_0,
+	    FLCTL_FLTREQ1I, FLCTL_FLTREQ0I, FLCTL_FLTENDI, FLCTL_FLSTEI } },
+	{ /* IMR8A / IMCR8A */ 0xe69400a0, 0xe69400e0, 8,
+	  { SDHI1_3, SDHI1_2, SDHI1_1, SDHI1_0,
+	    0, USBHSDMAC, 0, AP_ARM_L2CINT } },
+	{ /* IMR9A / IMCR9A */ 0xe69400a4, 0xe69400e4, 8,
+	  { CMT1_3, CMT1_2, CMT1_1, CMT1_0,
+	    CMT2, USBF_IXL_INT, USBF_OUL_SOF, SGX540 } },
+	{ /* IMR10A / IMCR10A */ 0xe69400a8, 0xe69400e8, 8,
+	  { 0, DMAC2_2_DADERR, DMAC2_2_DEI5, DMAC2_2_DEI4,
+	    0, 0, 0, 0 } },
+	{ /* IMR11A / IMCR11A */ 0xe69400ac, 0xe69400ec, 8,
+	  { IIC1_DTEI, IIC1_WAITI, IIC1_TACKI, IIC1_ALI,
+	    ICBS0, 0, 0, 0 } },
+	{ /* IMR12A / IMCR12A */ 0xe69400b0, 0xe69400f0, 8,
+	  { 0, 0, TPU0, SCIFA6,
+	    SCIFA7, GbEther, 0, 0 } },
+	{ /* IMR13A / IMCR13A */ 0xe69400b4, 0xe69400f4, 8,
+	  { SDHI2_3, SDHI2_2, SDHI2_1, SDHI2_0,
+	    0, CMT3, 0, RWDT0 } },
+	{ /* IMR0A3 / IMCR0A3 */ 0xe6950080, 0xe69500c0, 8,
+	  { SHWYSTAT_RT, SHWYSTAT_HS, SHWYSTAT_COM, 0,
+	    0, 0, 0, 0 } },
+	  /* IMR1A3 / IMCR1A3 */
+	{ /* IMR2A3 / IMCR2A3 */ 0xe6950088, 0xe69500c8, 8,
+	  { 0, 0, USBH_INT, USBH_OHCI,
+	    USBH_EHCI, USBH_PME, USBH_BIND, 0 } },
+	  /* IMR3A3 / IMCR3A3 */
+	{ /* IMR4A3 / IMCR4A3 */ 0xe6950090, 0xe69500d0, 8,
+	  { 0, 0, 0, 0,
+	    RSPI_OVRF, RSPI_SPTEF, RSPI_SPRF, 0 } },
+	{ /* IMR5A3 / IMCR5A3 */ 0xe6950094, 0xe69500d4, 8,
+	  { SPU2_0, SPU2_1, FSI, FMSI,
+	    0, 0, 0, 0 } },
+	{ /* IMR6A3 / IMCR6A3 */ 0xe6950098, 0xe69500d8, 8,
+	  { 0, IPMMU, 0, 0,
+	    AP_ARM_CTIIRQ, AP_ARM_PMURQ, 0, 0 } },
+	{ /* IMR7A3 / IMCR7A3 */ 0xe695009c, 0xe69500dc, 8,
+	  { MFIS2, CPORTR2S, CMT14, CMT15,
+	    0, MMCIF_0, MMCIF_1, MMCIF_2 } },
+	  /* IMR8A3 / IMCR8A3 */
+	{ /* IMR9A3 / IMCR9A3 */ 0xe69500a4, 0xe69500e4, 8,
+	  { SIM_ERI, SIM_RXI, SIM_TXI, SIM_TEI,
+	    STPRO_0, STPRO_1, STPRO_2, STPRO_3 } },
+	{ /* IMR10A3 / IMCR10A3 */ 0xe69500a8, 0xe69500e8, 8,
+	  { STPRO_4, 0, 0, 0,
+	    0, 0, 0, 0 } },
+};
+
+static struct intc_prio_reg intca_prio_registers[] __initdata = {
+	{ 0xe6940000, 0, 16, 4, /* IPRAA */ { DMAC3_1, DMAC3_2, CMT2, ICBS0 } },
+	{ 0xe6940004, 0, 16, 4, /* IPRBA */ { IRDA, 0, BBIF1, BBIF2 } },
+	{ 0xe6940008, 0, 16, 4, /* IPRCA */ { ATAPI, 0, CMT1_1, AP_ARM1 } },
+	{ 0xe694000c, 0, 16, 4, /* IPRDA */ { 0, 0, CMT1_2, 0 } },
+	{ 0xe6940010, 0, 16, 4, /* IPREA */ { DMAC1_1, MFIS, MFI, USBF } },
+	{ 0xe6940014, 0, 16, 4, /* IPRFA */ { KEYSC, DMAC1_2,
+					      SGX540, CMT1_0 } },
+	{ 0xe6940018, 0, 16, 4, /* IPRGA */ { SCIFA0, SCIFA1,
+					      SCIFA2, SCIFA3 } },
+	{ 0xe694001c, 0, 16, 4, /* IPRGH */ { MSIOF2, USBHSDMAC,
+					      FLCTL, SDHI0 } },
+	{ 0xe6940020, 0, 16, 4, /* IPRIA */ { MSIOF1, SCIFA4, 0, IIC1 } },
+	{ 0xe6940024, 0, 16, 4, /* IPRJA */ { DMAC2_1, DMAC2_2,
+					      AP_ARM_L2CINT, 0 } },
+	{ 0xe6940028, 0, 16, 4, /* IPRKA */ { 0, CMT1_3, 0, SDHI1 } },
+	{ 0xe694002c, 0, 16, 4, /* IPRLA */ { TPU0, SCIFA6,
+					      SCIFA7, GbEther } },
+	{ 0xe6940030, 0, 16, 4, /* IPRMA */ { 0, CMT3, 0, RWDT0 } },
+	{ 0xe6940034, 0, 16, 4, /* IPRNA */ { SCIFB, SCIFA5, 0, DDM } },
+	{ 0xe6940038, 0, 16, 4, /* IPROA */ { 0, 0, DIRC, SDHI2 } },
+	{ 0xe6950000, 0, 16, 4, /* IPRAA3 */ { SHWYSTAT, 0, 0, 0 } },
+				/* IPRBA3 */
+				/* IPRCA3 */
+				/* IPRDA3 */
+	{ 0xe6950010, 0, 16, 4, /* IPREA3 */ { USBH1, 0, 0, 0 } },
+	{ 0xe6950014, 0, 16, 4, /* IPRFA3 */ { USBH2, 0, 0, 0 } },
+				/* IPRGA3 */
+				/* IPRHA3 */
+				/* IPRIA3 */
+	{ 0xe6950024, 0, 16, 4, /* IPRJA3 */ { RSPI, 0, 0, 0 } },
+	{ 0xe6950028, 0, 16, 4, /* IPRKA3 */ { SPU2, 0, FSI, FMSI } },
+				/* IPRLA3 */
+	{ 0xe6950030, 0, 16, 4, /* IPRMA3 */ { IPMMU, 0, 0, 0 } },
+	{ 0xe6950034, 0, 16, 4, /* IPRNA3 */ { AP_ARM2, 0, 0, 0 } },
+	{ 0xe6950038, 0, 16, 4, /* IPROA3 */ { MFIS2, CPORTR2S,
+					       CMT14, CMT15 } },
+	{ 0xe695003c, 0, 16, 4, /* IPRPA3 */ { 0, MMCIF_0, MMCIF_1, MMCIF_2 } },
+				/* IPRQA3 */
+				/* IPRRA3 */
+	{ 0xe6950048, 0, 16, 4, /* IPRSA3 */ { SIM_ERI, SIM_RXI,
+					       SIM_TXI, SIM_TEI } },
+	{ 0xe695004c, 0, 16, 4, /* IPRTA3 */ { STPRO_0, STPRO_1,
+					       STPRO_2, STPRO_3 } },
+	{ 0xe6950050, 0, 16, 4, /* IPRUA3 */ { STPRO_4, 0, 0, 0 } },
+};
+
+static DECLARE_INTC_DESC(intca_desc, "r8a7740-intca",
+			 intca_vectors, intca_groups,
+			 intca_mask_registers, intca_prio_registers,
+			 NULL);
+
+INTC_IRQ_PINS_32(intca_irq_pins, 0xe6900000,
+		 INTC_VECT, "r8a7740-intca-irq-pins");
+
+
+/*
+ *		INTCS
+ */
+enum {
+	UNUSED_INTCS = 0,
+
+	INTCS,
+
+	/* interrupt sources INTCS */
+
+	/* HUDI */
+	/* STPRO */
+	/* RTDMAC(1) */
+	VPU5HA2,
+	_2DG_TRAP, _2DG_GPM_INT, _2DG_CER_INT,
+	/* MFI */
+	/* BBIF2 */
+	VPU5F,
+	_2DG_BRK_INT,
+	/* SGX540 */
+	/* 2DDMAC */
+	/* IPMMU */
+	/* RTDMAC 2 */
+	/* KEYSC */
+	/* MSIOF */
+	IIC0_ALI, IIC0_TACKI, IIC0_WAITI, IIC0_DTEI,
+	TMU0_0, TMU0_1, TMU0_2,
+	CMT0,
+	/* CMT2 */
+	LMB,
+	CTI,
+	VOU,
+	/* RWDT0 */
+	ICB,
+	VIO6C,
+	CEU20, CEU21,
+	JPU,
+	LCDC0,
+	LCRC,
+	/* RTDMAC2(1) */
+	/* RTDMAC2(2) */
+	LCDC1,
+	/* SPU2 */
+	/* FSI */
+	/* FMSI */
+	TMU1_0, TMU1_1, TMU1_2,
+	CMT4,
+	DISP,
+	DSRV,
+	/* MFIS2 */
+	CPORTS2R,
+
+	/* interrupt groups INTCS */
+	_2DG1,
+	IIC0, TMU1,
+};
+
+static struct intc_vect intcs_vectors[] = {
+	/* HUDI */
+	/* STPRO */
+	/* RTDMAC(1) */
+	INTCS_VECT(VPU5HA2,		0x0880),
+	INTCS_VECT(_2DG_TRAP,		0x08A0),
+	INTCS_VECT(_2DG_GPM_INT,	0x08C0),
+	INTCS_VECT(_2DG_CER_INT,	0x08E0),
+	/* MFI */
+	/* BBIF2 */
+	INTCS_VECT(VPU5F,		0x0980),
+	INTCS_VECT(_2DG_BRK_INT,	0x09A0),
+	/* SGX540 */
+	/* 2DDMAC */
+	/* IPMMU */
+	/* RTDMAC(2) */
+	/* KEYSC */
+	/* MSIOF */
+	INTCS_VECT(IIC0_ALI,		0x0E00),
+	INTCS_VECT(IIC0_TACKI,		0x0E20),
+	INTCS_VECT(IIC0_WAITI,		0x0E40),
+	INTCS_VECT(IIC0_DTEI,		0x0E60),
+	INTCS_VECT(TMU0_0,		0x0E80),
+	INTCS_VECT(TMU0_1,		0x0EA0),
+	INTCS_VECT(TMU0_2,		0x0EC0),
+	INTCS_VECT(CMT0,		0x0F00),
+	/* CMT2 */
+	INTCS_VECT(LMB,			0x0F60),
+	INTCS_VECT(CTI,			0x0400),
+	INTCS_VECT(VOU,			0x0420),
+	/* RWDT0 */
+	INTCS_VECT(ICB,			0x0480),
+	INTCS_VECT(VIO6C,		0x04E0),
+	INTCS_VECT(CEU20,		0x0500),
+	INTCS_VECT(CEU21,		0x0520),
+	INTCS_VECT(JPU,			0x0560),
+	INTCS_VECT(LCDC0,		0x0580),
+	INTCS_VECT(LCRC,		0x05A0),
+	/* RTDMAC2(1) */
+	/* RTDMAC2(2) */
+	INTCS_VECT(LCDC1,		0x1780),
+	/* SPU2 */
+	/* FSI */
+	/* FMSI */
+	INTCS_VECT(TMU1_0,		0x1900),
+	INTCS_VECT(TMU1_1,		0x1920),
+	INTCS_VECT(TMU1_2,		0x1940),
+	INTCS_VECT(CMT4,		0x1980),
+	INTCS_VECT(DISP,		0x19A0),
+	INTCS_VECT(DSRV,		0x19C0),
+	/* MFIS2 */
+	INTCS_VECT(CPORTS2R,		0x1A20),
+
+	INTC_VECT(INTCS,		0xf80),
+};
 
-static int r8a7740_set_wake(struct irq_data *data, unsigned int on)
+static struct intc_group intcs_groups[] __initdata = {
+	INTC_GROUP(_2DG1, /*FIXME*/
+		   _2DG_CER_INT, _2DG_GPM_INT, _2DG_TRAP),
+	INTC_GROUP(IIC0,
+		   IIC0_DTEI, IIC0_WAITI, IIC0_TACKI, IIC0_ALI),
+	INTC_GROUP(TMU1,
+		   TMU1_0, TMU1_1, TMU1_2),
+};
+
+static struct intc_mask_reg intcs_mask_registers[] = {
+	  /* IMR0SA / IMCR0SA */ /* all 0 */
+	{ /* IMR1SA / IMCR1SA */ 0xffd20184, 0xffd201c4, 8,
+	  { _2DG_CER_INT, _2DG_GPM_INT, _2DG_TRAP, VPU5HA2,
+	    0, 0, 0, 0 /*STPRO*/ } },
+	{ /* IMR2SA / IMCR2SA */ 0xffd20188, 0xffd201c8, 8,
+	  { 0/*STPRO*/, 0, CEU21, VPU5F,
+	    0/*BBIF2*/, 0, 0, 0/*MFI*/ } },
+	{ /* IMR3SA / IMCR3SA */ 0xffd2018c, 0xffd201cc, 8,
+	  { 0, 0, 0, 0, /*2DDMAC*/
+	    VIO6C, 0, 0, ICB } },
+	{ /* IMR4SA / IMCR4SA */ 0xffd20190, 0xffd201d0, 8,
+	  { 0, 0, VOU, CTI,
+	    JPU, 0, LCRC, LCDC0 } },
+	  /* IMR5SA / IMCR5SA */ /*KEYSC/RTDMAC2/RTDMAC1*/
+	  /* IMR6SA / IMCR6SA */ /*MSIOF/SGX540*/
+	{ /* IMR7SA / IMCR7SA */ 0xffd2019c, 0xffd201dc, 8,
+	  { 0, TMU0_2, TMU0_1, TMU0_0,
+	    0, 0, 0, 0 } },
+	{ /* IMR8SA / IMCR8SA */ 0xffd201a0, 0xffd201e0, 8,
+	  { 0, 0, 0, 0,
+	    CEU20, 0, 0, 0 } },
+	{ /* IMR9SA / IMCR9SA */ 0xffd201a4, 0xffd201e4, 8,
+	  { 0, 0/*RWDT0*/, 0/*CMT2*/, CMT0,
+	    0, 0, 0, 0 } },
+	  /* IMR10SA / IMCR10SA */ /*IPMMU*/
+	{ /* IMR11SA / IMCR11SA */ 0xffd201ac, 0xffd201ec, 8,
+	  { IIC0_DTEI, IIC0_WAITI, IIC0_TACKI, IIC0_ALI,
+	    0, _2DG_BRK_INT, LMB, 0 } },
+	  /* IMR12SA / IMCR12SA */
+	  /* IMR13SA / IMCR13SA */
+	  /* IMR0SA3 / IMCR0SA3 */ /*RTDMAC2(1)/RTDMAC2(2)*/
+	  /* IMR1SA3 / IMCR1SA3 */
+	  /* IMR2SA3 / IMCR2SA3 */
+	  /* IMR3SA3 / IMCR3SA3 */
+	{ /* IMR4SA3 / IMCR4SA3 */ 0xffd50190, 0xffd501d0, 8,
+	  { 0, 0, 0, 0,
+	    LCDC1, 0, 0, 0 } },
+	  /* IMR5SA3 / IMCR5SA3 */ /* SPU2/FSI/FMSI */
+	{ /* IMR6SA3 / IMCR6SA3 */ 0xffd50198, 0xffd501d8, 8,
+	  { TMU1_0, TMU1_1, TMU1_2, 0,
+	    CMT4, DISP, DSRV, 0 } },
+	{ /* IMR7SA3 / IMCR7SA3 */ 0xffd5019c, 0xffd501dc, 8,
+	  { 0/*MFIS2*/, CPORTS2R, 0, 0,
+	    0, 0, 0, 0 } },
+	{ /* INTAMASK */ 0xffd20104, 0, 16,
+	  { 0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, INTCS } },
+};
+
+/* Priority is needed for INTCA to receive the INTCS interrupt */
+static struct intc_prio_reg intcs_prio_registers[] = {
+	{ 0xffd20000, 0, 16, 4, /* IPRAS */ { CTI, VOU, 0/*2DDMAC*/, ICB } },
+	{ 0xffd20004, 0, 16, 4, /* IPRBS */ { JPU, LCDC0, 0, LCRC } },
+				/* IPRCS */ /*BBIF2*/
+				/* IPRDS */
+	{ 0xffd20010, 0, 16, 4, /* IPRES */ { 0/*RTDMAC(1)*/, VPU5HA2,
+					      0/*MFI*/, VPU5F } },
+	{ 0xffd20014, 0, 16, 4, /* IPRFS */ { 0/*KEYSC*/, 0/*RTDMAC(2)*/,
+					      0/*CMT2*/, CMT0 } },
+	{ 0xffd20018, 0, 16, 4, /* IPRGS */ { TMU0_0, TMU0_1,
+					      TMU0_2, _2DG1 } },
+	{ 0xffd2001c, 0, 16, 4, /* IPRHS */ { 0, 0/*STPRO*/, 0/*STPRO*/,
+					      _2DG_BRK_INT/*FIXME*/ } },
+	{ 0xffd20020, 0, 16, 4, /* IPRIS */ { 0, 0/*MSIOF*/, 0, IIC0 } },
+	{ 0xffd20024, 0, 16, 4, /* IPRJS */ { CEU20, 0/*SGX540*/, 0, 0 } },
+	{ 0xffd20028, 0, 16, 4, /* IPRKS */ { VIO6C, 0, LMB, 0 } },
+	{ 0xffd2002c, 0, 16, 4, /* IPRLS */ { 0/*IPMMU*/, 0, CEU21, 0 } },
+				/* IPRMS */ /*RWDT0*/
+				/* IPRAS3 */ /*RTDMAC2(1)*/
+				/* IPRBS3 */ /*RTDMAC2(2)*/
+				/* IPRCS3 */
+				/* IPRDS3 */
+				/* IPRES3 */
+				/* IPRFS3 */
+				/* IPRGS3 */
+				/* IPRHS3 */
+				/* IPRIS3 */
+	{ 0xffd50024, 0, 16, 4, /* IPRJS3 */ { LCDC1, 0, 0, 0 } },
+				/* IPRKS3 */ /*SPU2/FSI/FMSi*/
+				/* IPRLS3 */
+	{ 0xffd50030, 0, 16, 4, /* IPRMS3 */ { TMU1, 0, 0, 0 } },
+	{ 0xffd50034, 0, 16, 4, /* IPRNS3 */ { CMT4, DISP, DSRV, 0 } },
+	{ 0xffd50038, 0, 16, 4, /* IPROS3 */ { 0/*MFIS2*/, CPORTS2R, 0, 0 } },
+				/* IPRPS3 */
+};
+
+static struct resource intcs_resources[] __initdata = {
+	[0] = {
+		.start	= 0xffd20000,
+		.end	= 0xffd201ff,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= 0xffd50000,
+		.end	= 0xffd501ff,
+		.flags	= IORESOURCE_MEM,
+	}
+};
+
+static struct intc_desc intcs_desc __initdata = {
+	.name = "r8a7740-intcs",
+	.resource = intcs_resources,
+	.num_resources = ARRAY_SIZE(intcs_resources),
+	.hw = INTC_HW_DESC(intcs_vectors, intcs_groups, intcs_mask_registers,
+			   intcs_prio_registers, NULL, NULL),
+};
+
+static void intcs_demux(unsigned int irq, struct irq_desc *desc)
 {
-	return 0; /* always allow wakeup */
+	void __iomem *reg = (void *)irq_get_handler_data(irq);
+	unsigned int evtcodeas = ioread32(reg);
+
+	generic_handle_irq(intcs_evt2irq(evtcodeas));
 }
 
 void __init r8a7740_init_irq(void)
 {
-	void __iomem *gic_dist_base = __io(0xf0001000);
-	void __iomem *gic_cpu_base = __io(0xf0000000);
+	void __iomem *intevtsa = ioremap_nocache(0xffd20100, PAGE_SIZE);
 
-	/*
-	 * Change INT_SEL INTCA->GIC
-	 * (on GPIO)
-	 */
-	__raw_writel(__raw_readl(INTA_CTRL) & ~(1 << 1), INTA_CTRL);
+	register_intc_controller(&intca_desc);
+	register_intc_controller(&intca_irq_pins_desc);
+	register_intc_controller(&intcs_desc);
 
-	gic_init(0, 29, gic_dist_base, gic_cpu_base);
-	gic_arch_extn.irq_set_wake = r8a7740_set_wake;
+	/* demux using INTEVTSA */
+	irq_set_handler_data(evt2irq(0xf80), (void *)intevtsa);
+	irq_set_chained_handler(evt2irq(0xf80), intcs_demux);
 }
diff --git a/arch/arm/mach-shmobile/setup-r8a7740.c b/arch/arm/mach-shmobile/setup-r8a7740.c
index 718cb82..bbdb3dc 100644
--- a/arch/arm/mach-shmobile/setup-r8a7740.c
+++ b/arch/arm/mach-shmobile/setup-r8a7740.c
@@ -35,8 +35,8 @@ static struct plat_sci_port scif0_platform_data = {
 	.scscr		= SCSCR_RE | SCSCR_TE,
 	.scbrr_algo_id	= SCBRR_ALGO_4,
 	.type		= PORT_SCIFA,
-	.irqs		= { gic_spi(100), gic_spi(100),
-			    gic_spi(100), gic_spi(100) },
+	.irqs		= { evt2irq(0x0c00), evt2irq(0x0c00),
+			    evt2irq(0x0c00), evt2irq(0x0c00) },
 };
 
 static struct platform_device scif0_device = {
@@ -54,8 +54,8 @@ static struct plat_sci_port scif1_platform_data = {
 	.scscr		= SCSCR_RE | SCSCR_TE,
 	.scbrr_algo_id	= SCBRR_ALGO_4,
 	.type		= PORT_SCIFA,
-	.irqs		= { gic_spi(101), gic_spi(101),
-			    gic_spi(101), gic_spi(101) },
+	.irqs		= { evt2irq(0x0c20), evt2irq(0x0c20),
+			    evt2irq(0x0c20), evt2irq(0x0c20) },
 };
 
 static struct platform_device scif1_device = {
@@ -73,8 +73,8 @@ static struct plat_sci_port scif2_platform_data = {
 	.scscr		= SCSCR_RE | SCSCR_TE,
 	.scbrr_algo_id	= SCBRR_ALGO_4,
 	.type		= PORT_SCIFA,
-	.irqs		= { gic_spi(102), gic_spi(102),
-			    gic_spi(102), gic_spi(102) },
+	.irqs		= { evt2irq(0x0c40), evt2irq(0x0c40),
+			    evt2irq(0x0c40), evt2irq(0x0c40) },
 };
 
 static struct platform_device scif2_device = {
@@ -92,8 +92,8 @@ static struct plat_sci_port scif3_platform_data = {
 	.scscr		= SCSCR_RE | SCSCR_TE,
 	.scbrr_algo_id	= SCBRR_ALGO_4,
 	.type		= PORT_SCIFA,
-	.irqs		= { gic_spi(103), gic_spi(103),
-			    gic_spi(103), gic_spi(103) },
+	.irqs		= { evt2irq(0x0c60), evt2irq(0x0c60),
+			    evt2irq(0x0c60), evt2irq(0x0c60) },
 };
 
 static struct platform_device scif3_device = {
@@ -111,8 +111,8 @@ static struct plat_sci_port scif4_platform_data = {
 	.scscr		= SCSCR_RE | SCSCR_TE,
 	.scbrr_algo_id	= SCBRR_ALGO_4,
 	.type		= PORT_SCIFA,
-	.irqs		= { gic_spi(104), gic_spi(104),
-			    gic_spi(104), gic_spi(104) },
+	.irqs		= { evt2irq(0x0d20), evt2irq(0x0d20),
+			    evt2irq(0x0d20), evt2irq(0x0d20) },
 };
 
 static struct platform_device scif4_device = {
@@ -130,8 +130,8 @@ static struct plat_sci_port scif5_platform_data = {
 	.scscr		= SCSCR_RE | SCSCR_TE,
 	.scbrr_algo_id	= SCBRR_ALGO_4,
 	.type		= PORT_SCIFA,
-	.irqs		= { gic_spi(105), gic_spi(105),
-			    gic_spi(105), gic_spi(105) },
+	.irqs		= { evt2irq(0x0d40), evt2irq(0x0d40),
+			    evt2irq(0x0d40), evt2irq(0x0d40) },
 };
 
 static struct platform_device scif5_device = {
@@ -149,8 +149,8 @@ static struct plat_sci_port scif6_platform_data = {
 	.scscr		= SCSCR_RE | SCSCR_TE,
 	.scbrr_algo_id	= SCBRR_ALGO_4,
 	.type		= PORT_SCIFA,
-	.irqs		= { gic_spi(106), gic_spi(106),
-			    gic_spi(106), gic_spi(106) },
+	.irqs		= { evt2irq(0x04c0), evt2irq(0x04c0),
+			    evt2irq(0x04c0), evt2irq(0x04c0) },
 };
 
 static struct platform_device scif6_device = {
@@ -168,8 +168,8 @@ static struct plat_sci_port scif7_platform_data = {
 	.scscr		= SCSCR_RE | SCSCR_TE,
 	.scbrr_algo_id	= SCBRR_ALGO_4,
 	.type		= PORT_SCIFA,
-	.irqs		= { gic_spi(107), gic_spi(107),
-			    gic_spi(107), gic_spi(107) },
+	.irqs		= { evt2irq(0x04e0), evt2irq(0x04e0),
+			    evt2irq(0x04e0), evt2irq(0x04e0) },
 };
 
 static struct platform_device scif7_device = {
@@ -187,8 +187,8 @@ static struct plat_sci_port scifb_platform_data = {
 	.scscr		= SCSCR_RE | SCSCR_TE,
 	.scbrr_algo_id	= SCBRR_ALGO_4,
 	.type		= PORT_SCIFB,
-	.irqs		= { gic_spi(108), gic_spi(108),
-			    gic_spi(108), gic_spi(108) },
+	.irqs		= { evt2irq(0x0d60), evt2irq(0x0d60),
+			    evt2irq(0x0d60), evt2irq(0x0d60) },
 };
 
 static struct platform_device scifb_device = {
@@ -216,7 +216,7 @@ static struct resource cmt10_resources[] = {
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= gic_spi(58),
+		.start	= evt2irq(0x0b00),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -253,8 +253,8 @@ static struct resource i2c0_resources[] = {
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= gic_spi(201),
-		.end	= gic_spi(204),
+		.start	= intcs_evt2irq(0xe00),
+		.end	= intcs_evt2irq(0xe60),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -267,8 +267,8 @@ static struct resource i2c1_resources[] = {
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= gic_spi(70),
-		.end	= gic_spi(73),
+		.start  = evt2irq(0x780), /* IIC1_ALI1 */
+		.end    = evt2irq(0x7e0), /* IIC1_DTEI1 */
 		.flags	= IORESOURCE_IRQ,
 	},
 };
-- 
1.7.4.1


^ permalink raw reply related

* [PATCH 0/5] ARM: mach-shmobile: r8a7740: INTCA/INTCS support
From: Kuninori Morimoto @ 2011-10-20  3:00 UTC (permalink / raw)
  To: linux-sh


Hi Paul, Magnus, SH ML members

These are r8a7740/bonito INTCA/INTCS support patch set

Kuninori Morimoto (5):
      ARM: mach-shmobile: r8a7740: use INTC instead of GIC
      ARM: mach-shmobile: bonito: make sure static function
      ARM: mach-shmobile: bonito: fixup fpga_write()
      ARM: mach-shmobile: add FPGA irq demux
      ARM: mach-shmobile: add SMSC9221 support

Best regards
---
Kuninori Morimoto

^ permalink raw reply

* [PATCH 3/3] ARM: mach-shmobile: sh7372 A4R support (v4)
From: Rafael J. Wysocki @ 2011-10-19 22:15 UTC (permalink / raw)
  To: Linux-sh list; +Cc: Linux PM list, Linux Kernel, Magnus Damm
In-Reply-To: <201110200012.43840.rjw@sisk.pl>

From: Magnus Damm <damm@opensource.se>

This change adds support for the sh7372 A4R power domain.

The sh7372 A4R hardware power domain contains the
SH CPU Core and a set of I/O devices including
multimedia accelerators and I2C controllers.

One special case about A4R is the INTCS interrupt
controller that needs to be saved and restored to
keep working as expected. Also the LCDC hardware
blocks are in a different hardware power domain
but have their IRQs routed only through INTCS. So
as long as LCDCs are active we cannot power down
INTCS because that would risk losing interrupts.

Signed-off-by: Magnus Damm <damm@opensource.se>
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---
 arch/arm/mach-shmobile/board-ap4evb.c        |    1 
 arch/arm/mach-shmobile/board-mackerel.c      |    1 
 arch/arm/mach-shmobile/include/mach/sh7372.h |    7 +++
 arch/arm/mach-shmobile/intc-sh7372.c         |   52 ++++++++++++++++++++++++++-
 arch/arm/mach-shmobile/pm-sh7372.c           |   29 ++++++++++++++-
 arch/arm/mach-shmobile/setup-sh7372.c        |    8 ++++
 6 files changed, 96 insertions(+), 2 deletions(-)

Index: linux/arch/arm/mach-shmobile/board-ap4evb.c
=================================--- linux.orig/arch/arm/mach-shmobile/board-ap4evb.c
+++ linux/arch/arm/mach-shmobile/board-ap4evb.c
@@ -1412,6 +1412,7 @@ static void __init ap4evb_init(void)
 	sh7372_add_device_to_domain(&sh7372_a3sp, &sh_mmcif_device);
 	sh7372_add_device_to_domain(&sh7372_a3sp, &sdhi0_device);
 	sh7372_add_device_to_domain(&sh7372_a3sp, &sdhi1_device);
+	sh7372_add_device_to_domain(&sh7372_a4r, &ceu_device);
 
 	hdmi_init_pm_clock();
 	fsi_init_pm_clock();
Index: linux/arch/arm/mach-shmobile/board-mackerel.c
=================================--- linux.orig/arch/arm/mach-shmobile/board-mackerel.c
+++ linux/arch/arm/mach-shmobile/board-mackerel.c
@@ -1596,6 +1596,7 @@ static void __init mackerel_init(void)
 	sh7372_add_device_to_domain(&sh7372_a3sp, &sdhi1_device);
 #endif
 	sh7372_add_device_to_domain(&sh7372_a3sp, &sdhi2_device);
+	sh7372_add_device_to_domain(&sh7372_a4r, &ceu_device);
 
 	hdmi_init_pm_clock();
 	sh7372_pm_init();
Index: linux/arch/arm/mach-shmobile/include/mach/sh7372.h
=================================--- linux.orig/arch/arm/mach-shmobile/include/mach/sh7372.h
+++ linux/arch/arm/mach-shmobile/include/mach/sh7372.h
@@ -480,8 +480,11 @@ struct platform_device;
 struct sh7372_pm_domain {
 	struct generic_pm_domain genpd;
 	struct dev_power_governor *gov;
+	void (*suspend)(void);
+	void (*resume)(void);
 	unsigned int bit_shift;
 	bool no_debug;
+	bool stay_on;
 };
 
 static inline struct sh7372_pm_domain *to_sh7372_pd(struct generic_pm_domain *d)
@@ -493,6 +496,7 @@ static inline struct sh7372_pm_domain *t
 extern struct sh7372_pm_domain sh7372_a4lc;
 extern struct sh7372_pm_domain sh7372_a4mp;
 extern struct sh7372_pm_domain sh7372_d4;
+extern struct sh7372_pm_domain sh7372_a4r;
 extern struct sh7372_pm_domain sh7372_a3rv;
 extern struct sh7372_pm_domain sh7372_a3ri;
 extern struct sh7372_pm_domain sh7372_a3sp;
@@ -509,4 +513,7 @@ extern void sh7372_pm_add_subdomain(stru
 #define sh7372_pm_add_subdomain(pd, sd) do { } while(0)
 #endif /* CONFIG_PM */
 
+extern void sh7372_intcs_suspend(void);
+extern void sh7372_intcs_resume(void);
+
 #endif /* __ASM_SH7372_H__ */
Index: linux/arch/arm/mach-shmobile/intc-sh7372.c
=================================--- linux.orig/arch/arm/mach-shmobile/intc-sh7372.c
+++ linux/arch/arm/mach-shmobile/intc-sh7372.c
@@ -606,9 +606,16 @@ static void intcs_demux(unsigned int irq
 	generic_handle_irq(intcs_evt2irq(evtcodeas));
 }
 
+static void __iomem *intcs_ffd2;
+static void __iomem *intcs_ffd5;
+
 void __init sh7372_init_irq(void)
 {
-	void __iomem *intevtsa = ioremap_nocache(0xffd20100, PAGE_SIZE);
+	void __iomem *intevtsa;
+
+	intcs_ffd2 = ioremap_nocache(0xffd20000, PAGE_SIZE);
+	intevtsa = intcs_ffd2 + 0x100;
+	intcs_ffd5 = ioremap_nocache(0xffd50000, PAGE_SIZE);
 
 	register_intc_controller(&intca_desc);
 	register_intc_controller(&intcs_desc);
@@ -617,3 +624,46 @@ void __init sh7372_init_irq(void)
 	irq_set_handler_data(evt2irq(0xf80), (void *)intevtsa);
 	irq_set_chained_handler(evt2irq(0xf80), intcs_demux);
 }
+
+static unsigned short ffd2[0x200];
+static unsigned short ffd5[0x100];
+
+void sh7372_intcs_suspend(void)
+{
+	int k;
+
+	for (k = 0x00; k <= 0x30; k += 4)
+		ffd2[k] = __raw_readw(intcs_ffd2 + k);
+
+	for (k = 0x80; k <= 0xb0; k += 4)
+		ffd2[k] = __raw_readb(intcs_ffd2 + k);
+
+	for (k = 0x180; k <= 0x188; k += 4)
+		ffd2[k] = __raw_readb(intcs_ffd2 + k);
+
+	for (k = 0x00; k <= 0x3c; k += 4)
+		ffd5[k] = __raw_readw(intcs_ffd5 + k);
+
+	for (k = 0x80; k <= 0x9c; k += 4)
+		ffd5[k] = __raw_readb(intcs_ffd5 + k);
+}
+
+void sh7372_intcs_resume(void)
+{
+	int k;
+
+	for (k = 0x00; k <= 0x30; k += 4)
+		__raw_writew(ffd2[k], intcs_ffd2 + k);
+
+	for (k = 0x80; k <= 0xb0; k += 4)
+		__raw_writeb(ffd2[k], intcs_ffd2 + k);
+
+	for (k = 0x180; k <= 0x188; k += 4)
+		__raw_writeb(ffd2[k], intcs_ffd2 + k);
+
+	for (k = 0x00; k <= 0x3c; k += 4)
+		__raw_writew(ffd5[k], intcs_ffd5 + k);
+
+	for (k = 0x80; k <= 0x9c; k += 4)
+		__raw_writeb(ffd5[k], intcs_ffd5 + k);
+}
Index: linux/arch/arm/mach-shmobile/pm-sh7372.c
=================================--- linux.orig/arch/arm/mach-shmobile/pm-sh7372.c
+++ linux/arch/arm/mach-shmobile/pm-sh7372.c
@@ -44,6 +44,7 @@
 #define SPDCR 0xe6180008
 #define SWUCR 0xe6180014
 #define SBAR 0xe6180020
+#define WUPRMSK 0xe6180028
 #define WUPSMSK 0xe618002c
 #define WUPSMSK2 0xe6180048
 #define PSTR 0xe6180080
@@ -80,6 +81,12 @@ static int pd_power_down(struct generic_
 	struct sh7372_pm_domain *sh7372_pd = to_sh7372_pd(genpd);
 	unsigned int mask = 1 << sh7372_pd->bit_shift;
 
+	if (sh7372_pd->suspend)
+		sh7372_pd->suspend();
+
+	if (sh7372_pd->stay_on)
+		return 0;
+
 	if (__raw_readl(PSTR) & mask) {
 		unsigned int retry_count;
 
@@ -106,6 +113,9 @@ static int pd_power_up(struct generic_pm
 	unsigned int retry_count;
 	int ret = 0;
 
+	if (sh7372_pd->stay_on)
+		goto out;
+
 	if (__raw_readl(PSTR) & mask)
 		goto out;
 
@@ -122,14 +132,23 @@ static int pd_power_up(struct generic_pm
 	if (__raw_readl(SWUCR) & mask)
 		ret = -EIO;
 
- out:
 	if (!sh7372_pd->no_debug)
 		pr_debug("sh7372 power domain up 0x%08x -> PSTR = 0x%08x\n",
 			 mask, __raw_readl(PSTR));
 
+ out:
+	if (ret = 0 && sh7372_pd->resume)
+		sh7372_pd->resume();
+
 	return ret;
 }
 
+static void sh7372_a4r_suspend(void)
+{
+	sh7372_intcs_suspend();
+	__raw_writel(0x300fffff, WUPRMSK); /* avoid wakeup */
+}
+
 static bool pd_active_wakeup(struct device *dev)
 {
 	return true;
@@ -186,6 +205,14 @@ struct sh7372_pm_domain sh7372_d4 = {
 	.bit_shift = 3,
 };
 
+struct sh7372_pm_domain sh7372_a4r = {
+	.bit_shift = 5,
+	.gov = &sh7372_always_on_gov,
+	.suspend = sh7372_a4r_suspend,
+	.resume = sh7372_intcs_resume,
+	.stay_on = true,
+};
+
 struct sh7372_pm_domain sh7372_a3rv = {
 	.bit_shift = 6,
 };
Index: linux/arch/arm/mach-shmobile/setup-sh7372.c
=================================--- linux.orig/arch/arm/mach-shmobile/setup-sh7372.c
+++ linux/arch/arm/mach-shmobile/setup-sh7372.c
@@ -991,12 +991,14 @@ void __init sh7372_add_standard_devices(
 	sh7372_init_pm_domain(&sh7372_a4lc);
 	sh7372_init_pm_domain(&sh7372_a4mp);
 	sh7372_init_pm_domain(&sh7372_d4);
+	sh7372_init_pm_domain(&sh7372_a4r);
 	sh7372_init_pm_domain(&sh7372_a3rv);
 	sh7372_init_pm_domain(&sh7372_a3ri);
 	sh7372_init_pm_domain(&sh7372_a3sg);
 	sh7372_init_pm_domain(&sh7372_a3sp);
 
 	sh7372_pm_add_subdomain(&sh7372_a4lc, &sh7372_a3rv);
+	sh7372_pm_add_subdomain(&sh7372_a4r, &sh7372_a4lc);
 
 	platform_add_devices(sh7372_early_devices,
 			    ARRAY_SIZE(sh7372_early_devices));
@@ -1020,6 +1022,12 @@ void __init sh7372_add_standard_devices(
 	sh7372_add_device_to_domain(&sh7372_a3sp, &dma2_device);
 	sh7372_add_device_to_domain(&sh7372_a3sp, &usb_dma0_device);
 	sh7372_add_device_to_domain(&sh7372_a3sp, &usb_dma1_device);
+	sh7372_add_device_to_domain(&sh7372_a4r, &iic0_device);
+	sh7372_add_device_to_domain(&sh7372_a4r, &veu0_device);
+	sh7372_add_device_to_domain(&sh7372_a4r, &veu1_device);
+	sh7372_add_device_to_domain(&sh7372_a4r, &veu2_device);
+	sh7372_add_device_to_domain(&sh7372_a4r, &veu3_device);
+	sh7372_add_device_to_domain(&sh7372_a4r, &jpu_device);
 }
 
 void __init sh7372_add_early_devices(void)


^ permalink raw reply

* [PATCH 2/3] ARM: mach-shmobile: sh7372 A3SP support (v4)
From: Rafael J. Wysocki @ 2011-10-19 22:14 UTC (permalink / raw)
  To: Linux-sh list; +Cc: Linux PM list, Linux Kernel, Magnus Damm
In-Reply-To: <201110200012.43840.rjw@sisk.pl>

From: Magnus Damm <damm@opensource.se>

This change adds support for the sh7372 A3SP power domain.

The sh7372 A3SP hardware power domain contains a
wide range of I/O devices. The list of I/O devices
include SCIF serial ports, DMA Engine hardware,
SD and MMC controller hardware, USB controllers
and I2C master controllers.

This patch adds the A3SP low level code which 
powers the hardware power domain on and off. It
also ties in platform devices to the pm domain
support code.

It is worth noting that the serial console is
hooked up to SCIFA0 on most sh7372 boards, and
the SCIFA0 port is included in the A3SP hardware
power domain. For this reason we cannot output
debug messages from the low level power control
code in the case of A3SP.

QoS support is needed in drivers before we can
enable the A3SP power control on the fly.

Signed-off-by: Magnus Damm <damm@opensource.se>
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---
 arch/arm/mach-shmobile/board-ap4evb.c        |    4 +++
 arch/arm/mach-shmobile/board-mackerel.c      |    8 +++++++
 arch/arm/mach-shmobile/include/mach/sh7372.h |    3 ++
 arch/arm/mach-shmobile/pm-sh7372.c           |   30 ++++++++++++++++++++++-----
 arch/arm/mach-shmobile/setup-sh7372.c        |   14 ++++++++++++
 5 files changed, 54 insertions(+), 5 deletions(-)

Index: linux/arch/arm/mach-shmobile/board-ap4evb.c
=================================--- linux.orig/arch/arm/mach-shmobile/board-ap4evb.c
+++ linux/arch/arm/mach-shmobile/board-ap4evb.c
@@ -1409,6 +1409,10 @@ static void __init ap4evb_init(void)
 	sh7372_add_device_to_domain(&sh7372_a4lc, &lcdc_device);
 	sh7372_add_device_to_domain(&sh7372_a4mp, &fsi_device);
 
+	sh7372_add_device_to_domain(&sh7372_a3sp, &sh_mmcif_device);
+	sh7372_add_device_to_domain(&sh7372_a3sp, &sdhi0_device);
+	sh7372_add_device_to_domain(&sh7372_a3sp, &sdhi1_device);
+
 	hdmi_init_pm_clock();
 	fsi_init_pm_clock();
 	sh7372_pm_init();
Index: linux/arch/arm/mach-shmobile/board-mackerel.c
=================================--- linux.orig/arch/arm/mach-shmobile/board-mackerel.c
+++ linux/arch/arm/mach-shmobile/board-mackerel.c
@@ -1588,6 +1588,14 @@ static void __init mackerel_init(void)
 	sh7372_add_device_to_domain(&sh7372_a4lc, &lcdc_device);
 	sh7372_add_device_to_domain(&sh7372_a4lc, &hdmi_lcdc_device);
 	sh7372_add_device_to_domain(&sh7372_a4mp, &fsi_device);
+	sh7372_add_device_to_domain(&sh7372_a3sp, &usbhs0_device);
+	sh7372_add_device_to_domain(&sh7372_a3sp, &usbhs1_device);
+	sh7372_add_device_to_domain(&sh7372_a3sp, &sh_mmcif_device);
+	sh7372_add_device_to_domain(&sh7372_a3sp, &sdhi0_device);
+#if !defined(CONFIG_MMC_SH_MMCIF) && !defined(CONFIG_MMC_SH_MMCIF_MODULE)
+	sh7372_add_device_to_domain(&sh7372_a3sp, &sdhi1_device);
+#endif
+	sh7372_add_device_to_domain(&sh7372_a3sp, &sdhi2_device);
 
 	hdmi_init_pm_clock();
 	sh7372_pm_init();
Index: linux/arch/arm/mach-shmobile/include/mach/sh7372.h
=================================--- linux.orig/arch/arm/mach-shmobile/include/mach/sh7372.h
+++ linux/arch/arm/mach-shmobile/include/mach/sh7372.h
@@ -479,7 +479,9 @@ struct platform_device;
 
 struct sh7372_pm_domain {
 	struct generic_pm_domain genpd;
+	struct dev_power_governor *gov;
 	unsigned int bit_shift;
+	bool no_debug;
 };
 
 static inline struct sh7372_pm_domain *to_sh7372_pd(struct generic_pm_domain *d)
@@ -493,6 +495,7 @@ extern struct sh7372_pm_domain sh7372_a4
 extern struct sh7372_pm_domain sh7372_d4;
 extern struct sh7372_pm_domain sh7372_a3rv;
 extern struct sh7372_pm_domain sh7372_a3ri;
+extern struct sh7372_pm_domain sh7372_a3sp;
 extern struct sh7372_pm_domain sh7372_a3sg;
 
 extern void sh7372_init_pm_domain(struct sh7372_pm_domain *sh7372_pd);
Index: linux/arch/arm/mach-shmobile/pm-sh7372.c
=================================--- linux.orig/arch/arm/mach-shmobile/pm-sh7372.c
+++ linux/arch/arm/mach-shmobile/pm-sh7372.c
@@ -92,8 +92,9 @@ static int pd_power_down(struct generic_
 		}
 	}
 
-	pr_debug("sh7372 power domain down 0x%08x -> PSTR = 0x%08x\n",
-		 mask, __raw_readl(PSTR));
+	if (!sh7372_pd->no_debug)
+		pr_debug("sh7372 power domain down 0x%08x -> PSTR = 0x%08x\n",
+			 mask, __raw_readl(PSTR));
 
 	return 0;
 }
@@ -122,8 +123,9 @@ static int pd_power_up(struct generic_pm
 		ret = -EIO;
 
  out:
-	pr_debug("sh7372 power domain up 0x%08x -> PSTR = 0x%08x\n",
-		 mask, __raw_readl(PSTR));
+	if (!sh7372_pd->no_debug)
+		pr_debug("sh7372 power domain up 0x%08x -> PSTR = 0x%08x\n",
+			 mask, __raw_readl(PSTR));
 
 	return ret;
 }
@@ -133,11 +135,20 @@ static bool pd_active_wakeup(struct devi
 	return true;
 }
 
+static bool sh7372_power_down_forbidden(struct dev_pm_domain *domain)
+{
+	return false;
+}
+
+struct dev_power_governor sh7372_always_on_gov = {
+	.power_down_ok = sh7372_power_down_forbidden,
+};
+
 void sh7372_init_pm_domain(struct sh7372_pm_domain *sh7372_pd)
 {
 	struct generic_pm_domain *genpd = &sh7372_pd->genpd;
 
-	pm_genpd_init(genpd, NULL, false);
+	pm_genpd_init(genpd, sh7372_pd->gov, false);
 	genpd->stop_device = pm_clk_suspend;
 	genpd->start_device = pm_clk_resume;
 	genpd->dev_irq_safe = true;
@@ -183,6 +194,12 @@ struct sh7372_pm_domain sh7372_a3ri = {
 	.bit_shift = 8,
 };
 
+struct sh7372_pm_domain sh7372_a3sp = {
+	.bit_shift = 11,
+	.gov = &sh7372_always_on_gov,
+	.no_debug = true,
+};
+
 struct sh7372_pm_domain sh7372_a3sg = {
 	.bit_shift = 13,
 };
@@ -422,6 +439,9 @@ void __init sh7372_pm_init(void)
 	__raw_writel(0x0000a501, DBGREG9);
 	__raw_writel(0x00000000, DBGREG1);
 
+	/* do not convert A3SM, A3SP, A3SG, A4R power down into A4S */
+	__raw_writel(0, PDNSEL);
+
 	sh7372_suspend_init();
 	sh7372_cpuidle_init();
 }
Index: linux/arch/arm/mach-shmobile/setup-sh7372.c
=================================--- linux.orig/arch/arm/mach-shmobile/setup-sh7372.c
+++ linux/arch/arm/mach-shmobile/setup-sh7372.c
@@ -994,6 +994,7 @@ void __init sh7372_add_standard_devices(
 	sh7372_init_pm_domain(&sh7372_a3rv);
 	sh7372_init_pm_domain(&sh7372_a3ri);
 	sh7372_init_pm_domain(&sh7372_a3sg);
+	sh7372_init_pm_domain(&sh7372_a3sp);
 
 	sh7372_pm_add_subdomain(&sh7372_a4lc, &sh7372_a3rv);
 
@@ -1006,6 +1007,19 @@ void __init sh7372_add_standard_devices(
 	sh7372_add_device_to_domain(&sh7372_a3rv, &vpu_device);
 	sh7372_add_device_to_domain(&sh7372_a4mp, &spu0_device);
 	sh7372_add_device_to_domain(&sh7372_a4mp, &spu1_device);
+	sh7372_add_device_to_domain(&sh7372_a3sp, &scif0_device);
+	sh7372_add_device_to_domain(&sh7372_a3sp, &scif1_device);
+	sh7372_add_device_to_domain(&sh7372_a3sp, &scif2_device);
+	sh7372_add_device_to_domain(&sh7372_a3sp, &scif3_device);
+	sh7372_add_device_to_domain(&sh7372_a3sp, &scif4_device);
+	sh7372_add_device_to_domain(&sh7372_a3sp, &scif5_device);
+	sh7372_add_device_to_domain(&sh7372_a3sp, &scif6_device);
+	sh7372_add_device_to_domain(&sh7372_a3sp, &iic1_device);
+	sh7372_add_device_to_domain(&sh7372_a3sp, &dma0_device);
+	sh7372_add_device_to_domain(&sh7372_a3sp, &dma1_device);
+	sh7372_add_device_to_domain(&sh7372_a3sp, &dma2_device);
+	sh7372_add_device_to_domain(&sh7372_a3sp, &usb_dma0_device);
+	sh7372_add_device_to_domain(&sh7372_a3sp, &usb_dma1_device);
 }
 
 void __init sh7372_add_early_devices(void)


^ permalink raw reply

* [PATCH 1/3] PM / Sleep: Mark devices involved in wakeup signaling during suspend
From: Rafael J. Wysocki @ 2011-10-19 22:13 UTC (permalink / raw)
  To: Linux-sh list; +Cc: Linux PM list, Linux Kernel, Magnus Damm
In-Reply-To: <201110200012.43840.rjw@sisk.pl>

From: Rafael J. Wysocki <rjw@sisk.pl>

The generic PM domains code in drivers/base/power/domain.c has
to avoid powering off domains that provide power to wakeup devices
during system suspend.  Currently, however, this only works for
wakeup devices directly belonging to the given domain and not for
their children (or the children of their children and so on).
Thus, if there's a wakeup device whose parent belongs to a power
domain handled by the generic PM domains code, the domain will be
powered off during system suspend preventing the device from
signaling wakeup.

To address this problem introduce a device flag, power.wakeup_path,
that will be set during system suspend for all wakeup devices,
their parents, the parents of their parents and so on.  This way,
all wakeup paths in the device hierarchy will be marked and the
generic PM domains code will only need to avoid powering off
domains containing devices whose power.wakeup_path is set.

Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---
 drivers/base/power/domain.c |    4 ++--
 drivers/base/power/main.c   |    8 +++++++-
 include/linux/pm.h          |    1 +
 3 files changed, 10 insertions(+), 3 deletions(-)

Index: linux/drivers/base/power/domain.c
=================================--- linux.orig/drivers/base/power/domain.c
+++ linux/drivers/base/power/domain.c
@@ -714,7 +714,7 @@ static int pm_genpd_suspend_noirq(struct
 	if (ret)
 		return ret;
 
-	if (device_may_wakeup(dev)
+	if (dev->power.wakeup_path
 	    && genpd->active_wakeup && genpd->active_wakeup(dev))
 		return 0;
 
@@ -938,7 +938,7 @@ static int pm_genpd_dev_poweroff_noirq(s
 	if (ret)
 		return ret;
 
-	if (device_may_wakeup(dev)
+	if (dev->power.wakeup_path
 	    && genpd->active_wakeup && genpd->active_wakeup(dev))
 		return 0;
 
Index: linux/drivers/base/power/main.c
=================================--- linux.orig/drivers/base/power/main.c
+++ linux/drivers/base/power/main.c
@@ -917,7 +917,11 @@ static int __device_suspend(struct devic
 	}
 
  End:
-	dev->power.is_suspended = !error;
+	if (!error) {
+		dev->power.is_suspended = true;
+		if (dev->power.wakeup_path && dev->parent)
+			dev->parent->power.wakeup_path = true;
+	}
 
 	device_unlock(dev);
 	complete_all(&dev->power.completion);
@@ -1020,6 +1024,8 @@ static int device_prepare(struct device
 
 	device_lock(dev);
 
+	dev->power.wakeup_path = device_may_wakeup(dev);
+
 	if (dev->pm_domain) {
 		pm_dev_dbg(dev, state, "preparing power domain ");
 		if (dev->pm_domain->ops.prepare)
Index: linux/include/linux/pm.h
=================================--- linux.orig/include/linux/pm.h
+++ linux/include/linux/pm.h
@@ -452,6 +452,7 @@ struct dev_pm_info {
 	struct list_head	entry;
 	struct completion	completion;
 	struct wakeup_source	*wakeup;
+	bool			wakeup_path:1;
 #else
 	unsigned int		should_wakeup:1;
 #endif


^ permalink raw reply

* [PATCH 0/3] Support for A3SP and A4R domains on SH7372
From: Rafael J. Wysocki @ 2011-10-19 22:12 UTC (permalink / raw)
  To: Linux-sh list; +Cc: Linux PM list, Linux Kernel, Magnus Damm

Hi,

Patches [2/3] and [3/3] add support for the SH7372's A3SP and A4R power
domains, respectively.

Patch [1/3] is a fix that's needed for console wakeup to work with the
A3SP domain patch.

Thanks,
Rafael


^ permalink raw reply

* [PATCH] sh: pfc: get_config_reg() shift clean up
From: Magnus Damm @ 2011-10-17  9:01 UTC (permalink / raw)
  To: linux-sh

From: Magnus Damm <damm@opensource.se>

Clean up the f_width shift code in get_config_reg().

Reported-by: Ryusuke Sakato <ryusuke.sakato.bx@renesas.com>
Signed-off-by: Magnus Damm <damm@opensource.se>
---

 drivers/sh/pfc.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

--- 0005/drivers/sh/pfc.c
+++ work/drivers/sh/pfc.c	2011-10-14 20:11:19.000000000 +0900
@@ -217,7 +217,7 @@ static int get_config_reg(struct pinmux_
 
 		if (!r_width)
 			break;
-		for (n = 0; n < (r_width / f_width) * 1 << f_width; n++) {
+		for (n = 0; n < (r_width / f_width) * (1 << f_width); n++) {
 			if (config_reg->enum_ids[n] = enum_id) {
 				*crp = config_reg;
 				*indexp = n;

^ permalink raw reply

* [PATCH] ARM: mach-shmobile: sh73a0 and AG5EVM PINT support
From: Magnus Damm @ 2011-10-17  9:00 UTC (permalink / raw)
  To: linux-sh

From: Magnus Damm <damm@opensource.se>

Support PINT on sh73a0 and AG5EVM using INTC PINT macros.

With this patch applied the AG5EVM ethernet is handled
through one of the chained sh73a0 PINT interrupt controllers.

Signed-off-by: Magnus Damm <damm@opensource.se>
---

 Depends on "[PATCH] ARM: mach-shmobile: Add support for PINT though macros"
 and on "[PATCH 00/07] ARM: mach-shmobile: External IRQ pin update"

 arch/arm/mach-shmobile/board-ag5evm.c        |   17 ------
 arch/arm/mach-shmobile/include/mach/sh73a0.h |    4 +
 arch/arm/mach-shmobile/intc-sh73a0.c         |   65 ++++++++++++++++++++++++++
 3 files changed, 71 insertions(+), 15 deletions(-)

--- 0014/arch/arm/mach-shmobile/board-ag5evm.c
+++ work/arch/arm/mach-shmobile/board-ag5evm.c	2011-10-14 18:50:07.000000000 +0900
@@ -58,7 +58,7 @@ static struct resource smsc9220_resource
 		.flags		= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start		= gic_spi(33), /* PINT1 */
+		.start		= SH73A0_PINT0_IRQ(2), /* PINTA2 */
 		.flags		= IORESOURCE_IRQ,
 	},
 };
@@ -465,19 +465,6 @@ static void __init ag5evm_map_io(void)
 	shmobile_setup_console();
 }
 
-#define PINTC_ADDR	0xe6900000
-#define PINTER0A	(PINTC_ADDR + 0xa0)
-#define PINTCR0A	(PINTC_ADDR + 0xb0)
-
-void __init ag5evm_init_irq(void)
-{
-	sh73a0_init_irq();
-
-	/* setup PINT: enable PINTA2 as active low */
-	__raw_writel(__raw_readl(PINTER0A) | (1<<29), PINTER0A);
-	__raw_writew(__raw_readw(PINTCR0A) | (2<<10), PINTCR0A);
-}
-
 #define DSI0PHYCR	0xe615006c
 
 static void __init ag5evm_init(void)
@@ -611,7 +598,7 @@ struct sys_timer ag5evm_timer = {
 
 MACHINE_START(AG5EVM, "ag5evm")
 	.map_io		= ag5evm_map_io,
-	.init_irq	= ag5evm_init_irq,
+	.init_irq	= sh73a0_init_irq,
 	.handle_irq	= shmobile_handle_irq_gic,
 	.init_machine	= ag5evm_init,
 	.timer		= &ag5evm_timer,
--- 0002/arch/arm/mach-shmobile/include/mach/sh73a0.h
+++ work/arch/arm/mach-shmobile/include/mach/sh73a0.h	2011-10-14 18:50:07.000000000 +0900
@@ -507,4 +507,8 @@ enum {
 	SHDMA_SLAVE_MMCIF_RX,
 };
 
+/* PINT interrupts are located at Linux IRQ 768 and up */
+#define SH73A0_PINT0_IRQ(irq) ((irq) + 768)
+#define SH73A0_PINT1_IRQ(irq) ((irq) + 800)
+
 #endif /* __ASM_SH73A0_H__ */
--- 0013/arch/arm/mach-shmobile/intc-sh73a0.c
+++ work/arch/arm/mach-shmobile/intc-sh73a0.c	2011-10-17 16:52:48.000000000 +0900
@@ -23,6 +23,7 @@
 #include <linux/io.h>
 #include <linux/sh_intc.h>
 #include <mach/intc.h>
+#include <mach/sh73a0.h>
 #include <asm/hardware/gic.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -363,6 +364,59 @@ static irqreturn_t sh73a0_irq_pin_demux(
 
 static struct irqaction sh73a0_irq_pin_cascade[32];
 
+#define PINTER0 0xe69000a0
+#define PINTER1 0xe69000a4
+#define PINTRR0 0xe69000d0
+#define PINTRR1 0xe69000d4
+
+#define PINT0A_IRQ(n, irq) INTC_IRQ((n), SH73A0_PINT0_IRQ(irq))
+#define PINT0B_IRQ(n, irq) INTC_IRQ((n), SH73A0_PINT0_IRQ(irq + 8))
+#define PINT0C_IRQ(n, irq) INTC_IRQ((n), SH73A0_PINT0_IRQ(irq + 16))
+#define PINT0D_IRQ(n, irq) INTC_IRQ((n), SH73A0_PINT0_IRQ(irq + 24))
+#define PINT1E_IRQ(n, irq) INTC_IRQ((n), SH73A0_PINT1_IRQ(irq))
+
+INTC_PINT(intc_pint0, PINTER0, 0xe69000b0, "sh73a0-pint0",		\
+  INTC_PINT_E(A), INTC_PINT_E(B), INTC_PINT_E(C), INTC_PINT_E(D),	\
+  INTC_PINT_V(A, PINT0A_IRQ), INTC_PINT_V(B, PINT0B_IRQ),		\
+  INTC_PINT_V(C, PINT0C_IRQ), INTC_PINT_V(D, PINT0D_IRQ),		\
+  INTC_PINT_E(A), INTC_PINT_E(B), INTC_PINT_E(C), INTC_PINT_E(D),	\
+  INTC_PINT_E(A), INTC_PINT_E(B), INTC_PINT_E(C), INTC_PINT_E(D));
+
+INTC_PINT(intc_pint1, PINTER1, 0xe69000c0, "sh73a0-pint1",		\
+  INTC_PINT_E(E), INTC_PINT_E_EMPTY, INTC_PINT_E_EMPTY, INTC_PINT_E_EMPTY, \
+  INTC_PINT_V(E, PINT1E_IRQ), INTC_PINT_V_NONE,				\
+  INTC_PINT_V_NONE, INTC_PINT_V_NONE,					\
+  INTC_PINT_E_NONE, INTC_PINT_E_NONE, INTC_PINT_E_NONE, INTC_PINT_E(E), \
+  INTC_PINT_E(E), INTC_PINT_E_NONE, INTC_PINT_E_NONE, INTC_PINT_E_NONE);
+
+static struct irqaction sh73a0_pint0_cascade;
+static struct irqaction sh73a0_pint1_cascade;
+
+static void pint_demux(unsigned long rr, unsigned long er, int base_irq)
+{
+	unsigned long value =  ioread32(rr) & ioread32(er);
+	int k;
+
+	for (k = 0; k < 32; k++) {
+		if (value & (1 << (31 - k))) {
+			generic_handle_irq(base_irq + k);
+			iowrite32(~(1 << (31 - k)), rr);
+		}
+	}
+}
+
+static irqreturn_t sh73a0_pint0_demux(int irq, void *dev_id)
+{
+	pint_demux(PINTRR0, PINTER0, SH73A0_PINT0_IRQ(0));
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t sh73a0_pint1_demux(int irq, void *dev_id)
+{
+	pint_demux(PINTRR1, PINTER1, SH73A0_PINT1_IRQ(0));
+	return IRQ_HANDLED;
+}
+
 void __init sh73a0_init_irq(void)
 {
 	void __iomem *gic_dist_base = __io(0xf0001000);
@@ -375,6 +429,8 @@ void __init sh73a0_init_irq(void)
 
 	register_intc_controller(&intcs_desc);
 	register_intc_controller(&intca_irq_pins_desc);
+	register_intc_controller(&intc_pint0_desc);
+	register_intc_controller(&intc_pint1_desc);
 
 	/* demux using INTEVTSA */
 	sh73a0_intcs_cascade.name = "INTCS cascade";
@@ -393,4 +449,13 @@ void __init sh73a0_init_irq(void)
 					      handle_level_irq, "level");
 		set_irq_flags(n, IRQF_VALID); /* yuck */
 	}
+
+	/* PINT pins are sanely tied to the GIC as SPI */
+	sh73a0_pint0_cascade.name = "PINT0 cascade";
+	sh73a0_pint0_cascade.handler = sh73a0_pint0_demux;
+	setup_irq(gic_spi(33), &sh73a0_pint0_cascade);
+
+	sh73a0_pint1_cascade.name = "PINT1 cascade";
+	sh73a0_pint1_cascade.handler = sh73a0_pint1_demux;
+	setup_irq(gic_spi(34), &sh73a0_pint1_cascade);
 }

^ permalink raw reply

* [PATCH] ARM: mach-shmobile: Add support for PINT though INTC macros
From: Magnus Damm @ 2011-10-17  9:00 UTC (permalink / raw)
  To: linux-sh

From: Magnus Damm <damm@opensource.se>

Add a INTC_PINT() macro with various helper bits to allow SoCs
like sh73a0 to suppor the PINT hardware using regular INTC tables.

Signed-off-by: Magnus Damm <damm@opensource.se>
---

 Depends on "[PATCH 00/07] ARM: mach-shmobile: External IRQ pin update"

 arch/arm/mach-shmobile/include/mach/intc.h |   51 ++++++++++++++++++++++++++++
 1 file changed, 51 insertions(+)

--- 0008/arch/arm/mach-shmobile/include/mach/intc.h
+++ work/arch/arm/mach-shmobile/include/mach/intc.h	2011-10-14 18:47:45.000000000 +0900
@@ -192,4 +192,55 @@ static struct intc_desc p ## _desc __ini
 			     p ## _sense_registers, p ## _ack_registers) \
 }
 
+#define INTC_PINT_E_EMPTY
+#define INTC_PINT_E_NONE 0, 0, 0, 0, 0, 0, 0, 0,
+#define INTC_PINT_E(p)							\
+	PINT ## p ## 0, PINT ## p ## 1, PINT ## p ## 2, PINT ## p ## 3,	\
+	PINT ## p ## 4, PINT ## p ## 5, PINT ## p ## 6, PINT ## p ## 7,
+
+#define INTC_PINT_V_NONE
+#define INTC_PINT_V(p, vect)					\
+	vect(PINT ## p ## 0, 0), vect(PINT ## p ## 1, 1),	\
+	vect(PINT ## p ## 2, 2), vect(PINT ## p ## 3, 3),	\
+	vect(PINT ## p ## 4, 4), vect(PINT ## p ## 5, 5),	\
+	vect(PINT ## p ## 6, 6), vect(PINT ## p ## 7, 7),
+
+#define INTC_PINT(p, mask_reg, sense_base, str,				\
+	enums_1, enums_2, enums_3, enums_4,				\
+	vect_1, vect_2, vect_3, vect_4,					\
+	mask_a, mask_b, mask_c, mask_d,					\
+	sense_a, sense_b, sense_c, sense_d)				\
+									\
+enum {									\
+	PINT ## p ## _UNUSED = 0,					\
+	enums_1 enums_2 enums_3 enums_4 				\
+};									\
+									\
+static struct intc_vect p ## _vectors[] __initdata = {			\
+	vect_1 vect_2 vect_3 vect_4					\
+};									\
+									\
+static struct intc_mask_reg p ## _mask_registers[] __initdata = {	\
+	{ mask_reg, 0, 32, /* PINTER */					\
+	  { mask_a mask_b mask_c mask_d } }				\
+};									\
+									\
+static struct intc_sense_reg p ## _sense_registers[] __initdata = {	\
+	{ sense_base + 0x00, 16, 2, /* PINTCR */			\
+	  { sense_a } },						\
+	{ sense_base + 0x04, 16, 2, /* PINTCR */			\
+	  { sense_b } },						\
+	{ sense_base + 0x08, 16, 2, /* PINTCR */			\
+	  { sense_c } },						\
+	{ sense_base + 0x0c, 16, 2, /* PINTCR */			\
+	  { sense_d } },						\
+};									\
+									\
+static struct intc_desc p ## _desc __initdata = {			\
+	.name = str,							\
+	.hw = INTC_HW_DESC(p ## _vectors, NULL,				\
+			     p ## _mask_registers, NULL,		\
+			     p ## _sense_registers, NULL),		\
+}
+
 #endif  /* __ASM_MACH_INTC_H */

^ permalink raw reply


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