Skip to content

Commit

Permalink
clk: meson: mpll: add rw operation
Browse files Browse the repository at this point in the history
This patch adds new callbacks to the meson-mpll driver to control
and set the pll rate. For this, we also need to add the enable bit and
sdm enable bit. The corresponding parameters are added to mpll data
structure.

Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
Signed-off-by: Michael Turquette <mturquette@baylibre.com>
Link: lkml.kernel.org/r/20170309104154.28295-6-jbrunet@baylibre.com
  • Loading branch information
jbrun3t authored and mturquette committed Mar 27, 2017
1 parent b92332e commit 007e6e5
Show file tree
Hide file tree
Showing 3 changed files with 180 additions and 6 deletions.
152 changes: 147 additions & 5 deletions drivers/clk/meson/clk-mpll.c
Original file line number Diff line number Diff line change
Expand Up @@ -64,16 +64,50 @@
#include <linux/clk-provider.h>
#include "clkc.h"

#define SDM_MAX 16384
#define SDM_DEN 16384
#define SDM_MIN 1
#define SDM_MAX 16383
#define N2_MIN 4
#define N2_MAX 127

#define to_meson_clk_mpll(_hw) container_of(_hw, struct meson_clk_mpll, hw)

static unsigned long rate_from_params(unsigned long parent_rate,
unsigned long sdm,
unsigned long n2)
{
return (parent_rate * SDM_DEN) / ((SDM_DEN * n2) + sdm);
}

static void params_from_rate(unsigned long requested_rate,
unsigned long parent_rate,
unsigned long *sdm,
unsigned long *n2)
{
uint64_t div = parent_rate;
unsigned long rem = do_div(div, requested_rate);

if (div < N2_MIN) {
*n2 = N2_MIN;
*sdm = SDM_MIN;
} else if (div > N2_MAX) {
*n2 = N2_MAX;
*sdm = SDM_MAX;
} else {
*n2 = div;
*sdm = DIV_ROUND_UP(rem * SDM_DEN, requested_rate);
if (*sdm < SDM_MIN)
*sdm = SDM_MIN;
else if (*sdm > SDM_MAX)
*sdm = SDM_MAX;
}
}

static unsigned long mpll_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct meson_clk_mpll *mpll = to_meson_clk_mpll(hw);
struct parm *p;
unsigned long rate = 0;
unsigned long reg, sdm, n2;

p = &mpll->sdm;
Expand All @@ -84,11 +118,119 @@ static unsigned long mpll_recalc_rate(struct clk_hw *hw,
reg = readl(mpll->base + p->reg_off);
n2 = PARM_GET(p->width, p->shift, reg);

rate = (parent_rate * SDM_MAX) / ((SDM_MAX * n2) + sdm);
return rate_from_params(parent_rate, sdm, n2);
}

static long mpll_round_rate(struct clk_hw *hw,
unsigned long rate,
unsigned long *parent_rate)
{
unsigned long sdm, n2;

params_from_rate(rate, *parent_rate, &sdm, &n2);
return rate_from_params(*parent_rate, sdm, n2);
}

static int mpll_set_rate(struct clk_hw *hw,
unsigned long rate,
unsigned long parent_rate)
{
struct meson_clk_mpll *mpll = to_meson_clk_mpll(hw);
struct parm *p;
unsigned long reg, sdm, n2;
unsigned long flags = 0;

params_from_rate(rate, parent_rate, &sdm, &n2);

if (mpll->lock)
spin_lock_irqsave(mpll->lock, flags);
else
__acquire(mpll->lock);

p = &mpll->sdm;
reg = readl(mpll->base + p->reg_off);
reg = PARM_SET(p->width, p->shift, reg, sdm);
writel(reg, mpll->base + p->reg_off);

p = &mpll->sdm_en;
reg = readl(mpll->base + p->reg_off);
reg = PARM_SET(p->width, p->shift, reg, 1);
writel(reg, mpll->base + p->reg_off);

p = &mpll->n2;
reg = readl(mpll->base + p->reg_off);
reg = PARM_SET(p->width, p->shift, reg, n2);
writel(reg, mpll->base + p->reg_off);

if (mpll->lock)
spin_unlock_irqrestore(mpll->lock, flags);
else
__release(mpll->lock);

return rate;
return 0;
}

static void mpll_enable_core(struct clk_hw *hw, int enable)
{
struct meson_clk_mpll *mpll = to_meson_clk_mpll(hw);
struct parm *p;
unsigned long reg;
unsigned long flags = 0;

if (mpll->lock)
spin_lock_irqsave(mpll->lock, flags);
else
__acquire(mpll->lock);

p = &mpll->en;
reg = readl(mpll->base + p->reg_off);
reg = PARM_SET(p->width, p->shift, reg, enable ? 1 : 0);
writel(reg, mpll->base + p->reg_off);

if (mpll->lock)
spin_unlock_irqrestore(mpll->lock, flags);
else
__release(mpll->lock);
}


static int mpll_enable(struct clk_hw *hw)
{
mpll_enable_core(hw, 1);

return 0;
}

static void mpll_disable(struct clk_hw *hw)
{
mpll_enable_core(hw, 0);
}

static int mpll_is_enabled(struct clk_hw *hw)
{
struct meson_clk_mpll *mpll = to_meson_clk_mpll(hw);
struct parm *p;
unsigned long reg;
int en;

p = &mpll->en;
reg = readl(mpll->base + p->reg_off);
en = PARM_GET(p->width, p->shift, reg);

return en;
}

const struct clk_ops meson_clk_mpll_ro_ops = {
.recalc_rate = mpll_recalc_rate,
.recalc_rate = mpll_recalc_rate,
.round_rate = mpll_round_rate,
.is_enabled = mpll_is_enabled,
};

const struct clk_ops meson_clk_mpll_ops = {
.recalc_rate = mpll_recalc_rate,
.round_rate = mpll_round_rate,
.set_rate = mpll_set_rate,
.enable = mpll_enable,
.disable = mpll_disable,
.is_enabled = mpll_is_enabled,
};
4 changes: 3 additions & 1 deletion drivers/clk/meson/clkc.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,9 @@ struct meson_clk_mpll {
struct clk_hw hw;
void __iomem *base;
struct parm sdm;
struct parm sdm_en;
struct parm n2;
/* FIXME ssen gate control? */
struct parm en;
spinlock_t *lock;
};

Expand All @@ -116,5 +117,6 @@ extern const struct clk_ops meson_clk_pll_ro_ops;
extern const struct clk_ops meson_clk_pll_ops;
extern const struct clk_ops meson_clk_cpu_ops;
extern const struct clk_ops meson_clk_mpll_ro_ops;
extern const struct clk_ops meson_clk_mpll_ops;

#endif /* __CLKC_H */
30 changes: 30 additions & 0 deletions drivers/clk/meson/gxbb.c
Original file line number Diff line number Diff line change
Expand Up @@ -441,11 +441,21 @@ static struct meson_clk_mpll gxbb_mpll0 = {
.shift = 0,
.width = 14,
},
.sdm_en = {
.reg_off = HHI_MPLL_CNTL7,
.shift = 15,
.width = 1,
},
.n2 = {
.reg_off = HHI_MPLL_CNTL7,
.shift = 16,
.width = 9,
},
.en = {
.reg_off = HHI_MPLL_CNTL7,
.shift = 14,
.width = 1,
},
.lock = &clk_lock,
.hw.init = &(struct clk_init_data){
.name = "mpll0",
Expand All @@ -461,11 +471,21 @@ static struct meson_clk_mpll gxbb_mpll1 = {
.shift = 0,
.width = 14,
},
.sdm_en = {
.reg_off = HHI_MPLL_CNTL8,
.shift = 15,
.width = 1,
},
.n2 = {
.reg_off = HHI_MPLL_CNTL8,
.shift = 16,
.width = 9,
},
.en = {
.reg_off = HHI_MPLL_CNTL8,
.shift = 14,
.width = 1,
},
.lock = &clk_lock,
.hw.init = &(struct clk_init_data){
.name = "mpll1",
Expand All @@ -481,11 +501,21 @@ static struct meson_clk_mpll gxbb_mpll2 = {
.shift = 0,
.width = 14,
},
.sdm_en = {
.reg_off = HHI_MPLL_CNTL9,
.shift = 15,
.width = 1,
},
.n2 = {
.reg_off = HHI_MPLL_CNTL9,
.shift = 16,
.width = 9,
},
.en = {
.reg_off = HHI_MPLL_CNTL9,
.shift = 14,
.width = 1,
},
.lock = &clk_lock,
.hw.init = &(struct clk_init_data){
.name = "mpll2",
Expand Down

0 comments on commit 007e6e5

Please sign in to comment.