Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 184636
b: refs/heads/master
c: 369d561
h: refs/heads/master
v: v3
  • Loading branch information
Paul Walmsley committed Jan 27, 2010
1 parent ca02de4 commit 35b3368
Show file tree
Hide file tree
Showing 5 changed files with 238 additions and 40 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: e909d62a8afda7a224a7e322cf2f387d69ca771f
refs/heads/master: 369d5614457384edcf62c5f39b03dd20be6ea1df
216 changes: 196 additions & 20 deletions trunk/arch/arm/mach-omap2/clockdomain.c
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,6 @@ static struct clkdm_dep *_clkdm_deps_lookup(struct clockdomain *clkdm,
return ERR_PTR(-EINVAL);

for (cd = deps; cd->clkdm_name; cd++) {

if (!omap_chip_is(cd->omap_chip))
continue;

Expand All @@ -122,7 +121,6 @@ static struct clkdm_dep *_clkdm_deps_lookup(struct clockdomain *clkdm,

if (cd->clkdm == clkdm)
break;

}

if (!cd->clkdm_name)
Expand Down Expand Up @@ -254,6 +252,96 @@ static void _omap2_clkdm_set_hwsup(struct clockdomain *clkdm, int enable)

}

/**
* _init_wkdep_usecount - initialize wkdep usecounts to match hardware
* @clkdm: clockdomain to initialize wkdep usecounts
*
* Initialize the wakeup dependency usecount variables for clockdomain @clkdm.
* If a wakeup dependency is present in the hardware, the usecount will be
* set to 1; otherwise, it will be set to 0. Software should clear all
* software wakeup dependencies prior to calling this function if it wishes
* to ensure that all usecounts start at 0. No return value.
*/
static void _init_wkdep_usecount(struct clockdomain *clkdm)
{
u32 v;
struct clkdm_dep *cd;

if (!clkdm->wkdep_srcs)
return;

for (cd = clkdm->wkdep_srcs; cd->clkdm_name; cd++) {
if (!omap_chip_is(cd->omap_chip))
continue;

if (!cd->clkdm && cd->clkdm_name)
cd->clkdm = _clkdm_lookup(cd->clkdm_name);

if (!cd->clkdm) {
WARN(!cd->clkdm, "clockdomain: %s: wkdep clkdm %s not "
"found\n", clkdm->name, cd->clkdm_name);
continue;
}

v = prm_read_mod_bits_shift(clkdm->pwrdm.ptr->prcm_offs,
PM_WKDEP,
(1 << cd->clkdm->dep_bit));

if (v)
pr_debug("clockdomain: %s: wakeup dependency already "
"set to wake up when %s wakes\n",
clkdm->name, cd->clkdm->name);

atomic_set(&cd->wkdep_usecount, (v) ? 1 : 0);
}
}

/**
* _init_sleepdep_usecount - initialize sleepdep usecounts to match hardware
* @clkdm: clockdomain to initialize sleepdep usecounts
*
* Initialize the sleep dependency usecount variables for clockdomain @clkdm.
* If a sleep dependency is present in the hardware, the usecount will be
* set to 1; otherwise, it will be set to 0. Software should clear all
* software sleep dependencies prior to calling this function if it wishes
* to ensure that all usecounts start at 0. No return value.
*/
static void _init_sleepdep_usecount(struct clockdomain *clkdm)
{
u32 v;
struct clkdm_dep *cd;

if (!cpu_is_omap34xx())
return;

if (!clkdm->sleepdep_srcs)
return;

for (cd = clkdm->sleepdep_srcs; cd->clkdm_name; cd++) {
if (!omap_chip_is(cd->omap_chip))
continue;

if (!cd->clkdm && cd->clkdm_name)
cd->clkdm = _clkdm_lookup(cd->clkdm_name);

if (!cd->clkdm) {
WARN(!cd->clkdm, "clockdomain: %s: sleepdep clkdm %s "
"not found\n", clkdm->name, cd->clkdm_name);
continue;
}

v = prm_read_mod_bits_shift(clkdm->pwrdm.ptr->prcm_offs,
OMAP3430_CM_SLEEPDEP,
(1 << cd->clkdm->dep_bit));

if (v)
pr_debug("clockdomain: %s: sleep dependency already "
"set to prevent from idling until %s "
"idles\n", clkdm->name, cd->clkdm->name);

atomic_set(&cd->sleepdep_usecount, (v) ? 1 : 0);
}
};

/* Public functions */

Expand All @@ -272,6 +360,7 @@ void clkdm_init(struct clockdomain **clkdms,
struct clkdm_autodep *init_autodeps)
{
struct clockdomain **c = NULL;
struct clockdomain *clkdm;
struct clkdm_autodep *autodep = NULL;

if (clkdms)
Expand All @@ -282,6 +371,15 @@ void clkdm_init(struct clockdomain **clkdms,
if (autodeps)
for (autodep = autodeps; autodep->clkdm.ptr; autodep++)
_autodep_lookup(autodep);

/*
* Ensure that the *dep_usecount registers reflect the current
* state of the PRCM.
*/
list_for_each_entry(clkdm, &clkdm_list, node) {
_init_wkdep_usecount(clkdm);
_init_sleepdep_usecount(clkdm);
}
}

/**
Expand Down Expand Up @@ -387,11 +485,13 @@ int clkdm_add_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
return PTR_ERR(cd);
}

pr_debug("clockdomain: hardware will wake up %s when %s wakes up\n",
clkdm1->name, clkdm2->name);
if (atomic_inc_return(&cd->wkdep_usecount) == 1) {
pr_debug("clockdomain: hardware will wake up %s when %s wakes "
"up\n", clkdm1->name, clkdm2->name);

prm_set_mod_reg_bits((1 << clkdm2->dep_bit),
clkdm1->pwrdm.ptr->prcm_offs, PM_WKDEP);
prm_set_mod_reg_bits((1 << clkdm2->dep_bit),
clkdm1->pwrdm.ptr->prcm_offs, PM_WKDEP);
}

return 0;
}
Expand Down Expand Up @@ -420,11 +520,13 @@ int clkdm_del_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
return PTR_ERR(cd);
}

pr_debug("clockdomain: hardware will no longer wake up %s after %s "
"wakes up\n", clkdm1->name, clkdm2->name);
if (atomic_dec_return(&cd->wkdep_usecount) == 0) {
pr_debug("clockdomain: hardware will no longer wake up %s "
"after %s wakes up\n", clkdm1->name, clkdm2->name);

prm_clear_mod_reg_bits((1 << clkdm2->dep_bit),
clkdm1->pwrdm.ptr->prcm_offs, PM_WKDEP);
prm_clear_mod_reg_bits((1 << clkdm2->dep_bit),
clkdm1->pwrdm.ptr->prcm_offs, PM_WKDEP);
}

return 0;
}
Expand Down Expand Up @@ -457,10 +559,43 @@ int clkdm_read_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
return PTR_ERR(cd);
}

/* XXX It's faster to return the atomic wkdep_usecount */
return prm_read_mod_bits_shift(clkdm1->pwrdm.ptr->prcm_offs, PM_WKDEP,
(1 << clkdm2->dep_bit));
}

/**
* clkdm_clear_all_wkdeps - remove all wakeup dependencies from target clkdm
* @clkdm: struct clockdomain * to remove all wakeup dependencies from
*
* Remove all inter-clockdomain wakeup dependencies that could cause
* @clkdm to wake. Intended to be used during boot to initialize the
* PRCM to a known state, after all clockdomains are put into swsup idle
* and woken up. Returns -EINVAL if @clkdm pointer is invalid, or
* 0 upon success.
*/
int clkdm_clear_all_wkdeps(struct clockdomain *clkdm)
{
struct clkdm_dep *cd;
u32 mask = 0;

if (!clkdm)
return -EINVAL;

for (cd = clkdm->wkdep_srcs; cd && cd->clkdm_name; cd++) {
if (!omap_chip_is(cd->omap_chip))
continue;

/* PRM accesses are slow, so minimize them */
mask |= 1 << cd->clkdm->dep_bit;
atomic_set(&cd->wkdep_usecount, 0);
}

prm_clear_mod_reg_bits(mask, clkdm->pwrdm.ptr->prcm_offs, PM_WKDEP);

return 0;
}

/**
* clkdm_add_sleepdep - add a sleep dependency from clkdm2 to clkdm1
* @clkdm1: prevent this struct clockdomain * from sleeping (dependent)
Expand Down Expand Up @@ -491,12 +626,14 @@ int clkdm_add_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
return PTR_ERR(cd);
}

pr_debug("clockdomain: will prevent %s from sleeping if %s is active\n",
clkdm1->name, clkdm2->name);
if (atomic_inc_return(&cd->sleepdep_usecount) == 1) {
pr_debug("clockdomain: will prevent %s from sleeping if %s "
"is active\n", clkdm1->name, clkdm2->name);

cm_set_mod_reg_bits((1 << clkdm2->dep_bit),
clkdm1->pwrdm.ptr->prcm_offs,
OMAP3430_CM_SLEEPDEP);
cm_set_mod_reg_bits((1 << clkdm2->dep_bit),
clkdm1->pwrdm.ptr->prcm_offs,
OMAP3430_CM_SLEEPDEP);
}

return 0;
}
Expand Down Expand Up @@ -531,12 +668,15 @@ int clkdm_del_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
return PTR_ERR(cd);
}

pr_debug("clockdomain: will no longer prevent %s from sleeping if "
"%s is active\n", clkdm1->name, clkdm2->name);
if (atomic_dec_return(&cd->sleepdep_usecount) == 0) {
pr_debug("clockdomain: will no longer prevent %s from "
"sleeping if %s is active\n", clkdm1->name,
clkdm2->name);

cm_clear_mod_reg_bits((1 << clkdm2->dep_bit),
clkdm1->pwrdm.ptr->prcm_offs,
OMAP3430_CM_SLEEPDEP);
cm_clear_mod_reg_bits((1 << clkdm2->dep_bit),
clkdm1->pwrdm.ptr->prcm_offs,
OMAP3430_CM_SLEEPDEP);
}

return 0;
}
Expand Down Expand Up @@ -575,11 +715,47 @@ int clkdm_read_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
return PTR_ERR(cd);
}

/* XXX It's faster to return the atomic sleepdep_usecount */
return prm_read_mod_bits_shift(clkdm1->pwrdm.ptr->prcm_offs,
OMAP3430_CM_SLEEPDEP,
(1 << clkdm2->dep_bit));
}

/**
* clkdm_clear_all_sleepdeps - remove all sleep dependencies from target clkdm
* @clkdm: struct clockdomain * to remove all sleep dependencies from
*
* Remove all inter-clockdomain sleep dependencies that could prevent
* @clkdm from idling. Intended to be used during boot to initialize the
* PRCM to a known state, after all clockdomains are put into swsup idle
* and woken up. Returns -EINVAL if @clkdm pointer is invalid, or
* 0 upon success.
*/
int clkdm_clear_all_sleepdeps(struct clockdomain *clkdm)
{
struct clkdm_dep *cd;
u32 mask = 0;

if (!cpu_is_omap34xx())
return -EINVAL;

if (!clkdm)
return -EINVAL;

for (cd = clkdm->sleepdep_srcs; cd && cd->clkdm_name; cd++) {
if (!omap_chip_is(cd->omap_chip))
continue;

/* PRM accesses are slow, so minimize them */
mask |= 1 << cd->clkdm->dep_bit;
atomic_set(&cd->sleepdep_usecount, 0);
}

prm_clear_mod_reg_bits(mask, clkdm->pwrdm.ptr->prcm_offs,
OMAP3430_CM_SLEEPDEP);

return 0;
}

/**
* omap2_clkdm_clktrctrl_read - read the clkdm's current state transition mode
Expand Down
Loading

0 comments on commit 35b3368

Please sign in to comment.