Index: head/sys/arm64/rockchip/clk/rk_clk_armclk.c =================================================================== --- head/sys/arm64/rockchip/clk/rk_clk_armclk.c (revision 354554) +++ head/sys/arm64/rockchip/clk/rk_clk_armclk.c (revision 354555) @@ -1,253 +1,258 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2018 Emmanuel Vadot * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include "clkdev_if.h" struct rk_clk_armclk_sc { uint32_t muxdiv_offset; uint32_t mux_shift; uint32_t mux_width; uint32_t mux_mask; uint32_t div_shift; uint32_t div_width; uint32_t div_mask; uint32_t gate_offset; uint32_t gate_shift; uint32_t flags; uint32_t main_parent; uint32_t alt_parent; struct rk_clk_armclk_rates *rates; int nrates; }; #define WRITE4(_clk, off, val) \ CLKDEV_WRITE_4(clknode_get_device(_clk), off, val) #define READ4(_clk, off, val) \ CLKDEV_READ_4(clknode_get_device(_clk), off, val) -#define DEVICE_LOCK(_clk) \ +#define DEVICE_LOCK(_clk) \ CLKDEV_DEVICE_LOCK(clknode_get_device(_clk)) #define DEVICE_UNLOCK(_clk) \ CLKDEV_DEVICE_UNLOCK(clknode_get_device(_clk)) #define RK_ARMCLK_WRITE_MASK_SHIFT 16 -/* #define dprintf(format, arg...) printf("%s:(%s)" format, __func__, clknode_get_name(clk), arg) */ +#if 0 +#define dprintf(format, arg...) \ + printf("%s:(%s)" format, __func__, clknode_get_name(clk), arg) +#else #define dprintf(format, arg...) +#endif static int rk_clk_armclk_init(struct clknode *clk, device_t dev) { struct rk_clk_armclk_sc *sc; uint32_t val, idx; sc = clknode_get_softc(clk); idx = 0; DEVICE_LOCK(clk); READ4(clk, sc->muxdiv_offset, &val); DEVICE_UNLOCK(clk); idx = (val & sc->mux_mask) >> sc->mux_shift; clknode_init_parent_idx(clk, idx); return (0); } static int rk_clk_armclk_set_mux(struct clknode *clk, int index) { struct rk_clk_armclk_sc *sc; uint32_t val = 0; sc = clknode_get_softc(clk); dprintf("Set mux to %d\n", index); DEVICE_LOCK(clk); val |= index << sc->mux_shift; val |= sc->mux_mask << RK_ARMCLK_WRITE_MASK_SHIFT; dprintf("Write: muxdiv_offset=%x, val=%x\n", sc->muxdiv_offset, val); WRITE4(clk, sc->muxdiv_offset, val); DEVICE_UNLOCK(clk); return (0); } static int rk_clk_armclk_recalc(struct clknode *clk, uint64_t *freq) { struct rk_clk_armclk_sc *sc; uint32_t reg, div; sc = clknode_get_softc(clk); DEVICE_LOCK(clk); READ4(clk, sc->muxdiv_offset, ®); dprintf("Read: muxdiv_offset=%x, val=%x\n", sc->muxdiv_offset, reg); DEVICE_UNLOCK(clk); div = ((reg & sc->div_mask) >> sc->div_shift) + 1; - dprintf("parent_freq=%lu, div=%u\n", *freq, div); + dprintf("parent_freq=%ju, div=%u\n", *freq, div); *freq = *freq / div; return (0); } static int rk_clk_armclk_set_freq(struct clknode *clk, uint64_t fparent, uint64_t *fout, int flags, int *stop) { struct rk_clk_armclk_sc *sc; struct clknode *p_main; const char **p_names; uint64_t best = 0, best_p = 0; uint32_t div = 0, val = 0; int err, i, rate = 0; sc = clknode_get_softc(clk); - dprintf("Finding best parent/div for target freq of %lu\n", *fout); + dprintf("Finding best parent/div for target freq of %ju\n", *fout); p_names = clknode_get_parent_names(clk); p_main = clknode_find_by_name(p_names[sc->main_parent]); for (i = 0; i < sc->nrates; i++) { if (sc->rates[i].freq == *fout) { best = sc->rates[i].freq; div = sc->rates[i].div; best_p = best * div; rate = i; - dprintf("Best parent %s (%d) with best freq at %lu\n", + dprintf("Best parent %s (%d) with best freq at %ju\n", clknode_get_name(p_main), sc->main_parent, best); break; } } if (rate == sc->nrates) return (0); if ((flags & CLK_SET_DRYRUN) != 0) { *fout = best; *stop = 1; return (0); } - dprintf("Changing parent (%s) freq to %lu\n", clknode_get_name(p_main), best_p); + dprintf("Changing parent (%s) freq to %ju\n", clknode_get_name(p_main), + best_p); err = clknode_set_freq(p_main, best_p, 0, 1); if (err != 0) - printf("Cannot set %s to %lu\n", + printf("Cannot set %s to %ju\n", clknode_get_name(p_main), best_p); clknode_set_parent_by_idx(clk, sc->main_parent); clknode_get_freq(p_main, &best_p); - dprintf("main parent freq at %lu\n", best_p); + dprintf("main parent freq at %ju\n", best_p); DEVICE_LOCK(clk); val |= (div - 1) << sc->div_shift; val |= sc->div_mask << RK_ARMCLK_WRITE_MASK_SHIFT; dprintf("Write: muxdiv_offset=%x, val=%x\n", sc->muxdiv_offset, val); WRITE4(clk, sc->muxdiv_offset, val); DEVICE_UNLOCK(clk); *fout = best; *stop = 1; return (0); } static clknode_method_t rk_clk_armclk_clknode_methods[] = { /* Device interface */ CLKNODEMETHOD(clknode_init, rk_clk_armclk_init), CLKNODEMETHOD(clknode_set_mux, rk_clk_armclk_set_mux), CLKNODEMETHOD(clknode_recalc_freq, rk_clk_armclk_recalc), CLKNODEMETHOD(clknode_set_freq, rk_clk_armclk_set_freq), CLKNODEMETHOD_END }; DEFINE_CLASS_1(rk_clk_armclk_clknode, rk_clk_armclk_clknode_class, rk_clk_armclk_clknode_methods, sizeof(struct rk_clk_armclk_sc), clknode_class); int rk_clk_armclk_register(struct clkdom *clkdom, struct rk_clk_armclk_def *clkdef) { struct clknode *clk; struct rk_clk_armclk_sc *sc; clk = clknode_create(clkdom, &rk_clk_armclk_clknode_class, &clkdef->clkdef); if (clk == NULL) return (1); sc = clknode_get_softc(clk); sc->muxdiv_offset = clkdef->muxdiv_offset; sc->mux_shift = clkdef->mux_shift; sc->mux_width = clkdef->mux_width; sc->mux_mask = ((1 << clkdef->mux_width) - 1) << sc->mux_shift; sc->div_shift = clkdef->div_shift; sc->div_width = clkdef->div_width; sc->div_mask = ((1 << clkdef->div_width) - 1) << sc->div_shift; sc->flags = clkdef->flags; sc->main_parent = clkdef->main_parent; sc->alt_parent = clkdef->alt_parent; sc->rates = clkdef->rates; sc->nrates = clkdef->nrates; clknode_register(clkdom, clk); return (0); } Index: head/sys/arm64/rockchip/clk/rk_clk_composite.c =================================================================== --- head/sys/arm64/rockchip/clk/rk_clk_composite.c (revision 354554) +++ head/sys/arm64/rockchip/clk/rk_clk_composite.c (revision 354555) @@ -1,299 +1,308 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2018 Emmanuel Vadot * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include "clkdev_if.h" struct rk_clk_composite_sc { uint32_t muxdiv_offset; uint32_t mux_shift; uint32_t mux_width; uint32_t mux_mask; uint32_t div_shift; uint32_t div_width; uint32_t div_mask; uint32_t gate_offset; uint32_t gate_shift; uint32_t flags; }; #define WRITE4(_clk, off, val) \ CLKDEV_WRITE_4(clknode_get_device(_clk), off, val) #define READ4(_clk, off, val) \ CLKDEV_READ_4(clknode_get_device(_clk), off, val) -#define DEVICE_LOCK(_clk) \ +#define DEVICE_LOCK(_clk) \ CLKDEV_DEVICE_LOCK(clknode_get_device(_clk)) #define DEVICE_UNLOCK(_clk) \ CLKDEV_DEVICE_UNLOCK(clknode_get_device(_clk)) #define RK_CLK_COMPOSITE_MASK_SHIFT 16 -/* #define dprintf(format, arg...) printf("%s:(%s)" format, __func__, clknode_get_name(clk), arg) */ +#if 0 +#define dprintf(format, arg...) \ + printf("%s:(%s)" format, __func__, clknode_get_name(clk), arg) +#else #define dprintf(format, arg...) +#endif static int rk_clk_composite_init(struct clknode *clk, device_t dev) { struct rk_clk_composite_sc *sc; uint32_t val, idx; sc = clknode_get_softc(clk); idx = 0; if ((sc->flags & RK_CLK_COMPOSITE_HAVE_MUX) != 0) { DEVICE_LOCK(clk); READ4(clk, sc->muxdiv_offset, &val); DEVICE_UNLOCK(clk); idx = (val & sc->mux_mask) >> sc->mux_shift; } clknode_init_parent_idx(clk, idx); return (0); } static int rk_clk_composite_set_gate(struct clknode *clk, bool enable) { struct rk_clk_composite_sc *sc; uint32_t val = 0; sc = clknode_get_softc(clk); if ((sc->flags & RK_CLK_COMPOSITE_HAVE_GATE) == 0) return (0); dprintf("%sabling gate\n", enable ? "En" : "Dis"); if (!enable) val |= 1 << sc->gate_shift; dprintf("sc->gate_shift: %x\n", sc->gate_shift); val |= (1 << sc->gate_shift) << RK_CLK_COMPOSITE_MASK_SHIFT; dprintf("Write: gate_offset=%x, val=%x\n", sc->gate_offset, val); DEVICE_LOCK(clk); WRITE4(clk, sc->gate_offset, val); DEVICE_UNLOCK(clk); return (0); } static int rk_clk_composite_set_mux(struct clknode *clk, int index) { struct rk_clk_composite_sc *sc; uint32_t val = 0; sc = clknode_get_softc(clk); if ((sc->flags & RK_CLK_COMPOSITE_HAVE_MUX) == 0) return (0); dprintf("Set mux to %d\n", index); DEVICE_LOCK(clk); val |= (index << sc->mux_shift); val |= sc->mux_mask << RK_CLK_COMPOSITE_MASK_SHIFT; dprintf("Write: muxdiv_offset=%x, val=%x\n", sc->muxdiv_offset, val); WRITE4(clk, sc->muxdiv_offset, val); DEVICE_UNLOCK(clk); return (0); } static int rk_clk_composite_recalc(struct clknode *clk, uint64_t *freq) { struct rk_clk_composite_sc *sc; uint32_t reg, div; sc = clknode_get_softc(clk); DEVICE_LOCK(clk); READ4(clk, sc->muxdiv_offset, ®); dprintf("Read: muxdiv_offset=%x, val=%x\n", sc->muxdiv_offset, reg); DEVICE_UNLOCK(clk); div = ((reg & sc->div_mask) >> sc->div_shift) + 1; dprintf("parent_freq=%lu, div=%u\n", *freq, div); *freq = *freq / div; + dprintf("Final freq=%ju\n", *freq); return (0); } static uint32_t rk_clk_composite_find_best(struct rk_clk_composite_sc *sc, uint64_t fparent, uint64_t freq) { uint64_t best, cur; uint32_t best_div, div; for (best = 0, best_div = 0, div = 0; div <= ((sc->div_mask >> sc->div_shift) + 1); div++) { cur = fparent / div; if ((freq - cur) < (freq - best)) { best = cur; best_div = div; break; } } return (best_div); } static int rk_clk_composite_set_freq(struct clknode *clk, uint64_t fparent, uint64_t *fout, int flags, int *stop) { struct rk_clk_composite_sc *sc; struct clknode *p_clk; const char **p_names; uint64_t best, cur; uint32_t div, best_div, val = 0; int p_idx, best_parent; sc = clknode_get_softc(clk); - dprintf("Finding best parent/div for target freq of %lu\n", *fout); + dprintf("Finding best parent/div for target freq of %ju\n", *fout); p_names = clknode_get_parent_names(clk); for (best_div = 0, best = 0, p_idx = 0; p_idx != clknode_get_parents_num(clk); p_idx++) { p_clk = clknode_find_by_name(p_names[p_idx]); clknode_get_freq(p_clk, &fparent); - dprintf("Testing with parent %s (%d) at freq %lu\n", clknode_get_name(p_clk), p_idx, fparent); + dprintf("Testing with parent %s (%d) at freq %ju\n", + clknode_get_name(p_clk), p_idx, fparent); div = rk_clk_composite_find_best(sc, fparent, *fout); cur = fparent / div; if ((*fout - cur) < (*fout - best)) { best = cur; best_div = div; best_parent = p_idx; - dprintf("Best parent so far %s (%d) with best freq at %lu\n", clknode_get_name(p_clk), p_idx, best); + dprintf("Best parent so far %s (%d) with best freq at " + "%ju\n", clknode_get_name(p_clk), p_idx, best); } } if (best_div == 0) return (0); if ((best < *fout) && ((flags & CLK_SET_ROUND_DOWN) == 0)) { *stop = 1; return (ERANGE); } if ((best > *fout) && ((flags & CLK_SET_ROUND_UP) == 0)) { *stop = 1; return (ERANGE); } if ((flags & CLK_SET_DRYRUN) != 0) { *fout = best; *stop = 1; return (0); } p_idx = clknode_get_parent_idx(clk); if (p_idx != best_parent) { - dprintf("Switching parent index from %d to %d\n", p_idx, best_parent); + dprintf("Switching parent index from %d to %d\n", p_idx, + best_parent); clknode_set_parent_by_idx(clk, best_parent); } dprintf("Setting divider to %d\n", best_div); DEVICE_LOCK(clk); val |= (best_div - 1) << sc->div_shift; val |= (sc->div_mask << sc->div_shift) << RK_CLK_COMPOSITE_MASK_SHIFT; dprintf("Write: muxdiv_offset=%x, val=%x\n", sc->muxdiv_offset, val); WRITE4(clk, sc->muxdiv_offset, val); DEVICE_UNLOCK(clk); *fout = best; *stop = 1; return (0); } static clknode_method_t rk_clk_composite_clknode_methods[] = { /* Device interface */ CLKNODEMETHOD(clknode_init, rk_clk_composite_init), CLKNODEMETHOD(clknode_set_gate, rk_clk_composite_set_gate), CLKNODEMETHOD(clknode_set_mux, rk_clk_composite_set_mux), CLKNODEMETHOD(clknode_recalc_freq, rk_clk_composite_recalc), CLKNODEMETHOD(clknode_set_freq, rk_clk_composite_set_freq), CLKNODEMETHOD_END }; DEFINE_CLASS_1(rk_clk_composite_clknode, rk_clk_composite_clknode_class, rk_clk_composite_clknode_methods, sizeof(struct rk_clk_composite_sc), clknode_class); int -rk_clk_composite_register(struct clkdom *clkdom, struct rk_clk_composite_def *clkdef) +rk_clk_composite_register(struct clkdom *clkdom, + struct rk_clk_composite_def *clkdef) { struct clknode *clk; struct rk_clk_composite_sc *sc; clk = clknode_create(clkdom, &rk_clk_composite_clknode_class, &clkdef->clkdef); if (clk == NULL) return (1); sc = clknode_get_softc(clk); sc->muxdiv_offset = clkdef->muxdiv_offset; sc->mux_shift = clkdef->mux_shift; sc->mux_width = clkdef->mux_width; sc->mux_mask = ((1 << clkdef->mux_width) - 1) << sc->mux_shift; sc->div_shift = clkdef->div_shift; sc->div_width = clkdef->div_width; sc->div_mask = ((1 << clkdef->div_width) - 1) << sc->div_shift; sc->gate_offset = clkdef->gate_offset; sc->gate_shift = clkdef->gate_shift; sc->flags = clkdef->flags; clknode_register(clkdom, clk); return (0); } Index: head/sys/arm64/rockchip/clk/rk_clk_gate.c =================================================================== --- head/sys/arm64/rockchip/clk/rk_clk_gate.c (revision 354554) +++ head/sys/arm64/rockchip/clk/rk_clk_gate.c (revision 354555) @@ -1,135 +1,135 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright 2016 Michal Meloun * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include "clkdev_if.h" #define WR4(_clk, off, val) \ CLKDEV_WRITE_4(clknode_get_device(_clk), off, val) #define RD4(_clk, off, val) \ CLKDEV_READ_4(clknode_get_device(_clk), off, val) #define MD4(_clk, off, clr, set ) \ CLKDEV_MODIFY_4(clknode_get_device(_clk), off, clr, set) -#define DEVICE_LOCK(_clk) \ +#define DEVICE_LOCK(_clk) \ CLKDEV_DEVICE_LOCK(clknode_get_device(_clk)) #define DEVICE_UNLOCK(_clk) \ CLKDEV_DEVICE_UNLOCK(clknode_get_device(_clk)) static int rk_clk_gate_init(struct clknode *clk, device_t dev); static int rk_clk_gate_set_gate(struct clknode *clk, bool enable); struct rk_clk_gate_sc { uint32_t offset; uint32_t shift; uint32_t mask; uint32_t on_value; uint32_t off_value; int gate_flags; bool ungated; }; static clknode_method_t rk_clk_gate_methods[] = { /* Device interface */ CLKNODEMETHOD(clknode_init, rk_clk_gate_init), CLKNODEMETHOD(clknode_set_gate, rk_clk_gate_set_gate), CLKNODEMETHOD_END }; DEFINE_CLASS_1(rk_clk_gate, rk_clk_gate_class, rk_clk_gate_methods, sizeof(struct rk_clk_gate_sc), clknode_class); static int rk_clk_gate_init(struct clknode *clk, device_t dev) { uint32_t reg; struct rk_clk_gate_sc *sc; int rv; sc = clknode_get_softc(clk); DEVICE_LOCK(clk); rv = RD4(clk, sc->offset, ®); DEVICE_UNLOCK(clk); if (rv != 0) return (rv); reg = (reg >> sc->shift) & sc->mask; sc->ungated = reg == sc->on_value ? 1 : 0; clknode_init_parent_idx(clk, 0); return(0); } static int rk_clk_gate_set_gate(struct clknode *clk, bool enable) { uint32_t reg; struct rk_clk_gate_sc *sc; int rv; sc = clknode_get_softc(clk); sc->ungated = enable; DEVICE_LOCK(clk); rv = MD4(clk, sc->offset, sc->mask << sc->shift, ((sc->ungated ? sc->on_value : sc->off_value) << sc->shift) | RK_CLK_GATE_MASK); if (rv != 0) { DEVICE_UNLOCK(clk); return (rv); } RD4(clk, sc->offset, ®); DEVICE_UNLOCK(clk); return(0); } int rk_clk_gate_register(struct clkdom *clkdom, struct rk_clk_gate_def *clkdef) { struct clknode *clk; struct rk_clk_gate_sc *sc; clk = clknode_create(clkdom, &rk_clk_gate_class, &clkdef->clkdef); if (clk == NULL) return (1); sc = clknode_get_softc(clk); sc->offset = clkdef->offset; sc->shift = clkdef->shift; sc->mask = clkdef->mask; sc->on_value = clkdef->on_value; sc->off_value = clkdef->off_value; sc->gate_flags = clkdef->gate_flags; clknode_register(clkdom, clk); return (0); } Index: head/sys/arm64/rockchip/clk/rk_clk_mux.c =================================================================== --- head/sys/arm64/rockchip/clk/rk_clk_mux.c (revision 354554) +++ head/sys/arm64/rockchip/clk/rk_clk_mux.c (revision 354555) @@ -1,139 +1,139 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright 2016 Michal Meloun * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include "clkdev_if.h" #define WR4(_clk, off, val) \ CLKDEV_WRITE_4(clknode_get_device(_clk), off, val) #define RD4(_clk, off, val) \ CLKDEV_READ_4(clknode_get_device(_clk), off, val) #define MD4(_clk, off, clr, set ) \ CLKDEV_MODIFY_4(clknode_get_device(_clk), off, clr, set) -#define DEVICE_LOCK(_clk) \ +#define DEVICE_LOCK(_clk) \ CLKDEV_DEVICE_LOCK(clknode_get_device(_clk)) #define DEVICE_UNLOCK(_clk) \ CLKDEV_DEVICE_UNLOCK(clknode_get_device(_clk)) static int rk_clk_mux_init(struct clknode *clk, device_t dev); static int rk_clk_mux_set_mux(struct clknode *clk, int idx); struct rk_clk_mux_sc { uint32_t offset; uint32_t shift; uint32_t mask; int mux_flags; }; static clknode_method_t rk_clk_mux_methods[] = { /* Device interface */ CLKNODEMETHOD(clknode_init, rk_clk_mux_init), CLKNODEMETHOD(clknode_set_mux, rk_clk_mux_set_mux), CLKNODEMETHOD_END }; DEFINE_CLASS_1(rk_clk_mux, rk_clk_mux_class, rk_clk_mux_methods, sizeof(struct rk_clk_mux_sc), clknode_class); static int rk_clk_mux_init(struct clknode *clk, device_t dev) { uint32_t reg; struct rk_clk_mux_sc *sc; int rv; sc = clknode_get_softc(clk); DEVICE_LOCK(clk); rv = RD4(clk, sc->offset, ®); DEVICE_UNLOCK(clk); if (rv != 0) { return (rv); } reg = (reg >> sc->shift) & sc->mask; clknode_init_parent_idx(clk, reg); return(0); } static int rk_clk_mux_set_mux(struct clknode *clk, int idx) { uint32_t reg; struct rk_clk_mux_sc *sc; int rv; sc = clknode_get_softc(clk); DEVICE_LOCK(clk); rv = MD4(clk, sc->offset, sc->mask << sc->shift, ((idx & sc->mask) << sc->shift) | RK_CLK_MUX_MASK); if (rv != 0) { DEVICE_UNLOCK(clk); return (rv); } RD4(clk, sc->offset, ®); DEVICE_UNLOCK(clk); return(0); } int rk_clk_mux_register(struct clkdom *clkdom, struct rk_clk_mux_def *clkdef) { struct clknode *clk; struct rk_clk_mux_sc *sc; clk = clknode_create(clkdom, &rk_clk_mux_class, &clkdef->clkdef); if (clk == NULL) return (1); sc = clknode_get_softc(clk); sc->offset = clkdef->offset; sc->shift = clkdef->shift; sc->mask = (1 << clkdef->width) - 1; sc->mux_flags = clkdef->mux_flags; clknode_register(clkdom, clk); return (0); } Index: head/sys/arm64/rockchip/clk/rk_clk_pll.c =================================================================== --- head/sys/arm64/rockchip/clk/rk_clk_pll.c (revision 354554) +++ head/sys/arm64/rockchip/clk/rk_clk_pll.c (revision 354555) @@ -1,548 +1,557 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2018 Emmanuel Vadot * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include "clkdev_if.h" struct rk_clk_pll_sc { uint32_t base_offset; uint32_t gate_offset; uint32_t gate_shift; uint32_t mode_reg; uint32_t mode_shift; uint32_t flags; struct rk_clk_pll_rate *rates; struct rk_clk_pll_rate *frac_rates; bool normal_mode; }; -#define WRITE4(_clk, off, val) \ +#define WRITE4(_clk, off, val) \ CLKDEV_WRITE_4(clknode_get_device(_clk), off, val) -#define READ4(_clk, off, val) \ +#define READ4(_clk, off, val) \ CLKDEV_READ_4(clknode_get_device(_clk), off, val) -#define DEVICE_LOCK(_clk) \ +#define DEVICE_LOCK(_clk) \ CLKDEV_DEVICE_LOCK(clknode_get_device(_clk)) -#define DEVICE_UNLOCK(_clk) \ +#define DEVICE_UNLOCK(_clk) \ CLKDEV_DEVICE_UNLOCK(clknode_get_device(_clk)) #define RK_CLK_PLL_MASK_SHIFT 16 -/* #define dprintf(format, arg...) printf("%s:(%s)" format, __func__, clknode_get_name(clk), arg) */ +#if 0 +#define dprintf(format, arg...) \ + printf("%s:(%s)" format, __func__, clknode_get_name(clk), arg) +#else #define dprintf(format, arg...) +#endif static int rk_clk_pll_set_gate(struct clknode *clk, bool enable) { struct rk_clk_pll_sc *sc; uint32_t val = 0; sc = clknode_get_softc(clk); if ((sc->flags & RK_CLK_PLL_HAVE_GATE) == 0) return (0); dprintf("%sabling gate\n", enable ? "En" : "Dis"); if (!enable) val |= 1 << sc->gate_shift; dprintf("sc->gate_shift: %x\n", sc->gate_shift); val |= (1 << sc->gate_shift) << RK_CLK_PLL_MASK_SHIFT; dprintf("Write: gate_offset=%x, val=%x\n", sc->gate_offset, val); DEVICE_LOCK(clk); WRITE4(clk, sc->gate_offset, val); DEVICE_UNLOCK(clk); return (0); } #define RK3328_CLK_PLL_FBDIV_OFFSET 0 #define RK3328_CLK_PLL_FBDIV_SHIFT 0 #define RK3328_CLK_PLL_FBDIV_MASK 0xFFF #define RK3328_CLK_PLL_POSTDIV1_OFFSET 0 #define RK3328_CLK_PLL_POSTDIV1_SHIFT 12 #define RK3328_CLK_PLL_POSTDIV1_MASK 0x7000 #define RK3328_CLK_PLL_DSMPD_OFFSET 4 #define RK3328_CLK_PLL_DSMPD_SHIFT 12 #define RK3328_CLK_PLL_DSMPD_MASK 0x1000 #define RK3328_CLK_PLL_REFDIV_OFFSET 4 #define RK3328_CLK_PLL_REFDIV_SHIFT 0 #define RK3328_CLK_PLL_REFDIV_MASK 0x3F #define RK3328_CLK_PLL_POSTDIV2_OFFSET 4 #define RK3328_CLK_PLL_POSTDIV2_SHIFT 6 #define RK3328_CLK_PLL_POSTDIV2_MASK 0x1C0 #define RK3328_CLK_PLL_FRAC_OFFSET 8 #define RK3328_CLK_PLL_FRAC_SHIFT 0 #define RK3328_CLK_PLL_FRAC_MASK 0xFFFFFF #define RK3328_CLK_PLL_LOCK_MASK 0x400 #define RK3328_CLK_PLL_MODE_SLOW 0 #define RK3328_CLK_PLL_MODE_NORMAL 1 #define RK3328_CLK_PLL_MODE_MASK 0x1 static int rk3328_clk_pll_init(struct clknode *clk, device_t dev) { struct rk_clk_pll_sc *sc; sc = clknode_get_softc(clk); clknode_init_parent_idx(clk, 0); return (0); } static int rk3328_clk_pll_recalc(struct clknode *clk, uint64_t *freq) { struct rk_clk_pll_sc *sc; uint64_t rate; uint32_t dsmpd, refdiv, fbdiv; uint32_t postdiv1, postdiv2, frac; uint32_t raw1, raw2, raw3; sc = clknode_get_softc(clk); DEVICE_LOCK(clk); READ4(clk, sc->base_offset, &raw1); READ4(clk, sc->base_offset + 4, &raw2); READ4(clk, sc->base_offset + 8, &raw3); fbdiv = (raw1 & RK3328_CLK_PLL_FBDIV_MASK) >> RK3328_CLK_PLL_FBDIV_SHIFT; postdiv1 = (raw1 & RK3328_CLK_PLL_POSTDIV1_MASK) >> RK3328_CLK_PLL_POSTDIV1_SHIFT; dsmpd = (raw2 & RK3328_CLK_PLL_DSMPD_MASK) >> RK3328_CLK_PLL_DSMPD_SHIFT; refdiv = (raw2 & RK3328_CLK_PLL_REFDIV_MASK) >> RK3328_CLK_PLL_REFDIV_SHIFT; postdiv2 = (raw2 & RK3328_CLK_PLL_POSTDIV2_MASK) >> RK3328_CLK_PLL_POSTDIV2_SHIFT; frac = (raw3 & RK3328_CLK_PLL_FRAC_MASK) >> RK3328_CLK_PLL_FRAC_SHIFT; DEVICE_UNLOCK(clk); rate = *freq * fbdiv / refdiv; if (dsmpd == 0) { /* Fractional mode */ uint64_t frac_rate; frac_rate = *freq * frac / refdiv; rate += frac_rate >> 24; } *freq = rate / postdiv1 / postdiv2; if (*freq % 2) *freq = *freq + 1; return (0); } static int rk3328_clk_pll_set_freq(struct clknode *clk, uint64_t fparent, uint64_t *fout, int flags, int *stop) { struct rk_clk_pll_rate *rates; struct rk_clk_pll_sc *sc; uint32_t reg; int timeout; sc = clknode_get_softc(clk); if (sc->rates) rates = sc->rates; else if (sc->frac_rates) rates = sc->frac_rates; else return (EINVAL); for (; rates->freq; rates++) { if (rates->freq == *fout) break; } if (rates->freq == 0) { *stop = 1; return (EINVAL); } DEVICE_LOCK(clk); /* Setting to slow mode during frequency change */ reg = (RK3328_CLK_PLL_MODE_MASK << sc->mode_shift) << RK_CLK_PLL_MASK_SHIFT; dprintf("Set PLL_MODEREG to %x\n", reg); WRITE4(clk, sc->mode_reg, reg); /* Setting postdiv1 and fbdiv */ reg = (rates->postdiv1 << RK3328_CLK_PLL_POSTDIV1_SHIFT) | (rates->fbdiv << RK3328_CLK_PLL_FBDIV_SHIFT); reg |= (RK3328_CLK_PLL_POSTDIV1_MASK | RK3328_CLK_PLL_FBDIV_MASK) << 16; dprintf("Set PLL_CON0 to %x\n", reg); WRITE4(clk, sc->base_offset, reg); /* Setting dsmpd, postdiv2 and refdiv */ reg = (rates->dsmpd << RK3328_CLK_PLL_DSMPD_SHIFT) | (rates->postdiv2 << RK3328_CLK_PLL_POSTDIV2_SHIFT) | (rates->refdiv << RK3328_CLK_PLL_REFDIV_SHIFT); reg |= (RK3328_CLK_PLL_DSMPD_MASK | RK3328_CLK_PLL_POSTDIV2_MASK | RK3328_CLK_PLL_REFDIV_MASK) << RK_CLK_PLL_MASK_SHIFT; dprintf("Set PLL_CON1 to %x\n", reg); WRITE4(clk, sc->base_offset + 0x4, reg); /* Setting frac */ READ4(clk, sc->base_offset + 0x8, ®); reg &= ~RK3328_CLK_PLL_FRAC_MASK; reg |= rates->frac << RK3328_CLK_PLL_FRAC_SHIFT; dprintf("Set PLL_CON2 to %x\n", reg); WRITE4(clk, sc->base_offset + 0x8, reg); /* Reading lock */ for (timeout = 1000; timeout; timeout--) { READ4(clk, sc->base_offset + 0x4, ®); if ((reg & RK3328_CLK_PLL_LOCK_MASK) == 0) break; DELAY(1); } /* Set back to normal mode */ reg = (RK3328_CLK_PLL_MODE_NORMAL << sc->mode_shift); reg |= (RK3328_CLK_PLL_MODE_MASK << sc->mode_shift) << RK_CLK_PLL_MASK_SHIFT; dprintf("Set PLL_MODEREG to %x\n", reg); WRITE4(clk, sc->mode_reg, reg); DEVICE_UNLOCK(clk); *stop = 1; return (0); } static clknode_method_t rk3328_clk_pll_clknode_methods[] = { /* Device interface */ CLKNODEMETHOD(clknode_init, rk3328_clk_pll_init), CLKNODEMETHOD(clknode_set_gate, rk_clk_pll_set_gate), CLKNODEMETHOD(clknode_recalc_freq, rk3328_clk_pll_recalc), CLKNODEMETHOD(clknode_set_freq, rk3328_clk_pll_set_freq), CLKNODEMETHOD_END }; DEFINE_CLASS_1(rk3328_clk_pll_clknode, rk3328_clk_pll_clknode_class, rk3328_clk_pll_clknode_methods, sizeof(struct rk_clk_pll_sc), clknode_class); int rk3328_clk_pll_register(struct clkdom *clkdom, struct rk_clk_pll_def *clkdef) { struct clknode *clk; struct rk_clk_pll_sc *sc; clk = clknode_create(clkdom, &rk3328_clk_pll_clknode_class, &clkdef->clkdef); if (clk == NULL) return (1); sc = clknode_get_softc(clk); sc->base_offset = clkdef->base_offset; sc->gate_offset = clkdef->gate_offset; sc->gate_shift = clkdef->gate_shift; sc->mode_reg = clkdef->mode_reg; sc->mode_shift = clkdef->mode_shift; sc->flags = clkdef->flags; sc->rates = clkdef->rates; sc->frac_rates = clkdef->frac_rates; clknode_register(clkdom, clk); return (0); } #define RK3399_CLK_PLL_FBDIV_OFFSET 0 #define RK3399_CLK_PLL_FBDIV_SHIFT 0 #define RK3399_CLK_PLL_FBDIV_MASK 0xFFF #define RK3399_CLK_PLL_POSTDIV2_OFFSET 4 #define RK3399_CLK_PLL_POSTDIV2_SHIFT 12 #define RK3399_CLK_PLL_POSTDIV2_MASK 0x7000 #define RK3399_CLK_PLL_POSTDIV1_OFFSET 4 #define RK3399_CLK_PLL_POSTDIV1_SHIFT 8 #define RK3399_CLK_PLL_POSTDIV1_MASK 0x700 #define RK3399_CLK_PLL_REFDIV_OFFSET 4 #define RK3399_CLK_PLL_REFDIV_SHIFT 0 #define RK3399_CLK_PLL_REFDIV_MASK 0x3F #define RK3399_CLK_PLL_FRAC_OFFSET 8 #define RK3399_CLK_PLL_FRAC_SHIFT 0 #define RK3399_CLK_PLL_FRAC_MASK 0xFFFFFF #define RK3399_CLK_PLL_DSMPD_OFFSET 0xC #define RK3399_CLK_PLL_DSMPD_SHIFT 3 #define RK3399_CLK_PLL_DSMPD_MASK 0x8 #define RK3399_CLK_PLL_LOCK_OFFSET 8 #define RK3399_CLK_PLL_LOCK_MASK 0x400 #define RK3399_CLK_PLL_MODE_OFFSET 0xC #define RK3399_CLK_PLL_MODE_MASK 0x300 #define RK3399_CLK_PLL_MODE_SLOW 0 #define RK3399_CLK_PLL_MODE_NORMAL 1 #define RK3399_CLK_PLL_MODE_DEEPSLOW 2 #define RK3399_CLK_PLL_MODE_SHIFT 8 #define RK3399_CLK_PLL_WRITE_MASK 0xFFFF0000 static int rk3399_clk_pll_init(struct clknode *clk, device_t dev) { struct rk_clk_pll_sc *sc; uint32_t reg; sc = clknode_get_softc(clk); if (sc->normal_mode) { /* Setting to normal mode */ reg = RK3399_CLK_PLL_MODE_NORMAL << RK3399_CLK_PLL_MODE_SHIFT; reg |= RK3399_CLK_PLL_MODE_MASK << RK_CLK_PLL_MASK_SHIFT; WRITE4(clk, sc->base_offset + RK3399_CLK_PLL_MODE_OFFSET, reg | RK3399_CLK_PLL_WRITE_MASK); } clknode_init_parent_idx(clk, 0); return (0); } static int rk3399_clk_pll_recalc(struct clknode *clk, uint64_t *freq) { struct rk_clk_pll_sc *sc; uint32_t dsmpd, refdiv, fbdiv; uint32_t postdiv1, postdiv2, fracdiv; uint32_t con1, con2, con3, con4; uint64_t foutvco; uint32_t mode; sc = clknode_get_softc(clk); DEVICE_LOCK(clk); READ4(clk, sc->base_offset, &con1); READ4(clk, sc->base_offset + 4, &con2); READ4(clk, sc->base_offset + 8, &con3); READ4(clk, sc->base_offset + 0xC, &con4); DEVICE_UNLOCK(clk); /* * if we are in slow mode the output freq * is the parent one, the 24Mhz external oscillator * if we are in deep mode the output freq is 32.768khz */ mode = (con4 & RK3399_CLK_PLL_MODE_MASK) >> RK3399_CLK_PLL_MODE_SHIFT; if (mode == RK3399_CLK_PLL_MODE_SLOW) { dprintf("pll in slow mode, con4=%x\n", con4); return (0); } else if (mode == RK3399_CLK_PLL_MODE_DEEPSLOW) { dprintf("pll in deep slow, con4=%x\n", con4); *freq = 32768; return (0); } dprintf("con0: %x\n", con1); dprintf("con1: %x\n", con2); dprintf("con2: %x\n", con3); dprintf("con3: %x\n", con4); - fbdiv = (con1 & RK3399_CLK_PLL_FBDIV_MASK) >> RK3399_CLK_PLL_FBDIV_SHIFT; + fbdiv = (con1 & RK3399_CLK_PLL_FBDIV_MASK) + >> RK3399_CLK_PLL_FBDIV_SHIFT; - postdiv1 = (con2 & RK3399_CLK_PLL_POSTDIV1_MASK) >> RK3399_CLK_PLL_POSTDIV1_SHIFT; - postdiv2 = (con2 & RK3399_CLK_PLL_POSTDIV2_MASK) >> RK3399_CLK_PLL_POSTDIV2_SHIFT; - refdiv = (con2 & RK3399_CLK_PLL_REFDIV_MASK) >> RK3399_CLK_PLL_REFDIV_SHIFT; + postdiv1 = (con2 & RK3399_CLK_PLL_POSTDIV1_MASK) + >> RK3399_CLK_PLL_POSTDIV1_SHIFT; + postdiv2 = (con2 & RK3399_CLK_PLL_POSTDIV2_MASK) + >> RK3399_CLK_PLL_POSTDIV2_SHIFT; + refdiv = (con2 & RK3399_CLK_PLL_REFDIV_MASK) + >> RK3399_CLK_PLL_REFDIV_SHIFT; - fracdiv = (con3 & RK3399_CLK_PLL_FRAC_MASK) >> RK3399_CLK_PLL_FRAC_SHIFT; + fracdiv = (con3 & RK3399_CLK_PLL_FRAC_MASK) + >> RK3399_CLK_PLL_FRAC_SHIFT; fracdiv >>= 24; dsmpd = (con4 & RK3399_CLK_PLL_DSMPD_MASK) >> RK3399_CLK_PLL_DSMPD_SHIFT; dprintf("fbdiv: %d\n", fbdiv); dprintf("postdiv1: %d\n", postdiv1); dprintf("postdiv2: %d\n", postdiv2); dprintf("refdiv: %d\n", refdiv); dprintf("fracdiv: %d\n", fracdiv); dprintf("dsmpd: %d\n", dsmpd); - dprintf("parent freq=%lu\n", *freq); + dprintf("parent freq=%ju\n", *freq); if (dsmpd == 0) { /* Fractional mode */ foutvco = *freq / refdiv * (fbdiv + fracdiv); } else { /* Integer mode */ foutvco = *freq / refdiv * fbdiv; } - dprintf("foutvco: %lu\n", foutvco); + dprintf("foutvco: %ju\n", foutvco); *freq = foutvco / postdiv1 / postdiv2; - dprintf("freq: %lu\n", *freq); + dprintf("freq: %ju\n", *freq); return (0); } static int rk3399_clk_pll_set_freq(struct clknode *clk, uint64_t fparent, uint64_t *fout, int flags, int *stop) { struct rk_clk_pll_rate *rates; struct rk_clk_pll_sc *sc; uint32_t reg; int timeout; sc = clknode_get_softc(clk); if (sc->rates) rates = sc->rates; else if (sc->frac_rates) rates = sc->frac_rates; else return (EINVAL); for (; rates->freq; rates++) { if (rates->freq == *fout) break; } if (rates->freq == 0) { *stop = 1; return (EINVAL); } DEVICE_LOCK(clk); /* Set to slow mode during frequency change */ reg = RK3399_CLK_PLL_MODE_SLOW << RK3399_CLK_PLL_MODE_SHIFT; reg |= RK3399_CLK_PLL_MODE_MASK << RK_CLK_PLL_MASK_SHIFT; WRITE4(clk, sc->base_offset + 0xC, reg); /* Setting fbdiv */ reg = rates->fbdiv << RK3399_CLK_PLL_FBDIV_SHIFT; reg |= RK3399_CLK_PLL_FBDIV_MASK << RK_CLK_PLL_MASK_SHIFT; WRITE4(clk, sc->base_offset, reg); /* Setting postdiv1, postdiv2 and refdiv */ reg = rates->postdiv1 << RK3399_CLK_PLL_POSTDIV1_SHIFT; reg |= rates->postdiv2 << RK3399_CLK_PLL_POSTDIV2_SHIFT; reg |= rates->refdiv << RK3399_CLK_PLL_REFDIV_SHIFT; reg |= (RK3399_CLK_PLL_POSTDIV1_MASK | RK3399_CLK_PLL_POSTDIV2_MASK | RK3399_CLK_PLL_REFDIV_MASK) << RK_CLK_PLL_MASK_SHIFT; WRITE4(clk, sc->base_offset + 0x4, reg); /* Setting frac */ READ4(clk, sc->base_offset + 0x8, ®); reg &= ~RK3399_CLK_PLL_FRAC_MASK; reg |= rates->frac << RK3399_CLK_PLL_FRAC_SHIFT; WRITE4(clk, sc->base_offset + 0x8, reg | RK3399_CLK_PLL_WRITE_MASK); /* Set dsmpd */ reg = rates->dsmpd << RK3399_CLK_PLL_DSMPD_SHIFT; reg |= RK3399_CLK_PLL_DSMPD_MASK << RK_CLK_PLL_MASK_SHIFT; WRITE4(clk, sc->base_offset + 0xC, reg); /* Reading lock */ for (timeout = 1000; timeout; timeout--) { READ4(clk, sc->base_offset + RK3399_CLK_PLL_LOCK_OFFSET, ®); if ((reg & RK3399_CLK_PLL_LOCK_MASK) == 0) break; DELAY(1); } /* Set back to normal mode */ reg = RK3399_CLK_PLL_MODE_NORMAL << RK3399_CLK_PLL_MODE_SHIFT; reg |= RK3399_CLK_PLL_MODE_MASK << RK_CLK_PLL_MASK_SHIFT; WRITE4(clk, sc->base_offset + 0xC, reg); DEVICE_UNLOCK(clk); *stop = 1; return (0); } static clknode_method_t rk3399_clk_pll_clknode_methods[] = { /* Device interface */ CLKNODEMETHOD(clknode_init, rk3399_clk_pll_init), CLKNODEMETHOD(clknode_set_gate, rk_clk_pll_set_gate), CLKNODEMETHOD(clknode_recalc_freq, rk3399_clk_pll_recalc), CLKNODEMETHOD(clknode_set_freq, rk3399_clk_pll_set_freq), CLKNODEMETHOD_END }; DEFINE_CLASS_1(rk3399_clk_pll_clknode, rk3399_clk_pll_clknode_class, rk3399_clk_pll_clknode_methods, sizeof(struct rk_clk_pll_sc), clknode_class); int rk3399_clk_pll_register(struct clkdom *clkdom, struct rk_clk_pll_def *clkdef) { struct clknode *clk; struct rk_clk_pll_sc *sc; clk = clknode_create(clkdom, &rk3399_clk_pll_clknode_class, &clkdef->clkdef); if (clk == NULL) return (1); sc = clknode_get_softc(clk); sc->base_offset = clkdef->base_offset; sc->gate_offset = clkdef->gate_offset; sc->gate_shift = clkdef->gate_shift; sc->flags = clkdef->flags; sc->rates = clkdef->rates; sc->frac_rates = clkdef->frac_rates; sc->normal_mode = clkdef->normal_mode; clknode_register(clkdom, clk); return (0); } Index: head/sys/arm64/rockchip/clk/rk_cru.c =================================================================== --- head/sys/arm64/rockchip/clk/rk_cru.c (revision 354554) +++ head/sys/arm64/rockchip/clk/rk_cru.c (revision 354555) @@ -1,290 +1,293 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2018 Emmanuel Vadot * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ /* * RockChip Clock and Reset Unit */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "clkdev_if.h" #include "hwreset_if.h" static struct resource_spec rk_cru_spec[] = { { SYS_RES_MEMORY, 0, RF_ACTIVE }, { -1, 0 } }; #define CCU_READ4(sc, reg) bus_read_4((sc)->res, (reg)) #define CCU_WRITE4(sc, reg, val) bus_write_4((sc)->res, (reg), (val)) void rk3328_cru_register_clocks(struct rk_cru_softc *sc); static int rk_cru_write_4(device_t dev, bus_addr_t addr, uint32_t val) { struct rk_cru_softc *sc; sc = device_get_softc(dev); CCU_WRITE4(sc, addr, val); return (0); } static int rk_cru_read_4(device_t dev, bus_addr_t addr, uint32_t *val) { struct rk_cru_softc *sc; sc = device_get_softc(dev); *val = CCU_READ4(sc, addr); return (0); } static int rk_cru_modify_4(device_t dev, bus_addr_t addr, uint32_t clr, uint32_t set) { struct rk_cru_softc *sc; uint32_t reg; sc = device_get_softc(dev); reg = CCU_READ4(sc, addr); reg &= ~clr; reg |= set; CCU_WRITE4(sc, addr, reg); return (0); } static int rk_cru_reset_assert(device_t dev, intptr_t id, bool reset) { struct rk_cru_softc *sc; uint32_t reg; int bit; uint32_t val; sc = device_get_softc(dev); if (id > sc->reset_num) return (ENXIO); reg = sc->reset_offset + id / 16 * 4; bit = id % 16; mtx_lock(&sc->mtx); val = 0; if (reset) val = (1 << bit); CCU_WRITE4(sc, reg, val | ((1 << bit) << 16)); mtx_unlock(&sc->mtx); return (0); } static int rk_cru_reset_is_asserted(device_t dev, intptr_t id, bool *reset) { struct rk_cru_softc *sc; uint32_t reg; int bit; uint32_t val; sc = device_get_softc(dev); if (id > sc->reset_num) return (ENXIO); reg = sc->reset_offset + id / 16 * 4; bit = id % 16; mtx_lock(&sc->mtx); val = CCU_READ4(sc, reg); mtx_unlock(&sc->mtx); *reset = false; if (val & (1 << bit)) *reset = true; return (0); } static void rk_cru_device_lock(device_t dev) { struct rk_cru_softc *sc; sc = device_get_softc(dev); mtx_lock(&sc->mtx); } static void rk_cru_device_unlock(device_t dev) { struct rk_cru_softc *sc; sc = device_get_softc(dev); mtx_unlock(&sc->mtx); } static int rk_cru_register_gates(struct rk_cru_softc *sc) { struct rk_clk_gate_def def; int i; for (i = 0; i < sc->ngates; i++) { if (sc->gates[i].name == NULL) continue; memset(&def, 0, sizeof(def)); def.clkdef.id = sc->gates[i].id; def.clkdef.name = sc->gates[i].name; def.clkdef.parent_names = &sc->gates[i].parent_name; def.clkdef.parent_cnt = 1; def.offset = sc->gates[i].offset; def.shift = sc->gates[i].shift; def.mask = 1; def.on_value = 0; def.off_value = 1; rk_clk_gate_register(sc->clkdom, &def); } return (0); } int rk_cru_attach(device_t dev) { struct rk_cru_softc *sc; phandle_t node; int i; sc = device_get_softc(dev); sc->dev = dev; node = ofw_bus_get_node(dev); if (bus_alloc_resources(dev, rk_cru_spec, &sc->res) != 0) { device_printf(dev, "cannot allocate resources for device\n"); return (ENXIO); } mtx_init(&sc->mtx, device_get_nameunit(dev), NULL, MTX_DEF); sc->clkdom = clkdom_create(dev); if (sc->clkdom == NULL) panic("Cannot create clkdom\n"); for (i = 0; i < sc->nclks; i++) { switch (sc->clks[i].type) { case RK_CLK_UNDEFINED: break; case RK3328_CLK_PLL: - rk3328_clk_pll_register(sc->clkdom, sc->clks[i].clk.pll); + rk3328_clk_pll_register(sc->clkdom, + sc->clks[i].clk.pll); break; case RK3399_CLK_PLL: - rk3399_clk_pll_register(sc->clkdom, sc->clks[i].clk.pll); + rk3399_clk_pll_register(sc->clkdom, + sc->clks[i].clk.pll); break; case RK_CLK_COMPOSITE: rk_clk_composite_register(sc->clkdom, sc->clks[i].clk.composite); break; case RK_CLK_MUX: rk_clk_mux_register(sc->clkdom, sc->clks[i].clk.mux); break; case RK_CLK_ARMCLK: - rk_clk_armclk_register(sc->clkdom, sc->clks[i].clk.armclk); + rk_clk_armclk_register(sc->clkdom, + sc->clks[i].clk.armclk); break; default: device_printf(dev, "Unknown clock type\n"); return (ENXIO); break; } } if (sc->gates) rk_cru_register_gates(sc); if (clkdom_finit(sc->clkdom) != 0) panic("cannot finalize clkdom initialization\n"); if (bootverbose) clkdom_dump(sc->clkdom); clk_set_assigned(dev, node); /* register our self as a reset provider */ hwreset_register_ofw_provider(dev); return (0); } static device_method_t rk_cru_methods[] = { /* clkdev interface */ DEVMETHOD(clkdev_write_4, rk_cru_write_4), DEVMETHOD(clkdev_read_4, rk_cru_read_4), DEVMETHOD(clkdev_modify_4, rk_cru_modify_4), DEVMETHOD(clkdev_device_lock, rk_cru_device_lock), DEVMETHOD(clkdev_device_unlock, rk_cru_device_unlock), /* Reset interface */ DEVMETHOD(hwreset_assert, rk_cru_reset_assert), DEVMETHOD(hwreset_is_asserted, rk_cru_reset_is_asserted), DEVMETHOD_END }; DEFINE_CLASS_0(rk_cru, rk_cru_driver, rk_cru_methods, sizeof(struct rk_cru_softc));