sh: clkfwk: rate table construction and rounding for SH7785.
[firefly-linux-kernel-4.4.55.git] / arch / sh / kernel / cpu / sh4a / clock-sh7785.c
1 /*
2  * arch/sh/kernel/cpu/sh4a/clock-sh7785.c
3  *
4  * SH7785 support for the clock framework
5  *
6  *  Copyright (C) 2007 - 2009  Paul Mundt
7  *
8  * This file is subject to the terms and conditions of the GNU General Public
9  * License.  See the file "COPYING" in the main directory of this archive
10  * for more details.
11  */
12 #include <linux/init.h>
13 #include <linux/kernel.h>
14 #include <linux/clk.h>
15 #include <linux/io.h>
16 #include <linux/cpufreq.h>
17 #include <asm/clock.h>
18 #include <asm/freq.h>
19
20 static unsigned int div2[] = { 1, 2, 4, 6, 8, 12, 16, 18,
21                                24, 32, 36, 48 };
22 struct clk_priv {
23         unsigned int                    shift;
24
25         /* allowable divisor bitmap */
26         unsigned long                   div_bitmap;
27
28         /* Supportable frequencies + termination entry */
29         struct cpufreq_frequency_table  freq_table[ARRAY_SIZE(div2)+1];
30 };
31
32 #define FRQMR_CLK_DATA(_name, _shift, _div_bitmap)      \
33 static struct clk_priv _name##_data = {                 \
34         .shift          = _shift,                       \
35         .div_bitmap     = _div_bitmap,                  \
36                                                         \
37         .freq_table[0]  = {                             \
38                 .index = 0,                             \
39                 .frequency = CPUFREQ_TABLE_END,         \
40         },                                              \
41 }
42
43 FRQMR_CLK_DATA(pfc,  0, 0x0f80);
44 FRQMR_CLK_DATA(s3fc, 4, 0x0ff0);
45 FRQMR_CLK_DATA(s2fc, 8, 0x0030);
46 FRQMR_CLK_DATA(mfc, 12, 0x000c);
47 FRQMR_CLK_DATA(bfc, 16, 0x0fe0);
48 FRQMR_CLK_DATA(sfc, 20, 0x000c);
49 FRQMR_CLK_DATA(ufc, 24, 0x000c);
50 FRQMR_CLK_DATA(ifc, 28, 0x000e);
51
52 static unsigned long frqmr_recalc(struct clk *clk)
53 {
54         struct clk_priv *data = clk->priv;
55         unsigned int idx;
56
57         idx = (__raw_readl(FRQMR1) >> data->shift) & 0x000f;
58
59         /*
60          * XXX: PLL1 multiplier is locked for the default clock mode,
61          * when mode pin detection and configuration support is added,
62          * select the multiplier dynamically.
63          */
64         return clk->parent->rate * 36 / div2[idx];
65 }
66
67 static void frqmr_build_rate_table(struct clk *clk)
68 {
69         struct clk_priv *data = clk->priv;
70         int i, entry;
71
72         for (i = entry = 0; i < ARRAY_SIZE(div2); i++) {
73                 if ((data->div_bitmap & (1 << i)) == 0)
74                         continue;
75
76                 data->freq_table[entry].index = entry;
77                 data->freq_table[entry].frequency =
78                         clk->parent->rate * 36 / div2[i];
79
80                 entry++;
81         }
82
83         if (entry == 0) {
84                 pr_warning("clkfwk: failed to build frequency table "
85                            "for \"%s\" clk!\n", clk->name);
86                 return;
87         }
88
89         /* Termination entry */
90         data->freq_table[entry].index = entry;
91         data->freq_table[entry].frequency = CPUFREQ_TABLE_END;
92 }
93
94 static long frqmr_round_rate(struct clk *clk, unsigned long rate)
95 {
96         struct clk_priv *data = clk->priv;
97         unsigned long rate_error, rate_error_prev = ~0UL;
98         unsigned long rate_best_fit = rate;
99         unsigned long highest, lowest;
100         int i;
101
102         highest = lowest = 0;
103
104         for (i = 0; data->freq_table[i].frequency != CPUFREQ_TABLE_END; i++) {
105                 unsigned long freq = data->freq_table[i].frequency;
106
107                 if (freq == CPUFREQ_ENTRY_INVALID)
108                         continue;
109
110                 if (freq > highest)
111                         highest = freq;
112                 if (freq < lowest)
113                         lowest = freq;
114
115                 rate_error = abs(freq - rate);
116                 if (rate_error < rate_error_prev) {
117                         rate_best_fit = freq;
118                         rate_error_prev = rate_error;
119                 }
120
121                 if (rate_error == 0)
122                         break;
123         }
124
125         if (rate >= highest)
126                 rate_best_fit = highest;
127         if (rate <= lowest)
128                 rate_best_fit = lowest;
129
130         return rate_best_fit;
131 }
132
133 static struct clk_ops frqmr_clk_ops = {
134         .recalc                 = frqmr_recalc,
135         .build_rate_table       = frqmr_build_rate_table,
136         .round_rate             = frqmr_round_rate,
137 };
138
139 /*
140  * Default rate for the root input clock, reset this with clk_set_rate()
141  * from the platform code.
142  */
143 static struct clk extal_clk = {
144         .name           = "extal",
145         .id             = -1,
146         .rate           = 33333333,
147 };
148
149 static struct clk cpu_clk = {
150         .name           = "cpu_clk",            /* Ick */
151         .id             = -1,
152         .ops            = &frqmr_clk_ops,
153         .parent         = &extal_clk,
154         .flags          = CLK_ENABLE_ON_INIT,
155         .priv           = &ifc_data,
156 };
157
158 static struct clk shyway_clk = {
159         .name           = "shyway_clk",         /* SHck */
160         .id             = -1,
161         .ops            = &frqmr_clk_ops,
162         .parent         = &extal_clk,
163         .flags          = CLK_ENABLE_ON_INIT,
164         .priv           = &sfc_data,
165 };
166
167 static struct clk peripheral_clk = {
168         .name           = "peripheral_clk",     /* Pck */
169         .id             = -1,
170         .ops            = &frqmr_clk_ops,
171         .parent         = &extal_clk,
172         .flags          = CLK_ENABLE_ON_INIT,
173         .priv           = &pfc_data,
174 };
175
176 static struct clk ddr_clk = {
177         .name           = "ddr_clk",            /* DDRck */
178         .id             = -1,
179         .ops            = &frqmr_clk_ops,
180         .parent         = &extal_clk,
181         .flags          = CLK_ENABLE_ON_INIT,
182         .priv           = &mfc_data,
183 };
184
185 static struct clk bus_clk = {
186         .name           = "bus_clk",            /* Bck */
187         .id             = -1,
188         .ops            = &frqmr_clk_ops,
189         .parent         = &extal_clk,
190         .flags          = CLK_ENABLE_ON_INIT,
191         .priv           = &bfc_data,
192 };
193
194 static struct clk ga_clk = {
195         .name           = "ga_clk",             /* GAck */
196         .id             = -1,
197         .ops            = &frqmr_clk_ops,
198         .parent         = &extal_clk,
199         .priv           = &s2fc_data,
200 };
201
202 static struct clk du_clk = {
203         .name           = "du_clk",             /* DUck */
204         .id             = -1,
205         .ops            = &frqmr_clk_ops,
206         .parent         = &extal_clk,
207         .priv           = &s3fc_data,
208 };
209
210 static struct clk umem_clk = {
211         .name           = "umem_clk",           /* uck */
212         .id             = -1,
213         .ops            = &frqmr_clk_ops,
214         .parent         = &extal_clk,
215         .flags          = CLK_ENABLE_ON_INIT,
216         .priv           = &ufc_data,
217 };
218
219 static struct clk *clks[] = {
220         &extal_clk,
221         &cpu_clk,
222         &shyway_clk,
223         &peripheral_clk,
224         &ddr_clk,
225         &bus_clk,
226         &ga_clk,
227         &du_clk,
228         &umem_clk,
229 };
230
231 int __init arch_clk_init(void)
232 {
233         int i, ret = 0;
234
235         for (i = 0; i < ARRAY_SIZE(clks); i++)
236                 ret |= clk_register(clks[i]);
237
238         return ret;
239 }