jh71x0_clkc.c revision 1.3 1 1.3 skrll /* $NetBSD: jh71x0_clkc.c,v 1.3 2024/08/19 07:33:55 skrll Exp $ */
2 1.1 skrll
3 1.1 skrll /*-
4 1.1 skrll * Copyright (c) 2023 The NetBSD Foundation, Inc.
5 1.1 skrll * All rights reserved.
6 1.1 skrll *
7 1.1 skrll * This code is derived from software contributed to The NetBSD Foundation
8 1.1 skrll * by Nick Hudson
9 1.1 skrll *
10 1.1 skrll * Redistribution and use in source and binary forms, with or without
11 1.1 skrll * modification, are permitted provided that the following conditions
12 1.1 skrll * are met:
13 1.1 skrll * 1. Redistributions of source code must retain the above copyright
14 1.1 skrll * notice, this list of conditions and the following disclaimer.
15 1.1 skrll * 2. Redistributions in binary form must reproduce the above copyright
16 1.1 skrll * notice, this list of conditions and the following disclaimer in the
17 1.1 skrll * documentation and/or other materials provided with the distribution.
18 1.1 skrll *
19 1.1 skrll * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 1.1 skrll * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 1.1 skrll * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 1.1 skrll * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 1.1 skrll * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 1.1 skrll * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 1.1 skrll * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 1.1 skrll * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 1.1 skrll * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 1.1 skrll * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 1.1 skrll * POSSIBILITY OF SUCH DAMAGE.
30 1.1 skrll */
31 1.1 skrll
32 1.1 skrll #include <sys/cdefs.h>
33 1.3 skrll __KERNEL_RCSID(0, "$NetBSD: jh71x0_clkc.c,v 1.3 2024/08/19 07:33:55 skrll Exp $");
34 1.1 skrll
35 1.1 skrll #include <sys/param.h>
36 1.1 skrll
37 1.1 skrll #include <sys/bus.h>
38 1.1 skrll #include <sys/device.h>
39 1.1 skrll
40 1.1 skrll #include <dev/clk/clk_backend.h>
41 1.1 skrll
42 1.1 skrll #include <dev/fdt/fdtvar.h>
43 1.1 skrll
44 1.1 skrll #include <riscv/starfive/jh71x0_clkc.h>
45 1.1 skrll
46 1.1 skrll #define RD4(sc, reg) \
47 1.1 skrll bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg))
48 1.1 skrll #define WR4(sc, reg, val) \
49 1.1 skrll bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val))
50 1.1 skrll
51 1.1 skrll
52 1.1 skrll static void
53 1.1 skrll jh71x0_clkc_update(struct jh71x0_clkc_softc * const sc,
54 1.1 skrll struct jh71x0_clkc_clk *jcc, uint32_t set, uint32_t clr)
55 1.1 skrll {
56 1.1 skrll // lock
57 1.1 skrll uint32_t val = RD4(sc, jcc->jcc_reg);
58 1.1 skrll val &= ~clr;
59 1.1 skrll val |= set;
60 1.1 skrll WR4(sc, jcc->jcc_reg, val);
61 1.1 skrll }
62 1.1 skrll
63 1.1 skrll /*
64 1.1 skrll * FIXED_FACTOR operations
65 1.1 skrll */
66 1.1 skrll
67 1.1 skrll static u_int
68 1.1 skrll jh71x0_clkc_fixed_factor_get_parent_rate(struct clk *clk)
69 1.1 skrll {
70 1.1 skrll struct clk *clk_parent = clk_get_parent(clk);
71 1.1 skrll if (clk_parent == NULL)
72 1.1 skrll return 0;
73 1.1 skrll
74 1.1 skrll return clk_get_rate(clk_parent);
75 1.1 skrll }
76 1.1 skrll
77 1.1 skrll u_int
78 1.1 skrll jh71x0_clkc_fixed_factor_get_rate(struct jh71x0_clkc_softc *sc,
79 1.1 skrll struct jh71x0_clkc_clk *jcc)
80 1.1 skrll {
81 1.1 skrll KASSERT(jcc->jcc_type == JH71X0CLK_FIXED_FACTOR);
82 1.1 skrll
83 1.1 skrll struct jh71x0_clkc_fixed_factor * const jcff = &jcc->jcc_ffactor;
84 1.1 skrll struct clk *clk = &jcc->jcc_clk;
85 1.1 skrll
86 1.1 skrll uint64_t rate = jh71x0_clkc_fixed_factor_get_parent_rate(clk);
87 1.1 skrll if (rate == 0)
88 1.1 skrll return 0;
89 1.1 skrll
90 1.1 skrll rate *= jcff->jcff_mult;
91 1.1 skrll rate /= jcff->jcff_div;
92 1.1 skrll
93 1.1 skrll return rate;
94 1.1 skrll }
95 1.1 skrll
96 1.1 skrll static int
97 1.1 skrll jh71x0_clkc_fixed_factor_set_parent_rate(struct clk *clk, u_int rate)
98 1.1 skrll {
99 1.1 skrll struct clk *clk_parent = clk_get_parent(clk);
100 1.1 skrll if (clk_parent == NULL)
101 1.1 skrll return ENXIO;
102 1.1 skrll
103 1.1 skrll return clk_set_rate(clk_parent, rate);
104 1.1 skrll }
105 1.1 skrll
106 1.1 skrll int
107 1.1 skrll jh71x0_clkc_fixed_factor_set_rate(struct jh71x0_clkc_softc *sc,
108 1.1 skrll struct jh71x0_clkc_clk *jcc, u_int rate)
109 1.1 skrll {
110 1.1 skrll KASSERT(jcc->jcc_type == JH71X0CLK_FIXED_FACTOR);
111 1.1 skrll
112 1.1 skrll struct jh71x0_clkc_fixed_factor * const jcff = &jcc->jcc_ffactor;
113 1.1 skrll struct clk *clk = &jcc->jcc_clk;
114 1.1 skrll
115 1.1 skrll
116 1.1 skrll uint64_t tmp = rate;
117 1.1 skrll tmp *= jcff->jcff_div;
118 1.1 skrll tmp /= jcff->jcff_mult;
119 1.1 skrll
120 1.1 skrll return jh71x0_clkc_fixed_factor_set_parent_rate(clk, tmp);
121 1.1 skrll }
122 1.1 skrll
123 1.1 skrll const char *
124 1.1 skrll jh71x0_clkc_fixed_factor_get_parent(struct jh71x0_clkc_softc *sc,
125 1.1 skrll struct jh71x0_clkc_clk *jcc)
126 1.1 skrll {
127 1.1 skrll KASSERT(jcc->jcc_type == JH71X0CLK_FIXED_FACTOR);
128 1.1 skrll
129 1.1 skrll struct jh71x0_clkc_fixed_factor * const jcff = &jcc->jcc_ffactor;
130 1.1 skrll
131 1.1 skrll return jcff->jcff_parent;
132 1.1 skrll }
133 1.1 skrll
134 1.1 skrll
135 1.1 skrll /*
136 1.1 skrll * MUX operations
137 1.1 skrll */
138 1.1 skrll
139 1.1 skrll int
140 1.1 skrll jh71x0_clkc_mux_set_parent(struct jh71x0_clkc_softc *sc,
141 1.1 skrll struct jh71x0_clkc_clk *jcc, const char *name)
142 1.1 skrll {
143 1.1 skrll KASSERT(jcc->jcc_type == JH71X0CLK_MUX);
144 1.1 skrll
145 1.1 skrll struct jh71x0_clkc_mux * const jcm = &jcc->jcc_mux;
146 1.1 skrll
147 1.1 skrll size_t i;
148 1.1 skrll for (i = 0; i < jcm->jcm_nparents; i++) {
149 1.1 skrll if (jcm->jcm_parents[i] != NULL &&
150 1.1 skrll strcmp(jcm->jcm_parents[i], name) == 0)
151 1.1 skrll break;
152 1.1 skrll }
153 1.1 skrll if (i >= jcm->jcm_nparents)
154 1.1 skrll return EINVAL;
155 1.1 skrll
156 1.3 skrll KASSERT(i <= __SHIFTOUT_MASK(JH71X0_CLK_MUX_MASK));
157 1.3 skrll
158 1.1 skrll uint32_t val = RD4(sc, jcc->jcc_reg);
159 1.1 skrll val &= ~JH71X0_CLK_MUX_MASK;
160 1.1 skrll val |= __SHIFTIN(i, JH71X0_CLK_MUX_MASK);
161 1.1 skrll WR4(sc, jcc->jcc_reg, val);
162 1.1 skrll
163 1.1 skrll return 0;
164 1.1 skrll }
165 1.1 skrll
166 1.1 skrll
167 1.1 skrll const char *
168 1.1 skrll jh71x0_clkc_mux_get_parent(struct jh71x0_clkc_softc *sc,
169 1.1 skrll struct jh71x0_clkc_clk *jcc)
170 1.1 skrll {
171 1.1 skrll KASSERT(jcc->jcc_type == JH71X0CLK_MUX);
172 1.1 skrll
173 1.1 skrll uint32_t val = RD4(sc, jcc->jcc_reg);
174 1.1 skrll size_t pindex = __SHIFTOUT(val, JH71X0_CLK_MUX_MASK);
175 1.1 skrll
176 1.1 skrll if (pindex >= jcc->jcc_mux.jcm_nparents)
177 1.1 skrll return NULL;
178 1.1 skrll
179 1.1 skrll return jcc->jcc_mux.jcm_parents[pindex];
180 1.1 skrll }
181 1.1 skrll
182 1.1 skrll
183 1.1 skrll /*
184 1.1 skrll * GATE operations
185 1.1 skrll */
186 1.1 skrll
187 1.1 skrll int
188 1.1 skrll jh71x0_clkc_gate_enable(struct jh71x0_clkc_softc *sc,
189 1.1 skrll struct jh71x0_clkc_clk *jcc, int enable)
190 1.1 skrll {
191 1.1 skrll KASSERT(jcc->jcc_type == JH71X0CLK_GATE);
192 1.1 skrll
193 1.1 skrll jh71x0_clkc_update(sc, jcc,
194 1.1 skrll (enable ? JH71X0_CLK_ENABLE : 0), JH71X0_CLK_ENABLE);
195 1.1 skrll
196 1.1 skrll return 0;
197 1.1 skrll }
198 1.1 skrll
199 1.1 skrll const char *
200 1.1 skrll jh71x0_clkc_gate_get_parent(struct jh71x0_clkc_softc *sc,
201 1.1 skrll struct jh71x0_clkc_clk *jcc)
202 1.1 skrll {
203 1.1 skrll KASSERT(jcc->jcc_type == JH71X0CLK_GATE);
204 1.1 skrll
205 1.1 skrll struct jh71x0_clkc_gate *jcc_gate = &jcc->jcc_gate;
206 1.1 skrll
207 1.1 skrll return jcc_gate->jcg_parent;
208 1.1 skrll }
209 1.1 skrll
210 1.1 skrll
211 1.1 skrll /*
212 1.1 skrll * DIVIDER operations
213 1.1 skrll */
214 1.1 skrll
215 1.1 skrll u_int
216 1.1 skrll jh71x0_clkc_div_get_rate(struct jh71x0_clkc_softc *sc,
217 1.1 skrll struct jh71x0_clkc_clk *jcc)
218 1.1 skrll {
219 1.1 skrll KASSERT(jcc->jcc_type == JH71X0CLK_DIV);
220 1.1 skrll
221 1.1 skrll struct clk * const clk = &jcc->jcc_clk;
222 1.1 skrll struct clk * const clk_parent = clk_get_parent(clk);
223 1.1 skrll
224 1.1 skrll if (clk_parent == NULL)
225 1.1 skrll return 0;
226 1.1 skrll
227 1.1 skrll u_int rate = clk_get_rate(clk_parent);
228 1.1 skrll if (rate == 0)
229 1.1 skrll return 0;
230 1.1 skrll
231 1.1 skrll uint32_t val = RD4(sc, jcc->jcc_reg);
232 1.1 skrll uint32_t div = __SHIFTOUT(val, JH71X0_CLK_DIV_MASK);
233 1.1 skrll
234 1.1 skrll return rate / div;
235 1.1 skrll }
236 1.1 skrll
237 1.1 skrll int
238 1.1 skrll jh71x0_clkc_div_set_rate(struct jh71x0_clkc_softc *sc,
239 1.1 skrll struct jh71x0_clkc_clk *jcc, u_int new_rate)
240 1.1 skrll {
241 1.1 skrll KASSERT(jcc->jcc_type == JH71X0CLK_DIV);
242 1.1 skrll
243 1.1 skrll struct jh71x0_clkc_div * const jcc_div = &jcc->jcc_div;
244 1.1 skrll struct clk * const clk = &jcc->jcc_clk;
245 1.1 skrll struct clk * const clk_parent = clk_get_parent(clk);
246 1.1 skrll
247 1.1 skrll if (clk_parent == NULL)
248 1.1 skrll return ENXIO;
249 1.1 skrll
250 1.1 skrll if (jcc_div->jcd_maxdiv == 0)
251 1.1 skrll return ENXIO;
252 1.1 skrll
253 1.1 skrll u_int parent_rate = clk_get_rate(clk_parent);
254 1.1 skrll if (parent_rate == 0) {
255 1.1 skrll return (new_rate == 0) ? 0 : ERANGE;
256 1.1 skrll }
257 1.1 skrll u_int ratio = howmany(parent_rate, new_rate);
258 1.1 skrll u_int div = uimin(ratio, jcc_div->jcd_maxdiv);
259 1.1 skrll
260 1.3 skrll KASSERT(div <= __SHIFTOUT_MASK(JH71X0_CLK_DIV_MASK));
261 1.3 skrll
262 1.1 skrll jh71x0_clkc_update(sc, jcc,
263 1.1 skrll __SHIFTIN(div, JH71X0_CLK_DIV_MASK), JH71X0_CLK_DIV_MASK);
264 1.1 skrll
265 1.1 skrll return 0;
266 1.1 skrll }
267 1.1 skrll
268 1.1 skrll const char *
269 1.1 skrll jh71x0_clkc_div_get_parent(struct jh71x0_clkc_softc *sc,
270 1.1 skrll struct jh71x0_clkc_clk *jcc)
271 1.1 skrll {
272 1.1 skrll KASSERT(jcc->jcc_type == JH71X0CLK_DIV);
273 1.1 skrll
274 1.1 skrll struct jh71x0_clkc_div *jcc_div = &jcc->jcc_div;
275 1.1 skrll
276 1.1 skrll return jcc_div->jcd_parent;
277 1.1 skrll }
278 1.1 skrll
279 1.1 skrll
280 1.1 skrll /*
281 1.1 skrll * FRACTIONAL DIVIDER operations
282 1.1 skrll */
283 1.1 skrll
284 1.1 skrll u_int
285 1.1 skrll jh71x0_clkc_fracdiv_get_rate(struct jh71x0_clkc_softc *sc,
286 1.1 skrll struct jh71x0_clkc_clk *jcc)
287 1.1 skrll {
288 1.1 skrll KASSERT(jcc->jcc_type == JH71X0CLK_FRACDIV);
289 1.1 skrll
290 1.1 skrll struct clk * const clk = &jcc->jcc_clk;
291 1.1 skrll struct clk * const clk_parent = clk_get_parent(clk);
292 1.1 skrll
293 1.1 skrll if (clk_parent == NULL)
294 1.1 skrll return 0;
295 1.1 skrll
296 1.1 skrll
297 1.1 skrll u_int rate = clk_get_rate(clk_parent);
298 1.1 skrll if (rate == 0)
299 1.1 skrll return 0;
300 1.1 skrll
301 1.1 skrll uint32_t val = RD4(sc, jcc->jcc_reg);
302 1.1 skrll unsigned long div100 =
303 1.1 skrll 100UL * __SHIFTOUT(val, JH71X0_CLK_INT_MASK) +
304 1.2 skrll __SHIFTOUT(val, JH71X0_CLK_FRAC_MASK);
305 1.1 skrll
306 1.1 skrll return (div100 >= JH71X0_CLK_FRAC_MIN) ? 100UL * rate / div100 : 0;
307 1.1 skrll }
308 1.1 skrll
309 1.1 skrll int
310 1.1 skrll jh71x0_clkc_fracdiv_set_rate(struct jh71x0_clkc_softc *sc,
311 1.1 skrll struct jh71x0_clkc_clk *jcc, u_int new_rate)
312 1.1 skrll {
313 1.1 skrll KASSERT(jcc->jcc_type == JH71X0CLK_FRACDIV);
314 1.1 skrll
315 1.1 skrll struct clk * const clk = &jcc->jcc_clk;
316 1.1 skrll struct clk * const clk_parent = clk_get_parent(clk);
317 1.1 skrll
318 1.1 skrll if (clk_parent == NULL)
319 1.1 skrll return ENXIO;
320 1.1 skrll
321 1.1 skrll #if 0
322 1.1 skrll if (jcc_div->jcd_maxdiv == 0)
323 1.1 skrll return ENXIO;
324 1.1 skrll
325 1.1 skrll u_int parent_rate = clk_get_rate(clk_parent);
326 1.1 skrll
327 1.1 skrll if (parent_rate == 0) {
328 1.1 skrll return (new_rate == 0) ? 0 : ERANGE;
329 1.1 skrll }
330 1.1 skrll u_int ratio = howmany(parent_rate, new_rate);
331 1.1 skrll u_int div = uimin(ratio, jcc_div->jcd_maxdiv);
332 1.1 skrll
333 1.3 skrll KASSERT(div <= __SHIFTOUT_MASK(JH71X0_CLK_DIV_MASK));
334 1.3 skrll
335 1.1 skrll jh71x0_clkc_update(sc, jcc,
336 1.1 skrll __SHIFTIN(div, JH71X0_CLK_DIV_MASK), JH71X0_CLK_DIV_MASK);
337 1.1 skrll #endif
338 1.1 skrll
339 1.1 skrll return 0;
340 1.1 skrll }
341 1.1 skrll
342 1.1 skrll const char *
343 1.1 skrll jh71x0_clkc_fracdiv_get_parent(struct jh71x0_clkc_softc *sc,
344 1.1 skrll struct jh71x0_clkc_clk *jcc)
345 1.1 skrll {
346 1.1 skrll KASSERT(jcc->jcc_type == JH71X0CLK_FRACDIV);
347 1.1 skrll
348 1.1 skrll struct jh71x0_clkc_fracdiv *jcc_fracdiv = &jcc->jcc_fracdiv;
349 1.1 skrll
350 1.1 skrll return jcc_fracdiv->jcd_parent;
351 1.1 skrll }
352 1.1 skrll
353 1.1 skrll
354 1.1 skrll /*
355 1.3 skrll * MUXDIV operations
356 1.3 skrll */
357 1.3 skrll
358 1.3 skrll
359 1.3 skrll int
360 1.3 skrll jh71x0_clkc_muxdiv_set_parent(struct jh71x0_clkc_softc *sc,
361 1.3 skrll struct jh71x0_clkc_clk *jcc, const char *name)
362 1.3 skrll {
363 1.3 skrll KASSERT(jcc->jcc_type == JH71X0CLK_MUXDIV);
364 1.3 skrll
365 1.3 skrll struct jh71x0_clkc_muxdiv * const jcmd = &jcc->jcc_muxdiv;
366 1.3 skrll
367 1.3 skrll size_t i;
368 1.3 skrll for (i = 0; i < jcmd->jcmd_nparents; i++) {
369 1.3 skrll if (jcmd->jcmd_parents[i] != NULL &&
370 1.3 skrll strcmp(jcmd->jcmd_parents[i], name) == 0)
371 1.3 skrll break;
372 1.3 skrll }
373 1.3 skrll if (i >= jcmd->jcmd_nparents)
374 1.3 skrll return EINVAL;
375 1.3 skrll
376 1.3 skrll KASSERT(i <= __SHIFTOUT_MASK(JH71X0_CLK_MUX_MASK));
377 1.3 skrll
378 1.3 skrll uint32_t val = RD4(sc, jcc->jcc_reg);
379 1.3 skrll val &= ~JH71X0_CLK_MUX_MASK;
380 1.3 skrll val |= __SHIFTIN(i, JH71X0_CLK_MUX_MASK);
381 1.3 skrll WR4(sc, jcc->jcc_reg, val);
382 1.3 skrll
383 1.3 skrll return 0;
384 1.3 skrll }
385 1.3 skrll
386 1.3 skrll
387 1.3 skrll const char *
388 1.3 skrll jh71x0_clkc_muxdiv_get_parent(struct jh71x0_clkc_softc *sc,
389 1.3 skrll struct jh71x0_clkc_clk *jcc)
390 1.3 skrll {
391 1.3 skrll KASSERT(jcc->jcc_type == JH71X0CLK_MUXDIV);
392 1.3 skrll
393 1.3 skrll uint32_t val = RD4(sc, jcc->jcc_reg);
394 1.3 skrll size_t pindex = __SHIFTOUT(val, JH71X0_CLK_MUX_MASK);
395 1.3 skrll
396 1.3 skrll if (pindex >= jcc->jcc_muxdiv.jcmd_nparents)
397 1.3 skrll return NULL;
398 1.3 skrll
399 1.3 skrll return jcc->jcc_muxdiv.jcmd_parents[pindex];
400 1.3 skrll }
401 1.3 skrll
402 1.3 skrll
403 1.3 skrll
404 1.3 skrll u_int
405 1.3 skrll jh71x0_clkc_muxdiv_get_rate(struct jh71x0_clkc_softc *sc,
406 1.3 skrll struct jh71x0_clkc_clk *jcc)
407 1.3 skrll {
408 1.3 skrll KASSERT(jcc->jcc_type == JH71X0CLK_MUXDIV);
409 1.3 skrll
410 1.3 skrll struct clk * const clk = &jcc->jcc_clk;
411 1.3 skrll struct clk * const clk_parent = clk_get_parent(clk);
412 1.3 skrll
413 1.3 skrll if (clk_parent == NULL)
414 1.3 skrll return 0;
415 1.3 skrll
416 1.3 skrll u_int rate = clk_get_rate(clk_parent);
417 1.3 skrll if (rate == 0)
418 1.3 skrll return 0;
419 1.3 skrll
420 1.3 skrll uint32_t val = RD4(sc, jcc->jcc_reg);
421 1.3 skrll uint32_t div = __SHIFTOUT(val, JH71X0_CLK_DIV_MASK);
422 1.3 skrll
423 1.3 skrll return rate / div;
424 1.3 skrll }
425 1.3 skrll
426 1.3 skrll int
427 1.3 skrll jh71x0_clkc_muxdiv_set_rate(struct jh71x0_clkc_softc *sc,
428 1.3 skrll struct jh71x0_clkc_clk *jcc, u_int new_rate)
429 1.3 skrll {
430 1.3 skrll KASSERT(jcc->jcc_type == JH71X0CLK_MUXDIV);
431 1.3 skrll
432 1.3 skrll struct jh71x0_clkc_muxdiv * const jcc_muxdiv = &jcc->jcc_muxdiv;
433 1.3 skrll struct clk * const clk = &jcc->jcc_clk;
434 1.3 skrll struct clk * const clk_parent = clk_get_parent(clk);
435 1.3 skrll
436 1.3 skrll if (clk_parent == NULL)
437 1.3 skrll return ENXIO;
438 1.3 skrll
439 1.3 skrll if (jcc_muxdiv->jcmd_maxdiv == 0)
440 1.3 skrll return ENXIO;
441 1.3 skrll
442 1.3 skrll u_int parent_rate = clk_get_rate(clk_parent);
443 1.3 skrll if (parent_rate == 0) {
444 1.3 skrll return (new_rate == 0) ? 0 : ERANGE;
445 1.3 skrll }
446 1.3 skrll u_int ratio = howmany(parent_rate, new_rate);
447 1.3 skrll u_int div = uimin(ratio, jcc_muxdiv->jcmd_maxdiv);
448 1.3 skrll
449 1.3 skrll KASSERT(div <= __SHIFTOUT_MASK(JH71X0_CLK_DIV_MASK));
450 1.3 skrll
451 1.3 skrll jh71x0_clkc_update(sc, jcc,
452 1.3 skrll __SHIFTIN(div, JH71X0_CLK_DIV_MASK), JH71X0_CLK_DIV_MASK);
453 1.3 skrll
454 1.3 skrll return 0;
455 1.3 skrll }
456 1.3 skrll
457 1.3 skrll
458 1.3 skrll /*
459 1.1 skrll * INV operations
460 1.1 skrll */
461 1.1 skrll const char *
462 1.1 skrll jh71x0_clkc_inv_get_parent(struct jh71x0_clkc_softc *sc,
463 1.1 skrll struct jh71x0_clkc_clk *jcc)
464 1.1 skrll {
465 1.1 skrll KASSERT(jcc->jcc_type == JH71X0CLK_INV);
466 1.1 skrll
467 1.1 skrll struct jh71x0_clkc_inv * const jci = &jcc->jcc_inv;
468 1.1 skrll
469 1.1 skrll return jci->jci_parent;
470 1.1 skrll }
471 1.1 skrll
472 1.1 skrll
473 1.1 skrll struct jh71x0_clkc_clkops jh71x0_clkc_gate_ops = {
474 1.1 skrll .jcco_enable = jh71x0_clkc_gate_enable,
475 1.1 skrll .jcco_getparent = jh71x0_clkc_gate_get_parent,
476 1.1 skrll };
477 1.1 skrll
478 1.1 skrll struct jh71x0_clkc_clkops jh71x0_clkc_div_ops = {
479 1.1 skrll .jcco_setrate = jh71x0_clkc_div_set_rate,
480 1.1 skrll .jcco_getrate = jh71x0_clkc_div_get_rate,
481 1.1 skrll .jcco_getparent = jh71x0_clkc_div_get_parent,
482 1.1 skrll };
483 1.1 skrll
484 1.1 skrll struct jh71x0_clkc_clkops jh71x0_clkc_fracdiv_ops = {
485 1.1 skrll .jcco_setrate = jh71x0_clkc_fracdiv_set_rate,
486 1.1 skrll .jcco_getrate = jh71x0_clkc_fracdiv_get_rate,
487 1.1 skrll .jcco_getparent = jh71x0_clkc_fracdiv_get_parent,
488 1.1 skrll };
489 1.1 skrll
490 1.1 skrll struct jh71x0_clkc_clkops jh71x0_clkc_ffactor_ops = {
491 1.1 skrll .jcco_setrate = jh71x0_clkc_fixed_factor_set_rate,
492 1.1 skrll .jcco_getrate = jh71x0_clkc_fixed_factor_get_rate,
493 1.1 skrll .jcco_getparent = jh71x0_clkc_fixed_factor_get_parent,
494 1.1 skrll };
495 1.1 skrll
496 1.1 skrll
497 1.1 skrll struct jh71x0_clkc_clkops jh71x0_clkc_mux_ops = {
498 1.1 skrll .jcco_setparent = jh71x0_clkc_mux_set_parent,
499 1.1 skrll .jcco_getparent = jh71x0_clkc_mux_get_parent,
500 1.1 skrll };
501 1.1 skrll
502 1.3 skrll struct jh71x0_clkc_clkops jh71x0_clkc_muxdiv_ops = {
503 1.3 skrll .jcco_setrate = jh71x0_clkc_muxdiv_set_rate,
504 1.3 skrll .jcco_getrate = jh71x0_clkc_muxdiv_get_rate,
505 1.3 skrll .jcco_setparent = jh71x0_clkc_muxdiv_set_parent,
506 1.3 skrll .jcco_getparent = jh71x0_clkc_muxdiv_get_parent,
507 1.3 skrll };
508 1.3 skrll
509 1.1 skrll
510 1.1 skrll struct jh71x0_clkc_clkops jh71x0_clkc_inv_ops = {
511 1.1 skrll .jcco_getparent = jh71x0_clkc_inv_get_parent,
512 1.1 skrll };
513 1.1 skrll
514 1.1 skrll static struct clk *
515 1.1 skrll jh71x0_clkc_get(void *priv, const char *name)
516 1.1 skrll {
517 1.1 skrll struct jh71x0_clkc_softc * const sc = priv;
518 1.1 skrll
519 1.1 skrll for (u_int id = 0; id < sc->sc_nclks; id++) {
520 1.1 skrll struct jh71x0_clkc_clk * const jcc = &sc->sc_clk[id];
521 1.1 skrll
522 1.1 skrll if (strcmp(name, jcc->jcc_clk.name) == 0) {
523 1.1 skrll return &jcc->jcc_clk;
524 1.1 skrll }
525 1.1 skrll }
526 1.1 skrll
527 1.1 skrll return NULL;
528 1.1 skrll }
529 1.1 skrll
530 1.1 skrll static void
531 1.1 skrll jh71x0_clkc_put(void *priv, struct clk *clk)
532 1.1 skrll {
533 1.1 skrll }
534 1.1 skrll
535 1.1 skrll
536 1.1 skrll static int
537 1.1 skrll jh71x0_clkc_set_rate(void *priv, struct clk *clk, u_int rate)
538 1.1 skrll {
539 1.1 skrll struct jh71x0_clkc_softc * const sc = priv;
540 1.1 skrll struct jh71x0_clkc_clk * const jcc =
541 1.1 skrll container_of(clk, struct jh71x0_clkc_clk, jcc_clk);
542 1.1 skrll
543 1.1 skrll if (clk->flags & CLK_SET_RATE_PARENT) {
544 1.1 skrll struct clk *clk_parent = clk_get_parent(clk);
545 1.1 skrll if (clk_parent == NULL) {
546 1.1 skrll aprint_debug("%s: no parent for %s\n", __func__,
547 1.1 skrll jcc->jcc_clk.name);
548 1.1 skrll return ENXIO;
549 1.1 skrll }
550 1.1 skrll return clk_set_rate(clk_parent, rate);
551 1.1 skrll }
552 1.1 skrll
553 1.1 skrll if (jcc->jcc_ops->jcco_setrate)
554 1.1 skrll return jcc->jcc_ops->jcco_setrate(sc, jcc, rate);
555 1.1 skrll
556 1.1 skrll return ENXIO;
557 1.1 skrll }
558 1.1 skrll
559 1.1 skrll static u_int
560 1.1 skrll jh71x0_clkc_get_rate(void *priv, struct clk *clk)
561 1.1 skrll {
562 1.1 skrll struct jh71x0_clkc_softc * const sc = priv;
563 1.1 skrll struct jh71x0_clkc_clk * const jcc =
564 1.1 skrll container_of(clk, struct jh71x0_clkc_clk, jcc_clk);
565 1.1 skrll
566 1.1 skrll if (jcc->jcc_ops->jcco_getrate)
567 1.1 skrll return jcc->jcc_ops->jcco_getrate(sc, jcc);
568 1.1 skrll
569 1.1 skrll struct clk * const clk_parent = clk_get_parent(clk);
570 1.1 skrll if (clk_parent == NULL) {
571 1.1 skrll aprint_debug("%s: no parent for %s\n", __func__,
572 1.1 skrll jcc->jcc_clk.name);
573 1.1 skrll return 0;
574 1.1 skrll }
575 1.1 skrll
576 1.1 skrll return clk_get_rate(clk_parent);
577 1.1 skrll }
578 1.1 skrll
579 1.1 skrll static int
580 1.1 skrll jh71x0_clkc_enable(void *priv, struct clk *clk)
581 1.1 skrll {
582 1.1 skrll struct jh71x0_clkc_softc * const sc = priv;
583 1.1 skrll struct jh71x0_clkc_clk * const jcc =
584 1.1 skrll container_of(clk, struct jh71x0_clkc_clk, jcc_clk);
585 1.1 skrll
586 1.1 skrll struct clk * const clk_parent = clk_get_parent(clk);
587 1.1 skrll if (clk_parent != NULL) {
588 1.1 skrll int error = clk_enable(clk_parent);
589 1.1 skrll if (error != 0)
590 1.1 skrll return error;
591 1.1 skrll }
592 1.1 skrll
593 1.1 skrll switch (jcc->jcc_type) {
594 1.1 skrll case JH71X0CLK_GATE:
595 1.1 skrll jh71x0_clkc_update(sc, jcc, JH71X0_CLK_ENABLE, 0);
596 1.1 skrll break;
597 1.1 skrll
598 1.1 skrll case JH71X0CLK_DIV: {
599 1.1 skrll struct jh71x0_clkc_div * const jcc_div = &jcc->jcc_div;
600 1.1 skrll if (jcc_div->jcd_flags & JH71X0CLKC_DIV_GATE) {
601 1.1 skrll jh71x0_clkc_update(sc, jcc, JH71X0_CLK_ENABLE, 0);
602 1.3 skrll }
603 1.3 skrll break;
604 1.3 skrll }
605 1.3 skrll
606 1.3 skrll case JH71X0CLK_MUX: {
607 1.3 skrll struct jh71x0_clkc_mux * const jcc_mux = &jcc->jcc_mux;
608 1.3 skrll if (jcc_mux->jcm_flags & JH71X0CLKC_MUX_GATE) {
609 1.3 skrll jh71x0_clkc_update(sc, jcc, JH71X0_CLK_ENABLE, 0);
610 1.1 skrll }
611 1.1 skrll break;
612 1.1 skrll }
613 1.1 skrll
614 1.1 skrll case JH71X0CLK_FIXED_FACTOR:
615 1.1 skrll case JH71X0CLK_INV:
616 1.3 skrll case JH71X0CLK_MUXDIV:
617 1.1 skrll break;
618 1.1 skrll
619 1.1 skrll default:
620 1.1 skrll printf("%s: type %d\n", __func__, jcc->jcc_type);
621 1.1 skrll return ENXIO;
622 1.1 skrll }
623 1.1 skrll return 0;
624 1.1 skrll }
625 1.1 skrll
626 1.1 skrll static int
627 1.1 skrll jh71x0_clkc_disable(void *priv, struct clk *clk)
628 1.1 skrll {
629 1.1 skrll struct jh71x0_clkc_softc * const sc = priv;
630 1.1 skrll struct jh71x0_clkc_clk * const jcc =
631 1.1 skrll container_of(clk, struct jh71x0_clkc_clk, jcc_clk);
632 1.1 skrll
633 1.1 skrll switch (jcc->jcc_type) {
634 1.1 skrll case JH71X0CLK_GATE:
635 1.3 skrll jh71x0_clkc_update(sc, jcc, 0, JH71X0_CLK_ENABLE);
636 1.3 skrll break;
637 1.3 skrll
638 1.3 skrll case JH71X0CLK_DIV: {
639 1.3 skrll struct jh71x0_clkc_div * const jcc_div = &jcc->jcc_div;
640 1.3 skrll if (jcc_div->jcd_flags & JH71X0CLKC_DIV_GATE) {
641 1.3 skrll jh71x0_clkc_update(sc, jcc, 0, JH71X0_CLK_ENABLE);
642 1.3 skrll }
643 1.3 skrll break;
644 1.3 skrll }
645 1.3 skrll
646 1.3 skrll case JH71X0CLK_MUX: {
647 1.3 skrll struct jh71x0_clkc_mux * const jcc_mux = &jcc->jcc_mux;
648 1.3 skrll if (jcc_mux->jcm_flags & JH71X0CLKC_MUX_GATE) {
649 1.3 skrll jh71x0_clkc_update(sc, jcc, 0, JH71X0_CLK_ENABLE);
650 1.3 skrll }
651 1.3 skrll break;
652 1.3 skrll }
653 1.3 skrll
654 1.3 skrll case JH71X0CLK_FIXED_FACTOR:
655 1.3 skrll case JH71X0CLK_INV:
656 1.3 skrll case JH71X0CLK_MUXDIV:
657 1.3 skrll break;
658 1.1 skrll
659 1.1 skrll default:
660 1.1 skrll return ENXIO;
661 1.1 skrll }
662 1.3 skrll return 0;
663 1.1 skrll }
664 1.1 skrll
665 1.1 skrll
666 1.1 skrll
667 1.1 skrll static struct jh71x0_clkc_clk *
668 1.1 skrll jh71x0_clkc_clock_find(struct jh71x0_clkc_softc *sc, const char *name)
669 1.1 skrll {
670 1.1 skrll for (size_t id = 0; id < sc->sc_nclks; id++) {
671 1.1 skrll struct jh71x0_clkc_clk * const jcc = &sc->sc_clk[id];
672 1.1 skrll
673 1.1 skrll if (jcc->jcc_clk.name == NULL)
674 1.1 skrll continue;
675 1.1 skrll if (strcmp(jcc->jcc_clk.name, name) == 0)
676 1.1 skrll return jcc;
677 1.1 skrll }
678 1.1 skrll
679 1.1 skrll return NULL;
680 1.1 skrll }
681 1.1 skrll
682 1.1 skrll
683 1.1 skrll
684 1.1 skrll static int
685 1.1 skrll jh71x0_clkc_set_parent(void *priv, struct clk *clk,
686 1.1 skrll struct clk *clk_parent)
687 1.1 skrll {
688 1.1 skrll struct jh71x0_clkc_softc * const sc = priv;
689 1.1 skrll struct jh71x0_clkc_clk * const jcc =
690 1.1 skrll container_of(clk, struct jh71x0_clkc_clk, jcc_clk);
691 1.1 skrll
692 1.1 skrll if (jcc->jcc_ops->jcco_setparent == NULL)
693 1.1 skrll return EINVAL;
694 1.1 skrll
695 1.1 skrll return jcc->jcc_ops->jcco_setparent(sc, jcc, clk_parent->name);
696 1.1 skrll }
697 1.1 skrll
698 1.1 skrll
699 1.1 skrll static struct clk *
700 1.1 skrll jh71x0_clkc_get_parent(void *priv, struct clk *clk)
701 1.1 skrll {
702 1.1 skrll struct jh71x0_clkc_softc * const sc = priv;
703 1.1 skrll struct jh71x0_clkc_clk * const jcc =
704 1.1 skrll container_of(clk, struct jh71x0_clkc_clk, jcc_clk);
705 1.1 skrll
706 1.1 skrll if (jcc->jcc_ops->jcco_getparent == NULL)
707 1.1 skrll return NULL;
708 1.1 skrll
709 1.1 skrll const char *parent = jcc->jcc_ops->jcco_getparent(sc, jcc);
710 1.1 skrll if (parent == NULL)
711 1.1 skrll return NULL;
712 1.1 skrll
713 1.1 skrll struct jh71x0_clkc_clk *jcc_parent = jh71x0_clkc_clock_find(sc, parent);
714 1.1 skrll if (jcc_parent != NULL)
715 1.1 skrll return &jcc_parent->jcc_clk;
716 1.1 skrll
717 1.1 skrll /* No parent in this domain, try FDT */
718 1.1 skrll return fdtbus_clock_get(sc->sc_phandle, parent);
719 1.1 skrll }
720 1.1 skrll
721 1.1 skrll
722 1.1 skrll const struct clk_funcs jh71x0_clkc_funcs = {
723 1.1 skrll .get = jh71x0_clkc_get,
724 1.1 skrll .put = jh71x0_clkc_put,
725 1.1 skrll .set_rate = jh71x0_clkc_set_rate,
726 1.1 skrll .get_rate = jh71x0_clkc_get_rate,
727 1.1 skrll .enable = jh71x0_clkc_enable,
728 1.1 skrll .disable = jh71x0_clkc_disable,
729 1.1 skrll .set_parent = jh71x0_clkc_set_parent,
730 1.1 skrll .get_parent = jh71x0_clkc_get_parent,
731 1.1 skrll };
732 1.1 skrll
733