public inbox for linux-arm-kernel@lists.infradead.org
 help / color / mirror / Atom feed
From: mturquette@linaro.org (Mike Turquette)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH 1/4] ARM: meson: add basic infrastructure for clocks
Date: Wed, 19 Nov 2014 14:30:56 -0800	[thread overview]
Message-ID: <20141119223056.25314.11072@quantum> (raw)
In-Reply-To: <1416393143-20434-2-git-send-email-carlo@caione.org>

Quoting Carlo Caione (2014-11-19 02:32:20)
> This patchset adds the infrastructure for registering and managing the
> core clocks found on Amlogic MesonX SoCs and also adds the support for
> the basic Meson6 clocks.

Minor nitpick: typically the $SUBJECT starts with "arm:" if the patch
primarily deals with code under arch/arm. Since this code lives in
drivers/clk it might be better to use something like:

clk: meson: add basic infrastructure for clocks

<snip>

> +static void meson_clk_pll_get_parms(struct meson_clk_pll *pll,
> +                                   unsigned long *rate, unsigned long p_rate,
> +                                   u16 *best_n, u16 *best_m, u16 *best_od_fb)
> +{
> +       unsigned long rate_mhz, p_rate_mhz;
> +       unsigned long pll_vco_min_mhz, pll_vco_max_mhz;
> +       unsigned long cur_rate_mhz, best_rate_mhz;
> +       u16 m, m_min, m_max, m_mask;
> +       u16 n, n_min, n_max, n_mask, _n_min, _n_max;
> +       u16 od_fb, od_fb_max;
> +
> +       rate_mhz = *rate / 1000000;
> +       p_rate_mhz = p_rate / 1000000;
> +       pll_vco_min_mhz = pll->conf->vco_min_mhz;
> +       pll_vco_max_mhz = pll->conf->vco_max_mhz;
> +       best_rate_mhz = ULONG_MAX;
> +       *best_n = 0;
> +       *best_m = 0;
> +       *best_od_fb = 1;
> +
> +       m_mask = PMASK(pll->conf->m.width);
> +       n_mask = PMASK(pll->conf->n.width);
> +
> +       /* FREF = P_RATE / N */
> +       n_min = max_t(u16, DIV_ROUND_UP(p_rate_mhz, MESON_FREF_MAX_MHZ), 1);
> +       n_max = min_t(u16, p_rate_mhz / MESON_FREF_MIN_MHZ, n_mask);
> +
> +       od_fb_max = 1 << PMASK(pll->conf->od_fb.width);
> +
> +       for (od_fb = 1; od_fb <= od_fb_max; od_fb <<= 1) {
> +
> +               /* VCO = P_RATE * M * OD_FB / N */
> +               m_min = max_t(u16, DIV_ROUND_UP(pll_vco_min_mhz,
> +                             p_rate_mhz * od_fb) * n_min, 1);
> +               m_max = min_t(u16, (pll_vco_max_mhz * n_max) /
> +                             (p_rate_mhz * od_fb), m_mask);
> +
> +
> +               for (m = m_min; m <= m_max; m++) {
> +                       _n_min = max_t(u16, n_min,
> +                                      DIV_ROUND_UP(p_rate_mhz * m * od_fb,
> +                                      pll_vco_max_mhz));
> +                       _n_max = min_t(u16, n_max,
> +                                      p_rate_mhz * m * od_fb / pll_vco_min_mhz);
> +
> +                       for (n = _n_min; n <= _n_max; n++) {
> +                               cur_rate_mhz = p_rate_mhz * m * od_fb / n;
> +
> +                               if (abs(cur_rate_mhz - rate_mhz) <
> +                                  abs(best_rate_mhz - rate_mhz)) {
> +                                       best_rate_mhz = cur_rate_mhz;
> +                                       *best_n = n;
> +                                       *best_m = m;
> +                                       *best_od_fb = od_fb;
> +                                       if (best_rate_mhz == rate_mhz)
> +                                               goto done;
> +                               }
> +                       }
> +               }
> +       }

Nothing strictly wrong with the above, but is is n^3 complexity. If your
tables are large then you might be spending a non-trivial amount time
calculating the pll parameters.

<snip>

> +
> +done:
> +       *best_od_fb >>= 1;
> +       *rate = best_rate_mhz * 1000000;
> +       return;
> +
> +}
> +
> +static unsigned long meson_clk_pll_recalc_rate(struct clk_hw *hw,
> +                                               unsigned long parent_rate)
> +{
> +       struct meson_clk_pll *pll = to_meson_clk_pll(hw);
> +       struct parm *p_n, *p_m, *p_od_fb;
> +       unsigned long parent_rate_mhz = parent_rate / 1000000;
> +       unsigned long rate_mhz;
> +       u16 n, m, od_fb = 1;
> +       u32 reg_n, reg_m, reg_od_fb;
> +
> +       p_n = &pll->conf->n;
> +       p_m = &pll->conf->m;
> +       p_od_fb = &pll->conf->od_fb;
> +
> +       reg_n = readl(pll->base + p_n->reg_off);
> +       n = PARM_GET(p_n->width, p_n->shift, reg_n);
> +
> +       reg_m = readl(pll->base + p_m->reg_off);
> +       m = PARM_GET(p_m->width, p_m->shift, reg_m);
> +
> +       if (p_od_fb->width != MESON_PARM_NOT_APPLICABLE) {
> +               reg_od_fb = readl(pll->base + p_od_fb->reg_off);
> +               od_fb = PARM_GET(p_od_fb->width, p_od_fb->shift, reg_od_fb);
> +               od_fb = 1 << od_fb;
> +       }
> +
> +       rate_mhz = parent_rate_mhz * m * od_fb / n;
> +
> +       return rate_mhz * 1000000;
> +}
> +
> +static long meson_clk_pll_round_rate(struct clk_hw *hw, unsigned long rate,
> +                                     unsigned long *parent_rate)
> +{
> +       struct meson_clk_pll *pll = to_meson_clk_pll(hw);
> +       u16 m, n, od_fb;
> +
> +       meson_clk_pll_get_parms(pll, &rate, *parent_rate, &n, &m, &od_fb);
> +       if (m == 0 || n == 0)
> +               return -EINVAL;
> +
> +       return rate;
> +}

Can the clock signal input to your pll by multiplexed? Are there
multiple possible parents to a pll? If so you might want to use
.determine_rate over .round_rate.

<snip>

> diff --git a/drivers/clk/meson/clkc.h b/drivers/clk/meson/clkc.h
> new file mode 100644
> index 0000000..6c0f611
> --- /dev/null
> +++ b/drivers/clk/meson/clkc.h
> @@ -0,0 +1,159 @@
> +/*
> + * Copyright (c) 2014 Carlo Caione <carlo@caione.org>
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License along with
> + * this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#ifndef __CLKC_H
> +#define __CLKC_H

<snip>

> +void meson_clk_init(struct device_node *np, unsigned long nr_clks);
> +void meson_clk_add_lookup(struct clk *clk, unsigned int id);
> +void meson_clk_register_pll_divs(struct pll_div_conf *pll_divs,
> +                                unsigned int nr_pll_divs,
> +                                void __iomem *reg_base);
> +void meson_clk_register_pll_div(struct pll_div_conf *pll_div_conf,
> +                               void __iomem *reg_base, spinlock_t *lock);
> +void meson_clk_register_clks(struct clk_conf *clk_confs,
> +                            unsigned int nr_confs,
> +                            void __iomem *clk_base);

Missing #endif here causes compile failure.

Regards,
Mike

  reply	other threads:[~2014-11-19 22:30 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-11-19 10:32 [PATCH 0/4] ARM: meson: add clock/reset controller Carlo Caione
2014-11-19 10:32 ` [PATCH 1/4] ARM: meson: add basic infrastructure for clocks Carlo Caione
2014-11-19 22:30   ` Mike Turquette [this message]
2014-11-19 22:48     ` Carlo Caione
2014-11-19 22:42   ` Mike Turquette
2014-11-19 22:51     ` Carlo Caione
2014-11-19 10:32 ` [PATCH 2/4] ARM: meson: add reset controller Carlo Caione
2014-11-19 10:32 ` [PATCH 3/4] ARM: meson: enable reset controller in kconfig Carlo Caione
2014-11-19 10:32 ` [PATCH 4/4] ARM: meson: add documentation for reset/clock controller Carlo Caione

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20141119223056.25314.11072@quantum \
    --to=mturquette@linaro.org \
    --cc=linux-arm-kernel@lists.infradead.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox