blob: 5f1986f2cb80b222f5a34b8afe4ae0ee0e7841b5 [file] [log] [blame]
Sean Anderson65cd44e2020-06-24 06:41:10 -04001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (C) 2020 Sean Anderson <seanga2@gmail.com>
4 */
5
6#define LOG_CATEGORY UCLASS_CLK
Sean Anderson65cd44e2020-06-24 06:41:10 -04007
Simon Glass43033962020-07-19 10:15:56 -06008#include <common.h>
9#include <clk.h>
Sean Anderson65cd44e2020-06-24 06:41:10 -040010#include <clk-uclass.h>
Simon Glass43033962020-07-19 10:15:56 -060011#include <dm.h>
12#include <log.h>
13#include <kendryte/bypass.h>
Sean Anderson65cd44e2020-06-24 06:41:10 -040014#include <linux/clk-provider.h>
15#include <linux/err.h>
Sean Anderson65cd44e2020-06-24 06:41:10 -040016
17#define CLK_K210_BYPASS "k210_clk_bypass"
18
19/*
20 * This is a small driver to do a software bypass of a clock if hardware bypass
21 * is not working. I have tried to write this in a generic fashion, so that it
22 * could be potentially broken out of the kendryte code at some future date.
23 *
24 * Say you have the following clock configuration
25 *
26 * +---+ +---+
27 * |osc| |pll|
28 * +---+ +---+
29 * ^
30 * /|
31 * / |
32 * / |
33 * / |
34 * / |
35 * +---+ +---+
36 * |clk| |clk|
37 * +---+ +---+
38 *
39 * But the pll does not have a bypass, so when you configure the pll, the
40 * configuration needs to change to look like
41 *
42 * +---+ +---+
43 * |osc| |pll|
44 * +---+ +---+
45 * ^
46 * |\
47 * | \
48 * | \
49 * | \
50 * | \
51 * +---+ +---+
52 * |clk| |clk|
53 * +---+ +---+
54 *
55 * To set this up, create a bypass clock with bypassee=pll and alt=osc. When
56 * creating the child clocks, set their parent to the bypass clock. After
57 * creating all the children, call k210_bypass_setchildren().
58 */
59
60static int k210_bypass_dobypass(struct k210_bypass *bypass)
61{
62 int ret, i;
63
64 /*
65 * If we already have saved parents, then the children are already
66 * bypassed
67 */
68 if (bypass->child_count && bypass->saved_parents[0])
69 return 0;
70
71 for (i = 0; i < bypass->child_count; i++) {
72 struct clk *child = bypass->children[i];
73 struct clk *parent = clk_get_parent(child);
74
75 if (IS_ERR(parent)) {
76 for (; i; i--)
77 bypass->saved_parents[i] = NULL;
78 return PTR_ERR(parent);
79 }
80 bypass->saved_parents[i] = parent;
81 }
82
83 for (i = 0; i < bypass->child_count; i++) {
84 struct clk *child = bypass->children[i];
85
86 ret = clk_set_parent(child, bypass->alt);
87 if (ret) {
88 for (; i; i--)
89 clk_set_parent(bypass->children[i],
90 bypass->saved_parents[i]);
91 for (i = 0; i < bypass->child_count; i++)
92 bypass->saved_parents[i] = NULL;
93 return ret;
94 }
95 }
96
97 return 0;
98}
99
100static int k210_bypass_unbypass(struct k210_bypass *bypass)
101{
102 int err, ret, i;
103
104 if (!bypass->child_count && !bypass->saved_parents[0]) {
105 log_warning("Cannot unbypass children; dobypass not called first\n");
106 return 0;
107 }
108
109 ret = 0;
110 for (i = 0; i < bypass->child_count; i++) {
111 err = clk_set_parent(bypass->children[i],
112 bypass->saved_parents[i]);
113 if (err)
114 ret = err;
115 bypass->saved_parents[i] = NULL;
116 }
117 return ret;
118}
119
120static ulong k210_bypass_get_rate(struct clk *clk)
121{
122 struct k210_bypass *bypass = to_k210_bypass(clk);
123 const struct clk_ops *ops = bypass->bypassee_ops;
124
125 if (ops->get_rate)
126 return ops->get_rate(bypass->bypassee);
127 else
128 return clk_get_parent_rate(bypass->bypassee);
129}
130
131static ulong k210_bypass_set_rate(struct clk *clk, unsigned long rate)
132{
133 int ret;
134 struct k210_bypass *bypass = to_k210_bypass(clk);
135 const struct clk_ops *ops = bypass->bypassee_ops;
136
137 /* Don't bother bypassing if we aren't going to set the rate */
138 if (!ops->set_rate)
139 return k210_bypass_get_rate(clk);
140
141 ret = k210_bypass_dobypass(bypass);
142 if (ret)
143 return ret;
144
145 ret = ops->set_rate(bypass->bypassee, rate);
146 if (ret < 0)
147 return ret;
148
149 return k210_bypass_unbypass(bypass);
150}
151
152static int k210_bypass_set_parent(struct clk *clk, struct clk *parent)
153{
154 struct k210_bypass *bypass = to_k210_bypass(clk);
155 const struct clk_ops *ops = bypass->bypassee_ops;
156
157 if (ops->set_parent)
158 return ops->set_parent(bypass->bypassee, parent);
159 else
160 return -ENOTSUPP;
161}
162
163/*
164 * For these next two functions, do the bypassing even if there is no
165 * en-/-disable function, since the bypassing itself can be observed in between
166 * calls.
167 */
168static int k210_bypass_enable(struct clk *clk)
169{
170 int ret;
171 struct k210_bypass *bypass = to_k210_bypass(clk);
172 const struct clk_ops *ops = bypass->bypassee_ops;
173
174 ret = k210_bypass_dobypass(bypass);
175 if (ret)
176 return ret;
177
178 if (ops->enable)
179 ret = ops->enable(bypass->bypassee);
180 else
181 ret = 0;
182 if (ret)
183 return ret;
184
185 return k210_bypass_unbypass(bypass);
186}
187
188static int k210_bypass_disable(struct clk *clk)
189{
190 int ret;
191 struct k210_bypass *bypass = to_k210_bypass(clk);
192 const struct clk_ops *ops = bypass->bypassee_ops;
193
194 ret = k210_bypass_dobypass(bypass);
195 if (ret)
196 return ret;
197
198 if (ops->disable)
199 return ops->disable(bypass->bypassee);
200 else
201 return 0;
202}
203
204static const struct clk_ops k210_bypass_ops = {
205 .get_rate = k210_bypass_get_rate,
206 .set_rate = k210_bypass_set_rate,
207 .set_parent = k210_bypass_set_parent,
208 .enable = k210_bypass_enable,
209 .disable = k210_bypass_disable,
210};
211
212int k210_bypass_set_children(struct clk *clk, struct clk **children,
213 size_t child_count)
214{
215 struct k210_bypass *bypass = to_k210_bypass(clk);
216
217 kfree(bypass->saved_parents);
218 if (child_count) {
219 bypass->saved_parents =
220 kcalloc(child_count, sizeof(struct clk *), GFP_KERNEL);
221 if (!bypass->saved_parents)
222 return -ENOMEM;
223 }
224 bypass->child_count = child_count;
225 bypass->children = children;
226
227 return 0;
228}
229
230struct clk *k210_register_bypass_struct(const char *name,
231 const char *parent_name,
232 struct k210_bypass *bypass)
233{
234 int ret;
235 struct clk *clk;
236
237 clk = &bypass->clk;
238
239 ret = clk_register(clk, CLK_K210_BYPASS, name, parent_name);
240 if (ret)
241 return ERR_PTR(ret);
242
243 bypass->bypassee->dev = clk->dev;
244 return clk;
245}
246
247struct clk *k210_register_bypass(const char *name, const char *parent_name,
248 struct clk *bypassee,
249 const struct clk_ops *bypassee_ops,
250 struct clk *alt)
251{
252 struct clk *clk;
253 struct k210_bypass *bypass;
254
255 bypass = kzalloc(sizeof(*bypass), GFP_KERNEL);
256 if (!bypass)
257 return ERR_PTR(-ENOMEM);
258
259 bypass->bypassee = bypassee;
260 bypass->bypassee_ops = bypassee_ops;
261 bypass->alt = alt;
262
263 clk = k210_register_bypass_struct(name, parent_name, bypass);
264 if (IS_ERR(clk))
265 kfree(bypass);
266 return clk;
267}
268
269U_BOOT_DRIVER(k210_bypass) = {
270 .name = CLK_K210_BYPASS,
271 .id = UCLASS_CLK,
272 .ops = &k210_bypass_ops,
273};