linux/drivers/clk/ti/clkt_dflt.c
<<
>>
Prefs
   1/*
   2 * Default clock type
   3 *
   4 * Copyright (C) 2005-2008, 2015 Texas Instruments, Inc.
   5 * Copyright (C) 2004-2010 Nokia Corporation
   6 *
   7 * Contacts:
   8 * Richard Woodruff <r-woodruff2@ti.com>
   9 * Paul Walmsley
  10 * Tero Kristo <t-kristo@ti.com>
  11 *
  12 * This program is free software; you can redistribute it and/or modify
  13 * it under the terms of the GNU General Public License version 2 as
  14 * published by the Free Software Foundation.
  15 *
  16 * This program is distributed "as is" WITHOUT ANY WARRANTY of any
  17 * kind, whether express or implied; without even the implied warranty
  18 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19 * GNU General Public License for more details.
  20 */
  21
  22#include <linux/kernel.h>
  23#include <linux/errno.h>
  24#include <linux/clk-provider.h>
  25#include <linux/io.h>
  26#include <linux/clk/ti.h>
  27#include <linux/delay.h>
  28
  29#include "clock.h"
  30
  31/*
  32 * MAX_MODULE_ENABLE_WAIT: maximum of number of microseconds to wait
  33 * for a module to indicate that it is no longer in idle
  34 */
  35#define MAX_MODULE_ENABLE_WAIT          100000
  36
  37/*
  38 * CM module register offsets, used for calculating the companion
  39 * register addresses.
  40 */
  41#define CM_FCLKEN                       0x0000
  42#define CM_ICLKEN                       0x0010
  43
  44/**
  45 * _wait_idlest_generic - wait for a module to leave the idle state
  46 * @clk: module clock to wait for (needed for register offsets)
  47 * @reg: virtual address of module IDLEST register
  48 * @mask: value to mask against to determine if the module is active
  49 * @idlest: idle state indicator (0 or 1) for the clock
  50 * @name: name of the clock (for printk)
  51 *
  52 * Wait for a module to leave idle, where its idle-status register is
  53 * not inside the CM module.  Returns 1 if the module left idle
  54 * promptly, or 0 if the module did not leave idle before the timeout
  55 * elapsed.  XXX Deprecated - should be moved into drivers for the
  56 * individual IP block that the IDLEST register exists in.
  57 */
  58static int _wait_idlest_generic(struct clk_hw_omap *clk,
  59                                struct clk_omap_reg *reg,
  60                                u32 mask, u8 idlest, const char *name)
  61{
  62        int i = 0, ena = 0;
  63
  64        ena = (idlest) ? 0 : mask;
  65
  66        /* Wait until module enters enabled state */
  67        for (i = 0; i < MAX_MODULE_ENABLE_WAIT; i++) {
  68                if ((ti_clk_ll_ops->clk_readl(reg) & mask) == ena)
  69                        break;
  70                udelay(1);
  71        }
  72
  73        if (i < MAX_MODULE_ENABLE_WAIT)
  74                pr_debug("omap clock: module associated with clock %s ready after %d loops\n",
  75                         name, i);
  76        else
  77                pr_err("omap clock: module associated with clock %s didn't enable in %d tries\n",
  78                       name, MAX_MODULE_ENABLE_WAIT);
  79
  80        return (i < MAX_MODULE_ENABLE_WAIT) ? 1 : 0;
  81}
  82
  83/**
  84 * _omap2_module_wait_ready - wait for an OMAP module to leave IDLE
  85 * @clk: struct clk * belonging to the module
  86 *
  87 * If the necessary clocks for the OMAP hardware IP block that
  88 * corresponds to clock @clk are enabled, then wait for the module to
  89 * indicate readiness (i.e., to leave IDLE).  This code does not
  90 * belong in the clock code and will be moved in the medium term to
  91 * module-dependent code.  No return value.
  92 */
  93static void _omap2_module_wait_ready(struct clk_hw_omap *clk)
  94{
  95        struct clk_omap_reg companion_reg, idlest_reg;
  96        u8 other_bit, idlest_bit, idlest_val, idlest_reg_id;
  97        s16 prcm_mod;
  98        int r;
  99
 100        /* Not all modules have multiple clocks that their IDLEST depends on */
 101        if (clk->ops->find_companion) {
 102                clk->ops->find_companion(clk, &companion_reg, &other_bit);
 103                if (!(ti_clk_ll_ops->clk_readl(&companion_reg) &
 104                      (1 << other_bit)))
 105                        return;
 106        }
 107
 108        clk->ops->find_idlest(clk, &idlest_reg, &idlest_bit, &idlest_val);
 109        r = ti_clk_ll_ops->cm_split_idlest_reg(&idlest_reg, &prcm_mod,
 110                                               &idlest_reg_id);
 111        if (r) {
 112                /* IDLEST register not in the CM module */
 113                _wait_idlest_generic(clk, &idlest_reg, (1 << idlest_bit),
 114                                     idlest_val, clk_hw_get_name(&clk->hw));
 115        } else {
 116                ti_clk_ll_ops->cm_wait_module_ready(0, prcm_mod, idlest_reg_id,
 117                                                    idlest_bit);
 118        }
 119}
 120
 121/**
 122 * omap2_clk_dflt_find_companion - find companion clock to @clk
 123 * @clk: struct clk * to find the companion clock of
 124 * @other_reg: void __iomem ** to return the companion clock CM_*CLKEN va in
 125 * @other_bit: u8 ** to return the companion clock bit shift in
 126 *
 127 * Note: We don't need special code here for INVERT_ENABLE for the
 128 * time being since INVERT_ENABLE only applies to clocks enabled by
 129 * CM_CLKEN_PLL
 130 *
 131 * Convert CM_ICLKEN* <-> CM_FCLKEN*.  This conversion assumes it's
 132 * just a matter of XORing the bits.
 133 *
 134 * Some clocks don't have companion clocks.  For example, modules with
 135 * only an interface clock (such as MAILBOXES) don't have a companion
 136 * clock.  Right now, this code relies on the hardware exporting a bit
 137 * in the correct companion register that indicates that the
 138 * nonexistent 'companion clock' is active.  Future patches will
 139 * associate this type of code with per-module data structures to
 140 * avoid this issue, and remove the casts.  No return value.
 141 */
 142void omap2_clk_dflt_find_companion(struct clk_hw_omap *clk,
 143                                   struct clk_omap_reg *other_reg,
 144                                   u8 *other_bit)
 145{
 146        memcpy(other_reg, &clk->enable_reg, sizeof(*other_reg));
 147
 148        /*
 149         * Convert CM_ICLKEN* <-> CM_FCLKEN*.  This conversion assumes
 150         * it's just a matter of XORing the bits.
 151         */
 152        other_reg->offset ^= (CM_FCLKEN ^ CM_ICLKEN);
 153
 154        *other_bit = clk->enable_bit;
 155}
 156
 157/**
 158 * omap2_clk_dflt_find_idlest - find CM_IDLEST reg va, bit shift for @clk
 159 * @clk: struct clk * to find IDLEST info for
 160 * @idlest_reg: void __iomem ** to return the CM_IDLEST va in
 161 * @idlest_bit: u8 * to return the CM_IDLEST bit shift in
 162 * @idlest_val: u8 * to return the idle status indicator
 163 *
 164 * Return the CM_IDLEST register address and bit shift corresponding
 165 * to the module that "owns" this clock.  This default code assumes
 166 * that the CM_IDLEST bit shift is the CM_*CLKEN bit shift, and that
 167 * the IDLEST register address ID corresponds to the CM_*CLKEN
 168 * register address ID (e.g., that CM_FCLKEN2 corresponds to
 169 * CM_IDLEST2).  This is not true for all modules.  No return value.
 170 */
 171void omap2_clk_dflt_find_idlest(struct clk_hw_omap *clk,
 172                                struct clk_omap_reg *idlest_reg, u8 *idlest_bit,
 173                                u8 *idlest_val)
 174{
 175        memcpy(idlest_reg, &clk->enable_reg, sizeof(*idlest_reg));
 176
 177        idlest_reg->offset &= ~0xf0;
 178        idlest_reg->offset |= 0x20;
 179
 180        *idlest_bit = clk->enable_bit;
 181
 182        /*
 183         * 24xx uses 0 to indicate not ready, and 1 to indicate ready.
 184         * 34xx reverses this, just to keep us on our toes
 185         * AM35xx uses both, depending on the module.
 186         */
 187        *idlest_val = ti_clk_get_features()->cm_idlest_val;
 188}
 189
 190/**
 191 * omap2_dflt_clk_enable - enable a clock in the hardware
 192 * @hw: struct clk_hw * of the clock to enable
 193 *
 194 * Enable the clock @hw in the hardware.  We first call into the OMAP
 195 * clockdomain code to "enable" the corresponding clockdomain if this
 196 * is the first enabled user of the clockdomain.  Then program the
 197 * hardware to enable the clock.  Then wait for the IP block that uses
 198 * this clock to leave idle (if applicable).  Returns the error value
 199 * from clkdm_clk_enable() if it terminated with an error, or -EINVAL
 200 * if @hw has a null clock enable_reg, or zero upon success.
 201 */
 202int omap2_dflt_clk_enable(struct clk_hw *hw)
 203{
 204        struct clk_hw_omap *clk;
 205        u32 v;
 206        int ret = 0;
 207        bool clkdm_control;
 208
 209        if (ti_clk_get_features()->flags & TI_CLK_DISABLE_CLKDM_CONTROL)
 210                clkdm_control = false;
 211        else
 212                clkdm_control = true;
 213
 214        clk = to_clk_hw_omap(hw);
 215
 216        if (clkdm_control && clk->clkdm) {
 217                ret = ti_clk_ll_ops->clkdm_clk_enable(clk->clkdm, hw->clk);
 218                if (ret) {
 219                        WARN(1,
 220                             "%s: could not enable %s's clockdomain %s: %d\n",
 221                             __func__, clk_hw_get_name(hw),
 222                             clk->clkdm_name, ret);
 223                        return ret;
 224                }
 225        }
 226
 227        /* FIXME should not have INVERT_ENABLE bit here */
 228        v = ti_clk_ll_ops->clk_readl(&clk->enable_reg);
 229        if (clk->flags & INVERT_ENABLE)
 230                v &= ~(1 << clk->enable_bit);
 231        else
 232                v |= (1 << clk->enable_bit);
 233        ti_clk_ll_ops->clk_writel(v, &clk->enable_reg);
 234        v = ti_clk_ll_ops->clk_readl(&clk->enable_reg); /* OCP barrier */
 235
 236        if (clk->ops && clk->ops->find_idlest)
 237                _omap2_module_wait_ready(clk);
 238
 239        return 0;
 240}
 241
 242/**
 243 * omap2_dflt_clk_disable - disable a clock in the hardware
 244 * @hw: struct clk_hw * of the clock to disable
 245 *
 246 * Disable the clock @hw in the hardware, and call into the OMAP
 247 * clockdomain code to "disable" the corresponding clockdomain if all
 248 * clocks/hwmods in that clockdomain are now disabled.  No return
 249 * value.
 250 */
 251void omap2_dflt_clk_disable(struct clk_hw *hw)
 252{
 253        struct clk_hw_omap *clk;
 254        u32 v;
 255
 256        clk = to_clk_hw_omap(hw);
 257
 258        v = ti_clk_ll_ops->clk_readl(&clk->enable_reg);
 259        if (clk->flags & INVERT_ENABLE)
 260                v |= (1 << clk->enable_bit);
 261        else
 262                v &= ~(1 << clk->enable_bit);
 263        ti_clk_ll_ops->clk_writel(v, &clk->enable_reg);
 264        /* No OCP barrier needed here since it is a disable operation */
 265
 266        if (!(ti_clk_get_features()->flags & TI_CLK_DISABLE_CLKDM_CONTROL) &&
 267            clk->clkdm)
 268                ti_clk_ll_ops->clkdm_clk_disable(clk->clkdm, hw->clk);
 269}
 270
 271/**
 272 * omap2_dflt_clk_is_enabled - is clock enabled in the hardware?
 273 * @hw: struct clk_hw * to check
 274 *
 275 * Return 1 if the clock represented by @hw is enabled in the
 276 * hardware, or 0 otherwise.  Intended for use in the struct
 277 * clk_ops.is_enabled function pointer.
 278 */
 279int omap2_dflt_clk_is_enabled(struct clk_hw *hw)
 280{
 281        struct clk_hw_omap *clk = to_clk_hw_omap(hw);
 282        u32 v;
 283
 284        v = ti_clk_ll_ops->clk_readl(&clk->enable_reg);
 285
 286        if (clk->flags & INVERT_ENABLE)
 287                v ^= BIT(clk->enable_bit);
 288
 289        v &= BIT(clk->enable_bit);
 290
 291        return v ? 1 : 0;
 292}
 293
 294const struct clk_hw_omap_ops clkhwops_wait = {
 295        .find_idlest    = omap2_clk_dflt_find_idlest,
 296        .find_companion = omap2_clk_dflt_find_companion,
 297};
 298