|
@@ -287,6 +287,32 @@ static void _disable_hwsup(struct clockdomain *clkdm)
|
|
|
BUG();
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * _resolve_clkdm_deps() - resolve clkdm_names in @clkdm_deps to clkdms
|
|
|
+ * @clkdm: clockdomain that we are resolving dependencies for
|
|
|
+ * @clkdm_deps: ptr to array of struct clkdm_deps to resolve
|
|
|
+ *
|
|
|
+ * Iterates through @clkdm_deps, looking up the struct clockdomain named by
|
|
|
+ * clkdm_name and storing the clockdomain pointer in the struct clkdm_dep.
|
|
|
+ * No return value.
|
|
|
+ */
|
|
|
+static void _resolve_clkdm_deps(struct clockdomain *clkdm,
|
|
|
+ struct clkdm_dep *clkdm_deps)
|
|
|
+{
|
|
|
+ struct clkdm_dep *cd;
|
|
|
+
|
|
|
+ for (cd = clkdm_deps; cd && cd->clkdm_name; cd++) {
|
|
|
+ if (!omap_chip_is(cd->omap_chip))
|
|
|
+ continue;
|
|
|
+ if (cd->clkdm)
|
|
|
+ continue;
|
|
|
+ cd->clkdm = _clkdm_lookup(cd->clkdm_name);
|
|
|
+
|
|
|
+ WARN(!cd->clkdm, "clockdomain: %s: could not find clkdm %s while resolving dependencies - should never happen",
|
|
|
+ clkdm->name, cd->clkdm_name);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
/* Public functions */
|
|
|
|
|
|
/**
|
|
@@ -333,7 +359,10 @@ void clkdm_init(struct clockdomain **clkdms,
|
|
|
else if (clkdm->flags & CLKDM_CAN_DISABLE_AUTO)
|
|
|
omap2_clkdm_deny_idle(clkdm);
|
|
|
|
|
|
+ _resolve_clkdm_deps(clkdm, clkdm->wkdep_srcs);
|
|
|
clkdm_clear_all_wkdeps(clkdm);
|
|
|
+
|
|
|
+ _resolve_clkdm_deps(clkdm, clkdm->sleepdep_srcs);
|
|
|
clkdm_clear_all_sleepdeps(clkdm);
|
|
|
}
|
|
|
}
|
|
@@ -430,6 +459,7 @@ struct powerdomain *clkdm_get_pwrdm(struct clockdomain *clkdm)
|
|
|
int clkdm_add_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
|
|
|
{
|
|
|
struct clkdm_dep *cd;
|
|
|
+ int ret = 0;
|
|
|
|
|
|
if (!cpu_is_omap24xx() && !cpu_is_omap34xx()) {
|
|
|
pr_err("clockdomain: %s/%s: %s: not yet implemented\n",
|
|
@@ -441,21 +471,26 @@ int clkdm_add_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
|
|
|
return -EINVAL;
|
|
|
|
|
|
cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs);
|
|
|
- if (IS_ERR(cd)) {
|
|
|
+ if (IS_ERR(cd))
|
|
|
+ ret = PTR_ERR(cd);
|
|
|
+
|
|
|
+ if (!arch_clkdm || !arch_clkdm->clkdm_add_wkdep)
|
|
|
+ ret = -EINVAL;
|
|
|
+
|
|
|
+ if (ret) {
|
|
|
pr_debug("clockdomain: hardware cannot set/clear wake up of "
|
|
|
"%s when %s wakes up\n", clkdm1->name, clkdm2->name);
|
|
|
- return PTR_ERR(cd);
|
|
|
+ return ret;
|
|
|
}
|
|
|
|
|
|
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);
|
|
|
|
|
|
- omap2_prm_set_mod_reg_bits((1 << clkdm2->dep_bit),
|
|
|
- clkdm1->pwrdm.ptr->prcm_offs, PM_WKDEP);
|
|
|
+ ret = arch_clkdm->clkdm_add_wkdep(clkdm1, clkdm2);
|
|
|
}
|
|
|
|
|
|
- return 0;
|
|
|
+ return ret;
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -471,6 +506,7 @@ int clkdm_add_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
|
|
|
int clkdm_del_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
|
|
|
{
|
|
|
struct clkdm_dep *cd;
|
|
|
+ int ret = 0;
|
|
|
|
|
|
if (!cpu_is_omap24xx() && !cpu_is_omap34xx()) {
|
|
|
pr_err("clockdomain: %s/%s: %s: not yet implemented\n",
|
|
@@ -482,21 +518,26 @@ int clkdm_del_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
|
|
|
return -EINVAL;
|
|
|
|
|
|
cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs);
|
|
|
- if (IS_ERR(cd)) {
|
|
|
+ if (IS_ERR(cd))
|
|
|
+ ret = PTR_ERR(cd);
|
|
|
+
|
|
|
+ if (!arch_clkdm || !arch_clkdm->clkdm_del_wkdep)
|
|
|
+ ret = -EINVAL;
|
|
|
+
|
|
|
+ if (ret) {
|
|
|
pr_debug("clockdomain: hardware cannot set/clear wake up of "
|
|
|
"%s when %s wakes up\n", clkdm1->name, clkdm2->name);
|
|
|
- return PTR_ERR(cd);
|
|
|
+ return ret;
|
|
|
}
|
|
|
|
|
|
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);
|
|
|
|
|
|
- omap2_prm_clear_mod_reg_bits((1 << clkdm2->dep_bit),
|
|
|
- clkdm1->pwrdm.ptr->prcm_offs, PM_WKDEP);
|
|
|
+ ret = arch_clkdm->clkdm_del_wkdep(clkdm1, clkdm2);
|
|
|
}
|
|
|
|
|
|
- return 0;
|
|
|
+ return ret;
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -516,6 +557,7 @@ int clkdm_del_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
|
|
|
int clkdm_read_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
|
|
|
{
|
|
|
struct clkdm_dep *cd;
|
|
|
+ int ret = 0;
|
|
|
|
|
|
if (!clkdm1 || !clkdm2)
|
|
|
return -EINVAL;
|
|
@@ -527,15 +569,20 @@ int clkdm_read_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
|
|
|
}
|
|
|
|
|
|
cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs);
|
|
|
- if (IS_ERR(cd)) {
|
|
|
+ if (IS_ERR(cd))
|
|
|
+ ret = PTR_ERR(cd);
|
|
|
+
|
|
|
+ if (!arch_clkdm || !arch_clkdm->clkdm_read_wkdep)
|
|
|
+ ret = -EINVAL;
|
|
|
+
|
|
|
+ if (ret) {
|
|
|
pr_debug("clockdomain: hardware cannot set/clear wake up of "
|
|
|
"%s when %s wakes up\n", clkdm1->name, clkdm2->name);
|
|
|
- return PTR_ERR(cd);
|
|
|
+ return ret;
|
|
|
}
|
|
|
|
|
|
/* XXX It's faster to return the atomic wkdep_usecount */
|
|
|
- return omap2_prm_read_mod_bits_shift(clkdm1->pwrdm.ptr->prcm_offs, PM_WKDEP,
|
|
|
- (1 << clkdm2->dep_bit));
|
|
|
+ return arch_clkdm->clkdm_read_wkdep(clkdm1, clkdm2);
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -550,9 +597,6 @@ int clkdm_read_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
|
|
|
*/
|
|
|
int clkdm_clear_all_wkdeps(struct clockdomain *clkdm)
|
|
|
{
|
|
|
- struct clkdm_dep *cd;
|
|
|
- u32 mask = 0;
|
|
|
-
|
|
|
if (!cpu_is_omap24xx() && !cpu_is_omap34xx()) {
|
|
|
pr_err("clockdomain: %s: %s: not yet implemented\n",
|
|
|
clkdm->name, __func__);
|
|
@@ -562,21 +606,10 @@ int clkdm_clear_all_wkdeps(struct clockdomain *clkdm)
|
|
|
if (!clkdm)
|
|
|
return -EINVAL;
|
|
|
|
|
|
- for (cd = clkdm->wkdep_srcs; cd && 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);
|
|
|
-
|
|
|
- /* PRM accesses are slow, so minimize them */
|
|
|
- mask |= 1 << cd->clkdm->dep_bit;
|
|
|
- atomic_set(&cd->wkdep_usecount, 0);
|
|
|
- }
|
|
|
-
|
|
|
- omap2_prm_clear_mod_reg_bits(mask, clkdm->pwrdm.ptr->prcm_offs, PM_WKDEP);
|
|
|
+ if (!arch_clkdm || !arch_clkdm->clkdm_clear_all_wkdeps)
|
|
|
+ return -EINVAL;
|
|
|
|
|
|
- return 0;
|
|
|
+ return arch_clkdm->clkdm_clear_all_wkdeps(clkdm);
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -594,31 +627,33 @@ int clkdm_clear_all_wkdeps(struct clockdomain *clkdm)
|
|
|
int clkdm_add_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
|
|
|
{
|
|
|
struct clkdm_dep *cd;
|
|
|
-
|
|
|
- if (!cpu_is_omap34xx())
|
|
|
- return -EINVAL;
|
|
|
+ int ret = 0;
|
|
|
|
|
|
if (!clkdm1 || !clkdm2)
|
|
|
return -EINVAL;
|
|
|
|
|
|
cd = _clkdm_deps_lookup(clkdm2, clkdm1->sleepdep_srcs);
|
|
|
- if (IS_ERR(cd)) {
|
|
|
+ if (IS_ERR(cd))
|
|
|
+ ret = PTR_ERR(cd);
|
|
|
+
|
|
|
+ if (!arch_clkdm || !arch_clkdm->clkdm_add_sleepdep)
|
|
|
+ ret = -EINVAL;
|
|
|
+
|
|
|
+ if (ret) {
|
|
|
pr_debug("clockdomain: hardware cannot set/clear sleep "
|
|
|
"dependency affecting %s from %s\n", clkdm1->name,
|
|
|
clkdm2->name);
|
|
|
- return PTR_ERR(cd);
|
|
|
+ return ret;
|
|
|
}
|
|
|
|
|
|
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);
|
|
|
|
|
|
- omap2_cm_set_mod_reg_bits((1 << clkdm2->dep_bit),
|
|
|
- clkdm1->pwrdm.ptr->prcm_offs,
|
|
|
- OMAP3430_CM_SLEEPDEP);
|
|
|
+ ret = arch_clkdm->clkdm_add_sleepdep(clkdm1, clkdm2);
|
|
|
}
|
|
|
|
|
|
- return 0;
|
|
|
+ return ret;
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -636,19 +671,23 @@ int clkdm_add_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
|
|
|
int clkdm_del_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
|
|
|
{
|
|
|
struct clkdm_dep *cd;
|
|
|
-
|
|
|
- if (!cpu_is_omap34xx())
|
|
|
- return -EINVAL;
|
|
|
+ int ret = 0;
|
|
|
|
|
|
if (!clkdm1 || !clkdm2)
|
|
|
return -EINVAL;
|
|
|
|
|
|
cd = _clkdm_deps_lookup(clkdm2, clkdm1->sleepdep_srcs);
|
|
|
- if (IS_ERR(cd)) {
|
|
|
+ if (IS_ERR(cd))
|
|
|
+ ret = PTR_ERR(cd);
|
|
|
+
|
|
|
+ if (!arch_clkdm || !arch_clkdm->clkdm_del_sleepdep)
|
|
|
+ ret = -EINVAL;
|
|
|
+
|
|
|
+ if (ret) {
|
|
|
pr_debug("clockdomain: hardware cannot set/clear sleep "
|
|
|
"dependency affecting %s from %s\n", clkdm1->name,
|
|
|
clkdm2->name);
|
|
|
- return PTR_ERR(cd);
|
|
|
+ return ret;
|
|
|
}
|
|
|
|
|
|
if (atomic_dec_return(&cd->sleepdep_usecount) == 0) {
|
|
@@ -656,12 +695,10 @@ int clkdm_del_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
|
|
|
"sleeping if %s is active\n", clkdm1->name,
|
|
|
clkdm2->name);
|
|
|
|
|
|
- omap2_cm_clear_mod_reg_bits((1 << clkdm2->dep_bit),
|
|
|
- clkdm1->pwrdm.ptr->prcm_offs,
|
|
|
- OMAP3430_CM_SLEEPDEP);
|
|
|
+ ret = arch_clkdm->clkdm_del_sleepdep(clkdm1, clkdm2);
|
|
|
}
|
|
|
|
|
|
- return 0;
|
|
|
+ return ret;
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -683,25 +720,27 @@ int clkdm_del_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
|
|
|
int clkdm_read_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
|
|
|
{
|
|
|
struct clkdm_dep *cd;
|
|
|
-
|
|
|
- if (!cpu_is_omap34xx())
|
|
|
- return -EINVAL;
|
|
|
+ int ret = 0;
|
|
|
|
|
|
if (!clkdm1 || !clkdm2)
|
|
|
return -EINVAL;
|
|
|
|
|
|
cd = _clkdm_deps_lookup(clkdm2, clkdm1->sleepdep_srcs);
|
|
|
- if (IS_ERR(cd)) {
|
|
|
+ if (IS_ERR(cd))
|
|
|
+ ret = PTR_ERR(cd);
|
|
|
+
|
|
|
+ if (!arch_clkdm || !arch_clkdm->clkdm_read_sleepdep)
|
|
|
+ ret = -EINVAL;
|
|
|
+
|
|
|
+ if (ret) {
|
|
|
pr_debug("clockdomain: hardware cannot set/clear sleep "
|
|
|
"dependency affecting %s from %s\n", clkdm1->name,
|
|
|
clkdm2->name);
|
|
|
- return PTR_ERR(cd);
|
|
|
+ return ret;
|
|
|
}
|
|
|
|
|
|
/* XXX It's faster to return the atomic sleepdep_usecount */
|
|
|
- return omap2_prm_read_mod_bits_shift(clkdm1->pwrdm.ptr->prcm_offs,
|
|
|
- OMAP3430_CM_SLEEPDEP,
|
|
|
- (1 << clkdm2->dep_bit));
|
|
|
+ return arch_clkdm->clkdm_read_sleepdep(clkdm1, clkdm2);
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -716,31 +755,13 @@ int clkdm_read_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
|
|
|
*/
|
|
|
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;
|
|
|
-
|
|
|
- if (!cd->clkdm && cd->clkdm_name)
|
|
|
- cd->clkdm = _clkdm_lookup(cd->clkdm_name);
|
|
|
-
|
|
|
- /* PRM accesses are slow, so minimize them */
|
|
|
- mask |= 1 << cd->clkdm->dep_bit;
|
|
|
- atomic_set(&cd->sleepdep_usecount, 0);
|
|
|
- }
|
|
|
-
|
|
|
- omap2_prm_clear_mod_reg_bits(mask, clkdm->pwrdm.ptr->prcm_offs,
|
|
|
- OMAP3430_CM_SLEEPDEP);
|
|
|
+ if (!arch_clkdm || !arch_clkdm->clkdm_clear_all_sleepdeps)
|
|
|
+ return -EINVAL;
|
|
|
|
|
|
- return 0;
|
|
|
+ return arch_clkdm->clkdm_clear_all_sleepdeps(clkdm);
|
|
|
}
|
|
|
|
|
|
/**
|