Skip to content

Commit a0f9819

Browse files
Dinh Nguyenbebarino
authored andcommitted
clk: socfpga: agilex: add clock driver for eASIC N5X platform
Add support for Intel's eASIC N5X platform. The clock manager driver for the N5X is very similar to the Agilex platform, we can re-use most of the Agilex clock driver. This patch makes the necessary changes for the driver to differentiate between the Agilex and the N5X platforms. Signed-off-by: Dinh Nguyen <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Stephen Boyd <[email protected]>
1 parent 2bea59d commit a0f9819

File tree

4 files changed

+238
-3
lines changed

4 files changed

+238
-3
lines changed

drivers/clk/socfpga/clk-agilex.c

Lines changed: 86 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,17 @@ static const struct stratix10_pll_clock agilex_pll_clks[] = {
196196
0, 0x9c},
197197
};
198198

199+
static const struct n5x_perip_c_clock n5x_main_perip_c_clks[] = {
200+
{ AGILEX_MAIN_PLL_C0_CLK, "main_pll_c0", "main_pll", NULL, 1, 0, 0x54, 0},
201+
{ AGILEX_MAIN_PLL_C1_CLK, "main_pll_c1", "main_pll", NULL, 1, 0, 0x54, 8},
202+
{ AGILEX_MAIN_PLL_C2_CLK, "main_pll_c2", "main_pll", NULL, 1, 0, 0x54, 16},
203+
{ AGILEX_MAIN_PLL_C3_CLK, "main_pll_c3", "main_pll", NULL, 1, 0, 0x54, 24},
204+
{ AGILEX_PERIPH_PLL_C0_CLK, "peri_pll_c0", "periph_pll", NULL, 1, 0, 0xA8, 0},
205+
{ AGILEX_PERIPH_PLL_C1_CLK, "peri_pll_c1", "periph_pll", NULL, 1, 0, 0xA8, 8},
206+
{ AGILEX_PERIPH_PLL_C2_CLK, "peri_pll_c2", "periph_pll", NULL, 1, 0, 0xA8, 16},
207+
{ AGILEX_PERIPH_PLL_C3_CLK, "peri_pll_c3", "periph_pll", NULL, 1, 0, 0xA8, 24},
208+
};
209+
199210
static const struct stratix10_perip_c_clock agilex_main_perip_c_clks[] = {
200211
{ AGILEX_MAIN_PLL_C0_CLK, "main_pll_c0", "main_pll", NULL, 1, 0, 0x58},
201212
{ AGILEX_MAIN_PLL_C1_CLK, "main_pll_c1", "main_pll", NULL, 1, 0, 0x5C},
@@ -289,6 +300,25 @@ static const struct stratix10_gate_clock agilex_gate_clks[] = {
289300
10, 0, 0, 0, 0, 0, 4},
290301
};
291302

303+
static int n5x_clk_register_c_perip(const struct n5x_perip_c_clock *clks,
304+
int nums, struct stratix10_clock_data *data)
305+
{
306+
struct clk *clk;
307+
void __iomem *base = data->base;
308+
int i;
309+
310+
for (i = 0; i < nums; i++) {
311+
clk = n5x_register_periph(&clks[i], base);
312+
if (IS_ERR(clk)) {
313+
pr_err("%s: failed to register clock %s\n",
314+
__func__, clks[i].name);
315+
continue;
316+
}
317+
data->clk_data.clks[clks[i].id] = clk;
318+
}
319+
return 0;
320+
}
321+
292322
static int agilex_clk_register_c_perip(const struct stratix10_perip_c_clock *clks,
293323
int nums, struct stratix10_clock_data *data)
294324
{
@@ -367,6 +397,26 @@ static int agilex_clk_register_pll(const struct stratix10_pll_clock *clks,
367397
return 0;
368398
}
369399

400+
static int n5x_clk_register_pll(const struct stratix10_pll_clock *clks,
401+
int nums, struct stratix10_clock_data *data)
402+
{
403+
struct clk *clk;
404+
void __iomem *base = data->base;
405+
int i;
406+
407+
for (i = 0; i < nums; i++) {
408+
clk = n5x_register_pll(&clks[i], base);
409+
if (IS_ERR(clk)) {
410+
pr_err("%s: failed to register clock %s\n",
411+
__func__, clks[i].name);
412+
continue;
413+
}
414+
data->clk_data.clks[clks[i].id] = clk;
415+
}
416+
417+
return 0;
418+
}
419+
370420
static struct stratix10_clock_data *__socfpga_agilex_clk_init(struct platform_device *pdev,
371421
int nr_clks)
372422
{
@@ -401,7 +451,7 @@ static struct stratix10_clock_data *__socfpga_agilex_clk_init(struct platform_de
401451
return clk_data;
402452
}
403453

404-
static int agilex_clkmgr_probe(struct platform_device *pdev)
454+
static int agilex_clkmgr_init(struct platform_device *pdev)
405455
{
406456
struct stratix10_clock_data *clk_data;
407457

@@ -423,9 +473,43 @@ static int agilex_clkmgr_probe(struct platform_device *pdev)
423473
return 0;
424474
}
425475

476+
static int n5x_clkmgr_init(struct platform_device *pdev)
477+
{
478+
struct stratix10_clock_data *clk_data;
479+
480+
clk_data = __socfpga_agilex_clk_init(pdev, AGILEX_NUM_CLKS);
481+
if (IS_ERR(clk_data))
482+
return PTR_ERR(clk_data);
483+
484+
n5x_clk_register_pll(agilex_pll_clks, ARRAY_SIZE(agilex_pll_clks), clk_data);
485+
486+
n5x_clk_register_c_perip(n5x_main_perip_c_clks,
487+
ARRAY_SIZE(n5x_main_perip_c_clks), clk_data);
488+
489+
agilex_clk_register_cnt_perip(agilex_main_perip_cnt_clks,
490+
ARRAY_SIZE(agilex_main_perip_cnt_clks),
491+
clk_data);
492+
493+
agilex_clk_register_gate(agilex_gate_clks, ARRAY_SIZE(agilex_gate_clks),
494+
clk_data);
495+
return 0;
496+
}
497+
498+
static int agilex_clkmgr_probe(struct platform_device *pdev)
499+
{
500+
int (*probe_func)(struct platform_device *init_func);
501+
502+
probe_func = of_device_get_match_data(&pdev->dev);
503+
if (!probe_func)
504+
return -ENODEV;
505+
return probe_func(pdev);
506+
}
507+
426508
static const struct of_device_id agilex_clkmgr_match_table[] = {
427509
{ .compatible = "intel,agilex-clkmgr",
428-
.data = agilex_clkmgr_probe },
510+
.data = agilex_clkmgr_init },
511+
{ .compatible = "intel,easic-n5x-clkmgr",
512+
.data = n5x_clkmgr_init },
429513
{ }
430514
};
431515

drivers/clk/socfpga/clk-periph-s10.c

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,21 @@
1515

1616
#define to_periph_clk(p) container_of(p, struct socfpga_periph_clk, hw.hw)
1717

18+
static unsigned long n5x_clk_peri_c_clk_recalc_rate(struct clk_hw *hwclk,
19+
unsigned long parent_rate)
20+
{
21+
struct socfpga_periph_clk *socfpgaclk = to_periph_clk(hwclk);
22+
unsigned long div;
23+
unsigned long shift = socfpgaclk->shift;
24+
u32 val;
25+
26+
val = readl(socfpgaclk->hw.reg);
27+
val &= (0x1f << shift);
28+
div = (val >> shift) + 1;
29+
30+
return parent_rate / div;
31+
}
32+
1833
static unsigned long clk_peri_c_clk_recalc_rate(struct clk_hw *hwclk,
1934
unsigned long parent_rate)
2035
{
@@ -63,6 +78,11 @@ static u8 clk_periclk_get_parent(struct clk_hw *hwclk)
6378
return parent;
6479
}
6580

81+
static const struct clk_ops n5x_peri_c_clk_ops = {
82+
.recalc_rate = n5x_clk_peri_c_clk_recalc_rate,
83+
.get_parent = clk_periclk_get_parent,
84+
};
85+
6686
static const struct clk_ops peri_c_clk_ops = {
6787
.recalc_rate = clk_peri_c_clk_recalc_rate,
6888
.get_parent = clk_periclk_get_parent,
@@ -107,6 +127,39 @@ struct clk *s10_register_periph(const struct stratix10_perip_c_clock *clks,
107127
return clk;
108128
}
109129

130+
struct clk *n5x_register_periph(const struct n5x_perip_c_clock *clks,
131+
void __iomem *regbase)
132+
{
133+
struct clk *clk;
134+
struct socfpga_periph_clk *periph_clk;
135+
struct clk_init_data init;
136+
const char *name = clks->name;
137+
const char *parent_name = clks->parent_name;
138+
139+
periph_clk = kzalloc(sizeof(*periph_clk), GFP_KERNEL);
140+
if (WARN_ON(!periph_clk))
141+
return NULL;
142+
143+
periph_clk->hw.reg = regbase + clks->offset;
144+
periph_clk->shift = clks->shift;
145+
146+
init.name = name;
147+
init.ops = &n5x_peri_c_clk_ops;
148+
init.flags = clks->flags;
149+
150+
init.num_parents = clks->num_parents;
151+
init.parent_names = parent_name ? &parent_name : NULL;
152+
153+
periph_clk->hw.hw.init = &init;
154+
155+
clk = clk_register(NULL, &periph_clk->hw.hw);
156+
if (WARN_ON(IS_ERR(clk))) {
157+
kfree(periph_clk);
158+
return NULL;
159+
}
160+
return clk;
161+
}
162+
110163
struct clk *s10_register_cnt_periph(const struct stratix10_perip_cnt_clock *clks,
111164
void __iomem *regbase)
112165
{

drivers/clk/socfpga/clk-pll-s10.c

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,37 @@
2727
#define SWCTRLBTCLKSEL_MASK 0x200
2828
#define SWCTRLBTCLKSEL_SHIFT 9
2929

30+
#define SOCFPGA_N5X_PLLDIV_FDIV_MASK GENMASK(16, 8)
31+
#define SOCFPGA_N5X_PLLDIV_FDIV_SHIFT 8
32+
#define SOCFPGA_N5X_PLLDIV_RDIV_MASK GENMASK(5, 0)
33+
#define SOCFPGA_N5X_PLLDIV_QDIV_MASK GENMASK(26, 24)
34+
#define SOCFPGA_N5X_PLLDIV_QDIV_SHIFT 24
35+
3036
#define SOCFPGA_BOOT_CLK "boot_clk"
3137

3238
#define to_socfpga_clk(p) container_of(p, struct socfpga_pll, hw.hw)
3339

40+
static unsigned long n5x_clk_pll_recalc_rate(struct clk_hw *hwclk,
41+
unsigned long parent_rate)
42+
{
43+
struct socfpga_pll *socfpgaclk = to_socfpga_clk(hwclk);
44+
unsigned long fdiv, reg, rdiv, qdiv;
45+
u32 power = 1;
46+
47+
/* read VCO1 reg for numerator and denominator */
48+
reg = readl(socfpgaclk->hw.reg + 0x8);
49+
fdiv = (reg & SOCFPGA_N5X_PLLDIV_FDIV_MASK) >> SOCFPGA_N5X_PLLDIV_FDIV_SHIFT;
50+
rdiv = (reg & SOCFPGA_N5X_PLLDIV_RDIV_MASK);
51+
qdiv = (reg & SOCFPGA_N5X_PLLDIV_QDIV_MASK) >> SOCFPGA_N5X_PLLDIV_QDIV_SHIFT;
52+
53+
while (qdiv) {
54+
power *= 2;
55+
qdiv--;
56+
}
57+
58+
return ((parent_rate * 2 * (fdiv + 1)) / ((rdiv + 1) * power));
59+
}
60+
3461
static unsigned long agilex_clk_pll_recalc_rate(struct clk_hw *hwclk,
3562
unsigned long parent_rate)
3663
{
@@ -123,6 +150,25 @@ static int clk_pll_prepare(struct clk_hw *hwclk)
123150
return 0;
124151
}
125152

153+
static int n5x_clk_pll_prepare(struct clk_hw *hwclk)
154+
{
155+
struct socfpga_pll *socfpgaclk = to_socfpga_clk(hwclk);
156+
u32 reg;
157+
158+
/* Bring PLL out of reset */
159+
reg = readl(socfpgaclk->hw.reg + 0x4);
160+
reg |= SOCFPGA_PLL_RESET_MASK;
161+
writel(reg, socfpgaclk->hw.reg + 0x4);
162+
163+
return 0;
164+
}
165+
166+
static const struct clk_ops n5x_clk_pll_ops = {
167+
.recalc_rate = n5x_clk_pll_recalc_rate,
168+
.get_parent = clk_pll_get_parent,
169+
.prepare = n5x_clk_pll_prepare,
170+
};
171+
126172
static const struct clk_ops agilex_clk_pll_ops = {
127173
.recalc_rate = agilex_clk_pll_recalc_rate,
128174
.get_parent = clk_pll_get_parent,
@@ -214,3 +260,40 @@ struct clk *agilex_register_pll(const struct stratix10_pll_clock *clks,
214260
}
215261
return clk;
216262
}
263+
264+
struct clk *n5x_register_pll(const struct stratix10_pll_clock *clks,
265+
void __iomem *reg)
266+
{
267+
struct clk *clk;
268+
struct socfpga_pll *pll_clk;
269+
struct clk_init_data init;
270+
const char *name = clks->name;
271+
272+
pll_clk = kzalloc(sizeof(*pll_clk), GFP_KERNEL);
273+
if (WARN_ON(!pll_clk))
274+
return NULL;
275+
276+
pll_clk->hw.reg = reg + clks->offset;
277+
278+
if (streq(name, SOCFPGA_BOOT_CLK))
279+
init.ops = &clk_boot_ops;
280+
else
281+
init.ops = &n5x_clk_pll_ops;
282+
283+
init.name = name;
284+
init.flags = clks->flags;
285+
286+
init.num_parents = clks->num_parents;
287+
init.parent_names = NULL;
288+
init.parent_data = clks->parent_data;
289+
pll_clk->hw.hw.init = &init;
290+
291+
pll_clk->hw.bit_idx = SOCFPGA_PLL_POWER;
292+
293+
clk = clk_register(NULL, &pll_clk->hw.hw);
294+
if (WARN_ON(IS_ERR(clk))) {
295+
kfree(pll_clk);
296+
return NULL;
297+
}
298+
return clk;
299+
}

drivers/clk/socfpga/stratix10-clk.h

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,17 @@ struct stratix10_perip_c_clock {
3030
unsigned long offset;
3131
};
3232

33+
struct n5x_perip_c_clock {
34+
unsigned int id;
35+
const char *name;
36+
const char *parent_name;
37+
const char *const *parent_names;
38+
u8 num_parents;
39+
unsigned long flags;
40+
unsigned long offset;
41+
unsigned long shift;
42+
};
43+
3344
struct stratix10_perip_cnt_clock {
3445
unsigned int id;
3546
const char *name;
@@ -64,8 +75,12 @@ struct clk *s10_register_pll(const struct stratix10_pll_clock *,
6475
void __iomem *);
6576
struct clk *agilex_register_pll(const struct stratix10_pll_clock *,
6677
void __iomem *);
78+
struct clk *n5x_register_pll(const struct stratix10_pll_clock *clks,
79+
void __iomem *reg);
6780
struct clk *s10_register_periph(const struct stratix10_perip_c_clock *,
68-
void __iomem *);
81+
void __iomem *reg);
82+
struct clk *n5x_register_periph(const struct n5x_perip_c_clock *clks,
83+
void __iomem *reg);
6984
struct clk *s10_register_cnt_periph(const struct stratix10_perip_cnt_clock *,
7085
void __iomem *);
7186
struct clk *s10_register_gate(const struct stratix10_gate_clock *,

0 commit comments

Comments
 (0)