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