0001
0002
0003
0004
0005
0006
0007 #include <linux/clkdev.h>
0008 #include <linux/delay.h>
0009 #include <linux/io.h>
0010 #include <linux/of_device.h>
0011 #include "sifive-prci.h"
0012 #include "fu540-prci.h"
0013 #include "fu740-prci.h"
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032 static u32 __prci_readl(struct __prci_data *pd, u32 offs)
0033 {
0034 return readl_relaxed(pd->va + offs);
0035 }
0036
0037 static void __prci_writel(u32 v, u32 offs, struct __prci_data *pd)
0038 {
0039 writel_relaxed(v, pd->va + offs);
0040 }
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058 static void __prci_wrpll_unpack(struct wrpll_cfg *c, u32 r)
0059 {
0060 u32 v;
0061
0062 v = r & PRCI_COREPLLCFG0_DIVR_MASK;
0063 v >>= PRCI_COREPLLCFG0_DIVR_SHIFT;
0064 c->divr = v;
0065
0066 v = r & PRCI_COREPLLCFG0_DIVF_MASK;
0067 v >>= PRCI_COREPLLCFG0_DIVF_SHIFT;
0068 c->divf = v;
0069
0070 v = r & PRCI_COREPLLCFG0_DIVQ_MASK;
0071 v >>= PRCI_COREPLLCFG0_DIVQ_SHIFT;
0072 c->divq = v;
0073
0074 v = r & PRCI_COREPLLCFG0_RANGE_MASK;
0075 v >>= PRCI_COREPLLCFG0_RANGE_SHIFT;
0076 c->range = v;
0077
0078 c->flags &=
0079 (WRPLL_FLAGS_INT_FEEDBACK_MASK | WRPLL_FLAGS_EXT_FEEDBACK_MASK);
0080
0081
0082 c->flags |= WRPLL_FLAGS_INT_FEEDBACK_MASK;
0083 }
0084
0085
0086
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096
0097
0098
0099
0100 static u32 __prci_wrpll_pack(const struct wrpll_cfg *c)
0101 {
0102 u32 r = 0;
0103
0104 r |= c->divr << PRCI_COREPLLCFG0_DIVR_SHIFT;
0105 r |= c->divf << PRCI_COREPLLCFG0_DIVF_SHIFT;
0106 r |= c->divq << PRCI_COREPLLCFG0_DIVQ_SHIFT;
0107 r |= c->range << PRCI_COREPLLCFG0_RANGE_SHIFT;
0108
0109
0110 r |= PRCI_COREPLLCFG0_FSE_MASK;
0111
0112 return r;
0113 }
0114
0115
0116
0117
0118
0119
0120
0121
0122
0123
0124
0125
0126
0127 static void __prci_wrpll_read_cfg0(struct __prci_data *pd,
0128 struct __prci_wrpll_data *pwd)
0129 {
0130 __prci_wrpll_unpack(&pwd->c, __prci_readl(pd, pwd->cfg0_offs));
0131 }
0132
0133
0134
0135
0136
0137
0138
0139
0140
0141
0142
0143
0144
0145
0146
0147 static void __prci_wrpll_write_cfg0(struct __prci_data *pd,
0148 struct __prci_wrpll_data *pwd,
0149 struct wrpll_cfg *c)
0150 {
0151 __prci_writel(__prci_wrpll_pack(c), pwd->cfg0_offs, pd);
0152
0153 memcpy(&pwd->c, c, sizeof(*c));
0154 }
0155
0156
0157
0158
0159
0160
0161
0162
0163 static void __prci_wrpll_write_cfg1(struct __prci_data *pd,
0164 struct __prci_wrpll_data *pwd,
0165 u32 enable)
0166 {
0167 __prci_writel(enable, pwd->cfg1_offs, pd);
0168 }
0169
0170
0171
0172
0173
0174
0175
0176
0177 unsigned long sifive_prci_wrpll_recalc_rate(struct clk_hw *hw,
0178 unsigned long parent_rate)
0179 {
0180 struct __prci_clock *pc = clk_hw_to_prci_clock(hw);
0181 struct __prci_wrpll_data *pwd = pc->pwd;
0182
0183 return wrpll_calc_output_rate(&pwd->c, parent_rate);
0184 }
0185
0186 long sifive_prci_wrpll_round_rate(struct clk_hw *hw,
0187 unsigned long rate,
0188 unsigned long *parent_rate)
0189 {
0190 struct __prci_clock *pc = clk_hw_to_prci_clock(hw);
0191 struct __prci_wrpll_data *pwd = pc->pwd;
0192 struct wrpll_cfg c;
0193
0194 memcpy(&c, &pwd->c, sizeof(c));
0195
0196 wrpll_configure_for_rate(&c, rate, *parent_rate);
0197
0198 return wrpll_calc_output_rate(&c, *parent_rate);
0199 }
0200
0201 int sifive_prci_wrpll_set_rate(struct clk_hw *hw,
0202 unsigned long rate, unsigned long parent_rate)
0203 {
0204 struct __prci_clock *pc = clk_hw_to_prci_clock(hw);
0205 struct __prci_wrpll_data *pwd = pc->pwd;
0206 struct __prci_data *pd = pc->pd;
0207 int r;
0208
0209 r = wrpll_configure_for_rate(&pwd->c, rate, parent_rate);
0210 if (r)
0211 return r;
0212
0213 if (pwd->enable_bypass)
0214 pwd->enable_bypass(pd);
0215
0216 __prci_wrpll_write_cfg0(pd, pwd, &pwd->c);
0217
0218 udelay(wrpll_calc_max_lock_us(&pwd->c));
0219
0220 return 0;
0221 }
0222
0223 int sifive_clk_is_enabled(struct clk_hw *hw)
0224 {
0225 struct __prci_clock *pc = clk_hw_to_prci_clock(hw);
0226 struct __prci_wrpll_data *pwd = pc->pwd;
0227 struct __prci_data *pd = pc->pd;
0228 u32 r;
0229
0230 r = __prci_readl(pd, pwd->cfg1_offs);
0231
0232 if (r & PRCI_COREPLLCFG1_CKE_MASK)
0233 return 1;
0234 else
0235 return 0;
0236 }
0237
0238 int sifive_prci_clock_enable(struct clk_hw *hw)
0239 {
0240 struct __prci_clock *pc = clk_hw_to_prci_clock(hw);
0241 struct __prci_wrpll_data *pwd = pc->pwd;
0242 struct __prci_data *pd = pc->pd;
0243
0244 if (sifive_clk_is_enabled(hw))
0245 return 0;
0246
0247 __prci_wrpll_write_cfg1(pd, pwd, PRCI_COREPLLCFG1_CKE_MASK);
0248
0249 if (pwd->disable_bypass)
0250 pwd->disable_bypass(pd);
0251
0252 return 0;
0253 }
0254
0255 void sifive_prci_clock_disable(struct clk_hw *hw)
0256 {
0257 struct __prci_clock *pc = clk_hw_to_prci_clock(hw);
0258 struct __prci_wrpll_data *pwd = pc->pwd;
0259 struct __prci_data *pd = pc->pd;
0260 u32 r;
0261
0262 if (pwd->enable_bypass)
0263 pwd->enable_bypass(pd);
0264
0265 r = __prci_readl(pd, pwd->cfg1_offs);
0266 r &= ~PRCI_COREPLLCFG1_CKE_MASK;
0267
0268 __prci_wrpll_write_cfg1(pd, pwd, r);
0269 }
0270
0271
0272
0273 unsigned long sifive_prci_tlclksel_recalc_rate(struct clk_hw *hw,
0274 unsigned long parent_rate)
0275 {
0276 struct __prci_clock *pc = clk_hw_to_prci_clock(hw);
0277 struct __prci_data *pd = pc->pd;
0278 u32 v;
0279 u8 div;
0280
0281 v = __prci_readl(pd, PRCI_CLKMUXSTATUSREG_OFFSET);
0282 v &= PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_MASK;
0283 div = v ? 1 : 2;
0284
0285 return div_u64(parent_rate, div);
0286 }
0287
0288
0289
0290 unsigned long sifive_prci_hfpclkplldiv_recalc_rate(struct clk_hw *hw,
0291 unsigned long parent_rate)
0292 {
0293 struct __prci_clock *pc = clk_hw_to_prci_clock(hw);
0294 struct __prci_data *pd = pc->pd;
0295 u32 div = __prci_readl(pd, PRCI_HFPCLKPLLDIV_OFFSET);
0296
0297 return div_u64(parent_rate, div + 2);
0298 }
0299
0300
0301
0302
0303
0304
0305
0306
0307
0308
0309
0310
0311
0312
0313 void sifive_prci_coreclksel_use_hfclk(struct __prci_data *pd)
0314 {
0315 u32 r;
0316
0317 r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET);
0318 r |= PRCI_CORECLKSEL_CORECLKSEL_MASK;
0319 __prci_writel(r, PRCI_CORECLKSEL_OFFSET, pd);
0320
0321 r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET);
0322 }
0323
0324
0325
0326
0327
0328
0329
0330
0331
0332
0333
0334 void sifive_prci_coreclksel_use_corepll(struct __prci_data *pd)
0335 {
0336 u32 r;
0337
0338 r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET);
0339 r &= ~PRCI_CORECLKSEL_CORECLKSEL_MASK;
0340 __prci_writel(r, PRCI_CORECLKSEL_OFFSET, pd);
0341
0342 r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET);
0343 }
0344
0345
0346
0347
0348
0349
0350
0351
0352
0353
0354
0355
0356 void sifive_prci_coreclksel_use_final_corepll(struct __prci_data *pd)
0357 {
0358 u32 r;
0359
0360 r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET);
0361 r &= ~PRCI_CORECLKSEL_CORECLKSEL_MASK;
0362 __prci_writel(r, PRCI_CORECLKSEL_OFFSET, pd);
0363
0364 r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET);
0365 }
0366
0367
0368
0369
0370
0371
0372
0373
0374
0375
0376
0377 void sifive_prci_corepllsel_use_dvfscorepll(struct __prci_data *pd)
0378 {
0379 u32 r;
0380
0381 r = __prci_readl(pd, PRCI_COREPLLSEL_OFFSET);
0382 r |= PRCI_COREPLLSEL_COREPLLSEL_MASK;
0383 __prci_writel(r, PRCI_COREPLLSEL_OFFSET, pd);
0384
0385 r = __prci_readl(pd, PRCI_COREPLLSEL_OFFSET);
0386 }
0387
0388
0389
0390
0391
0392
0393
0394
0395
0396
0397
0398 void sifive_prci_corepllsel_use_corepll(struct __prci_data *pd)
0399 {
0400 u32 r;
0401
0402 r = __prci_readl(pd, PRCI_COREPLLSEL_OFFSET);
0403 r &= ~PRCI_COREPLLSEL_COREPLLSEL_MASK;
0404 __prci_writel(r, PRCI_COREPLLSEL_OFFSET, pd);
0405
0406 r = __prci_readl(pd, PRCI_COREPLLSEL_OFFSET);
0407 }
0408
0409
0410
0411
0412
0413
0414
0415
0416
0417
0418
0419 void sifive_prci_hfpclkpllsel_use_hfclk(struct __prci_data *pd)
0420 {
0421 u32 r;
0422
0423 r = __prci_readl(pd, PRCI_HFPCLKPLLSEL_OFFSET);
0424 r |= PRCI_HFPCLKPLLSEL_HFPCLKPLLSEL_MASK;
0425 __prci_writel(r, PRCI_HFPCLKPLLSEL_OFFSET, pd);
0426
0427 r = __prci_readl(pd, PRCI_HFPCLKPLLSEL_OFFSET);
0428 }
0429
0430
0431
0432
0433
0434
0435
0436
0437
0438
0439
0440 void sifive_prci_hfpclkpllsel_use_hfpclkpll(struct __prci_data *pd)
0441 {
0442 u32 r;
0443
0444 r = __prci_readl(pd, PRCI_HFPCLKPLLSEL_OFFSET);
0445 r &= ~PRCI_HFPCLKPLLSEL_HFPCLKPLLSEL_MASK;
0446 __prci_writel(r, PRCI_HFPCLKPLLSEL_OFFSET, pd);
0447
0448 r = __prci_readl(pd, PRCI_HFPCLKPLLSEL_OFFSET);
0449 }
0450
0451
0452 int sifive_prci_pcie_aux_clock_is_enabled(struct clk_hw *hw)
0453 {
0454 struct __prci_clock *pc = clk_hw_to_prci_clock(hw);
0455 struct __prci_data *pd = pc->pd;
0456 u32 r;
0457
0458 r = __prci_readl(pd, PRCI_PCIE_AUX_OFFSET);
0459
0460 if (r & PRCI_PCIE_AUX_EN_MASK)
0461 return 1;
0462 else
0463 return 0;
0464 }
0465
0466 int sifive_prci_pcie_aux_clock_enable(struct clk_hw *hw)
0467 {
0468 struct __prci_clock *pc = clk_hw_to_prci_clock(hw);
0469 struct __prci_data *pd = pc->pd;
0470 u32 r __maybe_unused;
0471
0472 if (sifive_prci_pcie_aux_clock_is_enabled(hw))
0473 return 0;
0474
0475 __prci_writel(1, PRCI_PCIE_AUX_OFFSET, pd);
0476 r = __prci_readl(pd, PRCI_PCIE_AUX_OFFSET);
0477
0478 return 0;
0479 }
0480
0481 void sifive_prci_pcie_aux_clock_disable(struct clk_hw *hw)
0482 {
0483 struct __prci_clock *pc = clk_hw_to_prci_clock(hw);
0484 struct __prci_data *pd = pc->pd;
0485 u32 r __maybe_unused;
0486
0487 __prci_writel(0, PRCI_PCIE_AUX_OFFSET, pd);
0488 r = __prci_readl(pd, PRCI_PCIE_AUX_OFFSET);
0489
0490 }
0491
0492
0493
0494
0495
0496
0497
0498
0499
0500
0501
0502
0503 static int __prci_register_clocks(struct device *dev, struct __prci_data *pd,
0504 const struct prci_clk_desc *desc)
0505 {
0506 struct clk_init_data init = { };
0507 struct __prci_clock *pic;
0508 int parent_count, i, r;
0509
0510 parent_count = of_clk_get_parent_count(dev->of_node);
0511 if (parent_count != EXPECTED_CLK_PARENT_COUNT) {
0512 dev_err(dev, "expected only two parent clocks, found %d\n",
0513 parent_count);
0514 return -EINVAL;
0515 }
0516
0517
0518 for (i = 0; i < desc->num_clks; ++i) {
0519 pic = &(desc->clks[i]);
0520
0521 init.name = pic->name;
0522 init.parent_names = &pic->parent_name;
0523 init.num_parents = 1;
0524 init.ops = pic->ops;
0525 pic->hw.init = &init;
0526
0527 pic->pd = pd;
0528
0529 if (pic->pwd)
0530 __prci_wrpll_read_cfg0(pd, pic->pwd);
0531
0532 r = devm_clk_hw_register(dev, &pic->hw);
0533 if (r) {
0534 dev_warn(dev, "Failed to register clock %s: %d\n",
0535 init.name, r);
0536 return r;
0537 }
0538
0539 r = clk_hw_register_clkdev(&pic->hw, pic->name, dev_name(dev));
0540 if (r) {
0541 dev_warn(dev, "Failed to register clkdev for %s: %d\n",
0542 init.name, r);
0543 return r;
0544 }
0545
0546 pd->hw_clks.hws[i] = &pic->hw;
0547 }
0548
0549 pd->hw_clks.num = i;
0550
0551 r = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get,
0552 &pd->hw_clks);
0553 if (r) {
0554 dev_err(dev, "could not add hw_provider: %d\n", r);
0555 return r;
0556 }
0557
0558 return 0;
0559 }
0560
0561
0562
0563
0564
0565
0566
0567 static int sifive_prci_probe(struct platform_device *pdev)
0568 {
0569 struct device *dev = &pdev->dev;
0570 struct resource *res;
0571 struct __prci_data *pd;
0572 const struct prci_clk_desc *desc;
0573 int r;
0574
0575 desc = of_device_get_match_data(&pdev->dev);
0576
0577 pd = devm_kzalloc(dev, struct_size(pd, hw_clks.hws, desc->num_clks), GFP_KERNEL);
0578 if (!pd)
0579 return -ENOMEM;
0580
0581 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
0582 pd->va = devm_ioremap_resource(dev, res);
0583 if (IS_ERR(pd->va))
0584 return PTR_ERR(pd->va);
0585
0586 pd->reset.rcdev.owner = THIS_MODULE;
0587 pd->reset.rcdev.nr_resets = PRCI_RST_NR;
0588 pd->reset.rcdev.ops = &reset_simple_ops;
0589 pd->reset.rcdev.of_node = pdev->dev.of_node;
0590 pd->reset.active_low = true;
0591 pd->reset.membase = pd->va + PRCI_DEVICESRESETREG_OFFSET;
0592 spin_lock_init(&pd->reset.lock);
0593
0594 r = devm_reset_controller_register(&pdev->dev, &pd->reset.rcdev);
0595 if (r) {
0596 dev_err(dev, "could not register reset controller: %d\n", r);
0597 return r;
0598 }
0599 r = __prci_register_clocks(dev, pd, desc);
0600 if (r) {
0601 dev_err(dev, "could not register clocks: %d\n", r);
0602 return r;
0603 }
0604
0605 dev_dbg(dev, "SiFive PRCI probed\n");
0606
0607 return 0;
0608 }
0609
0610 static const struct of_device_id sifive_prci_of_match[] = {
0611 {.compatible = "sifive,fu540-c000-prci", .data = &prci_clk_fu540},
0612 {.compatible = "sifive,fu740-c000-prci", .data = &prci_clk_fu740},
0613 {}
0614 };
0615
0616 static struct platform_driver sifive_prci_driver = {
0617 .driver = {
0618 .name = "sifive-clk-prci",
0619 .of_match_table = sifive_prci_of_match,
0620 },
0621 .probe = sifive_prci_probe,
0622 };
0623
0624 static int __init sifive_prci_init(void)
0625 {
0626 return platform_driver_register(&sifive_prci_driver);
0627 }
0628 core_initcall(sifive_prci_init);