Commit 722825dc authored by Jerome Brunet's avatar Jerome Brunet Committed by Neil Armstrong

clk: meson: migrate plls clocks to clk_regmap

Rework meson pll driver to use clk_regmap and move meson8b, gxbb and
axg's clock using meson_clk_pll to clk_regmap.

This rework is not just about clk_regmap, there a serious clean-up of
the driver code:
* Add lock and reset field: Previously inferred from the n field.
* Simplify the reset logic: Code seemed to apply reset differently but
  in fact it was always the same -> assert reset, apply params,
  de-assert reset. The 2 lock checking loops have been kept for now, as
  they seem to be necessary.
* Do the sequence of init register pokes only at .init() instead of in
  .set_rate(). Redoing the init on every set_rate() is not necessary
Signed-off-by: default avatarJerome Brunet <jbrunet@baylibre.com>
Signed-off-by: default avatarNeil Armstrong <narmstrong@baylibre.com>
parent 88a4e128
...@@ -22,28 +22,39 @@ ...@@ -22,28 +22,39 @@
static DEFINE_SPINLOCK(meson_clk_lock); static DEFINE_SPINLOCK(meson_clk_lock);
static struct meson_clk_pll axg_fixed_pll = { static struct clk_regmap axg_fixed_pll = {
.m = { .data = &(struct meson_clk_pll_data){
.reg_off = HHI_MPLL_CNTL, .m = {
.shift = 0, .reg_off = HHI_MPLL_CNTL,
.width = 9, .shift = 0,
}, .width = 9,
.n = { },
.reg_off = HHI_MPLL_CNTL, .n = {
.shift = 9, .reg_off = HHI_MPLL_CNTL,
.width = 5, .shift = 9,
}, .width = 5,
.od = { },
.reg_off = HHI_MPLL_CNTL, .od = {
.shift = 16, .reg_off = HHI_MPLL_CNTL,
.width = 2, .shift = 16,
}, .width = 2,
.frac = { },
.reg_off = HHI_MPLL_CNTL2, .frac = {
.shift = 0, .reg_off = HHI_MPLL_CNTL2,
.width = 12, .shift = 0,
}, .width = 12,
.lock = &meson_clk_lock, },
.l = {
.reg_off = HHI_MPLL_CNTL,
.shift = 31,
.width = 1,
},
.rst = {
.reg_off = HHI_MPLL_CNTL,
.shift = 29,
.width = 1,
},
},
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "fixed_pll", .name = "fixed_pll",
.ops = &meson_clk_pll_ro_ops, .ops = &meson_clk_pll_ro_ops,
...@@ -52,23 +63,34 @@ static struct meson_clk_pll axg_fixed_pll = { ...@@ -52,23 +63,34 @@ static struct meson_clk_pll axg_fixed_pll = {
}, },
}; };
static struct meson_clk_pll axg_sys_pll = { static struct clk_regmap axg_sys_pll = {
.m = { .data = &(struct meson_clk_pll_data){
.reg_off = HHI_SYS_PLL_CNTL, .m = {
.shift = 0, .reg_off = HHI_SYS_PLL_CNTL,
.width = 9, .shift = 0,
}, .width = 9,
.n = { },
.reg_off = HHI_SYS_PLL_CNTL, .n = {
.shift = 9, .reg_off = HHI_SYS_PLL_CNTL,
.width = 5, .shift = 9,
}, .width = 5,
.od = { },
.reg_off = HHI_SYS_PLL_CNTL, .od = {
.shift = 16, .reg_off = HHI_SYS_PLL_CNTL,
.width = 2, .shift = 16,
.width = 2,
},
.l = {
.reg_off = HHI_SYS_PLL_CNTL,
.shift = 31,
.width = 1,
},
.rst = {
.reg_off = HHI_SYS_PLL_CNTL,
.shift = 29,
.width = 1,
},
}, },
.lock = &meson_clk_lock,
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "sys_pll", .name = "sys_pll",
.ops = &meson_clk_pll_ro_ops, .ops = &meson_clk_pll_ro_ops,
...@@ -169,40 +191,47 @@ static const struct pll_rate_table axg_gp0_pll_rate_table[] = { ...@@ -169,40 +191,47 @@ static const struct pll_rate_table axg_gp0_pll_rate_table[] = {
{ /* sentinel */ }, { /* sentinel */ },
}; };
static struct pll_params_table axg_gp0_params_table[] = { const struct reg_sequence axg_gp0_init_regs[] = {
PLL_PARAM(HHI_GP0_PLL_CNTL, 0x40010250), { .reg = HHI_GP0_PLL_CNTL, .def = 0x40010250 },
PLL_PARAM(HHI_GP0_PLL_CNTL1, 0xc084a000), { .reg = HHI_GP0_PLL_CNTL1, .def = 0xc084a000 },
PLL_PARAM(HHI_GP0_PLL_CNTL2, 0xb75020be), { .reg = HHI_GP0_PLL_CNTL2, .def = 0xb75020be },
PLL_PARAM(HHI_GP0_PLL_CNTL3, 0x0a59a288), { .reg = HHI_GP0_PLL_CNTL3, .def = 0x0a59a288 },
PLL_PARAM(HHI_GP0_PLL_CNTL4, 0xc000004d), { .reg = HHI_GP0_PLL_CNTL4, .def = 0xc000004d },
PLL_PARAM(HHI_GP0_PLL_CNTL5, 0x00078000), { .reg = HHI_GP0_PLL_CNTL5, .def = 0x00078000 },
}; };
static struct meson_clk_pll axg_gp0_pll = { static struct clk_regmap axg_gp0_pll = {
.m = { .data = &(struct meson_clk_pll_data){
.reg_off = HHI_GP0_PLL_CNTL, .m = {
.shift = 0, .reg_off = HHI_GP0_PLL_CNTL,
.width = 9, .shift = 0,
}, .width = 9,
.n = { },
.reg_off = HHI_GP0_PLL_CNTL, .n = {
.shift = 9, .reg_off = HHI_GP0_PLL_CNTL,
.width = 5, .shift = 9,
}, .width = 5,
.od = { },
.reg_off = HHI_GP0_PLL_CNTL, .od = {
.shift = 16, .reg_off = HHI_GP0_PLL_CNTL,
.width = 2, .shift = 16,
}, .width = 2,
.params = { },
.params_table = axg_gp0_params_table, .l = {
.params_count = ARRAY_SIZE(axg_gp0_params_table), .reg_off = HHI_GP0_PLL_CNTL,
.no_init_reset = true, .shift = 31,
.reset_lock_loop = true, .width = 1,
}, },
.rate_table = axg_gp0_pll_rate_table, .rst = {
.rate_count = ARRAY_SIZE(axg_gp0_pll_rate_table), .reg_off = HHI_GP0_PLL_CNTL,
.lock = &meson_clk_lock, .shift = 29,
.width = 1,
},
.table = axg_gp0_pll_rate_table,
.init_regs = axg_gp0_init_regs,
.init_count = ARRAY_SIZE(axg_gp0_init_regs),
.flags = CLK_MESON_PLL_LOCK_LOOP_RST,
},
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "gp0_pll", .name = "gp0_pll",
.ops = &meson_clk_pll_ops, .ops = &meson_clk_pll_ops,
...@@ -698,14 +727,7 @@ static struct clk_hw_onecell_data axg_hw_onecell_data = { ...@@ -698,14 +727,7 @@ static struct clk_hw_onecell_data axg_hw_onecell_data = {
.num = NR_CLKS, .num = NR_CLKS,
}; };
/* Convenience tables to populate base addresses in .probe */ /* Convenience table to populate regmap in .probe */
static struct meson_clk_pll *const axg_clk_plls[] = {
&axg_fixed_pll,
&axg_sys_pll,
&axg_gp0_pll,
};
static struct clk_regmap *const axg_clk_regmaps[] = { static struct clk_regmap *const axg_clk_regmaps[] = {
&axg_clk81, &axg_clk81,
&axg_ddr, &axg_ddr,
...@@ -764,22 +786,13 @@ static struct clk_regmap *const axg_clk_regmaps[] = { ...@@ -764,22 +786,13 @@ static struct clk_regmap *const axg_clk_regmaps[] = {
&axg_mpll1, &axg_mpll1,
&axg_mpll2, &axg_mpll2,
&axg_mpll3, &axg_mpll3,
}; &axg_fixed_pll,
&axg_sys_pll,
struct clkc_data { &axg_gp0_pll,
struct meson_clk_pll *const *clk_plls;
unsigned int clk_plls_count;
struct clk_hw_onecell_data *hw_onecell_data;
};
static const struct clkc_data axg_clkc_data = {
.clk_plls = axg_clk_plls,
.clk_plls_count = ARRAY_SIZE(axg_clk_plls),
.hw_onecell_data = &axg_hw_onecell_data,
}; };
static const struct of_device_id clkc_match_table[] = { static const struct of_device_id clkc_match_table[] = {
{ .compatible = "amlogic,axg-clkc", .data = &axg_clkc_data }, { .compatible = "amlogic,axg-clkc" },
{} {}
}; };
...@@ -792,16 +805,11 @@ static const struct regmap_config clkc_regmap_config = { ...@@ -792,16 +805,11 @@ static const struct regmap_config clkc_regmap_config = {
static int axg_clkc_probe(struct platform_device *pdev) static int axg_clkc_probe(struct platform_device *pdev)
{ {
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
const struct clkc_data *clkc_data;
struct resource *res; struct resource *res;
void __iomem *clk_base; void __iomem *clk_base;
struct regmap *map; struct regmap *map;
int ret, i; int ret, i;
clkc_data = of_device_get_match_data(dev);
if (!clkc_data)
return -EINVAL;
/* Generic clocks and PLLs */ /* Generic clocks and PLLs */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) if (!res)
...@@ -817,21 +825,16 @@ static int axg_clkc_probe(struct platform_device *pdev) ...@@ -817,21 +825,16 @@ static int axg_clkc_probe(struct platform_device *pdev)
if (IS_ERR(map)) if (IS_ERR(map))
return PTR_ERR(map); return PTR_ERR(map);
/* Populate base address for PLLs */
for (i = 0; i < clkc_data->clk_plls_count; i++)
clkc_data->clk_plls[i]->base = clk_base;
/* Populate regmap for the regmap backed clocks */ /* Populate regmap for the regmap backed clocks */
for (i = 0; i < ARRAY_SIZE(axg_clk_regmaps); i++) for (i = 0; i < ARRAY_SIZE(axg_clk_regmaps); i++)
axg_clk_regmaps[i]->map = map; axg_clk_regmaps[i]->map = map;
for (i = 0; i < clkc_data->hw_onecell_data->num; i++) { for (i = 0; i < axg_hw_onecell_data.num; i++) {
/* array might be sparse */ /* array might be sparse */
if (!clkc_data->hw_onecell_data->hws[i]) if (!axg_hw_onecell_data.hws[i])
continue; continue;
ret = devm_clk_hw_register(dev, ret = devm_clk_hw_register(dev, axg_hw_onecell_data.hws[i]);
clkc_data->hw_onecell_data->hws[i]);
if (ret) { if (ret) {
dev_err(dev, "Clock registration failed\n"); dev_err(dev, "Clock registration failed\n");
return ret; return ret;
...@@ -839,7 +842,7 @@ static int axg_clkc_probe(struct platform_device *pdev) ...@@ -839,7 +842,7 @@ static int axg_clkc_probe(struct platform_device *pdev)
} }
return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get,
clkc_data->hw_onecell_data); &axg_hw_onecell_data);
} }
static struct platform_driver axg_driver = { static struct platform_driver axg_driver = {
......
...@@ -42,52 +42,36 @@ ...@@ -42,52 +42,36 @@
#include "clkc.h" #include "clkc.h"
#define MESON_PLL_RESET BIT(29) static inline struct meson_clk_pll_data *
#define MESON_PLL_LOCK BIT(31) meson_clk_pll_data(struct clk_regmap *clk)
{
#define to_meson_clk_pll(_hw) container_of(_hw, struct meson_clk_pll, hw) return (struct meson_clk_pll_data *)clk->data;
}
static unsigned long meson_clk_pll_recalc_rate(struct clk_hw *hw, static unsigned long meson_clk_pll_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate) unsigned long parent_rate)
{ {
struct meson_clk_pll *pll = to_meson_clk_pll(hw); struct clk_regmap *clk = to_clk_regmap(hw);
struct parm *p; struct meson_clk_pll_data *pll = meson_clk_pll_data(clk);
u64 rate; u64 rate;
u16 n, m, frac = 0, od, od2 = 0, od3 = 0; u16 n, m, frac = 0, od, od2 = 0, od3 = 0;
u32 reg;
p = &pll->n;
reg = readl(pll->base + p->reg_off);
n = PARM_GET(p->width, p->shift, reg);
p = &pll->m; n = meson_parm_read(clk->map, &pll->n);
reg = readl(pll->base + p->reg_off); m = meson_parm_read(clk->map, &pll->m);
m = PARM_GET(p->width, p->shift, reg); od = meson_parm_read(clk->map, &pll->od);
p = &pll->od; if (MESON_PARM_APPLICABLE(&pll->od2))
reg = readl(pll->base + p->reg_off); od2 = meson_parm_read(clk->map, &pll->od2);
od = PARM_GET(p->width, p->shift, reg);
p = &pll->od2; if (MESON_PARM_APPLICABLE(&pll->od3))
if (p->width) { od3 = meson_parm_read(clk->map, &pll->od3);
reg = readl(pll->base + p->reg_off);
od2 = PARM_GET(p->width, p->shift, reg);
}
p = &pll->od3;
if (p->width) {
reg = readl(pll->base + p->reg_off);
od3 = PARM_GET(p->width, p->shift, reg);
}
rate = (u64)m * parent_rate; rate = (u64)m * parent_rate;
p = &pll->frac; if (MESON_PARM_APPLICABLE(&pll->frac)) {
if (p->width) { frac = meson_parm_read(clk->map, &pll->frac);
reg = readl(pll->base + p->reg_off);
frac = PARM_GET(p->width, p->shift, reg);
rate += mul_u64_u32_shr(parent_rate, frac, p->width); rate += mul_u64_u32_shr(parent_rate, frac, pll->frac.width);
} }
return div_u64(rate, n) >> od >> od2 >> od3; return div_u64(rate, n) >> od >> od2 >> od3;
...@@ -96,177 +80,136 @@ static unsigned long meson_clk_pll_recalc_rate(struct clk_hw *hw, ...@@ -96,177 +80,136 @@ static unsigned long meson_clk_pll_recalc_rate(struct clk_hw *hw,
static long meson_clk_pll_round_rate(struct clk_hw *hw, unsigned long rate, static long meson_clk_pll_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *parent_rate) unsigned long *parent_rate)
{ {
struct meson_clk_pll *pll = to_meson_clk_pll(hw); struct clk_regmap *clk = to_clk_regmap(hw);
const struct pll_rate_table *rate_table = pll->rate_table; struct meson_clk_pll_data *pll = meson_clk_pll_data(clk);
int i; const struct pll_rate_table *pllt;
/* /*
* if the table is missing, just return the current rate * if the table is missing, just return the current rate
* since we don't have the other available frequencies * since we don't have the other available frequencies
*/ */
if (!rate_table) if (!pll->table)
return meson_clk_pll_recalc_rate(hw, *parent_rate); return meson_clk_pll_recalc_rate(hw, *parent_rate);
for (i = 0; i < pll->rate_count; i++) { for (pllt = pll->table; pllt->rate; pllt++) {
if (rate <= rate_table[i].rate) if (rate <= pllt->rate)
return rate_table[i].rate; return pllt->rate;
} }
/* else return the smallest value */ /* else return the smallest value */
return rate_table[0].rate; return pll->table[0].rate;
} }
static const struct pll_rate_table *meson_clk_get_pll_settings(struct meson_clk_pll *pll, static const struct pll_rate_table *
unsigned long rate) meson_clk_get_pll_settings(const struct pll_rate_table *table,
unsigned long rate)
{ {
const struct pll_rate_table *rate_table = pll->rate_table; const struct pll_rate_table *pllt;
int i;
if (!rate_table) if (!table)
return NULL; return NULL;
for (i = 0; i < pll->rate_count; i++) { for (pllt = table; pllt->rate; pllt++) {
if (rate == rate_table[i].rate) if (rate == pllt->rate)
return &rate_table[i]; return pllt;
} }
return NULL; return NULL;
} }
/* Specific wait loop for GXL/GXM GP0 PLL */ static int meson_clk_pll_wait_lock(struct clk_hw *hw)
static int meson_clk_pll_wait_lock_reset(struct meson_clk_pll *pll,
struct parm *p_n)
{ {
int delay = 100; struct clk_regmap *clk = to_clk_regmap(hw);
u32 reg; struct meson_clk_pll_data *pll = meson_clk_pll_data(clk);
int delay = pll->flags & CLK_MESON_PLL_LOCK_LOOP_RST ?
while (delay > 0) { 100 : 24000000;
reg = readl(pll->base + p_n->reg_off);
writel(reg | MESON_PLL_RESET, pll->base + p_n->reg_off); do {
udelay(10); /* Specific wait loop for GXL/GXM GP0 PLL */
writel(reg & ~MESON_PLL_RESET, pll->base + p_n->reg_off); if (pll->flags & CLK_MESON_PLL_LOCK_LOOP_RST) {
/* Procedure taken from the vendor kernel */
/* This delay comes from AMLogic tree clk-gp0-gxl driver */ meson_parm_write(clk->map, &pll->rst, 1);
mdelay(1); udelay(10);
meson_parm_write(clk->map, &pll->rst, 0);
reg = readl(pll->base + p_n->reg_off); mdelay(1);
if (reg & MESON_PLL_LOCK) }
/* Is the clock locked now ? */
if (meson_parm_read(clk->map, &pll->l))
return 0; return 0;
delay--;
}
return -ETIMEDOUT;
}
static int meson_clk_pll_wait_lock(struct meson_clk_pll *pll,
struct parm *p_n)
{
int delay = 24000000;
u32 reg;
while (delay > 0) {
reg = readl(pll->base + p_n->reg_off);
if (reg & MESON_PLL_LOCK)
return 0;
delay--; delay--;
} } while (delay > 0);
return -ETIMEDOUT; return -ETIMEDOUT;
} }
static void meson_clk_pll_init_params(struct meson_clk_pll *pll) static void meson_clk_pll_init(struct clk_hw *hw)
{ {
int i; struct clk_regmap *clk = to_clk_regmap(hw);
struct meson_clk_pll_data *pll = meson_clk_pll_data(clk);
for (i = 0 ; i < pll->params.params_count ; ++i)
writel(pll->params.params_table[i].value, if (pll->init_count) {
pll->base + pll->params.params_table[i].reg_off); meson_parm_write(clk->map, &pll->rst, 1);
regmap_multi_reg_write(clk->map, pll->init_regs,
pll->init_count);
meson_parm_write(clk->map, &pll->rst, 0);
}
} }
static int meson_clk_pll_set_rate(struct clk_hw *hw, unsigned long rate, static int meson_clk_pll_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate) unsigned long parent_rate)
{ {
struct meson_clk_pll *pll = to_meson_clk_pll(hw); struct clk_regmap *clk = to_clk_regmap(hw);
struct parm *p; struct meson_clk_pll_data *pll = meson_clk_pll_data(clk);
const struct pll_rate_table *rate_set; const struct pll_rate_table *pllt;
unsigned long old_rate; unsigned long old_rate;
int ret = 0;
u32 reg;
if (parent_rate == 0 || rate == 0) if (parent_rate == 0 || rate == 0)
return -EINVAL; return -EINVAL;
old_rate = rate; old_rate = rate;
rate_set = meson_clk_get_pll_settings(pll, rate); pllt = meson_clk_get_pll_settings(pll->table, rate);
if (!rate_set) if (!pllt)
return -EINVAL; return -EINVAL;
/* Initialize the PLL in a clean state if specified */ /* Put the pll in reset to write the params */
if (pll->params.params_count) meson_parm_write(clk->map, &pll->rst, 1);
meson_clk_pll_init_params(pll);
/* PLL reset */
p = &pll->n;
reg = readl(pll->base + p->reg_off);
/* If no_init_reset is provided, avoid resetting at this point */
if (!pll->params.no_init_reset)
writel(reg | MESON_PLL_RESET, pll->base + p->reg_off);
reg = PARM_SET(p->width, p->shift, reg, rate_set->n);
writel(reg, pll->base + p->reg_off);
p = &pll->m;
reg = readl(pll->base + p->reg_off);
reg = PARM_SET(p->width, p->shift, reg, rate_set->m);
writel(reg, pll->base + p->reg_off);
p = &pll->od;
reg = readl(pll->base + p->reg_off);
reg = PARM_SET(p->width, p->shift, reg, rate_set->od);
writel(reg, pll->base + p->reg_off);
p = &pll->od2;
if (p->width) {
reg = readl(pll->base + p->reg_off);
reg = PARM_SET(p->width, p->shift, reg, rate_set->od2);
writel(reg, pll->base + p->reg_off);
}
p = &pll->od3; meson_parm_write(clk->map, &pll->n, pllt->n);
if (p->width) { meson_parm_write(clk->map, &pll->m, pllt->m);
reg = readl(pll->base + p->reg_off); meson_parm_write(clk->map, &pll->od, pllt->od);
reg = PARM_SET(p->width, p->shift, reg, rate_set->od3);
writel(reg, pll->base + p->reg_off);
}
p = &pll->frac; if (MESON_PARM_APPLICABLE(&pll->od2))
if (p->width) { meson_parm_write(clk->map, &pll->od2, pllt->od2);
reg = readl(pll->base + p->reg_off);
reg = PARM_SET(p->width, p->shift, reg, rate_set->frac);
writel(reg, pll->base + p->reg_off);
}
p = &pll->n; if (MESON_PARM_APPLICABLE(&pll->od3))
/* If clear_reset_for_lock is provided, remove the reset bit here */ meson_parm_write(clk->map, &pll->od3, pllt->od3);
if (pll->params.clear_reset_for_lock) {
reg = readl(pll->base + p->reg_off); if (MESON_PARM_APPLICABLE(&pll->frac))
writel(reg & ~MESON_PLL_RESET, pll->base + p->reg_off); meson_parm_write(clk->map, &pll->frac, pllt->frac);
}
/* make sure the reset is cleared at this point */
meson_parm_write(clk->map, &pll->rst, 0);
/* If reset_lock_loop, use a special loop including resetting */ if (meson_clk_pll_wait_lock(hw)) {
if (pll->params.reset_lock_loop)
ret = meson_clk_pll_wait_lock_reset(pll, p);
else
ret = meson_clk_pll_wait_lock(pll, p);
if (ret) {
pr_warn("%s: pll did not lock, trying to restore old rate %lu\n", pr_warn("%s: pll did not lock, trying to restore old rate %lu\n",
__func__, old_rate); __func__, old_rate);
/*
* FIXME: Do we really need/want this HACK ?
* It looks unsafe. what happens if the clock gets into a
* broken state and we can't lock back on the old_rate ? Looks
* like an infinite recursion is possible
*/
meson_clk_pll_set_rate(hw, old_rate, parent_rate); meson_clk_pll_set_rate(hw, old_rate, parent_rate);
} }
return ret; return 0;
} }
const struct clk_ops meson_clk_pll_ops = { const struct clk_ops meson_clk_pll_ops = {
.init = meson_clk_pll_init,
.recalc_rate = meson_clk_pll_recalc_rate, .recalc_rate = meson_clk_pll_recalc_rate,
.round_rate = meson_clk_pll_round_rate, .round_rate = meson_clk_pll_round_rate,
.set_rate = meson_clk_pll_set_rate, .set_rate = meson_clk_pll_set_rate,
......
...@@ -82,41 +82,21 @@ struct pll_rate_table { ...@@ -82,41 +82,21 @@ struct pll_rate_table {
.frac = (_frac), \ .frac = (_frac), \
} \ } \
struct pll_params_table { #define CLK_MESON_PLL_LOCK_LOOP_RST BIT(0)
unsigned int reg_off;
unsigned int value;
};
#define PLL_PARAM(_reg, _val) \
{ \
.reg_off = (_reg), \
.value = (_val), \
}
struct pll_setup_params {
struct pll_params_table *params_table;
unsigned int params_count;
/* Workaround for GP0, do not reset before configuring */
bool no_init_reset;
/* Workaround for GP0, unreset right before checking for lock */
bool clear_reset_for_lock;
/* Workaround for GXL GP0, reset in the lock checking loop */
bool reset_lock_loop;
};
struct meson_clk_pll { struct meson_clk_pll_data {
struct clk_hw hw;
void __iomem *base;
struct parm m; struct parm m;
struct parm n; struct parm n;
struct parm frac; struct parm frac;
struct parm od; struct parm od;
struct parm od2; struct parm od2;
struct parm od3; struct parm od3;
const struct pll_setup_params params; struct parm l;
const struct pll_rate_table *rate_table; struct parm rst;
unsigned int rate_count; const struct reg_sequence *init_regs;
spinlock_t *lock; unsigned int init_count;
const struct pll_rate_table *table;
u8 flags;
}; };
#define to_meson_clk_pll(_hw) container_of(_hw, struct meson_clk_pll, hw) #define to_meson_clk_pll(_hw) container_of(_hw, struct meson_clk_pll, hw)
......
This diff is collapsed.
...@@ -122,23 +122,34 @@ static struct clk_fixed_rate meson8b_xtal = { ...@@ -122,23 +122,34 @@ static struct clk_fixed_rate meson8b_xtal = {
}, },
}; };
static struct meson_clk_pll meson8b_fixed_pll = { static struct clk_regmap meson8b_fixed_pll = {
.m = { .data = &(struct meson_clk_pll_data){
.reg_off = HHI_MPLL_CNTL, .m = {
.shift = 0, .reg_off = HHI_MPLL_CNTL,
.width = 9, .shift = 0,
}, .width = 9,
.n = { },
.reg_off = HHI_MPLL_CNTL, .n = {
.shift = 9, .reg_off = HHI_MPLL_CNTL,
.width = 5, .shift = 9,
}, .width = 5,
.od = { },
.reg_off = HHI_MPLL_CNTL, .od = {
.shift = 16, .reg_off = HHI_MPLL_CNTL,
.width = 2, .shift = 16,
}, .width = 2,
.lock = &meson_clk_lock, },
.l = {
.reg_off = HHI_MPLL_CNTL,
.shift = 31,
.width = 1,
},
.rst = {
.reg_off = HHI_MPLL_CNTL,
.shift = 29,
.width = 1,
},
},
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "fixed_pll", .name = "fixed_pll",
.ops = &meson_clk_pll_ro_ops, .ops = &meson_clk_pll_ro_ops,
...@@ -148,23 +159,34 @@ static struct meson_clk_pll meson8b_fixed_pll = { ...@@ -148,23 +159,34 @@ static struct meson_clk_pll meson8b_fixed_pll = {
}, },
}; };
static struct meson_clk_pll meson8b_vid_pll = { static struct clk_regmap meson8b_vid_pll = {
.m = { .data = &(struct meson_clk_pll_data){
.reg_off = HHI_VID_PLL_CNTL, .m = {
.shift = 0, .reg_off = HHI_VID_PLL_CNTL,
.width = 9, .shift = 0,
}, .width = 9,
.n = { },
.reg_off = HHI_VID_PLL_CNTL, .n = {
.shift = 9, .reg_off = HHI_VID_PLL_CNTL,
.width = 5, .shift = 9,
}, .width = 5,
.od = { },
.reg_off = HHI_VID_PLL_CNTL, .od = {
.shift = 16, .reg_off = HHI_VID_PLL_CNTL,
.width = 2, .shift = 16,
.width = 2,
},
.l = {
.reg_off = HHI_VID_PLL_CNTL,
.shift = 31,
.width = 1,
},
.rst = {
.reg_off = HHI_VID_PLL_CNTL,
.shift = 29,
.width = 1,
},
}, },
.lock = &meson_clk_lock,
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "vid_pll", .name = "vid_pll",
.ops = &meson_clk_pll_ro_ops, .ops = &meson_clk_pll_ro_ops,
...@@ -174,25 +196,35 @@ static struct meson_clk_pll meson8b_vid_pll = { ...@@ -174,25 +196,35 @@ static struct meson_clk_pll meson8b_vid_pll = {
}, },
}; };
static struct meson_clk_pll meson8b_sys_pll = { static struct clk_regmap meson8b_sys_pll = {
.m = { .data = &(struct meson_clk_pll_data){
.reg_off = HHI_SYS_PLL_CNTL, .m = {
.shift = 0, .reg_off = HHI_SYS_PLL_CNTL,
.width = 9, .shift = 0,
}, .width = 9,
.n = { },
.reg_off = HHI_SYS_PLL_CNTL, .n = {
.shift = 9, .reg_off = HHI_SYS_PLL_CNTL,
.width = 5, .shift = 9,
}, .width = 5,
.od = { },
.reg_off = HHI_SYS_PLL_CNTL, .od = {
.shift = 16, .reg_off = HHI_SYS_PLL_CNTL,
.width = 2, .shift = 16,
}, .width = 2,
.rate_table = sys_pll_rate_table, },
.rate_count = ARRAY_SIZE(sys_pll_rate_table), .l = {
.lock = &meson_clk_lock, .reg_off = HHI_SYS_PLL_CNTL,
.shift = 31,
.width = 1,
},
.rst = {
.reg_off = HHI_SYS_PLL_CNTL,
.shift = 29,
.width = 1,
},
.table = sys_pll_rate_table,
},
.hw.init = &(struct clk_init_data){ .hw.init = &(struct clk_init_data){
.name = "sys_pll", .name = "sys_pll",
.ops = &meson_clk_pll_ops, .ops = &meson_clk_pll_ops,
...@@ -613,12 +645,6 @@ static struct clk_hw_onecell_data meson8b_hw_onecell_data = { ...@@ -613,12 +645,6 @@ static struct clk_hw_onecell_data meson8b_hw_onecell_data = {
.num = CLK_NR_CLKS, .num = CLK_NR_CLKS,
}; };
static struct meson_clk_pll *const meson8b_clk_plls[] = {
&meson8b_fixed_pll,
&meson8b_vid_pll,
&meson8b_sys_pll,
};
static struct clk_regmap *const meson8b_clk_regmaps[] = { static struct clk_regmap *const meson8b_clk_regmaps[] = {
&meson8b_clk81, &meson8b_clk81,
&meson8b_ddr, &meson8b_ddr,
...@@ -703,6 +729,9 @@ static struct clk_regmap *const meson8b_clk_regmaps[] = { ...@@ -703,6 +729,9 @@ static struct clk_regmap *const meson8b_clk_regmaps[] = {
&meson8b_mpll0, &meson8b_mpll0,
&meson8b_mpll1, &meson8b_mpll1,
&meson8b_mpll2, &meson8b_mpll2,
&meson8b_fixed_pll,
&meson8b_vid_pll,
&meson8b_sys_pll,
}; };
static const struct meson8b_clk_reset_line { static const struct meson8b_clk_reset_line {
...@@ -825,10 +854,6 @@ static int meson8b_clkc_probe(struct platform_device *pdev) ...@@ -825,10 +854,6 @@ static int meson8b_clkc_probe(struct platform_device *pdev)
if (IS_ERR(map)) if (IS_ERR(map))
return PTR_ERR(map); return PTR_ERR(map);
/* Populate base address for PLLs */
for (i = 0; i < ARRAY_SIZE(meson8b_clk_plls); i++)
meson8b_clk_plls[i]->base = clk_base;
/* Populate the base address for CPU clk */ /* Populate the base address for CPU clk */
meson8b_cpu_clk.base = clk_base; meson8b_cpu_clk.base = clk_base;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment