瀏覽代碼

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>
Magnus Damm 16 年之前
父節點
當前提交
0f8ee1874f
共有 3 個文件被更改,包括 60 次插入26 次删除
  1. 11 2
      arch/sh/include/asm/hwblk.h
  2. 47 22
      arch/sh/kernel/cpu/hwblk.c
  3. 2 2
      arch/sh/kernel/cpu/sh4a/hwblk-sh7722.c

+ 11 - 2
arch/sh/include/asm/hwblk.h

@@ -4,6 +4,9 @@
 #include <asm/clock.h>
 #include <asm/clock.h>
 #include <asm/io.h>
 #include <asm/io.h>
 
 
+#define HWBLK_CNT_USAGE 0
+#define HWBLK_CNT_NR 1
+
 #define HWBLK_AREA_FLAG_PARENT (1 << 0) /* valid parent */
 #define HWBLK_AREA_FLAG_PARENT (1 << 0) /* valid parent */
 
 
 #define HWBLK_AREA(_flags, _parent)		\
 #define HWBLK_AREA(_flags, _parent)		\
@@ -13,7 +16,7 @@
 }
 }
 
 
 struct hwblk_area {
 struct hwblk_area {
-	unsigned long cnt;
+	int cnt[HWBLK_CNT_NR];
 	unsigned char parent;
 	unsigned char parent;
 	unsigned char flags;
 	unsigned char flags;
 };
 };
@@ -29,7 +32,7 @@ struct hwblk {
 	void __iomem *mstp;
 	void __iomem *mstp;
 	unsigned char bit;
 	unsigned char bit;
 	unsigned char area;
 	unsigned char area;
-	unsigned long cnt;
+	int cnt[HWBLK_CNT_NR];
 };
 };
 
 
 struct hwblk_info {
 struct hwblk_info {
@@ -46,6 +49,12 @@ int arch_hwblk_sleep_mode(void);
 int hwblk_register(struct hwblk_info *info);
 int hwblk_register(struct hwblk_info *info);
 int hwblk_init(void);
 int hwblk_init(void);
 
 
+void hwblk_enable(struct hwblk_info *info, int hwblk);
+void hwblk_disable(struct hwblk_info *info, int hwblk);
+
+void hwblk_cnt_inc(struct hwblk_info *info, int hwblk, int cnt);
+void hwblk_cnt_dec(struct hwblk_info *info, int hwblk, int cnt);
+
 /* allow clocks to enable and disable hardware blocks */
 /* allow clocks to enable and disable hardware blocks */
 #define SH_HWBLK_CLK(_name, _id, _parent, _hwblk, _flags)	\
 #define SH_HWBLK_CLK(_name, _id, _parent, _hwblk, _flags)	\
 {							\
 {							\

+ 47 - 22
arch/sh/kernel/cpu/hwblk.c

@@ -9,38 +9,64 @@
 
 
 static DEFINE_SPINLOCK(hwblk_lock);
 static DEFINE_SPINLOCK(hwblk_lock);
 
 
-static void hwblk_area_inc(struct hwblk_info *info, int area)
+static void hwblk_area_mod_cnt(struct hwblk_info *info,
+			       int area, int counter, int value, int goal)
 {
 {
 	struct hwblk_area *hap = info->areas + area;
 	struct hwblk_area *hap = info->areas + area;
 
 
-	hap->cnt++;
-	if (hap->cnt == 1)
-		if (hap->flags & HWBLK_AREA_FLAG_PARENT)
-			hwblk_area_inc(info, hap->parent);
+	hap->cnt[counter] += value;
+
+	if (hap->cnt[counter] != goal)
+		return;
+
+	if (hap->flags & HWBLK_AREA_FLAG_PARENT)
+		hwblk_area_mod_cnt(info, hap->parent, counter, value, goal);
 }
 }
 
 
-static void hwblk_area_dec(struct hwblk_info *info, int area)
+
+static int __hwblk_mod_cnt(struct hwblk_info *info, int hwblk,
+			  int counter, int value, int goal)
 {
 {
-	struct hwblk_area *hap = info->areas + area;
+	struct hwblk *hp = info->hwblks + hwblk;
+
+	hp->cnt[counter] += value;
+	if (hp->cnt[counter] == goal)
+		hwblk_area_mod_cnt(info, hp->area, counter, value, goal);
 
 
-	if (hap->cnt == 1)
-		if (hap->flags & HWBLK_AREA_FLAG_PARENT)
-			hwblk_area_dec(info, hap->parent);
-	hap->cnt--;
+	return hp->cnt[counter];
 }
 }
 
 
-static void hwblk_enable(struct hwblk_info *info, int hwblk)
+static void hwblk_mod_cnt(struct hwblk_info *info, int hwblk,
+			  int counter, int value, int goal)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&hwblk_lock, flags);
+	__hwblk_mod_cnt(info, hwblk, counter, value, goal);
+	spin_unlock_irqrestore(&hwblk_lock, flags);
+}
+
+void hwblk_cnt_inc(struct hwblk_info *info, int hwblk, int counter)
+{
+	hwblk_mod_cnt(info, hwblk, counter, 1, 1);
+}
+
+void hwblk_cnt_dec(struct hwblk_info *info, int hwblk, int counter)
+{
+	hwblk_mod_cnt(info, hwblk, counter, -1, 0);
+}
+
+void hwblk_enable(struct hwblk_info *info, int hwblk)
 {
 {
 	struct hwblk *hp = info->hwblks + hwblk;
 	struct hwblk *hp = info->hwblks + hwblk;
 	unsigned long tmp;
 	unsigned long tmp;
 	unsigned long flags;
 	unsigned long flags;
+	int ret;
 
 
 	spin_lock_irqsave(&hwblk_lock, flags);
 	spin_lock_irqsave(&hwblk_lock, flags);
 
 
-	hp->cnt++;
-	if (hp->cnt == 1) {
-		hwblk_area_inc(info, hp->area);
-
+	ret = __hwblk_mod_cnt(info, hwblk, HWBLK_CNT_USAGE, 1, 1);
+	if (ret == 1) {
 		tmp = __raw_readl(hp->mstp);
 		tmp = __raw_readl(hp->mstp);
 		tmp &= ~(1 << hp->bit);
 		tmp &= ~(1 << hp->bit);
 		__raw_writel(tmp, hp->mstp);
 		__raw_writel(tmp, hp->mstp);
@@ -49,27 +75,26 @@ static void hwblk_enable(struct hwblk_info *info, int hwblk)
 	spin_unlock_irqrestore(&hwblk_lock, flags);
 	spin_unlock_irqrestore(&hwblk_lock, flags);
 }
 }
 
 
-static void hwblk_disable(struct hwblk_info *info, int hwblk)
+void hwblk_disable(struct hwblk_info *info, int hwblk)
 {
 {
 	struct hwblk *hp = info->hwblks + hwblk;
 	struct hwblk *hp = info->hwblks + hwblk;
 	unsigned long tmp;
 	unsigned long tmp;
 	unsigned long flags;
 	unsigned long flags;
+	int ret;
 
 
 	spin_lock_irqsave(&hwblk_lock, flags);
 	spin_lock_irqsave(&hwblk_lock, flags);
 
 
-	if (hp->cnt == 1) {
-		hwblk_area_dec(info, hp->area);
-
+	ret = __hwblk_mod_cnt(info, hwblk, HWBLK_CNT_USAGE, -1, 0);
+	if (ret == 0) {
 		tmp = __raw_readl(hp->mstp);
 		tmp = __raw_readl(hp->mstp);
 		tmp |= 1 << hp->bit;
 		tmp |= 1 << hp->bit;
 		__raw_writel(tmp, hp->mstp);
 		__raw_writel(tmp, hp->mstp);
 	}
 	}
-	hp->cnt--;
 
 
 	spin_unlock_irqrestore(&hwblk_lock, flags);
 	spin_unlock_irqrestore(&hwblk_lock, flags);
 }
 }
 
 
-static struct hwblk_info *hwblk_info;
+struct hwblk_info *hwblk_info;
 
 
 int __init hwblk_register(struct hwblk_info *info)
 int __init hwblk_register(struct hwblk_info *info)
 {
 {

+ 2 - 2
arch/sh/kernel/cpu/sh4a/hwblk-sh7722.c

@@ -91,10 +91,10 @@ static struct hwblk_info sh7722_hwblk_info = {
 
 
 int arch_hwblk_sleep_mode(void)
 int arch_hwblk_sleep_mode(void)
 {
 {
-	if (!sh7722_hwblk_area[CORE_AREA].cnt)
+	if (!sh7722_hwblk_area[CORE_AREA].cnt[HWBLK_CNT_USAGE])
 		return SUSP_SH_STANDBY | SUSP_SH_SF;
 		return SUSP_SH_STANDBY | SUSP_SH_SF;
 
 
-	if (!sh7722_hwblk_area[CORE_AREA_BM].cnt)
+	if (!sh7722_hwblk_area[CORE_AREA_BM].cnt[HWBLK_CNT_USAGE])
 		return SUSP_SH_SLEEP | SUSP_SH_SF;
 		return SUSP_SH_SLEEP | SUSP_SH_SF;
 
 
 	return SUSP_SH_SLEEP;
 	return SUSP_SH_SLEEP;