Path: blob/main/sys/dev/clk/starfive/jh7110_clk.c
106180 views
/*-1* SPDX-License-Identifier: BSD-2-Clause2*3* Copyright (c) 2019 Emmanuel Vadot <[email protected]>4* Copyright (c) 2022 Mitchell Horne <[email protected]>5* Copyright (c) 2024 Jari Sihvola <[email protected]>6*/78#include <sys/param.h>9#include <sys/systm.h>10#include <sys/bus.h>11#include <sys/mutex.h>12#include <sys/rman.h>1314#include <machine/bus.h>15#include <machine/intr.h>16#include <machine/resource.h>1718#include <dev/clk/clk.h>19#include <dev/hwreset/hwreset.h>2021#include <dt-bindings/clock/starfive,jh7110-crg.h>2223#include <dev/clk/starfive/jh7110_clk.h>2425#include "clkdev_if.h"26#include "hwreset_if.h"2728#define JH7110_DIV_MASK 0xffffff29#define JH7110_MUX_SHIFT 2430#define JH7110_MUX_MASK 0x3f00000031#define JH7110_ENABLE_SHIFT 313233#define REG_SIZE 43435struct jh7110_clk_sc {36uint32_t offset;37uint32_t flags;38uint64_t d_max;39int id;40};4142#define DIV_ROUND_CLOSEST(n, d) (((n) + (d) / 2) / (d))4344#define READ4(_sc, _off) \45bus_read_4(_sc->mem_res, _off)46#define WRITE4(_sc, _off, _val) \47bus_write_4(_sc->mem_res, _off, _val)4849#define DEVICE_LOCK(_clk) \50CLKDEV_DEVICE_LOCK(clknode_get_device(_clk))51#define DEVICE_UNLOCK(_clk) \52CLKDEV_DEVICE_UNLOCK(clknode_get_device(_clk))5354/* Reset functions */5556int57jh7110_reset_assert(device_t dev, intptr_t id, bool assert)58{59struct jh7110_clkgen_softc *sc;60uint32_t regvalue, offset, bitmask = 1UL << id % 32;6162sc = device_get_softc(dev);63offset = sc->reset_selector_offset + id / 32 * 4;6465mtx_lock(&sc->mtx);6667regvalue = READ4(sc, offset);6869if (assert)70regvalue |= bitmask;71else72regvalue &= ~bitmask;73WRITE4(sc, offset, regvalue);7475mtx_unlock(&sc->mtx);7677return (0);78}7980int81jh7110_reset_is_asserted(device_t dev, intptr_t id, bool *reset)82{83struct jh7110_clkgen_softc *sc;84uint32_t regvalue, offset, bitmask;8586sc = device_get_softc(dev);87offset = sc->reset_status_offset + id / 32 * 4;8889mtx_lock(&sc->mtx);9091regvalue = READ4(sc, offset);92bitmask = 1UL << id % 32;9394mtx_unlock(&sc->mtx);9596*reset = (regvalue & bitmask) == 0;9798return (0);99}100101/* Clock functions */102103static int104jh7110_clk_init(struct clknode *clk, device_t dev)105{106struct jh7110_clkgen_softc *sc;107struct jh7110_clk_sc *sc_clk;108uint32_t reg;109int idx = 0;110111sc = device_get_softc(clknode_get_device(clk));112sc_clk = clknode_get_softc(clk);113114if (sc_clk->flags & JH7110_CLK_HAS_MUX) {115DEVICE_LOCK(clk);116reg = READ4(sc, sc_clk->offset);117DEVICE_UNLOCK(clk);118idx = (reg & JH7110_MUX_MASK) >> JH7110_MUX_SHIFT;119}120121clknode_init_parent_idx(clk, idx);122123return (0);124}125126static int127jh7110_clk_set_gate(struct clknode *clk, bool enable)128{129struct jh7110_clkgen_softc *sc;130struct jh7110_clk_sc *sc_clk;131uint32_t reg;132133sc = device_get_softc(clknode_get_device(clk));134sc_clk = clknode_get_softc(clk);135136if ((sc_clk->flags & JH7110_CLK_HAS_GATE) == 0)137return (0);138139DEVICE_LOCK(clk);140141reg = READ4(sc, sc_clk->offset);142if (enable)143reg |= (1 << JH7110_ENABLE_SHIFT);144else145reg &= ~(1 << JH7110_ENABLE_SHIFT);146WRITE4(sc, sc_clk->offset, reg);147148DEVICE_UNLOCK(clk);149150return (0);151}152153static int154jh7110_clk_set_mux(struct clknode *clk, int idx)155{156struct jh7110_clkgen_softc *sc;157struct jh7110_clk_sc *sc_clk;158uint32_t reg;159160sc = device_get_softc(clknode_get_device(clk));161sc_clk = clknode_get_softc(clk);162163if ((sc_clk->flags & JH7110_CLK_HAS_MUX) == 0)164return (ENXIO);165166/* Checking index size */167if ((idx & (JH7110_MUX_MASK >> JH7110_MUX_SHIFT)) != idx)168return (EINVAL);169170DEVICE_LOCK(clk);171172reg = READ4(sc, sc_clk->offset) & ~JH7110_MUX_MASK;173reg |= idx << JH7110_MUX_SHIFT;174WRITE4(sc, sc_clk->offset, reg);175176DEVICE_UNLOCK(clk);177178return (0);179}180181static int182jh7110_clk_recalc_freq(struct clknode *clk, uint64_t *freq)183{184struct jh7110_clkgen_softc *sc;185struct jh7110_clk_sc *sc_clk;186uint32_t divisor;187188sc = device_get_softc(clknode_get_device(clk));189sc_clk = clknode_get_softc(clk);190191/* Returning error here causes panic */192if ((sc_clk->flags & JH7110_CLK_HAS_DIV) == 0)193return (0);194195DEVICE_LOCK(clk);196197divisor = READ4(sc, sc_clk->offset) & JH7110_DIV_MASK;198199DEVICE_UNLOCK(clk);200201if (divisor)202*freq = *freq / divisor;203else204*freq = 0;205206return (0);207}208209static int210jh7110_clk_set_freq(struct clknode *clk, uint64_t fin, uint64_t *fout,211int flags, int *done)212{213struct jh7110_clkgen_softc *sc;214struct jh7110_clk_sc *sc_clk;215uint32_t divisor;216217sc = device_get_softc(clknode_get_device(clk));218sc_clk = clknode_get_softc(clk);219220if ((sc_clk->flags & JH7110_CLK_HAS_DIV) == 0)221return (0);222223divisor = MIN(MAX(DIV_ROUND_CLOSEST(fin, *fout), 1UL), sc_clk->d_max);224225if (flags & CLK_SET_DRYRUN)226goto done;227228DEVICE_LOCK(clk);229230divisor |= READ4(sc, sc_clk->offset) & ~JH7110_DIV_MASK;231WRITE4(sc, sc_clk->offset, divisor);232233DEVICE_UNLOCK(clk);234235done:236*fout = divisor;237*done = 1;238239return (0);240}241242static clknode_method_t jh7110_clknode_methods[] = {243/* Device interface */244CLKNODEMETHOD(clknode_init, jh7110_clk_init),245CLKNODEMETHOD(clknode_set_gate, jh7110_clk_set_gate),246CLKNODEMETHOD(clknode_set_mux, jh7110_clk_set_mux),247CLKNODEMETHOD(clknode_recalc_freq, jh7110_clk_recalc_freq),248CLKNODEMETHOD(clknode_set_freq, jh7110_clk_set_freq),249CLKNODEMETHOD_END250};251252DEFINE_CLASS_1(jh7110_clknode, jh7110_clknode_class, jh7110_clknode_methods,253sizeof(struct jh7110_clk_sc), clknode_class);254255int256jh7110_clk_register(struct clkdom *clkdom, const struct jh7110_clk_def *clkdef)257{258struct clknode *clk;259struct jh7110_clk_sc *sc;260261clk = clknode_create(clkdom, &jh7110_clknode_class, &clkdef->clkdef);262if (clk == NULL)263return (-1);264265sc = clknode_get_softc(clk);266267sc->offset = clkdef->clkdef.id * REG_SIZE;268269sc->flags = clkdef->flags;270sc->id = clkdef->clkdef.id;271sc->d_max = clkdef->d_max;272273clknode_register(clkdom, clk);274275return (0);276}277278279