Skip to content

Commit c4e0544

Browse files
fancerbebarino
authored andcommitted
clk: baikal-t1: Convert to platform device driver
In accordance with the way the MIPS platform is normally design there are only six clock sources which need to be available on the kernel start in order to one end up booting correctly: + CPU PLL: needed by the r4k and MIPS GIC timer drivers. The former one is initialized by the arch code, while the later one is implemented in the mips-gic-timer.c driver as the OF-declared timer. + PCIe PLL: required as a parental clock source for the APB/timer domains. + APB clock: needed in order to access all the SoC CSRs at least for the timer OF-declared drivers. + APB Timer{0-2} clocks: these are the DW APB timers which drivers dw_apb_timer_of.c are implemented as the OF-declared timers. So as long as the clocks above are available early the kernel will normally work. Let's convert the Baikal-T1 CCU drivers to the platform device drivers keeping that in mind. Generally speaking the conversion isn't that complicated since the driver infrastructure has been designed as flexible enough for that. First we need to add a new PLL/Divider clock features flag which indicates the corresponding clock source as a basic one and that clock sources will be available on the kernel early boot stages. Second the internal PLL/Divider descriptors need to be initialized with -EPROBE_DEFER value as the corresponding clock source is unavailable at the early stages. They will be allocated and initialized on the Baikal-T1 clock platform driver probe procedure. Finally the already available PLL/Divider init functions need to be split up into two ones: init procedure performed in the framework of the OF-declared clock initialization (of_clk_init()), and the probe procedure called by the platform devices bus driver. Note the later method will just continue the system clocks initialization started in the former one. Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru> Link: https://lore.kernel.org/r/20220929225402.9696-9-Sergey.Semin@baikalelectronics.ru [sboyd@kernel.org: Remove module things because the Kconfig is still bool] Signed-off-by: Stephen Boyd <sboyd@kernel.org>
1 parent fa6bd54 commit c4e0544

File tree

4 files changed

+226
-54
lines changed

4 files changed

+226
-54
lines changed

drivers/clk/baikal-t1/ccu-div.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,16 @@
2323

2424
/*
2525
* CCU Divider private flags
26+
* @CCU_DIV_BASIC: Basic divider clock required by the kernel as early as
27+
* possible.
2628
* @CCU_DIV_SKIP_ONE: Due to some reason divider can't be set to 1.
2729
* It can be 0 though, which is functionally the same.
2830
* @CCU_DIV_SKIP_ONE_TO_THREE: For some reason divider can't be within [1,3].
2931
* It can be either 0 or greater than 3.
3032
* @CCU_DIV_LOCK_SHIFTED: Find lock-bit at non-standard position.
3133
* @CCU_DIV_RESET_DOMAIN: There is a clock domain reset handle.
3234
*/
35+
#define CCU_DIV_BASIC BIT(0)
3336
#define CCU_DIV_SKIP_ONE BIT(1)
3437
#define CCU_DIV_SKIP_ONE_TO_THREE BIT(2)
3538
#define CCU_DIV_LOCK_SHIFTED BIT(3)

drivers/clk/baikal-t1/ccu-pll.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,12 @@
1313
#include <linux/bits.h>
1414
#include <linux/of.h>
1515

16+
/*
17+
* CCU PLL private flags
18+
* @CCU_PLL_BASIC: Basic PLL required by the kernel as early as possible.
19+
*/
20+
#define CCU_PLL_BASIC BIT(0)
21+
1622
/*
1723
* struct ccu_pll_init_data - CCU PLL initialization data
1824
* @id: Clock private identifier.
@@ -22,6 +28,7 @@
2228
* @sys_regs: Baikal-T1 System Controller registers map.
2329
* @np: Pointer to the node describing the CCU PLLs.
2430
* @flags: PLL clock flags.
31+
* @features: PLL private features.
2532
*/
2633
struct ccu_pll_init_data {
2734
unsigned int id;
@@ -31,6 +38,7 @@ struct ccu_pll_init_data {
3138
struct regmap *sys_regs;
3239
struct device_node *np;
3340
unsigned long flags;
41+
unsigned long features;
3442
};
3543

3644
/*

drivers/clk/baikal-t1/clk-ccu-div.c

Lines changed: 118 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#define pr_fmt(fmt) "bt1-ccu-div: " fmt
1313

1414
#include <linux/kernel.h>
15+
#include <linux/platform_device.h>
1516
#include <linux/printk.h>
1617
#include <linux/slab.h>
1718
#include <linux/clk-provider.h>
@@ -180,7 +181,7 @@ static const struct ccu_div_info sys_info[] = {
180181
CLK_SET_RATE_PARENT),
181182
CCU_DIV_VAR_INFO(CCU_SYS_APB_CLK, "sys_apb_clk",
182183
"pcie_clk", CCU_SYS_APB_BASE, 5,
183-
CLK_IS_CRITICAL, CCU_DIV_RESET_DOMAIN),
184+
CLK_IS_CRITICAL, CCU_DIV_BASIC | CCU_DIV_RESET_DOMAIN),
184185
CCU_DIV_GATE_INFO(CCU_SYS_GMAC0_TX_CLK, "sys_gmac0_tx_clk",
185186
"eth_clk", CCU_SYS_GMAC0_BASE, 5),
186187
CCU_DIV_FIXED_INFO(CCU_SYS_GMAC0_PTP_CLK, "sys_gmac0_ptp_clk",
@@ -214,28 +215,53 @@ static const struct ccu_div_info sys_info[] = {
214215
"ref_clk", 25),
215216
CCU_DIV_VAR_INFO(CCU_SYS_TIMER0_CLK, "sys_timer0_clk",
216217
"ref_clk", CCU_SYS_TIMER0_BASE, 17,
217-
CLK_SET_RATE_GATE, 0),
218+
CLK_SET_RATE_GATE, CCU_DIV_BASIC),
218219
CCU_DIV_VAR_INFO(CCU_SYS_TIMER1_CLK, "sys_timer1_clk",
219220
"ref_clk", CCU_SYS_TIMER1_BASE, 17,
220-
CLK_SET_RATE_GATE, 0),
221+
CLK_SET_RATE_GATE, CCU_DIV_BASIC),
221222
CCU_DIV_VAR_INFO(CCU_SYS_TIMER2_CLK, "sys_timer2_clk",
222223
"ref_clk", CCU_SYS_TIMER2_BASE, 17,
223-
CLK_SET_RATE_GATE, 0),
224+
CLK_SET_RATE_GATE, CCU_DIV_BASIC),
224225
CCU_DIV_VAR_INFO(CCU_SYS_WDT_CLK, "sys_wdt_clk",
225226
"eth_clk", CCU_SYS_WDT_BASE, 17,
226227
CLK_SET_RATE_GATE, CCU_DIV_SKIP_ONE_TO_THREE)
227228
};
228229

230+
static struct ccu_div_data *axi_data;
231+
static struct ccu_div_data *sys_data;
232+
233+
static void ccu_div_set_data(struct ccu_div_data *data)
234+
{
235+
struct device_node *np = data->np;
236+
237+
if (of_device_is_compatible(np, "baikal,bt1-ccu-axi"))
238+
axi_data = data;
239+
else if (of_device_is_compatible(np, "baikal,bt1-ccu-sys"))
240+
sys_data = data;
241+
else
242+
pr_err("Invalid DT node '%s' specified\n", of_node_full_name(np));
243+
}
244+
245+
static struct ccu_div_data *ccu_div_get_data(struct device_node *np)
246+
{
247+
if (of_device_is_compatible(np, "baikal,bt1-ccu-axi"))
248+
return axi_data;
249+
else if (of_device_is_compatible(np, "baikal,bt1-ccu-sys"))
250+
return sys_data;
251+
252+
pr_err("Invalid DT node '%s' specified\n", of_node_full_name(np));
253+
254+
return NULL;
255+
}
256+
229257
static struct ccu_div *ccu_div_find_desc(struct ccu_div_data *data,
230258
unsigned int clk_id)
231259
{
232-
struct ccu_div *div;
233260
int idx;
234261

235262
for (idx = 0; idx < data->divs_num; ++idx) {
236-
div = data->divs[idx];
237-
if (div && div->id == clk_id)
238-
return div;
263+
if (data->divs_info[idx].id == clk_id)
264+
return data->divs[idx];
239265
}
240266

241267
return ERR_PTR(-EINVAL);
@@ -307,21 +333,30 @@ static struct clk_hw *ccu_div_of_clk_hw_get(struct of_phandle_args *clkspec,
307333
clk_id = clkspec->args[0];
308334
div = ccu_div_find_desc(data, clk_id);
309335
if (IS_ERR(div)) {
310-
pr_info("Invalid clock ID %d specified\n", clk_id);
336+
if (div != ERR_PTR(-EPROBE_DEFER))
337+
pr_info("Invalid clock ID %d specified\n", clk_id);
338+
311339
return ERR_CAST(div);
312340
}
313341

314342
return ccu_div_get_clk_hw(div);
315343
}
316344

317-
static int ccu_div_clk_register(struct ccu_div_data *data)
345+
static int ccu_div_clk_register(struct ccu_div_data *data, bool defer)
318346
{
319347
int idx, ret;
320348

321349
for (idx = 0; idx < data->divs_num; ++idx) {
322350
const struct ccu_div_info *info = &data->divs_info[idx];
323351
struct ccu_div_init_data init = {0};
324352

353+
if (!!(info->features & CCU_DIV_BASIC) ^ defer) {
354+
if (!data->divs[idx])
355+
data->divs[idx] = ERR_PTR(-EPROBE_DEFER);
356+
357+
continue;
358+
}
359+
325360
init.id = info->id;
326361
init.name = info->name;
327362
init.parent_name = info->parent_name;
@@ -354,30 +389,43 @@ static int ccu_div_clk_register(struct ccu_div_data *data)
354389
}
355390
}
356391

357-
ret = of_clk_add_hw_provider(data->np, ccu_div_of_clk_hw_get, data);
358-
if (ret) {
359-
pr_err("Couldn't register dividers '%s' clock provider\n",
360-
of_node_full_name(data->np));
361-
goto err_hw_unregister;
362-
}
363-
364392
return 0;
365393

366394
err_hw_unregister:
367-
for (--idx; idx >= 0; --idx)
395+
for (--idx; idx >= 0; --idx) {
396+
if (!!(data->divs_info[idx].features & CCU_DIV_BASIC) ^ defer)
397+
continue;
398+
368399
ccu_div_hw_unregister(data->divs[idx]);
400+
}
369401

370402
return ret;
371403
}
372404

373-
static void ccu_div_clk_unregister(struct ccu_div_data *data)
405+
static void ccu_div_clk_unregister(struct ccu_div_data *data, bool defer)
374406
{
375407
int idx;
376408

377-
of_clk_del_provider(data->np);
409+
/* Uninstall only the clocks registered on the specfied stage */
410+
for (idx = 0; idx < data->divs_num; ++idx) {
411+
if (!!(data->divs_info[idx].features & CCU_DIV_BASIC) ^ defer)
412+
continue;
378413

379-
for (idx = 0; idx < data->divs_num; ++idx)
380414
ccu_div_hw_unregister(data->divs[idx]);
415+
}
416+
}
417+
418+
static int ccu_div_of_register(struct ccu_div_data *data)
419+
{
420+
int ret;
421+
422+
ret = of_clk_add_hw_provider(data->np, ccu_div_of_clk_hw_get, data);
423+
if (ret) {
424+
pr_err("Couldn't register dividers '%s' clock provider\n",
425+
of_node_full_name(data->np));
426+
}
427+
428+
return ret;
381429
}
382430

383431
static int ccu_div_rst_register(struct ccu_div_data *data)
@@ -397,7 +445,48 @@ static int ccu_div_rst_register(struct ccu_div_data *data)
397445
return 0;
398446
}
399447

400-
static void ccu_div_init(struct device_node *np)
448+
static int ccu_div_probe(struct platform_device *pdev)
449+
{
450+
struct ccu_div_data *data;
451+
int ret;
452+
453+
data = ccu_div_get_data(dev_of_node(&pdev->dev));
454+
if (!data)
455+
return -EINVAL;
456+
457+
ret = ccu_div_clk_register(data, false);
458+
if (ret)
459+
return ret;
460+
461+
ret = ccu_div_rst_register(data);
462+
if (ret)
463+
goto err_clk_unregister;
464+
465+
return 0;
466+
467+
err_clk_unregister:
468+
ccu_div_clk_unregister(data, false);
469+
470+
return ret;
471+
}
472+
473+
static const struct of_device_id ccu_div_of_match[] = {
474+
{ .compatible = "baikal,bt1-ccu-axi" },
475+
{ .compatible = "baikal,bt1-ccu-sys" },
476+
{ }
477+
};
478+
479+
static struct platform_driver ccu_div_driver = {
480+
.probe = ccu_div_probe,
481+
.driver = {
482+
.name = "clk-ccu-div",
483+
.of_match_table = ccu_div_of_match,
484+
.suppress_bind_attrs = true,
485+
},
486+
};
487+
builtin_platform_driver(ccu_div_driver);
488+
489+
static __init void ccu_div_init(struct device_node *np)
401490
{
402491
struct ccu_div_data *data;
403492
int ret;
@@ -410,22 +499,23 @@ static void ccu_div_init(struct device_node *np)
410499
if (ret)
411500
goto err_free_data;
412501

413-
ret = ccu_div_clk_register(data);
502+
ret = ccu_div_clk_register(data, true);
414503
if (ret)
415504
goto err_free_data;
416505

417-
ret = ccu_div_rst_register(data);
506+
ret = ccu_div_of_register(data);
418507
if (ret)
419508
goto err_clk_unregister;
420509

510+
ccu_div_set_data(data);
511+
421512
return;
422513

423514
err_clk_unregister:
424-
ccu_div_clk_unregister(data);
515+
ccu_div_clk_unregister(data, true);
425516

426517
err_free_data:
427518
ccu_div_free_data(data);
428519
}
429-
430-
CLK_OF_DECLARE(ccu_axi, "baikal,bt1-ccu-axi", ccu_div_init);
431-
CLK_OF_DECLARE(ccu_sys, "baikal,bt1-ccu-sys", ccu_div_init);
520+
CLK_OF_DECLARE_DRIVER(ccu_axi, "baikal,bt1-ccu-axi", ccu_div_init);
521+
CLK_OF_DECLARE_DRIVER(ccu_sys, "baikal,bt1-ccu-sys", ccu_div_init);

0 commit comments

Comments
 (0)