]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - sitara-epos/sitara-epos-kernel.git/blobdiff - arch/arm/mach-omap2/omap_hwmod.c
OMAP4: hwmod: Introduce the module control in hwmod control
[sitara-epos/sitara-epos-kernel.git] / arch / arm / mach-omap2 / omap_hwmod.c
index e03429453ce7aa8b20eee7fe0b1026a66fec8c5b..4424fee5cd5a071a6df0057113bed37db8a22ef8 100644 (file)
@@ -2,6 +2,7 @@
  * omap_hwmod implementation for OMAP2/3/4
  *
  * Copyright (C) 2009-2011 Nokia Corporation
+ * Copyright (C) 2011 Texas Instruments, Inc.
  *
  * Paul Walmsley, BenoĆ®t Cousson, Kevin Hilman
  *
 #include <plat/prcm.h>
 
 #include "cm2xxx_3xxx.h"
-#include "cm44xx.h"
+#include "cminst44xx.h"
 #include "prm2xxx_3xxx.h"
 #include "prm44xx.h"
+#include "prminst44xx.h"
 #include "mux.h"
 
 /* Maximum microseconds to wait for OMAP module to softreset */
@@ -387,11 +389,10 @@ static int _set_module_autoidle(struct omap_hwmod *oh, u8 autoidle,
  */
 static int _enable_wakeup(struct omap_hwmod *oh, u32 *v)
 {
-       u32 wakeup_mask;
-
        if (!oh->class->sysc ||
            !((oh->class->sysc->sysc_flags & SYSC_HAS_ENAWAKEUP) ||
-             (oh->class->sysc->idlemodes & SIDLE_SMART_WKUP)))
+             (oh->class->sysc->idlemodes & SIDLE_SMART_WKUP) ||
+             (oh->class->sysc->idlemodes & MSTANDBY_SMART_WKUP)))
                return -EINVAL;
 
        if (!oh->class->sysc->sysc_fields) {
@@ -399,12 +400,13 @@ static int _enable_wakeup(struct omap_hwmod *oh, u32 *v)
                return -EINVAL;
        }
 
-       wakeup_mask = (0x1 << oh->class->sysc->sysc_fields->enwkup_shift);
-
-       *v |= wakeup_mask;
+       if (oh->class->sysc->sysc_flags & SYSC_HAS_ENAWAKEUP)
+               *v |= 0x1 << oh->class->sysc->sysc_fields->enwkup_shift;
 
        if (oh->class->sysc->idlemodes & SIDLE_SMART_WKUP)
                _set_slave_idlemode(oh, HWMOD_IDLEMODE_SMART_WKUP, v);
+       if (oh->class->sysc->idlemodes & MSTANDBY_SMART_WKUP)
+               _set_master_standbymode(oh, HWMOD_IDLEMODE_SMART_WKUP, v);
 
        /* XXX test pwrdm_get_wken for this hwmod's subsystem */
 
@@ -422,11 +424,10 @@ static int _enable_wakeup(struct omap_hwmod *oh, u32 *v)
  */
 static int _disable_wakeup(struct omap_hwmod *oh, u32 *v)
 {
-       u32 wakeup_mask;
-
        if (!oh->class->sysc ||
            !((oh->class->sysc->sysc_flags & SYSC_HAS_ENAWAKEUP) ||
-             (oh->class->sysc->idlemodes & SIDLE_SMART_WKUP)))
+             (oh->class->sysc->idlemodes & SIDLE_SMART_WKUP) ||
+             (oh->class->sysc->idlemodes & MSTANDBY_SMART_WKUP)))
                return -EINVAL;
 
        if (!oh->class->sysc->sysc_fields) {
@@ -434,12 +435,13 @@ static int _disable_wakeup(struct omap_hwmod *oh, u32 *v)
                return -EINVAL;
        }
 
-       wakeup_mask = (0x1 << oh->class->sysc->sysc_fields->enwkup_shift);
-
-       *v &= ~wakeup_mask;
+       if (oh->class->sysc->sysc_flags & SYSC_HAS_ENAWAKEUP)
+               *v &= ~(0x1 << oh->class->sysc->sysc_fields->enwkup_shift);
 
        if (oh->class->sysc->idlemodes & SIDLE_SMART_WKUP)
                _set_slave_idlemode(oh, HWMOD_IDLEMODE_SMART, v);
+       if (oh->class->sysc->idlemodes & MSTANDBY_SMART_WKUP)
+               _set_master_standbymode(oh, HWMOD_IDLEMODE_SMART_WKUP, v);
 
        /* XXX test pwrdm_get_wken for this hwmod's subsystem */
 
@@ -677,6 +679,125 @@ static void _disable_optional_clocks(struct omap_hwmod *oh)
                }
 }
 
+/**
+ * _enable_module - enable CLKCTRL modulemode on OMAP4
+ * @oh: struct omap_hwmod *
+ *
+ * Enables the PRCM module mode related to the hwmod @oh.
+ * No return value.
+ */
+static void _enable_module(struct omap_hwmod *oh)
+{
+       /* The module mode does not exist prior OMAP4 */
+       if (cpu_is_omap24xx() || cpu_is_omap34xx())
+               return;
+
+       if (!oh->clkdm || !oh->prcm.omap4.modulemode)
+               return;
+
+       pr_debug("omap_hwmod: %s: _enable_module: %d\n",
+                oh->name, oh->prcm.omap4.modulemode);
+
+       omap4_cminst_module_enable(oh->prcm.omap4.modulemode,
+                                  oh->clkdm->prcm_partition,
+                                  oh->clkdm->cm_inst,
+                                  oh->clkdm->clkdm_offs,
+                                  oh->prcm.omap4.clkctrl_offs);
+}
+
+/**
+ * _disable_module - enable CLKCTRL modulemode on OMAP4
+ * @oh: struct omap_hwmod *
+ *
+ * Disable the PRCM module mode related to the hwmod @oh.
+ * No return value.
+ */
+static void _disable_module(struct omap_hwmod *oh)
+{
+       /* The module mode does not exist prior OMAP4 */
+       if (cpu_is_omap24xx() || cpu_is_omap34xx())
+               return;
+
+       if (!oh->clkdm || !oh->prcm.omap4.modulemode)
+               return;
+
+       pr_debug("omap_hwmod: %s: _disable_module\n", oh->name);
+
+       omap4_cminst_module_disable(oh->clkdm->prcm_partition,
+                                   oh->clkdm->cm_inst,
+                                   oh->clkdm->clkdm_offs,
+                                   oh->prcm.omap4.clkctrl_offs);
+}
+
+/**
+ * _count_mpu_irqs - count the number of MPU IRQ lines associated with @oh
+ * @oh: struct omap_hwmod *oh
+ *
+ * Count and return the number of MPU IRQs associated with the hwmod
+ * @oh.  Used to allocate struct resource data.  Returns 0 if @oh is
+ * NULL.
+ */
+static int _count_mpu_irqs(struct omap_hwmod *oh)
+{
+       struct omap_hwmod_irq_info *ohii;
+       int i = 0;
+
+       if (!oh || !oh->mpu_irqs)
+               return 0;
+
+       do {
+               ohii = &oh->mpu_irqs[i++];
+       } while (ohii->irq != -1);
+
+       return i;
+}
+
+/**
+ * _count_sdma_reqs - count the number of SDMA request lines associated with @oh
+ * @oh: struct omap_hwmod *oh
+ *
+ * Count and return the number of SDMA request lines associated with
+ * the hwmod @oh.  Used to allocate struct resource data.  Returns 0
+ * if @oh is NULL.
+ */
+static int _count_sdma_reqs(struct omap_hwmod *oh)
+{
+       struct omap_hwmod_dma_info *ohdi;
+       int i = 0;
+
+       if (!oh || !oh->sdma_reqs)
+               return 0;
+
+       do {
+               ohdi = &oh->sdma_reqs[i++];
+       } while (ohdi->dma_req != -1);
+
+       return i;
+}
+
+/**
+ * _count_ocp_if_addr_spaces - count the number of address space entries for @oh
+ * @oh: struct omap_hwmod *oh
+ *
+ * Count and return the number of address space ranges associated with
+ * the hwmod @oh.  Used to allocate struct resource data.  Returns 0
+ * if @oh is NULL.
+ */
+static int _count_ocp_if_addr_spaces(struct omap_hwmod_ocp_if *os)
+{
+       struct omap_hwmod_addr_space *mem;
+       int i = 0;
+
+       if (!os || !os->addr)
+               return 0;
+
+       do {
+               mem = &os->addr[i++];
+       } while (mem->pa_start != mem->pa_end);
+
+       return i;
+}
+
 /**
  * _find_mpu_port_index - find hwmod OCP slave port ID intended for MPU use
  * @oh: struct omap_hwmod *
@@ -722,8 +843,7 @@ static void __iomem * __init _find_mpu_rt_base(struct omap_hwmod *oh, u8 index)
 {
        struct omap_hwmod_ocp_if *os;
        struct omap_hwmod_addr_space *mem;
-       int i;
-       int found = 0;
+       int i = 0, found = 0;
        void __iomem *va_start;
 
        if (!oh || oh->slaves_cnt == 0)
@@ -731,12 +851,14 @@ static void __iomem * __init _find_mpu_rt_base(struct omap_hwmod *oh, u8 index)
 
        os = oh->slaves[index];
 
-       for (i = 0, mem = os->addr; i < os->addr_cnt; i++, mem++) {
-               if (mem->flags & ADDR_TYPE_RT) {
+       if (!os->addr)
+               return NULL;
+
+       do {
+               mem = &os->addr[i++];
+               if (mem->flags & ADDR_TYPE_RT)
                        found = 1;
-                       break;
-               }
-       }
+       } while (!found && mem->pa_start != mem->pa_end);
 
        if (found) {
                va_start = ioremap(mem->pa_start, mem->pa_end - mem->pa_start);
@@ -781,8 +903,16 @@ static void _enable_sysc(struct omap_hwmod *oh)
        }
 
        if (sf & SYSC_HAS_MIDLEMODE) {
-               idlemode = (oh->flags & HWMOD_SWSUP_MSTANDBY) ?
-                       HWMOD_IDLEMODE_NO : HWMOD_IDLEMODE_SMART;
+               if (oh->flags & HWMOD_SWSUP_MSTANDBY) {
+                       idlemode = HWMOD_IDLEMODE_NO;
+               } else {
+                       if (sf & SYSC_HAS_ENAWAKEUP)
+                               _enable_wakeup(oh, &v);
+                       if (oh->class->sysc->idlemodes & MSTANDBY_SMART_WKUP)
+                               idlemode = HWMOD_IDLEMODE_SMART_WKUP;
+                       else
+                               idlemode = HWMOD_IDLEMODE_SMART;
+               }
                _set_master_standbymode(oh, idlemode, &v);
        }
 
@@ -840,8 +970,16 @@ static void _idle_sysc(struct omap_hwmod *oh)
        }
 
        if (sf & SYSC_HAS_MIDLEMODE) {
-               idlemode = (oh->flags & HWMOD_SWSUP_MSTANDBY) ?
-                       HWMOD_IDLEMODE_FORCE : HWMOD_IDLEMODE_SMART;
+               if (oh->flags & HWMOD_SWSUP_MSTANDBY) {
+                       idlemode = HWMOD_IDLEMODE_FORCE;
+               } else {
+                       if (sf & SYSC_HAS_ENAWAKEUP)
+                               _enable_wakeup(oh, &v);
+                       if (oh->class->sysc->idlemodes & MSTANDBY_SMART_WKUP)
+                               idlemode = HWMOD_IDLEMODE_SMART_WKUP;
+                       else
+                               idlemode = HWMOD_IDLEMODE_SMART;
+               }
                _set_master_standbymode(oh, idlemode, &v);
        }
 
@@ -903,9 +1041,40 @@ static struct omap_hwmod *_lookup(const char *name)
 
        return oh;
 }
+/**
+ * _init_clkdm - look up a clockdomain name, store pointer in omap_hwmod
+ * @oh: struct omap_hwmod *
+ *
+ * Convert a clockdomain name stored in a struct omap_hwmod into a
+ * clockdomain pointer, and save it into the struct omap_hwmod.
+ * return -EINVAL if clkdm_name does not exist or if the lookup failed.
+ */
+static int _init_clkdm(struct omap_hwmod *oh)
+{
+       if (cpu_is_omap24xx() || cpu_is_omap34xx())
+               return 0;
+
+       if (!oh->clkdm_name) {
+               pr_warning("omap_hwmod: %s: no clkdm_name\n", oh->name);
+               return -EINVAL;
+       }
+
+       oh->clkdm = clkdm_lookup(oh->clkdm_name);
+       if (!oh->clkdm) {
+               pr_warning("omap_hwmod: %s: could not associate to clkdm %s\n",
+                       oh->name, oh->clkdm_name);
+               return -EINVAL;
+       }
+
+       pr_debug("omap_hwmod: %s: associated to clkdm %s\n",
+               oh->name, oh->clkdm_name);
+
+       return 0;
+}
 
 /**
- * _init_clocks - clk_get() all clocks associated with this hwmod
+ * _init_clocks - clk_get() all clocks associated with this hwmod. Retrieve as
+ * well the clockdomain.
  * @oh: struct omap_hwmod *
  * @data: not used; pass NULL
  *
@@ -925,9 +1094,12 @@ static int _init_clocks(struct omap_hwmod *oh, void *data)
        ret |= _init_main_clk(oh);
        ret |= _init_interface_clks(oh);
        ret |= _init_opt_clks(oh);
+       ret |= _init_clkdm(oh);
 
        if (!ret)
                oh->_state = _HWMOD_STATE_CLKS_INITED;
+       else
+               pr_warning("omap_hwmod: %s: cannot _init_clocks\n", oh->name);
 
        return ret;
 }
@@ -939,7 +1111,7 @@ static int _init_clocks(struct omap_hwmod *oh, void *data)
  * Wait for a module @oh to leave slave idle.  Returns 0 if the module
  * does not have an IDLEST bit or if the module successfully leaves
  * slave idle; otherwise, pass along the return value of the
- * appropriate *_cm_wait_module_ready() function.
+ * appropriate *_cm*_wait_module_ready() function.
  */
 static int _wait_target_ready(struct omap_hwmod *oh)
 {
@@ -966,7 +1138,13 @@ static int _wait_target_ready(struct omap_hwmod *oh)
                                                 oh->prcm.omap2.idlest_reg_id,
                                                 oh->prcm.omap2.idlest_idle_bit);
        } else if (cpu_is_omap44xx()) {
-               ret = omap4_cm_wait_module_ready(oh->prcm.omap4.clkctrl_reg);
+               if (!oh->clkdm)
+                       return -EINVAL;
+
+               ret = omap4_cminst_wait_module_ready(oh->clkdm->prcm_partition,
+                                                    oh->clkdm->cm_inst,
+                                                    oh->clkdm->clkdm_offs,
+                                                    oh->prcm.omap4.clkctrl_offs);
        } else {
                BUG();
        };
@@ -974,6 +1152,36 @@ static int _wait_target_ready(struct omap_hwmod *oh)
        return ret;
 }
 
+/**
+ * _wait_target_disable - wait for a module to be disabled
+ * @oh: struct omap_hwmod *
+ *
+ * Wait for a module @oh to enter slave idle.  Returns 0 if the module
+ * does not have an IDLEST bit or if the module successfully enters
+ * slave idle; otherwise, pass along the return value of the
+ * appropriate *_cm*_wait_module_idle() function.
+ */
+static int _wait_target_disable(struct omap_hwmod *oh)
+{
+       /* TODO: For now just handle OMAP4+ */
+       if (cpu_is_omap24xx() || cpu_is_omap34xx())
+               return 0;
+
+       if (!oh)
+               return -EINVAL;
+
+       if (oh->_int_flags & _HWMOD_NO_MPU_PORT)
+               return 0;
+
+       if (oh->flags & HWMOD_NO_IDLEST)
+               return 0;
+
+       return omap4_cminst_wait_module_idle(oh->clkdm->prcm_partition,
+                                            oh->clkdm->cm_inst,
+                                            oh->clkdm->clkdm_offs,
+                                            oh->prcm.omap4.clkctrl_offs);
+}
+
 /**
  * _lookup_hardreset - fill register bit info for this hwmod/reset line
  * @oh: struct omap_hwmod *
@@ -1030,8 +1238,10 @@ static int _assert_hardreset(struct omap_hwmod *oh, const char *name)
                return omap2_prm_assert_hardreset(oh->prcm.omap2.module_offs,
                                                  ohri.rst_shift);
        else if (cpu_is_omap44xx())
-               return omap4_prm_assert_hardreset(oh->prcm.omap4.rstctrl_reg,
-                                                 ohri.rst_shift);
+               return omap4_prminst_assert_hardreset(ohri.rst_shift,
+                                 oh->clkdm->pwrdm.ptr->prcm_partition,
+                                 oh->clkdm->pwrdm.ptr->prcm_offs,
+                                 oh->prcm.omap4.rstctrl_offs);
        else
                return -EINVAL;
 }
@@ -1066,8 +1276,10 @@ static int _deassert_hardreset(struct omap_hwmod *oh, const char *name)
                if (ohri.st_shift)
                        pr_err("omap_hwmod: %s: %s: hwmod data error: OMAP4 does not support st_shift\n",
                               oh->name, name);
-               ret = omap4_prm_deassert_hardreset(oh->prcm.omap4.rstctrl_reg,
-                                                  ohri.rst_shift);
+               ret = omap4_prminst_deassert_hardreset(ohri.rst_shift,
+                                 oh->clkdm->pwrdm.ptr->prcm_partition,
+                                 oh->clkdm->pwrdm.ptr->prcm_offs,
+                                 oh->prcm.omap4.rstctrl_offs);
        } else {
                return -EINVAL;
        }
@@ -1102,8 +1314,10 @@ static int _read_hardreset(struct omap_hwmod *oh, const char *name)
                return omap2_prm_is_hardreset_asserted(oh->prcm.omap2.module_offs,
                                                       ohri.st_shift);
        } else if (cpu_is_omap44xx()) {
-               return omap4_prm_is_hardreset_asserted(oh->prcm.omap4.rstctrl_reg,
-                                                      ohri.rst_shift);
+               return omap4_prminst_is_hardreset_asserted(ohri.rst_shift,
+                                 oh->clkdm->pwrdm.ptr->prcm_partition,
+                                 oh->clkdm->pwrdm.ptr->prcm_offs,
+                                 oh->prcm.omap4.rstctrl_offs);
        } else {
                return -EINVAL;
        }
@@ -1224,6 +1438,8 @@ static int _enable(struct omap_hwmod *oh)
 {
        int r;
 
+       pr_debug("omap_hwmod: %s: enabling\n", oh->name);
+
        if (oh->_state != _HWMOD_STATE_INITIALIZED &&
            oh->_state != _HWMOD_STATE_IDLE &&
            oh->_state != _HWMOD_STATE_DISABLED) {
@@ -1232,17 +1448,6 @@ static int _enable(struct omap_hwmod *oh)
                return -EINVAL;
        }
 
-       pr_debug("omap_hwmod: %s: enabling\n", oh->name);
-
-       /*
-        * If an IP contains only one HW reset line, then de-assert it in order
-        * to allow to enable the clocks. Otherwise the PRCM will return
-        * Intransition status, and the init will failed.
-        */
-       if ((oh->_state == _HWMOD_STATE_INITIALIZED ||
-            oh->_state == _HWMOD_STATE_DISABLED) && oh->rst_lines_cnt == 1)
-               _deassert_hardreset(oh, oh->rst_lines[0].name);
-
        /* Mux pins for device runtime if populated */
        if (oh->mux && (!oh->mux->enabled ||
                        ((oh->_state == _HWMOD_STATE_IDLE) &&
@@ -1252,20 +1457,32 @@ static int _enable(struct omap_hwmod *oh)
        _add_initiator_dep(oh, mpu_oh);
        _enable_clocks(oh);
 
-       r = _wait_target_ready(oh);
-       if (!r) {
-               oh->_state = _HWMOD_STATE_ENABLED;
+       /*
+        * If an IP contains only one HW reset line, then de-assert it in order
+        * to allow the module state transition. Otherwise the PRCM will return
+        * Intransition status, and the init will failed.
+        */
+       if ((oh->_state == _HWMOD_STATE_INITIALIZED ||
+            oh->_state == _HWMOD_STATE_DISABLED) && oh->rst_lines_cnt == 1)
+               _deassert_hardreset(oh, oh->rst_lines[0].name);
 
-               /* Access the sysconfig only if the target is ready */
-               if (oh->class->sysc) {
-                       if (!(oh->_int_flags & _HWMOD_SYSCONFIG_LOADED))
-                               _update_sysc_cache(oh);
-                       _enable_sysc(oh);
-               }
-       } else {
-               _disable_clocks(oh);
+       r = _wait_target_ready(oh);
+       if (r) {
                pr_debug("omap_hwmod: %s: _wait_target_ready: %d\n",
                         oh->name, r);
+               _disable_clocks(oh);
+
+               return r;
+       }
+       _enable_module(oh);
+
+       oh->_state = _HWMOD_STATE_ENABLED;
+
+       /* Access the sysconfig only if the target is ready */
+       if (oh->class->sysc) {
+               if (!(oh->_int_flags & _HWMOD_SYSCONFIG_LOADED))
+                       _update_sysc_cache(oh);
+               _enable_sysc(oh);
        }
 
        return r;
@@ -1281,17 +1498,30 @@ static int _enable(struct omap_hwmod *oh)
  */
 static int _idle(struct omap_hwmod *oh)
 {
+       int ret;
+
+       pr_debug("omap_hwmod: %s: idling\n", oh->name);
+
        if (oh->_state != _HWMOD_STATE_ENABLED) {
                WARN(1, "omap_hwmod: %s: idle state can only be entered from "
                     "enabled state\n", oh->name);
                return -EINVAL;
        }
 
-       pr_debug("omap_hwmod: %s: idling\n", oh->name);
-
        if (oh->class->sysc)
                _idle_sysc(oh);
        _del_initiator_dep(oh, mpu_oh);
+       _disable_module(oh);
+       ret = _wait_target_disable(oh);
+       if (ret)
+               pr_warn("omap_hwmod: %s: _wait_target_disable failed\n",
+                       oh->name);
+       /*
+        * The module must be in idle mode before disabling any parents
+        * clocks. Otherwise, the parent clock might be disabled before
+        * the module transition is done, and thus will prevent the
+        * transition to complete properly.
+        */
        _disable_clocks(oh);
 
        /* Mux pins for device idle if populated */
@@ -1374,24 +1604,32 @@ static int _shutdown(struct omap_hwmod *oh)
                }
        }
 
-       if (oh->class->sysc)
+       if (oh->class->sysc) {
+               if (oh->_state == _HWMOD_STATE_IDLE)
+                       _enable(oh);
                _shutdown_sysc(oh);
-
-       /*
-        * If an IP contains only one HW reset line, then assert it
-        * before disabling the clocks and shutting down the IP.
-        */
-       if (oh->rst_lines_cnt == 1)
-               _assert_hardreset(oh, oh->rst_lines[0].name);
+       }
 
        /* clocks and deps are already disabled in idle */
        if (oh->_state == _HWMOD_STATE_ENABLED) {
                _del_initiator_dep(oh, mpu_oh);
                /* XXX what about the other system initiators here? dma, dsp */
+               _disable_module(oh);
+               ret = _wait_target_disable(oh);
+               if (ret)
+                       pr_warn("omap_hwmod: %s: _wait_target_disable failed\n",
+                               oh->name);
                _disable_clocks(oh);
        }
        /* XXX Should this code also force-disable the optional clocks? */
 
+       /*
+        * If an IP contains only one HW reset line, then assert it
+        * after disabling the clocks and before shutting down the IP.
+        */
+       if (oh->rst_lines_cnt == 1)
+               _assert_hardreset(oh, oh->rst_lines[0].name);
+
        /* Mux pins to safe mode or use populated off mode values */
        if (oh->mux)
                omap_hwmod_mux(oh->mux, _HWMOD_STATE_DISABLED);
@@ -1561,6 +1799,33 @@ void omap_hwmod_write(u32 v, struct omap_hwmod *oh, u16 reg_offs)
                __raw_writel(v, oh->_mpu_rt_va + reg_offs);
 }
 
+/**
+ * omap_hwmod_softreset - reset a module via SYSCONFIG.SOFTRESET bit
+ * @oh: struct omap_hwmod *
+ *
+ * This is a public function exposed to drivers. Some drivers may need to do
+ * some settings before and after resetting the device.  Those drivers after
+ * doing the necessary settings could use this function to start a reset by
+ * setting the SYSCONFIG.SOFTRESET bit.
+ */
+int omap_hwmod_softreset(struct omap_hwmod *oh)
+{
+       u32 v;
+       int ret;
+
+       if (!oh || !(oh->_sysc_cache))
+               return -EINVAL;
+
+       v = oh->_sysc_cache;
+       ret = _set_softreset(oh, &v);
+       if (ret)
+               goto error;
+       _write_sysconfig(v, oh);
+
+error:
+       return ret;
+}
+
 /**
  * omap_hwmod_set_slave_idlemode - set the hwmod's OCP slave idlemode
  * @oh: struct omap_hwmod *
@@ -1628,7 +1893,7 @@ int omap_hwmod_for_each(int (*fn)(struct omap_hwmod *oh, void *data),
                        void *data)
 {
        struct omap_hwmod *temp_oh;
-       int ret;
+       int ret = 0;
 
        if (!fn)
                return -EINVAL;
@@ -1685,9 +1950,6 @@ static int __init _populate_mpu_rt_base(struct omap_hwmod *oh, void *data)
                return 0;
 
        oh->_mpu_rt_va = _find_mpu_rt_base(oh, oh->_mpu_port_index);
-       if (!oh->_mpu_rt_va)
-               pr_warning("omap_hwmod: %s found no _mpu_rt_va for %s\n",
-                               __func__, oh->name);
 
        return 0;
 }
@@ -1939,10 +2201,10 @@ int omap_hwmod_count_resources(struct omap_hwmod *oh)
 {
        int ret, i;
 
-       ret = oh->mpu_irqs_cnt + oh->sdma_reqs_cnt;
+       ret = _count_mpu_irqs(oh) + _count_sdma_reqs(oh);
 
        for (i = 0; i < oh->slaves_cnt; i++)
-               ret += oh->slaves[i]->addr_cnt;
+               ret += _count_ocp_if_addr_spaces(oh->slaves[i]);
 
        return ret;
 }
@@ -1959,12 +2221,13 @@ int omap_hwmod_count_resources(struct omap_hwmod *oh)
  */
 int omap_hwmod_fill_resources(struct omap_hwmod *oh, struct resource *res)
 {
-       int i, j;
+       int i, j, mpu_irqs_cnt, sdma_reqs_cnt;
        int r = 0;
 
        /* For each IRQ, DMA, memory area, fill in array.*/
 
-       for (i = 0; i < oh->mpu_irqs_cnt; i++) {
+       mpu_irqs_cnt = _count_mpu_irqs(oh);
+       for (i = 0; i < mpu_irqs_cnt; i++) {
                (res + r)->name = (oh->mpu_irqs + i)->name;
                (res + r)->start = (oh->mpu_irqs + i)->irq;
                (res + r)->end = (oh->mpu_irqs + i)->irq;
@@ -1972,7 +2235,8 @@ int omap_hwmod_fill_resources(struct omap_hwmod *oh, struct resource *res)
                r++;
        }
 
-       for (i = 0; i < oh->sdma_reqs_cnt; i++) {
+       sdma_reqs_cnt = _count_sdma_reqs(oh);
+       for (i = 0; i < sdma_reqs_cnt; i++) {
                (res + r)->name = (oh->sdma_reqs + i)->name;
                (res + r)->start = (oh->sdma_reqs + i)->dma_req;
                (res + r)->end = (oh->sdma_reqs + i)->dma_req;
@@ -1982,10 +2246,12 @@ int omap_hwmod_fill_resources(struct omap_hwmod *oh, struct resource *res)
 
        for (i = 0; i < oh->slaves_cnt; i++) {
                struct omap_hwmod_ocp_if *os;
+               int addr_cnt;
 
                os = oh->slaves[i];
+               addr_cnt = _count_ocp_if_addr_spaces(os);
 
-               for (j = 0; j < os->addr_cnt; j++) {
+               for (j = 0; j < addr_cnt; j++) {
                        (res + r)->name = (os->addr + j)->name;
                        (res + r)->start = (os->addr + j)->pa_start;
                        (res + r)->end = (os->addr + j)->pa_end;