Add clkng driver for Allwinner SoC
Since Linux 4.9-4.10 DTS doesn't have clocks under /clocks but only a ccu node. Currently only H3 is supported with almost the same state as HEAD. (video pll aren't supported for now but we don't support video). This driver and clocks will also be used for other SoC (A64, A31, H5, H2 etc ...) Reviewed by: jmcneill Differential Revision: https://reviews.freebsd.org/D9517
This commit is contained in:
parent
2d4a5bcccb
commit
f5d1d20574
348
sys/arm/allwinner/clkng/aw_ccung.c
Normal file
348
sys/arm/allwinner/clkng/aw_ccung.c
Normal file
@ -0,0 +1,348 @@
|
||||
/*-
|
||||
* Copyright (c) 2017 Emmanuel Vadot <manu@freebsd.org>
|
||||
* 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$
|
||||
*/
|
||||
|
||||
/*
|
||||
* Allwinner Clock Control Unit
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/rman.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/module.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/extres/clk/clk.h>
|
||||
#include <dev/extres/clk/clk_gate.h>
|
||||
|
||||
#include <dev/extres/hwreset/hwreset.h>
|
||||
|
||||
#include <arm/allwinner/clkng/aw_ccung.h>
|
||||
#include <arm/allwinner/clkng/aw_clk.h>
|
||||
|
||||
#if defined(SOC_ALLWINNER_H3)
|
||||
#include <arm/allwinner/clkng/ccu_h3.h>
|
||||
#endif
|
||||
|
||||
#include "clkdev_if.h"
|
||||
#include "hwreset_if.h"
|
||||
|
||||
static struct resource_spec aw_ccung_spec[] = {
|
||||
{ SYS_RES_MEMORY, 0, RF_ACTIVE },
|
||||
{ -1, 0 }
|
||||
};
|
||||
|
||||
#if defined(SOC_ALLWINNER_H3)
|
||||
#define H3_CCU 1
|
||||
#endif
|
||||
|
||||
static struct ofw_compat_data compat_data[] = {
|
||||
#if defined(SOC_ALLWINNER_H3)
|
||||
{ "allwinner,sun8i-h3-ccu", H3_CCU },
|
||||
#endif
|
||||
{NULL, 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))
|
||||
|
||||
static int
|
||||
aw_ccung_write_4(device_t dev, bus_addr_t addr, uint32_t val)
|
||||
{
|
||||
struct aw_ccung_softc *sc;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
CCU_WRITE4(sc, addr, val);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
aw_ccung_read_4(device_t dev, bus_addr_t addr, uint32_t *val)
|
||||
{
|
||||
struct aw_ccung_softc *sc;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
*val = CCU_READ4(sc, addr);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
aw_ccung_modify_4(device_t dev, bus_addr_t addr, uint32_t clr, uint32_t set)
|
||||
{
|
||||
struct aw_ccung_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
|
||||
aw_ccung_reset_assert(device_t dev, intptr_t id, bool reset)
|
||||
{
|
||||
struct aw_ccung_softc *sc;
|
||||
uint32_t val;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
if (id >= sc->nresets || sc->resets[id].offset == 0)
|
||||
return (0);
|
||||
|
||||
mtx_lock(&sc->mtx);
|
||||
val = CCU_READ4(sc, sc->resets[id].offset);
|
||||
if (reset)
|
||||
val &= ~(1 << sc->resets[id].shift);
|
||||
else
|
||||
val |= 1 << sc->resets[id].shift;
|
||||
CCU_WRITE4(sc, sc->resets[id].offset, val);
|
||||
mtx_unlock(&sc->mtx);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
aw_ccung_reset_is_asserted(device_t dev, intptr_t id, bool *reset)
|
||||
{
|
||||
struct aw_ccung_softc *sc;
|
||||
uint32_t val;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
if (id >= sc->nresets || sc->resets[id].offset == 0)
|
||||
return (0);
|
||||
|
||||
mtx_lock(&sc->mtx);
|
||||
val = CCU_READ4(sc, sc->resets[id].offset);
|
||||
*reset = (val & (1 << sc->resets[id].shift)) != 0 ? false : true;
|
||||
mtx_unlock(&sc->mtx);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
aw_ccung_device_lock(device_t dev)
|
||||
{
|
||||
struct aw_ccung_softc *sc;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
mtx_lock(&sc->mtx);
|
||||
}
|
||||
|
||||
static void
|
||||
aw_ccung_device_unlock(device_t dev)
|
||||
{
|
||||
struct aw_ccung_softc *sc;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
mtx_unlock(&sc->mtx);
|
||||
}
|
||||
|
||||
static int
|
||||
aw_ccung_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, "Allwinner Clock Control Unit NG");
|
||||
return (BUS_PROBE_DEFAULT);
|
||||
}
|
||||
|
||||
static int
|
||||
aw_ccung_register_gates(struct aw_ccung_softc *sc)
|
||||
{
|
||||
struct 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 = i;
|
||||
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 = 1;
|
||||
def.off_value = 0;
|
||||
clknode_gate_register(sc->clkdom, &def);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
aw_ccung_init_clocks(struct aw_ccung_softc *sc)
|
||||
{
|
||||
struct clknode *clknode;
|
||||
int i, error;
|
||||
|
||||
for (i = 0; i < sc->n_clk_init; i++) {
|
||||
clknode = clknode_find_by_name(sc->clk_init[i].name);
|
||||
if (clknode == NULL) {
|
||||
device_printf(sc->dev, "Cannot find clock %s\n",
|
||||
sc->clk_init[i].name);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sc->clk_init[i].parent_name != NULL) {
|
||||
if (bootverbose)
|
||||
device_printf(sc->dev, "Setting %s as parent for %s\n",
|
||||
sc->clk_init[i].parent_name,
|
||||
sc->clk_init[i].name);
|
||||
error = clknode_set_parent_by_name(clknode,
|
||||
sc->clk_init[i].parent_name);
|
||||
if (error != 0) {
|
||||
device_printf(sc->dev,
|
||||
"Cannot set parent to %s for %s\n",
|
||||
sc->clk_init[i].parent_name,
|
||||
sc->clk_init[i].name);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (sc->clk_init[i].default_freq != 0) {
|
||||
error = clknode_set_freq(clknode,
|
||||
sc->clk_init[i].default_freq, 0 , 0);
|
||||
if (error != 0) {
|
||||
device_printf(sc->dev,
|
||||
"Cannot set frequency for %s to %llu\n",
|
||||
sc->clk_init[i].name,
|
||||
sc->clk_init[i].default_freq);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (sc->clk_init[i].enable) {
|
||||
error = clknode_enable(clknode);
|
||||
if (error != 0) {
|
||||
device_printf(sc->dev,
|
||||
"Cannot enable %s\n",
|
||||
sc->clk_init[i].name);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
aw_ccung_attach(device_t dev)
|
||||
{
|
||||
struct aw_ccung_softc *sc;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
sc->dev = dev;
|
||||
|
||||
if (bus_alloc_resources(dev, aw_ccung_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->type = ofw_bus_search_compatible(dev, compat_data)->ocd_data;
|
||||
|
||||
sc->clkdom = clkdom_create(dev);
|
||||
if (sc->clkdom == NULL)
|
||||
panic("Cannot create clkdom\n");
|
||||
|
||||
switch (sc->type) {
|
||||
#if defined(SOC_ALLWINNER_H3)
|
||||
case H3_CCU:
|
||||
ccu_h3_register_clocks(sc);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (sc->gates)
|
||||
aw_ccung_register_gates(sc);
|
||||
if (clkdom_finit(sc->clkdom) != 0)
|
||||
panic("cannot finalize clkdom initialization\n");
|
||||
|
||||
clkdom_xlock(sc->clkdom);
|
||||
aw_ccung_init_clocks(sc);
|
||||
clkdom_unlock(sc->clkdom);
|
||||
|
||||
if (bootverbose)
|
||||
clkdom_dump(sc->clkdom);
|
||||
|
||||
/* If we have resets, register our self as a reset provider */
|
||||
if (sc->resets)
|
||||
hwreset_register_ofw_provider(dev);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static device_method_t aw_ccung_methods[] = {
|
||||
/* Device interface */
|
||||
DEVMETHOD(device_probe, aw_ccung_probe),
|
||||
DEVMETHOD(device_attach, aw_ccung_attach),
|
||||
|
||||
/* clkdev interface */
|
||||
DEVMETHOD(clkdev_write_4, aw_ccung_write_4),
|
||||
DEVMETHOD(clkdev_read_4, aw_ccung_read_4),
|
||||
DEVMETHOD(clkdev_modify_4, aw_ccung_modify_4),
|
||||
DEVMETHOD(clkdev_device_lock, aw_ccung_device_lock),
|
||||
DEVMETHOD(clkdev_device_unlock, aw_ccung_device_unlock),
|
||||
|
||||
/* Reset interface */
|
||||
DEVMETHOD(hwreset_assert, aw_ccung_reset_assert),
|
||||
DEVMETHOD(hwreset_is_asserted, aw_ccung_reset_is_asserted),
|
||||
|
||||
DEVMETHOD_END
|
||||
};
|
||||
|
||||
static driver_t aw_ccung_driver = {
|
||||
"aw_ccung",
|
||||
aw_ccung_methods,
|
||||
sizeof(struct aw_ccung_softc),
|
||||
};
|
||||
|
||||
static devclass_t aw_ccung_devclass;
|
||||
|
||||
EARLY_DRIVER_MODULE(aw_ccung, simplebus, aw_ccung_driver, aw_ccung_devclass,
|
||||
0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE);
|
||||
MODULE_VERSION(aw_ccung, 1);
|
59
sys/arm/allwinner/clkng/aw_ccung.h
Normal file
59
sys/arm/allwinner/clkng/aw_ccung.h
Normal file
@ -0,0 +1,59 @@
|
||||
/*-
|
||||
* Copyright (c) 2017 Emmanuel Vadot <manu@freebsd.org>
|
||||
* 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$
|
||||
*/
|
||||
|
||||
#ifndef __CCU_NG_H__
|
||||
#define __CCU_NG_H__
|
||||
|
||||
struct aw_ccung_softc {
|
||||
device_t dev;
|
||||
struct resource *res;
|
||||
struct clkdom *clkdom;
|
||||
struct mtx mtx;
|
||||
int type;
|
||||
struct aw_ccung_reset *resets;
|
||||
int nresets;
|
||||
struct aw_ccung_gate *gates;
|
||||
int ngates;
|
||||
struct aw_clk_init *clk_init;
|
||||
int n_clk_init;
|
||||
};
|
||||
|
||||
struct aw_ccung_reset {
|
||||
uint32_t offset;
|
||||
uint32_t shift;
|
||||
};
|
||||
|
||||
struct aw_ccung_gate {
|
||||
const char *name;
|
||||
const char *parent_name;
|
||||
uint32_t id;
|
||||
uint32_t offset;
|
||||
uint32_t shift;
|
||||
};
|
||||
|
||||
#endif /* __CCU_NG_H__ */
|
317
sys/arm/allwinner/clkng/aw_clk.h
Normal file
317
sys/arm/allwinner/clkng/aw_clk.h
Normal file
@ -0,0 +1,317 @@
|
||||
/*-
|
||||
* Copyright (c) 2017 Emmanuel Vadot <manu@freebsd.org>
|
||||
* 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$
|
||||
*/
|
||||
|
||||
#ifndef __AW_CLK_H__
|
||||
#define __AW_CLK_H__
|
||||
|
||||
/*
|
||||
Allwinner clocks formula :
|
||||
|
||||
PLLs:
|
||||
|
||||
(24MHz*N*K)/(M*P)
|
||||
(24MHz*N)/(M*P)
|
||||
(24MHz*N*2)/M
|
||||
(24MHz*N)/M
|
||||
(24MHz*N*K)/M
|
||||
(24MHz*N*K/2)
|
||||
(24MHz*N)/M
|
||||
(24MHz*N*K/2)
|
||||
(24MHz*N)/M
|
||||
|
||||
Periph clocks:
|
||||
|
||||
Clock Source/Divider N/Divider M
|
||||
Clock Source/Divider N/Divider M/2
|
||||
|
||||
*/
|
||||
|
||||
struct aw_clk_init {
|
||||
const char *name;
|
||||
const char *parent_name;
|
||||
uint64_t default_freq;
|
||||
bool enable;
|
||||
};
|
||||
|
||||
#define AW_CLK_HAS_GATE 0x0001
|
||||
#define AW_CLK_HAS_LOCK 0x0002
|
||||
#define AW_CLK_HAS_MUX 0x0004
|
||||
#define AW_CLK_REPARENT 0x0008
|
||||
#define AW_CLK_SCALE_CHANGE 0x0010
|
||||
|
||||
#define AW_CLK_FACTOR_POWER_OF_TWO 0x0001
|
||||
#define AW_CLK_FACTOR_ZERO_BASED 0x0002
|
||||
#define AW_CLK_FACTOR_HAS_COND 0x0004
|
||||
#define AW_CLK_FACTOR_FIXED 0x0008
|
||||
|
||||
struct aw_clk_factor {
|
||||
uint32_t shift; /* Shift bits for the factor */
|
||||
uint32_t mask; /* Mask to get the factor, will be override by the clk methods */
|
||||
uint32_t width; /* Number of bits for the factor */
|
||||
uint32_t value; /* Fixed value, depends on AW_CLK_FACTOR_FIXED */
|
||||
|
||||
uint32_t cond_shift;
|
||||
uint32_t cond_mask;
|
||||
uint32_t cond_width;
|
||||
uint32_t cond_value;
|
||||
|
||||
uint32_t flags; /* Flags */
|
||||
};
|
||||
|
||||
static inline uint32_t
|
||||
aw_clk_get_factor(uint32_t val, struct aw_clk_factor *factor)
|
||||
{
|
||||
uint32_t factor_val;
|
||||
uint32_t cond;
|
||||
|
||||
if (factor->flags & AW_CLK_FACTOR_HAS_COND) {
|
||||
cond = (val & factor->cond_mask) >> factor->cond_shift;
|
||||
if (cond != factor->cond_value)
|
||||
return (1);
|
||||
}
|
||||
|
||||
if (factor->flags & AW_CLK_FACTOR_FIXED)
|
||||
return (factor->value);
|
||||
|
||||
factor_val = (val & factor->mask) >> factor->shift;
|
||||
if (!(factor->flags & AW_CLK_FACTOR_ZERO_BASED))
|
||||
factor_val += 1;
|
||||
else if (factor->flags & AW_CLK_FACTOR_POWER_OF_TWO)
|
||||
factor_val = 1 << factor_val;
|
||||
|
||||
return (factor_val);
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
aw_clk_factor_get_max(struct aw_clk_factor *factor)
|
||||
{
|
||||
uint32_t max;
|
||||
|
||||
if (factor->flags & AW_CLK_FACTOR_FIXED)
|
||||
max = factor->value;
|
||||
else if (factor->flags & AW_CLK_FACTOR_POWER_OF_TWO)
|
||||
max = 1 << ((1 << factor->width) - 1);
|
||||
else {
|
||||
max = (1 << factor->width);
|
||||
}
|
||||
|
||||
return (max);
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
aw_clk_factor_get_min(struct aw_clk_factor *factor)
|
||||
{
|
||||
uint32_t min;
|
||||
|
||||
if (factor->flags & AW_CLK_FACTOR_FIXED)
|
||||
min = factor->value;
|
||||
else if (factor->flags & AW_CLK_FACTOR_ZERO_BASED)
|
||||
min = 0;
|
||||
else
|
||||
min = 1;
|
||||
|
||||
return (min);
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
aw_clk_factor_get_value(struct aw_clk_factor *factor, uint32_t raw)
|
||||
{
|
||||
uint32_t val;
|
||||
|
||||
if (factor->flags & AW_CLK_FACTOR_FIXED)
|
||||
return (factor->value);
|
||||
|
||||
if (factor->flags & AW_CLK_FACTOR_ZERO_BASED)
|
||||
val = raw;
|
||||
else if (factor->flags & AW_CLK_FACTOR_POWER_OF_TWO) {
|
||||
for (val = 0; raw != 1; val++)
|
||||
raw >>= 1;
|
||||
} else
|
||||
val = raw - 1;
|
||||
|
||||
return (val);
|
||||
}
|
||||
|
||||
#define CCU_RESET(idx, o, s) \
|
||||
[idx] = { \
|
||||
.offset = o, \
|
||||
.shift = s, \
|
||||
},
|
||||
|
||||
#define CCU_GATE(idx, clkname, pname, o, s) \
|
||||
[idx] = { \
|
||||
.name = clkname, \
|
||||
.parent_name = pname, \
|
||||
.offset = o, \
|
||||
.shift = s, \
|
||||
},
|
||||
|
||||
#define NKMP_CLK(_id, _name, _pnames, \
|
||||
_offset, \
|
||||
_n_shift, _n_width, _n_value, _n_flags, \
|
||||
_k_shift, _k_width, _k_value, _k_flags, \
|
||||
_m_shift, _m_width, _m_value, _m_flags, \
|
||||
_p_shift, _p_width, _p_value, _p_flags, \
|
||||
_gate, \
|
||||
_lock, _lock_retries, \
|
||||
_flags) \
|
||||
{ \
|
||||
.clkdef = { \
|
||||
.id = _id, \
|
||||
.name = _name, \
|
||||
.parent_names = _pnames, \
|
||||
.parent_cnt = nitems(_pnames), \
|
||||
}, \
|
||||
.offset = _offset, \
|
||||
.n.shift = _n_shift, \
|
||||
.n.width = _n_width, \
|
||||
.n.value = _n_value, \
|
||||
.n.flags = _n_flags, \
|
||||
.k.shift = _k_shift, \
|
||||
.k.width = _k_width, \
|
||||
.k.value = _k_value, \
|
||||
.k.flags = _k_flags, \
|
||||
.m.shift = _m_shift, \
|
||||
.m.width = _m_width, \
|
||||
.m.value = _m_value, \
|
||||
.m.flags = _m_flags, \
|
||||
.p.shift = _p_shift, \
|
||||
.p.width = _p_width, \
|
||||
.p.value = _p_value, \
|
||||
.p.flags = _p_flags, \
|
||||
.gate_shift = _gate, \
|
||||
.lock_shift = _lock, \
|
||||
.lock_retries = _lock_retries, \
|
||||
.flags = _flags, \
|
||||
},
|
||||
|
||||
#define NM_CLK(_id, _name, _pnames, \
|
||||
_offset, \
|
||||
_nshift, _nwidth, _nvalue, _nflags, \
|
||||
_mshift, _mwidth, _mvalue, _mflags, \
|
||||
_mux_shift, _mux_width, \
|
||||
_gate_shift, \
|
||||
_flags) \
|
||||
{ \
|
||||
.clkdef = { \
|
||||
.id = _id, \
|
||||
.name = _name, \
|
||||
.parent_names = _pnames, \
|
||||
.parent_cnt = nitems(_pnames), \
|
||||
}, \
|
||||
.offset = _offset, \
|
||||
.n.shift = _nshift, \
|
||||
.n.width = _nwidth, \
|
||||
.n.value = _nvalue, \
|
||||
.n.flags = _nflags, \
|
||||
.mux_shift = _mux_shift, \
|
||||
.m.shift = _mshift, \
|
||||
.m.width = _mwidth, \
|
||||
.m.value = _mvalue, \
|
||||
.m.flags = _mflags, \
|
||||
.mux_width = _mux_width, \
|
||||
.flags = _flags, \
|
||||
},
|
||||
|
||||
#define PREDIV_CLK(_id, _name, _pnames, \
|
||||
_offset, \
|
||||
_mux_shift, _mux_width, \
|
||||
_div_shift, _div_width, _div_value, _div_flags, \
|
||||
_prediv_shift, _prediv_width, _prediv_value, _prediv_flags, \
|
||||
_prediv_cond_shift, _prediv_cond_width, _prediv_cond_value) \
|
||||
{ \
|
||||
.clkdef = { \
|
||||
.id = _id, \
|
||||
.name = _name, \
|
||||
.parent_names = _pnames, \
|
||||
.parent_cnt = nitems(_pnames), \
|
||||
}, \
|
||||
.offset = _offset, \
|
||||
.mux_shift = _mux_shift, \
|
||||
.mux_width = _mux_width, \
|
||||
.div.shift = _div_shift, \
|
||||
.div.width = _div_width, \
|
||||
.div.value = _div_value, \
|
||||
.div.flags = _div_flags, \
|
||||
.prediv.shift = _prediv_shift, \
|
||||
.prediv.width = _prediv_width, \
|
||||
.prediv.value = _prediv_value, \
|
||||
.prediv.flags = _prediv_flags, \
|
||||
.prediv.cond_shift = _prediv_cond_shift, \
|
||||
.prediv.cond_width = _prediv_cond_width, \
|
||||
.prediv.cond_value = _prediv_cond_value, \
|
||||
},
|
||||
|
||||
#define MUX_CLK(_id, _name, _pnames, \
|
||||
_offset, _shift, _width) \
|
||||
{ \
|
||||
.clkdef = { \
|
||||
.id = _id, \
|
||||
.name = _name, \
|
||||
.parent_names = _pnames, \
|
||||
.parent_cnt = nitems(_pnames) \
|
||||
}, \
|
||||
.offset = _offset, \
|
||||
.shift = _shift, \
|
||||
.width = _width, \
|
||||
},
|
||||
|
||||
#define DIV_CLK(_id, _name, _pnames, \
|
||||
_offset, \
|
||||
_i_shift, _i_width, \
|
||||
_div_flags, _div_table) \
|
||||
{ \
|
||||
.clkdef = { \
|
||||
.id = _id, \
|
||||
.name = _name, \
|
||||
.parent_names = _pnames, \
|
||||
.parent_cnt = nitems(_pnames) \
|
||||
}, \
|
||||
.offset = _offset, \
|
||||
.i_shift = _i_shift, \
|
||||
.i_width = _i_width, \
|
||||
.div_flags = _div_flags, \
|
||||
.div_table = _div_table, \
|
||||
},
|
||||
|
||||
#define FIXED_CLK(_id, _name, _pnames, \
|
||||
_freq, _mult, _div, _flags) \
|
||||
{ \
|
||||
.clkdef = { \
|
||||
.id = _id, \
|
||||
.name = _name, \
|
||||
.parent_names = _pnames, \
|
||||
.parent_cnt = 1, \
|
||||
}, \
|
||||
.freq = _freq, \
|
||||
.mult = _mult, \
|
||||
.div = _div, \
|
||||
.fixed_flags = _flags, \
|
||||
},
|
||||
|
||||
#endif /* __AW_CLK_H__ */
|
362
sys/arm/allwinner/clkng/aw_clk_nkmp.c
Normal file
362
sys/arm/allwinner/clkng/aw_clk_nkmp.c
Normal file
@ -0,0 +1,362 @@
|
||||
/*-
|
||||
* Copyright (c) 2017 Emmanuel Vadot <manu@freebsd.org>
|
||||
* 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 <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/bus.h>
|
||||
|
||||
#include <dev/extres/clk/clk.h>
|
||||
|
||||
#include <arm/allwinner/clkng/aw_clk.h>
|
||||
#include <arm/allwinner/clkng/aw_clk_nkmp.h>
|
||||
|
||||
#include "clkdev_if.h"
|
||||
|
||||
/*
|
||||
* clknode for clocks matching the formula :
|
||||
*
|
||||
* clk = (clkin * n * k) / (m * p)
|
||||
*
|
||||
*/
|
||||
|
||||
struct aw_clk_nkmp_sc {
|
||||
uint32_t offset;
|
||||
|
||||
struct aw_clk_factor n;
|
||||
struct aw_clk_factor k;
|
||||
struct aw_clk_factor m;
|
||||
struct aw_clk_factor p;
|
||||
|
||||
uint32_t gate_shift;
|
||||
uint32_t lock_shift;
|
||||
uint32_t lock_retries;
|
||||
|
||||
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 MODIFY4(_clk, off, clr, set ) \
|
||||
CLKDEV_MODIFY_4(clknode_get_device(_clk), off, clr, set)
|
||||
#define DEVICE_LOCK(_clk) \
|
||||
CLKDEV_DEVICE_LOCK(clknode_get_device(_clk))
|
||||
#define DEVICE_UNLOCK(_clk) \
|
||||
CLKDEV_DEVICE_UNLOCK(clknode_get_device(_clk))
|
||||
|
||||
static int
|
||||
aw_clk_nkmp_init(struct clknode *clk, device_t dev)
|
||||
{
|
||||
clknode_init_parent_idx(clk, 0);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
aw_clk_nkmp_set_gate(struct clknode *clk, bool enable)
|
||||
{
|
||||
struct aw_clk_nkmp_sc *sc;
|
||||
uint32_t val;
|
||||
|
||||
sc = clknode_get_softc(clk);
|
||||
|
||||
if ((sc->flags & AW_CLK_HAS_GATE) == 0)
|
||||
return (0);
|
||||
|
||||
DEVICE_LOCK(clk);
|
||||
READ4(clk, sc->offset, &val);
|
||||
if (enable)
|
||||
val |= (1 << sc->gate_shift);
|
||||
else
|
||||
val &= ~(1 << sc->gate_shift);
|
||||
WRITE4(clk, sc->offset, val);
|
||||
DEVICE_UNLOCK(clk);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static uint64_t
|
||||
aw_clk_nkmp_find_best(struct aw_clk_nkmp_sc *sc, uint64_t fparent, uint64_t *fout,
|
||||
uint32_t *factor_n, uint32_t *factor_k, uint32_t *factor_m, uint32_t *factor_p)
|
||||
{
|
||||
uint64_t cur, best;
|
||||
uint32_t n, k, m, p;
|
||||
|
||||
best = 0;
|
||||
*factor_n = 0;
|
||||
*factor_k = 0;
|
||||
*factor_m = 0;
|
||||
*factor_p = 0;
|
||||
|
||||
for (n = aw_clk_factor_get_min(&sc->n); n <= aw_clk_factor_get_max(&sc->n); ) {
|
||||
for (k = aw_clk_factor_get_min(&sc->k); k <= aw_clk_factor_get_max(&sc->k); ) {
|
||||
for (m = aw_clk_factor_get_min(&sc->m); m <= aw_clk_factor_get_max(&sc->m); ) {
|
||||
for (p = aw_clk_factor_get_min(&sc->p); p <= aw_clk_factor_get_max(&sc->p); ) {
|
||||
cur = (fparent * n * k) / (m * p);
|
||||
if ((*fout - cur) < (*fout - best)) {
|
||||
best = cur;
|
||||
*factor_n = n;
|
||||
*factor_k = k;
|
||||
*factor_m = m;
|
||||
*factor_p = p;
|
||||
}
|
||||
if (best == *fout)
|
||||
return (best);
|
||||
if ((sc->p.flags & AW_CLK_FACTOR_POWER_OF_TWO) != 0)
|
||||
p <<= 1;
|
||||
else
|
||||
p++;
|
||||
}
|
||||
if ((sc->m.flags & AW_CLK_FACTOR_POWER_OF_TWO) != 0)
|
||||
m <<= 1;
|
||||
else
|
||||
m++;
|
||||
}
|
||||
if ((sc->k.flags & AW_CLK_FACTOR_POWER_OF_TWO) != 0)
|
||||
k <<= 1;
|
||||
else
|
||||
k++;
|
||||
}
|
||||
if ((sc->n.flags & AW_CLK_FACTOR_POWER_OF_TWO) != 0)
|
||||
n <<= 1;
|
||||
else
|
||||
n++;
|
||||
}
|
||||
|
||||
return best;
|
||||
}
|
||||
|
||||
static void
|
||||
aw_clk_nkmp_set_freq_scale(struct clknode *clk, struct aw_clk_nkmp_sc *sc,
|
||||
uint32_t factor_n, uint32_t factor_k, uint32_t factor_m, uint32_t factor_p)
|
||||
{
|
||||
uint32_t val, n, k, m, p;
|
||||
int retry;
|
||||
|
||||
DEVICE_LOCK(clk);
|
||||
READ4(clk, sc->offset, &val);
|
||||
|
||||
n = aw_clk_get_factor(val, &sc->n);
|
||||
k = aw_clk_get_factor(val, &sc->k);
|
||||
m = aw_clk_get_factor(val, &sc->m);
|
||||
p = aw_clk_get_factor(val, &sc->p);
|
||||
|
||||
if (p < factor_p) {
|
||||
val &= ~sc->p.mask;
|
||||
val |= aw_clk_factor_get_value(&sc->p, factor_p) << sc->p.shift;
|
||||
WRITE4(clk, sc->offset, val);
|
||||
DELAY(2000);
|
||||
}
|
||||
|
||||
if (m < factor_m) {
|
||||
val &= ~sc->m.mask;
|
||||
val |= aw_clk_factor_get_value(&sc->m, factor_m) << sc->m.shift;
|
||||
WRITE4(clk, sc->offset, val);
|
||||
DELAY(2000);
|
||||
}
|
||||
|
||||
val &= ~sc->n.mask;
|
||||
val &= ~sc->k.mask;
|
||||
val |= aw_clk_factor_get_value(&sc->n, factor_n) << sc->n.shift;
|
||||
val |= aw_clk_factor_get_value(&sc->k, factor_k) << sc->k.shift;
|
||||
WRITE4(clk, sc->offset, val);
|
||||
DELAY(2000);
|
||||
|
||||
if (m > factor_m) {
|
||||
val &= ~sc->m.mask;
|
||||
val |= aw_clk_factor_get_value(&sc->m, factor_m) << sc->m.shift;
|
||||
WRITE4(clk, sc->offset, val);
|
||||
DELAY(2000);
|
||||
}
|
||||
|
||||
if (p > factor_p) {
|
||||
val &= ~sc->p.mask;
|
||||
val |= aw_clk_factor_get_value(&sc->p, factor_p) << sc->p.shift;
|
||||
WRITE4(clk, sc->offset, val);
|
||||
DELAY(2000);
|
||||
}
|
||||
|
||||
if ((sc->flags & AW_CLK_HAS_LOCK) != 0) {
|
||||
for (retry = 0; retry < sc->lock_retries; retry++) {
|
||||
READ4(clk, sc->offset, &val);
|
||||
if ((val & (1 << sc->lock_shift)) != 0)
|
||||
break;
|
||||
DELAY(1000);
|
||||
}
|
||||
}
|
||||
|
||||
DEVICE_UNLOCK(clk);
|
||||
}
|
||||
|
||||
static int
|
||||
aw_clk_nkmp_set_freq(struct clknode *clk, uint64_t fparent, uint64_t *fout,
|
||||
int flags, int *stop)
|
||||
{
|
||||
struct aw_clk_nkmp_sc *sc;
|
||||
uint64_t best;
|
||||
uint32_t val, best_n, best_k, best_m, best_p;
|
||||
int retry;
|
||||
|
||||
sc = clknode_get_softc(clk);
|
||||
|
||||
best = aw_clk_nkmp_find_best(sc, fparent, fout,
|
||||
&best_n, &best_k, &best_m, &best_p);
|
||||
if ((flags & CLK_SET_DRYRUN) != 0) {
|
||||
*fout = best;
|
||||
*stop = 1;
|
||||
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 ((sc->flags & AW_CLK_SCALE_CHANGE) != 0)
|
||||
aw_clk_nkmp_set_freq_scale(clk, sc,
|
||||
best_n, best_k, best_m, best_p);
|
||||
else {
|
||||
DEVICE_LOCK(clk);
|
||||
READ4(clk, sc->offset, &val);
|
||||
val &= ~sc->n.mask;
|
||||
val &= ~sc->k.mask;
|
||||
val &= ~sc->m.mask;
|
||||
val &= ~sc->p.mask;
|
||||
val |= aw_clk_factor_get_value(&sc->n, best_n) << sc->n.shift;
|
||||
val |= aw_clk_factor_get_value(&sc->k, best_k) << sc->k.shift;
|
||||
val |= aw_clk_factor_get_value(&sc->m, best_m) << sc->m.shift;
|
||||
val |= aw_clk_factor_get_value(&sc->p, best_p) << sc->p.shift;
|
||||
WRITE4(clk, sc->offset, val);
|
||||
DELAY(2000);
|
||||
|
||||
if ((sc->flags & AW_CLK_HAS_LOCK) != 0) {
|
||||
for (retry = 0; retry < sc->lock_retries; retry++) {
|
||||
READ4(clk, sc->offset, &val);
|
||||
if ((val & (1 << sc->lock_shift)) != 0)
|
||||
break;
|
||||
DELAY(1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*fout = best;
|
||||
*stop = 1;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
aw_clk_nkmp_recalc(struct clknode *clk, uint64_t *freq)
|
||||
{
|
||||
struct aw_clk_nkmp_sc *sc;
|
||||
uint32_t val, m, n, k, p;
|
||||
|
||||
sc = clknode_get_softc(clk);
|
||||
|
||||
DEVICE_LOCK(clk);
|
||||
READ4(clk, sc->offset, &val);
|
||||
DEVICE_UNLOCK(clk);
|
||||
|
||||
n = aw_clk_get_factor(val, &sc->n);
|
||||
k = aw_clk_get_factor(val, &sc->k);
|
||||
m = aw_clk_get_factor(val, &sc->m);
|
||||
p = aw_clk_get_factor(val, &sc->p);
|
||||
|
||||
*freq = (*freq * n * k) / (m * p);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static clknode_method_t aw_nkmp_clknode_methods[] = {
|
||||
/* Device interface */
|
||||
CLKNODEMETHOD(clknode_init, aw_clk_nkmp_init),
|
||||
CLKNODEMETHOD(clknode_set_gate, aw_clk_nkmp_set_gate),
|
||||
CLKNODEMETHOD(clknode_recalc_freq, aw_clk_nkmp_recalc),
|
||||
CLKNODEMETHOD(clknode_set_freq, aw_clk_nkmp_set_freq),
|
||||
CLKNODEMETHOD_END
|
||||
};
|
||||
|
||||
DEFINE_CLASS_1(aw_nkmp_clknode, aw_nkmp_clknode_class, aw_nkmp_clknode_methods,
|
||||
sizeof(struct aw_clk_nkmp_sc), clknode_class);
|
||||
|
||||
int
|
||||
aw_clk_nkmp_register(struct clkdom *clkdom, struct aw_clk_nkmp_def *clkdef)
|
||||
{
|
||||
struct clknode *clk;
|
||||
struct aw_clk_nkmp_sc *sc;
|
||||
|
||||
clk = clknode_create(clkdom, &aw_nkmp_clknode_class, &clkdef->clkdef);
|
||||
if (clk == NULL)
|
||||
return (1);
|
||||
|
||||
sc = clknode_get_softc(clk);
|
||||
|
||||
sc->offset = clkdef->offset;
|
||||
|
||||
sc->n.shift = clkdef->n.shift;
|
||||
sc->n.width = clkdef->n.width;
|
||||
sc->n.mask = ((1 << clkdef->n.width) - 1) << sc->n.shift;
|
||||
sc->n.value = clkdef->n.value;
|
||||
sc->n.flags = clkdef->n.flags;
|
||||
|
||||
sc->k.shift = clkdef->k.shift;
|
||||
sc->k.width = clkdef->k.width;
|
||||
sc->k.mask = ((1 << clkdef->k.width) - 1) << sc->k.shift;
|
||||
sc->k.value = clkdef->k.value;
|
||||
sc->k.flags = clkdef->k.flags;
|
||||
|
||||
sc->m.shift = clkdef->m.shift;
|
||||
sc->m.width = clkdef->m.width;
|
||||
sc->m.mask = ((1 << clkdef->m.width) - 1) << sc->m.shift;
|
||||
sc->m.value = clkdef->m.value;
|
||||
sc->m.flags = clkdef->m.flags;
|
||||
|
||||
sc->p.shift = clkdef->p.shift;
|
||||
sc->p.width = clkdef->p.width;
|
||||
sc->p.mask = ((1 << clkdef->p.width) - 1) << sc->p.shift;
|
||||
sc->p.value = clkdef->p.value;
|
||||
sc->p.flags = clkdef->p.flags;
|
||||
|
||||
sc->gate_shift = clkdef->gate_shift;
|
||||
sc->lock_shift = clkdef->lock_shift;
|
||||
sc->lock_retries = clkdef->lock_retries;
|
||||
sc->flags = clkdef->flags;
|
||||
|
||||
clknode_register(clkdom, clk);
|
||||
|
||||
return (0);
|
||||
}
|
53
sys/arm/allwinner/clkng/aw_clk_nkmp.h
Normal file
53
sys/arm/allwinner/clkng/aw_clk_nkmp.h
Normal file
@ -0,0 +1,53 @@
|
||||
/*-
|
||||
* Copyright (c) 2017 Emmanuel Vadot <manu@freebsd.org>
|
||||
* 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$
|
||||
*/
|
||||
|
||||
#ifndef __AW_CLK_NKMP_H__
|
||||
#define __AW_CLK_NKMP_H__
|
||||
|
||||
#include <arm/allwinner/clkng/aw_clk.h>
|
||||
|
||||
struct aw_clk_nkmp_def {
|
||||
struct clknode_init_def clkdef;
|
||||
|
||||
uint32_t offset;
|
||||
|
||||
struct aw_clk_factor m;
|
||||
struct aw_clk_factor k;
|
||||
struct aw_clk_factor n;
|
||||
struct aw_clk_factor p;
|
||||
|
||||
uint32_t gate_shift;
|
||||
uint32_t lock_shift;
|
||||
uint32_t lock_retries;
|
||||
|
||||
uint32_t flags;
|
||||
};
|
||||
|
||||
int aw_clk_nkmp_register(struct clkdom *clkdom, struct aw_clk_nkmp_def *clkdef);
|
||||
|
||||
#endif /* __AW_CLK_NKMP_H__ */
|
315
sys/arm/allwinner/clkng/aw_clk_nm.c
Normal file
315
sys/arm/allwinner/clkng/aw_clk_nm.c
Normal file
@ -0,0 +1,315 @@
|
||||
/*-
|
||||
* Copyright (c) 2017 Emmanuel Vadot <manu@freebsd.org>
|
||||
* 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 <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/bus.h>
|
||||
|
||||
#include <dev/extres/clk/clk.h>
|
||||
|
||||
#include <arm/allwinner/clkng/aw_clk.h>
|
||||
#include <arm/allwinner/clkng/aw_clk_nm.h>
|
||||
|
||||
#include "clkdev_if.h"
|
||||
|
||||
/*
|
||||
* clknode for clocks matching the formula :
|
||||
*
|
||||
* clk = clkin / n / m
|
||||
*
|
||||
*/
|
||||
|
||||
struct aw_clk_nm_sc {
|
||||
uint32_t offset;
|
||||
|
||||
struct aw_clk_factor m;
|
||||
struct aw_clk_factor n;
|
||||
|
||||
uint32_t mux_shift;
|
||||
uint32_t mux_mask;
|
||||
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) \
|
||||
CLKDEV_DEVICE_LOCK(clknode_get_device(_clk))
|
||||
#define DEVICE_UNLOCK(_clk) \
|
||||
CLKDEV_DEVICE_UNLOCK(clknode_get_device(_clk))
|
||||
|
||||
static int
|
||||
aw_clk_nm_init(struct clknode *clk, device_t dev)
|
||||
{
|
||||
struct aw_clk_nm_sc *sc;
|
||||
uint32_t val, idx;
|
||||
|
||||
sc = clknode_get_softc(clk);
|
||||
|
||||
idx = 0;
|
||||
if ((sc->flags & AW_CLK_HAS_MUX) != 0) {
|
||||
DEVICE_LOCK(clk);
|
||||
READ4(clk, sc->offset, &val);
|
||||
DEVICE_UNLOCK(clk);
|
||||
|
||||
idx = (val & sc->mux_mask) >> sc->mux_shift;
|
||||
}
|
||||
|
||||
clknode_init_parent_idx(clk, idx);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
aw_clk_nm_set_gate(struct clknode *clk, bool enable)
|
||||
{
|
||||
struct aw_clk_nm_sc *sc;
|
||||
uint32_t val;
|
||||
|
||||
sc = clknode_get_softc(clk);
|
||||
|
||||
if ((sc->flags & AW_CLK_HAS_GATE) == 0)
|
||||
return (0);
|
||||
|
||||
DEVICE_LOCK(clk);
|
||||
READ4(clk, sc->offset, &val);
|
||||
if (enable)
|
||||
val |= (1 << sc->gate_shift);
|
||||
else
|
||||
val &= ~(1 << sc->gate_shift);
|
||||
WRITE4(clk, sc->offset, val);
|
||||
DEVICE_UNLOCK(clk);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
aw_clk_nm_set_mux(struct clknode *clk, int index)
|
||||
{
|
||||
struct aw_clk_nm_sc *sc;
|
||||
uint32_t val;
|
||||
|
||||
sc = clknode_get_softc(clk);
|
||||
|
||||
if ((sc->flags & AW_CLK_HAS_MUX) != 0)
|
||||
return (0);
|
||||
|
||||
DEVICE_LOCK(clk);
|
||||
READ4(clk, sc->offset, &val);
|
||||
val &= ~(sc->mux_mask >> sc->mux_shift);
|
||||
val |= index << sc->mux_shift;
|
||||
WRITE4(clk, sc->offset, val);
|
||||
DEVICE_UNLOCK(clk);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static uint64_t
|
||||
aw_clk_nm_find_best(struct aw_clk_nm_sc *sc, uint64_t fparent, uint64_t *fout,
|
||||
uint32_t *factor_n, uint32_t *factor_m)
|
||||
{
|
||||
uint64_t cur, best;
|
||||
uint32_t m, n, max_m, max_n, min_m, min_n;
|
||||
|
||||
*factor_n = *factor_m = 0;
|
||||
|
||||
max_m = aw_clk_factor_get_max(&sc->m);
|
||||
max_n = aw_clk_factor_get_max(&sc->n);
|
||||
min_m = aw_clk_factor_get_min(&sc->m);
|
||||
min_n = aw_clk_factor_get_min(&sc->n);
|
||||
|
||||
for (m = min_m; m <= max_m; ) {
|
||||
for (n = min_m; n <= max_n; ) {
|
||||
cur = fparent / n / m;
|
||||
if ((*fout - cur) < (*fout - best)) {
|
||||
best = cur;
|
||||
*factor_n = n;
|
||||
*factor_m = m;
|
||||
}
|
||||
|
||||
if ((sc->n.flags & AW_CLK_FACTOR_POWER_OF_TWO) != 0)
|
||||
n <<= 1;
|
||||
else
|
||||
n++;
|
||||
}
|
||||
if ((sc->m.flags & AW_CLK_FACTOR_POWER_OF_TWO) != 0)
|
||||
m <<= 1;
|
||||
else
|
||||
m++;
|
||||
}
|
||||
|
||||
return (best);
|
||||
}
|
||||
|
||||
static int
|
||||
aw_clk_nm_set_freq(struct clknode *clk, uint64_t fparent, uint64_t *fout,
|
||||
int flags, int *stop)
|
||||
{
|
||||
struct aw_clk_nm_sc *sc;
|
||||
struct clknode *p_clk;
|
||||
const char **p_names;
|
||||
uint64_t cur, best;
|
||||
uint32_t val, m, n, best_m, best_n;
|
||||
int p_idx, best_parent;
|
||||
|
||||
sc = clknode_get_softc(clk);
|
||||
|
||||
best = cur = 0;
|
||||
best_parent = 0;
|
||||
|
||||
if ((sc->flags & AW_CLK_REPARENT) != 0) {
|
||||
p_names = clknode_get_parent_names(clk);
|
||||
for (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);
|
||||
|
||||
cur = aw_clk_nm_find_best(sc, fparent, fout, &n, &m);
|
||||
if ((*fout - cur) < (*fout - best)) {
|
||||
best = cur;
|
||||
best_parent = p_idx;
|
||||
best_n = n;
|
||||
best_m = m;
|
||||
}
|
||||
}
|
||||
|
||||
p_idx = clknode_get_parent_idx(clk);
|
||||
p_clk = clknode_get_parent(clk);
|
||||
clknode_get_freq(p_clk, &fparent);
|
||||
} else
|
||||
best = aw_clk_nm_find_best(sc, fparent, fout, &best_n, &best_m);
|
||||
|
||||
if ((flags & CLK_SET_DRYRUN) != 0) {
|
||||
*fout = best;
|
||||
*stop = 1;
|
||||
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 (p_idx != best_parent)
|
||||
clknode_set_parent_by_idx(clk, best_parent);
|
||||
|
||||
n = aw_clk_factor_get_value(&sc->n, best_n);
|
||||
m = aw_clk_factor_get_value(&sc->m, best_m);
|
||||
DEVICE_LOCK(clk);
|
||||
READ4(clk, sc->offset, &val);
|
||||
val &= ~sc->n.mask;
|
||||
val &= ~sc->m.mask;
|
||||
val |= n << sc->n.shift;
|
||||
val |= m << sc->m.shift;
|
||||
WRITE4(clk, sc->offset, val);
|
||||
DEVICE_UNLOCK(clk);
|
||||
|
||||
*fout = best;
|
||||
*stop = 1;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
aw_clk_nm_recalc(struct clknode *clk, uint64_t *freq)
|
||||
{
|
||||
struct aw_clk_nm_sc *sc;
|
||||
uint32_t val, m, n;
|
||||
|
||||
sc = clknode_get_softc(clk);
|
||||
|
||||
DEVICE_LOCK(clk);
|
||||
READ4(clk, sc->offset, &val);
|
||||
DEVICE_UNLOCK(clk);
|
||||
|
||||
m = aw_clk_get_factor(val, &sc->m);
|
||||
n = aw_clk_get_factor(val, &sc->n);
|
||||
|
||||
*freq = *freq / n / m;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static clknode_method_t aw_nm_clknode_methods[] = {
|
||||
/* Device interface */
|
||||
CLKNODEMETHOD(clknode_init, aw_clk_nm_init),
|
||||
CLKNODEMETHOD(clknode_set_gate, aw_clk_nm_set_gate),
|
||||
CLKNODEMETHOD(clknode_set_mux, aw_clk_nm_set_mux),
|
||||
CLKNODEMETHOD(clknode_recalc_freq, aw_clk_nm_recalc),
|
||||
CLKNODEMETHOD(clknode_set_freq, aw_clk_nm_set_freq),
|
||||
CLKNODEMETHOD_END
|
||||
};
|
||||
|
||||
DEFINE_CLASS_1(aw_nm_clknode, aw_nm_clknode_class, aw_nm_clknode_methods,
|
||||
sizeof(struct aw_clk_nm_sc), clknode_class);
|
||||
|
||||
int
|
||||
aw_clk_nm_register(struct clkdom *clkdom, struct aw_clk_nm_def *clkdef)
|
||||
{
|
||||
struct clknode *clk;
|
||||
struct aw_clk_nm_sc *sc;
|
||||
|
||||
clk = clknode_create(clkdom, &aw_nm_clknode_class, &clkdef->clkdef);
|
||||
if (clk == NULL)
|
||||
return (1);
|
||||
|
||||
sc = clknode_get_softc(clk);
|
||||
|
||||
sc->offset = clkdef->offset;
|
||||
|
||||
sc->m.shift = clkdef->m.shift;
|
||||
sc->m.width = clkdef->m.width;
|
||||
sc->m.mask = ((1 << sc->m.width) - 1) << sc->m.shift;
|
||||
sc->m.flags = clkdef->m.flags;
|
||||
|
||||
sc->n.shift = clkdef->n.shift;
|
||||
sc->n.width = clkdef->n.width;
|
||||
sc->n.mask = ((1 << sc->n.width) - 1) << sc->n.shift;
|
||||
sc->n.flags = clkdef->n.flags;
|
||||
|
||||
sc->mux_shift = clkdef->mux_shift;
|
||||
sc->mux_mask = ((1 << clkdef->mux_width) - 1) << sc->mux_shift;
|
||||
|
||||
sc->gate_shift = clkdef->gate_shift;
|
||||
|
||||
sc->flags = clkdef->flags;
|
||||
|
||||
clknode_register(clkdom, clk);
|
||||
|
||||
return (0);
|
||||
}
|
50
sys/arm/allwinner/clkng/aw_clk_nm.h
Normal file
50
sys/arm/allwinner/clkng/aw_clk_nm.h
Normal file
@ -0,0 +1,50 @@
|
||||
/*-
|
||||
* Copyright (c) 2017 Emmanuel Vadot <manu@freebsd.org>
|
||||
* 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$
|
||||
*/
|
||||
|
||||
#ifndef __AW_CLK_NM_H__
|
||||
#define __AW_CLK_NM_H__
|
||||
|
||||
#include <dev/extres/clk/clk.h>
|
||||
|
||||
struct aw_clk_nm_def {
|
||||
struct clknode_init_def clkdef;
|
||||
uint32_t offset;
|
||||
|
||||
struct aw_clk_factor m;
|
||||
struct aw_clk_factor n;
|
||||
|
||||
uint32_t mux_shift;
|
||||
uint32_t mux_width;
|
||||
uint32_t gate_shift;
|
||||
|
||||
uint32_t flags;
|
||||
};
|
||||
|
||||
int aw_clk_nm_register(struct clkdom *clkdom, struct aw_clk_nm_def *clkdef);
|
||||
|
||||
#endif /* __AW_CLK_NM_H__ */
|
169
sys/arm/allwinner/clkng/aw_clk_prediv_mux.c
Normal file
169
sys/arm/allwinner/clkng/aw_clk_prediv_mux.c
Normal file
@ -0,0 +1,169 @@
|
||||
/*-
|
||||
* Copyright (c) 2017 Emmanuel Vadot <manu@freebsd.org>
|
||||
* 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 <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/bus.h>
|
||||
|
||||
#include <dev/extres/clk/clk.h>
|
||||
|
||||
#include <arm/allwinner/clkng/aw_clk.h>
|
||||
#include <arm/allwinner/clkng/aw_clk_prediv_mux.h>
|
||||
|
||||
#include "clkdev_if.h"
|
||||
|
||||
/*
|
||||
* clknode for clocks matching the formula :
|
||||
*
|
||||
* clk = clkin / prediv / div
|
||||
*
|
||||
* and where prediv is conditional
|
||||
*
|
||||
*/
|
||||
|
||||
struct aw_clk_prediv_mux_sc {
|
||||
uint32_t offset;
|
||||
|
||||
uint32_t mux_shift;
|
||||
uint32_t mux_mask;
|
||||
|
||||
struct aw_clk_factor div;
|
||||
struct aw_clk_factor prediv;
|
||||
|
||||
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 MODIFY4(_clk, off, clr, set ) \
|
||||
CLKDEV_MODIFY_4(clknode_get_device(_clk), off, clr, set)
|
||||
#define DEVICE_LOCK(_clk) \
|
||||
CLKDEV_DEVICE_LOCK(clknode_get_device(_clk))
|
||||
#define DEVICE_UNLOCK(_clk) \
|
||||
CLKDEV_DEVICE_UNLOCK(clknode_get_device(_clk))
|
||||
|
||||
static int
|
||||
aw_clk_prediv_mux_init(struct clknode *clk, device_t dev)
|
||||
{
|
||||
clknode_init_parent_idx(clk, 0);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
aw_clk_prediv_mux_set_mux(struct clknode *clk, int index)
|
||||
{
|
||||
struct aw_clk_prediv_mux_sc *sc;
|
||||
uint32_t val;
|
||||
|
||||
sc = clknode_get_softc(clk);
|
||||
|
||||
DEVICE_LOCK(clk);
|
||||
READ4(clk, sc->offset, &val);
|
||||
val &= ~sc->mux_mask;
|
||||
val |= index << sc->mux_shift;
|
||||
WRITE4(clk, sc->offset, val);
|
||||
DEVICE_UNLOCK(clk);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
aw_clk_prediv_mux_recalc(struct clknode *clk, uint64_t *freq)
|
||||
{
|
||||
struct aw_clk_prediv_mux_sc *sc;
|
||||
uint32_t val, div, prediv;
|
||||
|
||||
sc = clknode_get_softc(clk);
|
||||
|
||||
DEVICE_LOCK(clk);
|
||||
READ4(clk, sc->offset, &val);
|
||||
DEVICE_UNLOCK(clk);
|
||||
|
||||
div = aw_clk_get_factor(val, &sc->div);
|
||||
prediv = aw_clk_get_factor(val, &sc->prediv);
|
||||
|
||||
*freq = *freq / prediv / div;
|
||||
return (0);
|
||||
}
|
||||
|
||||
static clknode_method_t aw_prediv_mux_clknode_methods[] = {
|
||||
/* Device interface */
|
||||
CLKNODEMETHOD(clknode_init, aw_clk_prediv_mux_init),
|
||||
CLKNODEMETHOD(clknode_set_mux, aw_clk_prediv_mux_set_mux),
|
||||
CLKNODEMETHOD(clknode_recalc_freq, aw_clk_prediv_mux_recalc),
|
||||
CLKNODEMETHOD_END
|
||||
};
|
||||
|
||||
DEFINE_CLASS_1(aw_prediv_mux_clknode, aw_prediv_mux_clknode_class,
|
||||
aw_prediv_mux_clknode_methods, sizeof(struct aw_clk_prediv_mux_sc),
|
||||
clknode_class);
|
||||
|
||||
int
|
||||
aw_clk_prediv_mux_register(struct clkdom *clkdom, struct aw_clk_prediv_mux_def *clkdef)
|
||||
{
|
||||
struct clknode *clk;
|
||||
struct aw_clk_prediv_mux_sc *sc;
|
||||
|
||||
clk = clknode_create(clkdom, &aw_prediv_mux_clknode_class, &clkdef->clkdef);
|
||||
if (clk == NULL)
|
||||
return (1);
|
||||
|
||||
sc = clknode_get_softc(clk);
|
||||
|
||||
sc->offset = clkdef->offset;
|
||||
|
||||
sc->mux_shift = clkdef->mux_shift;
|
||||
sc->mux_mask = ((1 << clkdef->mux_width) - 1) << sc->mux_shift;
|
||||
|
||||
sc->div.shift = clkdef->div.shift;
|
||||
sc->div.mask = ((1 << clkdef->div.width) - 1) << sc->div.shift;
|
||||
sc->div.value = clkdef->div.value;
|
||||
sc->div.cond_shift = clkdef->div.cond_shift;
|
||||
sc->div.cond_mask = ((1 << clkdef->div.cond_width) - 1) << sc->div.shift;
|
||||
sc->div.cond_value = clkdef->div.cond_value;
|
||||
sc->div.flags = clkdef->div.flags;
|
||||
|
||||
sc->prediv.shift = clkdef->prediv.shift;
|
||||
sc->prediv.mask = ((1 << clkdef->prediv.width) - 1) << sc->prediv.shift;
|
||||
sc->prediv.value = clkdef->prediv.value;
|
||||
sc->prediv.cond_shift = clkdef->prediv.cond_shift;
|
||||
sc->prediv.cond_mask = ((1 << clkdef->prediv.cond_width) - 1) << sc->prediv.shift;
|
||||
sc->prediv.cond_value = clkdef->prediv.cond_value;
|
||||
sc->prediv.flags = clkdef->prediv.flags;
|
||||
|
||||
sc->flags = clkdef->flags;
|
||||
|
||||
clknode_register(clkdom, clk);
|
||||
|
||||
return (0);
|
||||
}
|
49
sys/arm/allwinner/clkng/aw_clk_prediv_mux.h
Normal file
49
sys/arm/allwinner/clkng/aw_clk_prediv_mux.h
Normal file
@ -0,0 +1,49 @@
|
||||
/*-
|
||||
* Copyright (c) 2017 Emmanuel Vadot <manu@freebsd.org>
|
||||
* 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$
|
||||
*/
|
||||
|
||||
#ifndef __AW_CLK_PREDIV_MUX_H__
|
||||
#define __AW_CLK_PREDIV_MUX_H__
|
||||
|
||||
#include <arm/allwinner/clkng/aw_clk.h>
|
||||
|
||||
struct aw_clk_prediv_mux_def {
|
||||
struct clknode_init_def clkdef;
|
||||
uint32_t offset;
|
||||
|
||||
uint32_t mux_shift;
|
||||
uint32_t mux_width;
|
||||
|
||||
struct aw_clk_factor div;
|
||||
struct aw_clk_factor prediv;
|
||||
|
||||
uint32_t flags;
|
||||
};
|
||||
|
||||
int aw_clk_prediv_mux_register(struct clkdom *clkdom, struct aw_clk_prediv_mux_def *clkdef);
|
||||
|
||||
#endif /* __AW_CLK_PREDIV_MUX_H__ */
|
475
sys/arm/allwinner/clkng/ccu_h3.c
Normal file
475
sys/arm/allwinner/clkng/ccu_h3.c
Normal file
@ -0,0 +1,475 @@
|
||||
/*-
|
||||
* Copyright (c) 2017 Emmanuel Vadot <manu@freebsd.org>
|
||||
* 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 <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/bus.h>
|
||||
|
||||
#include <dev/extres/clk/clk_div.h>
|
||||
#include <dev/extres/clk/clk_fixed.h>
|
||||
#include <dev/extres/clk/clk_mux.h>
|
||||
|
||||
#include <arm/allwinner/clkng/aw_ccung.h>
|
||||
#include <arm/allwinner/clkng/aw_clk.h>
|
||||
#include <arm/allwinner/clkng/aw_clk_nm.h>
|
||||
#include <arm/allwinner/clkng/aw_clk_nkmp.h>
|
||||
#include <arm/allwinner/clkng/aw_clk_prediv_mux.h>
|
||||
|
||||
#include "ccu_h3.h"
|
||||
|
||||
static struct aw_ccung_reset h3_ccu_resets[] = {
|
||||
CCU_RESET(H3_RST_USB_PHY0, 0xcc, 0)
|
||||
CCU_RESET(H3_RST_USB_PHY1, 0xcc, 1)
|
||||
CCU_RESET(H3_RST_USB_PHY2, 0xcc, 2)
|
||||
CCU_RESET(H3_RST_USB_PHY3, 0xcc, 3)
|
||||
|
||||
CCU_RESET(H3_RST_MBUS, 0xfc, 31)
|
||||
|
||||
CCU_RESET(H3_RST_BUS_CE, 0x2c0, 5)
|
||||
CCU_RESET(H3_RST_BUS_DMA, 0x2c0, 6)
|
||||
CCU_RESET(H3_RST_BUS_MMC0, 0x2c0, 8)
|
||||
CCU_RESET(H3_RST_BUS_MMC1, 0x2c0, 9)
|
||||
CCU_RESET(H3_RST_BUS_MMC2, 0x2c0, 10)
|
||||
CCU_RESET(H3_RST_BUS_NAND, 0x2c0, 13)
|
||||
CCU_RESET(H3_RST_BUS_DRAM, 0x2c0, 14)
|
||||
CCU_RESET(H3_RST_BUS_EMAC, 0x2c0, 17)
|
||||
CCU_RESET(H3_RST_BUS_TS, 0x2c0, 18)
|
||||
CCU_RESET(H3_RST_BUS_HSTIMER, 0x2c0, 19)
|
||||
CCU_RESET(H3_RST_BUS_SPI0, 0x2c0, 20)
|
||||
CCU_RESET(H3_RST_BUS_SPI1, 0x2c0, 21)
|
||||
CCU_RESET(H3_RST_BUS_OTG, 0x2c0, 23)
|
||||
CCU_RESET(H3_RST_BUS_EHCI0, 0x2c0, 24)
|
||||
CCU_RESET(H3_RST_BUS_EHCI1, 0x2c0, 25)
|
||||
CCU_RESET(H3_RST_BUS_EHCI2, 0x2c0, 26)
|
||||
CCU_RESET(H3_RST_BUS_EHCI3, 0x2c0, 27)
|
||||
CCU_RESET(H3_RST_BUS_OHCI0, 0x2c0, 28)
|
||||
CCU_RESET(H3_RST_BUS_OHCI1, 0x2c0, 29)
|
||||
CCU_RESET(H3_RST_BUS_OHCI2, 0x2c0, 30)
|
||||
CCU_RESET(H3_RST_BUS_OHCI3, 0x2c0, 31)
|
||||
|
||||
CCU_RESET(H3_RST_BUS_VE, 0x2c4, 0)
|
||||
CCU_RESET(H3_RST_BUS_TCON0, 0x2c4, 3)
|
||||
CCU_RESET(H3_RST_BUS_TCON1, 0x2c4, 4)
|
||||
CCU_RESET(H3_RST_BUS_DEINTERLACE, 0x2c4, 5)
|
||||
CCU_RESET(H3_RST_BUS_CSI, 0x2c4, 8)
|
||||
CCU_RESET(H3_RST_BUS_TVE, 0x2c4, 9)
|
||||
CCU_RESET(H3_RST_BUS_HDMI0, 0x2c4, 10)
|
||||
CCU_RESET(H3_RST_BUS_HDMI1, 0x2c4, 11)
|
||||
CCU_RESET(H3_RST_BUS_DE, 0x2c4, 12)
|
||||
CCU_RESET(H3_RST_BUS_GPU, 0x2c4, 20)
|
||||
CCU_RESET(H3_RST_BUS_MSGBOX, 0x2c4, 21)
|
||||
CCU_RESET(H3_RST_BUS_SPINLOCK, 0x2c4, 22)
|
||||
CCU_RESET(H3_RST_BUS_DBG, 0x2c4, 31)
|
||||
|
||||
CCU_RESET(H3_RST_BUS_EPHY, 0x2c8, 2)
|
||||
|
||||
CCU_RESET(H3_RST_BUS_CODEC, 0x2d0, 0)
|
||||
CCU_RESET(H3_RST_BUS_SPDIF, 0x2d0, 1)
|
||||
CCU_RESET(H3_RST_BUS_THS, 0x2d0, 8)
|
||||
CCU_RESET(H3_RST_BUS_I2S0, 0x2d0, 12)
|
||||
CCU_RESET(H3_RST_BUS_I2S1, 0x2d0, 13)
|
||||
CCU_RESET(H3_RST_BUS_I2S2, 0x2d0, 14)
|
||||
|
||||
CCU_RESET(H3_RST_BUS_I2C0, 0x2d8, 0)
|
||||
CCU_RESET(H3_RST_BUS_I2C1, 0x2d8, 1)
|
||||
CCU_RESET(H3_RST_BUS_I2C2, 0x2d8, 2)
|
||||
CCU_RESET(H3_RST_BUS_UART0, 0x2d8, 16)
|
||||
CCU_RESET(H3_RST_BUS_UART1, 0x2d8, 17)
|
||||
CCU_RESET(H3_RST_BUS_UART2, 0x2d8, 18)
|
||||
CCU_RESET(H3_RST_BUS_UART3, 0x2d8, 19)
|
||||
CCU_RESET(H3_RST_BUS_SCR, 0x2d8, 20)
|
||||
};
|
||||
|
||||
static struct aw_ccung_gate h3_ccu_gates[] = {
|
||||
CCU_GATE(H3_CLK_BUS_CE, "bus-ce", "ahb1", 0x60, 5)
|
||||
CCU_GATE(H3_CLK_BUS_DMA, "bus-dma", "ahb1", 0x60, 6)
|
||||
CCU_GATE(H3_CLK_BUS_MMC0, "bus-mmc0", "ahb1", 0x60, 8)
|
||||
CCU_GATE(H3_CLK_BUS_MMC1, "bus-mmc1", "ahb1", 0x60, 9)
|
||||
CCU_GATE(H3_CLK_BUS_MMC2, "bus-mmc2", "ahb1", 0x60, 10)
|
||||
CCU_GATE(H3_CLK_BUS_NAND, "bus-nand", "ahb1", 0x60, 13)
|
||||
CCU_GATE(H3_CLK_BUS_DRAM, "bus-dram", "ahb1", 0x60, 14)
|
||||
CCU_GATE(H3_CLK_BUS_EMAC, "bus-emac", "ahb2", 0x60, 17)
|
||||
CCU_GATE(H3_CLK_BUS_TS, "bus-ts", "ahb1", 0x60, 18)
|
||||
CCU_GATE(H3_CLK_BUS_HSTIMER, "bus-hstimer", "ahb1", 0x60, 19)
|
||||
CCU_GATE(H3_CLK_BUS_SPI0, "bus-spi0", "ahb1", 0x60, 20)
|
||||
CCU_GATE(H3_CLK_BUS_SPI1, "bus-spi1", "ahb1", 0x60, 21)
|
||||
CCU_GATE(H3_CLK_BUS_OTG, "bus-otg", "ahb1", 0x60, 23)
|
||||
CCU_GATE(H3_CLK_BUS_EHCI0, "bus-ehci0", "ahb1", 0x60, 24)
|
||||
CCU_GATE(H3_CLK_BUS_EHCI1, "bus-ehci1", "ahb2", 0x60, 25)
|
||||
CCU_GATE(H3_CLK_BUS_EHCI2, "bus-ehci2", "ahb2", 0x60, 26)
|
||||
CCU_GATE(H3_CLK_BUS_EHCI3, "bus-ehci3", "ahb2", 0x60, 27)
|
||||
CCU_GATE(H3_CLK_BUS_OHCI0, "bus-ohci0", "ahb1", 0x60, 28)
|
||||
CCU_GATE(H3_CLK_BUS_OHCI1, "bus-ohci1", "ahb2", 0x60, 29)
|
||||
CCU_GATE(H3_CLK_BUS_OHCI2, "bus-ohci2", "ahb2", 0x60, 30)
|
||||
CCU_GATE(H3_CLK_BUS_OHCI3, "bus-ohci3", "ahb2", 0x60, 31)
|
||||
|
||||
CCU_GATE(H3_CLK_BUS_VE, "bus-ve", "ahb1", 0x64, 0)
|
||||
CCU_GATE(H3_CLK_BUS_TCON0, "bus-tcon0", "ahb1", 0x64, 3)
|
||||
CCU_GATE(H3_CLK_BUS_TCON1, "bus-tcon1", "ahb1", 0x64, 4)
|
||||
CCU_GATE(H3_CLK_BUS_DEINTERLACE, "bus-deinterlace", "ahb1", 0x64, 5)
|
||||
CCU_GATE(H3_CLK_BUS_CSI, "bus-csi", "ahb1", 0x64, 8)
|
||||
CCU_GATE(H3_CLK_BUS_TVE, "bus-tve", "ahb1", 0x64, 9)
|
||||
CCU_GATE(H3_CLK_BUS_HDMI, "bus-hdmi", "ahb1", 0x64, 11)
|
||||
CCU_GATE(H3_CLK_BUS_DE, "bus-de", "ahb1", 0x64, 12)
|
||||
CCU_GATE(H3_CLK_BUS_GPU, "bus-gpu", "ahb1", 0x64, 20)
|
||||
CCU_GATE(H3_CLK_BUS_MSGBOX, "bus-msgbox", "ahb1", 0x64, 21)
|
||||
CCU_GATE(H3_CLK_BUS_SPINLOCK, "bus-spinlock", "ahb1", 0x64, 22)
|
||||
|
||||
CCU_GATE(H3_CLK_BUS_CODEC, "bus-codec", "apb1", 0x68, 0)
|
||||
CCU_GATE(H3_CLK_BUS_SPDIF, "bus-spdif", "apb1", 0x68, 1)
|
||||
CCU_GATE(H3_CLK_BUS_PIO, "bus-pio", "apb1", 0x68, 5)
|
||||
CCU_GATE(H3_CLK_BUS_THS, "bus-ths", "apb1", 0x68, 8)
|
||||
CCU_GATE(H3_CLK_BUS_I2S0, "bus-i2c0", "apb1", 0x68, 12)
|
||||
CCU_GATE(H3_CLK_BUS_I2S1, "bus-i2c1", "apb1", 0x68, 13)
|
||||
CCU_GATE(H3_CLK_BUS_I2S2, "bus-i2c2", "apb1", 0x68, 14)
|
||||
|
||||
CCU_GATE(H3_CLK_BUS_I2C0, "bus-i2c0", "apb2", 0x6c, 0)
|
||||
CCU_GATE(H3_CLK_BUS_I2C1, "bus-i2c1", "apb2", 0x6c, 1)
|
||||
CCU_GATE(H3_CLK_BUS_I2C2, "bus-i2c2", "apb2", 0x6c, 2)
|
||||
CCU_GATE(H3_CLK_BUS_UART0, "bus-uart0", "apb2", 0x6c, 16)
|
||||
CCU_GATE(H3_CLK_BUS_UART1, "bus-uart1", "apb2", 0x6c, 17)
|
||||
CCU_GATE(H3_CLK_BUS_UART2, "bus-uart2", "apb2", 0x6c, 18)
|
||||
CCU_GATE(H3_CLK_BUS_UART3, "bus-uart3", "apb2", 0x6c, 19)
|
||||
CCU_GATE(H3_CLK_BUS_SCR, "bus-scr", "apb2", 0x6c, 20)
|
||||
|
||||
CCU_GATE(H3_CLK_BUS_EPHY, "bus-ephy", "ahb1", 0x70, 0)
|
||||
CCU_GATE(H3_CLK_BUS_DBG, "bus-dbg", "ahb1", 0x70, 7)
|
||||
|
||||
CCU_GATE(H3_CLK_USBPHY0, "usb-phy0", "osc24M", 0xcc, 8)
|
||||
CCU_GATE(H3_CLK_USBPHY1, "usb-phy1", "osc24M", 0xcc, 9)
|
||||
CCU_GATE(H3_CLK_USBPHY2, "usb-phy2", "osc24M", 0xcc, 10)
|
||||
CCU_GATE(H3_CLK_USBPHY3, "usb-phy3", "osc24M", 0xcc, 11)
|
||||
CCU_GATE(H3_CLK_USBOHCI0, "usb-ohci0", "osc24M", 0xcc, 16)
|
||||
CCU_GATE(H3_CLK_USBOHCI1, "usb-ohci1", "osc24M", 0xcc, 17)
|
||||
CCU_GATE(H3_CLK_USBOHCI2, "usb-ohci2", "osc24M", 0xcc, 18)
|
||||
CCU_GATE(H3_CLK_USBOHCI3, "usb-ohci3", "osc24M", 0xcc, 19)
|
||||
|
||||
CCU_GATE(H3_CLK_THS, "ths", "thsdiv", 0x74, 31)
|
||||
CCU_GATE(H3_CLK_I2S0, "i2s0", "i2s0mux", 0xB0, 31)
|
||||
CCU_GATE(H3_CLK_I2S1, "i2s1", "i2s1mux", 0xB4, 31)
|
||||
CCU_GATE(H3_CLK_I2S2, "i2s2", "i2s2mux", 0xB8, 31)
|
||||
};
|
||||
|
||||
static const char *pll_cpux_parents[] = {"osc24M"};
|
||||
static const char *pll_audio_parents[] = {"osc24M"};
|
||||
static const char *pll_audio_mult_parents[] = {"pll_audio"};
|
||||
/*
|
||||
* Need fractional mode on nkmp or a NM fract
|
||||
static const char *pll_video_parents[] = {"osc24M"};
|
||||
*/
|
||||
/*
|
||||
* Need fractional mode on nkmp or a NM fract
|
||||
static const char *pll_ve_parents[] = {"osc24M"};
|
||||
*/
|
||||
/*
|
||||
* Needs a update bit on nkmp or special clk
|
||||
static const char *pll_ddr_parents[] = {"osc24M"};
|
||||
*/
|
||||
static const char *pll_periph0_parents[] = {"osc24M"};
|
||||
static const char *pll_periph0_2x_parents[] = {"pll_periph0"};
|
||||
/*
|
||||
* Need fractional mode on nkmp or a NM fract
|
||||
static const char *pll_gpu_parents[] = {"osc24M"};
|
||||
*/
|
||||
static const char *pll_periph1_parents[] = {"osc24M"};
|
||||
/*
|
||||
* Need fractional mode on nkmp or a NM fract
|
||||
static const char *pll_de_parents[] = {"osc24M"};
|
||||
*/
|
||||
|
||||
static struct aw_clk_nkmp_def nkmp_clks[] = {
|
||||
NKMP_CLK(H3_CLK_PLL_CPUX, /* id */
|
||||
"pll_cpux", pll_cpux_parents, /* name, parents */
|
||||
0x00, /* offset */
|
||||
8, 5, 0, 0, /* n factor */
|
||||
4, 2, 0, 0, /* k factor */
|
||||
0, 2, 0, 0, /* m factor */
|
||||
16, 2, 0, AW_CLK_FACTOR_POWER_OF_TWO, /* p factor */
|
||||
31, /* gate */
|
||||
28, 1000, /* lock */
|
||||
AW_CLK_HAS_GATE | AW_CLK_HAS_LOCK | AW_CLK_SCALE_CHANGE) /* flags */
|
||||
NKMP_CLK(H3_CLK_PLL_AUDIO, /* id */
|
||||
"pll_audio", pll_audio_parents, /* name, parents */
|
||||
0x08, /* offset */
|
||||
8, 7, 0, 0, /* n factor */
|
||||
0, 0, 1, AW_CLK_FACTOR_FIXED, /* k factor (fake) */
|
||||
0, 5, 0, 0, /* m factor */
|
||||
16, 4, 0, 0, /* p factor */
|
||||
31, /* gate */
|
||||
28, 1000, /* lock */
|
||||
AW_CLK_HAS_GATE | AW_CLK_HAS_LOCK) /* flags */
|
||||
NKMP_CLK(H3_CLK_PLL_PERIPH0, /* id */
|
||||
"pll_periph0", pll_periph0_parents, /* name, parents */
|
||||
0x28, /* offset */
|
||||
8, 5, 0, 0, /* n factor */
|
||||
4, 2, 0, 0, /* k factor */
|
||||
0, 0, 2, AW_CLK_FACTOR_FIXED, /* m factor (fake) */
|
||||
0, 0, 1, AW_CLK_FACTOR_FIXED, /* p factor (fake) */
|
||||
31, /* gate */
|
||||
28, 1000, /* lock */
|
||||
AW_CLK_HAS_GATE | AW_CLK_HAS_LOCK) /* flags */
|
||||
NKMP_CLK(H3_CLK_PLL_PERIPH1, /* id */
|
||||
"pll_periph1", pll_periph1_parents, /* name, parents */
|
||||
0x44, /* offset */
|
||||
8, 5, 0, 0, /* n factor */
|
||||
4, 2, 0, 0, /* k factor */
|
||||
0, 0, 2, AW_CLK_FACTOR_FIXED, /* m factor (fake) */
|
||||
0, 0, 1, AW_CLK_FACTOR_FIXED, /* p factor (fake) */
|
||||
31, /* gate */
|
||||
28, 1000, /* lock */
|
||||
AW_CLK_HAS_GATE | AW_CLK_HAS_LOCK) /* flags */
|
||||
};
|
||||
|
||||
static const char *ahb1_parents[] = {"osc32k", "osc24M", "axi", "pll_periph0"};
|
||||
static const char *ahb2_parents[] = {"ahb1", "pll_periph0"};
|
||||
|
||||
static struct aw_clk_prediv_mux_def prediv_mux_clks[] = {
|
||||
PREDIV_CLK(H3_CLK_AHB1, /* id */
|
||||
"ahb1", ahb1_parents, /* name, parents */
|
||||
0x54, /* offset */
|
||||
12, 2, /* mux */
|
||||
4, 2, 0, AW_CLK_FACTOR_POWER_OF_TWO, /* div */
|
||||
6, 2, 0, AW_CLK_FACTOR_HAS_COND, /* prediv */
|
||||
12, 2, 3) /* prediv condition */
|
||||
PREDIV_CLK(H3_CLK_AHB2, /* id */
|
||||
"ahb2", ahb2_parents, /* name, parents */
|
||||
0x5c, /* offset */
|
||||
0, 2, /* mux */
|
||||
0, 0, 1, AW_CLK_FACTOR_FIXED, /* div */
|
||||
0, 0, 2, AW_CLK_FACTOR_HAS_COND | AW_CLK_FACTOR_FIXED, /* prediv */
|
||||
0, 2, 1) /* prediv condition */
|
||||
};
|
||||
|
||||
static const char *apb2_parents[] = {"osc32k", "osc24M", "pll_periph0", "pll_periph0"};
|
||||
static const char *mod_parents[] = {"osc24M", "pll_periph0", "pll_periph1"};
|
||||
static const char *ts_parents[] = {"osc24M", "pll_periph0"};
|
||||
static const char *spdif_parents[] = {"pll_audio"};
|
||||
static const char *i2s_parents[] = {"pll_audio-8x", "pll_audio-4x", "pll_audio-2x", "pll_audio"};
|
||||
|
||||
static struct aw_clk_nm_def nm_clks[] = {
|
||||
NM_CLK(H3_CLK_APB2, /* id */
|
||||
"apb2", apb2_parents, /* name, parents */
|
||||
0x58, /* offset */
|
||||
16, 2, 0, AW_CLK_FACTOR_POWER_OF_TWO, /* n factor */
|
||||
0, 5, 0, 0, /* m factor */
|
||||
24, 2, /* mux */
|
||||
0, /* gate */
|
||||
AW_CLK_HAS_MUX)
|
||||
NM_CLK(H3_CLK_NAND, "nand", mod_parents, /* id, name, parents */
|
||||
0x80, /* offset */
|
||||
16, 2, 0, AW_CLK_FACTOR_POWER_OF_TWO, /* n factor */
|
||||
0, 4, 0, 0, /* m factor */
|
||||
24, 2, /* mux */
|
||||
31, /* gate */
|
||||
AW_CLK_HAS_GATE | AW_CLK_HAS_MUX) /* flags */
|
||||
NM_CLK(H3_CLK_MMC0, "mmc0", mod_parents, /* id, name, parents */
|
||||
0x88, /* offset */
|
||||
16, 2, 0, AW_CLK_FACTOR_POWER_OF_TWO, /* n factor */
|
||||
0, 4, 0, 0, /* m factor */
|
||||
24, 2, /* mux */
|
||||
31, /* gate */
|
||||
AW_CLK_HAS_GATE | AW_CLK_HAS_MUX |
|
||||
AW_CLK_REPARENT) /* flags */
|
||||
NM_CLK(H3_CLK_MMC1, "mmc1", mod_parents, /* id, name, parents */
|
||||
0x8c, /* offset */
|
||||
16, 2, 0, AW_CLK_FACTOR_POWER_OF_TWO, /* n factor */
|
||||
0, 4, 0, 0, /* m factor */
|
||||
24, 2, /* mux */
|
||||
31, /* gate */
|
||||
AW_CLK_HAS_GATE | AW_CLK_HAS_MUX |
|
||||
AW_CLK_REPARENT) /* flags */
|
||||
NM_CLK(H3_CLK_MMC2, "mmc2", mod_parents, /* id, name, parents */
|
||||
0x90, /* offset */
|
||||
16, 2, 0, AW_CLK_FACTOR_POWER_OF_TWO, /* n factor */
|
||||
0, 4, 0, 0, /* m factor */
|
||||
24, 2, /* mux */
|
||||
31, /* gate */
|
||||
AW_CLK_HAS_GATE | AW_CLK_HAS_MUX |
|
||||
AW_CLK_REPARENT) /* flags */
|
||||
NM_CLK(H3_CLK_TS, "ts", ts_parents, /* id, name, parents */
|
||||
0x98, /* offset */
|
||||
16, 2, 0, AW_CLK_FACTOR_POWER_OF_TWO, /* n factor */
|
||||
0, 4, 0, 0, /* m factor */
|
||||
24, 2, /* mux */
|
||||
31, /* gate */
|
||||
AW_CLK_HAS_GATE | AW_CLK_HAS_MUX) /* flags */
|
||||
NM_CLK(H3_CLK_CE, "ce", mod_parents, /* id, name, parents */
|
||||
0x9C, /* offset */
|
||||
16, 2, 0, AW_CLK_FACTOR_POWER_OF_TWO, /* n factor */
|
||||
0, 4, 0, 0, /* m factor */
|
||||
24, 2, /* mux */
|
||||
31, /* gate */
|
||||
AW_CLK_HAS_GATE | AW_CLK_HAS_MUX) /* flags */
|
||||
NM_CLK(H3_CLK_SPI0, "spi0", mod_parents, /* id, name, parents */
|
||||
0xA0, /* offset */
|
||||
16, 2, 0, AW_CLK_FACTOR_POWER_OF_TWO, /* n factor */
|
||||
0, 4, 0, 0, /* m factor */
|
||||
24, 2, /* mux */
|
||||
31, /* gate */
|
||||
AW_CLK_HAS_GATE | AW_CLK_HAS_MUX |
|
||||
AW_CLK_REPARENT) /* flags */
|
||||
NM_CLK(H3_CLK_SPI1, "spi1", mod_parents, /* id, name, parents */
|
||||
0xA4, /* offset */
|
||||
16, 2, 0, AW_CLK_FACTOR_POWER_OF_TWO, /* n factor */
|
||||
0, 4, 0, 0, /* m factor */
|
||||
24, 2, /* mux */
|
||||
31, /* gate */
|
||||
AW_CLK_HAS_GATE | AW_CLK_HAS_MUX |
|
||||
AW_CLK_REPARENT) /* flags */
|
||||
NM_CLK(H3_CLK_SPDIF, "spdif", spdif_parents, /* id, name, parents */
|
||||
0xC0, /* offset */
|
||||
0, 0, 1, AW_CLK_FACTOR_FIXED, /* n factor (fake) */
|
||||
0, 4, 0, 0, /* m factor */
|
||||
0, 0, /* mux */
|
||||
31, /* gate */
|
||||
AW_CLK_HAS_GATE) /* flags */
|
||||
|
||||
};
|
||||
|
||||
static const char *cpux_parents[] = {"osc32k", "osc24M", "pll_cpux", "pll_cpux"};
|
||||
|
||||
static struct clk_mux_def mux_clks[] = {
|
||||
MUX_CLK(H3_CLK_CPUX, /* id */
|
||||
"cpux", cpux_parents, /* name, parents */
|
||||
0x50, 16, 2) /* offset, shift, width */
|
||||
MUX_CLK(0,
|
||||
"i2s0mux", i2s_parents,
|
||||
0xb0, 16, 2)
|
||||
MUX_CLK(0,
|
||||
"i2s1mux", i2s_parents,
|
||||
0xb4, 16, 2)
|
||||
MUX_CLK(0,
|
||||
"i2s2mux", i2s_parents,
|
||||
0xb8, 16, 2)
|
||||
};
|
||||
|
||||
static struct clk_div_table apb1_div_table[] = {
|
||||
{ .value = 0, .divider = 2, },
|
||||
{ .value = 1, .divider = 2, },
|
||||
{ .value = 2, .divider = 4, },
|
||||
{ .value = 3, .divider = 8, },
|
||||
{ },
|
||||
};
|
||||
|
||||
static struct clk_div_table ths_div_table[] = {
|
||||
{ .value = 0, .divider = 1, },
|
||||
{ .value = 1, .divider = 2, },
|
||||
{ .value = 2, .divider = 4, },
|
||||
{ .value = 3, .divider = 6, },
|
||||
{ },
|
||||
};
|
||||
|
||||
static const char *ths_parents[] = {"osc24M"};
|
||||
static const char *axi_parents[] = {"cpux"};
|
||||
static const char *apb1_parents[] = {"ahb1"};
|
||||
|
||||
static struct clk_div_def div_clks[] = {
|
||||
DIV_CLK(H3_CLK_AXI, /* id */
|
||||
"axi", axi_parents, /* name, parents */
|
||||
0x50, /* offset */
|
||||
0, 2, /* shift, width */
|
||||
0, NULL) /* flags, div table */
|
||||
DIV_CLK(H3_CLK_APB1, /* id */
|
||||
"apb1", apb1_parents, /* name, parents */
|
||||
0x54, /* offset */
|
||||
8, 2, /* shift, width */
|
||||
CLK_DIV_WITH_TABLE, /* flags */
|
||||
apb1_div_table) /* div table */
|
||||
DIV_CLK(0, /* id */
|
||||
"thsdiv", ths_parents, /* name, parents */
|
||||
0x74, /* offset */
|
||||
0, 2, /* shift, width */
|
||||
CLK_DIV_WITH_TABLE, /* flags */
|
||||
ths_div_table) /* div table */
|
||||
};
|
||||
|
||||
static struct clk_fixed_def fixed_factor_clks[] = {
|
||||
FIXED_CLK(H3_CLK_PLL_PERIPH0_2X, /* id */
|
||||
"pll_periph0-2x", /* name */
|
||||
pll_periph0_2x_parents, /* parent */
|
||||
0, /* freq */
|
||||
2, /* mult */
|
||||
1, /* div */
|
||||
0) /* flags */
|
||||
FIXED_CLK(H3_CLK_PLL_AUDIO_2X, /* id */
|
||||
"pll_audio-2x", /* name */
|
||||
pll_audio_mult_parents, /* parent */
|
||||
0, /* freq */
|
||||
2, /* mult */
|
||||
1, /* div */
|
||||
0) /* flags */
|
||||
FIXED_CLK(H3_CLK_PLL_AUDIO_4X, /* id */
|
||||
"pll_audio-4x", /* name */
|
||||
pll_audio_mult_parents, /* parent */
|
||||
0, /* freq */
|
||||
4, /* mult */
|
||||
1, /* div */
|
||||
0) /* flags */
|
||||
FIXED_CLK(H3_CLK_PLL_AUDIO_8X, /* id */
|
||||
"pll_audio-8x", /* name */
|
||||
pll_audio_mult_parents, /* parent */
|
||||
0, /* freq */
|
||||
8, /* mult */
|
||||
1, /* div */
|
||||
0) /* flags */
|
||||
};
|
||||
|
||||
static struct aw_clk_init init_clks[] = {
|
||||
{"ahb1", "pll_periph0", 0, false},
|
||||
{"ahb2", "pll_periph0", 0, false},
|
||||
};
|
||||
|
||||
void
|
||||
ccu_h3_register_clocks(struct aw_ccung_softc *sc)
|
||||
{
|
||||
int i;
|
||||
|
||||
sc->resets = h3_ccu_resets;
|
||||
sc->nresets = nitems(h3_ccu_resets);
|
||||
sc->gates = h3_ccu_gates;
|
||||
sc->ngates = nitems(h3_ccu_gates);
|
||||
sc->clk_init = init_clks;
|
||||
sc->n_clk_init = nitems(init_clks);
|
||||
|
||||
for (i = 0; i < nitems(nkmp_clks); i++)
|
||||
aw_clk_nkmp_register(sc->clkdom, &nkmp_clks[i]);
|
||||
for (i = 0; i < nitems(nm_clks); i++)
|
||||
aw_clk_nm_register(sc->clkdom, &nm_clks[i]);
|
||||
for (i = 0; i < nitems(prediv_mux_clks); i++)
|
||||
aw_clk_prediv_mux_register(sc->clkdom, &prediv_mux_clks[i]);
|
||||
|
||||
for (i = 0; i < nitems(mux_clks); i++)
|
||||
clknode_mux_register(sc->clkdom, &mux_clks[i]);
|
||||
for (i = 0; i < nitems(div_clks); i++)
|
||||
clknode_div_register(sc->clkdom, &div_clks[i]);
|
||||
for (i = 0; i < nitems(fixed_factor_clks); i++)
|
||||
clknode_fixed_register(sc->clkdom, &fixed_factor_clks[i]);
|
||||
}
|
189
sys/arm/allwinner/clkng/ccu_h3.h
Normal file
189
sys/arm/allwinner/clkng/ccu_h3.h
Normal file
@ -0,0 +1,189 @@
|
||||
/*-
|
||||
* Copyright (c) 2017 Emmanuel Vadot <manu@freebsd.org>
|
||||
* 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$
|
||||
*/
|
||||
|
||||
#ifndef __CCU_H3_H__
|
||||
#define __CCU_H3_H__
|
||||
|
||||
#define H3_RST_USB_PHY0 0
|
||||
#define H3_RST_USB_PHY1 1
|
||||
#define H3_RST_USB_PHY2 2
|
||||
#define H3_RST_USB_PHY3 3
|
||||
#define H3_RST_MBUS 4
|
||||
#define H3_RST_BUS_CE 5
|
||||
#define H3_RST_BUS_DMA 6
|
||||
#define H3_RST_BUS_MMC0 7
|
||||
#define H3_RST_BUS_MMC1 8
|
||||
#define H3_RST_BUS_MMC2 9
|
||||
#define H3_RST_BUS_NAND 10
|
||||
#define H3_RST_BUS_DRAM 11
|
||||
#define H3_RST_BUS_EMAC 12
|
||||
#define H3_RST_BUS_TS 13
|
||||
#define H3_RST_BUS_HSTIMER 14
|
||||
#define H3_RST_BUS_SPI0 15
|
||||
#define H3_RST_BUS_SPI1 16
|
||||
#define H3_RST_BUS_OTG 17
|
||||
#define H3_RST_BUS_EHCI0 18
|
||||
#define H3_RST_BUS_EHCI1 19
|
||||
#define H3_RST_BUS_EHCI2 20
|
||||
#define H3_RST_BUS_EHCI3 21
|
||||
#define H3_RST_BUS_OHCI0 22
|
||||
#define H3_RST_BUS_OHCI1 23
|
||||
#define H3_RST_BUS_OHCI2 24
|
||||
#define H3_RST_BUS_OHCI3 25
|
||||
#define H3_RST_BUS_VE 26
|
||||
#define H3_RST_BUS_TCON0 27
|
||||
#define H3_RST_BUS_TCON1 28
|
||||
#define H3_RST_BUS_DEINTERLACE 29
|
||||
#define H3_RST_BUS_CSI 30
|
||||
#define H3_RST_BUS_TVE 31
|
||||
#define H3_RST_BUS_HDMI0 32
|
||||
#define H3_RST_BUS_HDMI1 33
|
||||
#define H3_RST_BUS_DE 34
|
||||
#define H3_RST_BUS_GPU 35
|
||||
#define H3_RST_BUS_MSGBOX 36
|
||||
#define H3_RST_BUS_SPINLOCK 37
|
||||
#define H3_RST_BUS_DBG 38
|
||||
#define H3_RST_BUS_EPHY 39
|
||||
#define H3_RST_BUS_CODEC 40
|
||||
#define H3_RST_BUS_SPDIF 41
|
||||
#define H3_RST_BUS_THS 42
|
||||
#define H3_RST_BUS_I2S0 43
|
||||
#define H3_RST_BUS_I2S1 44
|
||||
#define H3_RST_BUS_I2S2 45
|
||||
#define H3_RST_BUS_I2C0 46
|
||||
#define H3_RST_BUS_I2C1 47
|
||||
#define H3_RST_BUS_I2C2 48
|
||||
#define H3_RST_BUS_UART0 49
|
||||
#define H3_RST_BUS_UART1 50
|
||||
#define H3_RST_BUS_UART2 51
|
||||
#define H3_RST_BUS_UART3 52
|
||||
#define H3_RST_BUS_SCR 53
|
||||
|
||||
#define H3_CLK_PLL_CPUX 0
|
||||
#define H3_CLK_PLL_AUDIO_BASE 1
|
||||
#define H3_CLK_PLL_AUDIO 2
|
||||
#define H3_CLK_PLL_AUDIO_2X 3
|
||||
#define H3_CLK_PLL_AUDIO_4X 4
|
||||
#define H3_CLK_PLL_AUDIO_8X 5
|
||||
#define H3_CLK_PLL_VIDEO 6
|
||||
#define H3_CLK_PLL_VE 7
|
||||
#define H3_CLK_PLL_DDR 8
|
||||
#define H3_CLK_PLL_PERIPH0 9
|
||||
#define H3_CLK_PLL_PERIPH0_2X 10
|
||||
#define H3_CLK_PLL_GPU 11
|
||||
#define H3_CLK_PLL_PERIPH1 12
|
||||
#define H3_CLK_PLL_DE 13
|
||||
|
||||
#define H3_CLK_CPUX 14
|
||||
#define H3_CLK_AXI 15
|
||||
#define H3_CLK_AHB1 16
|
||||
#define H3_CLK_APB1 17
|
||||
#define H3_CLK_APB2 18
|
||||
#define H3_CLK_AHB2 19
|
||||
|
||||
#define H3_CLK_BUS_CE 20
|
||||
#define H3_CLK_BUS_DMA 21
|
||||
#define H3_CLK_BUS_MMC0 22
|
||||
#define H3_CLK_BUS_MMC1 23
|
||||
#define H3_CLK_BUS_MMC2 24
|
||||
#define H3_CLK_BUS_NAND 25
|
||||
#define H3_CLK_BUS_DRAM 26
|
||||
#define H3_CLK_BUS_EMAC 27
|
||||
#define H3_CLK_BUS_TS 28
|
||||
#define H3_CLK_BUS_HSTIMER 29
|
||||
#define H3_CLK_BUS_SPI0 30
|
||||
#define H3_CLK_BUS_SPI1 31
|
||||
#define H3_CLK_BUS_OTG 32
|
||||
#define H3_CLK_BUS_EHCI0 33
|
||||
#define H3_CLK_BUS_EHCI1 34
|
||||
#define H3_CLK_BUS_EHCI2 35
|
||||
#define H3_CLK_BUS_EHCI3 36
|
||||
#define H3_CLK_BUS_OHCI0 37
|
||||
#define H3_CLK_BUS_OHCI1 38
|
||||
#define H3_CLK_BUS_OHCI2 39
|
||||
#define H3_CLK_BUS_OHCI3 40
|
||||
#define H3_CLK_BUS_VE 41
|
||||
#define H3_CLK_BUS_TCON0 42
|
||||
#define H3_CLK_BUS_TCON1 43
|
||||
#define H3_CLK_BUS_DEINTERLACE 44
|
||||
#define H3_CLK_BUS_CSI 45
|
||||
#define H3_CLK_BUS_TVE 46
|
||||
#define H3_CLK_BUS_HDMI 47
|
||||
#define H3_CLK_BUS_DE 48
|
||||
#define H3_CLK_BUS_GPU 49
|
||||
#define H3_CLK_BUS_MSGBOX 50
|
||||
#define H3_CLK_BUS_SPINLOCK 51
|
||||
#define H3_CLK_BUS_CODEC 52
|
||||
#define H3_CLK_BUS_SPDIF 53
|
||||
#define H3_CLK_BUS_PIO 54
|
||||
#define H3_CLK_BUS_THS 55
|
||||
#define H3_CLK_BUS_I2S0 56
|
||||
#define H3_CLK_BUS_I2S1 57
|
||||
#define H3_CLK_BUS_I2S2 58
|
||||
#define H3_CLK_BUS_I2C0 59
|
||||
#define H3_CLK_BUS_I2C1 60
|
||||
#define H3_CLK_BUS_I2C2 61
|
||||
#define H3_CLK_BUS_UART0 62
|
||||
#define H3_CLK_BUS_UART1 63
|
||||
#define H3_CLK_BUS_UART2 64
|
||||
#define H3_CLK_BUS_UART3 65
|
||||
#define H3_CLK_BUS_SCR 66
|
||||
#define H3_CLK_BUS_EPHY 67
|
||||
#define H3_CLK_BUS_DBG 68
|
||||
|
||||
#define H3_CLK_THS 69
|
||||
#define H3_CLK_NAND 70
|
||||
#define H3_CLK_MMC0 71
|
||||
#define H3_CLK_MMC0_SAMPLE 72
|
||||
#define H3_CLK_MMC0_OUTPUT 73
|
||||
#define H3_CLK_MMC1 74
|
||||
#define H3_CLK_MMC1_SAMPLE 75
|
||||
#define H3_CLK_MMC1_OUTPUT 76
|
||||
#define H3_CLK_MMC2 77
|
||||
#define H3_CLK_MMC2_SAMPLE 78
|
||||
#define H3_CLK_MMC2_OUTPUT 79
|
||||
#define H3_CLK_TS 80
|
||||
#define H3_CLK_CE 81
|
||||
#define H3_CLK_SPI0 82
|
||||
#define H3_CLK_SPI1 83
|
||||
#define H3_CLK_I2S0 84
|
||||
#define H3_CLK_I2S1 85
|
||||
#define H3_CLK_I2S2 86
|
||||
#define H3_CLK_SPDIF 87
|
||||
#define H3_CLK_USBPHY0 88
|
||||
#define H3_CLK_USBPHY1 89
|
||||
#define H3_CLK_USBPHY2 90
|
||||
#define H3_CLK_USBPHY3 91
|
||||
#define H3_CLK_USBOHCI0 92
|
||||
#define H3_CLK_USBOHCI1 93
|
||||
#define H3_CLK_USBOHCI2 94
|
||||
#define H3_CLK_USBOHCI3 95
|
||||
|
||||
void ccu_h3_register_clocks(struct aw_ccung_softc *sc);
|
||||
|
||||
#endif /* __CCU_H3_H__ */
|
@ -56,3 +56,8 @@ arm/allwinner/clk/aw_oscclk.c standard
|
||||
arm/allwinner/clk/aw_pll.c standard
|
||||
arm/allwinner/clk/aw_thsclk.c standard
|
||||
arm/allwinner/clk/aw_usbclk.c standard
|
||||
|
||||
arm/allwinner/clkng/aw_ccung.c standard
|
||||
arm/allwinner/clkng/aw_clk_nkmp.c standard
|
||||
arm/allwinner/clkng/aw_clk_nm.c standard
|
||||
arm/allwinner/clkng/aw_clk_prediv_mux.c standard
|
||||
|
@ -1,4 +1,5 @@
|
||||
# $FreeBSD$
|
||||
|
||||
arm/allwinner/clkng/ccu_h3.c standard
|
||||
arm/allwinner/h3/h3_padconf.c standard
|
||||
arm/allwinner/h3/h3_r_padconf.c standard
|
||||
|
Loading…
Reference in New Issue
Block a user