* [PATCH v2 2/4] zynq: move static peripheral mappings
From: Josh Cartwright @ 2012-10-23 16:26 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <201210231450.11540.arnd@arndb.de>
Hey Arnd-
Thanks for the review/suggestions.
On Tue, Oct 23, 2012 at 02:50:11PM +0000, Arnd Bergmann wrote:
> On Monday 22 October 2012, Josh Cartwright wrote:
> > Shifting them up into the vmalloc region prevents the following warning,
> > when booting a zynq qemu target with more than 512mb of RAM:
> >
> > BUG: mapping for 0xe0000000 at 0xe0000000 out of vmalloc space
> >
> > In addition, it allows for reuse of these mappings when the proper
> > drivers issue requests via ioremap().
> >
> > Signed-off-by: Josh Cartwright <josh.cartwright@ni.com>
>
> This looks like a bug fix that should be backported to older kernels,
> so it would be good to add 'Cc: stable at vger.kernel.org' below your
> Signed-off-by.
Will-do, thanks.
> > diff --git a/arch/arm/mach-zynq/include/mach/zynq_soc.h b/arch/arm/mach-zynq/include/mach/zynq_soc.h
> > index d0d3f8f..ae3b236 100644
> > --- a/arch/arm/mach-zynq/include/mach/zynq_soc.h
> > +++ b/arch/arm/mach-zynq/include/mach/zynq_soc.h
> > @@ -15,33 +15,37 @@
> > #ifndef __MACH_XILINX_SOC_H__
> > #define __MACH_XILINX_SOC_H__
> >
> > +#include <asm/pgtable.h>
> > +
> > #define PERIPHERAL_CLOCK_RATE 2500000
> >
> > -/* For now, all mappings are flat (physical = virtual)
> > +/* Static peripheral mappings are mapped at the top of the
> > + * vmalloc region
> > */
> > -#define UART0_PHYS 0xE0000000
> > -#define UART0_VIRT UART0_PHYS
> > +#define UART0_PHYS 0xE0000000
> > +#define UART0_SIZE SZ_4K
> > +#define UART0_VIRT (VMALLOC_END - UART0_SIZE)
>
> There are plans to move the uart location into a fixed virtual
> address in the future, but it hasn't been decided yet.
> It will still need a fixed mapping though, just to a different
> address.
>
> > -#define TTC0_PHYS 0xF8001000
> > -#define TTC0_VIRT TTC0_PHYS
> > +#define TTC0_PHYS 0xF8001000
> > +#define TTC0_SIZE SZ_4K
> > +#define TTC0_VIRT (UART0_VIRT - TTC0_SIZE)
>
> It's quite likely that this does not have to be a fixed mapping
> any more. Just have a look at how drivers/clocksource/dw_apb_timer_of.c
> calls of_iomap() to get the address.
Yes, this is already on my list of plans. The in-tree TTC driver
unfortunately doesn't yet support device tree bindings. Are you
comfortable waiting on the DT-ification of the TTC in a follow-up
patchset?
> > -#define PL310_L2CC_PHYS 0xF8F02000
> > -#define PL310_L2CC_VIRT PL310_L2CC_PHYS
> > +#define PL310_L2CC_PHYS 0xF8F02000
> > +#define PL310_L2CC_SIZE SZ_4K
> > +#define PL310_L2CC_VIRT (TTC0_VIRT - PL310_L2CC_SIZE)
>
> This address would not need a fixed mapping by calling l2x0_of_init
> rather than l2x0_init.
Great, I'll take care of this.
> > -#define SCU_PERIPH_PHYS 0xF8F00000
> > -#define SCU_PERIPH_VIRT SCU_PERIPH_PHYS
> > +#define SCU_PERIPH_PHYS 0xF8F00000
> > +#define SCU_PERIPH_SIZE SZ_8K
> > +#define SCU_PERIPH_VIRT (PL310_L2CC_VIRT - SCU_PERIPH_SIZE)
>
> And your patch 3 already obsoletes this mapping.
I'll spin up a reordered patchset to eliminate this odd state.
Thanks again,
Josh
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20121023/95ceb569/attachment.sig>
^ permalink raw reply
* [PATCH v2] pinctrl/nomadik: use irq_create_mapping()
From: Stephen Warren @ 2012-10-23 16:17 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350981339-13316-1-git-send-email-linus.walleij@stericsson.com>
On 10/23/2012 02:35 AM, Linus Walleij wrote:
> From: Linus Walleij <linus.walleij@linaro.org>
>
> Since in the DT case, the linear domain path will not allocate
> descriptors for the IRQs, we need to use irq_create_mapping()
> for mapping hwirqs to Linux IRQs, so these descriptors get
> created on-the-fly in this case.
>
> ChangeLog v1->v2:
>
> - Just use irq_create_mapping() in the .to_irq function since
> this is called before unmasking or enabling any interrupt
> lines, so irq_find_mapping() should be sufficient for the
> IRQ handler function.
Reviewed-by: Stephen Warren <swarren@nvidia.com>
^ permalink raw reply
* [PATCH v2 2/2] USB: doc: Binding document for ehci-platform driver
From: Stephen Warren @ 2012-10-23 16:15 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <Pine.LNX.4.44L0.1210231004310.1635-100000@iolanthe.rowland.org>
On 10/23/2012 08:10 AM, Alan Stern wrote:
> On Mon, 22 Oct 2012, Stephen Warren wrote:
>
>>> I see. But why would it be done this way instead having a separate
>>> property?
>>
>> Well, I did say normally:-)
>>
>> I can certainly see an argument for representing these differences using
>> custom properties, rather than deriving the information from the
>> compatible value. It's probably be OK to do so for something generic
>> like this; it's just perhaps not always the default choice.
>>
>> Do note that even though this binding document dictates a particular
>> value for the compatible property, every device tree should additionally
>> add a separate value alongside it to indicate the specific HW model
>> that's actually present, so that if some device-specific bug-fix or
>> workaround needs to be applied, the model can be identified anyway.
>>
>> So, rather than:
>>
>> compatible = "usb-ehci";
>>
>> You should always have e.g.:
>>
>> compatible = "nvidia,tegra20-ehci", "usb-ehci";
>>
>> Given that, there is then always enough information in the device tree
>> for the driver to be able to derive the other values from the compatible
>> value.
>
> Yes, I get it.
>
>> Whether you want to derive the information, or whether you want to
>> explicitly represent it via properties, is a decision to make based on
>> the trade-offs.
>>
>> Oh, and I note that quite a few device trees already use compatible
>> value "usb-ehci" in their device-trees. Care needs to be taken not to
>> usurp that value from any existing device drivers if that was to be
>> picked as the compatible value required by this binding.
>
> Right. I think Tony's new binding should use compatible value
> "usb-ehci-platform". It will essentially be a superset of "usb-ehci".
I know this is bike-shedding a little bit, but...
The word "platform" isn't really about describing the HW, but rather is
derived from the Linux SW used to program that HW. DT should be purely
about describing the HW.
Perhaps "usb-ehci-generic" or "usb-ehci-simple" would be better?
^ permalink raw reply
* [PATCH v2 1/4] ARM: dts: omap5: Update GPIO with address space and interrupts
From: Sebastien Guiriec @ 2012-10-23 16:15 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <5086C0C3.1060305@ti.com>
Hi Benoit and John,
On 10/23/2012 06:07 PM, Benoit Cousson wrote:
> On 10/23/2012 05:59 PM, Jon Hunter wrote:
>>
>> On 10/23/2012 10:09 AM, Benoit Cousson wrote:
>>> On 10/23/2012 04:49 PM, Jon Hunter wrote:
>>>> Hi Seb,
>>>>
>>>> On 10/23/2012 03:37 AM, Sebastien Guiriec wrote:
>>>>> Add base address and interrupt line inside Device Tree data for
>>>>> OMAP5
>>>>>
>>>>> Signed-off-by: Sebastien Guiriec <s-guiriec@ti.com>
>>>>> ---
>>>>> arch/arm/boot/dts/omap5.dtsi | 16 ++++++++++++++++
>>>>> 1 file changed, 16 insertions(+)
>>>>>
>>>>> diff --git a/arch/arm/boot/dts/omap5.dtsi b/arch/arm/boot/dts/omap5.dtsi
>>>>> index 42c78be..9e39f9f 100644
>>>>> --- a/arch/arm/boot/dts/omap5.dtsi
>>>>> +++ b/arch/arm/boot/dts/omap5.dtsi
>>>>> @@ -104,6 +104,8 @@
>>>>>
>>>>> gpio1: gpio at 4ae10000 {
>>>>> compatible = "ti,omap4-gpio";
>>>>> + reg = <0x4ae10000 0x200>;
>>>>> + interrupts = <0 29 0x4>;
>>>>> ti,hwmods = "gpio1";
>>>>> gpio-controller;
>>>>> #gpio-cells = <2>;
>>>>
>>>> I am wondering if we should add the "interrupt-parent" property to add
>>>> nodes in the device-tree source. I know that today the interrupt-parent
>>>> is being defined globally, but when device-tree maps an interrupt for a
>>>> device it searches for the interrupt-parent starting the current device
>>>> node.
>>>>
>>>> So in other words, for gpio1 it will search the gpio1 binding for
>>>> "interrupt-parent" and if not found move up a level and search again. It
>>>> will keep doing this until it finds the "interrupt-parent".
>>>>
>>>> Therefore, I believe it will improve search time and hence, boot time if
>>>> we have interrupt-parent defined in each node.
>>>
>>> Mmm, I'm not that sure. it will increase the size of the blob, so
>>> increase the time to load it and then to parse it. Where in the current
>>> case, it is just going up to the parent node using the already
>>> un-flatten tree in memory and thus that should not take that much time.
>>
>> Yes it will definitely increase the size, so that could slow things down.
>>
>>> That being said, it might be interesting to benchmark that to see what
>>> is the real impact.
>>
>> Right, I wonder what the key functions are we need to benchmark to get
>> an overall feel for what is best? Right now I am seeing some people add
>> the interrupt-parent for device nodes and others not. Ideally we should
>> be consistent, but at the same time it is probably something that we can
>> easily sort out later. So not a big deal either way.
>
> For consistency, I'd rather not add it at all for the moment.
> Later, when we will only support DT boot, people will start complaining
> about the boot time increase and then we will start optimizing a little
> bit :-)
I just do it like that to be consistent with what is inside OMAP4 dtsi
for those IPs (GPIO/UART/MMC/I2C). Now after checking Peter already add
the interrupt-parent for all audio IPs (OMAP3/4/5). But here we need
also interrupts name. So here we should try to be consistent.
So I can send back the series for OMAP5 and update the OMAP4 with
interrupts-parent = <&gic>
As of today we are not consistent.
>
> Regards,
> Benoit
>
>
^ permalink raw reply
* [RFC] ARM: OMAP: hwmod: wait for sysreset complete after enabling hwmod
From: Kevin Hilman @ 2012-10-23 16:09 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAM=Q2cvLc63tGMG1t1wguiMHqNxcrZ60GF+fHjxc6_8c7rBykw@mail.gmail.com>
Shubhrajyoti Datta <omaplinuxkernel@gmail.com> writes:
> On Tue, Oct 23, 2012 at 3:16 AM, Kevin Hilman
> <khilman@deeprootsystems.com> wrote:
>> Tero Kristo <t-kristo@ti.com> writes:
>>
>>> When waking up from off-mode, some IP blocks are reset automatically by
>>> hardware. For this reason, software must wait until the reset has
>>> completed before attempting to access the IP block.
>>>
>>> This patch fixes for example the bug introduced by commit
>>> 6c31b2150ff96755d24e0ab6d6fea08a7bf5c44c ("mmc: omap_hsmmc: remove access
>>> to SYSCONFIG register"), in which the MMC IP block is reset during
>>> off-mode entry, but the code expects the module to be already available
>>> during the execution of context restore.
>>>
>>> Signed-off-by: Tero Kristo <t-kristo@ti.com>
>>> Cc: Paul Walmsley <paul@pwsan.com>
>>> Cc: Benoit Cousson <b-cousson@ti.com>
>>> Cc: Venkatraman S <svenkatr@ti.com>
>>
>> I can confirm that this patch the regression in my OMAP3 PM tests where
>> suspend test (to retention or off) failed if ran after the off-idle
>> test.
>>
>> Tested-by: Kevin Hilman <khilman@ti.com>
>>
>> on 3530/Overo, 3730/OveroSTORM, 3730/Beagle-xM
>
> on 3630/Beagle works.
> However on 3430 on idle path didnot work.
> let me know if i am missing some thing.
Could you please explain what worked and didn't work on each platforms?
Also, which 3430 did you test on? If it's SDP, then it has a UART1
console, correct?
Kevin
^ permalink raw reply
* [PATCH 10/10] ARM: imx6q: implement WAIT mode with coupled cpuidle
From: Lee Robert-B18647 @ 2012-10-23 16:09 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1351005779-30347-11-git-send-email-shawn.guo@linaro.org>
Hey Shawn,
For your SRPG implementation, a couple of weeks ago an issue was found that affects all i.MX6 SRPG functionality that requires a work around for 100% reliable operation. It's my understanding that the workaround is almost but not yet finalized. Ranjani is most familiar with this issue so you and her can discuss further.
Best Regards,
Rob
> -----Original Message-----
> From: Shawn Guo [mailto:shawn.guo at linaro.org]
> Sent: Tuesday, October 23, 2012 10:23 AM
> To: linux-arm-kernel at lists.infradead.org
> Cc: Sascha Hauer; Lee Robert-B18647; Shawn Guo
> Subject: [PATCH 10/10] ARM: imx6q: implement WAIT mode with coupled
> cpuidle
>
> The imx6q has a low power mode named WAIT. When all cores are in WFI,
> imx6q will go into WAIT mode, and whenever there is a wakeup interrupt,
> it will exit WAIT mode. Software can configure hardware behavior
> during WAIT mode, clock gating or power gating for ARM core.
>
> This patch adds two more cpuidle states, wait and srpg, implementing
> the ARM clock gating and power gating in WAIT mode respectively. They
> are added as coupled cpuidle states. Though imx6q hardware already
> handles sequencing, the voting provided by coupled cpuidle is still
> quite useful, which will allow the system to at least get into clock
> gating when one cpu wants clock gating and the other wants power
> gating.
>
> As WAIT mode is broken on TO1.0 silicon, the feature is only provided
> for revision later than TO1.0.
>
> Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
> ---
> arch/arm/mach-imx/Kconfig | 1 +
> arch/arm/mach-imx/common.h | 1 +
> arch/arm/mach-imx/cpuidle-imx6q.c | 155
> ++++++++++++++++++++++++++++++++++++-
> arch/arm/mach-imx/cpuidle.c | 3 +
> arch/arm/mach-imx/headsmp.S | 56 ++++++++++++++
> arch/arm/mach-imx/mach-imx6q.c | 7 +-
> arch/arm/mach-imx/platsmp.c | 5 ++
> 7 files changed, 225 insertions(+), 3 deletions(-)
>
> diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
> index 3ce2771..08435a6 100644
> --- a/arch/arm/mach-imx/Kconfig
> +++ b/arch/arm/mach-imx/Kconfig
> @@ -831,6 +831,7 @@ config SOC_IMX6Q
> bool "i.MX6 Quad support"
> select ARCH_HAS_CPUFREQ
> select ARCH_HAS_OPP
> + select ARCH_NEEDS_CPU_IDLE_COUPLED if SMP
> select ARM_CPU_SUSPEND if PM
> select ARM_ERRATA_743622
> select ARM_ERRATA_751472
> diff --git a/arch/arm/mach-imx/common.h b/arch/arm/mach-imx/common.h
> index ea11bbc..a3fe18b 100644
> --- a/arch/arm/mach-imx/common.h
> +++ b/arch/arm/mach-imx/common.h
> @@ -121,6 +121,7 @@ extern void imx_lluart_map_io(void); static inline
> void imx_lluart_map_io(void) {} #endif extern void
> v7_cpu_resume(void);
> +extern int v7_suspend_finish(unsigned long val);
> extern u32 *pl310_get_save_ptr(void);
> #ifdef CONFIG_SMP
> extern void v7_secondary_startup(void); diff --git a/arch/arm/mach-
> imx/cpuidle-imx6q.c b/arch/arm/mach-imx/cpuidle-imx6q.c
> index 83facc9..3acd6ce 100644
> --- a/arch/arm/mach-imx/cpuidle-imx6q.c
> +++ b/arch/arm/mach-imx/cpuidle-imx6q.c
> @@ -6,21 +6,172 @@
> * published by the Free Software Foundation.
> */
>
> +#include <linux/clockchips.h>
> +#include <linux/cpu_pm.h>
> #include <linux/cpuidle.h>
> #include <linux/module.h>
> #include <asm/cpuidle.h>
> +#include <asm/proc-fns.h>
> +#include <asm/suspend.h>
>
> +#include "common.h"
> #include "cpuidle.h"
>
> +static atomic_t master = ATOMIC_INIT(0); static u32 g_diag_reg;
> +
> +/*
> + * The diagnostic register holds the ARM core errata bits,
> + * which need to be saved and restored.
> + */
> +static inline void save_cpu_arch_register(void) {
> + asm("mrc p15, 0, %0, c15, c0, 1" : "=r"(g_diag_reg) : : "cc"); }
> +
> +static inline void restore_cpu_arch_register(void) {
> + asm("mcr p15, 0, %0, c15, c0, 1" : : "r"(g_diag_reg) : "cc"); }
> +
> +#ifdef CONFIG_SMP
> +static inline void imx6q_wakeup_other_cpus(int cpu) {
> + struct cpumask online = *cpu_online_mask;
> + const struct cpumask *others;
> +
> + cpumask_clear_cpu(cpu, &online);
> + others = &online;
> + arch_send_wakeup_ipi_mask(others);
> +}
> +#else
> +static inline void imx6q_wakeup_other_cpus(int cpu) { } #endif
> +
> +static int imx6q_enter_wait(struct cpuidle_device *dev,
> + struct cpuidle_driver *drv, int index) {
> + int cpu = dev->cpu;
> +
> + clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &cpu);
> +
> + if (atomic_inc_return(&master) == num_online_cpus()) {
> + imx6q_set_lpm(WAIT_UNCLOCKED);
> + cpu_do_idle();
> + imx6q_set_lpm(WAIT_CLOCKED);
> + } else {
> + cpu_do_idle();
> + }
> +
> + atomic_dec(&master);
> + clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &cpu);
> +
> + /*
> + * The coupled cpuidle requires all cores exit together.
> + * Wake up other cores which could still be in idle.
> + */
> + imx6q_wakeup_other_cpus(cpu);
> +
> + return index;
> +}
> +
> +static inline int imx6q_do_srpg(int cpu) {
> + imx_set_cpu_jump(cpu, v7_cpu_resume);
> + return cpu_suspend(cpu, v7_suspend_finish); }
> +
> +static int imx6q_enter_srpg(struct cpuidle_device *dev,
> + struct cpuidle_driver *drv, int index) {
> + int cpu = dev->cpu;
> + int ret;
> +
> + clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &cpu);
> +
> + cpu_pm_enter();
> +
> + if (atomic_inc_return(&master) == num_online_cpus()) {
> + cpu_cluster_pm_enter();
> + imx6q_set_lpm(WAIT_UNCLOCKED_POWER_OFF);
> + }
> +
> + save_cpu_arch_register();
> + ret = imx6q_do_srpg(cpu);
> + /*
> + * The ret is 0 if it returns from a successful SRPG,
> + * otherwise it just aborts from there.
> + */
> + if (!ret) {
> + restore_cpu_arch_register();
> + cpu_pm_exit();
> + }
> +
> + if (atomic_dec_return(&master) == num_online_cpus() - 1) {
> + imx6q_set_lpm(WAIT_CLOCKED);
> + if (!ret)
> + cpu_cluster_pm_exit();
> + else
> + /*
> + * It just aborts from SRPG, so wake up other cores
> + * to return exit together.
> + */
> + imx6q_wakeup_other_cpus(cpu);
> + }
> +
> + clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &cpu);
> +
> + return ret ? -EBUSY : index;
> +}
> +
> +/*
> + * For each cpu, setup the broadcast timer because local timer
> + * stops for the states other than WFI.
> + */
> +static void imx6q_setup_broadcast_timer(void *arg) {
> + int cpu = smp_processor_id();
> +
> + clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ON, &cpu); }
> +
> static struct cpuidle_driver imx6q_cpuidle_driver = {
> .name = "imx6q_cpuidle",
> .owner = THIS_MODULE,
> .en_core_tk_irqen = 1,
> - .states[0] = ARM_CPUIDLE_WFI_STATE,
> - .state_count = 1,
> + .states = {
> + /* WFI */
> + ARM_CPUIDLE_WFI_STATE,
> + /* WAIT */
> + {
> + .exit_latency = 50,
> + .target_residency = 75,
> + .flags = CPUIDLE_FLAG_TIME_VALID |
> CPUIDLE_FLAG_COUPLED,
> + .enter = imx6q_enter_wait,
> + .name = "WAIT",
> + .desc = "Clock off",
> + },
> + /* SRPG */
> + {
> + .exit_latency = 1000,
> + .target_residency = 1200,
> + .flags = CPUIDLE_FLAG_TIME_VALID |
> CPUIDLE_FLAG_COUPLED,
> + .enter = imx6q_enter_srpg,
> + .name = "SRPG",
> + .desc = "Power off",
> + },
> + },
> + .state_count = 3,
> + .safe_state_index = 0,
> };
>
> int __init imx6q_cpuidle_init(void)
> {
> + /* Set initial power mode */
> + imx6q_set_lpm(WAIT_CLOCKED);
> +
> + /* Configure the broadcast timer on each cpu */
> + on_each_cpu(imx6q_setup_broadcast_timer, NULL, 1);
> +
> return imx_cpuidle_init(&imx6q_cpuidle_driver);
> }
> diff --git a/arch/arm/mach-imx/cpuidle.c b/arch/arm/mach-imx/cpuidle.c
> index d4cb511..05a537f 100644
> --- a/arch/arm/mach-imx/cpuidle.c
> +++ b/arch/arm/mach-imx/cpuidle.c
> @@ -60,6 +60,9 @@ int __init imx_cpuidle_init(struct cpuidle_driver
> *drv)
> dev = per_cpu_ptr(imx_cpuidle_devices, cpu_id);
> dev->cpu = cpu_id;
> dev->state_count = drv->state_count;
> +#ifdef CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED
> + dev->coupled_cpus = *cpu_online_mask; #endif
>
> ret = cpuidle_register_device(dev);
> if (ret) {
> diff --git a/arch/arm/mach-imx/headsmp.S b/arch/arm/mach-imx/headsmp.S
> index ac8a967..f920962 100644
> --- a/arch/arm/mach-imx/headsmp.S
> +++ b/arch/arm/mach-imx/headsmp.S
> @@ -71,6 +71,62 @@ ENDPROC(v7_secondary_startup) #endif
>
> #ifdef CONFIG_PM
> +ENTRY(v7_suspend_finish)
> + stmfd sp!, {r4-r12, lr}
> +
> + /* Disable D-cache */
> + mrc p15, 0, r0, c1, c0, 0
> + bic r0, r0, #(1 << 2) @ clear SCTRL.C
> + mcr p15, 0, r0, c1, c0, 0
> + isb
> +
> + /* Flush D-cache */
> + bl v7_flush_dcache_louis
> +
> +#ifdef CONFIG_SMP
> + /* Exit coherency */
> + mrc p15, 0, r0, c1, c0, 1
> + bic r0, r0, #(1 << 6) @ clear ACTLR.SMP
> + mcr p15, 0, r0, c1, c0, 1
> + isb
> +
> + /* Invalidate SCU tag RAM for the cpu */
> + bl imx_get_scu_base @ r0 = scu base
> + mrc p15, 0, r2, c0, c0, 5 @ r2 = cpu id
> + and r2, r2, #0xf
> + mov r2, r2, lsl #2
> + mov r1, #0xf
> + mov r1, r1, lsl r2
> + str r1, [r0, #0xc]
> + dsb
> +#endif
> +
> + /*
> + * CPU can speculatively prefetch instructions, so add 16 NOPs
> + * after WFI per Cortex-A9 pipeline.
> + */
> + wfi
> + .rept 16
> + nop
> + .endr
> +
> + /* Enable D-cache */
> + mrc p15, 0, r0, c1, c0, 0
> + orr r0, r0, #(1 << 2) @ set SCTRL.C
> + mcr p15, 0, r0, c1, c0, 0
> + isb
> +
> +#ifdef CONFIG_SMP
> + /* Enter coherency */
> + mrc p15, 0, r0, c1, c0, 1
> + orr r0, r0, #(1 << 6) @ set ACTLR.SMP
> + mcr p15, 0, r0, c1, c0, 1
> + isb
> +#endif
> +
> + ldmfd sp!, {r4-r12, pc}
> +ENDPROC(v7_suspend_finish)
> +
> /*
> * The following code is located into the .data section. This is to
> * allow phys_l2x0_saved_regs to be accessed with a relative load diff
> --git a/arch/arm/mach-imx/mach-imx6q.c b/arch/arm/mach-imx/mach-imx6q.c
> index 8ecdeb5..9c9dbf8 100644
> --- a/arch/arm/mach-imx/mach-imx6q.c
> +++ b/arch/arm/mach-imx/mach-imx6q.c
> @@ -182,7 +182,12 @@ static void __init imx6q_init_machine(void)
>
> static void __init imx6q_init_late(void) {
> - imx6q_cpuidle_init();
> + /*
> + * WAIT mode is broken on TO1.0, so there is no point to
> + * have cpuidle running on it.
> + */
> + if (imx6q_revision() > IMX_CHIP_REVISION_1_0)
> + imx6q_cpuidle_init();
> }
>
> static void __init imx6q_map_io(void)
> diff --git a/arch/arm/mach-imx/platsmp.c b/arch/arm/mach-imx/platsmp.c
> index fc25062..dcd590b 100644
> --- a/arch/arm/mach-imx/platsmp.c
> +++ b/arch/arm/mach-imx/platsmp.c
> @@ -24,6 +24,11 @@
>
> static void __iomem *scu_base;
>
> +void __iomem *imx_get_scu_base(void)
> +{
> + return scu_base;
> +}
> +
> static struct map_desc scu_io_desc __initdata = {
> /* .virtual and .pfn are run-time assigned */
> .length = SZ_4K,
> --
> 1.7.9.5
>
^ permalink raw reply
* [PATCH v2 1/4] ARM: dts: omap5: Update GPIO with address space and interrupts
From: Benoit Cousson @ 2012-10-23 16:07 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <5086BECA.9070502@ti.com>
On 10/23/2012 05:59 PM, Jon Hunter wrote:
>
> On 10/23/2012 10:09 AM, Benoit Cousson wrote:
>> On 10/23/2012 04:49 PM, Jon Hunter wrote:
>>> Hi Seb,
>>>
>>> On 10/23/2012 03:37 AM, Sebastien Guiriec wrote:
>>>> Add base address and interrupt line inside Device Tree data for
>>>> OMAP5
>>>>
>>>> Signed-off-by: Sebastien Guiriec <s-guiriec@ti.com>
>>>> ---
>>>> arch/arm/boot/dts/omap5.dtsi | 16 ++++++++++++++++
>>>> 1 file changed, 16 insertions(+)
>>>>
>>>> diff --git a/arch/arm/boot/dts/omap5.dtsi b/arch/arm/boot/dts/omap5.dtsi
>>>> index 42c78be..9e39f9f 100644
>>>> --- a/arch/arm/boot/dts/omap5.dtsi
>>>> +++ b/arch/arm/boot/dts/omap5.dtsi
>>>> @@ -104,6 +104,8 @@
>>>>
>>>> gpio1: gpio at 4ae10000 {
>>>> compatible = "ti,omap4-gpio";
>>>> + reg = <0x4ae10000 0x200>;
>>>> + interrupts = <0 29 0x4>;
>>>> ti,hwmods = "gpio1";
>>>> gpio-controller;
>>>> #gpio-cells = <2>;
>>>
>>> I am wondering if we should add the "interrupt-parent" property to add
>>> nodes in the device-tree source. I know that today the interrupt-parent
>>> is being defined globally, but when device-tree maps an interrupt for a
>>> device it searches for the interrupt-parent starting the current device
>>> node.
>>>
>>> So in other words, for gpio1 it will search the gpio1 binding for
>>> "interrupt-parent" and if not found move up a level and search again. It
>>> will keep doing this until it finds the "interrupt-parent".
>>>
>>> Therefore, I believe it will improve search time and hence, boot time if
>>> we have interrupt-parent defined in each node.
>>
>> Mmm, I'm not that sure. it will increase the size of the blob, so
>> increase the time to load it and then to parse it. Where in the current
>> case, it is just going up to the parent node using the already
>> un-flatten tree in memory and thus that should not take that much time.
>
> Yes it will definitely increase the size, so that could slow things down.
>
>> That being said, it might be interesting to benchmark that to see what
>> is the real impact.
>
> Right, I wonder what the key functions are we need to benchmark to get
> an overall feel for what is best? Right now I am seeing some people add
> the interrupt-parent for device nodes and others not. Ideally we should
> be consistent, but at the same time it is probably something that we can
> easily sort out later. So not a big deal either way.
For consistency, I'd rather not add it at all for the moment.
Later, when we will only support DT boot, people will start complaining
about the boot time increase and then we will start optimizing a little
bit :-)
Regards,
Benoit
^ permalink raw reply
* [PATCH] arm: sched: stop sched_clock() during suspend
From: Russell King - ARM Linux @ 2012-10-23 16:03 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <87a9vdclxe.fsf@deeprootsystems.com>
On Tue, Oct 23, 2012 at 07:17:33AM -0700, Kevin Hilman wrote:
> Russell King - ARM Linux <linux@arm.linux.org.uk> writes:
> > No, printk() does not need this. You think it does, but it doesn't. What
> > we have is a difference between ARM and x86, and this difference is breaking
> > the scheduler.
> >
> > The fact that the printk timestamp increments while suspended is a bug. It
> > doesn't on x86.
>
> Russell, I agree that it's a bug, but does it qualify as a something
> you're willing to take for v3.7-rc?
Definitely. Our current behaviour across suspend for the scheduler is
wrong. This is one of the questions I had when I created the sched_clock
stuff - but no one at the time could answer. So, now that we have our
answer, let's get it fixed to conform.
^ permalink raw reply
* [PATCH v2 1/4] ARM: dts: omap5: Update GPIO with address space and interrupts
From: Jon Hunter @ 2012-10-23 15:59 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <5086B316.6000001@ti.com>
On 10/23/2012 10:09 AM, Benoit Cousson wrote:
> On 10/23/2012 04:49 PM, Jon Hunter wrote:
>> Hi Seb,
>>
>> On 10/23/2012 03:37 AM, Sebastien Guiriec wrote:
>>> Add base address and interrupt line inside Device Tree data for
>>> OMAP5
>>>
>>> Signed-off-by: Sebastien Guiriec <s-guiriec@ti.com>
>>> ---
>>> arch/arm/boot/dts/omap5.dtsi | 16 ++++++++++++++++
>>> 1 file changed, 16 insertions(+)
>>>
>>> diff --git a/arch/arm/boot/dts/omap5.dtsi b/arch/arm/boot/dts/omap5.dtsi
>>> index 42c78be..9e39f9f 100644
>>> --- a/arch/arm/boot/dts/omap5.dtsi
>>> +++ b/arch/arm/boot/dts/omap5.dtsi
>>> @@ -104,6 +104,8 @@
>>>
>>> gpio1: gpio at 4ae10000 {
>>> compatible = "ti,omap4-gpio";
>>> + reg = <0x4ae10000 0x200>;
>>> + interrupts = <0 29 0x4>;
>>> ti,hwmods = "gpio1";
>>> gpio-controller;
>>> #gpio-cells = <2>;
>>
>> I am wondering if we should add the "interrupt-parent" property to add
>> nodes in the device-tree source. I know that today the interrupt-parent
>> is being defined globally, but when device-tree maps an interrupt for a
>> device it searches for the interrupt-parent starting the current device
>> node.
>>
>> So in other words, for gpio1 it will search the gpio1 binding for
>> "interrupt-parent" and if not found move up a level and search again. It
>> will keep doing this until it finds the "interrupt-parent".
>>
>> Therefore, I believe it will improve search time and hence, boot time if
>> we have interrupt-parent defined in each node.
>
> Mmm, I'm not that sure. it will increase the size of the blob, so
> increase the time to load it and then to parse it. Where in the current
> case, it is just going up to the parent node using the already
> un-flatten tree in memory and thus that should not take that much time.
Yes it will definitely increase the size, so that could slow things down.
> That being said, it might be interesting to benchmark that to see what
> is the real impact.
Right, I wonder what the key functions are we need to benchmark to get
an overall feel for what is best? Right now I am seeing some people add
the interrupt-parent for device nodes and others not. Ideally we should
be consistent, but at the same time it is probably something that we can
easily sort out later. So not a big deal either way.
Cheers
Jon
^ permalink raw reply
* [RFC] ARM: OMAP: hwmod: wait for sysreset complete after enabling hwmod
From: Shubhrajyoti Datta @ 2012-10-23 15:43 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <87zk3edvti.fsf@deeprootsystems.com>
On Tue, Oct 23, 2012 at 3:16 AM, Kevin Hilman
<khilman@deeprootsystems.com> wrote:
> Tero Kristo <t-kristo@ti.com> writes:
>
>> When waking up from off-mode, some IP blocks are reset automatically by
>> hardware. For this reason, software must wait until the reset has
>> completed before attempting to access the IP block.
>>
>> This patch fixes for example the bug introduced by commit
>> 6c31b2150ff96755d24e0ab6d6fea08a7bf5c44c ("mmc: omap_hsmmc: remove access
>> to SYSCONFIG register"), in which the MMC IP block is reset during
>> off-mode entry, but the code expects the module to be already available
>> during the execution of context restore.
>>
>> Signed-off-by: Tero Kristo <t-kristo@ti.com>
>> Cc: Paul Walmsley <paul@pwsan.com>
>> Cc: Benoit Cousson <b-cousson@ti.com>
>> Cc: Venkatraman S <svenkatr@ti.com>
>
> I can confirm that this patch the regression in my OMAP3 PM tests where
> suspend test (to retention or off) failed if ran after the off-idle
> test.
>
> Tested-by: Kevin Hilman <khilman@ti.com>
>
> on 3530/Overo, 3730/OveroSTORM, 3730/Beagle-xM
on 3630/Beagle works.
However on 3430 on idle path didnot work.
let me know if i am missing some thing.
>
> Thanks Tero for the fix,
>
> Kevin
> --
> To unsubscribe from this list: send the line "unsubscribe linux-omap" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [PATCH] i2c: omap: re-factor omap_i2c_init function
From: Shubhrajyoti D @ 2012-10-23 15:27 UTC (permalink / raw)
To: linux-arm-kernel
re-factor omap_i2c_init() so that we can re-use it for resume.
While at it also remove the bufstate variable as we write it
in omap_i2c_resize_fifo for every transfer.
Signed-off-by: Shubhrajyoti D <shubhrajyoti@ti.com>
---
Applies on Felipe's series
http://www.spinics.net/lists/linux-omap/msg79995.html
Tested with Terro sys fix + Felipe's stop sched_clock() during suspend
on omap3636 beagle both idle and suspend.
Functional testing on omap4sdp.
drivers/i2c/busses/i2c-omap.c | 68 +++++++++++++++++------------------------
1 files changed, 28 insertions(+), 40 deletions(-)
diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
index 5e5cefb..338cee7 100644
--- a/drivers/i2c/busses/i2c-omap.c
+++ b/drivers/i2c/busses/i2c-omap.c
@@ -209,7 +209,6 @@ struct omap_i2c_dev {
u16 pscstate;
u16 scllstate;
u16 sclhstate;
- u16 bufstate;
u16 syscstate;
u16 westate;
u16 errata;
@@ -285,9 +284,26 @@ static inline u16 omap_i2c_read_reg(struct omap_i2c_dev *i2c_dev, int reg)
}
}
+static void __omap_i2c_init(struct omap_i2c_dev *dev)
+{
+
+ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
+ /* Setup clock prescaler to obtain approx 12MHz I2C module clock: */
+ omap_i2c_write_reg(dev, OMAP_I2C_PSC_REG, dev->pscstate);
+
+ /* SCL low and high time values */
+ omap_i2c_write_reg(dev, OMAP_I2C_SCLL_REG, dev->scllstate);
+ omap_i2c_write_reg(dev, OMAP_I2C_SCLH_REG, dev->sclhstate);
+ if (dev->rev >= OMAP_I2C_REV_ON_3430_3530)
+ omap_i2c_write_reg(dev, OMAP_I2C_WE_REG, dev->westate);
+ /* Take the I2C module out of reset: */
+ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN);
+ omap_i2c_write_reg(dev, OMAP_I2C_IE_REG, dev->iestate);
+
+}
static int omap_i2c_init(struct omap_i2c_dev *dev)
{
- u16 psc = 0, scll = 0, sclh = 0, buf = 0;
+ u16 psc = 0, scll = 0, sclh = 0;
u16 fsscll = 0, fssclh = 0, hsscll = 0, hssclh = 0;
unsigned long fclk_rate = 12000000;
unsigned long timeout;
@@ -337,11 +353,8 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)
* REVISIT: Some wkup sources might not be needed.
*/
dev->westate = OMAP_I2C_WE_ALL;
- omap_i2c_write_reg(dev, OMAP_I2C_WE_REG,
- dev->westate);
}
}
- omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
if (dev->flags & OMAP_I2C_FLAG_ALWAYS_ARMXOR_CLK) {
/*
@@ -426,28 +439,18 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)
sclh = fclk_rate / (dev->speed * 2) - 7 + psc;
}
- /* Setup clock prescaler to obtain approx 12MHz I2C module clock: */
- omap_i2c_write_reg(dev, OMAP_I2C_PSC_REG, psc);
-
- /* SCL low and high time values */
- omap_i2c_write_reg(dev, OMAP_I2C_SCLL_REG, scll);
- omap_i2c_write_reg(dev, OMAP_I2C_SCLH_REG, sclh);
-
- /* Take the I2C module out of reset: */
- omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN);
-
/* Enable interrupts */
dev->iestate = (OMAP_I2C_IE_XRDY | OMAP_I2C_IE_RRDY |
OMAP_I2C_IE_NACK | OMAP_I2C_IE_AL) |
((dev->fifo_size) ? (OMAP_I2C_IE_RDR |
OMAP_I2C_IE_XDR) : 0);
- omap_i2c_write_reg(dev, OMAP_I2C_IE_REG, dev->iestate);
- if (dev->flags & OMAP_I2C_FLAG_RESET_REGS_POSTIDLE) {
- dev->pscstate = psc;
- dev->scllstate = scll;
- dev->sclhstate = sclh;
- dev->bufstate = buf;
- }
+
+ dev->pscstate = psc;
+ dev->scllstate = scll;
+ dev->sclhstate = sclh;
+
+ __omap_i2c_init(dev);
+
return 0;
}
@@ -1136,7 +1139,7 @@ omap_i2c_probe(struct platform_device *pdev)
if (IS_ERR_VALUE(r))
goto err_free_mem;
- dev->rev = omap_i2c_read_reg(dev, OMAP_I2C_REV_REG) & 0xff;
+ dev->rev = omap_i2c_read_reg(dev, OMAP_I2C_REV_REG) & 0xff;
dev->errata = 0;
@@ -1268,23 +1271,8 @@ static int omap_i2c_runtime_resume(struct device *dev)
{
struct omap_i2c_dev *_dev = dev_get_drvdata(dev);
- if (_dev->flags & OMAP_I2C_FLAG_RESET_REGS_POSTIDLE) {
- omap_i2c_write_reg(_dev, OMAP_I2C_CON_REG, 0);
- omap_i2c_write_reg(_dev, OMAP_I2C_PSC_REG, _dev->pscstate);
- omap_i2c_write_reg(_dev, OMAP_I2C_SCLL_REG, _dev->scllstate);
- omap_i2c_write_reg(_dev, OMAP_I2C_SCLH_REG, _dev->sclhstate);
- omap_i2c_write_reg(_dev, OMAP_I2C_BUF_REG, _dev->bufstate);
- omap_i2c_write_reg(_dev, OMAP_I2C_SYSC_REG, _dev->syscstate);
- omap_i2c_write_reg(_dev, OMAP_I2C_WE_REG, _dev->westate);
- omap_i2c_write_reg(_dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN);
- }
-
- /*
- * Don't write to this register if the IE state is 0 as it can
- * cause deadlock.
- */
- if (_dev->iestate)
- omap_i2c_write_reg(_dev, OMAP_I2C_IE_REG, _dev->iestate);
+ if (_dev->flags & OMAP_I2C_FLAG_RESET_REGS_POSTIDLE)
+ __omap_i2c_init(_dev);
return 0;
}
--
1.7.5.4
^ permalink raw reply related
* [PATCH 10/10] ARM: imx6q: implement WAIT mode with coupled cpuidle
From: Shawn Guo @ 2012-10-23 15:22 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1351005779-30347-1-git-send-email-shawn.guo@linaro.org>
The imx6q has a low power mode named WAIT. When all cores are in WFI,
imx6q will go into WAIT mode, and whenever there is a wakeup interrupt,
it will exit WAIT mode. Software can configure hardware behavior during
WAIT mode, clock gating or power gating for ARM core.
This patch adds two more cpuidle states, wait and srpg, implementing
the ARM clock gating and power gating in WAIT mode respectively. They
are added as coupled cpuidle states. Though imx6q hardware already
handles sequencing, the voting provided by coupled cpuidle is still
quite useful, which will allow the system to at least get into clock
gating when one cpu wants clock gating and the other wants power gating.
As WAIT mode is broken on TO1.0 silicon, the feature is only provided
for revision later than TO1.0.
Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
---
arch/arm/mach-imx/Kconfig | 1 +
arch/arm/mach-imx/common.h | 1 +
arch/arm/mach-imx/cpuidle-imx6q.c | 155 ++++++++++++++++++++++++++++++++++++-
arch/arm/mach-imx/cpuidle.c | 3 +
arch/arm/mach-imx/headsmp.S | 56 ++++++++++++++
arch/arm/mach-imx/mach-imx6q.c | 7 +-
arch/arm/mach-imx/platsmp.c | 5 ++
7 files changed, 225 insertions(+), 3 deletions(-)
diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
index 3ce2771..08435a6 100644
--- a/arch/arm/mach-imx/Kconfig
+++ b/arch/arm/mach-imx/Kconfig
@@ -831,6 +831,7 @@ config SOC_IMX6Q
bool "i.MX6 Quad support"
select ARCH_HAS_CPUFREQ
select ARCH_HAS_OPP
+ select ARCH_NEEDS_CPU_IDLE_COUPLED if SMP
select ARM_CPU_SUSPEND if PM
select ARM_ERRATA_743622
select ARM_ERRATA_751472
diff --git a/arch/arm/mach-imx/common.h b/arch/arm/mach-imx/common.h
index ea11bbc..a3fe18b 100644
--- a/arch/arm/mach-imx/common.h
+++ b/arch/arm/mach-imx/common.h
@@ -121,6 +121,7 @@ extern void imx_lluart_map_io(void);
static inline void imx_lluart_map_io(void) {}
#endif
extern void v7_cpu_resume(void);
+extern int v7_suspend_finish(unsigned long val);
extern u32 *pl310_get_save_ptr(void);
#ifdef CONFIG_SMP
extern void v7_secondary_startup(void);
diff --git a/arch/arm/mach-imx/cpuidle-imx6q.c b/arch/arm/mach-imx/cpuidle-imx6q.c
index 83facc9..3acd6ce 100644
--- a/arch/arm/mach-imx/cpuidle-imx6q.c
+++ b/arch/arm/mach-imx/cpuidle-imx6q.c
@@ -6,21 +6,172 @@
* published by the Free Software Foundation.
*/
+#include <linux/clockchips.h>
+#include <linux/cpu_pm.h>
#include <linux/cpuidle.h>
#include <linux/module.h>
#include <asm/cpuidle.h>
+#include <asm/proc-fns.h>
+#include <asm/suspend.h>
+#include "common.h"
#include "cpuidle.h"
+static atomic_t master = ATOMIC_INIT(0);
+static u32 g_diag_reg;
+
+/*
+ * The diagnostic register holds the ARM core errata bits,
+ * which need to be saved and restored.
+ */
+static inline void save_cpu_arch_register(void)
+{
+ asm("mrc p15, 0, %0, c15, c0, 1" : "=r"(g_diag_reg) : : "cc");
+}
+
+static inline void restore_cpu_arch_register(void)
+{
+ asm("mcr p15, 0, %0, c15, c0, 1" : : "r"(g_diag_reg) : "cc");
+}
+
+#ifdef CONFIG_SMP
+static inline void imx6q_wakeup_other_cpus(int cpu)
+{
+ struct cpumask online = *cpu_online_mask;
+ const struct cpumask *others;
+
+ cpumask_clear_cpu(cpu, &online);
+ others = &online;
+ arch_send_wakeup_ipi_mask(others);
+}
+#else
+static inline void imx6q_wakeup_other_cpus(int cpu) { }
+#endif
+
+static int imx6q_enter_wait(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv, int index)
+{
+ int cpu = dev->cpu;
+
+ clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &cpu);
+
+ if (atomic_inc_return(&master) == num_online_cpus()) {
+ imx6q_set_lpm(WAIT_UNCLOCKED);
+ cpu_do_idle();
+ imx6q_set_lpm(WAIT_CLOCKED);
+ } else {
+ cpu_do_idle();
+ }
+
+ atomic_dec(&master);
+ clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &cpu);
+
+ /*
+ * The coupled cpuidle requires all cores exit together.
+ * Wake up other cores which could still be in idle.
+ */
+ imx6q_wakeup_other_cpus(cpu);
+
+ return index;
+}
+
+static inline int imx6q_do_srpg(int cpu)
+{
+ imx_set_cpu_jump(cpu, v7_cpu_resume);
+ return cpu_suspend(cpu, v7_suspend_finish);
+}
+
+static int imx6q_enter_srpg(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv, int index)
+{
+ int cpu = dev->cpu;
+ int ret;
+
+ clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &cpu);
+
+ cpu_pm_enter();
+
+ if (atomic_inc_return(&master) == num_online_cpus()) {
+ cpu_cluster_pm_enter();
+ imx6q_set_lpm(WAIT_UNCLOCKED_POWER_OFF);
+ }
+
+ save_cpu_arch_register();
+ ret = imx6q_do_srpg(cpu);
+ /*
+ * The ret is 0 if it returns from a successful SRPG,
+ * otherwise it just aborts from there.
+ */
+ if (!ret) {
+ restore_cpu_arch_register();
+ cpu_pm_exit();
+ }
+
+ if (atomic_dec_return(&master) == num_online_cpus() - 1) {
+ imx6q_set_lpm(WAIT_CLOCKED);
+ if (!ret)
+ cpu_cluster_pm_exit();
+ else
+ /*
+ * It just aborts from SRPG, so wake up other cores
+ * to return exit together.
+ */
+ imx6q_wakeup_other_cpus(cpu);
+ }
+
+ clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &cpu);
+
+ return ret ? -EBUSY : index;
+}
+
+/*
+ * For each cpu, setup the broadcast timer because local timer
+ * stops for the states other than WFI.
+ */
+static void imx6q_setup_broadcast_timer(void *arg)
+{
+ int cpu = smp_processor_id();
+
+ clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ON, &cpu);
+}
+
static struct cpuidle_driver imx6q_cpuidle_driver = {
.name = "imx6q_cpuidle",
.owner = THIS_MODULE,
.en_core_tk_irqen = 1,
- .states[0] = ARM_CPUIDLE_WFI_STATE,
- .state_count = 1,
+ .states = {
+ /* WFI */
+ ARM_CPUIDLE_WFI_STATE,
+ /* WAIT */
+ {
+ .exit_latency = 50,
+ .target_residency = 75,
+ .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_COUPLED,
+ .enter = imx6q_enter_wait,
+ .name = "WAIT",
+ .desc = "Clock off",
+ },
+ /* SRPG */
+ {
+ .exit_latency = 1000,
+ .target_residency = 1200,
+ .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_COUPLED,
+ .enter = imx6q_enter_srpg,
+ .name = "SRPG",
+ .desc = "Power off",
+ },
+ },
+ .state_count = 3,
+ .safe_state_index = 0,
};
int __init imx6q_cpuidle_init(void)
{
+ /* Set initial power mode */
+ imx6q_set_lpm(WAIT_CLOCKED);
+
+ /* Configure the broadcast timer on each cpu */
+ on_each_cpu(imx6q_setup_broadcast_timer, NULL, 1);
+
return imx_cpuidle_init(&imx6q_cpuidle_driver);
}
diff --git a/arch/arm/mach-imx/cpuidle.c b/arch/arm/mach-imx/cpuidle.c
index d4cb511..05a537f 100644
--- a/arch/arm/mach-imx/cpuidle.c
+++ b/arch/arm/mach-imx/cpuidle.c
@@ -60,6 +60,9 @@ int __init imx_cpuidle_init(struct cpuidle_driver *drv)
dev = per_cpu_ptr(imx_cpuidle_devices, cpu_id);
dev->cpu = cpu_id;
dev->state_count = drv->state_count;
+#ifdef CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED
+ dev->coupled_cpus = *cpu_online_mask;
+#endif
ret = cpuidle_register_device(dev);
if (ret) {
diff --git a/arch/arm/mach-imx/headsmp.S b/arch/arm/mach-imx/headsmp.S
index ac8a967..f920962 100644
--- a/arch/arm/mach-imx/headsmp.S
+++ b/arch/arm/mach-imx/headsmp.S
@@ -71,6 +71,62 @@ ENDPROC(v7_secondary_startup)
#endif
#ifdef CONFIG_PM
+ENTRY(v7_suspend_finish)
+ stmfd sp!, {r4-r12, lr}
+
+ /* Disable D-cache */
+ mrc p15, 0, r0, c1, c0, 0
+ bic r0, r0, #(1 << 2) @ clear SCTRL.C
+ mcr p15, 0, r0, c1, c0, 0
+ isb
+
+ /* Flush D-cache */
+ bl v7_flush_dcache_louis
+
+#ifdef CONFIG_SMP
+ /* Exit coherency */
+ mrc p15, 0, r0, c1, c0, 1
+ bic r0, r0, #(1 << 6) @ clear ACTLR.SMP
+ mcr p15, 0, r0, c1, c0, 1
+ isb
+
+ /* Invalidate SCU tag RAM for the cpu */
+ bl imx_get_scu_base @ r0 = scu base
+ mrc p15, 0, r2, c0, c0, 5 @ r2 = cpu id
+ and r2, r2, #0xf
+ mov r2, r2, lsl #2
+ mov r1, #0xf
+ mov r1, r1, lsl r2
+ str r1, [r0, #0xc]
+ dsb
+#endif
+
+ /*
+ * CPU can speculatively prefetch instructions, so add 16 NOPs
+ * after WFI per Cortex-A9 pipeline.
+ */
+ wfi
+ .rept 16
+ nop
+ .endr
+
+ /* Enable D-cache */
+ mrc p15, 0, r0, c1, c0, 0
+ orr r0, r0, #(1 << 2) @ set SCTRL.C
+ mcr p15, 0, r0, c1, c0, 0
+ isb
+
+#ifdef CONFIG_SMP
+ /* Enter coherency */
+ mrc p15, 0, r0, c1, c0, 1
+ orr r0, r0, #(1 << 6) @ set ACTLR.SMP
+ mcr p15, 0, r0, c1, c0, 1
+ isb
+#endif
+
+ ldmfd sp!, {r4-r12, pc}
+ENDPROC(v7_suspend_finish)
+
/*
* The following code is located into the .data section. This is to
* allow phys_l2x0_saved_regs to be accessed with a relative load
diff --git a/arch/arm/mach-imx/mach-imx6q.c b/arch/arm/mach-imx/mach-imx6q.c
index 8ecdeb5..9c9dbf8 100644
--- a/arch/arm/mach-imx/mach-imx6q.c
+++ b/arch/arm/mach-imx/mach-imx6q.c
@@ -182,7 +182,12 @@ static void __init imx6q_init_machine(void)
static void __init imx6q_init_late(void)
{
- imx6q_cpuidle_init();
+ /*
+ * WAIT mode is broken on TO1.0, so there is no point to
+ * have cpuidle running on it.
+ */
+ if (imx6q_revision() > IMX_CHIP_REVISION_1_0)
+ imx6q_cpuidle_init();
}
static void __init imx6q_map_io(void)
diff --git a/arch/arm/mach-imx/platsmp.c b/arch/arm/mach-imx/platsmp.c
index fc25062..dcd590b 100644
--- a/arch/arm/mach-imx/platsmp.c
+++ b/arch/arm/mach-imx/platsmp.c
@@ -24,6 +24,11 @@
static void __iomem *scu_base;
+void __iomem *imx_get_scu_base(void)
+{
+ return scu_base;
+}
+
static struct map_desc scu_io_desc __initdata = {
/* .virtual and .pfn are run-time assigned */
.length = SZ_4K,
--
1.7.9.5
^ permalink raw reply related
* [PATCH 09/10] ARM: SMP: add function arch_send_wakeup_ipi_mask()
From: Shawn Guo @ 2012-10-23 15:22 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1351005779-30347-1-git-send-email-shawn.guo@linaro.org>
Add function arch_send_wakeup_ipi_mask(), so that platform code can
use it as an easy way to wake up cores that are in WFI.
Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
---
arch/arm/include/asm/smp.h | 1 +
arch/arm/kernel/smp.c | 5 +++++
2 files changed, 6 insertions(+)
diff --git a/arch/arm/include/asm/smp.h b/arch/arm/include/asm/smp.h
index 2e3be16..d3a22be 100644
--- a/arch/arm/include/asm/smp.h
+++ b/arch/arm/include/asm/smp.h
@@ -79,6 +79,7 @@ extern void cpu_die(void);
extern void arch_send_call_function_single_ipi(int cpu);
extern void arch_send_call_function_ipi_mask(const struct cpumask *mask);
+extern void arch_send_wakeup_ipi_mask(const struct cpumask *mask);
struct smp_operations {
#ifdef CONFIG_SMP
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index 8e20754d..dd5dd02 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -415,6 +415,11 @@ void arch_send_call_function_ipi_mask(const struct cpumask *mask)
smp_cross_call(mask, IPI_CALL_FUNC);
}
+void arch_send_wakeup_ipi_mask(const struct cpumask *mask)
+{
+ smp_cross_call(mask, IPI_WAKEUP);
+}
+
void arch_send_call_function_single_ipi(int cpu)
{
smp_cross_call(cpumask_of(cpu), IPI_CALL_FUNC_SINGLE);
--
1.7.9.5
^ permalink raw reply related
* [PATCH 08/10] ARM: imx: move imx6q_cpuidle_driver into a separate file
From: Shawn Guo @ 2012-10-23 15:22 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1351005779-30347-1-git-send-email-shawn.guo@linaro.org>
Move imx6q_cpuidle_driver into a separate file as more codes will
be added when WAIT mode gets implemented as cpuidle.
Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
---
arch/arm/mach-imx/Makefile | 6 +++++-
arch/arm/mach-imx/cpuidle-imx6q.c | 26 ++++++++++++++++++++++++++
arch/arm/mach-imx/cpuidle.h | 5 +++++
arch/arm/mach-imx/mach-imx6q.c | 12 +-----------
4 files changed, 37 insertions(+), 12 deletions(-)
create mode 100644 arch/arm/mach-imx/cpuidle-imx6q.c
diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile
index fe47b71..a29ed49 100644
--- a/arch/arm/mach-imx/Makefile
+++ b/arch/arm/mach-imx/Makefile
@@ -28,7 +28,11 @@ obj-$(CONFIG_MXC_ULPI) += ulpi.o
obj-$(CONFIG_MXC_USE_EPIT) += epit.o
obj-$(CONFIG_MXC_DEBUG_BOARD) += 3ds_debugboard.o
obj-$(CONFIG_CPU_FREQ_IMX) += cpufreq.o
-obj-$(CONFIG_CPU_IDLE) += cpuidle.o
+
+ifeq ($(CONFIG_CPU_IDLE),y)
+obj-y += cpuidle.o
+obj-$(CONFIG_SOC_IMX6Q) += cpuidle-imx6q.o
+endif
ifdef CONFIG_SND_IMX_SOC
obj-y += ssi-fiq.o
diff --git a/arch/arm/mach-imx/cpuidle-imx6q.c b/arch/arm/mach-imx/cpuidle-imx6q.c
new file mode 100644
index 0000000..83facc9
--- /dev/null
+++ b/arch/arm/mach-imx/cpuidle-imx6q.c
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2012 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/cpuidle.h>
+#include <linux/module.h>
+#include <asm/cpuidle.h>
+
+#include "cpuidle.h"
+
+static struct cpuidle_driver imx6q_cpuidle_driver = {
+ .name = "imx6q_cpuidle",
+ .owner = THIS_MODULE,
+ .en_core_tk_irqen = 1,
+ .states[0] = ARM_CPUIDLE_WFI_STATE,
+ .state_count = 1,
+};
+
+int __init imx6q_cpuidle_init(void)
+{
+ return imx_cpuidle_init(&imx6q_cpuidle_driver);
+}
diff --git a/arch/arm/mach-imx/cpuidle.h b/arch/arm/mach-imx/cpuidle.h
index bc932d1..e092d13 100644
--- a/arch/arm/mach-imx/cpuidle.h
+++ b/arch/arm/mach-imx/cpuidle.h
@@ -14,9 +14,14 @@
#ifdef CONFIG_CPU_IDLE
extern int imx_cpuidle_init(struct cpuidle_driver *drv);
+extern int imx6q_cpuidle_init(void);
#else
static inline int imx_cpuidle_init(struct cpuidle_driver *drv)
{
return -ENODEV;
}
+static inline int imx6q_cpuidle_init(void)
+{
+ return -ENODEV;
+}
#endif
diff --git a/arch/arm/mach-imx/mach-imx6q.c b/arch/arm/mach-imx/mach-imx6q.c
index 1c5acf8..8ecdeb5 100644
--- a/arch/arm/mach-imx/mach-imx6q.c
+++ b/arch/arm/mach-imx/mach-imx6q.c
@@ -12,7 +12,6 @@
#include <linux/clk.h>
#include <linux/clkdev.h>
-#include <linux/cpuidle.h>
#include <linux/delay.h>
#include <linux/export.h>
#include <linux/init.h>
@@ -26,7 +25,6 @@
#include <linux/regmap.h>
#include <linux/micrel_phy.h>
#include <linux/mfd/syscon.h>
-#include <asm/cpuidle.h>
#include <asm/smp_twd.h>
#include <asm/hardware/cache-l2x0.h>
#include <asm/hardware/gic.h>
@@ -182,17 +180,9 @@ static void __init imx6q_init_machine(void)
imx6q_usb_init();
}
-static struct cpuidle_driver imx6q_cpuidle_driver = {
- .name = "imx6q_cpuidle",
- .owner = THIS_MODULE,
- .en_core_tk_irqen = 1,
- .states[0] = ARM_CPUIDLE_WFI_STATE,
- .state_count = 1,
-};
-
static void __init imx6q_init_late(void)
{
- imx_cpuidle_init(&imx6q_cpuidle_driver);
+ imx6q_cpuidle_init();
}
static void __init imx6q_map_io(void)
--
1.7.9.5
^ permalink raw reply related
* [PATCH 07/10] ARM: imx6q: get v7_cpu_resume ready for cpuidle
From: Shawn Guo @ 2012-10-23 15:22 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1351005779-30347-1-git-send-email-shawn.guo@linaro.org>
To get v7_cpu_resume ready for cpuidle power gating case, we need the
following changes.
* L2X0_POWER_CTRL register needs to be restored.
* Enable SCU inside v7_cpu_resume. As the result, function
imx_smp_prepare gets eliminated.
* Remove v7_invalidate_l1 invoking from v7_cpu_resume. It turns out
that v7_invalidate_l1 only needs to be called for secondary cores
startup.
Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
---
arch/arm/mach-imx/common.h | 2 --
arch/arm/mach-imx/headsmp.S | 25 ++++++++++++++++++++++---
arch/arm/mach-imx/platsmp.c | 7 +------
arch/arm/mach-imx/pm-imx6q.c | 1 -
4 files changed, 23 insertions(+), 12 deletions(-)
diff --git a/arch/arm/mach-imx/common.h b/arch/arm/mach-imx/common.h
index 9ff0776..ea11bbc 100644
--- a/arch/arm/mach-imx/common.h
+++ b/arch/arm/mach-imx/common.h
@@ -125,11 +125,9 @@ extern u32 *pl310_get_save_ptr(void);
#ifdef CONFIG_SMP
extern void v7_secondary_startup(void);
extern void imx_scu_map_io(void);
-extern void imx_smp_prepare(void);
extern void imx_scu_standby_enable(bool enable);
#else
static inline void imx_scu_map_io(void) {}
-static inline void imx_smp_prepare(void) {}
static inline void imx_scu_standby_enable(bool enable) {}
#endif
extern void imx_enable_cpu(int cpu, bool enable);
diff --git a/arch/arm/mach-imx/headsmp.S b/arch/arm/mach-imx/headsmp.S
index 7e49deb..ac8a967 100644
--- a/arch/arm/mach-imx/headsmp.S
+++ b/arch/arm/mach-imx/headsmp.S
@@ -27,8 +27,7 @@
* clean + invalidate, before jumping into the kernel.
*
* This funciton is cloned from arch/arm/mach-tegra/headsmp.S, and needs
- * to be called for both secondary cores startup and primary core resume
- * procedures. Ideally, it should be moved into arch/arm/mm/cache-v7.S.
+ * to be called for secondary cores startup.
*/
ENTRY(v7_invalidate_l1)
mov r0, #0
@@ -84,10 +83,16 @@ ENDPROC(v7_secondary_startup)
.macro pl310_resume
ldr r2, phys_l2x0_saved_regs
ldr r0, [r2, #L2X0_R_PHY_BASE] @ get physical base of l2x0
+ ldr r1, [r0, #L2X0_CTRL] @ check if already enabled
+ tst r1, #1
+ bne 1f
ldr r1, [r2, #L2X0_R_AUX_CTRL] @ get aux_ctrl value
str r1, [r0, #L2X0_AUX_CTRL] @ restore aux_ctrl
+ ldr r1, [r2, #L2X0_R_PWR_CTRL]
+ str r1, [r0, #L2X0_POWER_CTRL]
mov r1, #0x1
str r1, [r0, #L2X0_CTRL] @ re-enable L2
+1:
.endm
.globl phys_l2x0_saved_regs
@@ -98,9 +103,23 @@ phys_l2x0_saved_regs:
.endm
#endif
+#ifdef CONFIG_SMP
+ .macro _scu_enable
+ /* Enable SCU */
+ mrc p15, 4, r0, c15, c0, 0 @ r0 = scu physical base
+ ldr r1, [r0] @ r1 = scu control register
+ tst r1, #0x1 @ check if already enabled
+ orreq r1, r1, #0x1
+ streq r1, [r0]
+ .endm
+#else
+ .macro _scu_enable
+ .endm
+#endif
+
ENTRY(v7_cpu_resume)
- bl v7_invalidate_l1
pl310_resume
+ _scu_enable
b cpu_resume
ENDPROC(v7_cpu_resume)
#endif
diff --git a/arch/arm/mach-imx/platsmp.c b/arch/arm/mach-imx/platsmp.c
index c739a8a..fc25062 100644
--- a/arch/arm/mach-imx/platsmp.c
+++ b/arch/arm/mach-imx/platsmp.c
@@ -89,14 +89,9 @@ static void __init imx_smp_init_cpus(void)
set_smp_cross_call(gic_raise_softirq);
}
-void imx_smp_prepare(void)
-{
- scu_enable(scu_base);
-}
-
static void __init imx_smp_prepare_cpus(unsigned int max_cpus)
{
- imx_smp_prepare();
+ scu_enable(scu_base);
}
struct smp_operations imx_smp_ops __initdata = {
diff --git a/arch/arm/mach-imx/pm-imx6q.c b/arch/arm/mach-imx/pm-imx6q.c
index a17543d..7c4347b 100644
--- a/arch/arm/mach-imx/pm-imx6q.c
+++ b/arch/arm/mach-imx/pm-imx6q.c
@@ -39,7 +39,6 @@ static int imx6q_pm_enter(suspend_state_t state)
imx_set_cpu_jump(0, v7_cpu_resume);
/* Zzz ... */
cpu_suspend(0, imx6q_suspend_finish);
- imx_smp_prepare();
imx_gpc_post_resume();
break;
default:
--
1.7.9.5
^ permalink raw reply related
* [PATCH 06/10] ARM: imx6q: prepare imx6q_set_lpm for cpudile support
From: Shawn Guo @ 2012-10-23 15:22 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1351005779-30347-1-git-send-email-shawn.guo@linaro.org>
WAIT_UNCLOCKED and WAIT_UNCLOCKED_POWER_OFF will be used to implement
cpuidle. Get function imx6q_set_lpm for that. The unused mode
STOP_POWER_ON is removed from there.
Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
---
arch/arm/mach-imx/clk-imx6q.c | 32 +++++++++++++++++++++++++++-----
arch/arm/mach-imx/common.h | 3 +++
arch/arm/mach-imx/gpc.c | 11 +++++------
arch/arm/mach-imx/platsmp.c | 14 ++++++++++++++
4 files changed, 49 insertions(+), 11 deletions(-)
diff --git a/arch/arm/mach-imx/clk-imx6q.c b/arch/arm/mach-imx/clk-imx6q.c
index 5f9f591..5ac10a0 100644
--- a/arch/arm/mach-imx/clk-imx6q.c
+++ b/arch/arm/mach-imx/clk-imx6q.c
@@ -23,6 +23,10 @@
#include "clk.h"
#include "common.h"
+#define CCSR 0x0c
+#define BM_CCSR_PLL1_SW_CLK_SEL (0x1 << 2)
+#define BM_CCSR_STEP_SEL (0x1 << 8)
+
#define CCGR0 0x68
#define CCGR1 0x6c
#define CCGR2 0x70
@@ -60,22 +64,27 @@ void __init imx6q_clock_map_io(void) { }
int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode)
{
+ static enum mxc_cpu_pwr_mode last_mode;
+ static u32 ccsr;
u32 val = readl_relaxed(ccm_base + CLPCR);
val &= ~BM_CLPCR_LPM;
switch (mode) {
case WAIT_CLOCKED:
+ /* Restore CCSR changed by WAIT_UNCLOCKED */
+ if (last_mode == WAIT_UNCLOCKED)
+ writel_relaxed(ccsr, ccm_base + CCSR);
break;
case WAIT_UNCLOCKED:
val |= 0x1 << BP_CLPCR_LPM;
- break;
- case STOP_POWER_ON:
- val |= 0x2 << BP_CLPCR_LPM;
+ val |= BM_CLPCR_ARM_CLK_DIS_ON_LPM;
+ /* Source arm clock from 24 MHz OSC */
+ ccsr = readl_relaxed(ccm_base + CCSR);
+ writel_relaxed((ccsr | BM_CCSR_PLL1_SW_CLK_SEL) &
+ ~BM_CCSR_STEP_SEL, ccm_base + CCSR);
break;
case WAIT_UNCLOCKED_POWER_OFF:
val |= 0x1 << BP_CLPCR_LPM;
- val &= ~BM_CLPCR_VSTBY;
- val &= ~BM_CLPCR_SBYOS;
break;
case STOP_POWER_OFF:
val |= 0x2 << BP_CLPCR_LPM;
@@ -88,6 +97,19 @@ int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode)
}
writel_relaxed(val, ccm_base + CLPCR);
+ last_mode = mode;
+
+ /* Need to enable SCU standby for entering WAIT modes */
+ if (mode == WAIT_UNCLOCKED || mode == WAIT_UNCLOCKED_POWER_OFF)
+ imx_scu_standby_enable(true);
+ else
+ imx_scu_standby_enable(false);
+
+ /* Tell GPC whether to power off ARM core */
+ if (mode == WAIT_UNCLOCKED_POWER_OFF || mode == STOP_POWER_OFF)
+ imx_gpc_cpu_pdn(true);
+ else
+ imx_gpc_cpu_pdn(false);
return 0;
}
diff --git a/arch/arm/mach-imx/common.h b/arch/arm/mach-imx/common.h
index ef8db6b..9ff0776 100644
--- a/arch/arm/mach-imx/common.h
+++ b/arch/arm/mach-imx/common.h
@@ -126,9 +126,11 @@ extern u32 *pl310_get_save_ptr(void);
extern void v7_secondary_startup(void);
extern void imx_scu_map_io(void);
extern void imx_smp_prepare(void);
+extern void imx_scu_standby_enable(bool enable);
#else
static inline void imx_scu_map_io(void) {}
static inline void imx_smp_prepare(void) {}
+static inline void imx_scu_standby_enable(bool enable) {}
#endif
extern void imx_enable_cpu(int cpu, bool enable);
extern void imx_set_cpu_jump(int cpu, void *jump_addr);
@@ -137,6 +139,7 @@ extern void imx_src_prepare_restart(void);
extern void imx_gpc_init(void);
extern void imx_gpc_pre_suspend(void);
extern void imx_gpc_post_resume(void);
+extern void imx_gpc_cpu_pdn(bool);
extern int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode);
extern void imx6q_clock_map_io(void);
diff --git a/arch/arm/mach-imx/gpc.c b/arch/arm/mach-imx/gpc.c
index be9a6cb..897a5af 100644
--- a/arch/arm/mach-imx/gpc.c
+++ b/arch/arm/mach-imx/gpc.c
@@ -27,14 +27,16 @@ static void __iomem *gpc_base;
static u32 gpc_wake_irqs[IMR_NUM];
static u32 gpc_saved_imrs[IMR_NUM];
+void imx_gpc_cpu_pdn(bool pdn)
+{
+ writel_relaxed(pdn ? 0x1 : 0x0, gpc_base + GPC_PGC_CPU_PDN);
+}
+
void imx_gpc_pre_suspend(void)
{
void __iomem *reg_imr1 = gpc_base + GPC_IMR1;
int i;
- /* Tell GPC to power off ARM core when suspend */
- writel_relaxed(0x1, gpc_base + GPC_PGC_CPU_PDN);
-
for (i = 0; i < IMR_NUM; i++) {
gpc_saved_imrs[i] = readl_relaxed(reg_imr1 + i * 4);
writel_relaxed(~gpc_wake_irqs[i], reg_imr1 + i * 4);
@@ -46,9 +48,6 @@ void imx_gpc_post_resume(void)
void __iomem *reg_imr1 = gpc_base + GPC_IMR1;
int i;
- /* Keep ARM core powered on for other low-power modes */
- writel_relaxed(0x0, gpc_base + GPC_PGC_CPU_PDN);
-
for (i = 0; i < IMR_NUM; i++)
writel_relaxed(gpc_saved_imrs[i], reg_imr1 + i * 4);
}
diff --git a/arch/arm/mach-imx/platsmp.c b/arch/arm/mach-imx/platsmp.c
index 3777b80..c739a8a 100644
--- a/arch/arm/mach-imx/platsmp.c
+++ b/arch/arm/mach-imx/platsmp.c
@@ -20,6 +20,8 @@
#include "common.h"
#include "hardware.h"
+#define SCU_STANDBY_ENABLE (1 << 5)
+
static void __iomem *scu_base;
static struct map_desc scu_io_desc __initdata = {
@@ -42,6 +44,18 @@ void __init imx_scu_map_io(void)
scu_base = IMX_IO_ADDRESS(base);
}
+void imx_scu_standby_enable(bool enable)
+{
+ u32 val = readl_relaxed(scu_base);
+
+ if (enable)
+ val |= SCU_STANDBY_ENABLE;
+ else
+ val &= ~SCU_STANDBY_ENABLE;
+
+ writel_relaxed(val, scu_base);
+}
+
static void __cpuinit imx_secondary_init(unsigned int cpu)
{
/*
--
1.7.9.5
^ permalink raw reply related
* [PATCH 05/10] ARM: imx: mask gpc interrupts initially
From: Shawn Guo @ 2012-10-23 15:22 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1351005779-30347-1-git-send-email-shawn.guo@linaro.org>
Mask gpc interrupts initially to avoid suspicious interrupts.
Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
---
arch/arm/mach-imx/gpc.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/arch/arm/mach-imx/gpc.c b/arch/arm/mach-imx/gpc.c
index c75842d..be9a6cb 100644
--- a/arch/arm/mach-imx/gpc.c
+++ b/arch/arm/mach-imx/gpc.c
@@ -102,6 +102,7 @@ static void imx_gpc_irq_mask(struct irq_data *d)
void __init imx_gpc_init(void)
{
struct device_node *np;
+ int i;
np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-gpc");
gpc_base = of_iomap(np, 0);
@@ -110,6 +111,10 @@ void __init imx_gpc_init(void)
/* Initialize cpu power up counters to minimize the latency */
writel_relaxed(0x101, gpc_base + GPC_PGC_CPU_PUPSCR);
+ /* Initially mask all interrupts */
+ for (i = 0; i < IMR_NUM; i++)
+ writel_relaxed(~0, gpc_base + GPC_IMR1 + i * 4);
+
/* Register GPC as the secondary interrupt controller behind GIC */
gic_arch_extn.irq_mask = imx_gpc_irq_mask;
gic_arch_extn.irq_unmask = imx_gpc_irq_unmask;
--
1.7.9.5
^ permalink raw reply related
* [PATCH 04/10] ARM: imx: initialize cpu power up counters
From: Shawn Guo @ 2012-10-23 15:22 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1351005779-30347-1-git-send-email-shawn.guo@linaro.org>
The default values of cpu power up counters are unnecessarily large.
Initialize them to small ones for minimizing the power up latency.
Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
---
arch/arm/mach-imx/gpc.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/arch/arm/mach-imx/gpc.c b/arch/arm/mach-imx/gpc.c
index e1537f9..c75842d 100644
--- a/arch/arm/mach-imx/gpc.c
+++ b/arch/arm/mach-imx/gpc.c
@@ -19,6 +19,7 @@
#define GPC_IMR1 0x008
#define GPC_PGC_CPU_PDN 0x2a0
+#define GPC_PGC_CPU_PUPSCR 0x2a4
#define IMR_NUM 4
@@ -106,6 +107,9 @@ void __init imx_gpc_init(void)
gpc_base = of_iomap(np, 0);
WARN_ON(!gpc_base);
+ /* Initialize cpu power up counters to minimize the latency */
+ writel_relaxed(0x101, gpc_base + GPC_PGC_CPU_PUPSCR);
+
/* Register GPC as the secondary interrupt controller behind GIC */
gic_arch_extn.irq_mask = imx_gpc_irq_mask;
gic_arch_extn.irq_unmask = imx_gpc_irq_unmask;
--
1.7.9.5
^ permalink raw reply related
* [PATCH 03/10] ARM: imx6q: select ARM and PL310 errata
From: Shawn Guo @ 2012-10-23 15:22 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1351005779-30347-1-git-send-email-shawn.guo@linaro.org>
ARM core r2p10 and PL310 r3p2 are integrated on imx6q. Select
corresponding errata.
Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
---
arch/arm/mach-imx/Kconfig | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
index 4f73866..3ce2771 100644
--- a/arch/arm/mach-imx/Kconfig
+++ b/arch/arm/mach-imx/Kconfig
@@ -832,6 +832,11 @@ config SOC_IMX6Q
select ARCH_HAS_CPUFREQ
select ARCH_HAS_OPP
select ARM_CPU_SUSPEND if PM
+ select ARM_ERRATA_743622
+ select ARM_ERRATA_751472
+ select ARM_ERRATA_754322
+ select ARM_ERRATA_764369 if SMP
+ select ARM_ERRATA_775420
select ARM_GIC
select COMMON_CLK
select CPU_V7
@@ -843,6 +848,9 @@ config SOC_IMX6Q
select MFD_SYSCON
select PINCTRL
select PINCTRL_IMX6Q
+ select PL310_ERRATA_588369 if CACHE_PL310
+ select PL310_ERRATA_727915 if CACHE_PL310
+ select PL310_ERRATA_769419 if CACHE_PL310
select PM_OPP if PM
help
--
1.7.9.5
^ permalink raw reply related
* [PATCH 02/10] ARM: imx: allow timer counter to roll over
From: Shawn Guo @ 2012-10-23 15:22 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1351005779-30347-1-git-send-email-shawn.guo@linaro.org>
The timer is configured in free-run mode. The counter should be
allowed to roll over to 0 when reaching 0xffffffff. Let's do that
by always returning 0 in set_next_event.
Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
---
arch/arm/mach-imx/time.c | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/arch/arm/mach-imx/time.c b/arch/arm/mach-imx/time.c
index f017302..858098c 100644
--- a/arch/arm/mach-imx/time.c
+++ b/arch/arm/mach-imx/time.c
@@ -139,8 +139,7 @@ static int mx1_2_set_next_event(unsigned long evt,
__raw_writel(tcmp, timer_base + MX1_2_TCMP);
- return (int)(tcmp - __raw_readl(timer_base + MX1_2_TCN)) < 0 ?
- -ETIME : 0;
+ return 0;
}
static int v2_set_next_event(unsigned long evt,
@@ -152,8 +151,7 @@ static int v2_set_next_event(unsigned long evt,
__raw_writel(tcmp, timer_base + V2_TCMP);
- return (int)(tcmp - __raw_readl(timer_base + V2_TCN)) < 0 ?
- -ETIME : 0;
+ return 0;
}
#ifdef DEBUG
--
1.7.9.5
^ permalink raw reply related
* [PATCH 01/10] ARM: imx6q: print silicon version on boot
From: Shawn Guo @ 2012-10-23 15:22 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1351005779-30347-1-git-send-email-shawn.guo@linaro.org>
i.MX6Q has 3 revisions 1.0, 1.1 and 1.2. Print revision on boot.
Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
---
arch/arm/mach-imx/mach-imx6q.c | 28 ++++++++++++++++++++++++++++
1 file changed, 28 insertions(+)
diff --git a/arch/arm/mach-imx/mach-imx6q.c b/arch/arm/mach-imx/mach-imx6q.c
index 978b6dd..1c5acf8 100644
--- a/arch/arm/mach-imx/mach-imx6q.c
+++ b/arch/arm/mach-imx/mach-imx6q.c
@@ -38,6 +38,33 @@
#include "cpuidle.h"
#include "hardware.h"
+#define IMX6Q_ANALOG_DIGPROG 0x260
+
+static int imx6q_revision(void)
+{
+ struct device_node *np;
+ void __iomem *base;
+ static u32 rev;
+
+ if (!rev) {
+ np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-anatop");
+ base = of_iomap(np, 0);
+ rev = readl_relaxed(base + IMX6Q_ANALOG_DIGPROG);
+ iounmap(base);
+ }
+
+ switch (rev & 0xff) {
+ case 0:
+ return IMX_CHIP_REVISION_1_0;
+ case 1:
+ return IMX_CHIP_REVISION_1_1;
+ case 2:
+ return IMX_CHIP_REVISION_1_2;
+ default:
+ return IMX_CHIP_REVISION_UNKNOWN;
+ }
+}
+
void imx6q_restart(char mode, const char *cmd)
{
struct device_node *np;
@@ -192,6 +219,7 @@ static void __init imx6q_timer_init(void)
{
mx6q_clocks_init();
twd_local_timer_of_register();
+ imx_print_silicon_rev("i.MX6Q", imx6q_revision());
}
static struct sys_timer imx6q_timer = {
--
1.7.9.5
^ permalink raw reply related
* [PATCH 00/10] Support imx6q WAIT mode with coupled cpuidle
From: Shawn Guo @ 2012-10-23 15:22 UTC (permalink / raw)
To: linux-arm-kernel
The imx6q has a low power mode named WAIT. When all cores are in WFI,
imx6q will go into WAIT mode, and whenever there is a wakeup interrupt,
it will exit WAIT mode. Software can configure hardware behavior during
WAIT mode, clock gating or power gating for ARM core.
The series implements ARM clock gating and power gating in WAIT mode
as two coupled cpuidle states, wait and srpg. Though imx6q hardware
already handles sequencing, the voting provided by coupled cpuidle is
still quite useful, which will allow the system to at least get into
clock gating when one cpu wants clock gating and the other wants power
gating.
Patches 1 ~ 9 make necessary code changes to prepare for WAIT mode
enabling, and the last patch enables the feature eventually.
As WAIT mode is broken on TO1.0 silicon, the feature is only provided
for revisions later than TO1.0.
Shawn Guo (10):
ARM: imx6q: print silicon version on boot
ARM: imx: allow timer counter to roll over
ARM: imx6q: select ARM and PL310 errata
ARM: imx: initialize cpu power up counters
ARM: imx: mask gpc interrupts initially
ARM: imx6q: prepare imx6q_set_lpm for cpudile support
ARM: imx6q: get v7_cpu_resume ready for cpuidle
ARM: imx: move imx6q_cpuidle_driver into a separate file
ARM: SMP: add function arch_send_wakeup_ipi_mask()
ARM: imx6q: implement WAIT mode with coupled cpuidle
arch/arm/include/asm/smp.h | 1 +
arch/arm/kernel/smp.c | 5 ++
arch/arm/mach-imx/Kconfig | 9 ++
arch/arm/mach-imx/Makefile | 6 +-
arch/arm/mach-imx/clk-imx6q.c | 32 +++++--
arch/arm/mach-imx/common.h | 6 +-
arch/arm/mach-imx/cpuidle-imx6q.c | 177 +++++++++++++++++++++++++++++++++++++
arch/arm/mach-imx/cpuidle.c | 3 +
arch/arm/mach-imx/cpuidle.h | 5 ++
arch/arm/mach-imx/gpc.c | 20 +++--
arch/arm/mach-imx/headsmp.S | 81 ++++++++++++++++-
arch/arm/mach-imx/mach-imx6q.c | 45 +++++++---
arch/arm/mach-imx/platsmp.c | 26 ++++--
arch/arm/mach-imx/pm-imx6q.c | 1 -
arch/arm/mach-imx/time.c | 6 +-
15 files changed, 384 insertions(+), 39 deletions(-)
create mode 100644 arch/arm/mach-imx/cpuidle-imx6q.c
--
1.7.9.5
^ permalink raw reply
* [PATCH v2 1/4] ARM: dts: omap5: Update GPIO with address space and interrupts
From: Benoit Cousson @ 2012-10-23 15:09 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <5086AE8E.60106@ti.com>
On 10/23/2012 04:49 PM, Jon Hunter wrote:
> Hi Seb,
>
> On 10/23/2012 03:37 AM, Sebastien Guiriec wrote:
>> Add base address and interrupt line inside Device Tree data for
>> OMAP5
>>
>> Signed-off-by: Sebastien Guiriec <s-guiriec@ti.com>
>> ---
>> arch/arm/boot/dts/omap5.dtsi | 16 ++++++++++++++++
>> 1 file changed, 16 insertions(+)
>>
>> diff --git a/arch/arm/boot/dts/omap5.dtsi b/arch/arm/boot/dts/omap5.dtsi
>> index 42c78be..9e39f9f 100644
>> --- a/arch/arm/boot/dts/omap5.dtsi
>> +++ b/arch/arm/boot/dts/omap5.dtsi
>> @@ -104,6 +104,8 @@
>>
>> gpio1: gpio at 4ae10000 {
>> compatible = "ti,omap4-gpio";
>> + reg = <0x4ae10000 0x200>;
>> + interrupts = <0 29 0x4>;
>> ti,hwmods = "gpio1";
>> gpio-controller;
>> #gpio-cells = <2>;
>
> I am wondering if we should add the "interrupt-parent" property to add
> nodes in the device-tree source. I know that today the interrupt-parent
> is being defined globally, but when device-tree maps an interrupt for a
> device it searches for the interrupt-parent starting the current device
> node.
>
> So in other words, for gpio1 it will search the gpio1 binding for
> "interrupt-parent" and if not found move up a level and search again. It
> will keep doing this until it finds the "interrupt-parent".
>
> Therefore, I believe it will improve search time and hence, boot time if
> we have interrupt-parent defined in each node.
Mmm, I'm not that sure. it will increase the size of the blob, so
increase the time to load it and then to parse it. Where in the current
case, it is just going up to the parent node using the already
un-flatten tree in memory and thus that should not take that much time.
That being said, it might be interesting to benchmark that to see what
is the real impact.
Regards,
Benoit
^ permalink raw reply
* ERROR: "read_current_timer" [fs/ext4/ext4.ko] undefined
From: Will Deacon @ 2012-10-23 14:57 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <022101cdb12d$724e9650$56ebc2f0$@org>
On Tue, Oct 23, 2012 at 03:48:21PM +0100, Kukjin Kim wrote:
> Hi all,
>
> Now, v3.7-rc2 happens following build error with s3c2410_defconfig...
>
> ERROR: "read_current_timer" [fs/ext4/ext4.ko] undefined!
> make[2]: *** [__modpost] Error 1
> make[1]: *** [modules] Error 2
> make[1]: *** Waiting for unfinished jobs....
>
> Any idea on this?
A fix for this is queued in rmk's fixes branch.
Will
^ permalink raw reply
* ERROR: "read_current_timer" [fs/ext4/ext4.ko] undefined
From: Marc Zyngier @ 2012-10-23 14:57 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <022101cdb12d$724e9650$56ebc2f0$@org>
On 23/10/12 15:48, Kukjin Kim wrote:
> Hi all,
>
> Now, v3.7-rc2 happens following build error with s3c2410_defconfig...
>
> ERROR: "read_current_timer" [fs/ext4/ext4.ko] undefined!
> make[2]: *** [__modpost] Error 1
> make[1]: *** [modules] Error 2
> make[1]: *** Waiting for unfinished jobs....
>
> Any idea on this?
This is becoming a recurring pattern...
Please see:
https://patchwork.kernel.org/patch/1570611/
https://lkml.org/lkml/2012/10/9/393
and probably a few other instances...
M.
--
Jazz is not dead. It just smells funny...
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox