forked from luck/tmp_suning_uos_patched
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>
This commit is contained in:
parent
a61c1a6366
commit
0f8ee1874f
@ -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) \
|
||||||
{ \
|
{ \
|
||||||
|
@ -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++;
|
hap->cnt[counter] += value;
|
||||||
if (hap->cnt == 1)
|
|
||||||
if (hap->flags & HWBLK_AREA_FLAG_PARENT)
|
if (hap->cnt[counter] != goal)
|
||||||
hwblk_area_inc(info, hap->parent);
|
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;
|
||||||
|
|
||||||
if (hap->cnt == 1)
|
hp->cnt[counter] += value;
|
||||||
if (hap->flags & HWBLK_AREA_FLAG_PARENT)
|
if (hp->cnt[counter] == goal)
|
||||||
hwblk_area_dec(info, hap->parent);
|
hwblk_area_mod_cnt(info, hp->area, counter, value, goal);
|
||||||
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++;
|
ret = __hwblk_mod_cnt(info, hwblk, HWBLK_CNT_USAGE, 1, 1);
|
||||||
if (hp->cnt == 1) {
|
if (ret == 1) {
|
||||||
hwblk_area_inc(info, hp->area);
|
|
||||||
|
|
||||||
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) {
|
ret = __hwblk_mod_cnt(info, hwblk, HWBLK_CNT_USAGE, -1, 0);
|
||||||
hwblk_area_dec(info, hp->area);
|
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)
|
||||||
{
|
{
|
||||||
|
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user