Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+108 −105
Original line number Original line Diff line number Diff line
@@ -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 = {
+93 −150
Original line number Original line Diff line number Diff line
@@ -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,
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;
}
}


/* 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 ?
		100 : 24000000;


	while (delay > 0) {
	do {
		reg = readl(pll->base + p_n->reg_off);
		/* 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 */
			meson_parm_write(clk->map, &pll->rst, 1);
			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--;
	}
	return -ETIMEDOUT;
		}
		}


static int meson_clk_pll_wait_lock(struct meson_clk_pll *pll,
		/* Is the clock locked now ? */
				   struct parm *p_n)
		if (meson_parm_read(clk->map, &pll->l))
{
	int delay = 24000000;
	u32 reg;

	while (delay > 0) {
		reg = readl(pll->base + p_n->reg_off);

		if (reg & MESON_PLL_LOCK)
			return 0;
			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)
	if (pll->init_count) {
		writel(pll->params.params_table[i].value,
		meson_parm_write(clk->map, &pll->rst, 1);
		       pll->base + pll->params.params_table[i].reg_off);
		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);
	}


	/* If reset_lock_loop, use a special loop including resetting */
	/* make sure the reset is cleared at this point */
	if (pll->params.reset_lock_loop)
	meson_parm_write(clk->map, &pll->rst, 0);
		ret = meson_clk_pll_wait_lock_reset(pll, p);

	else
	if (meson_clk_pll_wait_lock(hw)) {
		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,
+8 −28
Original line number Original line Diff line number Diff line
@@ -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)
+239 −185
Original line number Original line Diff line number Diff line
@@ -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 */
+87 −62
Original line number Original line Diff line number Diff line
@@ -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;