diff options
author | Magnus Damm <damm@igel.co.jp> | 2009-07-17 10:24:55 -0400 |
---|---|---|
committer | Paul Mundt <lethal@linux-sh.org> | 2009-07-19 15:23:39 -0400 |
commit | 0f8ee1874fa80899debc0a0670e2bed0a28d2548 (patch) | |
tree | f9d58ced4b3b8e6ac50371fdb009e3446bce40c8 | |
parent | a61c1a636628a28ab5b42a9d36582a8f6a08893a (diff) |
sh: Add support for multiple hwblk counters
Extend the SuperH hwblk code to support more than one counter.
Contains ground work for the future Runtime PM implementation.
Signed-off-by: Magnus Damm <damm@igel.co.jp>
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
-rw-r--r-- | arch/sh/include/asm/hwblk.h | 13 | ||||
-rw-r--r-- | arch/sh/kernel/cpu/hwblk.c | 69 | ||||
-rw-r--r-- | arch/sh/kernel/cpu/sh4a/hwblk-sh7722.c | 4 |
3 files changed, 60 insertions, 26 deletions
diff --git a/arch/sh/include/asm/hwblk.h b/arch/sh/include/asm/hwblk.h index 51a46f496639..c01d72cb6757 100644 --- a/arch/sh/include/asm/hwblk.h +++ b/arch/sh/include/asm/hwblk.h | |||
@@ -4,6 +4,9 @@ | |||
4 | #include <asm/clock.h> | 4 | #include <asm/clock.h> |
5 | #include <asm/io.h> | 5 | #include <asm/io.h> |
6 | 6 | ||
7 | #define HWBLK_CNT_USAGE 0 | ||
8 | #define HWBLK_CNT_NR 1 | ||
9 | |||
7 | #define HWBLK_AREA_FLAG_PARENT (1 << 0) /* valid parent */ | 10 | #define HWBLK_AREA_FLAG_PARENT (1 << 0) /* valid parent */ |
8 | 11 | ||
9 | #define HWBLK_AREA(_flags, _parent) \ | 12 | #define HWBLK_AREA(_flags, _parent) \ |
@@ -13,7 +16,7 @@ | |||
13 | } | 16 | } |
14 | 17 | ||
15 | struct hwblk_area { | 18 | struct hwblk_area { |
16 | unsigned long cnt; | 19 | int cnt[HWBLK_CNT_NR]; |
17 | unsigned char parent; | 20 | unsigned char parent; |
18 | unsigned char flags; | 21 | unsigned char flags; |
19 | }; | 22 | }; |
@@ -29,7 +32,7 @@ struct hwblk { | |||
29 | void __iomem *mstp; | 32 | void __iomem *mstp; |
30 | unsigned char bit; | 33 | unsigned char bit; |
31 | unsigned char area; | 34 | unsigned char area; |
32 | unsigned long cnt; | 35 | int cnt[HWBLK_CNT_NR]; |
33 | }; | 36 | }; |
34 | 37 | ||
35 | struct hwblk_info { | 38 | struct hwblk_info { |
@@ -46,6 +49,12 @@ int arch_hwblk_sleep_mode(void); | |||
46 | int hwblk_register(struct hwblk_info *info); | 49 | int hwblk_register(struct hwblk_info *info); |
47 | int hwblk_init(void); | 50 | int hwblk_init(void); |
48 | 51 | ||
52 | void hwblk_enable(struct hwblk_info *info, int hwblk); | ||
53 | void hwblk_disable(struct hwblk_info *info, int hwblk); | ||
54 | |||
55 | void hwblk_cnt_inc(struct hwblk_info *info, int hwblk, int cnt); | ||
56 | void hwblk_cnt_dec(struct hwblk_info *info, int hwblk, int cnt); | ||
57 | |||
49 | /* allow clocks to enable and disable hardware blocks */ | 58 | /* allow clocks to enable and disable hardware blocks */ |
50 | #define SH_HWBLK_CLK(_name, _id, _parent, _hwblk, _flags) \ | 59 | #define SH_HWBLK_CLK(_name, _id, _parent, _hwblk, _flags) \ |
51 | { \ | 60 | { \ |
diff --git a/arch/sh/kernel/cpu/hwblk.c b/arch/sh/kernel/cpu/hwblk.c index 7c3a73deff24..c0ad7d46e784 100644 --- a/arch/sh/kernel/cpu/hwblk.c +++ b/arch/sh/kernel/cpu/hwblk.c | |||
@@ -9,38 +9,64 @@ | |||
9 | 9 | ||
10 | static DEFINE_SPINLOCK(hwblk_lock); | 10 | static DEFINE_SPINLOCK(hwblk_lock); |
11 | 11 | ||
12 | static void hwblk_area_inc(struct hwblk_info *info, int area) | 12 | static void hwblk_area_mod_cnt(struct hwblk_info *info, |
13 | int area, int counter, int value, int goal) | ||
13 | { | 14 | { |
14 | struct hwblk_area *hap = info->areas + area; | 15 | struct hwblk_area *hap = info->areas + area; |
15 | 16 | ||
16 | hap->cnt++; | 17 | hap->cnt[counter] += value; |
17 | if (hap->cnt == 1) | 18 | |
18 | if (hap->flags & HWBLK_AREA_FLAG_PARENT) | 19 | if (hap->cnt[counter] != goal) |
19 | hwblk_area_inc(info, hap->parent); | 20 | return; |
21 | |||
22 | if (hap->flags & HWBLK_AREA_FLAG_PARENT) | ||
23 | hwblk_area_mod_cnt(info, hap->parent, counter, value, goal); | ||
20 | } | 24 | } |
21 | 25 | ||
22 | static void hwblk_area_dec(struct hwblk_info *info, int area) | 26 | |
27 | static int __hwblk_mod_cnt(struct hwblk_info *info, int hwblk, | ||
28 | int counter, int value, int goal) | ||
23 | { | 29 | { |
24 | struct hwblk_area *hap = info->areas + area; | 30 | struct hwblk *hp = info->hwblks + hwblk; |
31 | |||
32 | hp->cnt[counter] += value; | ||
33 | if (hp->cnt[counter] == goal) | ||
34 | hwblk_area_mod_cnt(info, hp->area, counter, value, goal); | ||
25 | 35 | ||
26 | if (hap->cnt == 1) | 36 | return hp->cnt[counter]; |
27 | if (hap->flags & HWBLK_AREA_FLAG_PARENT) | ||
28 | hwblk_area_dec(info, hap->parent); | ||
29 | hap->cnt--; | ||
30 | } | 37 | } |
31 | 38 | ||
32 | static void hwblk_enable(struct hwblk_info *info, int hwblk) | 39 | static void hwblk_mod_cnt(struct hwblk_info *info, int hwblk, |
40 | int counter, int value, int goal) | ||
41 | { | ||
42 | unsigned long flags; | ||
43 | |||
44 | spin_lock_irqsave(&hwblk_lock, flags); | ||
45 | __hwblk_mod_cnt(info, hwblk, counter, value, goal); | ||
46 | spin_unlock_irqrestore(&hwblk_lock, flags); | ||
47 | } | ||
48 | |||
49 | void hwblk_cnt_inc(struct hwblk_info *info, int hwblk, int counter) | ||
50 | { | ||
51 | hwblk_mod_cnt(info, hwblk, counter, 1, 1); | ||
52 | } | ||
53 | |||
54 | void hwblk_cnt_dec(struct hwblk_info *info, int hwblk, int counter) | ||
55 | { | ||
56 | hwblk_mod_cnt(info, hwblk, counter, -1, 0); | ||
57 | } | ||
58 | |||
59 | void hwblk_enable(struct hwblk_info *info, int hwblk) | ||
33 | { | 60 | { |
34 | struct hwblk *hp = info->hwblks + hwblk; | 61 | struct hwblk *hp = info->hwblks + hwblk; |
35 | unsigned long tmp; | 62 | unsigned long tmp; |
36 | unsigned long flags; | 63 | unsigned long flags; |
64 | int ret; | ||
37 | 65 | ||
38 | spin_lock_irqsave(&hwblk_lock, flags); | 66 | spin_lock_irqsave(&hwblk_lock, flags); |
39 | 67 | ||
40 | hp->cnt++; | 68 | ret = __hwblk_mod_cnt(info, hwblk, HWBLK_CNT_USAGE, 1, 1); |
41 | if (hp->cnt == 1) { | 69 | if (ret == 1) { |
42 | hwblk_area_inc(info, hp->area); | ||
43 | |||
44 | tmp = __raw_readl(hp->mstp); | 70 | tmp = __raw_readl(hp->mstp); |
45 | tmp &= ~(1 << hp->bit); | 71 | tmp &= ~(1 << hp->bit); |
46 | __raw_writel(tmp, hp->mstp); | 72 | __raw_writel(tmp, hp->mstp); |
@@ -49,27 +75,26 @@ static void hwblk_enable(struct hwblk_info *info, int hwblk) | |||
49 | spin_unlock_irqrestore(&hwblk_lock, flags); | 75 | spin_unlock_irqrestore(&hwblk_lock, flags); |
50 | } | 76 | } |
51 | 77 | ||
52 | static void hwblk_disable(struct hwblk_info *info, int hwblk) | 78 | void hwblk_disable(struct hwblk_info *info, int hwblk) |
53 | { | 79 | { |
54 | struct hwblk *hp = info->hwblks + hwblk; | 80 | struct hwblk *hp = info->hwblks + hwblk; |
55 | unsigned long tmp; | 81 | unsigned long tmp; |
56 | unsigned long flags; | 82 | unsigned long flags; |
83 | int ret; | ||
57 | 84 | ||
58 | spin_lock_irqsave(&hwblk_lock, flags); | 85 | spin_lock_irqsave(&hwblk_lock, flags); |
59 | 86 | ||
60 | if (hp->cnt == 1) { | 87 | ret = __hwblk_mod_cnt(info, hwblk, HWBLK_CNT_USAGE, -1, 0); |
61 | hwblk_area_dec(info, hp->area); | 88 | if (ret == 0) { |
62 | |||
63 | tmp = __raw_readl(hp->mstp); | 89 | tmp = __raw_readl(hp->mstp); |
64 | tmp |= 1 << hp->bit; | 90 | tmp |= 1 << hp->bit; |
65 | __raw_writel(tmp, hp->mstp); | 91 | __raw_writel(tmp, hp->mstp); |
66 | } | 92 | } |
67 | hp->cnt--; | ||
68 | 93 | ||
69 | spin_unlock_irqrestore(&hwblk_lock, flags); | 94 | spin_unlock_irqrestore(&hwblk_lock, flags); |
70 | } | 95 | } |
71 | 96 | ||
72 | static struct hwblk_info *hwblk_info; | 97 | struct hwblk_info *hwblk_info; |
73 | 98 | ||
74 | int __init hwblk_register(struct hwblk_info *info) | 99 | int __init hwblk_register(struct hwblk_info *info) |
75 | { | 100 | { |
diff --git a/arch/sh/kernel/cpu/sh4a/hwblk-sh7722.c b/arch/sh/kernel/cpu/sh4a/hwblk-sh7722.c index 00a1c02d82b1..a288b5d92341 100644 --- a/arch/sh/kernel/cpu/sh4a/hwblk-sh7722.c +++ b/arch/sh/kernel/cpu/sh4a/hwblk-sh7722.c | |||
@@ -91,10 +91,10 @@ static struct hwblk_info sh7722_hwblk_info = { | |||
91 | 91 | ||
92 | int arch_hwblk_sleep_mode(void) | 92 | int arch_hwblk_sleep_mode(void) |
93 | { | 93 | { |
94 | if (!sh7722_hwblk_area[CORE_AREA].cnt) | 94 | if (!sh7722_hwblk_area[CORE_AREA].cnt[HWBLK_CNT_USAGE]) |
95 | return SUSP_SH_STANDBY | SUSP_SH_SF; | 95 | return SUSP_SH_STANDBY | SUSP_SH_SF; |
96 | 96 | ||
97 | if (!sh7722_hwblk_area[CORE_AREA_BM].cnt) | 97 | if (!sh7722_hwblk_area[CORE_AREA_BM].cnt[HWBLK_CNT_USAGE]) |
98 | return SUSP_SH_SLEEP | SUSP_SH_SF; | 98 | return SUSP_SH_SLEEP | SUSP_SH_SF; |
99 | 99 | ||
100 | return SUSP_SH_SLEEP; | 100 | return SUSP_SH_SLEEP; |