diff options
author | Gabriel Fernandez <gabriel.fernandez@st.com> | 2018-03-08 11:53:58 -0500 |
---|---|---|
committer | Michael Turquette <mturquette@baylibre.com> | 2018-03-11 18:40:33 -0400 |
commit | c6cf4d3248980c5e1998ce21f3c2d86502f7e1a9 (patch) | |
tree | 29720b145816929e73d9e32a3e2f3aef535a1b73 | |
parent | dc32eaac4926b02fddba3ff02030827429394ad7 (diff) |
clk: stm32mp1: add PLL clocks
STMP32MP1 has 4 PLLs.
PLL supports integer and fractional mode.
Each PLL has 3 output dividers (p, q, r)
Signed-off-by: Gabriel Fernandez <gabriel.fernandez@st.com>
Signed-off-by: Michael Turquette <mturquette@baylibre.com>
-rw-r--r-- | drivers/clk/clk-stm32mp1.c | 209 |
1 files changed, 209 insertions, 0 deletions
diff --git a/drivers/clk/clk-stm32mp1.c b/drivers/clk/clk-stm32mp1.c index 47984f36494b..d62a3a94cc67 100644 --- a/drivers/clk/clk-stm32mp1.c +++ b/drivers/clk/clk-stm32mp1.c | |||
@@ -7,6 +7,7 @@ | |||
7 | 7 | ||
8 | #include <linux/clk.h> | 8 | #include <linux/clk.h> |
9 | #include <linux/clk-provider.h> | 9 | #include <linux/clk-provider.h> |
10 | #include <linux/delay.h> | ||
10 | #include <linux/err.h> | 11 | #include <linux/err.h> |
11 | #include <linux/io.h> | 12 | #include <linux/io.h> |
12 | #include <linux/of.h> | 13 | #include <linux/of.h> |
@@ -321,6 +322,196 @@ clk_stm32_register_gate_ops(struct device *dev, | |||
321 | return hw; | 322 | return hw; |
322 | } | 323 | } |
323 | 324 | ||
325 | /* STM32 PLL */ | ||
326 | |||
327 | struct stm32_pll_obj { | ||
328 | /* lock pll enable/disable registers */ | ||
329 | spinlock_t *lock; | ||
330 | void __iomem *reg; | ||
331 | struct clk_hw hw; | ||
332 | }; | ||
333 | |||
334 | #define to_pll(_hw) container_of(_hw, struct stm32_pll_obj, hw) | ||
335 | |||
336 | #define PLL_ON BIT(0) | ||
337 | #define PLL_RDY BIT(1) | ||
338 | #define DIVN_MASK 0x1FF | ||
339 | #define DIVM_MASK 0x3F | ||
340 | #define DIVM_SHIFT 16 | ||
341 | #define DIVN_SHIFT 0 | ||
342 | #define FRAC_OFFSET 0xC | ||
343 | #define FRAC_MASK 0x1FFF | ||
344 | #define FRAC_SHIFT 3 | ||
345 | #define FRACLE BIT(16) | ||
346 | |||
347 | static int __pll_is_enabled(struct clk_hw *hw) | ||
348 | { | ||
349 | struct stm32_pll_obj *clk_elem = to_pll(hw); | ||
350 | |||
351 | return readl_relaxed(clk_elem->reg) & PLL_ON; | ||
352 | } | ||
353 | |||
354 | #define TIMEOUT 5 | ||
355 | |||
356 | static int pll_enable(struct clk_hw *hw) | ||
357 | { | ||
358 | struct stm32_pll_obj *clk_elem = to_pll(hw); | ||
359 | u32 reg; | ||
360 | unsigned long flags = 0; | ||
361 | unsigned int timeout = TIMEOUT; | ||
362 | int bit_status = 0; | ||
363 | |||
364 | spin_lock_irqsave(clk_elem->lock, flags); | ||
365 | |||
366 | if (__pll_is_enabled(hw)) | ||
367 | goto unlock; | ||
368 | |||
369 | reg = readl_relaxed(clk_elem->reg); | ||
370 | reg |= PLL_ON; | ||
371 | writel_relaxed(reg, clk_elem->reg); | ||
372 | |||
373 | /* We can't use readl_poll_timeout() because we can be blocked if | ||
374 | * someone enables this clock before clocksource changes. | ||
375 | * Only jiffies counter is available. Jiffies are incremented by | ||
376 | * interruptions and enable op does not allow to be interrupted. | ||
377 | */ | ||
378 | do { | ||
379 | bit_status = !(readl_relaxed(clk_elem->reg) & PLL_RDY); | ||
380 | |||
381 | if (bit_status) | ||
382 | udelay(120); | ||
383 | |||
384 | } while (bit_status && --timeout); | ||
385 | |||
386 | unlock: | ||
387 | spin_unlock_irqrestore(clk_elem->lock, flags); | ||
388 | |||
389 | return bit_status; | ||
390 | } | ||
391 | |||
392 | static void pll_disable(struct clk_hw *hw) | ||
393 | { | ||
394 | struct stm32_pll_obj *clk_elem = to_pll(hw); | ||
395 | u32 reg; | ||
396 | unsigned long flags = 0; | ||
397 | |||
398 | spin_lock_irqsave(clk_elem->lock, flags); | ||
399 | |||
400 | reg = readl_relaxed(clk_elem->reg); | ||
401 | reg &= ~PLL_ON; | ||
402 | writel_relaxed(reg, clk_elem->reg); | ||
403 | |||
404 | spin_unlock_irqrestore(clk_elem->lock, flags); | ||
405 | } | ||
406 | |||
407 | static u32 pll_frac_val(struct clk_hw *hw) | ||
408 | { | ||
409 | struct stm32_pll_obj *clk_elem = to_pll(hw); | ||
410 | u32 reg, frac = 0; | ||
411 | |||
412 | reg = readl_relaxed(clk_elem->reg + FRAC_OFFSET); | ||
413 | if (reg & FRACLE) | ||
414 | frac = (reg >> FRAC_SHIFT) & FRAC_MASK; | ||
415 | |||
416 | return frac; | ||
417 | } | ||
418 | |||
419 | static unsigned long pll_recalc_rate(struct clk_hw *hw, | ||
420 | unsigned long parent_rate) | ||
421 | { | ||
422 | struct stm32_pll_obj *clk_elem = to_pll(hw); | ||
423 | u32 reg; | ||
424 | u32 frac, divm, divn; | ||
425 | u64 rate, rate_frac = 0; | ||
426 | |||
427 | reg = readl_relaxed(clk_elem->reg + 4); | ||
428 | |||
429 | divm = ((reg >> DIVM_SHIFT) & DIVM_MASK) + 1; | ||
430 | divn = ((reg >> DIVN_SHIFT) & DIVN_MASK) + 1; | ||
431 | rate = (u64)parent_rate * divn; | ||
432 | |||
433 | do_div(rate, divm); | ||
434 | |||
435 | frac = pll_frac_val(hw); | ||
436 | if (frac) { | ||
437 | rate_frac = (u64)parent_rate * (u64)frac; | ||
438 | do_div(rate_frac, (divm * 8192)); | ||
439 | } | ||
440 | |||
441 | return rate + rate_frac; | ||
442 | } | ||
443 | |||
444 | static int pll_is_enabled(struct clk_hw *hw) | ||
445 | { | ||
446 | struct stm32_pll_obj *clk_elem = to_pll(hw); | ||
447 | unsigned long flags = 0; | ||
448 | int ret; | ||
449 | |||
450 | spin_lock_irqsave(clk_elem->lock, flags); | ||
451 | ret = __pll_is_enabled(hw); | ||
452 | spin_unlock_irqrestore(clk_elem->lock, flags); | ||
453 | |||
454 | return ret; | ||
455 | } | ||
456 | |||
457 | static const struct clk_ops pll_ops = { | ||
458 | .enable = pll_enable, | ||
459 | .disable = pll_disable, | ||
460 | .recalc_rate = pll_recalc_rate, | ||
461 | .is_enabled = pll_is_enabled, | ||
462 | }; | ||
463 | |||
464 | static struct clk_hw *clk_register_pll(struct device *dev, const char *name, | ||
465 | const char *parent_name, | ||
466 | void __iomem *reg, | ||
467 | unsigned long flags, | ||
468 | spinlock_t *lock) | ||
469 | { | ||
470 | struct stm32_pll_obj *element; | ||
471 | struct clk_init_data init; | ||
472 | struct clk_hw *hw; | ||
473 | int err; | ||
474 | |||
475 | element = kzalloc(sizeof(*element), GFP_KERNEL); | ||
476 | if (!element) | ||
477 | return ERR_PTR(-ENOMEM); | ||
478 | |||
479 | init.name = name; | ||
480 | init.ops = &pll_ops; | ||
481 | init.flags = flags; | ||
482 | init.parent_names = &parent_name; | ||
483 | init.num_parents = 1; | ||
484 | |||
485 | element->hw.init = &init; | ||
486 | element->reg = reg; | ||
487 | element->lock = lock; | ||
488 | |||
489 | hw = &element->hw; | ||
490 | err = clk_hw_register(dev, hw); | ||
491 | |||
492 | if (err) { | ||
493 | kfree(element); | ||
494 | return ERR_PTR(err); | ||
495 | } | ||
496 | |||
497 | return hw; | ||
498 | } | ||
499 | |||
500 | struct stm32_pll_cfg { | ||
501 | u32 offset; | ||
502 | }; | ||
503 | |||
504 | struct clk_hw *_clk_register_pll(struct device *dev, | ||
505 | struct clk_hw_onecell_data *clk_data, | ||
506 | void __iomem *base, spinlock_t *lock, | ||
507 | const struct clock_config *cfg) | ||
508 | { | ||
509 | struct stm32_pll_cfg *stm_pll_cfg = cfg->cfg; | ||
510 | |||
511 | return clk_register_pll(dev, cfg->name, cfg->parent_name, | ||
512 | base + stm_pll_cfg->offset, cfg->flags, lock); | ||
513 | } | ||
514 | |||
324 | static struct clk_hw * | 515 | static struct clk_hw * |
325 | _clk_stm32_register_gate(struct device *dev, | 516 | _clk_stm32_register_gate(struct device *dev, |
326 | struct clk_hw_onecell_data *clk_data, | 517 | struct clk_hw_onecell_data *clk_data, |
@@ -400,6 +591,18 @@ _clk_stm32_register_gate(struct device *dev, | |||
400 | .func = _clk_hw_register_mux,\ | 591 | .func = _clk_hw_register_mux,\ |
401 | } | 592 | } |
402 | 593 | ||
594 | #define PLL(_id, _name, _parent, _flags, _offset)\ | ||
595 | {\ | ||
596 | .id = _id,\ | ||
597 | .name = _name,\ | ||
598 | .parent_name = _parent,\ | ||
599 | .flags = _flags,\ | ||
600 | .cfg = &(struct stm32_pll_cfg) {\ | ||
601 | .offset = _offset,\ | ||
602 | },\ | ||
603 | .func = _clk_register_pll,\ | ||
604 | } | ||
605 | |||
403 | /* STM32 GATE */ | 606 | /* STM32 GATE */ |
404 | #define STM32_GATE(_id, _name, _parent, _flags, _gate)\ | 607 | #define STM32_GATE(_id, _name, _parent, _flags, _gate)\ |
405 | {\ | 608 | {\ |
@@ -452,6 +655,12 @@ static const struct clock_config stm32mp1_clock_cfg[] = { | |||
452 | 655 | ||
453 | MUX(NO_ID, "ref4", ref4_parents, CLK_OPS_PARENT_ENABLE, RCC_RCK4SELR, | 656 | MUX(NO_ID, "ref4", ref4_parents, CLK_OPS_PARENT_ENABLE, RCC_RCK4SELR, |
454 | 0, 2, CLK_MUX_READ_ONLY), | 657 | 0, 2, CLK_MUX_READ_ONLY), |
658 | |||
659 | /* PLLs */ | ||
660 | PLL(PLL1, "pll1", "ref1", CLK_IGNORE_UNUSED, RCC_PLL1CR), | ||
661 | PLL(PLL2, "pll2", "ref1", CLK_IGNORE_UNUSED, RCC_PLL2CR), | ||
662 | PLL(PLL3, "pll3", "ref3", CLK_IGNORE_UNUSED, RCC_PLL3CR), | ||
663 | PLL(PLL4, "pll4", "ref4", CLK_IGNORE_UNUSED, RCC_PLL4CR), | ||
455 | }; | 664 | }; |
456 | 665 | ||
457 | struct stm32_clock_match_data { | 666 | struct stm32_clock_match_data { |