Microchip clock updates for v6.9

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 there clocks
   thus clock driver support was added for all MSSPLL output clocks.
 -----BEGIN PGP SIGNATURE-----
 
 iHUEABYIAB0WIQTsZ8eserC1pmhwqDmejrg/N2X7/QUCZeq6CgAKCRCejrg/N2X7
 /bCeAP0V3t0Hq/6spRqBHpPELN89xBGGNNOicUgbQRO7DbO+jgEAjynG5b7m4a7O
 uENJezIxboPEsl59wkhHCR4u7mfS1Ak=
 =oSTT
 -----END PGP SIGNATURE-----

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
This commit is contained in:
Stephen Boyd 2024-03-08 16:42:40 -08:00
commit 7a1b0e9d81
3 changed files with 96 additions and 69 deletions

View File

@ -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>;
};

View File

@ -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 }
};
/*
* MSS PLL internal clock
*/
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);
}
static long mpfs_clk_msspll_round_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;
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;

View File

@ -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 */