Skip to content

Commit 7a1b0e9

Browse files
committed
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
2 parents 6613476 + 7215119 commit 7a1b0e9

File tree

3 files changed

+96
-69
lines changed

3 files changed

+96
-69
lines changed

Documentation/devicetree/bindings/net/can/microchip,mpfs-can.yaml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@ properties:
2424
maxItems: 1
2525

2626
clocks:
27-
maxItems: 1
27+
items:
28+
- description: AHB peripheral clock
29+
- description: CAN bus clock
2830

2931
required:
3032
- compatible
@@ -39,7 +41,7 @@ examples:
3941
can@2010c000 {
4042
compatible = "microchip,mpfs-can";
4143
reg = <0x2010c000 0x1000>;
42-
clocks = <&clkcfg 17>;
44+
clocks = <&clkcfg 17>, <&clkcfg 37>;
4345
interrupt-parent = <&plic>;
4446
interrupts = <56>;
4547
};

drivers/clk/microchip/clk-mpfs.c

Lines changed: 87 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@
1515

1616
/* address offset of control registers */
1717
#define REG_MSSPLL_REF_CR 0x08u
18-
#define REG_MSSPLL_POSTDIV_CR 0x10u
18+
#define REG_MSSPLL_POSTDIV01_CR 0x10u
19+
#define REG_MSSPLL_POSTDIV23_CR 0x14u
1920
#define REG_MSSPLL_SSCG_2_CR 0x2Cu
2021
#define REG_CLOCK_CONFIG_CR 0x08u
2122
#define REG_RTC_CLOCK_CR 0x0Cu
@@ -26,10 +27,18 @@
2627
#define MSSPLL_FBDIV_WIDTH 0x0Cu
2728
#define MSSPLL_REFDIV_SHIFT 0x08u
2829
#define MSSPLL_REFDIV_WIDTH 0x06u
29-
#define MSSPLL_POSTDIV_SHIFT 0x08u
30+
#define MSSPLL_POSTDIV02_SHIFT 0x08u
31+
#define MSSPLL_POSTDIV13_SHIFT 0x18u
3032
#define MSSPLL_POSTDIV_WIDTH 0x07u
3133
#define MSSPLL_FIXED_DIV 4u
3234

35+
/*
36+
* This clock ID is defined here, rather than the binding headers, as it is an
37+
* internal clock only, and therefore has no consumers in other peripheral
38+
* blocks.
39+
*/
40+
#define CLK_MSSPLL_INTERNAL 38u
41+
3342
struct mpfs_clock_data {
3443
struct device *dev;
3544
void __iomem *base;
@@ -39,17 +48,27 @@ struct mpfs_clock_data {
3948

4049
struct mpfs_msspll_hw_clock {
4150
void __iomem *base;
51+
struct clk_hw hw;
52+
struct clk_init_data init;
4253
unsigned int id;
4354
u32 reg_offset;
4455
u32 shift;
4556
u32 width;
4657
u32 flags;
47-
struct clk_hw hw;
48-
struct clk_init_data init;
4958
};
5059

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

62+
struct mpfs_msspll_out_hw_clock {
63+
void __iomem *base;
64+
struct clk_divider output;
65+
struct clk_init_data init;
66+
unsigned int id;
67+
u32 reg_offset;
68+
};
69+
70+
#define to_mpfs_msspll_out_clk(_hw) container_of(_hw, struct mpfs_msspll_out_hw_clock, hw)
71+
5372
struct mpfs_cfg_hw_clock {
5473
struct clk_divider cfg;
5574
struct clk_init_data init;
@@ -93,93 +112,40 @@ static const struct clk_div_table mpfs_div_rtcref_table[] = {
93112
{ 0, 0 }
94113
};
95114

96-
static unsigned long mpfs_clk_msspll_recalc_rate(struct clk_hw *hw, unsigned long prate)
97-
{
98-
struct mpfs_msspll_hw_clock *msspll_hw = to_mpfs_msspll_clk(hw);
99-
void __iomem *mult_addr = msspll_hw->base + msspll_hw->reg_offset;
100-
void __iomem *ref_div_addr = msspll_hw->base + REG_MSSPLL_REF_CR;
101-
void __iomem *postdiv_addr = msspll_hw->base + REG_MSSPLL_POSTDIV_CR;
102-
u32 mult, ref_div, postdiv;
103-
104-
mult = readl_relaxed(mult_addr) >> MSSPLL_FBDIV_SHIFT;
105-
mult &= clk_div_mask(MSSPLL_FBDIV_WIDTH);
106-
ref_div = readl_relaxed(ref_div_addr) >> MSSPLL_REFDIV_SHIFT;
107-
ref_div &= clk_div_mask(MSSPLL_REFDIV_WIDTH);
108-
postdiv = readl_relaxed(postdiv_addr) >> MSSPLL_POSTDIV_SHIFT;
109-
postdiv &= clk_div_mask(MSSPLL_POSTDIV_WIDTH);
110-
111-
return prate * mult / (ref_div * MSSPLL_FIXED_DIV * postdiv);
112-
}
115+
/*
116+
* MSS PLL internal clock
117+
*/
113118

114-
static long mpfs_clk_msspll_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long *prate)
119+
static unsigned long mpfs_clk_msspll_recalc_rate(struct clk_hw *hw, unsigned long prate)
115120
{
116121
struct mpfs_msspll_hw_clock *msspll_hw = to_mpfs_msspll_clk(hw);
117122
void __iomem *mult_addr = msspll_hw->base + msspll_hw->reg_offset;
118123
void __iomem *ref_div_addr = msspll_hw->base + REG_MSSPLL_REF_CR;
119124
u32 mult, ref_div;
120-
unsigned long rate_before_ctrl;
121-
122-
mult = readl_relaxed(mult_addr) >> MSSPLL_FBDIV_SHIFT;
123-
mult &= clk_div_mask(MSSPLL_FBDIV_WIDTH);
124-
ref_div = readl_relaxed(ref_div_addr) >> MSSPLL_REFDIV_SHIFT;
125-
ref_div &= clk_div_mask(MSSPLL_REFDIV_WIDTH);
126-
127-
rate_before_ctrl = rate * (ref_div * MSSPLL_FIXED_DIV) / mult;
128-
129-
return divider_round_rate(hw, rate_before_ctrl, prate, NULL, MSSPLL_POSTDIV_WIDTH,
130-
msspll_hw->flags);
131-
}
132-
133-
static int mpfs_clk_msspll_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long prate)
134-
{
135-
struct mpfs_msspll_hw_clock *msspll_hw = to_mpfs_msspll_clk(hw);
136-
void __iomem *mult_addr = msspll_hw->base + msspll_hw->reg_offset;
137-
void __iomem *ref_div_addr = msspll_hw->base + REG_MSSPLL_REF_CR;
138-
void __iomem *postdiv_addr = msspll_hw->base + REG_MSSPLL_POSTDIV_CR;
139-
u32 mult, ref_div, postdiv;
140-
int divider_setting;
141-
unsigned long rate_before_ctrl, flags;
142125

143126
mult = readl_relaxed(mult_addr) >> MSSPLL_FBDIV_SHIFT;
144127
mult &= clk_div_mask(MSSPLL_FBDIV_WIDTH);
145128
ref_div = readl_relaxed(ref_div_addr) >> MSSPLL_REFDIV_SHIFT;
146129
ref_div &= clk_div_mask(MSSPLL_REFDIV_WIDTH);
147130

148-
rate_before_ctrl = rate * (ref_div * MSSPLL_FIXED_DIV) / mult;
149-
divider_setting = divider_get_val(rate_before_ctrl, prate, NULL, MSSPLL_POSTDIV_WIDTH,
150-
msspll_hw->flags);
151-
152-
if (divider_setting < 0)
153-
return divider_setting;
154-
155-
spin_lock_irqsave(&mpfs_clk_lock, flags);
156-
157-
postdiv = readl_relaxed(postdiv_addr);
158-
postdiv &= ~(clk_div_mask(MSSPLL_POSTDIV_WIDTH) << MSSPLL_POSTDIV_SHIFT);
159-
writel_relaxed(postdiv, postdiv_addr);
160-
161-
spin_unlock_irqrestore(&mpfs_clk_lock, flags);
162-
163-
return 0;
131+
return prate * mult / (ref_div * MSSPLL_FIXED_DIV);
164132
}
165133

166134
static const struct clk_ops mpfs_clk_msspll_ops = {
167135
.recalc_rate = mpfs_clk_msspll_recalc_rate,
168-
.round_rate = mpfs_clk_msspll_round_rate,
169-
.set_rate = mpfs_clk_msspll_set_rate,
170136
};
171137

172138
#define CLK_PLL(_id, _name, _parent, _shift, _width, _flags, _offset) { \
173139
.id = _id, \
140+
.flags = _flags, \
174141
.shift = _shift, \
175142
.width = _width, \
176143
.reg_offset = _offset, \
177-
.flags = _flags, \
178144
.hw.init = CLK_HW_INIT_PARENTS_DATA(_name, _parent, &mpfs_clk_msspll_ops, 0), \
179145
}
180146

181147
static struct mpfs_msspll_hw_clock mpfs_msspll_clks[] = {
182-
CLK_PLL(CLK_MSSPLL, "clk_msspll", mpfs_ext_ref, MSSPLL_FBDIV_SHIFT,
148+
CLK_PLL(CLK_MSSPLL_INTERNAL, "clk_msspll_internal", mpfs_ext_ref, MSSPLL_FBDIV_SHIFT,
183149
MSSPLL_FBDIV_WIDTH, 0, REG_MSSPLL_SSCG_2_CR),
184150
};
185151

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

201167
data->hw_data.hws[msspll_hw->id] = &msspll_hw->hw;
202168
}
203169

204170
return 0;
205171
}
206172

173+
/*
174+
* MSS PLL output clocks
175+
*/
176+
177+
#define CLK_PLL_OUT(_id, _name, _parent, _flags, _shift, _width, _offset) { \
178+
.id = _id, \
179+
.output.shift = _shift, \
180+
.output.width = _width, \
181+
.output.table = NULL, \
182+
.reg_offset = _offset, \
183+
.output.flags = _flags, \
184+
.output.hw.init = CLK_HW_INIT(_name, _parent, &clk_divider_ops, 0), \
185+
.output.lock = &mpfs_clk_lock, \
186+
}
187+
188+
static struct mpfs_msspll_out_hw_clock mpfs_msspll_out_clks[] = {
189+
CLK_PLL_OUT(CLK_MSSPLL0, "clk_msspll", "clk_msspll_internal", CLK_DIVIDER_ONE_BASED,
190+
MSSPLL_POSTDIV02_SHIFT, MSSPLL_POSTDIV_WIDTH, REG_MSSPLL_POSTDIV01_CR),
191+
CLK_PLL_OUT(CLK_MSSPLL1, "clk_msspll1", "clk_msspll_internal", CLK_DIVIDER_ONE_BASED,
192+
MSSPLL_POSTDIV13_SHIFT, MSSPLL_POSTDIV_WIDTH, REG_MSSPLL_POSTDIV01_CR),
193+
CLK_PLL_OUT(CLK_MSSPLL2, "clk_msspll2", "clk_msspll_internal", CLK_DIVIDER_ONE_BASED,
194+
MSSPLL_POSTDIV02_SHIFT, MSSPLL_POSTDIV_WIDTH, REG_MSSPLL_POSTDIV23_CR),
195+
CLK_PLL_OUT(CLK_MSSPLL3, "clk_msspll3", "clk_msspll_internal", CLK_DIVIDER_ONE_BASED,
196+
MSSPLL_POSTDIV13_SHIFT, MSSPLL_POSTDIV_WIDTH, REG_MSSPLL_POSTDIV23_CR),
197+
};
198+
199+
static int mpfs_clk_register_msspll_outs(struct device *dev,
200+
struct mpfs_msspll_out_hw_clock *msspll_out_hws,
201+
unsigned int num_clks, struct mpfs_clock_data *data)
202+
{
203+
unsigned int i;
204+
int ret;
205+
206+
for (i = 0; i < num_clks; i++) {
207+
struct mpfs_msspll_out_hw_clock *msspll_out_hw = &msspll_out_hws[i];
208+
209+
msspll_out_hw->output.reg = data->msspll_base + msspll_out_hw->reg_offset;
210+
ret = devm_clk_hw_register(dev, &msspll_out_hw->output.hw);
211+
if (ret)
212+
return dev_err_probe(dev, ret, "failed to register msspll out id: %d\n",
213+
msspll_out_hw->id);
214+
215+
data->hw_data.hws[msspll_out_hw->id] = &msspll_out_hw->output.hw;
216+
}
217+
218+
return 0;
219+
}
220+
207221
/*
208222
* "CFG" clocks
209223
*/
@@ -442,8 +456,8 @@ static int mpfs_clk_probe(struct platform_device *pdev)
442456
int ret;
443457

444458
/* CLK_RESERVED is not part of clock arrays, so add 1 */
445-
num_clks = ARRAY_SIZE(mpfs_msspll_clks) + ARRAY_SIZE(mpfs_cfg_clks)
446-
+ ARRAY_SIZE(mpfs_periph_clks) + 1;
459+
num_clks = ARRAY_SIZE(mpfs_msspll_clks) + ARRAY_SIZE(mpfs_msspll_out_clks)
460+
+ ARRAY_SIZE(mpfs_cfg_clks) + ARRAY_SIZE(mpfs_periph_clks) + 1;
447461

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

483+
ret = mpfs_clk_register_msspll_outs(dev, mpfs_msspll_out_clks,
484+
ARRAY_SIZE(mpfs_msspll_out_clks),
485+
clk_data);
486+
if (ret)
487+
return ret;
488+
469489
ret = mpfs_clk_register_cfgs(dev, mpfs_cfg_clks, ARRAY_SIZE(mpfs_cfg_clks), clk_data);
470490
if (ret)
471491
return ret;

include/dt-bindings/clock/microchip,mpfs-clock.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,11 @@
4444

4545
#define CLK_RTCREF 33
4646
#define CLK_MSSPLL 34
47+
#define CLK_MSSPLL0 34
48+
#define CLK_MSSPLL1 35
49+
#define CLK_MSSPLL2 36
50+
#define CLK_MSSPLL3 37
51+
/* 38 is reserved for MSS PLL internals */
4752

4853
/* Clock Conditioning Circuitry Clock IDs */
4954

0 commit comments

Comments
 (0)