diff options
Diffstat (limited to 'arch/arm/mach-shmobile')
-rw-r--r-- | arch/arm/mach-shmobile/board-ag5evm.c | 3 | ||||
-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 | 139 | ||||
-rw-r--r-- | arch/arm/mach-shmobile/board-mackerel.c | 2 | ||||
-rw-r--r-- | arch/arm/mach-shmobile/clock-sh73a0.c | 18 | ||||
-rw-r--r-- | arch/arm/mach-shmobile/include/mach/common.h | 4 | ||||
-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/intc-sh7372.c | 50 | ||||
-rw-r--r-- | arch/arm/mach-shmobile/pm-sh7372.c | 196 | ||||
-rw-r--r-- | arch/arm/mach-shmobile/setup-sh7372.c | 6 | ||||
-rw-r--r-- | arch/arm/mach-shmobile/sleep-sh7372.S | 21 |
14 files changed, 357 insertions, 96 deletions
diff --git a/arch/arm/mach-shmobile/board-ag5evm.c b/arch/arm/mach-shmobile/board-ag5evm.c index 202c3c6ec9d..a4e6ca04e31 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(); @@ -607,6 +605,7 @@ struct sys_timer ag5evm_timer = { MACHINE_START(AG5EVM, "ag5evm") .map_io = ag5evm_map_io, + .nr_irqs = NR_IRQS_LEGACY, .init_irq = sh73a0_init_irq, .handle_irq = gic_handle_irq, .init_machine = ag5evm_init, diff --git a/arch/arm/mach-shmobile/board-ap4evb.c b/arch/arm/mach-shmobile/board-ap4evb.c index 4c865ece9ac..6a6f9f7568c 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 8b620bf0622..72d557281b1 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 7719ddc5f59..2220b885cff 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 1b4439d3f9d..857ceeec1bb 100644 --- a/arch/arm/mach-shmobile/board-kota2.c +++ b/arch/arm/mach-shmobile/board-kota2.c @@ -33,6 +33,7 @@ #include <linux/input/sh_keysc.h> #include <linux/gpio_keys.h> #include <linux/leds.h> +#include <linux/platform_data/leds-renesas-tpu.h> #include <linux/mmc/host.h> #include <linux/mmc/sh_mmcif.h> #include <linux/mfd/tmio.h> @@ -56,7 +57,7 @@ static struct resource smsc9220_resources[] = { .flags = IORESOURCE_MEM, }, [1] = { - .start = gic_spi(33), /* PINTA2 @ PORT144 */ + .start = SH73A0_PINT0_IRQ(2), /* PINTA2 */ .flags = IORESOURCE_IRQ, }, }; @@ -157,10 +158,6 @@ static struct platform_device gpio_keys_device = { #define GPIO_LED(n, g) { .name = n, .gpio = g } static struct gpio_led gpio_leds[] = { - GPIO_LED("V2513", GPIO_PORT153), /* PORT153 [TPU1T02] -> V2513 */ - GPIO_LED("V2514", GPIO_PORT199), /* PORT199 [TPU4TO1] -> V2514 */ - GPIO_LED("V2515", GPIO_PORT197), /* PORT197 [TPU2TO1] -> V2515 */ - GPIO_LED("KEYLED", GPIO_PORT163), /* PORT163 [TPU3TO0] -> KEYLED */ GPIO_LED("G", GPIO_PORT20), /* PORT20 [GPO0] -> LED7 -> "G" */ GPIO_LED("H", GPIO_PORT21), /* PORT21 [GPO1] -> LED8 -> "H" */ GPIO_LED("J", GPIO_PORT22), /* PORT22 [GPO2] -> LED9 -> "J" */ @@ -179,6 +176,119 @@ static struct platform_device gpio_leds_device = { }, }; +/* TPU LED */ +static struct led_renesas_tpu_config led_renesas_tpu12_pdata = { + .name = "V2513", + .pin_gpio_fn = GPIO_FN_TPU1TO2, + .pin_gpio = GPIO_PORT153, + .channel_offset = 0x90, + .timer_bit = 2, + .max_brightness = 1000, +}; + +static struct resource tpu12_resources[] = { + [0] = { + .name = "TPU12", + .start = 0xe6610090, + .end = 0xe66100b5, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device leds_tpu12_device = { + .name = "leds-renesas-tpu", + .id = 12, + .dev = { + .platform_data = &led_renesas_tpu12_pdata, + }, + .num_resources = ARRAY_SIZE(tpu12_resources), + .resource = tpu12_resources, +}; + +static struct led_renesas_tpu_config led_renesas_tpu41_pdata = { + .name = "V2514", + .pin_gpio_fn = GPIO_FN_TPU4TO1, + .pin_gpio = GPIO_PORT199, + .channel_offset = 0x50, + .timer_bit = 1, + .max_brightness = 1000, +}; + +static struct resource tpu41_resources[] = { + [0] = { + .name = "TPU41", + .start = 0xe6640050, + .end = 0xe6640075, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device leds_tpu41_device = { + .name = "leds-renesas-tpu", + .id = 41, + .dev = { + .platform_data = &led_renesas_tpu41_pdata, + }, + .num_resources = ARRAY_SIZE(tpu41_resources), + .resource = tpu41_resources, +}; + +static struct led_renesas_tpu_config led_renesas_tpu21_pdata = { + .name = "V2515", + .pin_gpio_fn = GPIO_FN_TPU2TO1, + .pin_gpio = GPIO_PORT197, + .channel_offset = 0x50, + .timer_bit = 1, + .max_brightness = 1000, +}; + +static struct resource tpu21_resources[] = { + [0] = { + .name = "TPU21", + .start = 0xe6620050, + .end = 0xe6620075, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device leds_tpu21_device = { + .name = "leds-renesas-tpu", + .id = 21, + .dev = { + .platform_data = &led_renesas_tpu21_pdata, + }, + .num_resources = ARRAY_SIZE(tpu21_resources), + .resource = tpu21_resources, +}; + +static struct led_renesas_tpu_config led_renesas_tpu30_pdata = { + .name = "KEYLED", + .pin_gpio_fn = GPIO_FN_TPU3TO0, + .pin_gpio = GPIO_PORT163, + .channel_offset = 0x10, + .timer_bit = 0, + .max_brightness = 1000, +}; + +static struct resource tpu30_resources[] = { + [0] = { + .name = "TPU30", + .start = 0xe6630010, + .end = 0xe6630035, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device leds_tpu30_device = { + .name = "leds-renesas-tpu", + .id = 30, + .dev = { + .platform_data = &led_renesas_tpu30_pdata, + }, + .num_resources = ARRAY_SIZE(tpu30_resources), + .resource = tpu30_resources, +}; + /* MMCIF */ static struct resource mmcif_resources[] = { [0] = { @@ -291,6 +401,10 @@ static struct platform_device *kota2_devices[] __initdata = { &keysc_device, &gpio_keys_device, &gpio_leds_device, + &leds_tpu12_device, + &leds_tpu41_device, + &leds_tpu21_device, + &leds_tpu30_device, &mmcif_device, &sdhi0_device, &sdhi1_device, @@ -317,18 +431,6 @@ static void __init kota2_map_io(void) shmobile_setup_console(); } -#define PINTER0A 0xe69000a0 -#define PINTCR0A 0xe69000b0 - -void __init kota2_init_irq(void) -{ - sh73a0_init_irq(); - - /* setup PINT: enable PINTA2 as active low */ - __raw_writel(1 << 29, PINTER0A); - __raw_writew(2 << 10, PINTCR0A); -} - static void __init kota2_init(void) { sh73a0_pinmux_init(); @@ -447,7 +549,8 @@ struct sys_timer kota2_timer = { MACHINE_START(KOTA2, "kota2") .map_io = kota2_map_io, - .init_irq = kota2_init_irq, + .nr_irqs = NR_IRQS_LEGACY, + .init_irq = sh73a0_init_irq, .handle_irq = gic_handle_irq, .init_machine = kota2_init, .timer = &kota2_timer, diff --git a/arch/arm/mach-shmobile/board-mackerel.c b/arch/arm/mach-shmobile/board-mackerel.c index 9c5e598e0e3..ed525668739 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/clock-sh73a0.c b/arch/arm/mach-shmobile/clock-sh73a0.c index 61a846bb30f..1370a89ca35 100644 --- a/arch/arm/mach-shmobile/clock-sh73a0.c +++ b/arch/arm/mach-shmobile/clock-sh73a0.c @@ -113,6 +113,12 @@ static struct clk main_clk = { .ops = &main_clk_ops, }; +/* Divide Main clock by two */ +static struct clk main_div2_clk = { + .ops = &div2_clk_ops, + .parent = &main_clk, +}; + /* PLL0, PLL1, PLL2, PLL3 */ static unsigned long pll_recalc(struct clk *clk) { @@ -181,6 +187,7 @@ static struct clk *main_clks[] = { &extal1_div2_clk, &extal2_div2_clk, &main_clk, + &main_div2_clk, &pll0_clk, &pll1_clk, &pll2_clk, @@ -243,7 +250,7 @@ static struct clk div6_clks[DIV6_NR] = { [DIV6_VCK1] = SH_CLK_DIV6(&pll1_div2_clk, VCLKCR1, 0), [DIV6_VCK2] = SH_CLK_DIV6(&pll1_div2_clk, VCLKCR2, 0), [DIV6_VCK3] = SH_CLK_DIV6(&pll1_div2_clk, VCLKCR3, 0), - [DIV6_ZB1] = SH_CLK_DIV6(&pll1_div2_clk, ZBCKCR, 0), + [DIV6_ZB1] = SH_CLK_DIV6(&pll1_div2_clk, ZBCKCR, CLK_ENABLE_ON_INIT), [DIV6_FLCTL] = SH_CLK_DIV6(&pll1_div2_clk, FLCKCR, 0), [DIV6_SDHI0] = SH_CLK_DIV6(&pll1_div2_clk, SD0CKCR, 0), [DIV6_SDHI1] = SH_CLK_DIV6(&pll1_div2_clk, SD1CKCR, 0), @@ -268,6 +275,7 @@ enum { MSTP001, MSTP207, MSTP206, MSTP204, MSTP203, MSTP202, MSTP201, MSTP200, MSTP331, MSTP329, MSTP325, MSTP323, MSTP318, MSTP314, MSTP313, MSTP312, MSTP311, + MSTP303, MSTP302, MSTP301, MSTP300, MSTP411, MSTP410, MSTP403, MSTP_NR }; @@ -301,6 +309,10 @@ static struct clk mstp_clks[MSTP_NR] = { [MSTP313] = MSTP(&div6_clks[DIV6_SDHI1], SMSTPCR3, 13, 0), /* SDHI1 */ [MSTP312] = MSTP(&div4_clks[DIV4_HP], SMSTPCR3, 12, 0), /* MMCIF0 */ [MSTP311] = MSTP(&div6_clks[DIV6_SDHI2], SMSTPCR3, 11, 0), /* SDHI2 */ + [MSTP303] = MSTP(&main_div2_clk, SMSTPCR3, 3, 0), /* TPU1 */ + [MSTP302] = MSTP(&main_div2_clk, SMSTPCR3, 2, 0), /* TPU2 */ + [MSTP301] = MSTP(&main_div2_clk, SMSTPCR3, 1, 0), /* TPU3 */ + [MSTP300] = MSTP(&main_div2_clk, SMSTPCR3, 0, 0), /* TPU4 */ [MSTP411] = MSTP(&div4_clks[DIV4_HP], SMSTPCR4, 11, 0), /* IIC3 */ [MSTP410] = MSTP(&div4_clks[DIV4_HP], SMSTPCR4, 10, 0), /* IIC4 */ [MSTP403] = MSTP(&r_clk, SMSTPCR4, 3, 0), /* KEYSC */ @@ -350,6 +362,10 @@ static struct clk_lookup lookups[] = { CLKDEV_DEV_ID("sh_mobile_sdhi.1", &mstp_clks[MSTP313]), /* SDHI1 */ CLKDEV_DEV_ID("sh_mmcif.0", &mstp_clks[MSTP312]), /* MMCIF0 */ CLKDEV_DEV_ID("sh_mobile_sdhi.2", &mstp_clks[MSTP311]), /* SDHI2 */ + CLKDEV_DEV_ID("leds-renesas-tpu.12", &mstp_clks[MSTP303]), /* TPU1 */ + CLKDEV_DEV_ID("leds-renesas-tpu.21", &mstp_clks[MSTP302]), /* TPU2 */ + CLKDEV_DEV_ID("leds-renesas-tpu.30", &mstp_clks[MSTP301]), /* TPU3 */ + CLKDEV_DEV_ID("leds-renesas-tpu.41", &mstp_clks[MSTP300]), /* TPU4 */ CLKDEV_DEV_ID("i2c-sh_mobile.3", &mstp_clks[MSTP411]), /* I2C3 */ CLKDEV_DEV_ID("i2c-sh_mobile.4", &mstp_clks[MSTP410]), /* I2C4 */ CLKDEV_DEV_ID("sh_keysc.0", &mstp_clks[MSTP403]), /* KEYSC */ diff --git a/arch/arm/mach-shmobile/include/mach/common.h b/arch/arm/mach-shmobile/include/mach/common.h index 4bf82c15677..be78a2c73db 100644 --- a/arch/arm/mach-shmobile/include/mach/common.h +++ b/arch/arm/mach-shmobile/include/mach/common.h @@ -34,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/gpio.h b/arch/arm/mach-shmobile/include/mach/gpio.h index 7bf0890e16b..de795b42232 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 84532f9629b..8254ab86f6c 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/intc-sh7372.c b/arch/arm/mach-shmobile/intc-sh7372.c index 2d8856df80e..89afcaba99a 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 34bbcbfb170..77b8fc12fc2 100644 --- a/arch/arm/mach-shmobile/pm-sh7372.c +++ b/arch/arm/mach-shmobile/pm-sh7372.c @@ -82,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; @@ -101,8 +102,8 @@ 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; } @@ -113,9 +114,6 @@ static int __pd_power_up(struct sh7372_pm_domain *sh7372_pd, bool do_resume) unsigned int retry_count; int ret = 0; - if (sh7372_pd->stay_on) - goto out; - if (__raw_readl(PSTR) & mask) goto out; @@ -133,8 +131,8 @@ static int __pd_power_up(struct sh7372_pm_domain *sh7372_pd, bool do_resume) 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 && do_resume) @@ -148,35 +146,60 @@ static int pd_power_up(struct generic_pm_domain *genpd) return __pd_power_up(to_sh7372_pd(genpd), true); } -static void sh7372_a4r_suspend(void) +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; __pd_power_up(sh7372_pd, false); @@ -199,48 +222,73 @@ 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, }; -struct sh7372_pm_domain sh7372_a3sp = { - .bit_shift = 11, - .gov = &sh7372_always_on_gov, +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 void sh7372_a3sp_init(void) +static int sh7372_a3sp_suspend(void) { - /* serial consoles make use of SCIF hardware located in A3SP, + /* + * Serial consoles make use of SCIF hardware located in A3SP, * keep such power domain on if "no_console_suspend" is set. */ - sh7372_a3sp.stay_on = !console_suspend_enabled; + return console_suspend_enabled ? -EBUSY : 0; } +struct sh7372_pm_domain sh7372_a3sp = { + .genpd.name = "A3SP", + .bit_shift = 11, + .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, }; @@ -257,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); @@ -274,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; @@ -382,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; @@ -415,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 @@ -448,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"); @@ -464,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) {} @@ -482,8 +580,6 @@ void __init sh7372_pm_init(void) /* do not convert A3SM, A3SP, A3SG, A4R power down into A4S */ __raw_writel(0, PDNSEL); - sh7372_a3sp_init(); - sh7372_suspend_init(); sh7372_cpuidle_init(); } diff --git a/arch/arm/mach-shmobile/setup-sh7372.c b/arch/arm/mach-shmobile/setup-sh7372.c index 2380389e6ac..c197f9d29d0 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 f3ab3c5810e..1d564674451 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 |