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: Jerome Brunet <jbrunet@baylibre.com> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
This commit is contained in:
parent
88a4e12836
commit
722825dcd5
5 changed files with 525 additions and 520 deletions
|
@ -22,7 +22,8 @@
|
||||||
|
|
||||||
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 = {
|
||||||
|
.data = &(struct meson_clk_pll_data){
|
||||||
.m = {
|
.m = {
|
||||||
.reg_off = HHI_MPLL_CNTL,
|
.reg_off = HHI_MPLL_CNTL,
|
||||||
.shift = 0,
|
.shift = 0,
|
||||||
|
@ -43,7 +44,17 @@ static struct meson_clk_pll axg_fixed_pll = {
|
||||||
.shift = 0,
|
.shift = 0,
|
||||||
.width = 12,
|
.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,7 +63,8 @@ static struct meson_clk_pll axg_fixed_pll = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct meson_clk_pll axg_sys_pll = {
|
static struct clk_regmap axg_sys_pll = {
|
||||||
|
.data = &(struct meson_clk_pll_data){
|
||||||
.m = {
|
.m = {
|
||||||
.reg_off = HHI_SYS_PLL_CNTL,
|
.reg_off = HHI_SYS_PLL_CNTL,
|
||||||
.shift = 0,
|
.shift = 0,
|
||||||
|
@ -68,7 +80,17 @@ static struct meson_clk_pll axg_sys_pll = {
|
||||||
.shift = 16,
|
.shift = 16,
|
||||||
.width = 2,
|
.width = 2,
|
||||||
},
|
},
|
||||||
.lock = &meson_clk_lock,
|
.l = {
|
||||||
|
.reg_off = HHI_SYS_PLL_CNTL,
|
||||||
|
.shift = 31,
|
||||||
|
.width = 1,
|
||||||
|
},
|
||||||
|
.rst = {
|
||||||
|
.reg_off = HHI_SYS_PLL_CNTL,
|
||||||
|
.shift = 29,
|
||||||
|
.width = 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
.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,16 +191,17 @@ 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 = {
|
||||||
|
.data = &(struct meson_clk_pll_data){
|
||||||
.m = {
|
.m = {
|
||||||
.reg_off = HHI_GP0_PLL_CNTL,
|
.reg_off = HHI_GP0_PLL_CNTL,
|
||||||
.shift = 0,
|
.shift = 0,
|
||||||
|
@ -194,15 +217,21 @@ static struct meson_clk_pll axg_gp0_pll = {
|
||||||
.shift = 16,
|
.shift = 16,
|
||||||
.width = 2,
|
.width = 2,
|
||||||
},
|
},
|
||||||
.params = {
|
.l = {
|
||||||
.params_table = axg_gp0_params_table,
|
.reg_off = HHI_GP0_PLL_CNTL,
|
||||||
.params_count = ARRAY_SIZE(axg_gp0_params_table),
|
.shift = 31,
|
||||||
.no_init_reset = true,
|
.width = 1,
|
||||||
.reset_lock_loop = true,
|
},
|
||||||
|
.rst = {
|
||||||
|
.reg_off = HHI_GP0_PLL_CNTL,
|
||||||
|
.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,
|
||||||
},
|
},
|
||||||
.rate_table = axg_gp0_pll_rate_table,
|
|
||||||
.rate_count = ARRAY_SIZE(axg_gp0_pll_rate_table),
|
|
||||||
.lock = &meson_clk_lock,
|
|
||||||
.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 = {
|
||||||
.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[] = {
|
||||||
&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 = {
|
||||||
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)
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
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 @@
|
||||||
|
|
||||||
#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;
|
n = meson_parm_read(clk->map, &pll->n);
|
||||||
reg = readl(pll->base + p->reg_off);
|
m = meson_parm_read(clk->map, &pll->m);
|
||||||
n = PARM_GET(p->width, p->shift, reg);
|
od = meson_parm_read(clk->map, &pll->od);
|
||||||
|
|
||||||
p = &pll->m;
|
if (MESON_PARM_APPLICABLE(&pll->od2))
|
||||||
reg = readl(pll->base + p->reg_off);
|
od2 = meson_parm_read(clk->map, &pll->od2);
|
||||||
m = PARM_GET(p->width, p->shift, reg);
|
|
||||||
|
|
||||||
p = &pll->od;
|
if (MESON_PARM_APPLICABLE(&pll->od3))
|
||||||
reg = readl(pll->base + p->reg_off);
|
od3 = meson_parm_read(clk->map, &pll->od3);
|
||||||
od = PARM_GET(p->width, p->shift, reg);
|
|
||||||
|
|
||||||
p = &pll->od2;
|
|
||||||
if (p->width) {
|
|
||||||
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,
|
||||||
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 *
|
||||||
|
meson_clk_get_pll_settings(const struct pll_rate_table *table,
|
||||||
unsigned long rate)
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int meson_clk_pll_wait_lock(struct clk_hw *hw)
|
||||||
|
{
|
||||||
|
struct clk_regmap *clk = to_clk_regmap(hw);
|
||||||
|
struct meson_clk_pll_data *pll = meson_clk_pll_data(clk);
|
||||||
|
int delay = pll->flags & CLK_MESON_PLL_LOCK_LOOP_RST ?
|
||||||
|
100 : 24000000;
|
||||||
|
|
||||||
|
do {
|
||||||
/* Specific wait loop for GXL/GXM GP0 PLL */
|
/* Specific wait loop for GXL/GXM GP0 PLL */
|
||||||
static int meson_clk_pll_wait_lock_reset(struct meson_clk_pll *pll,
|
if (pll->flags & CLK_MESON_PLL_LOCK_LOOP_RST) {
|
||||||
struct parm *p_n)
|
/* Procedure taken from the vendor kernel */
|
||||||
{
|
meson_parm_write(clk->map, &pll->rst, 1);
|
||||||
int delay = 100;
|
|
||||||
u32 reg;
|
|
||||||
|
|
||||||
while (delay > 0) {
|
|
||||||
reg = readl(pll->base + p_n->reg_off);
|
|
||||||
writel(reg | MESON_PLL_RESET, pll->base + p_n->reg_off);
|
|
||||||
udelay(10);
|
udelay(10);
|
||||||
writel(reg & ~MESON_PLL_RESET, pll->base + p_n->reg_off);
|
meson_parm_write(clk->map, &pll->rst, 0);
|
||||||
|
|
||||||
/* This delay comes from AMLogic tree clk-gp0-gxl driver */
|
|
||||||
mdelay(1);
|
mdelay(1);
|
||||||
|
|
||||||
reg = readl(pll->base + p_n->reg_off);
|
|
||||||
if (reg & MESON_PLL_LOCK)
|
|
||||||
return 0;
|
|
||||||
delay--;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Is the clock locked now ? */
|
||||||
|
if (meson_parm_read(clk->map, &pll->l))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
delay--;
|
||||||
|
} while (delay > 0);
|
||||||
|
|
||||||
return -ETIMEDOUT;
|
return -ETIMEDOUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int meson_clk_pll_wait_lock(struct meson_clk_pll *pll,
|
static void meson_clk_pll_init(struct clk_hw *hw)
|
||||||
struct parm *p_n)
|
|
||||||
{
|
{
|
||||||
int delay = 24000000;
|
struct clk_regmap *clk = to_clk_regmap(hw);
|
||||||
u32 reg;
|
struct meson_clk_pll_data *pll = meson_clk_pll_data(clk);
|
||||||
|
|
||||||
while (delay > 0) {
|
if (pll->init_count) {
|
||||||
reg = readl(pll->base + p_n->reg_off);
|
meson_parm_write(clk->map, &pll->rst, 1);
|
||||||
|
regmap_multi_reg_write(clk->map, pll->init_regs,
|
||||||
if (reg & MESON_PLL_LOCK)
|
pll->init_count);
|
||||||
return 0;
|
meson_parm_write(clk->map, &pll->rst, 0);
|
||||||
delay--;
|
|
||||||
}
|
}
|
||||||
return -ETIMEDOUT;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void meson_clk_pll_init_params(struct meson_clk_pll *pll)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0 ; i < pll->params.params_count ; ++i)
|
|
||||||
writel(pll->params.params_table[i].value,
|
|
||||||
pll->base + pll->params.params_table[i].reg_off);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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 */
|
meson_parm_write(clk->map, &pll->n, pllt->n);
|
||||||
p = &pll->n;
|
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);
|
||||||
/* 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);
|
if (MESON_PARM_APPLICABLE(&pll->od2))
|
||||||
writel(reg, pll->base + p->reg_off);
|
meson_parm_write(clk->map, &pll->od2, pllt->od2);
|
||||||
|
|
||||||
p = &pll->m;
|
if (MESON_PARM_APPLICABLE(&pll->od3))
|
||||||
reg = readl(pll->base + p->reg_off);
|
meson_parm_write(clk->map, &pll->od3, pllt->od3);
|
||||||
reg = PARM_SET(p->width, p->shift, reg, rate_set->m);
|
|
||||||
writel(reg, pll->base + p->reg_off);
|
|
||||||
|
|
||||||
p = &pll->od;
|
if (MESON_PARM_APPLICABLE(&pll->frac))
|
||||||
reg = readl(pll->base + p->reg_off);
|
meson_parm_write(clk->map, &pll->frac, pllt->frac);
|
||||||
reg = PARM_SET(p->width, p->shift, reg, rate_set->od);
|
|
||||||
writel(reg, pll->base + p->reg_off);
|
|
||||||
|
|
||||||
p = &pll->od2;
|
/* make sure the reset is cleared at this point */
|
||||||
if (p->width) {
|
meson_parm_write(clk->map, &pll->rst, 0);
|
||||||
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;
|
if (meson_clk_pll_wait_lock(hw)) {
|
||||||
if (p->width) {
|
|
||||||
reg = readl(pll->base + p->reg_off);
|
|
||||||
reg = PARM_SET(p->width, p->shift, reg, rate_set->od3);
|
|
||||||
writel(reg, pll->base + p->reg_off);
|
|
||||||
}
|
|
||||||
|
|
||||||
p = &pll->frac;
|
|
||||||
if (p->width) {
|
|
||||||
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 clear_reset_for_lock is provided, remove the reset bit here */
|
|
||||||
if (pll->params.clear_reset_for_lock) {
|
|
||||||
reg = readl(pll->base + p->reg_off);
|
|
||||||
writel(reg & ~MESON_PLL_RESET, pll->base + p->reg_off);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If reset_lock_loop, use a special loop including resetting */
|
|
||||||
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 {
|
||||||
.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) \
|
struct meson_clk_pll_data {
|
||||||
{ \
|
|
||||||
.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 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)
|
||||||
|
|
|
@ -188,7 +188,8 @@ static const struct pll_rate_table gxl_gp0_pll_rate_table[] = {
|
||||||
{ /* sentinel */ },
|
{ /* sentinel */ },
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct meson_clk_pll gxbb_fixed_pll = {
|
static struct clk_regmap gxbb_fixed_pll = {
|
||||||
|
.data = &(struct meson_clk_pll_data){
|
||||||
.m = {
|
.m = {
|
||||||
.reg_off = HHI_MPLL_CNTL,
|
.reg_off = HHI_MPLL_CNTL,
|
||||||
.shift = 0,
|
.shift = 0,
|
||||||
|
@ -209,7 +210,17 @@ static struct meson_clk_pll gxbb_fixed_pll = {
|
||||||
.shift = 0,
|
.shift = 0,
|
||||||
.width = 12,
|
.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,
|
||||||
|
@ -230,7 +241,8 @@ static struct clk_fixed_factor gxbb_hdmi_pll_pre_mult = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct meson_clk_pll gxbb_hdmi_pll = {
|
static struct clk_regmap gxbb_hdmi_pll = {
|
||||||
|
.data = &(struct meson_clk_pll_data){
|
||||||
.m = {
|
.m = {
|
||||||
.reg_off = HHI_HDMI_PLL_CNTL,
|
.reg_off = HHI_HDMI_PLL_CNTL,
|
||||||
.shift = 0,
|
.shift = 0,
|
||||||
|
@ -261,7 +273,17 @@ static struct meson_clk_pll gxbb_hdmi_pll = {
|
||||||
.shift = 18,
|
.shift = 18,
|
||||||
.width = 2,
|
.width = 2,
|
||||||
},
|
},
|
||||||
.lock = &meson_clk_lock,
|
.l = {
|
||||||
|
.reg_off = HHI_HDMI_PLL_CNTL,
|
||||||
|
.shift = 31,
|
||||||
|
.width = 1,
|
||||||
|
},
|
||||||
|
.rst = {
|
||||||
|
.reg_off = HHI_HDMI_PLL_CNTL,
|
||||||
|
.shift = 28,
|
||||||
|
.width = 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
.hw.init = &(struct clk_init_data){
|
.hw.init = &(struct clk_init_data){
|
||||||
.name = "hdmi_pll",
|
.name = "hdmi_pll",
|
||||||
.ops = &meson_clk_pll_ro_ops,
|
.ops = &meson_clk_pll_ro_ops,
|
||||||
|
@ -271,7 +293,8 @@ static struct meson_clk_pll gxbb_hdmi_pll = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct meson_clk_pll gxl_hdmi_pll = {
|
static struct clk_regmap gxl_hdmi_pll = {
|
||||||
|
.data = &(struct meson_clk_pll_data){
|
||||||
.m = {
|
.m = {
|
||||||
.reg_off = HHI_HDMI_PLL_CNTL,
|
.reg_off = HHI_HDMI_PLL_CNTL,
|
||||||
.shift = 0,
|
.shift = 0,
|
||||||
|
@ -284,9 +307,10 @@ static struct meson_clk_pll gxl_hdmi_pll = {
|
||||||
},
|
},
|
||||||
.frac = {
|
.frac = {
|
||||||
/*
|
/*
|
||||||
* On gxl, there is a register shift due to HHI_HDMI_PLL_CNTL1
|
* On gxl, there is a register shift due to
|
||||||
* which does not exist on gxbb, so we compute the register
|
* HHI_HDMI_PLL_CNTL1 which does not exist on gxbb,
|
||||||
* offset based on the PLL base to get it right
|
* so we compute the register offset based on the PLL
|
||||||
|
* base to get it right
|
||||||
*/
|
*/
|
||||||
.reg_off = HHI_HDMI_PLL_CNTL + 4,
|
.reg_off = HHI_HDMI_PLL_CNTL + 4,
|
||||||
.shift = 0,
|
.shift = 0,
|
||||||
|
@ -307,7 +331,17 @@ static struct meson_clk_pll gxl_hdmi_pll = {
|
||||||
.shift = 19,
|
.shift = 19,
|
||||||
.width = 2,
|
.width = 2,
|
||||||
},
|
},
|
||||||
.lock = &meson_clk_lock,
|
.l = {
|
||||||
|
.reg_off = HHI_HDMI_PLL_CNTL,
|
||||||
|
.shift = 31,
|
||||||
|
.width = 1,
|
||||||
|
},
|
||||||
|
.rst = {
|
||||||
|
.reg_off = HHI_HDMI_PLL_CNTL,
|
||||||
|
.shift = 29,
|
||||||
|
.width = 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
.hw.init = &(struct clk_init_data){
|
.hw.init = &(struct clk_init_data){
|
||||||
.name = "hdmi_pll",
|
.name = "hdmi_pll",
|
||||||
.ops = &meson_clk_pll_ro_ops,
|
.ops = &meson_clk_pll_ro_ops,
|
||||||
|
@ -317,7 +351,8 @@ static struct meson_clk_pll gxl_hdmi_pll = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct meson_clk_pll gxbb_sys_pll = {
|
static struct clk_regmap gxbb_sys_pll = {
|
||||||
|
.data = &(struct meson_clk_pll_data){
|
||||||
.m = {
|
.m = {
|
||||||
.reg_off = HHI_SYS_PLL_CNTL,
|
.reg_off = HHI_SYS_PLL_CNTL,
|
||||||
.shift = 0,
|
.shift = 0,
|
||||||
|
@ -333,7 +368,17 @@ static struct meson_clk_pll gxbb_sys_pll = {
|
||||||
.shift = 10,
|
.shift = 10,
|
||||||
.width = 2,
|
.width = 2,
|
||||||
},
|
},
|
||||||
.lock = &meson_clk_lock,
|
.l = {
|
||||||
|
.reg_off = HHI_SYS_PLL_CNTL,
|
||||||
|
.shift = 31,
|
||||||
|
.width = 1,
|
||||||
|
},
|
||||||
|
.rst = {
|
||||||
|
.reg_off = HHI_SYS_PLL_CNTL,
|
||||||
|
.shift = 29,
|
||||||
|
.width = 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
.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,
|
||||||
|
@ -343,14 +388,15 @@ static struct meson_clk_pll gxbb_sys_pll = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
struct pll_params_table gxbb_gp0_params_table[] = {
|
const struct reg_sequence gxbb_gp0_init_regs[] = {
|
||||||
PLL_PARAM(HHI_GP0_PLL_CNTL, 0x6a000228),
|
{ .reg = HHI_GP0_PLL_CNTL, .def = 0x6a000228 },
|
||||||
PLL_PARAM(HHI_GP0_PLL_CNTL2, 0x69c80000),
|
{ .reg = HHI_GP0_PLL_CNTL2, .def = 0x69c80000 },
|
||||||
PLL_PARAM(HHI_GP0_PLL_CNTL3, 0x0a5590c4),
|
{ .reg = HHI_GP0_PLL_CNTL3, .def = 0x0a5590c4 },
|
||||||
PLL_PARAM(HHI_GP0_PLL_CNTL4, 0x0000500d),
|
{ .reg = HHI_GP0_PLL_CNTL4, .def = 0x0000500d },
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct meson_clk_pll gxbb_gp0_pll = {
|
static struct clk_regmap gxbb_gp0_pll = {
|
||||||
|
.data = &(struct meson_clk_pll_data){
|
||||||
.m = {
|
.m = {
|
||||||
.reg_off = HHI_GP0_PLL_CNTL,
|
.reg_off = HHI_GP0_PLL_CNTL,
|
||||||
.shift = 0,
|
.shift = 0,
|
||||||
|
@ -366,15 +412,20 @@ static struct meson_clk_pll gxbb_gp0_pll = {
|
||||||
.shift = 16,
|
.shift = 16,
|
||||||
.width = 2,
|
.width = 2,
|
||||||
},
|
},
|
||||||
.params = {
|
.l = {
|
||||||
.params_table = gxbb_gp0_params_table,
|
.reg_off = HHI_GP0_PLL_CNTL,
|
||||||
.params_count = ARRAY_SIZE(gxbb_gp0_params_table),
|
.shift = 31,
|
||||||
.no_init_reset = true,
|
.width = 1,
|
||||||
.clear_reset_for_lock = true,
|
},
|
||||||
|
.rst = {
|
||||||
|
.reg_off = HHI_GP0_PLL_CNTL,
|
||||||
|
.shift = 29,
|
||||||
|
.width = 1,
|
||||||
|
},
|
||||||
|
.table = gxbb_gp0_pll_rate_table,
|
||||||
|
.init_regs = gxbb_gp0_init_regs,
|
||||||
|
.init_count = ARRAY_SIZE(gxbb_gp0_init_regs),
|
||||||
},
|
},
|
||||||
.rate_table = gxbb_gp0_pll_rate_table,
|
|
||||||
.rate_count = ARRAY_SIZE(gxbb_gp0_pll_rate_table),
|
|
||||||
.lock = &meson_clk_lock,
|
|
||||||
.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,
|
||||||
|
@ -384,16 +435,17 @@ static struct meson_clk_pll gxbb_gp0_pll = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
struct pll_params_table gxl_gp0_params_table[] = {
|
const struct reg_sequence gxl_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 gxl_gp0_pll = {
|
static struct clk_regmap gxl_gp0_pll = {
|
||||||
|
.data = &(struct meson_clk_pll_data){
|
||||||
.m = {
|
.m = {
|
||||||
.reg_off = HHI_GP0_PLL_CNTL,
|
.reg_off = HHI_GP0_PLL_CNTL,
|
||||||
.shift = 0,
|
.shift = 0,
|
||||||
|
@ -409,15 +461,21 @@ static struct meson_clk_pll gxl_gp0_pll = {
|
||||||
.shift = 16,
|
.shift = 16,
|
||||||
.width = 2,
|
.width = 2,
|
||||||
},
|
},
|
||||||
.params = {
|
.l = {
|
||||||
.params_table = gxl_gp0_params_table,
|
.reg_off = HHI_GP0_PLL_CNTL,
|
||||||
.params_count = ARRAY_SIZE(gxl_gp0_params_table),
|
.shift = 31,
|
||||||
.no_init_reset = true,
|
.width = 1,
|
||||||
.reset_lock_loop = true,
|
},
|
||||||
|
.rst = {
|
||||||
|
.reg_off = HHI_GP0_PLL_CNTL,
|
||||||
|
.shift = 29,
|
||||||
|
.width = 1,
|
||||||
|
},
|
||||||
|
.table = gxl_gp0_pll_rate_table,
|
||||||
|
.init_regs = gxl_gp0_init_regs,
|
||||||
|
.init_count = ARRAY_SIZE(gxl_gp0_init_regs),
|
||||||
|
.flags = CLK_MESON_PLL_LOCK_LOOP_RST,
|
||||||
},
|
},
|
||||||
.rate_table = gxl_gp0_pll_rate_table,
|
|
||||||
.rate_count = ARRAY_SIZE(gxl_gp0_pll_rate_table),
|
|
||||||
.lock = &meson_clk_lock,
|
|
||||||
.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,
|
||||||
|
@ -1762,20 +1820,14 @@ static struct clk_hw_onecell_data gxl_hw_onecell_data = {
|
||||||
.num = NR_CLKS,
|
.num = NR_CLKS,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Convenience tables to populate base addresses in .probe */
|
static struct clk_regmap *const gxbb_clk_regmaps[] = {
|
||||||
|
|
||||||
static struct meson_clk_pll *const gxbb_clk_plls[] = {
|
|
||||||
&gxbb_fixed_pll,
|
|
||||||
&gxbb_hdmi_pll,
|
|
||||||
&gxbb_sys_pll,
|
|
||||||
&gxbb_gp0_pll,
|
&gxbb_gp0_pll,
|
||||||
|
&gxbb_hdmi_pll,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct meson_clk_pll *const gxl_clk_plls[] = {
|
static struct clk_regmap *const gxl_clk_regmaps[] = {
|
||||||
&gxbb_fixed_pll,
|
|
||||||
&gxl_hdmi_pll,
|
|
||||||
&gxbb_sys_pll,
|
|
||||||
&gxl_gp0_pll,
|
&gxl_gp0_pll,
|
||||||
|
&gxl_hdmi_pll,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct clk_regmap *const gx_clk_regmaps[] = {
|
static struct clk_regmap *const gx_clk_regmaps[] = {
|
||||||
|
@ -1910,23 +1962,25 @@ static struct clk_regmap *const gx_clk_regmaps[] = {
|
||||||
&gxbb_mpll1,
|
&gxbb_mpll1,
|
||||||
&gxbb_mpll2,
|
&gxbb_mpll2,
|
||||||
&gxbb_cts_amclk_div,
|
&gxbb_cts_amclk_div,
|
||||||
|
&gxbb_fixed_pll,
|
||||||
|
&gxbb_sys_pll,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct clkc_data {
|
struct clkc_data {
|
||||||
struct meson_clk_pll *const *clk_plls;
|
struct clk_regmap *const *regmap_clks;
|
||||||
unsigned int clk_plls_count;
|
unsigned int regmap_clks_count;
|
||||||
struct clk_hw_onecell_data *hw_onecell_data;
|
struct clk_hw_onecell_data *hw_onecell_data;
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct clkc_data gxbb_clkc_data = {
|
static const struct clkc_data gxbb_clkc_data = {
|
||||||
.clk_plls = gxbb_clk_plls,
|
.regmap_clks = gxbb_clk_regmaps,
|
||||||
.clk_plls_count = ARRAY_SIZE(gxbb_clk_plls),
|
.regmap_clks_count = ARRAY_SIZE(gxbb_clk_regmaps),
|
||||||
.hw_onecell_data = &gxbb_hw_onecell_data,
|
.hw_onecell_data = &gxbb_hw_onecell_data,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct clkc_data gxl_clkc_data = {
|
static const struct clkc_data gxl_clkc_data = {
|
||||||
.clk_plls = gxl_clk_plls,
|
.regmap_clks = gxl_clk_regmaps,
|
||||||
.clk_plls_count = ARRAY_SIZE(gxl_clk_plls),
|
.regmap_clks_count = ARRAY_SIZE(gxl_clk_regmaps),
|
||||||
.hw_onecell_data = &gxl_hw_onecell_data,
|
.hw_onecell_data = &gxl_hw_onecell_data,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1969,14 +2023,14 @@ static int gxbb_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 common regmap backed clocks */
|
/* Populate regmap for the common regmap backed clocks */
|
||||||
for (i = 0; i < ARRAY_SIZE(gx_clk_regmaps); i++)
|
for (i = 0; i < ARRAY_SIZE(gx_clk_regmaps); i++)
|
||||||
gx_clk_regmaps[i]->map = map;
|
gx_clk_regmaps[i]->map = map;
|
||||||
|
|
||||||
|
/* Populate regmap for soc specific clocks */
|
||||||
|
for (i = 0; i < clkc_data->regmap_clks_count; i++)
|
||||||
|
clkc_data->regmap_clks[i]->map = map;
|
||||||
|
|
||||||
/* Register all clks */
|
/* Register all clks */
|
||||||
for (i = 0; i < clkc_data->hw_onecell_data->num; i++) {
|
for (i = 0; i < clkc_data->hw_onecell_data->num; i++) {
|
||||||
/* array might be sparse */
|
/* array might be sparse */
|
||||||
|
|
|
@ -122,7 +122,8 @@ static struct clk_fixed_rate meson8b_xtal = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct meson_clk_pll meson8b_fixed_pll = {
|
static struct clk_regmap meson8b_fixed_pll = {
|
||||||
|
.data = &(struct meson_clk_pll_data){
|
||||||
.m = {
|
.m = {
|
||||||
.reg_off = HHI_MPLL_CNTL,
|
.reg_off = HHI_MPLL_CNTL,
|
||||||
.shift = 0,
|
.shift = 0,
|
||||||
|
@ -138,7 +139,17 @@ static struct meson_clk_pll meson8b_fixed_pll = {
|
||||||
.shift = 16,
|
.shift = 16,
|
||||||
.width = 2,
|
.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,7 +159,8 @@ static struct meson_clk_pll meson8b_fixed_pll = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct meson_clk_pll meson8b_vid_pll = {
|
static struct clk_regmap meson8b_vid_pll = {
|
||||||
|
.data = &(struct meson_clk_pll_data){
|
||||||
.m = {
|
.m = {
|
||||||
.reg_off = HHI_VID_PLL_CNTL,
|
.reg_off = HHI_VID_PLL_CNTL,
|
||||||
.shift = 0,
|
.shift = 0,
|
||||||
|
@ -164,7 +176,17 @@ static struct meson_clk_pll meson8b_vid_pll = {
|
||||||
.shift = 16,
|
.shift = 16,
|
||||||
.width = 2,
|
.width = 2,
|
||||||
},
|
},
|
||||||
.lock = &meson_clk_lock,
|
.l = {
|
||||||
|
.reg_off = HHI_VID_PLL_CNTL,
|
||||||
|
.shift = 31,
|
||||||
|
.width = 1,
|
||||||
|
},
|
||||||
|
.rst = {
|
||||||
|
.reg_off = HHI_VID_PLL_CNTL,
|
||||||
|
.shift = 29,
|
||||||
|
.width = 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
.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,7 +196,8 @@ static struct meson_clk_pll meson8b_vid_pll = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct meson_clk_pll meson8b_sys_pll = {
|
static struct clk_regmap meson8b_sys_pll = {
|
||||||
|
.data = &(struct meson_clk_pll_data){
|
||||||
.m = {
|
.m = {
|
||||||
.reg_off = HHI_SYS_PLL_CNTL,
|
.reg_off = HHI_SYS_PLL_CNTL,
|
||||||
.shift = 0,
|
.shift = 0,
|
||||||
|
@ -190,9 +213,18 @@ static struct meson_clk_pll meson8b_sys_pll = {
|
||||||
.shift = 16,
|
.shift = 16,
|
||||||
.width = 2,
|
.width = 2,
|
||||||
},
|
},
|
||||||
.rate_table = sys_pll_rate_table,
|
.l = {
|
||||||
.rate_count = ARRAY_SIZE(sys_pll_rate_table),
|
.reg_off = HHI_SYS_PLL_CNTL,
|
||||||
.lock = &meson_clk_lock,
|
.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 = {
|
||||||
.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[] = {
|
||||||
&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)
|
||||||
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;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue