1 // SPDX-License-Identifier: GPL-2.0
3 * MVEBU Core divider clock
5 * Copyright (C) 2013 Marvell
7 * Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
11 #include <linux/kernel.h>
12 #include <linux/clk-provider.h>
14 #include <linux/of_address.h>
15 #include <linux/slab.h>
16 #include <linux/delay.h>
19 #define CORE_CLK_DIV_RATIO_MASK 0xff
22 * This structure describes the hardware details (bit offset and mask)
23 * to configure one particular core divider clock. Those hardware
24 * details may differ from one SoC to another. This structure is
25 * therefore typically instantiated statically to describe the
28 struct clk_corediv_desc
{
31 unsigned int fieldbit
;
35 * This structure describes the hardware details to configure the core
36 * divider clocks on a given SoC. Amongst others, it points to the
37 * array of core divider clock descriptors for this SoC, as well as
38 * the corresponding operations to manipulate them.
40 struct clk_corediv_soc_desc
{
41 const struct clk_corediv_desc
*descs
;
43 const struct clk_ops ops
;
45 u32 enable_bit_offset
;
50 * This structure represents one core divider clock for the clock
51 * framework, and is dynamically allocated for each core divider clock
52 * existing in the current SoC.
57 const struct clk_corediv_desc
*desc
;
58 const struct clk_corediv_soc_desc
*soc_desc
;
62 static struct clk_onecell_data clk_data
;
65 * Description of the core divider clocks available. For now, we
66 * support only NAND, and it is available at the same register
67 * locations regardless of the SoC.
69 static const struct clk_corediv_desc mvebu_corediv_desc
[] = {
70 { .mask
= 0x3f, .offset
= 8, .fieldbit
= 1 }, /* NAND clock */
73 static const struct clk_corediv_desc mv98dx3236_corediv_desc
[] = {
74 { .mask
= 0x0f, .offset
= 6, .fieldbit
= 27 }, /* NAND clock */
77 #define to_corediv_clk(p) container_of(p, struct clk_corediv, hw)
79 static int clk_corediv_is_enabled(struct clk_hw
*hwclk
)
81 struct clk_corediv
*corediv
= to_corediv_clk(hwclk
);
82 const struct clk_corediv_soc_desc
*soc_desc
= corediv
->soc_desc
;
83 const struct clk_corediv_desc
*desc
= corediv
->desc
;
84 u32 enable_mask
= BIT(desc
->fieldbit
) << soc_desc
->enable_bit_offset
;
86 return !!(readl(corediv
->reg
) & enable_mask
);
89 static int clk_corediv_enable(struct clk_hw
*hwclk
)
91 struct clk_corediv
*corediv
= to_corediv_clk(hwclk
);
92 const struct clk_corediv_soc_desc
*soc_desc
= corediv
->soc_desc
;
93 const struct clk_corediv_desc
*desc
= corediv
->desc
;
94 unsigned long flags
= 0;
97 spin_lock_irqsave(&corediv
->lock
, flags
);
99 reg
= readl(corediv
->reg
);
100 reg
|= (BIT(desc
->fieldbit
) << soc_desc
->enable_bit_offset
);
101 writel(reg
, corediv
->reg
);
103 spin_unlock_irqrestore(&corediv
->lock
, flags
);
108 static void clk_corediv_disable(struct clk_hw
*hwclk
)
110 struct clk_corediv
*corediv
= to_corediv_clk(hwclk
);
111 const struct clk_corediv_soc_desc
*soc_desc
= corediv
->soc_desc
;
112 const struct clk_corediv_desc
*desc
= corediv
->desc
;
113 unsigned long flags
= 0;
116 spin_lock_irqsave(&corediv
->lock
, flags
);
118 reg
= readl(corediv
->reg
);
119 reg
&= ~(BIT(desc
->fieldbit
) << soc_desc
->enable_bit_offset
);
120 writel(reg
, corediv
->reg
);
122 spin_unlock_irqrestore(&corediv
->lock
, flags
);
125 static unsigned long clk_corediv_recalc_rate(struct clk_hw
*hwclk
,
126 unsigned long parent_rate
)
128 struct clk_corediv
*corediv
= to_corediv_clk(hwclk
);
129 const struct clk_corediv_soc_desc
*soc_desc
= corediv
->soc_desc
;
130 const struct clk_corediv_desc
*desc
= corediv
->desc
;
133 reg
= readl(corediv
->reg
+ soc_desc
->ratio_offset
);
134 div
= (reg
>> desc
->offset
) & desc
->mask
;
135 return parent_rate
/ div
;
138 static long clk_corediv_round_rate(struct clk_hw
*hwclk
, unsigned long rate
,
139 unsigned long *parent_rate
)
141 /* Valid ratio are 1:4, 1:5, 1:6 and 1:8 */
144 div
= *parent_rate
/ rate
;
150 return *parent_rate
/ div
;
153 static int clk_corediv_set_rate(struct clk_hw
*hwclk
, unsigned long rate
,
154 unsigned long parent_rate
)
156 struct clk_corediv
*corediv
= to_corediv_clk(hwclk
);
157 const struct clk_corediv_soc_desc
*soc_desc
= corediv
->soc_desc
;
158 const struct clk_corediv_desc
*desc
= corediv
->desc
;
159 unsigned long flags
= 0;
162 div
= parent_rate
/ rate
;
164 spin_lock_irqsave(&corediv
->lock
, flags
);
166 /* Write new divider to the divider ratio register */
167 reg
= readl(corediv
->reg
+ soc_desc
->ratio_offset
);
168 reg
&= ~(desc
->mask
<< desc
->offset
);
169 reg
|= (div
& desc
->mask
) << desc
->offset
;
170 writel(reg
, corediv
->reg
+ soc_desc
->ratio_offset
);
172 /* Set reload-force for this clock */
173 reg
= readl(corediv
->reg
) | BIT(desc
->fieldbit
);
174 writel(reg
, corediv
->reg
);
176 /* Now trigger the clock update */
177 reg
= readl(corediv
->reg
) | soc_desc
->ratio_reload
;
178 writel(reg
, corediv
->reg
);
181 * Wait for clocks to settle down, and then clear all the
182 * ratios request and the reload request.
185 reg
&= ~(CORE_CLK_DIV_RATIO_MASK
| soc_desc
->ratio_reload
);
186 writel(reg
, corediv
->reg
);
189 spin_unlock_irqrestore(&corediv
->lock
, flags
);
194 static const struct clk_corediv_soc_desc armada370_corediv_soc
= {
195 .descs
= mvebu_corediv_desc
,
196 .ndescs
= ARRAY_SIZE(mvebu_corediv_desc
),
198 .enable
= clk_corediv_enable
,
199 .disable
= clk_corediv_disable
,
200 .is_enabled
= clk_corediv_is_enabled
,
201 .recalc_rate
= clk_corediv_recalc_rate
,
202 .round_rate
= clk_corediv_round_rate
,
203 .set_rate
= clk_corediv_set_rate
,
205 .ratio_reload
= BIT(8),
206 .enable_bit_offset
= 24,
210 static const struct clk_corediv_soc_desc armada380_corediv_soc
= {
211 .descs
= mvebu_corediv_desc
,
212 .ndescs
= ARRAY_SIZE(mvebu_corediv_desc
),
214 .enable
= clk_corediv_enable
,
215 .disable
= clk_corediv_disable
,
216 .is_enabled
= clk_corediv_is_enabled
,
217 .recalc_rate
= clk_corediv_recalc_rate
,
218 .round_rate
= clk_corediv_round_rate
,
219 .set_rate
= clk_corediv_set_rate
,
221 .ratio_reload
= BIT(8),
222 .enable_bit_offset
= 16,
226 static const struct clk_corediv_soc_desc armada375_corediv_soc
= {
227 .descs
= mvebu_corediv_desc
,
228 .ndescs
= ARRAY_SIZE(mvebu_corediv_desc
),
230 .recalc_rate
= clk_corediv_recalc_rate
,
231 .round_rate
= clk_corediv_round_rate
,
232 .set_rate
= clk_corediv_set_rate
,
234 .ratio_reload
= BIT(8),
238 static const struct clk_corediv_soc_desc mv98dx3236_corediv_soc
= {
239 .descs
= mv98dx3236_corediv_desc
,
240 .ndescs
= ARRAY_SIZE(mv98dx3236_corediv_desc
),
242 .recalc_rate
= clk_corediv_recalc_rate
,
243 .round_rate
= clk_corediv_round_rate
,
244 .set_rate
= clk_corediv_set_rate
,
246 .ratio_reload
= BIT(10),
251 mvebu_corediv_clk_init(struct device_node
*node
,
252 const struct clk_corediv_soc_desc
*soc_desc
)
254 struct clk_init_data init
;
255 struct clk_corediv
*corediv
;
258 const char *parent_name
;
259 const char *clk_name
;
262 base
= of_iomap(node
, 0);
266 parent_name
= of_clk_get_parent_name(node
, 0);
268 clk_data
.clk_num
= soc_desc
->ndescs
;
270 /* clks holds the clock array */
271 clks
= kcalloc(clk_data
.clk_num
, sizeof(struct clk
*),
275 /* corediv holds the clock specific array */
276 corediv
= kcalloc(clk_data
.clk_num
, sizeof(struct clk_corediv
),
278 if (WARN_ON(!corediv
))
281 spin_lock_init(&corediv
->lock
);
283 for (i
= 0; i
< clk_data
.clk_num
; i
++) {
284 of_property_read_string_index(node
, "clock-output-names",
286 init
.num_parents
= 1;
287 init
.parent_names
= &parent_name
;
288 init
.name
= clk_name
;
289 init
.ops
= &soc_desc
->ops
;
292 corediv
[i
].soc_desc
= soc_desc
;
293 corediv
[i
].desc
= soc_desc
->descs
+ i
;
294 corediv
[i
].reg
= base
;
295 corediv
[i
].hw
.init
= &init
;
297 clks
[i
] = clk_register(NULL
, &corediv
[i
].hw
);
298 WARN_ON(IS_ERR(clks
[i
]));
301 clk_data
.clks
= clks
;
302 of_clk_add_provider(node
, of_clk_src_onecell_get
, &clk_data
);
311 static void __init
armada370_corediv_clk_init(struct device_node
*node
)
313 return mvebu_corediv_clk_init(node
, &armada370_corediv_soc
);
315 CLK_OF_DECLARE(armada370_corediv_clk
, "marvell,armada-370-corediv-clock",
316 armada370_corediv_clk_init
);
318 static void __init
armada375_corediv_clk_init(struct device_node
*node
)
320 return mvebu_corediv_clk_init(node
, &armada375_corediv_soc
);
322 CLK_OF_DECLARE(armada375_corediv_clk
, "marvell,armada-375-corediv-clock",
323 armada375_corediv_clk_init
);
325 static void __init
armada380_corediv_clk_init(struct device_node
*node
)
327 return mvebu_corediv_clk_init(node
, &armada380_corediv_soc
);
329 CLK_OF_DECLARE(armada380_corediv_clk
, "marvell,armada-380-corediv-clock",
330 armada380_corediv_clk_init
);
332 static void __init
mv98dx3236_corediv_clk_init(struct device_node
*node
)
334 return mvebu_corediv_clk_init(node
, &mv98dx3236_corediv_soc
);
336 CLK_OF_DECLARE(mv98dx3236_corediv_clk
, "marvell,mv98dx3236-corediv-clock",
337 mv98dx3236_corediv_clk_init
);