diff options
| author | Rafael J. Wysocki <rjw@sisk.pl> | 2011-07-01 16:13:56 -0400 |
|---|---|---|
| committer | Rafael J. Wysocki <rjw@sisk.pl> | 2011-07-02 08:29:57 -0400 |
| commit | e3e0109138376bb262b8ecf33bad0586fa131925 (patch) | |
| tree | 0d078578eecee050041fc5f27976d1b0354712fc | |
| parent | 3d5c30367cbc0c55c93bb158e824e00badc7ddc4 (diff) | |
ARM / shmobile: Support for I/O power domains for SH7372 (v9)
Use the generic power domains support introduced by the previous
patch to implement support for power domains on SH7372.
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Acked-by: Paul Mundt <lethal@linux-sh.org>
| -rw-r--r-- | arch/arm/Kconfig | 1 | ||||
| -rw-r--r-- | arch/arm/mach-shmobile/board-mackerel.c | 4 | ||||
| -rw-r--r-- | arch/arm/mach-shmobile/include/mach/sh7372.h | 24 | ||||
| -rw-r--r-- | arch/arm/mach-shmobile/pm-sh7372.c | 102 |
4 files changed, 131 insertions, 0 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 9adc278a22ab..e04fa9d7637c 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig | |||
| @@ -642,6 +642,7 @@ config ARCH_SHMOBILE | |||
| 642 | select NO_IOPORT | 642 | select NO_IOPORT |
| 643 | select SPARSE_IRQ | 643 | select SPARSE_IRQ |
| 644 | select MULTI_IRQ_HANDLER | 644 | select MULTI_IRQ_HANDLER |
| 645 | select PM_GENERIC_DOMAINS if PM | ||
| 645 | help | 646 | help |
| 646 | Support for Renesas's SH-Mobile and R-Mobile ARM platforms. | 647 | Support for Renesas's SH-Mobile and R-Mobile ARM platforms. |
| 647 | 648 | ||
diff --git a/arch/arm/mach-shmobile/board-mackerel.c b/arch/arm/mach-shmobile/board-mackerel.c index 3802f2afabef..f93b1cb27fef 100644 --- a/arch/arm/mach-shmobile/board-mackerel.c +++ b/arch/arm/mach-shmobile/board-mackerel.c | |||
| @@ -1582,6 +1582,10 @@ static void __init mackerel_init(void) | |||
| 1582 | 1582 | ||
| 1583 | platform_add_devices(mackerel_devices, ARRAY_SIZE(mackerel_devices)); | 1583 | platform_add_devices(mackerel_devices, ARRAY_SIZE(mackerel_devices)); |
| 1584 | 1584 | ||
| 1585 | sh7372_init_pm_domain(&sh7372_a4lc); | ||
| 1586 | sh7372_add_device_to_domain(&sh7372_a4lc, &lcdc_device); | ||
| 1587 | sh7372_add_device_to_domain(&sh7372_a4lc, &hdmi_lcdc_device); | ||
| 1588 | |||
| 1585 | hdmi_init_pm_clock(); | 1589 | hdmi_init_pm_clock(); |
| 1586 | sh7372_pm_init(); | 1590 | sh7372_pm_init(); |
| 1587 | } | 1591 | } |
diff --git a/arch/arm/mach-shmobile/include/mach/sh7372.h b/arch/arm/mach-shmobile/include/mach/sh7372.h index df20d7670172..495013c75c6b 100644 --- a/arch/arm/mach-shmobile/include/mach/sh7372.h +++ b/arch/arm/mach-shmobile/include/mach/sh7372.h | |||
| @@ -12,6 +12,7 @@ | |||
| 12 | #define __ASM_SH7372_H__ | 12 | #define __ASM_SH7372_H__ |
| 13 | 13 | ||
| 14 | #include <linux/sh_clk.h> | 14 | #include <linux/sh_clk.h> |
| 15 | #include <linux/pm_domain.h> | ||
| 15 | 16 | ||
| 16 | /* | 17 | /* |
| 17 | * Pin Function Controller: | 18 | * Pin Function Controller: |
| @@ -470,4 +471,27 @@ extern struct clk sh7372_fsibck_clk; | |||
| 470 | extern struct clk sh7372_fsidiva_clk; | 471 | extern struct clk sh7372_fsidiva_clk; |
| 471 | extern struct clk sh7372_fsidivb_clk; | 472 | extern struct clk sh7372_fsidivb_clk; |
| 472 | 473 | ||
| 474 | struct platform_device; | ||
| 475 | |||
| 476 | struct sh7372_pm_domain { | ||
| 477 | struct generic_pm_domain genpd; | ||
| 478 | unsigned int bit_shift; | ||
| 479 | }; | ||
| 480 | |||
| 481 | static inline struct sh7372_pm_domain *to_sh7372_pd(struct generic_pm_domain *d) | ||
| 482 | { | ||
| 483 | return container_of(d, struct sh7372_pm_domain, genpd); | ||
| 484 | } | ||
| 485 | |||
| 486 | #ifdef CONFIG_PM | ||
| 487 | extern struct sh7372_pm_domain sh7372_a4lc; | ||
| 488 | |||
| 489 | extern void sh7372_init_pm_domain(struct sh7372_pm_domain *sh7372_pd); | ||
| 490 | extern void sh7372_add_device_to_domain(struct sh7372_pm_domain *sh7372_pd, | ||
| 491 | struct platform_device *pdev); | ||
| 492 | #else | ||
| 493 | #define sh7372_init_pm_domain(pd) do { } while(0) | ||
| 494 | #define sh7372_add_device_to_domain(pd, pdev) do { } while(0) | ||
| 495 | #endif /* CONFIG_PM */ | ||
| 496 | |||
| 473 | #endif /* __ASM_SH7372_H__ */ | 497 | #endif /* __ASM_SH7372_H__ */ |
diff --git a/arch/arm/mach-shmobile/pm-sh7372.c b/arch/arm/mach-shmobile/pm-sh7372.c index 8e4aadf14c9f..e17f12424ec7 100644 --- a/arch/arm/mach-shmobile/pm-sh7372.c +++ b/arch/arm/mach-shmobile/pm-sh7372.c | |||
| @@ -15,16 +15,118 @@ | |||
| 15 | #include <linux/list.h> | 15 | #include <linux/list.h> |
| 16 | #include <linux/err.h> | 16 | #include <linux/err.h> |
| 17 | #include <linux/slab.h> | 17 | #include <linux/slab.h> |
| 18 | #include <linux/pm_runtime.h> | ||
| 19 | #include <linux/platform_device.h> | ||
| 20 | #include <linux/delay.h> | ||
| 18 | #include <asm/system.h> | 21 | #include <asm/system.h> |
| 19 | #include <asm/io.h> | 22 | #include <asm/io.h> |
| 20 | #include <asm/tlbflush.h> | 23 | #include <asm/tlbflush.h> |
| 21 | #include <mach/common.h> | 24 | #include <mach/common.h> |
| 25 | #include <mach/sh7372.h> | ||
| 22 | 26 | ||
| 23 | #define SMFRAM 0xe6a70000 | 27 | #define SMFRAM 0xe6a70000 |
| 24 | #define SYSTBCR 0xe6150024 | 28 | #define SYSTBCR 0xe6150024 |
| 25 | #define SBAR 0xe6180020 | 29 | #define SBAR 0xe6180020 |
| 26 | #define APARMBAREA 0xe6f10020 | 30 | #define APARMBAREA 0xe6f10020 |
| 27 | 31 | ||
| 32 | #define SPDCR 0xe6180008 | ||
| 33 | #define SWUCR 0xe6180014 | ||
| 34 | #define PSTR 0xe6180080 | ||
| 35 | |||
| 36 | #define PSTR_RETRIES 100 | ||
| 37 | #define PSTR_DELAY_US 10 | ||
| 38 | |||
| 39 | #ifdef CONFIG_PM | ||
| 40 | |||
| 41 | static int pd_power_down(struct generic_pm_domain *genpd) | ||
| 42 | { | ||
| 43 | struct sh7372_pm_domain *sh7372_pd = to_sh7372_pd(genpd); | ||
| 44 | unsigned int mask = 1 << sh7372_pd->bit_shift; | ||
| 45 | |||
| 46 | if (__raw_readl(PSTR) & mask) { | ||
| 47 | unsigned int retry_count; | ||
| 48 | |||
| 49 | __raw_writel(mask, SPDCR); | ||
| 50 | |||
| 51 | for (retry_count = PSTR_RETRIES; retry_count; retry_count--) { | ||
| 52 | if (!(__raw_readl(SPDCR) & mask)) | ||
| 53 | break; | ||
| 54 | cpu_relax(); | ||
| 55 | } | ||
| 56 | } | ||
| 57 | |||
| 58 | pr_debug("sh7372 power domain down 0x%08x -> PSTR = 0x%08x\n", | ||
| 59 | mask, __raw_readl(PSTR)); | ||
| 60 | |||
| 61 | return 0; | ||
| 62 | } | ||
| 63 | |||
| 64 | static int pd_power_up(struct generic_pm_domain *genpd) | ||
| 65 | { | ||
| 66 | struct sh7372_pm_domain *sh7372_pd = to_sh7372_pd(genpd); | ||
| 67 | unsigned int mask = 1 << sh7372_pd->bit_shift; | ||
| 68 | unsigned int retry_count; | ||
| 69 | int ret = 0; | ||
| 70 | |||
| 71 | if (__raw_readl(PSTR) & mask) | ||
| 72 | goto out; | ||
| 73 | |||
| 74 | __raw_writel(mask, SWUCR); | ||
| 75 | |||
| 76 | for (retry_count = 2 * PSTR_RETRIES; retry_count; retry_count--) { | ||
| 77 | if (!(__raw_readl(SWUCR) & mask)) | ||
| 78 | goto out; | ||
| 79 | if (retry_count > PSTR_RETRIES) | ||
| 80 | udelay(PSTR_DELAY_US); | ||
| 81 | else | ||
| 82 | cpu_relax(); | ||
| 83 | } | ||
| 84 | if (__raw_readl(SWUCR) & mask) | ||
| 85 | ret = -EIO; | ||
| 86 | |||
| 87 | out: | ||
| 88 | pr_debug("sh7372 power domain up 0x%08x -> PSTR = 0x%08x\n", | ||
| 89 | mask, __raw_readl(PSTR)); | ||
| 90 | |||
| 91 | return ret; | ||
| 92 | } | ||
| 93 | |||
| 94 | static bool pd_active_wakeup(struct device *dev) | ||
| 95 | { | ||
| 96 | return true; | ||
| 97 | } | ||
| 98 | |||
| 99 | void sh7372_init_pm_domain(struct sh7372_pm_domain *sh7372_pd) | ||
| 100 | { | ||
| 101 | struct generic_pm_domain *genpd = &sh7372_pd->genpd; | ||
| 102 | |||
| 103 | pm_genpd_init(genpd, NULL, false); | ||
| 104 | genpd->stop_device = pm_clk_suspend; | ||
| 105 | genpd->start_device = pm_clk_resume; | ||
| 106 | genpd->active_wakeup = pd_active_wakeup; | ||
| 107 | genpd->power_off = pd_power_down; | ||
| 108 | genpd->power_on = pd_power_up; | ||
| 109 | pd_power_up(&sh7372_pd->genpd); | ||
| 110 | } | ||
| 111 | |||
| 112 | void sh7372_add_device_to_domain(struct sh7372_pm_domain *sh7372_pd, | ||
| 113 | struct platform_device *pdev) | ||
| 114 | { | ||
| 115 | struct device *dev = &pdev->dev; | ||
| 116 | |||
| 117 | if (!dev->power.subsys_data) { | ||
| 118 | pm_clk_init(dev); | ||
| 119 | pm_clk_add(dev, NULL); | ||
| 120 | } | ||
| 121 | pm_genpd_add_device(&sh7372_pd->genpd, dev); | ||
| 122 | } | ||
| 123 | |||
| 124 | struct sh7372_pm_domain sh7372_a4lc = { | ||
| 125 | .bit_shift = 1, | ||
| 126 | }; | ||
| 127 | |||
| 128 | #endif /* CONFIG_PM */ | ||
| 129 | |||
| 28 | static void sh7372_enter_core_standby(void) | 130 | static void sh7372_enter_core_standby(void) |
| 29 | { | 131 | { |
| 30 | void __iomem *smfram = (void __iomem *)SMFRAM; | 132 | void __iomem *smfram = (void __iomem *)SMFRAM; |
