|
@@ -221,3 +221,190 @@ static unsigned short free_ls, max_ls, ls_supp;
|
|
|
static bool inited;
|
|
|
|
|
|
/* Private functions */
|
|
|
+
|
|
|
+/**
|
|
|
+ * _fetch_next_ocp_if - return the next OCP interface in a list
|
|
|
+ * @p: ptr to a ptr to the list_head inside the ocp_if to return
|
|
|
+ * @i: pointer to the index of the element pointed to by @p in the list
|
|
|
+ *
|
|
|
+ * Return a pointer to the struct omap_hwmod_ocp_if record
|
|
|
+ * containing the struct list_head pointed to by @p, and increment
|
|
|
+ * @p such that a future call to this routine will return the next
|
|
|
+ * record.
|
|
|
+ */
|
|
|
+static struct omap_hwmod_ocp_if *_fetch_next_ocp_if(struct list_head **p,
|
|
|
+ int *i)
|
|
|
+{
|
|
|
+ struct omap_hwmod_ocp_if *oi;
|
|
|
+
|
|
|
+ oi = list_entry(*p, struct omap_hwmod_link, node)->ocp_if;
|
|
|
+ *p = (*p)->next;
|
|
|
+
|
|
|
+ *i = *i + 1;
|
|
|
+
|
|
|
+ return oi;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * _update_sysc_cache - return the module OCP_SYSCONFIG register, keep copy
|
|
|
+ * @oh: struct omap_hwmod *
|
|
|
+ *
|
|
|
+ * Load the current value of the hwmod OCP_SYSCONFIG register into the
|
|
|
+ * struct omap_hwmod for later use. Returns -EINVAL if the hwmod has no
|
|
|
+ * OCP_SYSCONFIG register or 0 upon success.
|
|
|
+ */
|
|
|
+static int _update_sysc_cache(struct omap_hwmod *oh)
|
|
|
+{
|
|
|
+ if (!oh->class->sysc) {
|
|
|
+ WARN(1, "omap_hwmod: %s: cannot read OCP_SYSCONFIG: not defined on hwmod's class\n", oh->name);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* XXX ensure module interface clock is up */
|
|
|
+
|
|
|
+ oh->_sysc_cache = omap_hwmod_read(oh, oh->class->sysc->sysc_offs);
|
|
|
+
|
|
|
+ if (!(oh->class->sysc->sysc_flags & SYSC_NO_CACHE))
|
|
|
+ oh->_int_flags |= _HWMOD_SYSCONFIG_LOADED;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * _write_sysconfig - write a value to the module's OCP_SYSCONFIG register
|
|
|
+ * @v: OCP_SYSCONFIG value to write
|
|
|
+ * @oh: struct omap_hwmod *
|
|
|
+ *
|
|
|
+ * Write @v into the module class' OCP_SYSCONFIG register, if it has
|
|
|
+ * one. No return value.
|
|
|
+ */
|
|
|
+static void _write_sysconfig(u32 v, struct omap_hwmod *oh)
|
|
|
+{
|
|
|
+ if (!oh->class->sysc) {
|
|
|
+ WARN(1, "omap_hwmod: %s: cannot write OCP_SYSCONFIG: not defined on hwmod's class\n", oh->name);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* XXX ensure module interface clock is up */
|
|
|
+
|
|
|
+ /* Module might have lost context, always update cache and register */
|
|
|
+ oh->_sysc_cache = v;
|
|
|
+ omap_hwmod_write(v, oh, oh->class->sysc->sysc_offs);
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * _set_master_standbymode: set the OCP_SYSCONFIG MIDLEMODE field in @v
|
|
|
+ * @oh: struct omap_hwmod *
|
|
|
+ * @standbymode: MIDLEMODE field bits
|
|
|
+ * @v: pointer to register contents to modify
|
|
|
+ *
|
|
|
+ * Update the master standby mode bits in @v to be @standbymode for
|
|
|
+ * the @oh hwmod. Does not write to the hardware. Returns -EINVAL
|
|
|
+ * upon error or 0 upon success.
|
|
|
+ */
|
|
|
+static int _set_master_standbymode(struct omap_hwmod *oh, u8 standbymode,
|
|
|
+ u32 *v)
|
|
|
+{
|
|
|
+ u32 mstandby_mask;
|
|
|
+ u8 mstandby_shift;
|
|
|
+
|
|
|
+ if (!oh->class->sysc ||
|
|
|
+ !(oh->class->sysc->sysc_flags & SYSC_HAS_MIDLEMODE))
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ if (!oh->class->sysc->sysc_fields) {
|
|
|
+ WARN(1, "omap_hwmod: %s: offset struct for sysconfig not provided in class\n", oh->name);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ mstandby_shift = oh->class->sysc->sysc_fields->midle_shift;
|
|
|
+ mstandby_mask = (0x3 << mstandby_shift);
|
|
|
+
|
|
|
+ *v &= ~mstandby_mask;
|
|
|
+ *v |= __ffs(standbymode) << mstandby_shift;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * _set_slave_idlemode: set the OCP_SYSCONFIG SIDLEMODE field in @v
|
|
|
+ * @oh: struct omap_hwmod *
|
|
|
+ * @idlemode: SIDLEMODE field bits
|
|
|
+ * @v: pointer to register contents to modify
|
|
|
+ *
|
|
|
+ * Update the slave idle mode bits in @v to be @idlemode for the @oh
|
|
|
+ * hwmod. Does not write to the hardware. Returns -EINVAL upon error
|
|
|
+ * or 0 upon success.
|
|
|
+ */
|
|
|
+static int _set_slave_idlemode(struct omap_hwmod *oh, u8 idlemode, u32 *v)
|
|
|
+{
|
|
|
+ u32 sidle_mask;
|
|
|
+ u8 sidle_shift;
|
|
|
+
|
|
|
+ if (!oh->class->sysc ||
|
|
|
+ !(oh->class->sysc->sysc_flags & SYSC_HAS_SIDLEMODE))
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ if (!oh->class->sysc->sysc_fields) {
|
|
|
+ WARN(1, "omap_hwmod: %s: offset struct for sysconfig not provided in class\n", oh->name);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ sidle_shift = oh->class->sysc->sysc_fields->sidle_shift;
|
|
|
+ sidle_mask = (0x3 << sidle_shift);
|
|
|
+
|
|
|
+ *v &= ~sidle_mask;
|
|
|
+ *v |= __ffs(idlemode) << sidle_shift;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * _set_clockactivity: set OCP_SYSCONFIG.CLOCKACTIVITY bits in @v
|
|
|
+ * @oh: struct omap_hwmod *
|
|
|
+ * @clockact: CLOCKACTIVITY field bits
|
|
|
+ * @v: pointer to register contents to modify
|
|
|
+ *
|
|
|
+ * Update the clockactivity mode bits in @v to be @clockact for the
|
|
|
+ * @oh hwmod. Used for additional powersaving on some modules. Does
|
|
|
+ * not write to the hardware. Returns -EINVAL upon error or 0 upon
|
|
|
+ * success.
|
|
|
+ */
|
|
|
+static int _set_clockactivity(struct omap_hwmod *oh, u8 clockact, u32 *v)
|
|
|
+{
|
|
|
+ u32 clkact_mask;
|
|
|
+ u8 clkact_shift;
|
|
|
+
|
|
|
+ if (!oh->class->sysc ||
|
|
|
+ !(oh->class->sysc->sysc_flags & SYSC_HAS_CLOCKACTIVITY))
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ if (!oh->class->sysc->sysc_fields) {
|
|
|
+ WARN(1, "omap_hwmod: %s: offset struct for sysconfig not provided in class\n", oh->name);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ clkact_shift = oh->class->sysc->sysc_fields->clkact_shift;
|
|
|
+ clkact_mask = (0x3 << clkact_shift);
|
|
|
+
|
|
|
+ *v &= ~clkact_mask;
|
|
|
+ *v |= clockact << clkact_shift;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * _set_softreset: set OCP_SYSCONFIG.CLOCKACTIVITY bits in @v
|
|
|
+ * @oh: struct omap_hwmod *
|
|
|
+ * @v: pointer to register contents to modify
|
|
|
+ *
|
|
|
+ * Set the SOFTRESET bit in @v for hwmod @oh. Returns -EINVAL upon
|
|
|
+ * error or 0 upon success.
|
|
|
+ */
|
|
|
+static int _set_softreset(struct omap_hwmod *oh, u32 *v)
|
|
|
+{
|
|
|
+ u32 softrst_mask;
|
|
|
+
|
|
|
+ if (!oh->class->sysc ||
|
|
|
+ !(oh->class->sysc->sysc_flags & SYSC_HAS_SOFTRESET))
|
|
|
+ return -EINVAL;
|