|
@@ -183,3 +183,166 @@ void omap2_init_clk_clkdm(struct clk_hw *hw)
|
|
pr_debug("clock: could not associate clk %s to clkdm %s\n",
|
|
pr_debug("clock: could not associate clk %s to clkdm %s\n",
|
|
clk_name, clk->clkdm_name);
|
|
clk_name, clk->clkdm_name);
|
|
}
|
|
}
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * omap2_clk_disable_clkdm_control - disable clkdm control on clk enable/disable
|
|
|
|
+ *
|
|
|
|
+ * Prevent the OMAP clock code from calling into the clockdomain code
|
|
|
|
+ * when a hardware clock in that clockdomain is enabled or disabled.
|
|
|
|
+ * Intended to be called at init time from omap*_clk_init(). No
|
|
|
|
+ * return value.
|
|
|
|
+ */
|
|
|
|
+void __init omap2_clk_disable_clkdm_control(void)
|
|
|
|
+{
|
|
|
|
+ clkdm_control = false;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * omap2_clk_dflt_find_companion - find companion clock to @clk
|
|
|
|
+ * @clk: struct clk * to find the companion clock of
|
|
|
|
+ * @other_reg: void __iomem ** to return the companion clock CM_*CLKEN va in
|
|
|
|
+ * @other_bit: u8 ** to return the companion clock bit shift in
|
|
|
|
+ *
|
|
|
|
+ * Note: We don't need special code here for INVERT_ENABLE for the
|
|
|
|
+ * time being since INVERT_ENABLE only applies to clocks enabled by
|
|
|
|
+ * CM_CLKEN_PLL
|
|
|
|
+ *
|
|
|
|
+ * Convert CM_ICLKEN* <-> CM_FCLKEN*. This conversion assumes it's
|
|
|
|
+ * just a matter of XORing the bits.
|
|
|
|
+ *
|
|
|
|
+ * Some clocks don't have companion clocks. For example, modules with
|
|
|
|
+ * only an interface clock (such as MAILBOXES) don't have a companion
|
|
|
|
+ * clock. Right now, this code relies on the hardware exporting a bit
|
|
|
|
+ * in the correct companion register that indicates that the
|
|
|
|
+ * nonexistent 'companion clock' is active. Future patches will
|
|
|
|
+ * associate this type of code with per-module data structures to
|
|
|
|
+ * avoid this issue, and remove the casts. No return value.
|
|
|
|
+ */
|
|
|
|
+void omap2_clk_dflt_find_companion(struct clk_hw_omap *clk,
|
|
|
|
+ void __iomem **other_reg, u8 *other_bit)
|
|
|
|
+{
|
|
|
|
+ u32 r;
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * Convert CM_ICLKEN* <-> CM_FCLKEN*. This conversion assumes
|
|
|
|
+ * it's just a matter of XORing the bits.
|
|
|
|
+ */
|
|
|
|
+ r = ((__force u32)clk->enable_reg ^ (CM_FCLKEN ^ CM_ICLKEN));
|
|
|
|
+
|
|
|
|
+ *other_reg = (__force void __iomem *)r;
|
|
|
|
+ *other_bit = clk->enable_bit;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * omap2_clk_dflt_find_idlest - find CM_IDLEST reg va, bit shift for @clk
|
|
|
|
+ * @clk: struct clk * to find IDLEST info for
|
|
|
|
+ * @idlest_reg: void __iomem ** to return the CM_IDLEST va in
|
|
|
|
+ * @idlest_bit: u8 * to return the CM_IDLEST bit shift in
|
|
|
|
+ * @idlest_val: u8 * to return the idle status indicator
|
|
|
|
+ *
|
|
|
|
+ * Return the CM_IDLEST register address and bit shift corresponding
|
|
|
|
+ * to the module that "owns" this clock. This default code assumes
|
|
|
|
+ * that the CM_IDLEST bit shift is the CM_*CLKEN bit shift, and that
|
|
|
|
+ * the IDLEST register address ID corresponds to the CM_*CLKEN
|
|
|
|
+ * register address ID (e.g., that CM_FCLKEN2 corresponds to
|
|
|
|
+ * CM_IDLEST2). This is not true for all modules. No return value.
|
|
|
|
+ */
|
|
|
|
+void omap2_clk_dflt_find_idlest(struct clk_hw_omap *clk,
|
|
|
|
+ void __iomem **idlest_reg, u8 *idlest_bit, u8 *idlest_val)
|
|
|
|
+{
|
|
|
|
+ u32 r;
|
|
|
|
+
|
|
|
|
+ r = (((__force u32)clk->enable_reg & ~0xf0) | 0x20);
|
|
|
|
+ *idlest_reg = (__force void __iomem *)r;
|
|
|
|
+ *idlest_bit = clk->enable_bit;
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * 24xx uses 0 to indicate not ready, and 1 to indicate ready.
|
|
|
|
+ * 34xx reverses this, just to keep us on our toes
|
|
|
|
+ * AM35xx uses both, depending on the module.
|
|
|
|
+ */
|
|
|
|
+ if (cpu_is_omap24xx())
|
|
|
|
+ *idlest_val = OMAP24XX_CM_IDLEST_VAL;
|
|
|
|
+ else if (cpu_is_omap34xx())
|
|
|
|
+ *idlest_val = OMAP34XX_CM_IDLEST_VAL;
|
|
|
|
+ else
|
|
|
|
+ BUG();
|
|
|
|
+
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * omap2_dflt_clk_enable - enable a clock in the hardware
|
|
|
|
+ * @hw: struct clk_hw * of the clock to enable
|
|
|
|
+ *
|
|
|
|
+ * Enable the clock @hw in the hardware. We first call into the OMAP
|
|
|
|
+ * clockdomain code to "enable" the corresponding clockdomain if this
|
|
|
|
+ * is the first enabled user of the clockdomain. Then program the
|
|
|
|
+ * hardware to enable the clock. Then wait for the IP block that uses
|
|
|
|
+ * this clock to leave idle (if applicable). Returns the error value
|
|
|
|
+ * from clkdm_clk_enable() if it terminated with an error, or -EINVAL
|
|
|
|
+ * if @hw has a null clock enable_reg, or zero upon success.
|
|
|
|
+ */
|
|
|
|
+int omap2_dflt_clk_enable(struct clk_hw *hw)
|
|
|
|
+{
|
|
|
|
+ struct clk_hw_omap *clk;
|
|
|
|
+ u32 v;
|
|
|
|
+ int ret = 0;
|
|
|
|
+
|
|
|
|
+ clk = to_clk_hw_omap(hw);
|
|
|
|
+
|
|
|
|
+ if (clkdm_control && clk->clkdm) {
|
|
|
|
+ ret = clkdm_clk_enable(clk->clkdm, hw->clk);
|
|
|
|
+ if (ret) {
|
|
|
|
+ WARN(1, "%s: could not enable %s's clockdomain %s: %d\n",
|
|
|
|
+ __func__, __clk_get_name(hw->clk),
|
|
|
|
+ clk->clkdm->name, ret);
|
|
|
|
+ return ret;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (unlikely(clk->enable_reg == NULL)) {
|
|
|
|
+ pr_err("%s: %s missing enable_reg\n", __func__,
|
|
|
|
+ __clk_get_name(hw->clk));
|
|
|
|
+ ret = -EINVAL;
|
|
|
|
+ goto err;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* FIXME should not have INVERT_ENABLE bit here */
|
|
|
|
+ v = __raw_readl(clk->enable_reg);
|
|
|
|
+ if (clk->flags & INVERT_ENABLE)
|
|
|
|
+ v &= ~(1 << clk->enable_bit);
|
|
|
|
+ else
|
|
|
|
+ v |= (1 << clk->enable_bit);
|
|
|
|
+ __raw_writel(v, clk->enable_reg);
|
|
|
|
+ v = __raw_readl(clk->enable_reg); /* OCP barrier */
|
|
|
|
+
|
|
|
|
+ if (clk->ops && clk->ops->find_idlest)
|
|
|
|
+ _omap2_module_wait_ready(clk);
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+
|
|
|
|
+err:
|
|
|
|
+ if (clkdm_control && clk->clkdm)
|
|
|
|
+ clkdm_clk_disable(clk->clkdm, hw->clk);
|
|
|
|
+ return ret;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * omap2_dflt_clk_disable - disable a clock in the hardware
|
|
|
|
+ * @hw: struct clk_hw * of the clock to disable
|
|
|
|
+ *
|
|
|
|
+ * Disable the clock @hw in the hardware, and call into the OMAP
|
|
|
|
+ * clockdomain code to "disable" the corresponding clockdomain if all
|
|
|
|
+ * clocks/hwmods in that clockdomain are now disabled. No return
|
|
|
|
+ * value.
|
|
|
|
+ */
|
|
|
|
+void omap2_dflt_clk_disable(struct clk_hw *hw)
|
|
|
|
+{
|
|
|
|
+ struct clk_hw_omap *clk;
|
|
|
|
+ u32 v;
|
|
|
|
+
|
|
|
|
+ clk = to_clk_hw_omap(hw);
|
|
|
|
+ if (!clk->enable_reg) {
|
|
|
|
+ /*
|
|
|
|
+ * 'independent' here refers to a clock which is not
|