|
@@ -1497,3 +1497,160 @@ static void _shutdown_sysc(struct omap_hwmod *oh)
|
|
|
static struct omap_hwmod *_lookup(const char *name)
|
|
|
{
|
|
|
struct omap_hwmod *oh, *temp_oh;
|
|
|
+
|
|
|
+ oh = NULL;
|
|
|
+
|
|
|
+ list_for_each_entry(temp_oh, &omap_hwmod_list, node) {
|
|
|
+ if (!strcmp(name, temp_oh->name)) {
|
|
|
+ oh = temp_oh;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ 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 the clkdm_name lookup failed.
|
|
|
+ */
|
|
|
+static int _init_clkdm(struct omap_hwmod *oh)
|
|
|
+{
|
|
|
+ if (!oh->clkdm_name) {
|
|
|
+ pr_debug("omap_hwmod: %s: missing clockdomain\n", oh->name);
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ 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. Retrieve as
|
|
|
+ * well the clockdomain.
|
|
|
+ * @oh: struct omap_hwmod *
|
|
|
+ * @data: not used; pass NULL
|
|
|
+ *
|
|
|
+ * Called by omap_hwmod_setup_*() (after omap2_clk_init()).
|
|
|
+ * Resolves all clock names embedded in the hwmod. Returns 0 on
|
|
|
+ * success, or a negative error code on failure.
|
|
|
+ */
|
|
|
+static int _init_clocks(struct omap_hwmod *oh, void *data)
|
|
|
+{
|
|
|
+ int ret = 0;
|
|
|
+
|
|
|
+ if (oh->_state != _HWMOD_STATE_REGISTERED)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ pr_debug("omap_hwmod: %s: looking up clocks\n", oh->name);
|
|
|
+
|
|
|
+ if (soc_ops.init_clkdm)
|
|
|
+ ret |= soc_ops.init_clkdm(oh);
|
|
|
+
|
|
|
+ ret |= _init_main_clk(oh);
|
|
|
+ ret |= _init_interface_clks(oh);
|
|
|
+ ret |= _init_opt_clks(oh);
|
|
|
+
|
|
|
+ if (!ret)
|
|
|
+ oh->_state = _HWMOD_STATE_CLKS_INITED;
|
|
|
+ else
|
|
|
+ pr_warning("omap_hwmod: %s: cannot _init_clocks\n", oh->name);
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * _lookup_hardreset - fill register bit info for this hwmod/reset line
|
|
|
+ * @oh: struct omap_hwmod *
|
|
|
+ * @name: name of the reset line in the context of this hwmod
|
|
|
+ * @ohri: struct omap_hwmod_rst_info * that this function will fill in
|
|
|
+ *
|
|
|
+ * Return the bit position of the reset line that match the
|
|
|
+ * input name. Return -ENOENT if not found.
|
|
|
+ */
|
|
|
+static int _lookup_hardreset(struct omap_hwmod *oh, const char *name,
|
|
|
+ struct omap_hwmod_rst_info *ohri)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+
|
|
|
+ for (i = 0; i < oh->rst_lines_cnt; i++) {
|
|
|
+ const char *rst_line = oh->rst_lines[i].name;
|
|
|
+ if (!strcmp(rst_line, name)) {
|
|
|
+ ohri->rst_shift = oh->rst_lines[i].rst_shift;
|
|
|
+ ohri->st_shift = oh->rst_lines[i].st_shift;
|
|
|
+ pr_debug("omap_hwmod: %s: %s: %s: rst %d st %d\n",
|
|
|
+ oh->name, __func__, rst_line, ohri->rst_shift,
|
|
|
+ ohri->st_shift);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return -ENOENT;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * _assert_hardreset - assert the HW reset line of submodules
|
|
|
+ * contained in the hwmod module.
|
|
|
+ * @oh: struct omap_hwmod *
|
|
|
+ * @name: name of the reset line to lookup and assert
|
|
|
+ *
|
|
|
+ * Some IP like dsp, ipu or iva contain processor that require an HW
|
|
|
+ * reset line to be assert / deassert in order to enable fully the IP.
|
|
|
+ * Returns -EINVAL if @oh is null, -ENOSYS if we have no way of
|
|
|
+ * asserting the hardreset line on the currently-booted SoC, or passes
|
|
|
+ * along the return value from _lookup_hardreset() or the SoC's
|
|
|
+ * assert_hardreset code.
|
|
|
+ */
|
|
|
+static int _assert_hardreset(struct omap_hwmod *oh, const char *name)
|
|
|
+{
|
|
|
+ struct omap_hwmod_rst_info ohri;
|
|
|
+ int ret = -EINVAL;
|
|
|
+
|
|
|
+ if (!oh)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ if (!soc_ops.assert_hardreset)
|
|
|
+ return -ENOSYS;
|
|
|
+
|
|
|
+ ret = _lookup_hardreset(oh, name, &ohri);
|
|
|
+ if (ret < 0)
|
|
|
+ return ret;
|
|
|
+
|
|
|
+ ret = soc_ops.assert_hardreset(oh, &ohri);
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * _deassert_hardreset - deassert the HW reset line of submodules contained
|
|
|
+ * in the hwmod module.
|
|
|
+ * @oh: struct omap_hwmod *
|
|
|
+ * @name: name of the reset line to look up and deassert
|
|
|
+ *
|
|
|
+ * Some IP like dsp, ipu or iva contain processor that require an HW
|
|
|
+ * reset line to be assert / deassert in order to enable fully the IP.
|
|
|
+ * Returns -EINVAL if @oh is null, -ENOSYS if we have no way of
|
|
|
+ * deasserting the hardreset line on the currently-booted SoC, or passes
|
|
|
+ * along the return value from _lookup_hardreset() or the SoC's
|
|
|
+ * deassert_hardreset code.
|
|
|
+ */
|
|
|
+static int _deassert_hardreset(struct omap_hwmod *oh, const char *name)
|
|
|
+{
|
|
|
+ struct omap_hwmod_rst_info ohri;
|
|
|
+ int ret = -EINVAL;
|
|
|
+ int hwsup = 0;
|
|
|
+
|