.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * OMAP3/4 - specific DPLL control functions |
---|
3 | 4 | * |
---|
.. | .. |
---|
12 | 13 | * |
---|
13 | 14 | * Parts of this code are based on code written by |
---|
14 | 15 | * Richard Woodruff, Tony Lindgren, Tuukka Tikkanen, Karthik Dasu |
---|
15 | | - * |
---|
16 | | - * This program is free software; you can redistribute it and/or modify |
---|
17 | | - * it under the terms of the GNU General Public License version 2 as |
---|
18 | | - * published by the Free Software Foundation. |
---|
19 | 16 | */ |
---|
20 | 17 | |
---|
21 | 18 | #include <linux/kernel.h> |
---|
.. | .. |
---|
731 | 728 | do { |
---|
732 | 729 | do { |
---|
733 | 730 | hw = clk_hw_get_parent(hw); |
---|
734 | | - } while (hw && (clk_hw_get_flags(hw) & CLK_IS_BASIC)); |
---|
| 731 | + } while (hw && (!omap2_clk_is_hw_omap(hw))); |
---|
735 | 732 | if (!hw) |
---|
736 | 733 | break; |
---|
737 | 734 | pclk = to_clk_hw_omap(hw); |
---|
.. | .. |
---|
782 | 779 | return rate; |
---|
783 | 780 | } |
---|
784 | 781 | |
---|
| 782 | +/** |
---|
| 783 | + * omap3_core_dpll_save_context - Save the m and n values of the divider |
---|
| 784 | + * @hw: pointer struct clk_hw |
---|
| 785 | + * |
---|
| 786 | + * Before the dpll registers are lost save the last rounded rate m and n |
---|
| 787 | + * and the enable mask. |
---|
| 788 | + */ |
---|
| 789 | +int omap3_core_dpll_save_context(struct clk_hw *hw) |
---|
| 790 | +{ |
---|
| 791 | + struct clk_hw_omap *clk = to_clk_hw_omap(hw); |
---|
| 792 | + struct dpll_data *dd; |
---|
| 793 | + u32 v; |
---|
| 794 | + |
---|
| 795 | + dd = clk->dpll_data; |
---|
| 796 | + |
---|
| 797 | + v = ti_clk_ll_ops->clk_readl(&dd->control_reg); |
---|
| 798 | + clk->context = (v & dd->enable_mask) >> __ffs(dd->enable_mask); |
---|
| 799 | + |
---|
| 800 | + if (clk->context == DPLL_LOCKED) { |
---|
| 801 | + v = ti_clk_ll_ops->clk_readl(&dd->mult_div1_reg); |
---|
| 802 | + dd->last_rounded_m = (v & dd->mult_mask) >> |
---|
| 803 | + __ffs(dd->mult_mask); |
---|
| 804 | + dd->last_rounded_n = ((v & dd->div1_mask) >> |
---|
| 805 | + __ffs(dd->div1_mask)) + 1; |
---|
| 806 | + } |
---|
| 807 | + |
---|
| 808 | + return 0; |
---|
| 809 | +} |
---|
| 810 | + |
---|
| 811 | +/** |
---|
| 812 | + * omap3_core_dpll_restore_context - restore the m and n values of the divider |
---|
| 813 | + * @hw: pointer struct clk_hw |
---|
| 814 | + * |
---|
| 815 | + * Restore the last rounded rate m and n |
---|
| 816 | + * and the enable mask. |
---|
| 817 | + */ |
---|
| 818 | +void omap3_core_dpll_restore_context(struct clk_hw *hw) |
---|
| 819 | +{ |
---|
| 820 | + struct clk_hw_omap *clk = to_clk_hw_omap(hw); |
---|
| 821 | + const struct dpll_data *dd; |
---|
| 822 | + u32 v; |
---|
| 823 | + |
---|
| 824 | + dd = clk->dpll_data; |
---|
| 825 | + |
---|
| 826 | + if (clk->context == DPLL_LOCKED) { |
---|
| 827 | + _omap3_dpll_write_clken(clk, 0x4); |
---|
| 828 | + _omap3_wait_dpll_status(clk, 0); |
---|
| 829 | + |
---|
| 830 | + v = ti_clk_ll_ops->clk_readl(&dd->mult_div1_reg); |
---|
| 831 | + v &= ~(dd->mult_mask | dd->div1_mask); |
---|
| 832 | + v |= dd->last_rounded_m << __ffs(dd->mult_mask); |
---|
| 833 | + v |= (dd->last_rounded_n - 1) << __ffs(dd->div1_mask); |
---|
| 834 | + ti_clk_ll_ops->clk_writel(v, &dd->mult_div1_reg); |
---|
| 835 | + |
---|
| 836 | + _omap3_dpll_write_clken(clk, DPLL_LOCKED); |
---|
| 837 | + _omap3_wait_dpll_status(clk, 1); |
---|
| 838 | + } else { |
---|
| 839 | + _omap3_dpll_write_clken(clk, clk->context); |
---|
| 840 | + } |
---|
| 841 | +} |
---|
| 842 | + |
---|
| 843 | +/** |
---|
| 844 | + * omap3_non_core_dpll_save_context - Save the m and n values of the divider |
---|
| 845 | + * @hw: pointer struct clk_hw |
---|
| 846 | + * |
---|
| 847 | + * Before the dpll registers are lost save the last rounded rate m and n |
---|
| 848 | + * and the enable mask. |
---|
| 849 | + */ |
---|
| 850 | +int omap3_noncore_dpll_save_context(struct clk_hw *hw) |
---|
| 851 | +{ |
---|
| 852 | + struct clk_hw_omap *clk = to_clk_hw_omap(hw); |
---|
| 853 | + struct dpll_data *dd; |
---|
| 854 | + u32 v; |
---|
| 855 | + |
---|
| 856 | + dd = clk->dpll_data; |
---|
| 857 | + |
---|
| 858 | + v = ti_clk_ll_ops->clk_readl(&dd->control_reg); |
---|
| 859 | + clk->context = (v & dd->enable_mask) >> __ffs(dd->enable_mask); |
---|
| 860 | + |
---|
| 861 | + if (clk->context == DPLL_LOCKED) { |
---|
| 862 | + v = ti_clk_ll_ops->clk_readl(&dd->mult_div1_reg); |
---|
| 863 | + dd->last_rounded_m = (v & dd->mult_mask) >> |
---|
| 864 | + __ffs(dd->mult_mask); |
---|
| 865 | + dd->last_rounded_n = ((v & dd->div1_mask) >> |
---|
| 866 | + __ffs(dd->div1_mask)) + 1; |
---|
| 867 | + } |
---|
| 868 | + |
---|
| 869 | + return 0; |
---|
| 870 | +} |
---|
| 871 | + |
---|
| 872 | +/** |
---|
| 873 | + * omap3_core_dpll_restore_context - restore the m and n values of the divider |
---|
| 874 | + * @hw: pointer struct clk_hw |
---|
| 875 | + * |
---|
| 876 | + * Restore the last rounded rate m and n |
---|
| 877 | + * and the enable mask. |
---|
| 878 | + */ |
---|
| 879 | +void omap3_noncore_dpll_restore_context(struct clk_hw *hw) |
---|
| 880 | +{ |
---|
| 881 | + struct clk_hw_omap *clk = to_clk_hw_omap(hw); |
---|
| 882 | + const struct dpll_data *dd; |
---|
| 883 | + u32 ctrl, mult_div1; |
---|
| 884 | + |
---|
| 885 | + dd = clk->dpll_data; |
---|
| 886 | + |
---|
| 887 | + ctrl = ti_clk_ll_ops->clk_readl(&dd->control_reg); |
---|
| 888 | + mult_div1 = ti_clk_ll_ops->clk_readl(&dd->mult_div1_reg); |
---|
| 889 | + |
---|
| 890 | + if (clk->context == ((ctrl & dd->enable_mask) >> |
---|
| 891 | + __ffs(dd->enable_mask)) && |
---|
| 892 | + dd->last_rounded_m == ((mult_div1 & dd->mult_mask) >> |
---|
| 893 | + __ffs(dd->mult_mask)) && |
---|
| 894 | + dd->last_rounded_n == ((mult_div1 & dd->div1_mask) >> |
---|
| 895 | + __ffs(dd->div1_mask)) + 1) { |
---|
| 896 | + /* nothing to be done */ |
---|
| 897 | + return; |
---|
| 898 | + } |
---|
| 899 | + |
---|
| 900 | + if (clk->context == DPLL_LOCKED) |
---|
| 901 | + omap3_noncore_dpll_program(clk, 0); |
---|
| 902 | + else |
---|
| 903 | + _omap3_dpll_write_clken(clk, clk->context); |
---|
| 904 | +} |
---|
| 905 | + |
---|
785 | 906 | /* OMAP3/4 non-CORE DPLL clkops */ |
---|
786 | 907 | const struct clk_hw_omap_ops clkhwops_omap3_dpll = { |
---|
787 | 908 | .allow_idle = omap3_dpll_allow_idle, |
---|