aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sh/kernel/cpu/hwblk.c
diff options
context:
space:
mode:
authorMagnus Damm <damm@igel.co.jp>2009-07-17 10:24:55 -0400
committerPaul Mundt <lethal@linux-sh.org>2009-07-19 15:23:39 -0400
commit0f8ee1874fa80899debc0a0670e2bed0a28d2548 (patch)
treef9d58ced4b3b8e6ac50371fdb009e3446bce40c8 /arch/sh/kernel/cpu/hwblk.c
parenta61c1a636628a28ab5b42a9d36582a8f6a08893a (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>
Diffstat (limited to 'arch/sh/kernel/cpu/hwblk.c')
-rw-r--r--arch/sh/kernel/cpu/hwblk.c69
1 files changed, 47 insertions, 22 deletions
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
10static DEFINE_SPINLOCK(hwblk_lock); 10static DEFINE_SPINLOCK(hwblk_lock);
11 11
12static void hwblk_area_inc(struct hwblk_info *info, int area) 12static 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
22static void hwblk_area_dec(struct hwblk_info *info, int area) 26
27static 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
32static void hwblk_enable(struct hwblk_info *info, int hwblk) 39static 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
49void hwblk_cnt_inc(struct hwblk_info *info, int hwblk, int counter)
50{
51 hwblk_mod_cnt(info, hwblk, counter, 1, 1);
52}
53
54void hwblk_cnt_dec(struct hwblk_info *info, int hwblk, int counter)
55{
56 hwblk_mod_cnt(info, hwblk, counter, -1, 0);
57}
58
59void 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
52static void hwblk_disable(struct hwblk_info *info, int hwblk) 78void 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
72static struct hwblk_info *hwblk_info; 97struct hwblk_info *hwblk_info;
73 98
74int __init hwblk_register(struct hwblk_info *info) 99int __init hwblk_register(struct hwblk_info *info)
75{ 100{