diff options
author | Gabriel Fernandez <gabriel.fernandez@st.com> | 2018-03-08 11:53:59 -0500 |
---|---|---|
committer | Michael Turquette <mturquette@baylibre.com> | 2018-03-11 18:40:33 -0400 |
commit | a97703c59f653f75814865c22ae6b16f5c477530 (patch) | |
tree | 1cd0b4df0e90609a8241bffd0b6d13b6b1d0adc6 | |
parent | c6cf4d3248980c5e1998ce21f3c2d86502f7e1a9 (diff) |
clk: stm32mp1: add Post-dividers for PLL
Each PLL has 3 outputs with post-dividers.
pll1_p is dedicated for Cortex-A7
pll1_q is not connected
pll1_r is not connected
pll2_p is dedicated for AXI
pll2_q is dedicated for GPU
pll2_r is dedicated for DDR
pll3_p is dedicated for mcu
pll3_q is for Peripheral Kernel Clock
pll3_r is for Peripheral Kernel Clock
pll4_p is for Peripheral Kernel Clock
pll4_q is for Peripheral Kernel Clock
pll4_r is for Peripheral Kernel Clock
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 | 221 |
1 files changed, 221 insertions, 0 deletions
diff --git a/drivers/clk/clk-stm32mp1.c b/drivers/clk/clk-stm32mp1.c index d62a3a94cc67..3a99ad7f7048 100644 --- a/drivers/clk/clk-stm32mp1.c +++ b/drivers/clk/clk-stm32mp1.c | |||
@@ -166,6 +166,23 @@ struct stm32_gate_cfg { | |||
166 | const struct clk_ops *ops; | 166 | const struct clk_ops *ops; |
167 | }; | 167 | }; |
168 | 168 | ||
169 | struct stm32_div_cfg { | ||
170 | struct div_cfg *div; | ||
171 | const struct clk_ops *ops; | ||
172 | }; | ||
173 | |||
174 | struct stm32_mux_cfg { | ||
175 | struct mux_cfg *mux; | ||
176 | const struct clk_ops *ops; | ||
177 | }; | ||
178 | |||
179 | /* STM32 Composite clock */ | ||
180 | struct stm32_composite_cfg { | ||
181 | const struct stm32_gate_cfg *gate; | ||
182 | const struct stm32_div_cfg *div; | ||
183 | const struct stm32_mux_cfg *mux; | ||
184 | }; | ||
185 | |||
169 | static struct clk_hw * | 186 | static struct clk_hw * |
170 | _clk_hw_register_gate(struct device *dev, | 187 | _clk_hw_register_gate(struct device *dev, |
171 | struct clk_hw_onecell_data *clk_data, | 188 | struct clk_hw_onecell_data *clk_data, |
@@ -259,6 +276,51 @@ const struct clk_ops mp1_gate_clk_ops = { | |||
259 | .is_enabled = clk_gate_is_enabled, | 276 | .is_enabled = clk_gate_is_enabled, |
260 | }; | 277 | }; |
261 | 278 | ||
279 | static struct clk_hw *_get_stm32_mux(void __iomem *base, | ||
280 | const struct stm32_mux_cfg *cfg, | ||
281 | spinlock_t *lock) | ||
282 | { | ||
283 | struct clk_mux *mux; | ||
284 | struct clk_hw *mux_hw; | ||
285 | |||
286 | mux = kzalloc(sizeof(*mux), GFP_KERNEL); | ||
287 | if (!mux) | ||
288 | return ERR_PTR(-ENOMEM); | ||
289 | |||
290 | mux->reg = cfg->mux->reg_off + base; | ||
291 | mux->shift = cfg->mux->shift; | ||
292 | mux->mask = (1 << cfg->mux->width) - 1; | ||
293 | mux->flags = cfg->mux->mux_flags; | ||
294 | mux->table = cfg->mux->table; | ||
295 | |||
296 | mux->lock = lock; | ||
297 | |||
298 | mux_hw = &mux->hw; | ||
299 | |||
300 | return mux_hw; | ||
301 | } | ||
302 | |||
303 | static struct clk_hw *_get_stm32_div(void __iomem *base, | ||
304 | const struct stm32_div_cfg *cfg, | ||
305 | spinlock_t *lock) | ||
306 | { | ||
307 | struct clk_divider *div; | ||
308 | |||
309 | div = kzalloc(sizeof(*div), GFP_KERNEL); | ||
310 | |||
311 | if (!div) | ||
312 | return ERR_PTR(-ENOMEM); | ||
313 | |||
314 | div->reg = cfg->div->reg_off + base; | ||
315 | div->shift = cfg->div->shift; | ||
316 | div->width = cfg->div->width; | ||
317 | div->flags = cfg->div->div_flags; | ||
318 | div->table = cfg->div->table; | ||
319 | div->lock = lock; | ||
320 | |||
321 | return &div->hw; | ||
322 | } | ||
323 | |||
262 | static struct clk_hw * | 324 | static struct clk_hw * |
263 | _get_stm32_gate(void __iomem *base, | 325 | _get_stm32_gate(void __iomem *base, |
264 | const struct stm32_gate_cfg *cfg, spinlock_t *lock) | 326 | const struct stm32_gate_cfg *cfg, spinlock_t *lock) |
@@ -322,6 +384,61 @@ clk_stm32_register_gate_ops(struct device *dev, | |||
322 | return hw; | 384 | return hw; |
323 | } | 385 | } |
324 | 386 | ||
387 | static struct clk_hw * | ||
388 | clk_stm32_register_composite(struct device *dev, | ||
389 | const char *name, const char * const *parent_names, | ||
390 | int num_parents, void __iomem *base, | ||
391 | const struct stm32_composite_cfg *cfg, | ||
392 | unsigned long flags, spinlock_t *lock) | ||
393 | { | ||
394 | const struct clk_ops *mux_ops, *div_ops, *gate_ops; | ||
395 | struct clk_hw *mux_hw, *div_hw, *gate_hw; | ||
396 | |||
397 | mux_hw = NULL; | ||
398 | div_hw = NULL; | ||
399 | gate_hw = NULL; | ||
400 | mux_ops = NULL; | ||
401 | div_ops = NULL; | ||
402 | gate_ops = NULL; | ||
403 | |||
404 | if (cfg->mux) { | ||
405 | mux_hw = _get_stm32_mux(base, cfg->mux, lock); | ||
406 | |||
407 | if (!IS_ERR(mux_hw)) { | ||
408 | mux_ops = &clk_mux_ops; | ||
409 | |||
410 | if (cfg->mux->ops) | ||
411 | mux_ops = cfg->mux->ops; | ||
412 | } | ||
413 | } | ||
414 | |||
415 | if (cfg->div) { | ||
416 | div_hw = _get_stm32_div(base, cfg->div, lock); | ||
417 | |||
418 | if (!IS_ERR(div_hw)) { | ||
419 | div_ops = &clk_divider_ops; | ||
420 | |||
421 | if (cfg->div->ops) | ||
422 | div_ops = cfg->div->ops; | ||
423 | } | ||
424 | } | ||
425 | |||
426 | if (cfg->gate) { | ||
427 | gate_hw = _get_stm32_gate(base, cfg->gate, lock); | ||
428 | |||
429 | if (!IS_ERR(gate_hw)) { | ||
430 | gate_ops = &clk_gate_ops; | ||
431 | |||
432 | if (cfg->gate->ops) | ||
433 | gate_ops = cfg->gate->ops; | ||
434 | } | ||
435 | } | ||
436 | |||
437 | return clk_hw_register_composite(dev, name, parent_names, num_parents, | ||
438 | mux_hw, mux_ops, div_hw, div_ops, | ||
439 | gate_hw, gate_ops, flags); | ||
440 | } | ||
441 | |||
325 | /* STM32 PLL */ | 442 | /* STM32 PLL */ |
326 | 443 | ||
327 | struct stm32_pll_obj { | 444 | struct stm32_pll_obj { |
@@ -527,6 +644,17 @@ _clk_stm32_register_gate(struct device *dev, | |||
527 | lock); | 644 | lock); |
528 | } | 645 | } |
529 | 646 | ||
647 | static struct clk_hw * | ||
648 | _clk_stm32_register_composite(struct device *dev, | ||
649 | struct clk_hw_onecell_data *clk_data, | ||
650 | void __iomem *base, spinlock_t *lock, | ||
651 | const struct clock_config *cfg) | ||
652 | { | ||
653 | return clk_stm32_register_composite(dev, cfg->name, cfg->parent_names, | ||
654 | cfg->num_parents, base, cfg->cfg, | ||
655 | cfg->flags, lock); | ||
656 | } | ||
657 | |||
530 | #define GATE(_id, _name, _parent, _flags, _offset, _bit_idx, _gate_flags)\ | 658 | #define GATE(_id, _name, _parent, _flags, _offset, _bit_idx, _gate_flags)\ |
531 | {\ | 659 | {\ |
532 | .id = _id,\ | 660 | .id = _id,\ |
@@ -624,6 +752,10 @@ _clk_stm32_register_gate(struct device *dev, | |||
624 | .ops = _ops,\ | 752 | .ops = _ops,\ |
625 | }) | 753 | }) |
626 | 754 | ||
755 | #define _GATE(_gate_offset, _gate_bit_idx, _gate_flags)\ | ||
756 | _STM32_GATE(_gate_offset, _gate_bit_idx, _gate_flags,\ | ||
757 | NULL)\ | ||
758 | |||
627 | #define _GATE_MP1(_gate_offset, _gate_bit_idx, _gate_flags)\ | 759 | #define _GATE_MP1(_gate_offset, _gate_bit_idx, _gate_flags)\ |
628 | _STM32_GATE(_gate_offset, _gate_bit_idx, _gate_flags,\ | 760 | _STM32_GATE(_gate_offset, _gate_bit_idx, _gate_flags,\ |
629 | &mp1_gate_clk_ops)\ | 761 | &mp1_gate_clk_ops)\ |
@@ -632,6 +764,44 @@ _clk_stm32_register_gate(struct device *dev, | |||
632 | STM32_GATE(_id, _name, _parent, _flags,\ | 764 | STM32_GATE(_id, _name, _parent, _flags,\ |
633 | _GATE_MP1(_offset, _bit_idx, _gate_flags)) | 765 | _GATE_MP1(_offset, _bit_idx, _gate_flags)) |
634 | 766 | ||
767 | #define _STM32_DIV(_div_offset, _div_shift, _div_width,\ | ||
768 | _div_flags, _div_table, _ops)\ | ||
769 | .div = &(struct stm32_div_cfg) {\ | ||
770 | &(struct div_cfg) {\ | ||
771 | .reg_off = _div_offset,\ | ||
772 | .shift = _div_shift,\ | ||
773 | .width = _div_width,\ | ||
774 | .div_flags = _div_flags,\ | ||
775 | .table = _div_table,\ | ||
776 | },\ | ||
777 | .ops = _ops,\ | ||
778 | } | ||
779 | |||
780 | #define _DIV(_div_offset, _div_shift, _div_width, _div_flags, _div_table)\ | ||
781 | _STM32_DIV(_div_offset, _div_shift, _div_width,\ | ||
782 | _div_flags, _div_table, NULL)\ | ||
783 | |||
784 | #define PARENT(_parent) ((const char *[]) { _parent}) | ||
785 | |||
786 | #define _NO_MUX .mux = NULL | ||
787 | #define _NO_DIV .div = NULL | ||
788 | #define _NO_GATE .gate = NULL | ||
789 | |||
790 | #define COMPOSITE(_id, _name, _parents, _flags, _gate, _mux, _div)\ | ||
791 | {\ | ||
792 | .id = _id,\ | ||
793 | .name = _name,\ | ||
794 | .parent_names = _parents,\ | ||
795 | .num_parents = ARRAY_SIZE(_parents),\ | ||
796 | .flags = _flags,\ | ||
797 | .cfg = &(struct stm32_composite_cfg) {\ | ||
798 | _gate,\ | ||
799 | _mux,\ | ||
800 | _div,\ | ||
801 | },\ | ||
802 | .func = _clk_stm32_register_composite,\ | ||
803 | } | ||
804 | |||
635 | static const struct clock_config stm32mp1_clock_cfg[] = { | 805 | static const struct clock_config stm32mp1_clock_cfg[] = { |
636 | /* Oscillator divider */ | 806 | /* Oscillator divider */ |
637 | DIV(NO_ID, "clk-hsi-div", "clk-hsi", 0, RCC_HSICFGR, 0, 2, | 807 | DIV(NO_ID, "clk-hsi-div", "clk-hsi", 0, RCC_HSICFGR, 0, 2, |
@@ -661,6 +831,57 @@ static const struct clock_config stm32mp1_clock_cfg[] = { | |||
661 | PLL(PLL2, "pll2", "ref1", CLK_IGNORE_UNUSED, RCC_PLL2CR), | 831 | PLL(PLL2, "pll2", "ref1", CLK_IGNORE_UNUSED, RCC_PLL2CR), |
662 | PLL(PLL3, "pll3", "ref3", CLK_IGNORE_UNUSED, RCC_PLL3CR), | 832 | PLL(PLL3, "pll3", "ref3", CLK_IGNORE_UNUSED, RCC_PLL3CR), |
663 | PLL(PLL4, "pll4", "ref4", CLK_IGNORE_UNUSED, RCC_PLL4CR), | 833 | PLL(PLL4, "pll4", "ref4", CLK_IGNORE_UNUSED, RCC_PLL4CR), |
834 | |||
835 | /* ODF */ | ||
836 | COMPOSITE(PLL1_P, "pll1_p", PARENT("pll1"), 0, | ||
837 | _GATE(RCC_PLL1CR, 4, 0), | ||
838 | _NO_MUX, | ||
839 | _DIV(RCC_PLL1CFGR2, 0, 7, 0, NULL)), | ||
840 | |||
841 | COMPOSITE(PLL2_P, "pll2_p", PARENT("pll2"), 0, | ||
842 | _GATE(RCC_PLL2CR, 4, 0), | ||
843 | _NO_MUX, | ||
844 | _DIV(RCC_PLL2CFGR2, 0, 7, 0, NULL)), | ||
845 | |||
846 | COMPOSITE(PLL2_Q, "pll2_q", PARENT("pll2"), 0, | ||
847 | _GATE(RCC_PLL2CR, 5, 0), | ||
848 | _NO_MUX, | ||
849 | _DIV(RCC_PLL2CFGR2, 8, 7, 0, NULL)), | ||
850 | |||
851 | COMPOSITE(PLL2_R, "pll2_r", PARENT("pll2"), CLK_IS_CRITICAL, | ||
852 | _GATE(RCC_PLL2CR, 6, 0), | ||
853 | _NO_MUX, | ||
854 | _DIV(RCC_PLL2CFGR2, 16, 7, 0, NULL)), | ||
855 | |||
856 | COMPOSITE(PLL3_P, "pll3_p", PARENT("pll3"), 0, | ||
857 | _GATE(RCC_PLL3CR, 4, 0), | ||
858 | _NO_MUX, | ||
859 | _DIV(RCC_PLL3CFGR2, 0, 7, 0, NULL)), | ||
860 | |||
861 | COMPOSITE(PLL3_Q, "pll3_q", PARENT("pll3"), 0, | ||
862 | _GATE(RCC_PLL3CR, 5, 0), | ||
863 | _NO_MUX, | ||
864 | _DIV(RCC_PLL3CFGR2, 8, 7, 0, NULL)), | ||
865 | |||
866 | COMPOSITE(PLL3_R, "pll3_r", PARENT("pll3"), 0, | ||
867 | _GATE(RCC_PLL3CR, 6, 0), | ||
868 | _NO_MUX, | ||
869 | _DIV(RCC_PLL3CFGR2, 16, 7, 0, NULL)), | ||
870 | |||
871 | COMPOSITE(PLL4_P, "pll4_p", PARENT("pll4"), 0, | ||
872 | _GATE(RCC_PLL4CR, 4, 0), | ||
873 | _NO_MUX, | ||
874 | _DIV(RCC_PLL4CFGR2, 0, 7, 0, NULL)), | ||
875 | |||
876 | COMPOSITE(PLL4_Q, "pll4_q", PARENT("pll4"), 0, | ||
877 | _GATE(RCC_PLL4CR, 5, 0), | ||
878 | _NO_MUX, | ||
879 | _DIV(RCC_PLL4CFGR2, 8, 7, 0, NULL)), | ||
880 | |||
881 | COMPOSITE(PLL4_R, "pll4_r", PARENT("pll4"), 0, | ||
882 | _GATE(RCC_PLL4CR, 6, 0), | ||
883 | _NO_MUX, | ||
884 | _DIV(RCC_PLL4CFGR2, 16, 7, 0, NULL)), | ||
664 | }; | 885 | }; |
665 | 886 | ||
666 | struct stm32_clock_match_data { | 887 | struct stm32_clock_match_data { |