These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / drivers / clk / meson / clk-pll.c
1 /*
2  * Copyright (c) 2015 Endless Mobile, Inc.
3  * Author: Carlo Caione <carlo@endlessm.com>
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms and conditions of the GNU General Public License,
7  * version 2, as published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
12  * more details.
13  *
14  * You should have received a copy of the GNU General Public License along with
15  * this program.  If not, see <http://www.gnu.org/licenses/>.
16  */
17
18 /*
19  * In the most basic form, a Meson PLL is composed as follows:
20  *
21  *                     PLL
22  *      +------------------------------+
23  *      |                              |
24  * in -----[ /N ]---[ *M ]---[ >>OD ]----->> out
25  *      |         ^        ^           |
26  *      +------------------------------+
27  *                |        |
28  *               FREF     VCO
29  *
30  * out = (in * M / N) >> OD
31  */
32
33 #include <linux/clk-provider.h>
34 #include <linux/delay.h>
35 #include <linux/err.h>
36 #include <linux/io.h>
37 #include <linux/module.h>
38 #include <linux/of_address.h>
39 #include <linux/slab.h>
40 #include <linux/string.h>
41
42 #include "clkc.h"
43
44 #define MESON_PLL_RESET                         BIT(29)
45 #define MESON_PLL_LOCK                          BIT(31)
46
47 struct meson_clk_pll {
48         struct clk_hw   hw;
49         void __iomem    *base;
50         struct pll_conf *conf;
51         unsigned int    rate_count;
52         spinlock_t      *lock;
53 };
54 #define to_meson_clk_pll(_hw) container_of(_hw, struct meson_clk_pll, hw)
55
56 static unsigned long meson_clk_pll_recalc_rate(struct clk_hw *hw,
57                                                 unsigned long parent_rate)
58 {
59         struct meson_clk_pll *pll = to_meson_clk_pll(hw);
60         struct parm *p;
61         unsigned long parent_rate_mhz = parent_rate / 1000000;
62         unsigned long rate_mhz;
63         u16 n, m, od;
64         u32 reg;
65
66         p = &pll->conf->n;
67         reg = readl(pll->base + p->reg_off);
68         n = PARM_GET(p->width, p->shift, reg);
69
70         p = &pll->conf->m;
71         reg = readl(pll->base + p->reg_off);
72         m = PARM_GET(p->width, p->shift, reg);
73
74         p = &pll->conf->od;
75         reg = readl(pll->base + p->reg_off);
76         od = PARM_GET(p->width, p->shift, reg);
77
78         rate_mhz = (parent_rate_mhz * m / n) >> od;
79
80         return rate_mhz * 1000000;
81 }
82
83 static long meson_clk_pll_round_rate(struct clk_hw *hw, unsigned long rate,
84                                      unsigned long *parent_rate)
85 {
86         struct meson_clk_pll *pll = to_meson_clk_pll(hw);
87         const struct pll_rate_table *rate_table = pll->conf->rate_table;
88         int i;
89
90         for (i = 0; i < pll->rate_count; i++) {
91                 if (rate <= rate_table[i].rate)
92                         return rate_table[i].rate;
93         }
94
95         /* else return the smallest value */
96         return rate_table[0].rate;
97 }
98
99 static const struct pll_rate_table *meson_clk_get_pll_settings(struct meson_clk_pll *pll,
100                                                                unsigned long rate)
101 {
102         const struct pll_rate_table *rate_table = pll->conf->rate_table;
103         int i;
104
105         for (i = 0; i < pll->rate_count; i++) {
106                 if (rate == rate_table[i].rate)
107                         return &rate_table[i];
108         }
109         return NULL;
110 }
111
112 static int meson_clk_pll_wait_lock(struct meson_clk_pll *pll,
113                                    struct parm *p_n)
114 {
115         int delay = 24000000;
116         u32 reg;
117
118         while (delay > 0) {
119                 reg = readl(pll->base + p_n->reg_off);
120
121                 if (reg & MESON_PLL_LOCK)
122                         return 0;
123                 delay--;
124         }
125         return -ETIMEDOUT;
126 }
127
128 static int meson_clk_pll_set_rate(struct clk_hw *hw, unsigned long rate,
129                                   unsigned long parent_rate)
130 {
131         struct meson_clk_pll *pll = to_meson_clk_pll(hw);
132         struct parm *p;
133         const struct pll_rate_table *rate_set;
134         unsigned long old_rate;
135         int ret = 0;
136         u32 reg;
137
138         if (parent_rate == 0 || rate == 0)
139                 return -EINVAL;
140
141         old_rate = rate;
142
143         rate_set = meson_clk_get_pll_settings(pll, rate);
144         if (!rate_set)
145                 return -EINVAL;
146
147         /* PLL reset */
148         p = &pll->conf->n;
149         reg = readl(pll->base + p->reg_off);
150         writel(reg | MESON_PLL_RESET, pll->base + p->reg_off);
151
152         reg = PARM_SET(p->width, p->shift, reg, rate_set->n);
153         writel(reg, pll->base + p->reg_off);
154
155         p = &pll->conf->m;
156         reg = readl(pll->base + p->reg_off);
157         reg = PARM_SET(p->width, p->shift, reg, rate_set->m);
158         writel(reg, pll->base + p->reg_off);
159
160         p = &pll->conf->od;
161         reg = readl(pll->base + p->reg_off);
162         reg = PARM_SET(p->width, p->shift, reg, rate_set->od);
163         writel(reg, pll->base + p->reg_off);
164
165         p = &pll->conf->n;
166         ret = meson_clk_pll_wait_lock(pll, p);
167         if (ret) {
168                 pr_warn("%s: pll did not lock, trying to restore old rate %lu\n",
169                         __func__, old_rate);
170                 meson_clk_pll_set_rate(hw, old_rate, parent_rate);
171         }
172
173         return ret;
174 }
175
176 static const struct clk_ops meson_clk_pll_ops = {
177         .recalc_rate    = meson_clk_pll_recalc_rate,
178         .round_rate     = meson_clk_pll_round_rate,
179         .set_rate       = meson_clk_pll_set_rate,
180 };
181
182 static const struct clk_ops meson_clk_pll_ro_ops = {
183         .recalc_rate    = meson_clk_pll_recalc_rate,
184 };
185
186 struct clk *meson_clk_register_pll(const struct clk_conf *clk_conf,
187                                    void __iomem *reg_base,
188                                    spinlock_t *lock)
189 {
190         struct clk *clk;
191         struct meson_clk_pll *clk_pll;
192         struct clk_init_data init;
193
194         clk_pll = kzalloc(sizeof(*clk_pll), GFP_KERNEL);
195         if (!clk_pll)
196                 return ERR_PTR(-ENOMEM);
197
198         clk_pll->base = reg_base + clk_conf->reg_off;
199         clk_pll->lock = lock;
200         clk_pll->conf = clk_conf->conf.pll;
201
202         init.name = clk_conf->clk_name;
203         init.flags = clk_conf->flags | CLK_GET_RATE_NOCACHE;
204
205         init.parent_names = &clk_conf->clks_parent[0];
206         init.num_parents = 1;
207         init.ops = &meson_clk_pll_ro_ops;
208
209         /* If no rate_table is specified we assume the PLL is read-only */
210         if (clk_pll->conf->rate_table) {
211                 int len;
212
213                 for (len = 0; clk_pll->conf->rate_table[len].rate != 0; )
214                         len++;
215
216                  clk_pll->rate_count = len;
217                  init.ops = &meson_clk_pll_ops;
218         }
219
220         clk_pll->hw.init = &init;
221
222         clk = clk_register(NULL, &clk_pll->hw);
223         if (IS_ERR(clk))
224                 kfree(clk_pll);
225
226         return clk;
227 }