Skip to content

Commit 1afa948

Browse files
committed
clk: microchip: mpfs: split MSSPLL in two
The MSSPLL is really two stages - there's the PLL itself and 4 outputs, each with their own divider. The current driver models this as a single entity, outputting a single clock, used for both the CPU and AHB/AXI buses. The other 3 outputs are used for the eMMC, "user crypto" and CAN controller. Split the MSSPLL in two, as a precursor to adding support for the other 3 outputs, with the PLL itself as one "hw" clock and the output divider stage as another. Signed-off-by: Conor Dooley <[email protected]>
1 parent 8c2b1b4 commit 1afa948

File tree

1 file changed

+116
-58
lines changed

1 file changed

+116
-58
lines changed

drivers/clk/microchip/clk-mpfs.c

Lines changed: 116 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,13 @@
3030
#define MSSPLL_POSTDIV_WIDTH 0x07u
3131
#define MSSPLL_FIXED_DIV 4u
3232

33+
/*
34+
* This clock ID is defined here, rather than the binding headers, as it is an
35+
* internal clock only, and therefore has no consumers in other peripheral
36+
* blocks.
37+
*/
38+
#define CLK_MSSPLL_INTERNAL 38u
39+
3340
struct mpfs_clock_data {
3441
struct device *dev;
3542
void __iomem *base;
@@ -39,16 +46,26 @@ struct mpfs_clock_data {
3946

4047
struct mpfs_msspll_hw_clock {
4148
void __iomem *base;
49+
struct clk_hw hw;
50+
struct clk_init_data init;
4251
unsigned int id;
4352
u32 reg_offset;
4453
u32 shift;
4554
u32 width;
4655
u32 flags;
56+
};
57+
58+
#define to_mpfs_msspll_clk(_hw) container_of(_hw, struct mpfs_msspll_hw_clock, hw)
59+
60+
struct mpfs_msspll_out_hw_clock {
61+
void __iomem *base;
4762
struct clk_hw hw;
4863
struct clk_init_data init;
64+
unsigned int id;
65+
u32 flags;
4966
};
5067

51-
#define to_mpfs_msspll_clk(_hw) container_of(_hw, struct mpfs_msspll_hw_clock, hw)
68+
#define to_mpfs_msspll_out_clk(_hw) container_of(_hw, struct mpfs_msspll_out_hw_clock, hw)
5269

5370
struct mpfs_cfg_hw_clock {
5471
struct clk_divider cfg;
@@ -93,61 +110,99 @@ static const struct clk_div_table mpfs_div_rtcref_table[] = {
93110
{ 0, 0 }
94111
};
95112

113+
/*
114+
* MSS PLL internal clock
115+
*/
116+
96117
static unsigned long mpfs_clk_msspll_recalc_rate(struct clk_hw *hw, unsigned long prate)
97118
{
98119
struct mpfs_msspll_hw_clock *msspll_hw = to_mpfs_msspll_clk(hw);
99120
void __iomem *mult_addr = msspll_hw->base + msspll_hw->reg_offset;
100121
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;
122+
u32 mult, ref_div;
103123

104124
mult = readl_relaxed(mult_addr) >> MSSPLL_FBDIV_SHIFT;
105125
mult &= clk_div_mask(MSSPLL_FBDIV_WIDTH);
106126
ref_div = readl_relaxed(ref_div_addr) >> MSSPLL_REFDIV_SHIFT;
107127
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);
110128

111-
return prate * mult / (ref_div * MSSPLL_FIXED_DIV * postdiv);
129+
return prate * mult / (ref_div * MSSPLL_FIXED_DIV);
112130
}
113131

114-
static long mpfs_clk_msspll_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long *prate)
132+
static const struct clk_ops mpfs_clk_msspll_ops = {
133+
.recalc_rate = mpfs_clk_msspll_recalc_rate,
134+
};
135+
136+
#define CLK_PLL(_id, _name, _parent, _shift, _width, _flags, _offset) { \
137+
.id = _id, \
138+
.flags = _flags, \
139+
.shift = _shift, \
140+
.width = _width, \
141+
.reg_offset = _offset, \
142+
.hw.init = CLK_HW_INIT_PARENTS_DATA(_name, _parent, &mpfs_clk_msspll_ops, 0), \
143+
}
144+
145+
static struct mpfs_msspll_hw_clock mpfs_msspll_clks[] = {
146+
CLK_PLL(CLK_MSSPLL_INTERNAL, "clk_msspll_internal", mpfs_ext_ref, MSSPLL_FBDIV_SHIFT,
147+
MSSPLL_FBDIV_WIDTH, 0, REG_MSSPLL_SSCG_2_CR),
148+
};
149+
150+
static int mpfs_clk_register_mssplls(struct device *dev, struct mpfs_msspll_hw_clock *msspll_hws,
151+
unsigned int num_clks, struct mpfs_clock_data *data)
115152
{
116-
struct mpfs_msspll_hw_clock *msspll_hw = to_mpfs_msspll_clk(hw);
117-
void __iomem *mult_addr = msspll_hw->base + msspll_hw->reg_offset;
118-
void __iomem *ref_div_addr = msspll_hw->base + REG_MSSPLL_REF_CR;
119-
u32 mult, ref_div;
120-
unsigned long rate_before_ctrl;
153+
unsigned int i;
154+
int ret;
121155

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);
156+
for (i = 0; i < num_clks; i++) {
157+
struct mpfs_msspll_hw_clock *msspll_hw = &msspll_hws[i];
158+
159+
msspll_hw->base = data->msspll_base;
160+
ret = devm_clk_hw_register(dev, &msspll_hw->hw);
161+
if (ret)
162+
return dev_err_probe(dev, ret, "failed to register msspll id: %d\n",
163+
CLK_MSSPLL_INTERNAL);
126164

127-
rate_before_ctrl = rate * (ref_div * MSSPLL_FIXED_DIV) / mult;
165+
data->hw_data.hws[msspll_hw->id] = &msspll_hw->hw;
166+
}
128167

129-
return divider_round_rate(hw, rate_before_ctrl, prate, NULL, MSSPLL_POSTDIV_WIDTH,
130-
msspll_hw->flags);
168+
return 0;
131169
}
132170

133-
static int mpfs_clk_msspll_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long prate)
171+
/*
172+
* MSS PLL output clocks
173+
*/
174+
175+
static unsigned long mpfs_clk_msspll_out_recalc_rate(struct clk_hw *hw, unsigned long prate)
134176
{
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;
177+
struct mpfs_msspll_out_hw_clock *msspll_out_hw = to_mpfs_msspll_out_clk(hw);
178+
void __iomem *postdiv_addr = msspll_out_hw->base + REG_MSSPLL_POSTDIV_CR;
179+
u32 postdiv;
142180

143-
mult = readl_relaxed(mult_addr) >> MSSPLL_FBDIV_SHIFT;
144-
mult &= clk_div_mask(MSSPLL_FBDIV_WIDTH);
145-
ref_div = readl_relaxed(ref_div_addr) >> MSSPLL_REFDIV_SHIFT;
146-
ref_div &= clk_div_mask(MSSPLL_REFDIV_WIDTH);
181+
postdiv = readl_relaxed(postdiv_addr) >> MSSPLL_POSTDIV_SHIFT;
182+
postdiv &= clk_div_mask(MSSPLL_POSTDIV_WIDTH);
147183

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);
184+
return prate / postdiv;
185+
}
186+
187+
static long mpfs_clk_msspll_out_round_rate(struct clk_hw *hw, unsigned long rate,
188+
unsigned long *prate)
189+
{
190+
struct mpfs_msspll_out_hw_clock *msspll_out_hw = to_mpfs_msspll_out_clk(hw);
191+
192+
return divider_round_rate(hw, rate, prate, NULL, MSSPLL_POSTDIV_WIDTH,
193+
msspll_out_hw->flags);
194+
}
195+
196+
static int mpfs_clk_msspll_out_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long prate)
197+
{
198+
struct mpfs_msspll_out_hw_clock *msspll_out_hw = to_mpfs_msspll_out_clk(hw);
199+
void __iomem *postdiv_addr = msspll_out_hw->base + REG_MSSPLL_POSTDIV_CR;
200+
u32 postdiv;
201+
int divider_setting;
202+
unsigned long flags;
203+
204+
divider_setting = divider_get_val(rate, prate, NULL, MSSPLL_POSTDIV_WIDTH,
205+
msspll_out_hw->flags);
151206

152207
if (divider_setting < 0)
153208
return divider_setting;
@@ -163,42 +218,39 @@ static int mpfs_clk_msspll_set_rate(struct clk_hw *hw, unsigned long rate, unsig
163218
return 0;
164219
}
165220

166-
static const struct clk_ops mpfs_clk_msspll_ops = {
167-
.recalc_rate = mpfs_clk_msspll_recalc_rate,
168-
.round_rate = mpfs_clk_msspll_round_rate,
169-
.set_rate = mpfs_clk_msspll_set_rate,
221+
static const struct clk_ops mpfs_clk_msspll_out_ops = {
222+
.recalc_rate = mpfs_clk_msspll_out_recalc_rate,
223+
.round_rate = mpfs_clk_msspll_out_round_rate,
224+
.set_rate = mpfs_clk_msspll_out_set_rate,
170225
};
171226

172-
#define CLK_PLL(_id, _name, _parent, _shift, _width, _flags, _offset) { \
173-
.id = _id, \
174-
.shift = _shift, \
175-
.width = _width, \
176-
.reg_offset = _offset, \
177-
.flags = _flags, \
178-
.hw.init = CLK_HW_INIT_PARENTS_DATA(_name, _parent, &mpfs_clk_msspll_ops, 0), \
227+
#define CLK_PLL_OUT(_id, _name, _parent, _flags) { \
228+
.id = _id, \
229+
.flags = _flags, \
230+
.hw.init = CLK_HW_INIT(_name, _parent, &mpfs_clk_msspll_out_ops, 0), \
179231
}
180232

181-
static struct mpfs_msspll_hw_clock mpfs_msspll_clks[] = {
182-
CLK_PLL(CLK_MSSPLL, "clk_msspll", mpfs_ext_ref, MSSPLL_FBDIV_SHIFT,
183-
MSSPLL_FBDIV_WIDTH, 0, REG_MSSPLL_SSCG_2_CR),
233+
static struct mpfs_msspll_out_hw_clock mpfs_msspll_out_clks[] = {
234+
CLK_PLL_OUT(CLK_MSSPLL0, "clk_msspll", "clk_msspll_internal", 0),
184235
};
185236

186-
static int mpfs_clk_register_mssplls(struct device *dev, struct mpfs_msspll_hw_clock *msspll_hws,
187-
unsigned int num_clks, struct mpfs_clock_data *data)
237+
static int mpfs_clk_register_msspll_outs(struct device *dev,
238+
struct mpfs_msspll_out_hw_clock *msspll_out_hws,
239+
unsigned int num_clks, struct mpfs_clock_data *data)
188240
{
189241
unsigned int i;
190242
int ret;
191243

192244
for (i = 0; i < num_clks; i++) {
193-
struct mpfs_msspll_hw_clock *msspll_hw = &msspll_hws[i];
245+
struct mpfs_msspll_out_hw_clock *msspll_out_hw = &msspll_out_hws[i];
194246

195-
msspll_hw->base = data->msspll_base;
196-
ret = devm_clk_hw_register(dev, &msspll_hw->hw);
247+
msspll_out_hw->base = data->msspll_base;
248+
ret = devm_clk_hw_register(dev, &msspll_out_hw->hw);
197249
if (ret)
198-
return dev_err_probe(dev, ret, "failed to register msspll id: %d\n",
199-
CLK_MSSPLL);
250+
return dev_err_probe(dev, ret, "failed to register msspll out id: %d\n",
251+
msspll_out_hw->id);
200252

201-
data->hw_data.hws[msspll_hw->id] = &msspll_hw->hw;
253+
data->hw_data.hws[msspll_out_hw->id] = &msspll_out_hw->hw;
202254
}
203255

204256
return 0;
@@ -442,8 +494,8 @@ static int mpfs_clk_probe(struct platform_device *pdev)
442494
int ret;
443495

444496
/* 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;
497+
num_clks = ARRAY_SIZE(mpfs_msspll_clks) + ARRAY_SIZE(mpfs_msspll_out_clks)
498+
+ ARRAY_SIZE(mpfs_cfg_clks) + ARRAY_SIZE(mpfs_periph_clks) + 1;
447499

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

521+
ret = mpfs_clk_register_msspll_outs(dev, mpfs_msspll_out_clks,
522+
ARRAY_SIZE(mpfs_msspll_out_clks),
523+
clk_data);
524+
if (ret)
525+
return ret;
526+
469527
ret = mpfs_clk_register_cfgs(dev, mpfs_cfg_clks, ARRAY_SIZE(mpfs_cfg_clks), clk_data);
470528
if (ret)
471529
return ret;

0 commit comments

Comments
 (0)