mirror of
https://github.com/torvalds/linux.git
synced 2026-05-23 22:52:19 +02:00
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:
commit
7a1b0e9d81
|
|
@ -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>;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user