• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1  #include <linux/kernel.h>
2  #include <linux/clk.h>
3  #include <linux/io.h>
4  #include <linux/errno.h>
5  #include <linux/delay.h>
6  #include <linux/slab.h>
7  #include <linux/err.h>
8  
9  #include <asm/div64.h>
10  
11  #include "clk.h"
12  
13  #define to_clk_pllv2(clk) (container_of(clk, struct clk_pllv2, clk))
14  
15  /* PLL Register Offsets */
16  #define MXC_PLL_DP_CTL			0x00
17  #define MXC_PLL_DP_CONFIG		0x04
18  #define MXC_PLL_DP_OP			0x08
19  #define MXC_PLL_DP_MFD			0x0C
20  #define MXC_PLL_DP_MFN			0x10
21  #define MXC_PLL_DP_MFNMINUS		0x14
22  #define MXC_PLL_DP_MFNPLUS		0x18
23  #define MXC_PLL_DP_HFS_OP		0x1C
24  #define MXC_PLL_DP_HFS_MFD		0x20
25  #define MXC_PLL_DP_HFS_MFN		0x24
26  #define MXC_PLL_DP_MFN_TOGC		0x28
27  #define MXC_PLL_DP_DESTAT		0x2c
28  
29  /* PLL Register Bit definitions */
30  #define MXC_PLL_DP_CTL_MUL_CTRL		0x2000
31  #define MXC_PLL_DP_CTL_DPDCK0_2_EN	0x1000
32  #define MXC_PLL_DP_CTL_DPDCK0_2_OFFSET	12
33  #define MXC_PLL_DP_CTL_ADE		0x800
34  #define MXC_PLL_DP_CTL_REF_CLK_DIV	0x400
35  #define MXC_PLL_DP_CTL_REF_CLK_SEL_MASK	(3 << 8)
36  #define MXC_PLL_DP_CTL_REF_CLK_SEL_OFFSET	8
37  #define MXC_PLL_DP_CTL_HFSM		0x80
38  #define MXC_PLL_DP_CTL_PRE		0x40
39  #define MXC_PLL_DP_CTL_UPEN		0x20
40  #define MXC_PLL_DP_CTL_RST		0x10
41  #define MXC_PLL_DP_CTL_RCP		0x8
42  #define MXC_PLL_DP_CTL_PLM		0x4
43  #define MXC_PLL_DP_CTL_BRM0		0x2
44  #define MXC_PLL_DP_CTL_LRF		0x1
45  
46  #define MXC_PLL_DP_CONFIG_BIST		0x8
47  #define MXC_PLL_DP_CONFIG_SJC_CE	0x4
48  #define MXC_PLL_DP_CONFIG_AREN		0x2
49  #define MXC_PLL_DP_CONFIG_LDREQ		0x1
50  
51  #define MXC_PLL_DP_OP_MFI_OFFSET	4
52  #define MXC_PLL_DP_OP_MFI_MASK		(0xF << 4)
53  #define MXC_PLL_DP_OP_PDF_OFFSET	0
54  #define MXC_PLL_DP_OP_PDF_MASK		0xF
55  
56  #define MXC_PLL_DP_MFD_OFFSET		0
57  #define MXC_PLL_DP_MFD_MASK		0x07FFFFFF
58  
59  #define MXC_PLL_DP_MFN_OFFSET		0x0
60  #define MXC_PLL_DP_MFN_MASK		0x07FFFFFF
61  
62  #define MXC_PLL_DP_MFN_TOGC_TOG_DIS	(1 << 17)
63  #define MXC_PLL_DP_MFN_TOGC_TOG_EN	(1 << 16)
64  #define MXC_PLL_DP_MFN_TOGC_CNT_OFFSET	0x0
65  #define MXC_PLL_DP_MFN_TOGC_CNT_MASK	0xFFFF
66  
67  #define MXC_PLL_DP_DESTAT_TOG_SEL	(1 << 31)
68  #define MXC_PLL_DP_DESTAT_MFN		0x07FFFFFF
69  
70  #define MAX_DPLL_WAIT_TRIES	1000 /* 1000 * udelay(1) = 1ms */
71  
72  struct clk_pllv2 {
73  	struct clk_hw	hw;
74  	void __iomem	*base;
75  };
76  
__clk_pllv2_recalc_rate(unsigned long parent_rate,u32 dp_ctl,u32 dp_op,u32 dp_mfd,u32 dp_mfn)77  static unsigned long __clk_pllv2_recalc_rate(unsigned long parent_rate,
78  		u32 dp_ctl, u32 dp_op, u32 dp_mfd, u32 dp_mfn)
79  {
80  	long mfi, mfn, mfd, pdf, ref_clk, mfn_abs;
81  	unsigned long dbl;
82  	s64 temp;
83  
84  	dbl = dp_ctl & MXC_PLL_DP_CTL_DPDCK0_2_EN;
85  
86  	pdf = dp_op & MXC_PLL_DP_OP_PDF_MASK;
87  	mfi = (dp_op & MXC_PLL_DP_OP_MFI_MASK) >> MXC_PLL_DP_OP_MFI_OFFSET;
88  	mfi = (mfi <= 5) ? 5 : mfi;
89  	mfd = dp_mfd & MXC_PLL_DP_MFD_MASK;
90  	mfn = mfn_abs = dp_mfn & MXC_PLL_DP_MFN_MASK;
91  	/* Sign extend to 32-bits */
92  	if (mfn >= 0x04000000) {
93  		mfn |= 0xFC000000;
94  		mfn_abs = -mfn;
95  	}
96  
97  	ref_clk = 2 * parent_rate;
98  	if (dbl != 0)
99  		ref_clk *= 2;
100  
101  	ref_clk /= (pdf + 1);
102  	temp = (u64) ref_clk * mfn_abs;
103  	do_div(temp, mfd + 1);
104  	if (mfn < 0)
105  		temp = -temp;
106  	temp = (ref_clk * mfi) + temp;
107  
108  	return temp;
109  }
110  
clk_pllv2_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)111  static unsigned long clk_pllv2_recalc_rate(struct clk_hw *hw,
112  		unsigned long parent_rate)
113  {
114  	u32 dp_op, dp_mfd, dp_mfn, dp_ctl;
115  	void __iomem *pllbase;
116  	struct clk_pllv2 *pll = to_clk_pllv2(hw);
117  
118  	pllbase = pll->base;
119  
120  	dp_ctl = __raw_readl(pllbase + MXC_PLL_DP_CTL);
121  	dp_op = __raw_readl(pllbase + MXC_PLL_DP_OP);
122  	dp_mfd = __raw_readl(pllbase + MXC_PLL_DP_MFD);
123  	dp_mfn = __raw_readl(pllbase + MXC_PLL_DP_MFN);
124  
125  	return __clk_pllv2_recalc_rate(parent_rate, dp_ctl, dp_op, dp_mfd, dp_mfn);
126  }
127  
__clk_pllv2_set_rate(unsigned long rate,unsigned long parent_rate,u32 * dp_op,u32 * dp_mfd,u32 * dp_mfn)128  static int __clk_pllv2_set_rate(unsigned long rate, unsigned long parent_rate,
129  		u32 *dp_op, u32 *dp_mfd, u32 *dp_mfn)
130  {
131  	u32 reg;
132  	long mfi, pdf, mfn, mfd = 999999;
133  	s64 temp64;
134  	unsigned long quad_parent_rate;
135  
136  	quad_parent_rate = 4 * parent_rate;
137  	pdf = mfi = -1;
138  	while (++pdf < 16 && mfi < 5)
139  		mfi = rate * (pdf+1) / quad_parent_rate;
140  	if (mfi > 15)
141  		return -EINVAL;
142  	pdf--;
143  
144  	temp64 = rate * (pdf + 1) - quad_parent_rate * mfi;
145  	do_div(temp64, quad_parent_rate / 1000000);
146  	mfn = (long)temp64;
147  
148  	reg = mfi << 4 | pdf;
149  
150  	*dp_op = reg;
151  	*dp_mfd = mfd;
152  	*dp_mfn = mfn;
153  
154  	return 0;
155  }
156  
clk_pllv2_set_rate(struct clk_hw * hw,unsigned long rate,unsigned long parent_rate)157  static int clk_pllv2_set_rate(struct clk_hw *hw, unsigned long rate,
158  		unsigned long parent_rate)
159  {
160  	struct clk_pllv2 *pll = to_clk_pllv2(hw);
161  	void __iomem *pllbase;
162  	u32 dp_ctl, dp_op, dp_mfd, dp_mfn;
163  	int ret;
164  
165  	pllbase = pll->base;
166  
167  
168  	ret = __clk_pllv2_set_rate(rate, parent_rate, &dp_op, &dp_mfd, &dp_mfn);
169  	if (ret)
170  		return ret;
171  
172  	dp_ctl = __raw_readl(pllbase + MXC_PLL_DP_CTL);
173  	/* use dpdck0_2 */
174  	__raw_writel(dp_ctl | 0x1000L, pllbase + MXC_PLL_DP_CTL);
175  
176  	__raw_writel(dp_op, pllbase + MXC_PLL_DP_OP);
177  	__raw_writel(dp_mfd, pllbase + MXC_PLL_DP_MFD);
178  	__raw_writel(dp_mfn, pllbase + MXC_PLL_DP_MFN);
179  
180  	return 0;
181  }
182  
clk_pllv2_round_rate(struct clk_hw * hw,unsigned long rate,unsigned long * prate)183  static long clk_pllv2_round_rate(struct clk_hw *hw, unsigned long rate,
184  		unsigned long *prate)
185  {
186  	u32 dp_op, dp_mfd, dp_mfn;
187  
188  	__clk_pllv2_set_rate(rate, *prate, &dp_op, &dp_mfd, &dp_mfn);
189  	return __clk_pllv2_recalc_rate(*prate, MXC_PLL_DP_CTL_DPDCK0_2_EN,
190  			dp_op, dp_mfd, dp_mfn);
191  }
192  
clk_pllv2_prepare(struct clk_hw * hw)193  static int clk_pllv2_prepare(struct clk_hw *hw)
194  {
195  	struct clk_pllv2 *pll = to_clk_pllv2(hw);
196  	u32 reg;
197  	void __iomem *pllbase;
198  	int i = 0;
199  
200  	pllbase = pll->base;
201  	reg = __raw_readl(pllbase + MXC_PLL_DP_CTL) | MXC_PLL_DP_CTL_UPEN;
202  	__raw_writel(reg, pllbase + MXC_PLL_DP_CTL);
203  
204  	/* Wait for lock */
205  	do {
206  		reg = __raw_readl(pllbase + MXC_PLL_DP_CTL);
207  		if (reg & MXC_PLL_DP_CTL_LRF)
208  			break;
209  
210  		udelay(1);
211  	} while (++i < MAX_DPLL_WAIT_TRIES);
212  
213  	if (i == MAX_DPLL_WAIT_TRIES) {
214  		pr_err("MX5: pll locking failed\n");
215  		return -EINVAL;
216  	}
217  
218  	return 0;
219  }
220  
clk_pllv2_unprepare(struct clk_hw * hw)221  static void clk_pllv2_unprepare(struct clk_hw *hw)
222  {
223  	struct clk_pllv2 *pll = to_clk_pllv2(hw);
224  	u32 reg;
225  	void __iomem *pllbase;
226  
227  	pllbase = pll->base;
228  	reg = __raw_readl(pllbase + MXC_PLL_DP_CTL) & ~MXC_PLL_DP_CTL_UPEN;
229  	__raw_writel(reg, pllbase + MXC_PLL_DP_CTL);
230  }
231  
232  static struct clk_ops clk_pllv2_ops = {
233  	.prepare = clk_pllv2_prepare,
234  	.unprepare = clk_pllv2_unprepare,
235  	.recalc_rate = clk_pllv2_recalc_rate,
236  	.round_rate = clk_pllv2_round_rate,
237  	.set_rate = clk_pllv2_set_rate,
238  };
239  
imx_clk_pllv2(const char * name,const char * parent,void __iomem * base)240  struct clk *imx_clk_pllv2(const char *name, const char *parent,
241  		void __iomem *base)
242  {
243  	struct clk_pllv2 *pll;
244  	struct clk *clk;
245  	struct clk_init_data init;
246  
247  	pll = kzalloc(sizeof(*pll), GFP_KERNEL);
248  	if (!pll)
249  		return ERR_PTR(-ENOMEM);
250  
251  	pll->base = base;
252  
253  	init.name = name;
254  	init.ops = &clk_pllv2_ops;
255  	init.flags = 0;
256  	init.parent_names = &parent;
257  	init.num_parents = 1;
258  
259  	pll->hw.init = &init;
260  
261  	clk = clk_register(NULL, &pll->hw);
262  	if (IS_ERR(clk))
263  		kfree(pll);
264  
265  	return clk;
266  }
267