diff options
author | Paul Mundt <lethal@linux-sh.org> | 2012-01-09 09:56:37 +0900 |
---|---|---|
committer | Paul Mundt <lethal@linux-sh.org> | 2012-01-09 09:56:37 +0900 |
commit | 04cf399640b7acfa9abe2eb7900cd934db8af697 (patch) | |
tree | f9a055f2f0170550f5f0b0507b06ffce8d98945d /arch/arm/mach-shmobile | |
parent | 17f0056e6a2f3d1818801705f5e12b71217bf4ef (diff) | |
parent | a0e86bd4252519321b0d102dc4ed90557aa7bee9 (diff) | |
download | blackbird-op-linux-04cf399640b7acfa9abe2eb7900cd934db8af697.tar.gz blackbird-op-linux-04cf399640b7acfa9abe2eb7900cd934db8af697.zip |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux into rmobile-latest
Conflicts:
arch/arm/mach-shmobile/Makefile
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'arch/arm/mach-shmobile')
-rw-r--r-- | arch/arm/mach-shmobile/Makefile | 1 | ||||
-rw-r--r-- | arch/arm/mach-shmobile/board-ag5evm.c | 4 | ||||
-rw-r--r-- | arch/arm/mach-shmobile/board-ap4evb.c | 2 | ||||
-rw-r--r-- | arch/arm/mach-shmobile/board-g3evm.c | 2 | ||||
-rw-r--r-- | arch/arm/mach-shmobile/board-g4evm.c | 2 | ||||
-rw-r--r-- | arch/arm/mach-shmobile/board-kota2.c | 2 | ||||
-rw-r--r-- | arch/arm/mach-shmobile/board-mackerel.c | 2 | ||||
-rw-r--r-- | arch/arm/mach-shmobile/entry-gic.S | 18 | ||||
-rw-r--r-- | arch/arm/mach-shmobile/include/mach/common.h | 5 | ||||
-rw-r--r-- | arch/arm/mach-shmobile/include/mach/entry-macro.S | 9 | ||||
-rw-r--r-- | arch/arm/mach-shmobile/include/mach/gpio.h | 2 | ||||
-rw-r--r-- | arch/arm/mach-shmobile/include/mach/sh7372.h | 6 | ||||
-rw-r--r-- | arch/arm/mach-shmobile/include/mach/system.h | 2 | ||||
-rw-r--r-- | arch/arm/mach-shmobile/include/mach/vmalloc.h | 7 | ||||
-rw-r--r-- | arch/arm/mach-shmobile/intc-sh7372.c | 50 | ||||
-rw-r--r-- | arch/arm/mach-shmobile/pm-sh7372.c | 215 | ||||
-rw-r--r-- | arch/arm/mach-shmobile/setup-sh7372.c | 6 | ||||
-rw-r--r-- | arch/arm/mach-shmobile/sleep-sh7372.S | 21 |
18 files changed, 240 insertions, 116 deletions
diff --git a/arch/arm/mach-shmobile/Makefile b/arch/arm/mach-shmobile/Makefile index 5ee604dcaf57..83e35f254bff 100644 --- a/arch/arm/mach-shmobile/Makefile +++ b/arch/arm/mach-shmobile/Makefile @@ -30,7 +30,6 @@ pfc-$(CONFIG_ARCH_R8A7740) += pfc-r8a7740.o 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-intc.o # PM objects diff --git a/arch/arm/mach-shmobile/board-ag5evm.c b/arch/arm/mach-shmobile/board-ag5evm.c index 7119b87cbfa0..a4e6ca04e319 100644 --- a/arch/arm/mach-shmobile/board-ag5evm.c +++ b/arch/arm/mach-shmobile/board-ag5evm.c @@ -466,8 +466,6 @@ static struct map_desc ag5evm_io_desc[] __initdata = { static void __init ag5evm_map_io(void) { iotable_init(ag5evm_io_desc, ARRAY_SIZE(ag5evm_io_desc)); - /* DMA memory at 0xf6000000 - 0xffdfffff */ - init_consistent_dma_size(158 << 20); /* setup early devices and console here as well */ sh73a0_add_early_devices(); @@ -609,7 +607,7 @@ MACHINE_START(AG5EVM, "ag5evm") .map_io = ag5evm_map_io, .nr_irqs = NR_IRQS_LEGACY, .init_irq = sh73a0_init_irq, - .handle_irq = shmobile_handle_irq_gic, + .handle_irq = gic_handle_irq, .init_machine = ag5evm_init, .timer = &ag5evm_timer, MACHINE_END diff --git a/arch/arm/mach-shmobile/board-ap4evb.c b/arch/arm/mach-shmobile/board-ap4evb.c index 4c865ece9ac4..6a6f9f7568c2 100644 --- a/arch/arm/mach-shmobile/board-ap4evb.c +++ b/arch/arm/mach-shmobile/board-ap4evb.c @@ -1172,8 +1172,6 @@ static struct map_desc ap4evb_io_desc[] __initdata = { static void __init ap4evb_map_io(void) { iotable_init(ap4evb_io_desc, ARRAY_SIZE(ap4evb_io_desc)); - /* DMA memory at 0xf6000000 - 0xffdfffff */ - init_consistent_dma_size(158 << 20); /* setup early devices and console here as well */ sh7372_add_early_devices(); diff --git a/arch/arm/mach-shmobile/board-g3evm.c b/arch/arm/mach-shmobile/board-g3evm.c index 8b620bf06221..72d557281b1f 100644 --- a/arch/arm/mach-shmobile/board-g3evm.c +++ b/arch/arm/mach-shmobile/board-g3evm.c @@ -261,8 +261,6 @@ static struct map_desc g3evm_io_desc[] __initdata = { static void __init g3evm_map_io(void) { iotable_init(g3evm_io_desc, ARRAY_SIZE(g3evm_io_desc)); - /* DMA memory at 0xf6000000 - 0xffdfffff */ - init_consistent_dma_size(158 << 20); /* setup early devices and console here as well */ sh7367_add_early_devices(); diff --git a/arch/arm/mach-shmobile/board-g4evm.c b/arch/arm/mach-shmobile/board-g4evm.c index 7719ddc5f591..2220b885cff5 100644 --- a/arch/arm/mach-shmobile/board-g4evm.c +++ b/arch/arm/mach-shmobile/board-g4evm.c @@ -275,8 +275,6 @@ static struct map_desc g4evm_io_desc[] __initdata = { static void __init g4evm_map_io(void) { iotable_init(g4evm_io_desc, ARRAY_SIZE(g4evm_io_desc)); - /* DMA memory at 0xf6000000 - 0xffdfffff */ - init_consistent_dma_size(158 << 20); /* setup early devices and console here as well */ sh7377_add_early_devices(); diff --git a/arch/arm/mach-shmobile/board-kota2.c b/arch/arm/mach-shmobile/board-kota2.c index f44150b5ae46..857ceeec1bb0 100644 --- a/arch/arm/mach-shmobile/board-kota2.c +++ b/arch/arm/mach-shmobile/board-kota2.c @@ -551,7 +551,7 @@ MACHINE_START(KOTA2, "kota2") .map_io = kota2_map_io, .nr_irqs = NR_IRQS_LEGACY, .init_irq = sh73a0_init_irq, - .handle_irq = shmobile_handle_irq_gic, + .handle_irq = gic_handle_irq, .init_machine = kota2_init, .timer = &kota2_timer, MACHINE_END diff --git a/arch/arm/mach-shmobile/board-mackerel.c b/arch/arm/mach-shmobile/board-mackerel.c index 9c5e598e0e3d..ed5256687397 100644 --- a/arch/arm/mach-shmobile/board-mackerel.c +++ b/arch/arm/mach-shmobile/board-mackerel.c @@ -1390,8 +1390,6 @@ static struct map_desc mackerel_io_desc[] __initdata = { static void __init mackerel_map_io(void) { iotable_init(mackerel_io_desc, ARRAY_SIZE(mackerel_io_desc)); - /* DMA memory at 0xf6000000 - 0xffdfffff */ - init_consistent_dma_size(158 << 20); /* setup early devices and console here as well */ sh7372_add_early_devices(); diff --git a/arch/arm/mach-shmobile/entry-gic.S b/arch/arm/mach-shmobile/entry-gic.S deleted file mode 100644 index e20239b08c83..000000000000 --- a/arch/arm/mach-shmobile/entry-gic.S +++ /dev/null @@ -1,18 +0,0 @@ -/* - * ARM Interrupt demux handler using GIC - * - * Copyright (C) 2010 Magnus Damm - * Copyright (C) 2011 Paul Mundt - * Copyright (C) 2010 - 2011 Renesas Solutions Corp. - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ - -#include <asm/assembler.h> -#include <asm/entry-macro-multi.S> -#include <asm/hardware/gic.h> -#include <asm/hardware/entry-macro-gic.S> - - arch_irq_handler shmobile_handle_irq_gic diff --git a/arch/arm/mach-shmobile/include/mach/common.h b/arch/arm/mach-shmobile/include/mach/common.h index 5055a00a83d4..3a9250bb6d05 100644 --- a/arch/arm/mach-shmobile/include/mach/common.h +++ b/arch/arm/mach-shmobile/include/mach/common.h @@ -7,7 +7,6 @@ extern void shmobile_secondary_vector(void); struct clk; extern int clk_init(void); extern void shmobile_handle_irq_intc(struct pt_regs *); -extern void shmobile_handle_irq_gic(struct pt_regs *); extern struct platform_suspend_ops shmobile_suspend_ops; struct cpuidle_driver; extern void (*shmobile_cpuidle_modes[])(void); @@ -35,8 +34,8 @@ extern void sh7372_add_standard_devices(void); extern void sh7372_clock_init(void); extern void sh7372_pinmux_init(void); extern void sh7372_pm_init(void); -extern void sh7372_resume_core_standby_a3sm(void); -extern int sh7372_do_idle_a3sm(unsigned long unused); +extern void sh7372_resume_core_standby_sysc(void); +extern int sh7372_do_idle_sysc(unsigned long sleep_mode); extern struct clk sh7372_extal1_clk; extern struct clk sh7372_extal2_clk; diff --git a/arch/arm/mach-shmobile/include/mach/entry-macro.S b/arch/arm/mach-shmobile/include/mach/entry-macro.S index 8d4a416d4285..2a57b2964ee9 100644 --- a/arch/arm/mach-shmobile/include/mach/entry-macro.S +++ b/arch/arm/mach-shmobile/include/mach/entry-macro.S @@ -18,14 +18,5 @@ .macro disable_fiq .endm - .macro get_irqnr_preamble, base, tmp - .endm - - .macro get_irqnr_and_base, irqnr, irqstat, base, tmp - .endm - - .macro test_for_ipi, irqnr, irqstat, base, tmp - .endm - .macro arch_ret_to_user, tmp1, tmp2 .endm diff --git a/arch/arm/mach-shmobile/include/mach/gpio.h b/arch/arm/mach-shmobile/include/mach/gpio.h index 7bf0890e16ba..de795b42232a 100644 --- a/arch/arm/mach-shmobile/include/mach/gpio.h +++ b/arch/arm/mach-shmobile/include/mach/gpio.h @@ -12,8 +12,6 @@ #include <linux/kernel.h> #include <linux/errno.h> - -#define ARCH_NR_GPIOS 1024 #include <linux/sh_pfc.h> #ifdef CONFIG_GPIOLIB diff --git a/arch/arm/mach-shmobile/include/mach/sh7372.h b/arch/arm/mach-shmobile/include/mach/sh7372.h index 84532f9629b2..8254ab86f6cd 100644 --- a/arch/arm/mach-shmobile/include/mach/sh7372.h +++ b/arch/arm/mach-shmobile/include/mach/sh7372.h @@ -480,11 +480,10 @@ struct platform_device; struct sh7372_pm_domain { struct generic_pm_domain genpd; struct dev_power_governor *gov; - void (*suspend)(void); + int (*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) @@ -499,6 +498,7 @@ 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_a4s; extern struct sh7372_pm_domain sh7372_a3sp; extern struct sh7372_pm_domain sh7372_a3sg; @@ -515,5 +515,7 @@ extern void sh7372_pm_add_subdomain(struct sh7372_pm_domain *sh7372_pd, extern void sh7372_intcs_suspend(void); extern void sh7372_intcs_resume(void); +extern void sh7372_intca_suspend(void); +extern void sh7372_intca_resume(void); #endif /* __ASM_SH7372_H__ */ diff --git a/arch/arm/mach-shmobile/include/mach/system.h b/arch/arm/mach-shmobile/include/mach/system.h index 76a687eeaa22..956ac18ddbf9 100644 --- a/arch/arm/mach-shmobile/include/mach/system.h +++ b/arch/arm/mach-shmobile/include/mach/system.h @@ -8,7 +8,7 @@ static inline void arch_idle(void) static inline void arch_reset(char mode, const char *cmd) { - cpu_reset(0); + soft_restart(0); } #endif diff --git a/arch/arm/mach-shmobile/include/mach/vmalloc.h b/arch/arm/mach-shmobile/include/mach/vmalloc.h deleted file mode 100644 index 2b8fd8b942fe..000000000000 --- a/arch/arm/mach-shmobile/include/mach/vmalloc.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef __ASM_MACH_VMALLOC_H -#define __ASM_MACH_VMALLOC_H - -/* Vmalloc at ... - 0xe5ffffff */ -#define VMALLOC_END 0xe6000000UL - -#endif /* __ASM_MACH_VMALLOC_H */ diff --git a/arch/arm/mach-shmobile/intc-sh7372.c b/arch/arm/mach-shmobile/intc-sh7372.c index 2d8856df80e2..89afcaba99a1 100644 --- a/arch/arm/mach-shmobile/intc-sh7372.c +++ b/arch/arm/mach-shmobile/intc-sh7372.c @@ -535,6 +535,7 @@ static struct resource intcs_resources[] __initdata = { static struct intc_desc intcs_desc __initdata = { .name = "sh7372-intcs", .force_enable = ENABLED_INTCS, + .skip_syscore_suspend = true, .resource = intcs_resources, .num_resources = ARRAY_SIZE(intcs_resources), .hw = INTC_HW_DESC(intcs_vectors, intcs_groups, intcs_mask_registers, @@ -611,3 +612,52 @@ void sh7372_intcs_resume(void) for (k = 0x80; k <= 0x9c; k += 4) __raw_writeb(ffd5[k], intcs_ffd5 + k); } + +static unsigned short e694[0x200]; +static unsigned short e695[0x200]; + +void sh7372_intca_suspend(void) +{ + int k; + + for (k = 0x00; k <= 0x38; k += 4) + e694[k] = __raw_readw(0xe6940000 + k); + + for (k = 0x80; k <= 0xb4; k += 4) + e694[k] = __raw_readb(0xe6940000 + k); + + for (k = 0x180; k <= 0x1b4; k += 4) + e694[k] = __raw_readb(0xe6940000 + k); + + for (k = 0x00; k <= 0x50; k += 4) + e695[k] = __raw_readw(0xe6950000 + k); + + for (k = 0x80; k <= 0xa8; k += 4) + e695[k] = __raw_readb(0xe6950000 + k); + + for (k = 0x180; k <= 0x1a8; k += 4) + e695[k] = __raw_readb(0xe6950000 + k); +} + +void sh7372_intca_resume(void) +{ + int k; + + for (k = 0x00; k <= 0x38; k += 4) + __raw_writew(e694[k], 0xe6940000 + k); + + for (k = 0x80; k <= 0xb4; k += 4) + __raw_writeb(e694[k], 0xe6940000 + k); + + for (k = 0x180; k <= 0x1b4; k += 4) + __raw_writeb(e694[k], 0xe6940000 + k); + + for (k = 0x00; k <= 0x50; k += 4) + __raw_writew(e695[k], 0xe6950000 + k); + + for (k = 0x80; k <= 0xa8; k += 4) + __raw_writeb(e695[k], 0xe6950000 + k); + + for (k = 0x180; k <= 0x1a8; k += 4) + __raw_writeb(e695[k], 0xe6950000 + k); +} diff --git a/arch/arm/mach-shmobile/pm-sh7372.c b/arch/arm/mach-shmobile/pm-sh7372.c index 0a5b22942fd3..77b8fc12fc2f 100644 --- a/arch/arm/mach-shmobile/pm-sh7372.c +++ b/arch/arm/mach-shmobile/pm-sh7372.c @@ -20,6 +20,7 @@ #include <linux/delay.h> #include <linux/irq.h> #include <linux/bitrev.h> +#include <linux/console.h> #include <asm/system.h> #include <asm/io.h> #include <asm/tlbflush.h> @@ -81,11 +82,12 @@ static int pd_power_down(struct generic_pm_domain *genpd) 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->suspend) { + int ret = sh7372_pd->suspend(); - if (sh7372_pd->stay_on) - return 0; + if (ret) + return ret; + } if (__raw_readl(PSTR) & mask) { unsigned int retry_count; @@ -100,22 +102,18 @@ static int pd_power_down(struct generic_pm_domain *genpd) } if (!sh7372_pd->no_debug) - pr_debug("sh7372 power domain down 0x%08x -> PSTR = 0x%08x\n", - mask, __raw_readl(PSTR)); + pr_debug("%s: Power off, 0x%08x -> PSTR = 0x%08x\n", + genpd->name, mask, __raw_readl(PSTR)); return 0; } -static int pd_power_up(struct generic_pm_domain *genpd) +static int __pd_power_up(struct sh7372_pm_domain *sh7372_pd, bool do_resume) { - struct sh7372_pm_domain *sh7372_pd = to_sh7372_pd(genpd); unsigned int mask = 1 << sh7372_pd->bit_shift; unsigned int retry_count; int ret = 0; - if (sh7372_pd->stay_on) - goto out; - if (__raw_readl(PSTR) & mask) goto out; @@ -123,58 +121,88 @@ static int pd_power_up(struct generic_pm_domain *genpd) for (retry_count = 2 * PSTR_RETRIES; retry_count; retry_count--) { if (!(__raw_readl(SWUCR) & mask)) - goto out; + break; if (retry_count > PSTR_RETRIES) udelay(PSTR_DELAY_US); else cpu_relax(); } - if (__raw_readl(SWUCR) & mask) + if (!retry_count) ret = -EIO; if (!sh7372_pd->no_debug) - pr_debug("sh7372 power domain up 0x%08x -> PSTR = 0x%08x\n", - mask, __raw_readl(PSTR)); + pr_debug("%s: Power on, 0x%08x -> PSTR = 0x%08x\n", + sh7372_pd->genpd.name, mask, __raw_readl(PSTR)); out: - if (ret == 0 && sh7372_pd->resume) + if (ret == 0 && sh7372_pd->resume && do_resume) sh7372_pd->resume(); return ret; } -static void sh7372_a4r_suspend(void) +static int pd_power_up(struct generic_pm_domain *genpd) +{ + return __pd_power_up(to_sh7372_pd(genpd), true); +} + +static int sh7372_a4r_suspend(void) { sh7372_intcs_suspend(); __raw_writel(0x300fffff, WUPRMSK); /* avoid wakeup */ + return 0; } static bool pd_active_wakeup(struct device *dev) { - return true; + bool (*active_wakeup)(struct device *dev); + + active_wakeup = dev_gpd_data(dev)->ops.active_wakeup; + return active_wakeup ? active_wakeup(dev) : true; } -static bool sh7372_power_down_forbidden(struct dev_pm_domain *domain) +static int sh7372_stop_dev(struct device *dev) { - return false; + int (*stop)(struct device *dev); + + stop = dev_gpd_data(dev)->ops.stop; + if (stop) { + int ret = stop(dev); + if (ret) + return ret; + } + return pm_clk_suspend(dev); } -struct dev_power_governor sh7372_always_on_gov = { - .power_down_ok = sh7372_power_down_forbidden, -}; +static int sh7372_start_dev(struct device *dev) +{ + int (*start)(struct device *dev); + int ret; + + ret = pm_clk_resume(dev); + if (ret) + return ret; + + start = dev_gpd_data(dev)->ops.start; + if (start) + ret = start(dev); + + return ret; +} 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); - genpd->stop_device = pm_clk_suspend; - genpd->start_device = pm_clk_resume; + pm_genpd_init(genpd, gov ? : &simple_qos_governor, false); + genpd->dev_ops.stop = sh7372_stop_dev; + genpd->dev_ops.start = sh7372_start_dev; + genpd->dev_ops.active_wakeup = pd_active_wakeup; genpd->dev_irq_safe = true; - genpd->active_wakeup = pd_active_wakeup; genpd->power_off = pd_power_down; genpd->power_on = pd_power_up; - genpd->power_on(&sh7372_pd->genpd); + __pd_power_up(sh7372_pd, false); } void sh7372_add_device_to_domain(struct sh7372_pm_domain *sh7372_pd, @@ -194,44 +222,81 @@ void sh7372_pm_add_subdomain(struct sh7372_pm_domain *sh7372_pd, } struct sh7372_pm_domain sh7372_a4lc = { + .genpd.name = "A4LC", .bit_shift = 1, }; struct sh7372_pm_domain sh7372_a4mp = { + .genpd.name = "A4MP", .bit_shift = 2, }; struct sh7372_pm_domain sh7372_d4 = { + .genpd.name = "D4", .bit_shift = 3, }; struct sh7372_pm_domain sh7372_a4r = { + .genpd.name = "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 = { + .genpd.name = "A3RV", .bit_shift = 6, }; struct sh7372_pm_domain sh7372_a3ri = { + .genpd.name = "A3RI", .bit_shift = 8, }; +static int sh7372_a4s_suspend(void) +{ + /* + * The A4S domain contains the CPU core and therefore it should + * only be turned off if the CPU is in use. + */ + return -EBUSY; +} + +struct sh7372_pm_domain sh7372_a4s = { + .genpd.name = "A4S", + .bit_shift = 10, + .gov = &pm_domain_always_on_gov, + .no_debug = true, + .suspend = sh7372_a4s_suspend, +}; + +static int sh7372_a3sp_suspend(void) +{ + /* + * Serial consoles make use of SCIF hardware located in A3SP, + * keep such power domain on if "no_console_suspend" is set. + */ + return console_suspend_enabled ? -EBUSY : 0; +} + struct sh7372_pm_domain sh7372_a3sp = { + .genpd.name = "A3SP", .bit_shift = 11, - .gov = &sh7372_always_on_gov, + .gov = &pm_domain_always_on_gov, .no_debug = true, + .suspend = sh7372_a3sp_suspend, }; struct sh7372_pm_domain sh7372_a3sg = { + .genpd.name = "A3SG", .bit_shift = 13, }; -#endif /* CONFIG_PM */ +#else /* !CONFIG_PM */ + +static inline void sh7372_a3sp_init(void) {} + +#endif /* !CONFIG_PM */ #if defined(CONFIG_SUSPEND) || defined(CONFIG_CPU_IDLE) static int sh7372_do_idle_core_standby(unsigned long unused) @@ -240,11 +305,16 @@ static int sh7372_do_idle_core_standby(unsigned long unused) return 0; } -static void sh7372_enter_core_standby(void) +static void sh7372_set_reset_vector(unsigned long address) { /* set reset vector, translate 4k */ - __raw_writel(__pa(sh7372_resume_core_standby_a3sm), SBAR); + __raw_writel(address, SBAR); __raw_writel(0, APARMBAREA); +} + +static void sh7372_enter_core_standby(void) +{ + sh7372_set_reset_vector(__pa(sh7372_resume_core_standby_sysc)); /* enter sleep mode with SYSTBCR to 0x10 */ __raw_writel(0x10, SYSTBCR); @@ -257,27 +327,22 @@ static void sh7372_enter_core_standby(void) #endif #ifdef CONFIG_SUSPEND -static void sh7372_enter_a3sm_common(int pllc0_on) +static void sh7372_enter_sysc(int pllc0_on, unsigned long sleep_mode) { - /* set reset vector, translate 4k */ - __raw_writel(__pa(sh7372_resume_core_standby_a3sm), SBAR); - __raw_writel(0, APARMBAREA); - if (pllc0_on) __raw_writel(0, PLLC01STPCR); else __raw_writel(1 << 28, PLLC01STPCR); - __raw_writel(0, PDNSEL); /* power-down A3SM only, not A4S */ __raw_readl(WUPSFAC); /* read wakeup int. factor before sleep */ - cpu_suspend(0, sh7372_do_idle_a3sm); + cpu_suspend(sleep_mode, sh7372_do_idle_sysc); __raw_readl(WUPSFAC); /* read wakeup int. factor after wakeup */ /* disable reset vector translation */ __raw_writel(0, SBAR); } -static int sh7372_a3sm_valid(unsigned long *mskp, unsigned long *msk2p) +static int sh7372_sysc_valid(unsigned long *mskp, unsigned long *msk2p) { unsigned long mstpsr0, mstpsr1, mstpsr2, mstpsr3, mstpsr4; unsigned long msk, msk2; @@ -365,7 +430,7 @@ static void sh7372_icr_to_irqcr(unsigned long icr, u16 *irqcr1p, u16 *irqcr2p) *irqcr2p = irqcr2; } -static void sh7372_setup_a3sm(unsigned long msk, unsigned long msk2) +static void sh7372_setup_sysc(unsigned long msk, unsigned long msk2) { u16 irqcrx_low, irqcrx_high, irqcry_low, irqcry_high; unsigned long tmp; @@ -398,6 +463,22 @@ static void sh7372_setup_a3sm(unsigned long msk, unsigned long msk2) __raw_writel((irqcrx_high << 16) | irqcrx_low, IRQCR3); __raw_writel((irqcry_high << 16) | irqcry_low, IRQCR4); } + +static void sh7372_enter_a3sm_common(int pllc0_on) +{ + sh7372_set_reset_vector(__pa(sh7372_resume_core_standby_sysc)); + sh7372_enter_sysc(pllc0_on, 1 << 12); +} + +static void sh7372_enter_a4s_common(int pllc0_on) +{ + sh7372_intca_suspend(); + memcpy((void *)SMFRAM, sh7372_resume_core_standby_sysc, 0x100); + sh7372_set_reset_vector(SMFRAM); + sh7372_enter_sysc(pllc0_on, 1 << 10); + sh7372_intca_resume(); +} + #endif #ifdef CONFIG_CPU_IDLE @@ -431,14 +512,20 @@ static int sh7372_enter_suspend(suspend_state_t suspend_state) unsigned long msk, msk2; /* check active clocks to determine potential wakeup sources */ - if (sh7372_a3sm_valid(&msk, &msk2)) { - + if (sh7372_sysc_valid(&msk, &msk2)) { /* convert INTC mask and sense to SYSC mask and sense */ - sh7372_setup_a3sm(msk, msk2); - - /* enter A3SM sleep with PLLC0 off */ - pr_debug("entering A3SM\n"); - sh7372_enter_a3sm_common(0); + sh7372_setup_sysc(msk, msk2); + + if (!console_suspend_enabled && + sh7372_a4s.genpd.status == GPD_STATE_POWER_OFF) { + /* enter A4S sleep with PLLC0 off */ + pr_debug("entering A4S\n"); + sh7372_enter_a4s_common(0); + } else { + /* enter A3SM sleep with PLLC0 off */ + pr_debug("entering A3SM\n"); + sh7372_enter_a3sm_common(0); + } } else { /* default to Core Standby that supports all wakeup sources */ pr_debug("entering Core Standby\n"); @@ -447,9 +534,37 @@ static int sh7372_enter_suspend(suspend_state_t suspend_state) return 0; } +/** + * sh7372_pm_notifier_fn - SH7372 PM notifier routine. + * @notifier: Unused. + * @pm_event: Event being handled. + * @unused: Unused. + */ +static int sh7372_pm_notifier_fn(struct notifier_block *notifier, + unsigned long pm_event, void *unused) +{ + switch (pm_event) { + case PM_SUSPEND_PREPARE: + /* + * This is necessary, because the A4R domain has to be "on" + * when suspend_device_irqs() and resume_device_irqs() are + * executed during system suspend and resume, respectively, so + * that those functions don't crash while accessing the INTCS. + */ + pm_genpd_poweron(&sh7372_a4r.genpd); + break; + case PM_POST_SUSPEND: + pm_genpd_poweroff_unused(); + break; + } + + return NOTIFY_DONE; +} + static void sh7372_suspend_init(void) { shmobile_suspend_ops.enter = sh7372_enter_suspend; + pm_notifier(sh7372_pm_notifier_fn, 0); } #else static void sh7372_suspend_init(void) {} diff --git a/arch/arm/mach-shmobile/setup-sh7372.c b/arch/arm/mach-shmobile/setup-sh7372.c index 2380389e6ac5..c197f9d29d04 100644 --- a/arch/arm/mach-shmobile/setup-sh7372.c +++ b/arch/arm/mach-shmobile/setup-sh7372.c @@ -994,12 +994,16 @@ void __init sh7372_add_standard_devices(void) 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_a4s); sh7372_init_pm_domain(&sh7372_a3sp); + sh7372_init_pm_domain(&sh7372_a3sg); sh7372_pm_add_subdomain(&sh7372_a4lc, &sh7372_a3rv); sh7372_pm_add_subdomain(&sh7372_a4r, &sh7372_a4lc); + sh7372_pm_add_subdomain(&sh7372_a4s, &sh7372_a3sg); + sh7372_pm_add_subdomain(&sh7372_a4s, &sh7372_a3sp); + platform_add_devices(sh7372_early_devices, ARRAY_SIZE(sh7372_early_devices)); diff --git a/arch/arm/mach-shmobile/sleep-sh7372.S b/arch/arm/mach-shmobile/sleep-sh7372.S index f3ab3c5810ea..1d564674451d 100644 --- a/arch/arm/mach-shmobile/sleep-sh7372.S +++ b/arch/arm/mach-shmobile/sleep-sh7372.S @@ -37,13 +37,18 @@ #if defined(CONFIG_SUSPEND) || defined(CONFIG_CPU_IDLE) .align 12 .text - .global sh7372_resume_core_standby_a3sm -sh7372_resume_core_standby_a3sm: + .global sh7372_resume_core_standby_sysc +sh7372_resume_core_standby_sysc: ldr pc, 1f 1: .long cpu_resume - PAGE_OFFSET + PLAT_PHYS_OFFSET - .global sh7372_do_idle_a3sm -sh7372_do_idle_a3sm: +#define SPDCR 0xe6180008 + + /* A3SM & A4S power down */ + .global sh7372_do_idle_sysc +sh7372_do_idle_sysc: + mov r8, r0 /* sleep mode passed in r0 */ + /* * Clear the SCTLR.C bit to prevent further data cache * allocation. Clearing SCTLR.C would make all the data accesses @@ -80,13 +85,9 @@ sh7372_do_idle_a3sm: dsb dmb -#define SPDCR 0xe6180008 -#define A3SM (1 << 12) - - /* A3SM power down */ + /* SYSC power down */ ldr r0, =SPDCR - ldr r1, =A3SM - str r1, [r0] + str r8, [r0] 1: b 1b |