Linux-libre 5.3.12-gnu
[librecmc/linux-libre.git] / drivers / clk / sunxi / clk-sun9i-core.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright 2014 Chen-Yu Tsai
4  *
5  * Chen-Yu Tsai <wens@csie.org>
6  */
7
8 #include <linux/clk.h>
9 #include <linux/clk-provider.h>
10 #include <linux/of.h>
11 #include <linux/of_address.h>
12 #include <linux/log2.h>
13
14 #include "clk-factors.h"
15
16
17 /**
18  * sun9i_a80_get_pll4_factors() - calculates n, p, m factors for PLL4
19  * PLL4 rate is calculated as follows
20  * rate = (parent_rate * n >> p) / (m + 1);
21  * parent_rate is always 24MHz
22  *
23  * p and m are named div1 and div2 in Allwinner's SDK
24  */
25
26 static void sun9i_a80_get_pll4_factors(struct factors_request *req)
27 {
28         int n;
29         int m = 1;
30         int p = 1;
31
32         /* Normalize value to a 6 MHz multiple (24 MHz / 4) */
33         n = DIV_ROUND_UP(req->rate, 6000000);
34
35         /* If n is too large switch to steps of 12 MHz */
36         if (n > 255) {
37                 m = 0;
38                 n = (n + 1) / 2;
39         }
40
41         /* If n is still too large switch to steps of 24 MHz */
42         if (n > 255) {
43                 p = 0;
44                 n = (n + 1) / 2;
45         }
46
47         /* n must be between 12 and 255 */
48         if (n > 255)
49                 n = 255;
50         else if (n < 12)
51                 n = 12;
52
53         req->rate = ((24000000 * n) >> p) / (m + 1);
54         req->n = n;
55         req->m = m;
56         req->p = p;
57 }
58
59 static const struct clk_factors_config sun9i_a80_pll4_config = {
60         .mshift = 18,
61         .mwidth = 1,
62         .nshift = 8,
63         .nwidth = 8,
64         .pshift = 16,
65         .pwidth = 1,
66 };
67
68 static const struct factors_data sun9i_a80_pll4_data __initconst = {
69         .enable = 31,
70         .table = &sun9i_a80_pll4_config,
71         .getter = sun9i_a80_get_pll4_factors,
72 };
73
74 static DEFINE_SPINLOCK(sun9i_a80_pll4_lock);
75
76 static void __init sun9i_a80_pll4_setup(struct device_node *node)
77 {
78         void __iomem *reg;
79
80         reg = of_io_request_and_map(node, 0, of_node_full_name(node));
81         if (IS_ERR(reg)) {
82                 pr_err("Could not get registers for a80-pll4-clk: %pOFn\n",
83                        node);
84                 return;
85         }
86
87         sunxi_factors_register(node, &sun9i_a80_pll4_data,
88                                &sun9i_a80_pll4_lock, reg);
89 }
90 CLK_OF_DECLARE(sun9i_a80_pll4, "allwinner,sun9i-a80-pll4-clk", sun9i_a80_pll4_setup);
91
92
93 /**
94  * sun9i_a80_get_gt_factors() - calculates m factor for GT
95  * GT rate is calculated as follows
96  * rate = parent_rate / (m + 1);
97  */
98
99 static void sun9i_a80_get_gt_factors(struct factors_request *req)
100 {
101         u32 div;
102
103         if (req->parent_rate < req->rate)
104                 req->rate = req->parent_rate;
105
106         div = DIV_ROUND_UP(req->parent_rate, req->rate);
107
108         /* maximum divider is 4 */
109         if (div > 4)
110                 div = 4;
111
112         req->rate = req->parent_rate / div;
113         req->m = div;
114 }
115
116 static const struct clk_factors_config sun9i_a80_gt_config = {
117         .mshift = 0,
118         .mwidth = 2,
119 };
120
121 static const struct factors_data sun9i_a80_gt_data __initconst = {
122         .mux = 24,
123         .muxmask = BIT(1) | BIT(0),
124         .table = &sun9i_a80_gt_config,
125         .getter = sun9i_a80_get_gt_factors,
126 };
127
128 static DEFINE_SPINLOCK(sun9i_a80_gt_lock);
129
130 static void __init sun9i_a80_gt_setup(struct device_node *node)
131 {
132         void __iomem *reg;
133
134         reg = of_io_request_and_map(node, 0, of_node_full_name(node));
135         if (IS_ERR(reg)) {
136                 pr_err("Could not get registers for a80-gt-clk: %pOFn\n",
137                        node);
138                 return;
139         }
140
141         /* The GT bus clock needs to be always enabled */
142         sunxi_factors_register_critical(node, &sun9i_a80_gt_data,
143                                         &sun9i_a80_gt_lock, reg);
144 }
145 CLK_OF_DECLARE(sun9i_a80_gt, "allwinner,sun9i-a80-gt-clk", sun9i_a80_gt_setup);
146
147
148 /**
149  * sun9i_a80_get_ahb_factors() - calculates p factor for AHB0/1/2
150  * AHB rate is calculated as follows
151  * rate = parent_rate >> p;
152  */
153
154 static void sun9i_a80_get_ahb_factors(struct factors_request *req)
155 {
156         u32 _p;
157
158         if (req->parent_rate < req->rate)
159                 req->rate = req->parent_rate;
160
161         _p = order_base_2(DIV_ROUND_UP(req->parent_rate, req->rate));
162
163         /* maximum p is 3 */
164         if (_p > 3)
165                 _p = 3;
166
167         req->rate = req->parent_rate >> _p;
168         req->p = _p;
169 }
170
171 static const struct clk_factors_config sun9i_a80_ahb_config = {
172         .pshift = 0,
173         .pwidth = 2,
174 };
175
176 static const struct factors_data sun9i_a80_ahb_data __initconst = {
177         .mux = 24,
178         .muxmask = BIT(1) | BIT(0),
179         .table = &sun9i_a80_ahb_config,
180         .getter = sun9i_a80_get_ahb_factors,
181 };
182
183 static DEFINE_SPINLOCK(sun9i_a80_ahb_lock);
184
185 static void __init sun9i_a80_ahb_setup(struct device_node *node)
186 {
187         void __iomem *reg;
188
189         reg = of_io_request_and_map(node, 0, of_node_full_name(node));
190         if (IS_ERR(reg)) {
191                 pr_err("Could not get registers for a80-ahb-clk: %pOFn\n",
192                        node);
193                 return;
194         }
195
196         sunxi_factors_register(node, &sun9i_a80_ahb_data,
197                                &sun9i_a80_ahb_lock, reg);
198 }
199 CLK_OF_DECLARE(sun9i_a80_ahb, "allwinner,sun9i-a80-ahb-clk", sun9i_a80_ahb_setup);
200
201
202 static const struct factors_data sun9i_a80_apb0_data __initconst = {
203         .mux = 24,
204         .muxmask = BIT(0),
205         .table = &sun9i_a80_ahb_config,
206         .getter = sun9i_a80_get_ahb_factors,
207 };
208
209 static DEFINE_SPINLOCK(sun9i_a80_apb0_lock);
210
211 static void __init sun9i_a80_apb0_setup(struct device_node *node)
212 {
213         void __iomem *reg;
214
215         reg = of_io_request_and_map(node, 0, of_node_full_name(node));
216         if (IS_ERR(reg)) {
217                 pr_err("Could not get registers for a80-apb0-clk: %pOFn\n",
218                        node);
219                 return;
220         }
221
222         sunxi_factors_register(node, &sun9i_a80_apb0_data,
223                                &sun9i_a80_apb0_lock, reg);
224 }
225 CLK_OF_DECLARE(sun9i_a80_apb0, "allwinner,sun9i-a80-apb0-clk", sun9i_a80_apb0_setup);
226
227
228 /**
229  * sun9i_a80_get_apb1_factors() - calculates m, p factors for APB1
230  * APB1 rate is calculated as follows
231  * rate = (parent_rate >> p) / (m + 1);
232  */
233
234 static void sun9i_a80_get_apb1_factors(struct factors_request *req)
235 {
236         u32 div;
237
238         if (req->parent_rate < req->rate)
239                 req->rate = req->parent_rate;
240
241         div = DIV_ROUND_UP(req->parent_rate, req->rate);
242
243         /* Highest possible divider is 256 (p = 3, m = 31) */
244         if (div > 256)
245                 div = 256;
246
247         req->p = order_base_2(div);
248         req->m = (req->parent_rate >> req->p) - 1;
249         req->rate = (req->parent_rate >> req->p) / (req->m + 1);
250 }
251
252 static const struct clk_factors_config sun9i_a80_apb1_config = {
253         .mshift = 0,
254         .mwidth = 5,
255         .pshift = 16,
256         .pwidth = 2,
257 };
258
259 static const struct factors_data sun9i_a80_apb1_data __initconst = {
260         .mux = 24,
261         .muxmask = BIT(0),
262         .table = &sun9i_a80_apb1_config,
263         .getter = sun9i_a80_get_apb1_factors,
264 };
265
266 static DEFINE_SPINLOCK(sun9i_a80_apb1_lock);
267
268 static void __init sun9i_a80_apb1_setup(struct device_node *node)
269 {
270         void __iomem *reg;
271
272         reg = of_io_request_and_map(node, 0, of_node_full_name(node));
273         if (IS_ERR(reg)) {
274                 pr_err("Could not get registers for a80-apb1-clk: %pOFn\n",
275                        node);
276                 return;
277         }
278
279         sunxi_factors_register(node, &sun9i_a80_apb1_data,
280                                &sun9i_a80_apb1_lock, reg);
281 }
282 CLK_OF_DECLARE(sun9i_a80_apb1, "allwinner,sun9i-a80-apb1-clk", sun9i_a80_apb1_setup);