Sekhar Nori <[email protected]> writes:

> Currently, the spinlock in DaVinci clock framework is being
> used to:
>
> 1) Protect clock structure variables usecount and rate against
> concurrent modification.
>
> 2) Protect against simultaneous PSC enables/disables ie.
> serialize davinci_psc_config().
>
> 3) Serialize clk_set_rate():
>       i.      Prevent simultaneous setting of clock rates
>       ii.     Ensure clock list remains sane during rate
>               propagation (also in clk_set_parent).
>
> Remove the spinlock usage in clock framework by:
>
> 1) Making clock rate and usecount as atomic variables.
>
> 2) Making davinci_psc_config() protect itself instead of
> relying on serialization by caller.
>
> 3) (i) Allowing the clk->set_rate to serialize itself. There
> should be no need to serialize all clock rate settings.
> Currently the only user of rate setting is cpufreq driver on
> DA850. cpufreq naturally serializes the calls to set CPU rate.
> Also, there appears no need to lock IRQs during CPU rate
> transtitions. If required, IRQs can be locked in the actual
> set_rate function.
>
> 3) (ii) Use the mutex already in place for serialzing clock list
> manipulation for serializing clock rate propagation as well.
>
> Apart from the general benefit of reducing locking granurlarity,
> the main motivation behind this change is to enable usage of
> clock framework for off-chip clock synthesizers. One such
> synthesizer, CDCE949, is present on DM6467 EVM. Access to the
> synthesizer happens through I2C bus - accessing which can lead to
> CPU sleep. Having IRQs locked in clk_set_rate prevents the
> clk->set_rate function from sleeping.
>
> Signed-off-by: Sekhar Nori <[email protected]>
> ---
>  arch/arm/mach-davinci/board-dm646x-evm.c |    4 +-
>  arch/arm/mach-davinci/clock.c            |   74 ++++++++++++-----------------
>  arch/arm/mach-davinci/clock.h            |    4 +-
>  arch/arm/mach-davinci/da830.c            |    2 +-
>  arch/arm/mach-davinci/da850.c            |    4 +-
>  arch/arm/mach-davinci/dm355.c            |    4 +-
>  arch/arm/mach-davinci/dm365.c            |    4 +-
>  arch/arm/mach-davinci/dm644x.c           |    8 ++--
>  arch/arm/mach-davinci/dm646x.c           |    8 ++--
>  arch/arm/mach-davinci/psc.c              |    6 ++
>  10 files changed, 56 insertions(+), 62 deletions(-)
>
> diff --git a/arch/arm/mach-davinci/board-dm646x-evm.c 
> b/arch/arm/mach-davinci/board-dm646x-evm.c
> index 542bfdb..6ff3411 100644
> --- a/arch/arm/mach-davinci/board-dm646x-evm.c
> +++ b/arch/arm/mach-davinci/board-dm646x-evm.c
> @@ -722,9 +722,9 @@ static __init void davinci_dm646x_evm_irq_init(void)
>  void __init dm646x_board_setup_refclk(struct clk *clk)
>  {
>       if (machine_is_davinci_dm6467tevm())
> -             clk->rate = DM6467T_EVM_REF_FREQ;
> +             atomic_set(&clk->rate, DM6467T_EVM_REF_FREQ);
>       else
> -             clk->rate = DM646X_EVM_REF_FREQ;
> +             atomic_set(&clk->rate, DM646X_EVM_REF_FREQ);
>  }
>  
>  MACHINE_START(DAVINCI_DM6467_EVM, "DaVinci DM646x EVM")
> diff --git a/arch/arm/mach-davinci/clock.c b/arch/arm/mach-davinci/clock.c
> index baece65..df884c8 100644
> --- a/arch/arm/mach-davinci/clock.c
> +++ b/arch/arm/mach-davinci/clock.c
> @@ -28,7 +28,6 @@
>  
>  static LIST_HEAD(clocks);
>  static DEFINE_MUTEX(clocks_mutex);
> -static DEFINE_SPINLOCK(clockfw_lock);
>  
>  static unsigned psc_domain(struct clk *clk)
>  {
> @@ -41,15 +40,16 @@ static void __clk_enable(struct clk *clk)
>  {
>       if (clk->parent)
>               __clk_enable(clk->parent);
> -     if (clk->usecount++ == 0 && (clk->flags & CLK_PSC))
> +     if (atomic_read(&clk->usecount) == 0 && (clk->flags & CLK_PSC))
>               davinci_psc_config(psc_domain(clk), clk->gpsc, clk->lpsc, 1);
> +     atomic_inc(&clk->usecount);
>  }
>  
>  static void __clk_disable(struct clk *clk)
>  {
> -     if (WARN_ON(clk->usecount == 0))
> +     if (WARN_ON(atomic_read(&clk->usecount) == 0))
>               return;
> -     if (--clk->usecount == 0 && !(clk->flags & CLK_PLL))
> +     if (atomic_dec_and_test(&clk->usecount) && !(clk->flags & CLK_PLL))
>               davinci_psc_config(psc_domain(clk), clk->gpsc, clk->lpsc, 0);
>       if (clk->parent)
>               __clk_disable(clk->parent);
> @@ -57,14 +57,10 @@ static void __clk_disable(struct clk *clk)
>  
>  int clk_enable(struct clk *clk)
>  {
> -     unsigned long flags;
> -
>       if (clk == NULL || IS_ERR(clk))
>               return -EINVAL;
>  
> -     spin_lock_irqsave(&clockfw_lock, flags);
>       __clk_enable(clk);
> -     spin_unlock_irqrestore(&clockfw_lock, flags);
>  
>       return 0;
>  }
> @@ -72,14 +68,10 @@ EXPORT_SYMBOL(clk_enable);
>  
>  void clk_disable(struct clk *clk)
>  {
> -     unsigned long flags;
> -
>       if (clk == NULL || IS_ERR(clk))
>               return;
>  
> -     spin_lock_irqsave(&clockfw_lock, flags);
>       __clk_disable(clk);
> -     spin_unlock_irqrestore(&clockfw_lock, flags);
>  }
>  EXPORT_SYMBOL(clk_disable);
>  
> @@ -88,7 +80,7 @@ unsigned long clk_get_rate(struct clk *clk)
>       if (clk == NULL || IS_ERR(clk))
>               return -EINVAL;
>  
> -     return clk->rate;
> +     return atomic_read(&clk->rate);
>  }
>  EXPORT_SYMBOL(clk_get_rate);
>  
> @@ -100,7 +92,7 @@ long clk_round_rate(struct clk *clk, unsigned long rate)
>       if (clk->round_rate)
>               return clk->round_rate(clk, rate);
>  
> -     return clk->rate;
> +     return atomic_read(&clk->rate);
>  }
>  EXPORT_SYMBOL(clk_round_rate);
>  
> @@ -111,28 +103,27 @@ static void propagate_rate(struct clk *root)
>  
>       list_for_each_entry(clk, &root->children, childnode) {
>               if (clk->recalc)
> -                     clk->rate = clk->recalc(clk);
> +                     atomic_set(&clk->rate, clk->recalc(clk));
>               propagate_rate(clk);
>       }
>  }
>  
>  int clk_set_rate(struct clk *clk, unsigned long rate)
>  {
> -     unsigned long flags;
>       int ret = -EINVAL;
>  
>       if (clk == NULL || IS_ERR(clk))
>               return ret;
>  
> -     spin_lock_irqsave(&clockfw_lock, flags);
>       if (clk->set_rate)
>               ret = clk->set_rate(clk, rate);
>       if (ret == 0) {
>               if (clk->recalc)
> -                     clk->rate = clk->recalc(clk);
> +                     atomic_set(&clk->rate, clk->recalc(clk));
> +             mutex_lock(&clocks_mutex);
>               propagate_rate(clk);
> +             mutex_unlock(&clocks_mutex);
>       }
> -     spin_unlock_irqrestore(&clockfw_lock, flags);
>  
>       return ret;
>  }
> @@ -140,26 +131,22 @@ EXPORT_SYMBOL(clk_set_rate);
>  
>  int clk_set_parent(struct clk *clk, struct clk *parent)
>  {
> -     unsigned long flags;
> -
>       if (clk == NULL || IS_ERR(clk))
>               return -EINVAL;
>  
>       /* Cannot change parent on enabled clock */
> -     if (WARN_ON(clk->usecount))
> +     if (WARN_ON(atomic_read(&clk->usecount)))
>               return -EINVAL;
>  
>       mutex_lock(&clocks_mutex);
>       clk->parent = parent;
>       list_del_init(&clk->childnode);
>       list_add(&clk->childnode, &clk->parent->children);
> -     mutex_unlock(&clocks_mutex);
>  
> -     spin_lock_irqsave(&clockfw_lock, flags);
>       if (clk->recalc)
> -             clk->rate = clk->recalc(clk);
> +             atomic_set(&clk->rate, clk->recalc(clk));
>       propagate_rate(clk);
> -     spin_unlock_irqrestore(&clockfw_lock, flags);
> +     mutex_unlock(&clocks_mutex);
>  
>       return 0;
>  }
> @@ -170,7 +157,7 @@ int clk_register(struct clk *clk)
>       if (clk == NULL || IS_ERR(clk))
>               return -EINVAL;
>  
> -     if (WARN(clk->parent && !clk->parent->rate,
> +     if (WARN(clk->parent && !atomic_read(&clk->parent->rate),
>                       "CLK: %s parent %s has no rate!\n",
>                       clk->name, clk->parent->name))
>               return -EINVAL;
> @@ -184,16 +171,16 @@ int clk_register(struct clk *clk)
>       mutex_unlock(&clocks_mutex);
>  
>       /* If rate is already set, use it */
> -     if (clk->rate)
> +     if (atomic_read(&clk->rate))
>               return 0;
>  
>       /* Else, see if there is a way to calculate it */
>       if (clk->recalc)
> -             clk->rate = clk->recalc(clk);
> +             atomic_set(&clk->rate, clk->recalc(clk));
>  
>       /* Otherwise, default to parent rate */
>       else if (clk->parent)
> -             clk->rate = clk->parent->rate;
> +             atomic_set(&clk->rate, atomic_read(&clk->parent->rate));
>  
>       return 0;
>  }
> @@ -219,9 +206,9 @@ static int __init clk_disable_unused(void)
>  {
>       struct clk *ck;
>  
> -     spin_lock_irq(&clockfw_lock);
> +     mutex_lock(&clocks_mutex);
>       list_for_each_entry(ck, &clocks, node) {
> -             if (ck->usecount > 0)
> +             if (atomic_read(&ck->usecount) > 0)
>                       continue;
>               if (!(ck->flags & CLK_PSC))
>                       continue;
> @@ -233,7 +220,7 @@ static int __init clk_disable_unused(void)
>               pr_info("Clocks: disable unused %s\n", ck->name);
>               davinci_psc_config(psc_domain(ck), ck->gpsc, ck->lpsc, 0);
>       }
> -     spin_unlock_irq(&clockfw_lock);
> +     mutex_unlock(&clocks_mutex);
>  
>       return 0;
>  }
> @@ -244,7 +231,7 @@ static unsigned long clk_sysclk_recalc(struct clk *clk)
>  {
>       u32 v, plldiv;
>       struct pll_data *pll;
> -     unsigned long rate = clk->rate;
> +     unsigned long rate = atomic_read(&clk->rate);
>  
>       /* If this is the PLL base clock, no more calculations needed */
>       if (clk->pll_data)
> @@ -253,7 +240,7 @@ static unsigned long clk_sysclk_recalc(struct clk *clk)
>       if (WARN_ON(!clk->parent))
>               return rate;
>  
> -     rate = clk->parent->rate;
> +     rate = atomic_read(&clk->parent->rate);
>  
>       /* Otherwise, the parent must be a PLL */
>       if (WARN_ON(!clk->parent->pll_data))
> @@ -281,9 +268,9 @@ static unsigned long clk_sysclk_recalc(struct clk *clk)
>  static unsigned long clk_leafclk_recalc(struct clk *clk)
>  {
>       if (WARN_ON(!clk->parent))
> -             return clk->rate;
> +             return atomic_read(&clk->rate);
>  
> -     return clk->parent->rate;
> +     return atomic_read(&clk->parent->rate);
>  }
>  
>  static unsigned long clk_pllclk_recalc(struct clk *clk)
> @@ -291,11 +278,11 @@ static unsigned long clk_pllclk_recalc(struct clk *clk)
>       u32 ctrl, mult = 1, prediv = 1, postdiv = 1;
>       u8 bypass;
>       struct pll_data *pll = clk->pll_data;
> -     unsigned long rate = clk->rate;
> +     unsigned long rate = atomic_read(&clk->rate);
>  
>       pll->base = IO_ADDRESS(pll->phys_base);
>       ctrl = __raw_readl(pll->base + PLLCTL);
> -     rate = pll->input_rate = clk->parent->rate;
> +     rate = pll->input_rate = atomic_read(&clk->parent->rate);
>  
>       if (ctrl & PLLCTL_PLLEN) {
>               bypass = 0;
> @@ -333,8 +320,8 @@ static unsigned long clk_pllclk_recalc(struct clk *clk)
>               rate /= postdiv;
>       }
>  
> -     pr_debug("PLL%d: input = %lu MHz [ ",
> -              pll->num, clk->parent->rate / 1000000);
> +     pr_debug("PLL%d: input = %u MHz [ ",
> +              pll->num, atomic_read(&clk->parent->rate) / 1000000);
>       if (bypass)
>               pr_debug("bypass ");
>       if (prediv > 1)
> @@ -452,7 +439,7 @@ int __init davinci_clk_init(struct davinci_clk *clocks)
>               }
>  
>               if (clk->recalc)
> -                     clk->rate = clk->recalc(clk);
> +                     atomic_set(&clk->rate, clk->recalc(clk));
>  
>               if (clk->lpsc)
>                       clk->flags |= CLK_PSC;
> @@ -514,7 +501,8 @@ dump_clock(struct seq_file *s, unsigned nest, struct clk 
> *parent)
>                       min(i, (unsigned)(sizeof(buf) - 1 - nest)));
>  
>       seq_printf(s, "%s users=%2d %-3s %9ld Hz\n",
> -                buf, parent->usecount, state, clk_get_rate(parent));
> +                     buf, atomic_read(&parent->usecount), state,
> +                     clk_get_rate(parent));
>       /* REVISIT show device associations too */
>  
>       /* cost is now small, but not linear... */
> diff --git a/arch/arm/mach-davinci/clock.h b/arch/arm/mach-davinci/clock.h
> index c92d77a..796a568 100644
> --- a/arch/arm/mach-davinci/clock.h
> +++ b/arch/arm/mach-davinci/clock.h
> @@ -67,8 +67,8 @@ struct clk {
>       struct list_head        node;
>       struct module           *owner;
>       const char              *name;
> -     unsigned long           rate;
> -     u8                      usecount;
> +     atomic_t                rate;
> +     atomic_t                usecount;
>       u8                      lpsc;
>       u8                      gpsc;
>       u32                     flags;
> diff --git a/arch/arm/mach-davinci/da830.c b/arch/arm/mach-davinci/da830.c
> index b22b5cf..d1961d2 100644
> --- a/arch/arm/mach-davinci/da830.c
> +++ b/arch/arm/mach-davinci/da830.c
> @@ -43,7 +43,7 @@ static struct pll_data pll0_data = {
>  
>  static struct clk ref_clk = {
>       .name           = "ref_clk",
> -     .rate           = DA830_REF_FREQ,
> +     .rate           = ATOMIC_INIT(DA830_REF_FREQ),
>  };
>  
>  static struct clk pll0_clk = {
> diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c
> index 717806c..62f8c22 100644
> --- a/arch/arm/mach-davinci/da850.c
> +++ b/arch/arm/mach-davinci/da850.c
> @@ -54,7 +54,7 @@ static struct pll_data pll0_data = {
>  
>  static struct clk ref_clk = {
>       .name           = "ref_clk",
> -     .rate           = DA850_REF_FREQ,
> +     .rate           = ATOMIC_INIT(DA850_REF_FREQ),
>  };
>  
>  static struct clk pll0_clk = {
> @@ -1024,7 +1024,7 @@ static int da850_set_pll0rate(struct clk *clk, unsigned 
> long armrate)
>  
>  static int da850_round_armrate(struct clk *clk, unsigned long rate)
>  {
> -     return clk->rate;
> +     return atomic_read(&clk->rate);
>  }
>  #endif
>  
> diff --git a/arch/arm/mach-davinci/dm355.c b/arch/arm/mach-davinci/dm355.c
> index dedf4d4..2244e8c 100644
> --- a/arch/arm/mach-davinci/dm355.c
> +++ b/arch/arm/mach-davinci/dm355.c
> @@ -55,7 +55,7 @@ static struct pll_data pll2_data = {
>  static struct clk ref_clk = {
>       .name = "ref_clk",
>       /* FIXME -- crystal rate is board-specific */
> -     .rate = DM355_REF_FREQ,
> +     .rate = ATOMIC_INIT(DM355_REF_FREQ),
>  };
>  
>  static struct clk pll1_clk = {
> @@ -314,7 +314,7 @@ static struct clk timer2_clk = {
>       .name = "timer2",
>       .parent = &pll1_aux_clk,
>       .lpsc = DAVINCI_LPSC_TIMER2,
> -     .usecount = 1,              /* REVISIT: why cant' this be disabled? */
> +     .usecount = ATOMIC_INIT(1), /* REVISIT: why cant' this be disabled? */
>  };
>  
>  static struct clk timer3_clk = {
> diff --git a/arch/arm/mach-davinci/dm365.c b/arch/arm/mach-davinci/dm365.c
> index 2ec619e..cc3bae4 100644
> --- a/arch/arm/mach-davinci/dm365.c
> +++ b/arch/arm/mach-davinci/dm365.c
> @@ -52,7 +52,7 @@ static struct pll_data pll2_data = {
>  
>  static struct clk ref_clk = {
>       .name           = "ref_clk",
> -     .rate           = DM365_REF_FREQ,
> +     .rate           = ATOMIC_INIT(DM365_REF_FREQ),
>  };
>  
>  static struct clk pll1_clk = {
> @@ -358,7 +358,7 @@ static struct clk timer2_clk = {
>       .name           = "timer2",
>       .parent         = &pll1_aux_clk,
>       .lpsc           = DAVINCI_LPSC_TIMER2,
> -     .usecount       = 1,
> +     .usecount       = ATOMIC_INIT(1),
>  };
>  
>  static struct clk timer3_clk = {
> diff --git a/arch/arm/mach-davinci/dm644x.c b/arch/arm/mach-davinci/dm644x.c
> index 2cd0081..e65e29e 100644
> --- a/arch/arm/mach-davinci/dm644x.c
> +++ b/arch/arm/mach-davinci/dm644x.c
> @@ -47,7 +47,7 @@ static struct pll_data pll2_data = {
>  
>  static struct clk ref_clk = {
>       .name = "ref_clk",
> -     .rate = DM644X_REF_FREQ,
> +     .rate = ATOMIC_INIT(DM644X_REF_FREQ),
>  };
>  
>  static struct clk pll1_clk = {
> @@ -131,7 +131,7 @@ static struct clk dsp_clk = {
>       .parent = &pll1_sysclk1,
>       .lpsc = DAVINCI_LPSC_GEM,
>       .flags = PSC_DSP,
> -     .usecount = 1,                  /* REVISIT how to disable? */
> +     .usecount = ATOMIC_INIT(1),     /* REVISIT how to disable? */
>  };
>  
>  static struct clk arm_clk = {
> @@ -146,7 +146,7 @@ static struct clk vicp_clk = {
>       .parent = &pll1_sysclk2,
>       .lpsc = DAVINCI_LPSC_IMCOP,
>       .flags = PSC_DSP,
> -     .usecount = 1,                  /* REVISIT how to disable? */
> +     .usecount = ATOMIC_INIT(1),     /* REVISIT how to disable? */
>  };
>  
>  static struct clk vpss_master_clk = {
> @@ -274,7 +274,7 @@ static struct clk timer2_clk = {
>       .name = "timer2",
>       .parent = &pll1_aux_clk,
>       .lpsc = DAVINCI_LPSC_TIMER2,
> -     .usecount = 1,              /* REVISIT: why cant' this be disabled? */
> +     .usecount = ATOMIC_INIT(1), /* REVISIT: why cant' this be disabled? */
>  };
>  
>  struct davinci_clk dm644x_clks[] = {
> diff --git a/arch/arm/mach-davinci/dm646x.c b/arch/arm/mach-davinci/dm646x.c
> index 515d3ed..6f80616 100644
> --- a/arch/arm/mach-davinci/dm646x.c
> +++ b/arch/arm/mach-davinci/dm646x.c
> @@ -60,7 +60,7 @@ static struct clk ref_clk = {
>  
>  static struct clk aux_clkin = {
>       .name = "aux_clkin",
> -     .rate = DM646X_AUX_FREQ,
> +     .rate = ATOMIC_INIT(DM646X_AUX_FREQ),
>  };
>  
>  static struct clk pll1_clk = {
> @@ -158,7 +158,7 @@ static struct clk dsp_clk = {
>       .parent = &pll1_sysclk1,
>       .lpsc = DM646X_LPSC_C64X_CPU,
>       .flags = PSC_DSP,
> -     .usecount = 1,                  /* REVISIT how to disable? */
> +     .usecount = ATOMIC_INIT(1),             /* REVISIT how to disable? */
>  };
>  
>  static struct clk arm_clk = {
> @@ -262,14 +262,14 @@ static struct clk pwm0_clk = {
>       .name = "pwm0",
>       .parent = &pll1_sysclk3,
>       .lpsc = DM646X_LPSC_PWM0,
> -     .usecount = 1,            /* REVIST: disabling hangs system */
> +     .usecount = ATOMIC_INIT(1),     /* REVIST: disabling hangs system */
>  };
>  
>  static struct clk pwm1_clk = {
>       .name = "pwm1",
>       .parent = &pll1_sysclk3,
>       .lpsc = DM646X_LPSC_PWM1,
> -     .usecount = 1,            /* REVIST: disabling hangs system */
> +     .usecount = ATOMIC_INIT(1),     /* REVIST: disabling hangs system */
>  };
>  
>  static struct clk timer0_clk = {
> diff --git a/arch/arm/mach-davinci/psc.c b/arch/arm/mach-davinci/psc.c
> index 04a3cb7..a9a4d08 100644
> --- a/arch/arm/mach-davinci/psc.c
> +++ b/arch/arm/mach-davinci/psc.c
> @@ -21,6 +21,7 @@
>  #include <linux/kernel.h>
>  #include <linux/init.h>
>  #include <linux/io.h>
> +#include <linux/spinlock.h>
>  
>  #include <mach/cputype.h>
>  #include <mach/psc.h>
> @@ -64,6 +65,9 @@ void davinci_psc_config(unsigned int domain, unsigned int 
> ctlr,
>       void __iomem *psc_base;
>       struct davinci_soc_info *soc_info = &davinci_soc_info;
>       u32 next_state = enable ? 0x3 : 0x2; /* 0x3 enables, 0x2 disables */
> +     /* Protect against simultaneous enable/disable of PSCs */
> +     DEFINE_SPINLOCK(lock);
> +     unsigned long flags;
>  
>       if (!soc_info->psc_bases || (ctlr >= soc_info->psc_bases_num)) {
>               pr_warning("PSC: Bad psc data: 0x%x[%d]\n",
> @@ -73,6 +77,7 @@ void davinci_psc_config(unsigned int domain, unsigned int 
> ctlr,
>  
>       psc_base = soc_info->psc_bases[ctlr];
>  
> +     spin_lock_irqsave(&lock, flags);
>       mdctl = __raw_readl(psc_base + MDCTL + 4 * id);
>       mdctl &= ~MDSTAT_STATE_MASK;
>       mdctl |= next_state;
> @@ -111,4 +116,5 @@ void davinci_psc_config(unsigned int domain, unsigned int 
> ctlr,
>       do {
>               mdstat = __raw_readl(psc_base + MDSTAT + 4 * id);
>       } while (!((mdstat & MDSTAT_STATE_MASK) == next_state));
> +     spin_unlock_irqrestore(&lock, flags);
>  }
> -- 
> 1.6.2.4
>
> _______________________________________________
> Davinci-linux-open-source mailing list
> [email protected]
> http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source

Sekhar Nori <[email protected]> writes:

> This patch modifies clock dump to take care of
> clock tress rooted at multiple oscillators.
> Current code assumes the entire tree is rooted
> on a single oscillator. When using off-chip
> clock synthesizers, some of the clocks can
> be obtained from a different on-board oscillator.
>
> Signed-off-by: Sekhar Nori <[email protected]>
> ---
>  arch/arm/mach-davinci/clock.c |   11 +++++++----
>  1 files changed, 7 insertions(+), 4 deletions(-)
>
> diff --git a/arch/arm/mach-davinci/clock.c b/arch/arm/mach-davinci/clock.c
> index df884c8..ba0b68f 100644
> --- a/arch/arm/mach-davinci/clock.c
> +++ b/arch/arm/mach-davinci/clock.c
> @@ -513,12 +513,15 @@ dump_clock(struct seq_file *s, unsigned nest, struct 
> clk *parent)
>  
>  static int davinci_ck_show(struct seq_file *m, void *v)
>  {
> -     /* Show clock tree; we know the main oscillator is first.
> -      * We trust nonzero usecounts equate to PSC enables...
> +     struct clk *clk;
> +
> +     /*
> +      * Show clock tree; We trust nonzero usecounts equate to PSC enables...
>        */
>       mutex_lock(&clocks_mutex);
> -     if (!list_empty(&clocks))
> -             dump_clock(m, 0, list_first_entry(&clocks, struct clk, node));
> +     list_for_each_entry(clk, &clocks, node)
> +             if (!clk->parent)
> +                     dump_clock(m, 0, clk);
>       mutex_unlock(&clocks_mutex);
>  
>       return 0;
> -- 
> 1.6.2.4
>
> _______________________________________________
> Davinci-linux-open-source mailing list
> [email protected]
> http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source

Sekhar Nori <[email protected]> writes:

> Move /proc/davinci_clocks to /sys/kernel/debug/davinci_clocks
> (debugfs).
>
> debugfs is more suited for this since the clock dump is
> debug information.
>
> Signed-off-by: Sekhar Nori <[email protected]>
> ---
>  arch/arm/mach-davinci/clock.c |   42 ++++++++++------------------------------
>  1 files changed, 11 insertions(+), 31 deletions(-)
>
> diff --git a/arch/arm/mach-davinci/clock.c b/arch/arm/mach-davinci/clock.c
> index ba0b68f..c9ea503 100644
> --- a/arch/arm/mach-davinci/clock.c
> +++ b/arch/arm/mach-davinci/clock.c
> @@ -455,24 +455,10 @@ int __init davinci_clk_init(struct davinci_clk *clocks)
>       return 0;
>  }
>  
> -#ifdef CONFIG_PROC_FS
> -#include <linux/proc_fs.h>
> -#include <linux/seq_file.h>
> -
> -static void *davinci_ck_start(struct seq_file *m, loff_t *pos)
> -{
> -     return *pos < 1 ? (void *)1 : NULL;
> -}
> -
> -static void *davinci_ck_next(struct seq_file *m, void *v, loff_t *pos)
> -{
> -     ++*pos;
> -     return NULL;
> -}
> +#ifdef CONFIG_DEBUG_FS
>  
> -static void davinci_ck_stop(struct seq_file *m, void *v)
> -{
> -}
> +#include <linux/debugfs.h>
> +#include <linux/seq_file.h>
>  
>  #define CLKNAME_MAX  10              /* longest clock name */
>  #define NEST_DELTA   2
> @@ -527,30 +513,24 @@ static int davinci_ck_show(struct seq_file *m, void *v)
>       return 0;
>  }
>  
> -static const struct seq_operations davinci_ck_op = {
> -     .start  = davinci_ck_start,
> -     .next   = davinci_ck_next,
> -     .stop   = davinci_ck_stop,
> -     .show   = davinci_ck_show
> -};
> -
>  static int davinci_ck_open(struct inode *inode, struct file *file)
>  {
> -     return seq_open(file, &davinci_ck_op);
> +     return single_open(file, davinci_ck_show, NULL);
>  }
>  
> -static const struct file_operations proc_davinci_ck_operations = {
> +static const struct file_operations davinci_ck_operations = {
>       .open           = davinci_ck_open,
>       .read           = seq_read,
>       .llseek         = seq_lseek,
> -     .release        = seq_release,
> +     .release        = single_release,
>  };
>  
> -static int __init davinci_ck_proc_init(void)
> +static int __init davinci_clk_debugfs_init(void)
>  {
> -     proc_create("davinci_clocks", 0, NULL, &proc_davinci_ck_operations);
> +     debugfs_create_file("davinci_clocks", S_IFREG | S_IRUGO, NULL, NULL,
> +                                             &davinci_ck_operations);
>       return 0;
>  
>  }
> -__initcall(davinci_ck_proc_init);
> -#endif /* CONFIG_DEBUG_PROC_FS */
> +device_initcall(davinci_clk_debugfs_init);
> +#endif /* CONFIG_DEBUG_FS */
> -- 
> 1.6.2.4
>
> _______________________________________________
> Davinci-linux-open-source mailing list
> [email protected]
> http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source

Sekhar Nori <[email protected]> writes:

> From: Nageswari Srinivasan <[email protected]>
>
> This patch adds support for TI's CDCE949 - a clock
> synthesizer with 4 PLLs and 9 outputs.
>
> It is used on DM6467 EVM. On the EVM, it generates
> clocks required for VPIF, TSIF and Audio modules.
>
> This patch adds it as part of the DaVinci clock framework.
>
> Testing:
> The various frequency outputs on Y1 have been tested using
> a out-of-tree VPIF video driver supporting HD video.
> The register values for Y5 frequency outputs have been
> derived from TSIF driver sources in MontaVista LSP kernel,
> but actual output has not been tested for lack of TSIF
> driver which actually works on the latest kernel.
>
> Signed-off-by: Nageswari Srinivasan <[email protected]>
> Signed-off-by: Sekhar Nori <[email protected]>
> ---
>  arch/arm/mach-davinci/cdce949.c              |  289 
> ++++++++++++++++++++++++++
>  arch/arm/mach-davinci/include/mach/cdce949.h |   19 ++
>  2 files changed, 308 insertions(+), 0 deletions(-)
>  create mode 100644 arch/arm/mach-davinci/cdce949.c
>  create mode 100644 arch/arm/mach-davinci/include/mach/cdce949.h
>
> diff --git a/arch/arm/mach-davinci/cdce949.c b/arch/arm/mach-davinci/cdce949.c
> new file mode 100644
> index 0000000..5a08283
> --- /dev/null
> +++ b/arch/arm/mach-davinci/cdce949.c
> @@ -0,0 +1,289 @@
> +/*
> + * TI CDCE949 clock synthesizer driver
> + *
> + * Note: This implementation assumes an input of 27MHz to the CDCE.
> + * This is by no means constrained by CDCE hardware although the datasheet
> + * does use this as an example for all illustrations and more importantly:
> + * that is the crystal input on boards it is currently used on.
> + *
> + * Copyright (C) 2009 Texas Instruments Incorporated. http://www.ti.com/
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + */
> +#include <linux/kernel.h>
> +#include <linux/clk.h>
> +#include <linux/platform_device.h>
> +#include <linux/i2c.h>
> +
> +#include <mach/clock.h>
> +
> +#include "clock.h"
> +
> +static struct i2c_client *cdce_i2c_client;
> +
> +/* CDCE register descriptor */
> +struct cdce_reg {
> +     u8      addr;
> +     u8      val;
> +};
> +
> +/* Per-Output (Y1, Y2 etc.) frequency descriptor */
> +struct cdce_freq {
> +     /* Frequency in KHz */
> +     unsigned long frequency;
> +     /*
> +      * List of registers to program to obtain a particular frequency.
> +      * 0x0 in register address and value is the end of list marker.
> +      */
> +     struct cdce_reg *reglist;
> +};
> +
> +#define CDCE_FREQ_TABLE_ENTRY(line, out)             \
> +{                                                    \
> +     .reglist        = cdce_y ##line## _ ##out,              \
> +     .frequency      = out,                          \
> +}
> +
> +/* List of CDCE outputs  */
> +struct cdce_output {
> +     /* List of frequencies on this output */
> +     struct cdce_freq *freq_table;
> +     /* Number of possible frequencies */
> +     int size;
> +};
> +
> +/*
> + * Finding out the values to program into CDCE949 registers for a particular
> + * frequency output is not a simple calculation. Have a look at the datasheet
> + * for the details. There is desktop software available to help users with
> + * the calculations. Here, we just depend on the output of that software
> + * (or hand calculations) instead trying to runtime calculate the register
> + * values and inflicting misery on ourselves.
> + */
> +static struct cdce_reg cdce_y1_148500[] = {
> +     { 0x13, 0x00 },
> +     /* program PLL1_0 multiplier */
> +     { 0x18, 0xaf },
> +     { 0x19, 0x50 },
> +     { 0x1a, 0x02 },
> +     { 0x1b, 0xc9 },
> +     /* program PLL1_11 multiplier */
> +     { 0x1c, 0x00 },
> +     { 0x1d, 0x40 },
> +     { 0x1e, 0x02 },
> +     { 0x1f, 0xc9 },
> +     /* output state selection */
> +     { 0x15, 0x00 },
> +     { 0x14, 0xef },
> +     /* switch MUX to PLL1 output */
> +     { 0x14, 0x6f },
> +     { 0x16, 0x06 },
> +     /* set P2DIV divider, P3DIV and input crystal */
> +     { 0x17, 0x06 },
> +     { 0x01, 0x00 },
> +     { 0x05, 0x48 },
> +     { 0x02, 0x80 },
> +     /* enable and disable PLL */
> +     { 0x02, 0xbc },
> +     { 0x03, 0x01 },
> +     { },
> +};
> +
> +static struct cdce_reg cdce_y1_74250[] = {
> +     { 0x13, 0x00 },
> +     { 0x18, 0xaf },
> +     { 0x19, 0x50 },
> +     { 0x1a, 0x02 },
> +     { 0x1b, 0xc9 },
> +     { 0x1c, 0x00 },
> +     { 0x1d, 0x40 },
> +     { 0x1e, 0x02 },
> +     { 0x1f, 0xc9 },
> +     /* output state selection */
> +     { 0x15, 0x00 },
> +     { 0x14, 0xef },
> +     /* switch MUX to PLL1 output */
> +     { 0x14, 0x6f },
> +     { 0x16, 0x06 },
> +     /* set P2DIV divider, P3DIV and input crystal */
> +     { 0x17, 0x06 },
> +     { 0x01, 0x00 },
> +     { 0x05, 0x48 },
> +     { 0x02, 0x80 },
> +     /* enable and disable PLL */
> +     { 0x02, 0xbc },
> +     { 0x03, 0x02 },
> +     { },
> +};
> +
> +static struct cdce_reg cdce_y1_27000[] = {
> +     { 0x13, 0x00 },
> +     { 0x18, 0x00 },
> +     { 0x19, 0x40 },
> +     { 0x1a, 0x02 },
> +     { 0x1b, 0x08 },
> +     { 0x1c, 0x00 },
> +     { 0x1d, 0x40 },
> +     { 0x1e, 0x02 },
> +     { 0x1f, 0x08 },
> +     { 0x15, 0x02 },
> +     { 0x14, 0xed },
> +     { 0x16, 0x01 },
> +     { 0x17, 0x01 },
> +     { 0x01, 0x00 },
> +     { 0x05, 0x50 },
> +     { 0x02, 0xb4 },
> +     { 0x03, 0x01 },
> +     { },
> +};
> +
> +static struct cdce_freq cdce_y1_freqs[] = {
> +     CDCE_FREQ_TABLE_ENTRY(1, 148500),
> +     CDCE_FREQ_TABLE_ENTRY(1, 74250),
> +     CDCE_FREQ_TABLE_ENTRY(1, 27000),
> +};
> +
> +static struct cdce_reg cdce_y5_13500[] = {
> +     { 0x27, 0x08 },
> +     { 0x28, 0x00 },
> +     { 0x29, 0x40 },
> +     { 0x2a, 0x02 },
> +     { 0x2b, 0x08 },
> +     { 0x24, 0x6f },
> +     { },
> +};
> +
> +static struct cdce_reg cdce_y5_16875[] = {
> +     { 0x27, 0x08 },
> +     { 0x28, 0x9f },
> +     { 0x29, 0xb0 },
> +     { 0x2a, 0x02 },
> +     { 0x2b, 0x89 },
> +     { 0x24, 0x6f },
> +     { },
> +};
> +
> +static struct cdce_reg cdce_y5_27000[] = {
> +     { 0x27, 0x04 },
> +     { 0x28, 0x00 },
> +     { 0x29, 0x40 },
> +     { 0x2a, 0x02 },
> +     { 0x2b, 0x08 },
> +     { 0x24, 0x6f },
> +     { },
> +};
> +static struct cdce_reg cdce_y5_54000[] = {
> +     { 0x27, 0x04 },
> +     { 0x28, 0xff },
> +     { 0x29, 0x80 },
> +     { 0x2a, 0x02 },
> +     { 0x2b, 0x07 },
> +     { 0x24, 0x6f },
> +     { },
> +};
> +
> +static struct cdce_reg cdce_y5_81000[] = {
> +     { 0x27, 0x02 },
> +     { 0x28, 0xbf },
> +     { 0x29, 0xa0 },
> +     { 0x2a, 0x03 },
> +     { 0x2b, 0x0a },
> +     { 0x24, 0x6f },
> +     { },
> +};
> +
> +static struct cdce_freq cdce_y5_freqs[] = {
> +     CDCE_FREQ_TABLE_ENTRY(5, 13500),
> +     CDCE_FREQ_TABLE_ENTRY(5, 16875),
> +     CDCE_FREQ_TABLE_ENTRY(5, 27000),
> +     CDCE_FREQ_TABLE_ENTRY(5, 54000),
> +     CDCE_FREQ_TABLE_ENTRY(5, 81000),
> +};
> +
> +
> +static struct cdce_output output_list[] = {
> +     [1]     = { cdce_y1_freqs, ARRAY_SIZE(cdce_y1_freqs) },
> +     [5]     = { cdce_y5_freqs, ARRAY_SIZE(cdce_y5_freqs) },
> +};
> +
> +int cdce_set_rate(struct clk *clk, unsigned long rate)
> +{
> +     int i, ret = 0;
> +     struct cdce_freq *freq_table = output_list[clk->lpsc].freq_table;
> +     struct cdce_reg  *regs = NULL;
> +
> +     if (!cdce_i2c_client)
> +             return -ENODEV;
> +
> +     if (!freq_table)
> +             return -EINVAL;
> +
> +     for (i = 0; i < output_list[clk->lpsc].size; i++) {
> +             if (freq_table[i].frequency == rate / 1000) {
> +                     regs = freq_table[i].reglist;
> +                     break;
> +             }
> +     }
> +
> +     if (!regs)
> +             return -EINVAL;
> +
> +     for (i = 0; regs[i].addr; i++) {
> +             ret = i2c_smbus_write_byte_data(cdce_i2c_client,
> +                                     regs[i].addr | 0x80, regs[i].val);
> +             if (ret)
> +                     return ret;
> +     }
> +
> +     atomic_set(&clk->rate, rate);
> +
> +     return 0;
> +}
> +
> +static int cdce_probe(struct i2c_client *client,
> +                                     const struct i2c_device_id *id)
> +{
> +     cdce_i2c_client = client;
> +     return 0;
> +}
> +
> +static int __devexit cdce_remove(struct i2c_client *client)
> +{
> +     cdce_i2c_client = NULL;
> +     return 0;
> +}
> +
> +static const struct i2c_device_id cdce_id[] = {
> +     {"cdce949", 0},
> +     {},
> +};
> +MODULE_DEVICE_TABLE(i2c, cdce_id);
> +
> +static struct i2c_driver cdce_driver = {
> +     .driver = {
> +             .owner  = THIS_MODULE,
> +             .name   = "cdce949",
> +     },
> +     .probe          = cdce_probe,
> +     .remove         = __devexit_p(cdce_remove),
> +     .id_table       = cdce_id,
> +};
> +
> +static int __init cdce_init(void)
> +{
> +     return i2c_add_driver(&cdce_driver);
> +}
> +subsys_initcall(cdce_init);
> +
> +static void __exit cdce_exit(void)
> +{
> +     i2c_del_driver(&cdce_driver);
> +}
> +module_exit(cdce_exit);
> +
> +MODULE_AUTHOR("Texas Instruments");
> +MODULE_DESCRIPTION("CDCE949 clock synthesizer driver");
> +MODULE_LICENSE("GPL v2");
> diff --git a/arch/arm/mach-davinci/include/mach/cdce949.h 
> b/arch/arm/mach-davinci/include/mach/cdce949.h
> new file mode 100644
> index 0000000..c73331f
> --- /dev/null
> +++ b/arch/arm/mach-davinci/include/mach/cdce949.h
> @@ -0,0 +1,19 @@
> +/*
> + * TI CDCE949 off-chip clock synthesizer support
> + *
> + * 2009 (C) Texas Instruments, Inc. http://www.ti.com/
> + *
> + * This file is licensed under the terms of the GNU General Public License
> + * version 2. This program is licensed "as is" without any warranty of any
> + * kind, whether express or implied.
> + */
> +#ifndef _MACH_DAVINCI_CDCE949_H
> +#define _MACH_DAVINCI_CDCE949_H
> +
> +#include <linux/clk.h>
> +
> +#include <mach/clock.h>
> +
> +int cdce_set_rate(struct clk *clk, unsigned long rate);
> +
> +#endif
> -- 
> 1.6.2.4
>
> _______________________________________________
> Davinci-linux-open-source mailing list
> [email protected]
> http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source

Sekhar Nori <[email protected]> writes:

> From: Nageswari Srinivasan <[email protected]>
>
> This patch adds the CDCE949 reference oscillator to
> the davinci clock list.
>
> On the DM6467T EVM, the CDCE949 is responsible for
> generating the pixel clock for display. On the DM6467
> EVM, this pixel clock was being obtained from an
> internal source. This is not possible on the DM6467T
> EVM because of the presence of a 33MHz oscillator.
>
> The TSIF module also requires the CDCE949 to generate
> the data clocks.
>
> The actual clock definitions will be added by patches
> adding support for DM6467T VPIF and TSIF. This patch
> mearly lays the foundation for that work.
>
> Signed-off-by: Nageswari Srinivasan <[email protected]>
> Signed-off-by: Sekhar Nori <[email protected]>
> ---
>  arch/arm/mach-davinci/Makefile           |    2 +-
>  arch/arm/mach-davinci/board-dm646x-evm.c |   32 
> ++++++++++++++++++++++++++++++
>  2 files changed, 33 insertions(+), 1 deletions(-)
>
> diff --git a/arch/arm/mach-davinci/Makefile b/arch/arm/mach-davinci/Makefile
> index eeb9230..7e806b0 100644
> --- a/arch/arm/mach-davinci/Makefile
> +++ b/arch/arm/mach-davinci/Makefile
> @@ -26,7 +26,7 @@ obj-$(CONFIG_MACH_SFFSDR)           += board-sffsdr.o
>  obj-$(CONFIG_MACH_NEUROS_OSD2)               += board-neuros-osd2.o
>  obj-$(CONFIG_MACH_DAVINCI_DM355_EVM) += board-dm355-evm.o
>  obj-$(CONFIG_MACH_DM355_LEOPARD)     += board-dm355-leopard.o
> -obj-$(CONFIG_MACH_DAVINCI_DM6467_EVM)        += board-dm646x-evm.o
> +obj-$(CONFIG_MACH_DAVINCI_DM6467_EVM)        += board-dm646x-evm.o cdce949.o
>  obj-$(CONFIG_MACH_DAVINCI_DM365_EVM) += board-dm365-evm.o
>  obj-$(CONFIG_MACH_DAVINCI_DA830_EVM) += board-da830-evm.o
>  obj-$(CONFIG_MACH_DAVINCI_DA850_EVM) += board-da850-evm.o
> diff --git a/arch/arm/mach-davinci/board-dm646x-evm.c 
> b/arch/arm/mach-davinci/board-dm646x-evm.c
> index 6ff3411..5d9283f 100644
> --- a/arch/arm/mach-davinci/board-dm646x-evm.c
> +++ b/arch/arm/mach-davinci/board-dm646x-evm.c
> @@ -40,6 +40,8 @@
>  #include <mach/serial.h>
>  #include <mach/i2c.h>
>  #include <mach/nand.h>
> +#include <mach/clock.h>
> +#include <mach/cdce949.h>
>  
>  #include "clock.h"
>  
> @@ -389,6 +391,9 @@ static struct i2c_board_info __initdata i2c_info[] =  {
>       {
>               I2C_BOARD_INFO("cpld_video", 0x3b),
>       },
> +     {
> +             I2C_BOARD_INFO("cdce949", 0x6c),
> +     },
>  };
>  
>  static struct davinci_i2c_platform_data i2c_pdata = {
> @@ -681,9 +686,36 @@ static void __init evm_init_i2c(void)
>       evm_init_video();
>  }
>  
> +#define CDCE949_XIN_RATE     27000000
> +
> +/* CDCE949 support - "lpsc" field is overridden to work as clock number */
> +static struct clk cdce_clk_in = {
> +     .name   = "cdce_xin",
> +     .flags  = ALWAYS_ENABLED,

Why do you need ALWAYS_ENABLED here.  I'd rather see
clk_get()/clk_enable() used when this clock is required.

To do this, we'll need to add enable/disable functionaltiy for non-PSC
clocks.  Probably the best way to do this is to add add an 'enable' hook
to 'struct clk' and clk_enable() can use that.

Kevin
_______________________________________________
Davinci-linux-open-source mailing list
[email protected]
http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source

Reply via email to