mirror of
https://github.com/freebsd/freebsd-src
synced 2024-10-15 04:43:53 +00:00
Revert "jh7110: Add StarFive JH7110 clock/reset generator drivers"
I did not set the author field properly; revert to fix this.
This reverts commit 5d6d627897
.
This commit is contained in:
parent
c8b472aa4b
commit
6ea05fce8e
|
@ -1,277 +0,0 @@
|
|||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2019 Emmanuel Vadot <manu@freebsd.org>
|
||||
* Copyright (c) 2022 Mitchell Horne <mhorne@FreeBSD.org>
|
||||
* Copyright (c) 2024 Jari Sihvola <jsihv@gmx.com>
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/mutex.h>
|
||||
#include <sys/rman.h>
|
||||
|
||||
#include <machine/bus.h>
|
||||
#include <machine/intr.h>
|
||||
#include <machine/resource.h>
|
||||
|
||||
#include <dev/clk/clk.h>
|
||||
#include <dev/hwreset/hwreset.h>
|
||||
|
||||
#include <dt-bindings/clock/starfive,jh7110-crg.h>
|
||||
|
||||
#include <dev/clk/starfive/jh7110_clk.h>
|
||||
|
||||
#include "clkdev_if.h"
|
||||
#include "hwreset_if.h"
|
||||
|
||||
#define JH7110_DIV_MASK 0xffffff
|
||||
#define JH7110_MUX_SHIFT 24
|
||||
#define JH7110_MUX_MASK 0x3f000000
|
||||
#define JH7110_ENABLE_SHIFT 31
|
||||
|
||||
#define REG_SIZE 4
|
||||
|
||||
struct jh7110_clk_sc {
|
||||
uint32_t offset;
|
||||
uint32_t flags;
|
||||
uint64_t d_max;
|
||||
int id;
|
||||
};
|
||||
|
||||
#define DIV_ROUND_CLOSEST(n, d) (((n) + (d) / 2) / (d))
|
||||
|
||||
#define READ4(_sc, _off) \
|
||||
bus_read_4(_sc->mem_res, _off)
|
||||
#define WRITE4(_sc, _off, _val) \
|
||||
bus_write_4(_sc->mem_res, _off, _val)
|
||||
|
||||
#define DEVICE_LOCK(_clk) \
|
||||
CLKDEV_DEVICE_LOCK(clknode_get_device(_clk))
|
||||
#define DEVICE_UNLOCK(_clk) \
|
||||
CLKDEV_DEVICE_UNLOCK(clknode_get_device(_clk))
|
||||
|
||||
/* Reset functions */
|
||||
|
||||
int
|
||||
jh7110_reset_assert(device_t dev, intptr_t id, bool assert)
|
||||
{
|
||||
struct jh7110_clkgen_softc *sc;
|
||||
uint32_t regvalue, offset, bitmask = 1UL << id % 32;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
offset = sc->reset_selector_offset + id / 32 * 4;
|
||||
|
||||
mtx_lock(&sc->mtx);
|
||||
|
||||
regvalue = READ4(sc, offset);
|
||||
|
||||
if (assert)
|
||||
regvalue |= bitmask;
|
||||
else
|
||||
regvalue &= ~bitmask;
|
||||
WRITE4(sc, offset, regvalue);
|
||||
|
||||
mtx_unlock(&sc->mtx);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
jh7110_reset_is_asserted(device_t dev, intptr_t id, bool *reset)
|
||||
{
|
||||
struct jh7110_clkgen_softc *sc;
|
||||
uint32_t regvalue, offset, bitmask;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
offset = sc->reset_status_offset + id / 32 * 4;
|
||||
|
||||
mtx_lock(&sc->mtx);
|
||||
|
||||
regvalue = READ4(sc, offset);
|
||||
bitmask = 1UL << id % 32;
|
||||
|
||||
mtx_unlock(&sc->mtx);
|
||||
|
||||
*reset = (regvalue & bitmask) == 0;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Clock functions */
|
||||
|
||||
static int
|
||||
jh7110_clk_init(struct clknode *clk, device_t dev)
|
||||
{
|
||||
struct jh7110_clkgen_softc *sc;
|
||||
struct jh7110_clk_sc *sc_clk;
|
||||
uint32_t reg;
|
||||
int idx = 0;
|
||||
|
||||
sc = device_get_softc(clknode_get_device(clk));
|
||||
sc_clk = clknode_get_softc(clk);
|
||||
|
||||
if (sc_clk->flags & JH7110_CLK_HAS_MUX) {
|
||||
DEVICE_LOCK(clk);
|
||||
reg = READ4(sc, sc_clk->offset);
|
||||
DEVICE_UNLOCK(clk);
|
||||
idx = (reg & JH7110_MUX_MASK) >> JH7110_MUX_SHIFT;
|
||||
}
|
||||
|
||||
clknode_init_parent_idx(clk, idx);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
jh7110_clk_set_gate(struct clknode *clk, bool enable)
|
||||
{
|
||||
struct jh7110_clkgen_softc *sc;
|
||||
struct jh7110_clk_sc *sc_clk;
|
||||
uint32_t reg;
|
||||
|
||||
sc = device_get_softc(clknode_get_device(clk));
|
||||
sc_clk = clknode_get_softc(clk);
|
||||
|
||||
if ((sc_clk->flags & JH7110_CLK_HAS_GATE) == 0)
|
||||
return (0);
|
||||
|
||||
DEVICE_LOCK(clk);
|
||||
|
||||
reg = READ4(sc, sc_clk->offset);
|
||||
if (enable)
|
||||
reg |= (1 << JH7110_ENABLE_SHIFT);
|
||||
else
|
||||
reg &= ~(1 << JH7110_ENABLE_SHIFT);
|
||||
WRITE4(sc, sc_clk->offset, reg);
|
||||
|
||||
DEVICE_UNLOCK(clk);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
jh7110_clk_set_mux(struct clknode *clk, int idx)
|
||||
{
|
||||
struct jh7110_clkgen_softc *sc;
|
||||
struct jh7110_clk_sc *sc_clk;
|
||||
uint32_t reg;
|
||||
|
||||
sc = device_get_softc(clknode_get_device(clk));
|
||||
sc_clk = clknode_get_softc(clk);
|
||||
|
||||
if ((sc_clk->flags & JH7110_CLK_HAS_MUX) == 0)
|
||||
return (ENXIO);
|
||||
|
||||
/* Checking index size */
|
||||
if ((idx & (JH7110_MUX_MASK >> JH7110_MUX_SHIFT)) != idx)
|
||||
return (EINVAL);
|
||||
|
||||
DEVICE_LOCK(clk);
|
||||
|
||||
reg = READ4(sc, sc_clk->offset) & ~JH7110_MUX_MASK;
|
||||
reg |= idx << JH7110_MUX_SHIFT;
|
||||
WRITE4(sc, sc_clk->offset, reg);
|
||||
|
||||
DEVICE_UNLOCK(clk);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
jh7110_clk_recalc_freq(struct clknode *clk, uint64_t *freq)
|
||||
{
|
||||
struct jh7110_clkgen_softc *sc;
|
||||
struct jh7110_clk_sc *sc_clk;
|
||||
uint32_t divisor;
|
||||
|
||||
sc = device_get_softc(clknode_get_device(clk));
|
||||
sc_clk = clknode_get_softc(clk);
|
||||
|
||||
/* Returning error here causes panic */
|
||||
if ((sc_clk->flags & JH7110_CLK_HAS_DIV) == 0)
|
||||
return (0);
|
||||
|
||||
DEVICE_LOCK(clk);
|
||||
|
||||
divisor = READ4(sc, sc_clk->offset) & JH7110_DIV_MASK;
|
||||
|
||||
DEVICE_UNLOCK(clk);
|
||||
|
||||
if (divisor)
|
||||
*freq = *freq / divisor;
|
||||
else
|
||||
*freq = 0;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
jh7110_clk_set_freq(struct clknode *clk, uint64_t fin, uint64_t *fout,
|
||||
int flags, int *done)
|
||||
{
|
||||
struct jh7110_clkgen_softc *sc;
|
||||
struct jh7110_clk_sc *sc_clk;
|
||||
uint32_t divisor;
|
||||
|
||||
sc = device_get_softc(clknode_get_device(clk));
|
||||
sc_clk = clknode_get_softc(clk);
|
||||
|
||||
if ((sc_clk->flags & JH7110_CLK_HAS_DIV) == 0)
|
||||
return (0);
|
||||
|
||||
divisor = MIN(MAX(DIV_ROUND_CLOSEST(fin, *fout), 1UL), sc_clk->d_max);
|
||||
|
||||
if (flags & CLK_SET_DRYRUN)
|
||||
goto done;
|
||||
|
||||
DEVICE_LOCK(clk);
|
||||
|
||||
divisor |= READ4(sc, sc_clk->offset) & ~JH7110_DIV_MASK;
|
||||
WRITE4(sc, sc_clk->offset, divisor);
|
||||
|
||||
DEVICE_UNLOCK(clk);
|
||||
|
||||
done:
|
||||
*fout = divisor;
|
||||
*done = 1;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static clknode_method_t jh7110_clknode_methods[] = {
|
||||
/* Device interface */
|
||||
CLKNODEMETHOD(clknode_init, jh7110_clk_init),
|
||||
CLKNODEMETHOD(clknode_set_gate, jh7110_clk_set_gate),
|
||||
CLKNODEMETHOD(clknode_set_mux, jh7110_clk_set_mux),
|
||||
CLKNODEMETHOD(clknode_recalc_freq, jh7110_clk_recalc_freq),
|
||||
CLKNODEMETHOD(clknode_set_freq, jh7110_clk_set_freq),
|
||||
CLKNODEMETHOD_END
|
||||
};
|
||||
|
||||
DEFINE_CLASS_1(jh7110_clknode, jh7110_clknode_class, jh7110_clknode_methods,
|
||||
sizeof(struct jh7110_clk_sc), clknode_class);
|
||||
|
||||
int
|
||||
jh7110_clk_register(struct clkdom *clkdom, const struct jh7110_clk_def *clkdef)
|
||||
{
|
||||
struct clknode *clk;
|
||||
struct jh7110_clk_sc *sc;
|
||||
|
||||
clk = clknode_create(clkdom, &jh7110_clknode_class, &clkdef->clkdef);
|
||||
if (clk == NULL)
|
||||
return (-1);
|
||||
|
||||
sc = clknode_get_softc(clk);
|
||||
|
||||
sc->offset = clkdef->clkdef.id * REG_SIZE;
|
||||
|
||||
sc->flags = clkdef->flags;
|
||||
sc->id = clkdef->clkdef.id;
|
||||
sc->d_max = clkdef->d_max;
|
||||
|
||||
clknode_register(clkdom, clk);
|
||||
|
||||
return (0);
|
||||
}
|
|
@ -1,72 +0,0 @@
|
|||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2024 Jari Sihvola <jsihv@gmx.com>
|
||||
*/
|
||||
|
||||
#ifndef _JH7110_CLK_H_
|
||||
#define _JH7110_CLK_H_
|
||||
|
||||
#include <dev/clk/clk.h>
|
||||
|
||||
#define JH7110_CLK_HAS_GATE 0x01
|
||||
#define JH7110_CLK_HAS_MUX 0x02
|
||||
#define JH7110_CLK_HAS_DIV 0x04
|
||||
#define JH7110_CLK_HAS_INV 0x08
|
||||
|
||||
#define AONCRG_RESET_SELECTOR 0x38
|
||||
#define AONCRG_RESET_STATUS 0x3c
|
||||
#define STGCRG_RESET_SELECTOR 0x74
|
||||
#define STGCRG_RESET_STATUS 0x78
|
||||
#define SYSCRG_RESET_SELECTOR 0x2f8
|
||||
#define SYSCRG_RESET_STATUS 0x308
|
||||
|
||||
struct jh7110_clkgen_softc {
|
||||
struct mtx mtx;
|
||||
struct clkdom *clkdom;
|
||||
struct resource *mem_res;
|
||||
uint32_t reset_status_offset;
|
||||
uint32_t reset_selector_offset;
|
||||
};
|
||||
|
||||
struct jh7110_clk_def {
|
||||
struct clknode_init_def clkdef;
|
||||
uint32_t offset;
|
||||
uint32_t flags;
|
||||
uint64_t d_max;
|
||||
};
|
||||
|
||||
#define JH7110_CLK(_idx, _name, _pn, _d_max, _flags) \
|
||||
{ \
|
||||
.clkdef.id = _idx, \
|
||||
.clkdef.name = _name, \
|
||||
.clkdef.parent_names = _pn, \
|
||||
.clkdef.parent_cnt = nitems(_pn), \
|
||||
.clkdef.flags = CLK_NODE_STATIC_STRINGS, \
|
||||
.flags = _flags, \
|
||||
.d_max = _d_max, \
|
||||
}
|
||||
|
||||
#define JH7110_GATE(_idx, _name, _pn) \
|
||||
JH7110_CLK(_idx, _name, _pn, 0, JH7110_CLK_HAS_GATE)
|
||||
#define JH7110_MUX(_idx, _name, _pn) \
|
||||
JH7110_CLK(_idx, _name, _pn, 0, JH7110_CLK_HAS_MUX)
|
||||
#define JH7110_DIV(_idx, _name, _pn, _d_max) \
|
||||
JH7110_CLK(_idx, _name, _pn, _d_max, JH7110_CLK_HAS_DIV)
|
||||
#define JH7110_GATEMUX(_idx, _name, _pn) \
|
||||
JH7110_CLK(_idx, _name, _pn, 0, JH7110_CLK_HAS_GATE | \
|
||||
JH7110_CLK_HAS_MUX)
|
||||
#define JH7110_GATEDIV(_idx, _name, _pn, _d_max) \
|
||||
JH7110_CLK(_idx, _name, _pn, _d_max, JH7110_CLK_HAS_GATE | \
|
||||
JH7110_CLK_HAS_DIV)
|
||||
#define JH7110_INV(_idx, _name, _pn) \
|
||||
JH7110_CLK(_idx, _name, _pn, 0, JH7110_CLK_HAS_INV)
|
||||
|
||||
int jh7110_clk_register(struct clkdom *clkdom,
|
||||
const struct jh7110_clk_def *clkdef);
|
||||
int jh7110_ofw_map(struct clkdom *clkdom, uint32_t ncells, phandle_t *cells,
|
||||
struct clknode **clk);
|
||||
int jh7110_reset_is_asserted(device_t dev, intptr_t id, bool *reset);
|
||||
int jh7110_reset_assert(device_t dev, intptr_t id, bool assert);
|
||||
|
||||
#endif /* _JH7110_CLK_H_ */
|
|
@ -1,168 +0,0 @@
|
|||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright 2016 Michal Meloun <mmel@FreeBSD.org>
|
||||
* Copyright (c) 2020 Oskar Holmlund <oskar.holmlund@ohdata.se>
|
||||
* Copyright (c) 2024 Jari Sihvola <jsihv@gmx.com>
|
||||
*/
|
||||
|
||||
/* Clocks for JH7110 AON group. PLL driver must be attached before this. */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/module.h>
|
||||
#include <sys/mutex.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/rman.h>
|
||||
#include <machine/bus.h>
|
||||
|
||||
#include <dev/fdt/simplebus.h>
|
||||
#include <dev/hwreset/hwreset.h>
|
||||
#include <dev/ofw/ofw_bus.h>
|
||||
#include <dev/ofw/ofw_bus_subr.h>
|
||||
|
||||
#include <dev/clk/clk.h>
|
||||
#include <dev/clk/starfive/jh7110_clk.h>
|
||||
|
||||
#include <dt-bindings/clock/starfive,jh7110-crg.h>
|
||||
|
||||
#include "clkdev_if.h"
|
||||
#include "hwreset_if.h"
|
||||
|
||||
static struct ofw_compat_data compat_data[] = {
|
||||
{ "starfive,jh7110-aoncrg", 1 },
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
static struct resource_spec res_spec[] = {
|
||||
{ SYS_RES_MEMORY, 0, RF_ACTIVE | RF_SHAREABLE },
|
||||
RESOURCE_SPEC_END
|
||||
};
|
||||
|
||||
/* parents */
|
||||
static const char *gmac0_axi_p[] = { "stg_axiahb" };
|
||||
static const char *gmac0_ahb_p[] = { "stg_axiahb" };
|
||||
static const char *gmac0_tx_inv_p[] = { "gmac0_tx" };
|
||||
static const char *gmac0_tx_p[] = { "gmac0_gtxclk", "gmac0_rmii_rtx" };
|
||||
static const char *gmac0_rmii_rtx_p[] = { "gmac0_rmii_refin" };
|
||||
|
||||
/* AON clocks */
|
||||
static const struct jh7110_clk_def aon_clks[] = {
|
||||
JH7110_GATE(JH7110_AONCLK_GMAC0_AXI, "gmac0_axi", gmac0_axi_p),
|
||||
JH7110_GATE(JH7110_AONCLK_GMAC0_AHB, "gmac0_ahb", gmac0_ahb_p),
|
||||
JH7110_GATEMUX(JH7110_AONCLK_GMAC0_TX, "gmac0_tx", gmac0_tx_p),
|
||||
JH7110_INV(JH7110_AONCLK_GMAC0_TX_INV, "gmac0_tx_inv", gmac0_tx_inv_p),
|
||||
JH7110_DIV(JH7110_AONCLK_GMAC0_RMII_RTX, "gmac0_rmii_rtx",
|
||||
gmac0_rmii_rtx_p, 30),
|
||||
};
|
||||
|
||||
static int
|
||||
jh7110_clk_aon_probe(device_t dev)
|
||||
{
|
||||
if (!ofw_bus_status_okay(dev))
|
||||
return (ENXIO);
|
||||
|
||||
if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
|
||||
return (ENXIO);
|
||||
|
||||
device_set_desc(dev, "StarFive JH7110 AON clock generator");
|
||||
|
||||
return (BUS_PROBE_DEFAULT);
|
||||
}
|
||||
|
||||
static int
|
||||
jh7110_clk_aon_attach(device_t dev)
|
||||
{
|
||||
struct jh7110_clkgen_softc *sc;
|
||||
int err;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
sc->reset_status_offset = AONCRG_RESET_STATUS;
|
||||
sc->reset_selector_offset = AONCRG_RESET_SELECTOR;
|
||||
|
||||
mtx_init(&sc->mtx, device_get_nameunit(dev), NULL, MTX_DEF);
|
||||
|
||||
err = bus_alloc_resources(dev, res_spec, &sc->mem_res);
|
||||
if (err != 0) {
|
||||
device_printf(dev, "Couldn't allocate resources, error %d\n",
|
||||
err);
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
sc->clkdom = clkdom_create(dev);
|
||||
if (sc->clkdom == NULL) {
|
||||
device_printf(dev, "Couldn't create clkdom, error %d\n", err);
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
for (int i = 0; i < nitems(aon_clks); i++) {
|
||||
err = jh7110_clk_register(sc->clkdom, &aon_clks[i]);
|
||||
if (err != 0) {
|
||||
device_printf(dev,
|
||||
"Couldn't register clk %s, error %d\n",
|
||||
aon_clks[i].clkdef.name, err);
|
||||
return (ENXIO);
|
||||
}
|
||||
}
|
||||
|
||||
if (clkdom_finit(sc->clkdom) != 0)
|
||||
panic("Cannot finalize clkdom initialization\n");
|
||||
|
||||
if (bootverbose)
|
||||
clkdom_dump(sc->clkdom);
|
||||
|
||||
hwreset_register_ofw_provider(dev);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
jh7110_clk_aon_device_lock(device_t dev)
|
||||
{
|
||||
struct jh7110_clkgen_softc *sc;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
mtx_lock(&sc->mtx);
|
||||
}
|
||||
|
||||
static void
|
||||
jh7110_clk_aon_device_unlock(device_t dev)
|
||||
{
|
||||
struct jh7110_clkgen_softc *sc;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
mtx_unlock(&sc->mtx);
|
||||
}
|
||||
|
||||
static int
|
||||
jh7110_clk_aon_detach(device_t dev)
|
||||
{
|
||||
/* Detach not supported */
|
||||
return (EBUSY);
|
||||
}
|
||||
|
||||
static device_method_t jh7110_clk_aon_methods[] = {
|
||||
/* Device interface */
|
||||
DEVMETHOD(device_probe, jh7110_clk_aon_probe),
|
||||
DEVMETHOD(device_attach, jh7110_clk_aon_attach),
|
||||
DEVMETHOD(device_detach, jh7110_clk_aon_detach),
|
||||
|
||||
/* clkdev interface */
|
||||
DEVMETHOD(clkdev_device_lock, jh7110_clk_aon_device_lock),
|
||||
DEVMETHOD(clkdev_device_unlock, jh7110_clk_aon_device_unlock),
|
||||
|
||||
/* Reset interface */
|
||||
DEVMETHOD(hwreset_assert, jh7110_reset_assert),
|
||||
DEVMETHOD(hwreset_is_asserted, jh7110_reset_is_asserted),
|
||||
|
||||
DEVMETHOD_END
|
||||
};
|
||||
|
||||
DEFINE_CLASS_0(jh7110_aon, jh7110_aon_driver, jh7110_clk_aon_methods,
|
||||
sizeof(struct jh7110_clkgen_softc));
|
||||
EARLY_DRIVER_MODULE(jh7110_aon, simplebus, jh7110_aon_driver, 0, 0,
|
||||
BUS_PASS_BUS + BUS_PASS_ORDER_LATE);
|
||||
MODULE_VERSION(jh7110_aon, 1);
|
|
@ -1,386 +0,0 @@
|
|||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2024 Jari Sihvola <jsihv@gmx.com>
|
||||
* Copyright (c) 2024 The FreeBSD Foundation
|
||||
*
|
||||
* Portions of this software were developed by Mitchell Horne
|
||||
* <mhorne@FreeBSD.org> under sponsorship from the FreeBSD Foundation.
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/module.h>
|
||||
#include <sys/mutex.h>
|
||||
|
||||
#include <machine/bus.h>
|
||||
|
||||
#include <dev/fdt/simplebus.h>
|
||||
#include <dev/ofw/ofw_bus.h>
|
||||
#include <dev/ofw/ofw_bus_subr.h>
|
||||
|
||||
#include <dev/clk/clk.h>
|
||||
#include <dev/clk/starfive/jh7110_clk.h>
|
||||
#include <dev/clk/starfive/jh7110_clk_pll.h>
|
||||
#include <dev/syscon/syscon.h>
|
||||
|
||||
#include <dt-bindings/clock/starfive,jh7110-crg.h>
|
||||
|
||||
#include "clkdev_if.h"
|
||||
#include "syscon_if.h"
|
||||
|
||||
#define JH7110_SYS_SYSCON_SYSCFG24 0x18
|
||||
#define JH7110_SYS_SYSCON_SYSCFG28 0x1c
|
||||
#define JH7110_SYS_SYSCON_SYSCFG32 0x20
|
||||
#define JH7110_SYS_SYSCON_SYSCFG36 0x24
|
||||
#define JH7110_SYS_SYSCON_SYSCFG40 0x28
|
||||
#define JH7110_SYS_SYSCON_SYSCFG44 0x2c
|
||||
#define JH7110_SYS_SYSCON_SYSCFG48 0x30
|
||||
#define JH7110_SYS_SYSCON_SYSCFG52 0x34
|
||||
|
||||
#define DEVICE_LOCK(_clk) \
|
||||
CLKDEV_DEVICE_LOCK(clknode_get_device(_clk))
|
||||
#define DEVICE_UNLOCK(_clk) \
|
||||
CLKDEV_DEVICE_UNLOCK(clknode_get_device(_clk))
|
||||
|
||||
#define PLL_MASK_FILL(sc, id) \
|
||||
do { \
|
||||
sc->dacpd_mask = PLL## id ##_DACPD_MASK; \
|
||||
sc->dsmpd_mask = PLL## id ##_DSMPD_MASK; \
|
||||
sc->fbdiv_mask = PLL## id ##_FBDIV_MASK; \
|
||||
sc->frac_mask = PLL## id ##_FRAC_MASK; \
|
||||
sc->prediv_mask = PLL## id ##_PREDIV_MASK; \
|
||||
sc->postdiv1_mask = PLL## id ##_POSTDIV1_MASK; \
|
||||
} while (0)
|
||||
|
||||
#define PLL_SHIFT_FILL(sc, id) \
|
||||
do { \
|
||||
sc->dacpd_shift = PLL## id ##_DACPD_SHIFT; \
|
||||
sc->dsmpd_shift = PLL## id ##_DSMPD_SHIFT; \
|
||||
sc->fbdiv_shift = PLL## id ##_FBDIV_SHIFT; \
|
||||
sc->frac_shift = PLL## id ##_FRAC_SHIFT; \
|
||||
sc->prediv_shift = PLL## id ##_PREDIV_SHIFT; \
|
||||
sc->postdiv1_shift = PLL## id ##_POSTDIV1_SHIFT; \
|
||||
} while (0)
|
||||
|
||||
struct jh7110_clk_pll_softc {
|
||||
struct mtx mtx;
|
||||
struct clkdom *clkdom;
|
||||
struct syscon *syscon;
|
||||
};
|
||||
|
||||
struct jh7110_pll_clknode_softc {
|
||||
uint32_t dacpd_offset;
|
||||
uint32_t dsmpd_offset;
|
||||
uint32_t fbdiv_offset;
|
||||
uint32_t frac_offset;
|
||||
uint32_t prediv_offset;
|
||||
uint32_t postdiv1_offset;
|
||||
|
||||
uint32_t dacpd_mask;
|
||||
uint32_t dsmpd_mask;
|
||||
uint32_t fbdiv_mask;
|
||||
uint32_t frac_mask;
|
||||
uint32_t prediv_mask;
|
||||
uint32_t postdiv1_mask;
|
||||
|
||||
uint32_t dacpd_shift;
|
||||
uint32_t dsmpd_shift;
|
||||
uint32_t fbdiv_shift;
|
||||
uint32_t frac_shift;
|
||||
uint32_t prediv_shift;
|
||||
uint32_t postdiv1_shift;
|
||||
|
||||
const struct jh7110_pll_syscon_value *syscon_arr;
|
||||
int syscon_nitems;
|
||||
};
|
||||
|
||||
static const char *pll_parents[] = { "osc" };
|
||||
|
||||
static struct jh7110_clk_def pll_out_clks[] = {
|
||||
{
|
||||
.clkdef.id = JH7110_PLLCLK_PLL0_OUT,
|
||||
.clkdef.name = "pll0_out",
|
||||
.clkdef.parent_names = pll_parents,
|
||||
.clkdef.parent_cnt = nitems(pll_parents),
|
||||
.clkdef.flags = CLK_NODE_STATIC_STRINGS,
|
||||
},
|
||||
{
|
||||
.clkdef.id = JH7110_PLLCLK_PLL1_OUT,
|
||||
.clkdef.name = "pll1_out",
|
||||
.clkdef.parent_names = pll_parents,
|
||||
.clkdef.parent_cnt = nitems(pll_parents),
|
||||
.clkdef.flags = CLK_NODE_STATIC_STRINGS,
|
||||
},
|
||||
{
|
||||
.clkdef.id = JH7110_PLLCLK_PLL2_OUT,
|
||||
.clkdef.name = "pll2_out",
|
||||
.clkdef.parent_names = pll_parents,
|
||||
.clkdef.parent_cnt = nitems(pll_parents),
|
||||
.clkdef.flags = CLK_NODE_STATIC_STRINGS,
|
||||
},
|
||||
};
|
||||
|
||||
static int jh7110_clk_pll_register(struct clkdom *clkdom,
|
||||
struct jh7110_clk_def *clkdef);
|
||||
|
||||
static int
|
||||
jh7110_clk_pll_recalc_freq(struct clknode *clk, uint64_t *freq)
|
||||
{
|
||||
struct jh7110_clk_pll_softc *sc;
|
||||
struct jh7110_pll_clknode_softc *clk_sc;
|
||||
uint32_t dacpd, dsmpd, fbdiv, prediv, postdiv1;
|
||||
uint64_t frac, fcal = 0;
|
||||
|
||||
sc = device_get_softc(clknode_get_device(clk));
|
||||
clk_sc = clknode_get_softc(clk);
|
||||
|
||||
DEVICE_LOCK(clk);
|
||||
|
||||
dacpd = (SYSCON_READ_4(sc->syscon, clk_sc->dacpd_offset) & clk_sc->dacpd_mask) >>
|
||||
clk_sc->dacpd_shift;
|
||||
dsmpd = (SYSCON_READ_4(sc->syscon, clk_sc->dsmpd_offset) & clk_sc->dsmpd_mask) >>
|
||||
clk_sc->dsmpd_shift;
|
||||
fbdiv = (SYSCON_READ_4(sc->syscon, clk_sc->fbdiv_offset) & clk_sc->fbdiv_mask) >>
|
||||
clk_sc->fbdiv_shift;
|
||||
prediv = (SYSCON_READ_4(sc->syscon, clk_sc->prediv_offset) & clk_sc->prediv_mask) >>
|
||||
clk_sc->prediv_shift;
|
||||
postdiv1 = (SYSCON_READ_4(sc->syscon, clk_sc->postdiv1_offset) &
|
||||
clk_sc->postdiv1_mask) >> clk_sc->postdiv1_shift;
|
||||
frac = (SYSCON_READ_4(sc->syscon, clk_sc->frac_offset) & clk_sc->frac_mask) >>
|
||||
clk_sc->frac_shift;
|
||||
|
||||
DEVICE_UNLOCK(clk);
|
||||
|
||||
/* dacpd and dsmpd both being 0 entails Fraction Multiple Mode */
|
||||
if (dacpd == 0 && dsmpd == 0)
|
||||
fcal = frac * FRAC_PATR_SIZE / (1 << 24);
|
||||
|
||||
*freq = *freq / FRAC_PATR_SIZE * (fbdiv * FRAC_PATR_SIZE + fcal) /
|
||||
prediv / (1 << postdiv1);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
jh7110_clk_pll_set_freq(struct clknode *clk, uint64_t fin, uint64_t *fout,
|
||||
int flags, int *done)
|
||||
{
|
||||
struct jh7110_clk_pll_softc *sc;
|
||||
struct jh7110_pll_clknode_softc *clk_sc;
|
||||
const struct jh7110_pll_syscon_value *syscon_val = NULL;
|
||||
|
||||
sc = device_get_softc(clknode_get_device(clk));
|
||||
clk_sc = clknode_get_softc(clk);
|
||||
|
||||
for (int i = 0; i != clk_sc->syscon_nitems; i++) {
|
||||
if (*fout == clk_sc->syscon_arr[i].freq) {
|
||||
syscon_val = &clk_sc->syscon_arr[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (syscon_val == NULL) {
|
||||
printf("%s: tried to set an unknown frequency %ju for %s\n",
|
||||
__func__, *fout, clknode_get_name(clk));
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
if ((flags & CLK_SET_DRYRUN) != 0) {
|
||||
*done = 1;
|
||||
return (0);
|
||||
}
|
||||
|
||||
DEVICE_LOCK(clk);
|
||||
|
||||
SYSCON_MODIFY_4(sc->syscon, clk_sc->dacpd_offset, clk_sc->dacpd_mask,
|
||||
syscon_val->dacpd << clk_sc->dacpd_shift & clk_sc->dacpd_mask);
|
||||
SYSCON_MODIFY_4(sc->syscon, clk_sc->dsmpd_offset, clk_sc->dsmpd_mask,
|
||||
syscon_val->dsmpd << clk_sc->dsmpd_shift & clk_sc->dsmpd_mask);
|
||||
SYSCON_MODIFY_4(sc->syscon, clk_sc->prediv_offset, clk_sc->prediv_mask,
|
||||
syscon_val->prediv << clk_sc->prediv_shift & clk_sc->prediv_mask);
|
||||
SYSCON_MODIFY_4(sc->syscon, clk_sc->fbdiv_offset, clk_sc->fbdiv_mask,
|
||||
syscon_val->fbdiv << clk_sc->fbdiv_shift & clk_sc->fbdiv_mask);
|
||||
SYSCON_MODIFY_4(sc->syscon, clk_sc->postdiv1_offset,
|
||||
clk_sc->postdiv1_mask, (syscon_val->postdiv1 >> 1) <<
|
||||
clk_sc->postdiv1_shift & clk_sc->postdiv1_mask);
|
||||
|
||||
if (!syscon_val->dacpd && !syscon_val->dsmpd) {
|
||||
SYSCON_MODIFY_4(sc->syscon, clk_sc->frac_offset, clk_sc->frac_mask,
|
||||
syscon_val->frac << clk_sc->frac_shift & clk_sc->frac_mask);
|
||||
}
|
||||
|
||||
DEVICE_UNLOCK(clk);
|
||||
|
||||
*done = 1;
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
jh7110_clk_pll_init(struct clknode *clk, device_t dev)
|
||||
{
|
||||
clknode_init_parent_idx(clk, 0);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
jh7110_clk_pll_probe(device_t dev)
|
||||
{
|
||||
if (!ofw_bus_status_okay(dev))
|
||||
return (ENXIO);
|
||||
|
||||
if (!ofw_bus_is_compatible(dev, "starfive,jh7110-pll"))
|
||||
return (ENXIO);
|
||||
|
||||
device_set_desc(dev, "StarFive JH7110 PLL clock generator");
|
||||
|
||||
return (BUS_PROBE_DEFAULT);
|
||||
}
|
||||
|
||||
static int
|
||||
jh7110_clk_pll_attach(device_t dev)
|
||||
{
|
||||
struct jh7110_clk_pll_softc *sc;
|
||||
int error;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
mtx_init(&sc->mtx, device_get_nameunit(dev), NULL, MTX_DEF);
|
||||
|
||||
sc->clkdom = clkdom_create(dev);
|
||||
if (sc->clkdom == NULL) {
|
||||
device_printf(dev, "Couldn't create clkdom\n");
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
error = syscon_get_by_ofw_node(dev, OF_parent(ofw_bus_get_node(dev)),
|
||||
&sc->syscon);
|
||||
if (error != 0) {
|
||||
device_printf(dev, "Couldn't get syscon handle of parent\n");
|
||||
return (error);
|
||||
}
|
||||
|
||||
for (int i = 0; i < nitems(pll_out_clks); i++) {
|
||||
error = jh7110_clk_pll_register(sc->clkdom, &pll_out_clks[i]);
|
||||
if (error != 0)
|
||||
device_printf(dev, "Couldn't register clock %s: %d\n",
|
||||
pll_out_clks[i].clkdef.name, error);
|
||||
}
|
||||
|
||||
error = clkdom_finit(sc->clkdom);
|
||||
if (error != 0) {
|
||||
device_printf(dev, "clkdom_finit() returned %d\n", error);
|
||||
}
|
||||
|
||||
if (bootverbose)
|
||||
clkdom_dump(sc->clkdom);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
jh7110_clk_pll_device_lock(device_t dev)
|
||||
{
|
||||
struct jh7110_clk_pll_softc *sc;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
mtx_lock(&sc->mtx);
|
||||
}
|
||||
|
||||
static void
|
||||
jh7110_clk_pll_device_unlock(device_t dev)
|
||||
{
|
||||
struct jh7110_clk_pll_softc *sc;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
mtx_unlock(&sc->mtx);
|
||||
}
|
||||
|
||||
static clknode_method_t jh7110_pllnode_methods[] = {
|
||||
/* Device interface */
|
||||
CLKNODEMETHOD(clknode_init, jh7110_clk_pll_init),
|
||||
CLKNODEMETHOD(clknode_recalc_freq, jh7110_clk_pll_recalc_freq),
|
||||
CLKNODEMETHOD(clknode_set_freq, jh7110_clk_pll_set_freq),
|
||||
|
||||
CLKNODEMETHOD_END
|
||||
};
|
||||
|
||||
static device_method_t jh7110_clk_pll_methods[] = {
|
||||
/* Device interface */
|
||||
DEVMETHOD(device_probe, jh7110_clk_pll_probe),
|
||||
DEVMETHOD(device_attach, jh7110_clk_pll_attach),
|
||||
|
||||
/* clkdev interface */
|
||||
DEVMETHOD(clkdev_device_lock, jh7110_clk_pll_device_lock),
|
||||
DEVMETHOD(clkdev_device_unlock, jh7110_clk_pll_device_unlock),
|
||||
|
||||
DEVMETHOD_END
|
||||
};
|
||||
|
||||
DEFINE_CLASS_1(jh7110_pllnode, jh7110_pllnode_class, jh7110_pllnode_methods,
|
||||
sizeof(struct jh7110_pll_clknode_softc), clknode_class);
|
||||
DEFINE_CLASS_0(jh7110_clk_pll, jh7110_clk_pll_driver, jh7110_clk_pll_methods,
|
||||
sizeof(struct jh7110_clk_pll_softc));
|
||||
EARLY_DRIVER_MODULE(jh7110_clk_pll, simplebus, jh7110_clk_pll_driver, 0, 0,
|
||||
BUS_PASS_BUS + BUS_PASS_ORDER_EARLY);
|
||||
MODULE_VERSION(jh7110_clk_pll, 1);
|
||||
|
||||
int
|
||||
jh7110_clk_pll_register(struct clkdom *clkdom, struct jh7110_clk_def *clkdef)
|
||||
{
|
||||
struct clknode *clk = NULL;
|
||||
struct jh7110_pll_clknode_softc *sc;
|
||||
|
||||
clk = clknode_create(clkdom, &jh7110_pllnode_class, &clkdef->clkdef);
|
||||
if (clk == NULL)
|
||||
return (1);
|
||||
|
||||
sc = clknode_get_softc(clk);
|
||||
|
||||
switch (clkdef->clkdef.id) {
|
||||
case JH7110_PLLCLK_PLL0_OUT:
|
||||
sc->syscon_arr = jh7110_pll0_syscon_freq;
|
||||
sc->syscon_nitems = nitems(jh7110_pll0_syscon_freq);
|
||||
PLL_MASK_FILL(sc, 0);
|
||||
PLL_SHIFT_FILL(sc, 0);
|
||||
sc->dacpd_offset = JH7110_SYS_SYSCON_SYSCFG24;
|
||||
sc->dsmpd_offset = JH7110_SYS_SYSCON_SYSCFG24;
|
||||
sc->fbdiv_offset = JH7110_SYS_SYSCON_SYSCFG28;
|
||||
sc->frac_offset = JH7110_SYS_SYSCON_SYSCFG32;
|
||||
sc->prediv_offset = JH7110_SYS_SYSCON_SYSCFG36;
|
||||
sc->postdiv1_offset = JH7110_SYS_SYSCON_SYSCFG32;
|
||||
break;
|
||||
case JH7110_PLLCLK_PLL1_OUT:
|
||||
sc->syscon_arr = jh7110_pll1_syscon_freq;
|
||||
sc->syscon_nitems = nitems(jh7110_pll1_syscon_freq);
|
||||
PLL_MASK_FILL(sc, 1);
|
||||
PLL_SHIFT_FILL(sc, 1);
|
||||
sc->dacpd_offset = JH7110_SYS_SYSCON_SYSCFG36;
|
||||
sc->dsmpd_offset = JH7110_SYS_SYSCON_SYSCFG36;
|
||||
sc->fbdiv_offset = JH7110_SYS_SYSCON_SYSCFG36;
|
||||
sc->frac_offset = JH7110_SYS_SYSCON_SYSCFG40;
|
||||
sc->prediv_offset = JH7110_SYS_SYSCON_SYSCFG44;
|
||||
sc->postdiv1_offset = JH7110_SYS_SYSCON_SYSCFG40;
|
||||
break;
|
||||
case JH7110_PLLCLK_PLL2_OUT:
|
||||
sc->syscon_arr = jh7110_pll2_syscon_freq;
|
||||
sc->syscon_nitems = nitems(jh7110_pll2_syscon_freq);
|
||||
PLL_MASK_FILL(sc, 2);
|
||||
PLL_SHIFT_FILL(sc, 2);
|
||||
sc->dacpd_offset = JH7110_SYS_SYSCON_SYSCFG44;
|
||||
sc->dsmpd_offset = JH7110_SYS_SYSCON_SYSCFG44;
|
||||
sc->fbdiv_offset = JH7110_SYS_SYSCON_SYSCFG44;
|
||||
sc->frac_offset = JH7110_SYS_SYSCON_SYSCFG48;
|
||||
sc->prediv_offset = JH7110_SYS_SYSCON_SYSCFG52;
|
||||
sc->postdiv1_offset = JH7110_SYS_SYSCON_SYSCFG48;
|
||||
break;
|
||||
default:
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
clknode_register(clkdom, clk);
|
||||
|
||||
return (0);
|
||||
}
|
|
@ -1,211 +0,0 @@
|
|||
/* SPDX-License-Identifier: MIT */
|
||||
/*
|
||||
* StarFive JH7110 PLL Clock Generator Driver
|
||||
*
|
||||
* Copyright (C) 2022 Xingyu Wu <xingyu.wu@starfivetech.com>
|
||||
*/
|
||||
|
||||
#define PLL0_DACPD_SHIFT 24
|
||||
#define PLL0_DACPD_MASK 0x1000000
|
||||
#define PLL_0_DACPD_SHIFT 24
|
||||
#define PLL_0_DACPD_MASK 0x1000000
|
||||
|
||||
#define PLL0_DSMPD_SHIFT 25
|
||||
#define PLL0_DSMPD_MASK 0x2000000
|
||||
#define PLL0_FBDIV_SHIFT 0
|
||||
#define PLL0_FBDIV_MASK 0xFFF
|
||||
#define PLL0_FRAC_SHIFT 0
|
||||
#define PLL0_FRAC_MASK 0xFFFFFF
|
||||
#define PLL0_POSTDIV1_SHIFT 28
|
||||
#define PLL0_POSTDIV1_MASK 0x30000000
|
||||
#define PLL0_PREDIV_SHIFT 0
|
||||
#define PLL0_PREDIV_MASK 0x3F
|
||||
|
||||
#define PLL1_DACPD_SHIFT 15
|
||||
#define PLL1_DACPD_MASK 0x8000
|
||||
#define PLL1_DSMPD_SHIFT 16
|
||||
#define PLL1_DSMPD_MASK 0x10000
|
||||
#define PLL1_FBDIV_SHIFT 17
|
||||
#define PLL1_FBDIV_MASK 0x1FFE0000
|
||||
#define PLL1_FRAC_SHIFT 0
|
||||
#define PLL1_FRAC_MASK 0xFFFFFF
|
||||
#define PLL1_POSTDIV1_SHIFT 28
|
||||
#define PLL1_POSTDIV1_MASK 0x30000000
|
||||
#define PLL1_PREDIV_SHIFT 0
|
||||
#define PLL1_PREDIV_MASK 0x3F
|
||||
|
||||
#define PLL2_DACPD_SHIFT 15
|
||||
#define PLL2_DACPD_MASK 0x8000
|
||||
#define PLL2_DSMPD_SHIFT 16
|
||||
#define PLL2_DSMPD_MASK 0x10000
|
||||
#define PLL2_FBDIV_SHIFT 17
|
||||
#define PLL2_FBDIV_MASK 0x1FFE0000
|
||||
#define PLL2_FRAC_SHIFT 0
|
||||
#define PLL2_FRAC_MASK 0xFFFFFF
|
||||
#define PLL2_POSTDIV1_SHIFT 28
|
||||
#define PLL2_POSTDIV1_MASK 0x30000000
|
||||
#define PLL2_PREDIV_SHIFT 0
|
||||
#define PLL2_PREDIV_MASK 0x3F
|
||||
|
||||
#define FRAC_PATR_SIZE 1000
|
||||
|
||||
struct jh7110_pll_syscon_value {
|
||||
uint64_t freq;
|
||||
uint32_t prediv;
|
||||
uint32_t fbdiv;
|
||||
uint32_t postdiv1;
|
||||
uint32_t dacpd;
|
||||
uint32_t dsmpd;
|
||||
uint32_t frac;
|
||||
};
|
||||
|
||||
enum starfive_pll0_freq_value {
|
||||
PLL0_FREQ_375_VALUE = 375000000,
|
||||
PLL0_FREQ_500_VALUE = 500000000,
|
||||
PLL0_FREQ_625_VALUE = 625000000,
|
||||
PLL0_FREQ_750_VALUE = 750000000,
|
||||
PLL0_FREQ_875_VALUE = 875000000,
|
||||
PLL0_FREQ_1000_VALUE = 1000000000,
|
||||
PLL0_FREQ_1250_VALUE = 1250000000,
|
||||
PLL0_FREQ_1375_VALUE = 1375000000,
|
||||
PLL0_FREQ_1500_VALUE = 1500000000
|
||||
};
|
||||
|
||||
enum starfive_pll0_freq {
|
||||
PLL0_FREQ_375 = 0,
|
||||
PLL0_FREQ_500,
|
||||
PLL0_FREQ_625,
|
||||
PLL0_FREQ_750,
|
||||
PLL0_FREQ_875,
|
||||
PLL0_FREQ_1000,
|
||||
PLL0_FREQ_1250,
|
||||
PLL0_FREQ_1375,
|
||||
PLL0_FREQ_1500,
|
||||
PLL0_FREQ_MAX = PLL0_FREQ_1500
|
||||
};
|
||||
|
||||
enum starfive_pll1_freq_value {
|
||||
PLL1_FREQ_1066_VALUE = 1066000000,
|
||||
};
|
||||
|
||||
enum starfive_pll1_freq {
|
||||
PLL1_FREQ_1066 = 0,
|
||||
};
|
||||
|
||||
enum starfive_pll2_freq_value {
|
||||
PLL2_FREQ_1188_VALUE = 1188000000,
|
||||
PLL2_FREQ_12288_VALUE = 1228800000,
|
||||
};
|
||||
|
||||
enum starfive_pll2_freq {
|
||||
PLL2_FREQ_1188 = 0,
|
||||
PLL2_FREQ_12288,
|
||||
};
|
||||
|
||||
static const struct jh7110_pll_syscon_value
|
||||
jh7110_pll0_syscon_freq[] = {
|
||||
[PLL0_FREQ_375] = {
|
||||
.freq = PLL0_FREQ_375_VALUE,
|
||||
.prediv = 8,
|
||||
.fbdiv = 125,
|
||||
.postdiv1 = 1,
|
||||
.dacpd = 1,
|
||||
.dsmpd = 1,
|
||||
},
|
||||
[PLL0_FREQ_500] = {
|
||||
.freq = PLL0_FREQ_500_VALUE,
|
||||
.prediv = 6,
|
||||
.fbdiv = 125,
|
||||
.postdiv1 = 1,
|
||||
.dacpd = 1,
|
||||
.dsmpd = 1,
|
||||
},
|
||||
[PLL0_FREQ_625] = {
|
||||
.freq = PLL0_FREQ_625_VALUE,
|
||||
.prediv = 24,
|
||||
.fbdiv = 625,
|
||||
.postdiv1 = 1,
|
||||
.dacpd = 1,
|
||||
.dsmpd = 1,
|
||||
},
|
||||
[PLL0_FREQ_750] = {
|
||||
.freq = PLL0_FREQ_750_VALUE,
|
||||
.prediv = 4,
|
||||
.fbdiv = 125,
|
||||
.postdiv1 = 1,
|
||||
.dacpd = 1,
|
||||
.dsmpd = 1,
|
||||
},
|
||||
[PLL0_FREQ_875] = {
|
||||
.freq = PLL0_FREQ_875_VALUE,
|
||||
.prediv = 24,
|
||||
.fbdiv = 875,
|
||||
.postdiv1 = 1,
|
||||
.dacpd = 1,
|
||||
.dsmpd = 1,
|
||||
},
|
||||
[PLL0_FREQ_1000] = {
|
||||
.freq = PLL0_FREQ_1000_VALUE,
|
||||
.prediv = 3,
|
||||
.fbdiv = 125,
|
||||
.postdiv1 = 1,
|
||||
.dacpd = 1,
|
||||
.dsmpd = 1,
|
||||
},
|
||||
[PLL0_FREQ_1250] = {
|
||||
.freq = PLL0_FREQ_1250_VALUE,
|
||||
.prediv = 12,
|
||||
.fbdiv = 625,
|
||||
.postdiv1 = 1,
|
||||
.dacpd = 1,
|
||||
.dsmpd = 1,
|
||||
},
|
||||
[PLL0_FREQ_1375] = {
|
||||
.freq = PLL0_FREQ_1375_VALUE,
|
||||
.prediv = 24,
|
||||
.fbdiv = 1375,
|
||||
.postdiv1 = 1,
|
||||
.dacpd = 1,
|
||||
.dsmpd = 1,
|
||||
},
|
||||
[PLL0_FREQ_1500] = {
|
||||
.freq = PLL0_FREQ_1500_VALUE,
|
||||
.prediv = 2,
|
||||
.fbdiv = 125,
|
||||
.postdiv1 = 1,
|
||||
.dacpd = 1,
|
||||
.dsmpd = 1,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct jh7110_pll_syscon_value
|
||||
jh7110_pll1_syscon_freq[] = {
|
||||
[PLL1_FREQ_1066] = {
|
||||
.freq = PLL1_FREQ_1066_VALUE,
|
||||
.prediv = 12,
|
||||
.fbdiv = 533,
|
||||
.postdiv1 = 1,
|
||||
.dacpd = 1,
|
||||
.dsmpd = 1,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct jh7110_pll_syscon_value
|
||||
jh7110_pll2_syscon_freq[] = {
|
||||
[PLL2_FREQ_1188] = {
|
||||
.freq = PLL2_FREQ_1188_VALUE,
|
||||
.prediv = 2,
|
||||
.fbdiv = 99,
|
||||
.postdiv1 = 1,
|
||||
.dacpd = 1,
|
||||
.dsmpd = 1,
|
||||
},
|
||||
[PLL2_FREQ_12288] = {
|
||||
.freq = PLL2_FREQ_12288_VALUE,
|
||||
.prediv = 5,
|
||||
.fbdiv = 256,
|
||||
.postdiv1 = 1,
|
||||
.dacpd = 1,
|
||||
.dsmpd = 1,
|
||||
},
|
||||
};
|
|
@ -1,261 +0,0 @@
|
|||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright 2016 Michal Meloun <mmel@FreeBSD.org>
|
||||
* Copyright (c) 2020 Oskar Holmlund <oskar.holmlund@ohdata.se>
|
||||
* Copyright (c) 2022 Mitchell Horne <mhorne@FreeBSD.org>
|
||||
* Copyright (c) 2024 Jari Sihvola <jsihv@gmx.com>
|
||||
*/
|
||||
|
||||
/* Clocks for JH7110 SYS group. PLL driver must be attached before this. */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/module.h>
|
||||
#include <sys/mutex.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/rman.h>
|
||||
|
||||
#include <machine/bus.h>
|
||||
|
||||
#include <dev/fdt/simplebus.h>
|
||||
#include <dev/ofw/ofw_bus.h>
|
||||
#include <dev/ofw/ofw_bus_subr.h>
|
||||
|
||||
#include <dev/clk/clk.h>
|
||||
#include <dev/clk/starfive/jh7110_clk.h>
|
||||
#include <dev/hwreset/hwreset.h>
|
||||
|
||||
#include <dt-bindings/clock/starfive,jh7110-crg.h>
|
||||
|
||||
#include "clkdev_if.h"
|
||||
#include "hwreset_if.h"
|
||||
|
||||
static struct ofw_compat_data compat_data[] = {
|
||||
{ "starfive,jh7110-syscrg", 1 },
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
static struct resource_spec res_spec[] = {
|
||||
{ SYS_RES_MEMORY, 0, RF_ACTIVE | RF_SHAREABLE },
|
||||
RESOURCE_SPEC_END
|
||||
};
|
||||
|
||||
/* parents for non-pll SYS clocks */
|
||||
static const char *cpu_root_p[] = { "osc", "pll0_out" };
|
||||
static const char *cpu_core_p[] = { "cpu_root" };
|
||||
static const char *cpu_bus_p[] = { "cpu_core" };
|
||||
static const char *perh_root_p[] = { "pll0_out", "pll2_out" };
|
||||
static const char *bus_root_p[] = { "osc", "pll2_out" };
|
||||
|
||||
static const char *apb_bus_p[] = { "stg_axiahb" };
|
||||
static const char *apb0_p[] = { "apb_bus" };
|
||||
static const char *u0_sys_iomux_apb_p[] = { "apb_bus" };
|
||||
static const char *stg_axiahb_p[] = { "axi_cfg0" };
|
||||
static const char *ahb0_p[] = { "stg_axiahb" };
|
||||
static const char *axi_cfg0_p[] = { "bus_root" };
|
||||
|
||||
static const char *u0_dw_uart_clk_apb_p[] = { "apb0" };
|
||||
static const char *u0_dw_uart_clk_core_p[] = { "osc" };
|
||||
static const char *u0_dw_sdio_clk_ahb_p[] = { "ahb0" };
|
||||
static const char *u0_dw_sdio_clk_sdcard_p[] = { "axi_cfg0" };
|
||||
static const char *u1_dw_uart_clk_apb_p[] = { "apb0" };
|
||||
static const char *u1_dw_uart_clk_core_p[] = { "osc" };
|
||||
static const char *u1_dw_sdio_clk_ahb_p[] = { "ahb0" };
|
||||
static const char *u1_dw_sdio_clk_sdcard_p[] = { "axi_cfg0" };
|
||||
static const char *u2_dw_uart_clk_apb_p[] = { "apb0" };
|
||||
static const char *u2_dw_uart_clk_core_p[] = { "osc" };
|
||||
static const char *u3_dw_uart_clk_apb_p[] = { "apb0" };
|
||||
static const char *u3_dw_uart_clk_core_p[] = { "perh_root" };
|
||||
|
||||
static const char *gmac_src_p[] = { "pll0_out" };
|
||||
static const char *gmac_phy_p[] = { "gmac_src" };
|
||||
static const char *gmac0_gtxclk_p[] = { "pll0_out" };
|
||||
static const char *gmac0_ptp_p[] = { "gmac_src" };
|
||||
static const char *gmac0_gtxc_p[] = { "gmac0_gtxclk" };
|
||||
static const char *gmac1_gtxclk_p[] = { "pll0_out" };
|
||||
static const char *gmac1_gtxc_p[] = { "gmac1_gtxclk" };
|
||||
static const char *gmac1_rmii_rtx_p[] = { "gmac1_rmii_refin" };
|
||||
static const char *gmac1_axi_p[] = { "stg_axiahb" };
|
||||
static const char *gmac1_ahb_p[] = { "ahb0" };
|
||||
static const char *gmac1_ptp_p[] = { "gmac_src" };
|
||||
static const char *gmac1_tx_inv_p[] = { "gmac1_tx" };
|
||||
static const char *gmac1_tx_p[] = { "gmac1_gtxclk", "gmac1_rmii_rtx" };
|
||||
static const char *gmac1_rx_p[] = { "gmac1_rgmii_rxin", "gmac1_rmii_rtx" };
|
||||
static const char *gmac1_rx_inv_p[] = { "gmac1_rx" };
|
||||
|
||||
/* non-pll SYS clocks */
|
||||
static const struct jh7110_clk_def sys_clks[] = {
|
||||
JH7110_MUX(JH7110_SYSCLK_CPU_ROOT, "cpu_root", cpu_root_p),
|
||||
JH7110_DIV(JH7110_SYSCLK_CPU_CORE, "cpu_core", cpu_core_p, 7),
|
||||
JH7110_DIV(JH7110_SYSCLK_CPU_BUS, "cpu_bus", cpu_bus_p, 2),
|
||||
JH7110_GATEDIV(JH7110_SYSCLK_PERH_ROOT, "perh_root", perh_root_p, 2),
|
||||
JH7110_MUX(JH7110_SYSCLK_BUS_ROOT, "bus_root", bus_root_p),
|
||||
|
||||
JH7110_GATE(JH7110_SYSCLK_APB0, "apb0", apb0_p),
|
||||
JH7110_GATE(JH7110_SYSCLK_IOMUX_APB, "u0_sys_iomux_apb",
|
||||
u0_sys_iomux_apb_p),
|
||||
JH7110_GATE(JH7110_SYSCLK_UART0_APB, "u0_dw_uart_clk_apb",
|
||||
u0_dw_uart_clk_apb_p),
|
||||
JH7110_GATE(JH7110_SYSCLK_UART0_CORE, "u0_dw_uart_clk_core",
|
||||
u0_dw_uart_clk_core_p),
|
||||
JH7110_GATE(JH7110_SYSCLK_UART1_APB, "u1_dw_uart_clk_apb",
|
||||
u1_dw_uart_clk_apb_p),
|
||||
JH7110_GATE(JH7110_SYSCLK_UART1_CORE, "u1_dw_uart_clk_core",
|
||||
u1_dw_uart_clk_core_p),
|
||||
JH7110_GATE(JH7110_SYSCLK_UART2_APB, "u2_dw_uart_clk_apb",
|
||||
u2_dw_uart_clk_apb_p),
|
||||
JH7110_GATE(JH7110_SYSCLK_UART2_CORE, "u2_dw_uart_clk_core",
|
||||
u2_dw_uart_clk_core_p),
|
||||
JH7110_GATE(JH7110_SYSCLK_UART3_APB, "u3_dw_uart_clk_apb",
|
||||
u3_dw_uart_clk_apb_p),
|
||||
JH7110_GATE(JH7110_SYSCLK_UART3_CORE, "u3_dw_uart_clk_core",
|
||||
u3_dw_uart_clk_core_p),
|
||||
|
||||
JH7110_DIV(JH7110_SYSCLK_AXI_CFG0, "axi_cfg0", axi_cfg0_p, 3),
|
||||
JH7110_DIV(JH7110_SYSCLK_STG_AXIAHB, "stg_axiahb", stg_axiahb_p, 2),
|
||||
JH7110_GATE(JH7110_SYSCLK_AHB0, "ahb0", ahb0_p),
|
||||
JH7110_DIV(JH7110_SYSCLK_APB_BUS, "apb_bus", apb_bus_p, 8),
|
||||
|
||||
JH7110_GATE(JH7110_SYSCLK_SDIO0_AHB, "u0_dw_sdio_clk_ahb",
|
||||
u0_dw_sdio_clk_ahb_p),
|
||||
JH7110_GATE(JH7110_SYSCLK_SDIO1_AHB, "u1_dw_sdio_clk_ahb",
|
||||
u1_dw_sdio_clk_ahb_p),
|
||||
JH7110_GATEDIV(JH7110_SYSCLK_SDIO0_SDCARD, "u0_dw_sdio_clk_sdcard",
|
||||
u0_dw_sdio_clk_sdcard_p, 15),
|
||||
JH7110_GATEDIV(JH7110_SYSCLK_SDIO1_SDCARD, "u1_dw_sdio_clk_sdcard",
|
||||
u1_dw_sdio_clk_sdcard_p, 15),
|
||||
|
||||
JH7110_DIV(JH7110_SYSCLK_GMAC_SRC, "gmac_src", gmac_src_p, 7),
|
||||
JH7110_GATEDIV(JH7110_SYSCLK_GMAC0_GTXCLK, "gmac0_gtxclk",
|
||||
gmac0_gtxclk_p, 15),
|
||||
JH7110_GATEDIV(JH7110_SYSCLK_GMAC0_PTP, "gmac0_ptp", gmac0_ptp_p, 31),
|
||||
JH7110_GATEDIV(JH7110_SYSCLK_GMAC_PHY, "gmac_phy", gmac_phy_p, 31),
|
||||
JH7110_GATE(JH7110_SYSCLK_GMAC0_GTXC, "gmac0_gtxc", gmac0_gtxc_p),
|
||||
|
||||
JH7110_MUX(JH7110_SYSCLK_GMAC1_RX, "gmac1_rx", gmac1_rx_p),
|
||||
JH7110_INV(JH7110_SYSCLK_GMAC1_RX_INV, "gmac1_rx_inv", gmac1_rx_inv_p),
|
||||
JH7110_GATE(JH7110_SYSCLK_GMAC1_AHB, "gmac1_ahb", gmac1_ahb_p),
|
||||
JH7110_DIV(JH7110_SYSCLK_GMAC1_GTXCLK, "gmac1_gtxclk",
|
||||
gmac1_gtxclk_p, 15),
|
||||
JH7110_GATEMUX(JH7110_SYSCLK_GMAC1_TX, "gmac1_tx", gmac1_tx_p),
|
||||
JH7110_INV(JH7110_SYSCLK_GMAC1_TX_INV, "gmac1_tx_inv", gmac1_tx_inv_p),
|
||||
JH7110_GATEDIV(JH7110_SYSCLK_GMAC1_PTP, "gmac1_ptp", gmac1_ptp_p, 31),
|
||||
JH7110_GATE(JH7110_SYSCLK_GMAC1_AXI, "gmac1_axi", gmac1_axi_p),
|
||||
JH7110_GATE(JH7110_SYSCLK_GMAC1_GTXC, "gmac1_gtxc", gmac1_gtxc_p),
|
||||
JH7110_DIV(JH7110_SYSCLK_GMAC1_RMII_RTX, "gmac1_rmii_rtx",
|
||||
gmac1_rmii_rtx_p, 30),
|
||||
};
|
||||
|
||||
static int
|
||||
jh7110_clk_sys_probe(device_t dev)
|
||||
{
|
||||
if (!ofw_bus_status_okay(dev))
|
||||
return (ENXIO);
|
||||
|
||||
if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
|
||||
return (ENXIO);
|
||||
|
||||
device_set_desc(dev, "StarFive JH7110 SYS clock generator");
|
||||
|
||||
return (BUS_PROBE_DEFAULT);
|
||||
}
|
||||
|
||||
static int
|
||||
jh7110_clk_sys_attach(device_t dev)
|
||||
{
|
||||
struct jh7110_clkgen_softc *sc;
|
||||
int i, error;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
sc->reset_status_offset = SYSCRG_RESET_STATUS;
|
||||
sc->reset_selector_offset = SYSCRG_RESET_SELECTOR;
|
||||
|
||||
mtx_init(&sc->mtx, device_get_nameunit(dev), NULL, MTX_DEF);
|
||||
|
||||
/* Allocate memory groups */
|
||||
error = bus_alloc_resources(dev, res_spec, &sc->mem_res);
|
||||
if (error != 0) {
|
||||
device_printf(dev, "Couldn't allocate resources, error %d\n",
|
||||
error);
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
/* Create clock domain */
|
||||
sc->clkdom = clkdom_create(dev);
|
||||
if (sc->clkdom == NULL) {
|
||||
device_printf(dev, "Couldn't create clkdom\n");
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
/* Register clocks */
|
||||
for (i = 0; i < nitems(sys_clks); i++) {
|
||||
error = jh7110_clk_register(sc->clkdom, &sys_clks[i]);
|
||||
if (error != 0) {
|
||||
device_printf(dev, "Couldn't register clock %s: %d\n",
|
||||
sys_clks[i].clkdef.name, error);
|
||||
return (ENXIO);
|
||||
}
|
||||
}
|
||||
|
||||
if (clkdom_finit(sc->clkdom) != 0)
|
||||
panic("Cannot finalize clkdom initialization\n");
|
||||
|
||||
if (bootverbose)
|
||||
clkdom_dump(sc->clkdom);
|
||||
|
||||
hwreset_register_ofw_provider(dev);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
jh7110_clk_sys_detach(device_t dev)
|
||||
{
|
||||
/* Detach not supported */
|
||||
return (EBUSY);
|
||||
}
|
||||
|
||||
static void
|
||||
jh7110_clk_sys_device_lock(device_t dev)
|
||||
{
|
||||
struct jh7110_clkgen_softc *sc;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
mtx_lock(&sc->mtx);
|
||||
}
|
||||
|
||||
static void
|
||||
jh7110_clk_sys_device_unlock(device_t dev)
|
||||
{
|
||||
struct jh7110_clkgen_softc *sc;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
mtx_unlock(&sc->mtx);
|
||||
}
|
||||
|
||||
static device_method_t jh7110_clk_sys_methods[] = {
|
||||
/* Device interface */
|
||||
DEVMETHOD(device_probe, jh7110_clk_sys_probe),
|
||||
DEVMETHOD(device_attach, jh7110_clk_sys_attach),
|
||||
DEVMETHOD(device_detach, jh7110_clk_sys_detach),
|
||||
|
||||
/* clkdev interface */
|
||||
DEVMETHOD(clkdev_device_lock, jh7110_clk_sys_device_lock),
|
||||
DEVMETHOD(clkdev_device_unlock, jh7110_clk_sys_device_unlock),
|
||||
|
||||
/* Reset interface */
|
||||
DEVMETHOD(hwreset_assert, jh7110_reset_assert),
|
||||
DEVMETHOD(hwreset_is_asserted, jh7110_reset_is_asserted),
|
||||
|
||||
DEVMETHOD_END
|
||||
};
|
||||
|
||||
DEFINE_CLASS_0(jh7110_clk_sys, jh7110_clk_sys_driver, jh7110_clk_sys_methods,
|
||||
sizeof(struct jh7110_clkgen_softc));
|
||||
EARLY_DRIVER_MODULE(jh7110_clk_sys, simplebus, jh7110_clk_sys_driver, 0, 0,
|
||||
BUS_PASS_BUS + BUS_PASS_ORDER_LATE);
|
||||
MODULE_VERSION(jh7110_clk_sys, 1);
|
|
@ -1,7 +1,3 @@
|
|||
dev/clk/starfive/jh7110_clk.c standard
|
||||
dev/clk/starfive/jh7110_clk_aon.c standard
|
||||
dev/clk/starfive/jh7110_clk_pll.c standard
|
||||
dev/clk/starfive/jh7110_clk_sys.c standard
|
||||
dev/mmc/host/dwmmc_starfive.c optional dwmmc_starfive fdt
|
||||
|
||||
riscv/starfive/starfive_syscon.c standard
|
||||
|
|
Loading…
Reference in a new issue