| .. | .. | 
|---|
|  | 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, | 
|---|