Commit 7a1b0e9d authored by Stephen Boyd's avatar Stephen Boyd
Browse files

Merge tag 'clk-microchip-6.9' of...

Merge tag 'clk-microchip-6.9' of https://git.kernel.org/pub/scm/linux/kernel/git/at91/linux into clk-microchip

Pull Microchip clk driver updates from Claudiu Beznea:

Polarfire:
- MSSPLL hardware has 4 output clocks (the driver supported previously
  only one output); each of these 4 outputs feed dividers and the output
  of each divider feed individual hardware blocks (e.g. CAN, Crypto,
  eMMC); individual hardware block drivers need to control their clocks
  thus clock driver support was added for all MSSPLL output clocks.

* tag 'clk-microchip-6.9' of https://git.kernel.org/pub/scm/linux/kernel/git/at91/linux:
  clk: microchip: mpfs: convert MSSPLL outputs to clk_divider
  clk: microchip: mpfs: add missing MSSPLL outputs
  clk: microchip: mpfs: setup for using other mss pll outputs
  clk: microchip: mpfs: split MSSPLL in two
  dt-bindings: can: mpfs: add missing required clock
  dt-bindings: clock: mpfs: add more MSSPLL output definitions
parents 6613476e 72151193
Loading
Loading
Loading
Loading
+4 −2
Original line number Diff line number Diff line
@@ -24,7 +24,9 @@ properties:
    maxItems: 1

  clocks:
    maxItems: 1
    items:
      - description: AHB peripheral clock
      - description: CAN bus clock

required:
  - compatible
@@ -39,7 +41,7 @@ examples:
    can@2010c000 {
        compatible = "microchip,mpfs-can";
        reg = <0x2010c000 0x1000>;
        clocks = <&clkcfg 17>;
        clocks = <&clkcfg 17>, <&clkcfg 37>;
        interrupt-parent = <&plic>;
        interrupts = <56>;
    };
+87 −67
Original line number Diff line number Diff line
@@ -15,7 +15,8 @@

/* address offset of control registers */
#define REG_MSSPLL_REF_CR	0x08u
#define REG_MSSPLL_POSTDIV_CR	0x10u
#define REG_MSSPLL_POSTDIV01_CR	0x10u
#define REG_MSSPLL_POSTDIV23_CR	0x14u
#define REG_MSSPLL_SSCG_2_CR	0x2Cu
#define REG_CLOCK_CONFIG_CR	0x08u
#define REG_RTC_CLOCK_CR	0x0Cu
@@ -26,10 +27,18 @@
#define MSSPLL_FBDIV_WIDTH	0x0Cu
#define MSSPLL_REFDIV_SHIFT	0x08u
#define MSSPLL_REFDIV_WIDTH	0x06u
#define MSSPLL_POSTDIV_SHIFT	0x08u
#define MSSPLL_POSTDIV02_SHIFT	0x08u
#define MSSPLL_POSTDIV13_SHIFT	0x18u
#define MSSPLL_POSTDIV_WIDTH	0x07u
#define MSSPLL_FIXED_DIV	4u

/*
 * This clock ID is defined here, rather than the binding headers, as it is an
 * internal clock only, and therefore has no consumers in other peripheral
 * blocks.
 */
#define CLK_MSSPLL_INTERNAL	38u

struct mpfs_clock_data {
	struct device *dev;
	void __iomem *base;
@@ -39,17 +48,27 @@ struct mpfs_clock_data {

struct mpfs_msspll_hw_clock {
	void __iomem *base;
	struct clk_hw hw;
	struct clk_init_data init;
	unsigned int id;
	u32 reg_offset;
	u32 shift;
	u32 width;
	u32 flags;
	struct clk_hw hw;
	struct clk_init_data init;
};

#define to_mpfs_msspll_clk(_hw) container_of(_hw, struct mpfs_msspll_hw_clock, hw)

struct mpfs_msspll_out_hw_clock {
	void __iomem *base;
	struct clk_divider output;
	struct clk_init_data init;
	unsigned int id;
	u32 reg_offset;
};

#define to_mpfs_msspll_out_clk(_hw) container_of(_hw, struct mpfs_msspll_out_hw_clock, hw)

struct mpfs_cfg_hw_clock {
	struct clk_divider cfg;
	struct clk_init_data init;
@@ -93,93 +112,40 @@ static const struct clk_div_table mpfs_div_rtcref_table[] = {
	{ 0, 0 }
};

static unsigned long mpfs_clk_msspll_recalc_rate(struct clk_hw *hw, unsigned long prate)
{
	struct mpfs_msspll_hw_clock *msspll_hw = to_mpfs_msspll_clk(hw);
	void __iomem *mult_addr = msspll_hw->base + msspll_hw->reg_offset;
	void __iomem *ref_div_addr = msspll_hw->base + REG_MSSPLL_REF_CR;
	void __iomem *postdiv_addr = msspll_hw->base + REG_MSSPLL_POSTDIV_CR;
	u32 mult, ref_div, postdiv;

	mult = readl_relaxed(mult_addr) >> MSSPLL_FBDIV_SHIFT;
	mult &= clk_div_mask(MSSPLL_FBDIV_WIDTH);
	ref_div = readl_relaxed(ref_div_addr) >> MSSPLL_REFDIV_SHIFT;
	ref_div &= clk_div_mask(MSSPLL_REFDIV_WIDTH);
	postdiv = readl_relaxed(postdiv_addr) >> MSSPLL_POSTDIV_SHIFT;
	postdiv &= clk_div_mask(MSSPLL_POSTDIV_WIDTH);

	return prate * mult / (ref_div * MSSPLL_FIXED_DIV * postdiv);
}
/*
 * MSS PLL internal clock
 */

static long mpfs_clk_msspll_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long *prate)
static unsigned long mpfs_clk_msspll_recalc_rate(struct clk_hw *hw, unsigned long prate)
{
	struct mpfs_msspll_hw_clock *msspll_hw = to_mpfs_msspll_clk(hw);
	void __iomem *mult_addr = msspll_hw->base + msspll_hw->reg_offset;
	void __iomem *ref_div_addr = msspll_hw->base + REG_MSSPLL_REF_CR;
	u32 mult, ref_div;
	unsigned long rate_before_ctrl;

	mult = readl_relaxed(mult_addr) >> MSSPLL_FBDIV_SHIFT;
	mult &= clk_div_mask(MSSPLL_FBDIV_WIDTH);
	ref_div = readl_relaxed(ref_div_addr) >> MSSPLL_REFDIV_SHIFT;
	ref_div &= clk_div_mask(MSSPLL_REFDIV_WIDTH);

	rate_before_ctrl = rate * (ref_div * MSSPLL_FIXED_DIV) / mult;

	return divider_round_rate(hw, rate_before_ctrl, prate, NULL, MSSPLL_POSTDIV_WIDTH,
				  msspll_hw->flags);
}

static int mpfs_clk_msspll_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long prate)
{
	struct mpfs_msspll_hw_clock *msspll_hw = to_mpfs_msspll_clk(hw);
	void __iomem *mult_addr = msspll_hw->base + msspll_hw->reg_offset;
	void __iomem *ref_div_addr = msspll_hw->base + REG_MSSPLL_REF_CR;
	void __iomem *postdiv_addr = msspll_hw->base + REG_MSSPLL_POSTDIV_CR;
	u32 mult, ref_div, postdiv;
	int divider_setting;
	unsigned long rate_before_ctrl, flags;

	mult = readl_relaxed(mult_addr) >> MSSPLL_FBDIV_SHIFT;
	mult &= clk_div_mask(MSSPLL_FBDIV_WIDTH);
	ref_div = readl_relaxed(ref_div_addr) >> MSSPLL_REFDIV_SHIFT;
	ref_div &= clk_div_mask(MSSPLL_REFDIV_WIDTH);

	rate_before_ctrl = rate * (ref_div * MSSPLL_FIXED_DIV) / mult;
	divider_setting = divider_get_val(rate_before_ctrl, prate, NULL, MSSPLL_POSTDIV_WIDTH,
					  msspll_hw->flags);

	if (divider_setting < 0)
		return divider_setting;

	spin_lock_irqsave(&mpfs_clk_lock, flags);

	postdiv = readl_relaxed(postdiv_addr);
	postdiv &= ~(clk_div_mask(MSSPLL_POSTDIV_WIDTH) << MSSPLL_POSTDIV_SHIFT);
	writel_relaxed(postdiv, postdiv_addr);

	spin_unlock_irqrestore(&mpfs_clk_lock, flags);

	return 0;
	return prate * mult / (ref_div * MSSPLL_FIXED_DIV);
}

static const struct clk_ops mpfs_clk_msspll_ops = {
	.recalc_rate = mpfs_clk_msspll_recalc_rate,
	.round_rate = mpfs_clk_msspll_round_rate,
	.set_rate = mpfs_clk_msspll_set_rate,
};

#define CLK_PLL(_id, _name, _parent, _shift, _width, _flags, _offset) {			\
	.id = _id,									\
	.flags = _flags,								\
	.shift = _shift,								\
	.width = _width,								\
	.reg_offset = _offset,								\
	.flags = _flags,								\
	.hw.init = CLK_HW_INIT_PARENTS_DATA(_name, _parent, &mpfs_clk_msspll_ops, 0),	\
}

static struct mpfs_msspll_hw_clock mpfs_msspll_clks[] = {
	CLK_PLL(CLK_MSSPLL, "clk_msspll", mpfs_ext_ref, MSSPLL_FBDIV_SHIFT,
	CLK_PLL(CLK_MSSPLL_INTERNAL, "clk_msspll_internal", mpfs_ext_ref, MSSPLL_FBDIV_SHIFT,
		MSSPLL_FBDIV_WIDTH, 0, REG_MSSPLL_SSCG_2_CR),
};

@@ -196,7 +162,7 @@ static int mpfs_clk_register_mssplls(struct device *dev, struct mpfs_msspll_hw_c
		ret = devm_clk_hw_register(dev, &msspll_hw->hw);
		if (ret)
			return dev_err_probe(dev, ret, "failed to register msspll id: %d\n",
					     CLK_MSSPLL);
					     CLK_MSSPLL_INTERNAL);

		data->hw_data.hws[msspll_hw->id] = &msspll_hw->hw;
	}
@@ -204,6 +170,54 @@ static int mpfs_clk_register_mssplls(struct device *dev, struct mpfs_msspll_hw_c
	return 0;
}

/*
 * MSS PLL output clocks
 */

#define CLK_PLL_OUT(_id, _name, _parent, _flags, _shift, _width, _offset) {	\
	.id = _id,								\
	.output.shift = _shift,							\
	.output.width = _width,							\
	.output.table = NULL,							\
	.reg_offset = _offset,							\
	.output.flags = _flags,							\
	.output.hw.init = CLK_HW_INIT(_name, _parent, &clk_divider_ops, 0),	\
	.output.lock = &mpfs_clk_lock,						\
}

static struct mpfs_msspll_out_hw_clock mpfs_msspll_out_clks[] = {
	CLK_PLL_OUT(CLK_MSSPLL0, "clk_msspll", "clk_msspll_internal", CLK_DIVIDER_ONE_BASED,
		    MSSPLL_POSTDIV02_SHIFT, MSSPLL_POSTDIV_WIDTH, REG_MSSPLL_POSTDIV01_CR),
	CLK_PLL_OUT(CLK_MSSPLL1, "clk_msspll1", "clk_msspll_internal", CLK_DIVIDER_ONE_BASED,
		    MSSPLL_POSTDIV13_SHIFT, MSSPLL_POSTDIV_WIDTH, REG_MSSPLL_POSTDIV01_CR),
	CLK_PLL_OUT(CLK_MSSPLL2, "clk_msspll2", "clk_msspll_internal", CLK_DIVIDER_ONE_BASED,
		    MSSPLL_POSTDIV02_SHIFT, MSSPLL_POSTDIV_WIDTH, REG_MSSPLL_POSTDIV23_CR),
	CLK_PLL_OUT(CLK_MSSPLL3, "clk_msspll3", "clk_msspll_internal", CLK_DIVIDER_ONE_BASED,
		    MSSPLL_POSTDIV13_SHIFT, MSSPLL_POSTDIV_WIDTH, REG_MSSPLL_POSTDIV23_CR),
};

static int mpfs_clk_register_msspll_outs(struct device *dev,
					 struct mpfs_msspll_out_hw_clock *msspll_out_hws,
					 unsigned int num_clks, struct mpfs_clock_data *data)
{
	unsigned int i;
	int ret;

	for (i = 0; i < num_clks; i++) {
		struct mpfs_msspll_out_hw_clock *msspll_out_hw = &msspll_out_hws[i];

		msspll_out_hw->output.reg = data->msspll_base + msspll_out_hw->reg_offset;
		ret = devm_clk_hw_register(dev, &msspll_out_hw->output.hw);
		if (ret)
			return dev_err_probe(dev, ret, "failed to register msspll out id: %d\n",
					     msspll_out_hw->id);

		data->hw_data.hws[msspll_out_hw->id] = &msspll_out_hw->output.hw;
	}

	return 0;
}

/*
 * "CFG" clocks
 */
@@ -442,8 +456,8 @@ static int mpfs_clk_probe(struct platform_device *pdev)
	int ret;

	/* CLK_RESERVED is not part of clock arrays, so add 1 */
	num_clks = ARRAY_SIZE(mpfs_msspll_clks) + ARRAY_SIZE(mpfs_cfg_clks)
		   + ARRAY_SIZE(mpfs_periph_clks) + 1;
	num_clks = ARRAY_SIZE(mpfs_msspll_clks) + ARRAY_SIZE(mpfs_msspll_out_clks)
		   + ARRAY_SIZE(mpfs_cfg_clks)  + ARRAY_SIZE(mpfs_periph_clks) + 1;

	clk_data = devm_kzalloc(dev, struct_size(clk_data, hw_data.hws, num_clks), GFP_KERNEL);
	if (!clk_data)
@@ -466,6 +480,12 @@ static int mpfs_clk_probe(struct platform_device *pdev)
	if (ret)
		return ret;

	ret = mpfs_clk_register_msspll_outs(dev, mpfs_msspll_out_clks,
					    ARRAY_SIZE(mpfs_msspll_out_clks),
					    clk_data);
	if (ret)
		return ret;

	ret = mpfs_clk_register_cfgs(dev, mpfs_cfg_clks, ARRAY_SIZE(mpfs_cfg_clks), clk_data);
	if (ret)
		return ret;
+5 −0
Original line number Diff line number Diff line
@@ -44,6 +44,11 @@

#define CLK_RTCREF	33
#define CLK_MSSPLL	34
#define CLK_MSSPLL0	34
#define CLK_MSSPLL1	35
#define CLK_MSSPLL2	36
#define CLK_MSSPLL3	37
/* 38 is reserved for MSS PLL internals */

/* Clock Conditioning Circuitry Clock IDs */