Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/arch/arm/sunxi Add support for gated dividers and /1, /2, ...
details: https://anonhg.NetBSD.org/src/rev/c2888f30ee47
branches: trunk
changeset: 356603:c2888f30ee47
user: jmcneill <jmcneill%NetBSD.org@localhost>
date: Thu Oct 05 01:28:47 2017 +0000
description:
Add support for gated dividers and /1,/2,/4,/6 style divider fields.
diffstat:
sys/arch/arm/sunxi/sunxi_ccu.h | 13 ++++++-
sys/arch/arm/sunxi/sunxi_ccu_div.c | 66 +++++++++++++++++++++++++++++++++++--
2 files changed, 74 insertions(+), 5 deletions(-)
diffs (148 lines):
diff -r d6868ce8ef02 -r c2888f30ee47 sys/arch/arm/sunxi/sunxi_ccu.h
--- a/sys/arch/arm/sunxi/sunxi_ccu.h Thu Oct 05 01:28:01 2017 +0000
+++ b/sys/arch/arm/sunxi/sunxi_ccu.h Thu Oct 05 01:28:47 2017 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: sunxi_ccu.h,v 1.11 2017/09/30 12:48:58 jmcneill Exp $ */
+/* $NetBSD: sunxi_ccu.h,v 1.12 2017/10/05 01:28:47 jmcneill Exp $ */
/*-
* Copyright (c) 2017 Jared McNeill <jmcneill%invisible.ca@localhost>
@@ -200,11 +200,15 @@
u_int nparents;
uint32_t div;
uint32_t sel;
+ uint32_t enable;
uint32_t flags;
#define SUNXI_CCU_DIV_POWER_OF_TWO __BIT(0)
#define SUNXI_CCU_DIV_ZERO_IS_ONE __BIT(1)
+#define SUNXI_CCU_DIV_TIMES_TWO __BIT(2)
};
+int sunxi_ccu_div_enable(struct sunxi_ccu_softc *,
+ struct sunxi_ccu_clk *, int);
u_int sunxi_ccu_div_get_rate(struct sunxi_ccu_softc *,
struct sunxi_ccu_clk *);
int sunxi_ccu_div_set_rate(struct sunxi_ccu_softc *,
@@ -217,6 +221,11 @@
#define SUNXI_CCU_DIV(_id, _name, _parents, _reg, _div, \
_sel, _flags) \
+ SUNXI_CCU_DIV_GATE(_id, _name, _parents, _reg, _div, \
+ _sel, 0, _flags)
+
+#define SUNXI_CCU_DIV_GATE(_id, _name, _parents, _reg, _div, \
+ _sel, _enable, _flags) \
[_id] = { \
.type = SUNXI_CCU_DIV, \
.base.name = (_name), \
@@ -225,7 +234,9 @@
.u.div.nparents = __arraycount(_parents), \
.u.div.div = (_div), \
.u.div.sel = (_sel), \
+ .u.div.enable = (_enable), \
.u.div.flags = (_flags), \
+ .enable = sunxi_ccu_div_enable, \
.get_rate = sunxi_ccu_div_get_rate, \
.set_rate = sunxi_ccu_div_set_rate, \
.set_parent = sunxi_ccu_div_set_parent, \
diff -r d6868ce8ef02 -r c2888f30ee47 sys/arch/arm/sunxi/sunxi_ccu_div.c
--- a/sys/arch/arm/sunxi/sunxi_ccu_div.c Thu Oct 05 01:28:01 2017 +0000
+++ b/sys/arch/arm/sunxi/sunxi_ccu_div.c Thu Oct 05 01:28:47 2017 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: sunxi_ccu_div.c,v 1.2 2017/08/25 00:07:03 jmcneill Exp $ */
+/* $NetBSD: sunxi_ccu_div.c,v 1.3 2017/10/05 01:28:47 jmcneill Exp $ */
/*-
* Copyright (c) 2017 Jared McNeill <jmcneill%invisible.ca@localhost>
@@ -27,7 +27,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sunxi_ccu_div.c,v 1.2 2017/08/25 00:07:03 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sunxi_ccu_div.c,v 1.3 2017/10/05 01:28:47 jmcneill Exp $");
#include <sys/param.h>
#include <sys/bus.h>
@@ -36,6 +36,28 @@
#include <arm/sunxi/sunxi_ccu.h>
+int
+sunxi_ccu_div_enable(struct sunxi_ccu_softc *sc, struct sunxi_ccu_clk *clk,
+ int enable)
+{
+ struct sunxi_ccu_div *div = &clk->u.div;
+ uint32_t val;
+
+ KASSERT(clk->type == SUNXI_CCU_DIV);
+
+ if (!div->enable)
+ return enable ? 0 : EINVAL;
+
+ val = CCU_READ(sc, div->reg);
+ if (enable)
+ val |= div->enable;
+ else
+ val &= ~div->enable;
+ CCU_WRITE(sc, div->reg, val);
+
+ return 0;
+}
+
u_int
sunxi_ccu_div_get_rate(struct sunxi_ccu_softc *sc,
struct sunxi_ccu_clk *clk)
@@ -66,7 +88,11 @@
ratio = 1;
if (div->flags & SUNXI_CCU_DIV_POWER_OF_TWO)
ratio = 1 << ratio;
- else
+ else if (div->flags & SUNXI_CCU_DIV_TIMES_TWO) {
+ ratio = ratio << 1;
+ if (ratio == 0)
+ ratio = 1;
+ } else
ratio++;
return rate / ratio;
@@ -76,7 +102,39 @@
sunxi_ccu_div_set_rate(struct sunxi_ccu_softc *sc,
struct sunxi_ccu_clk *clk, u_int new_rate)
{
- return EINVAL;
+ struct sunxi_ccu_div *div = &clk->u.div;
+ struct clk *clkp, *clkp_parent;
+ uint32_t val, raw_div;
+ int ratio;
+
+ KASSERT(clk->type == SUNXI_CCU_DIV);
+
+ clkp = &clk->base;
+ clkp_parent = clk_get_parent(clkp);
+ if (clkp_parent == NULL)
+ return ENXIO;
+
+ if (div->div == 0)
+ return ENXIO;
+
+ val = CCU_READ(sc, div->reg);
+
+ if ((div->flags & SUNXI_CCU_DIV_TIMES_TWO) != 0) {
+ ratio = howmany(clk_get_rate(clkp_parent), new_rate);
+ if (ratio > 1 && (ratio & 1) != 0)
+ ratio++;
+ raw_div = ratio >> 1;
+ if (raw_div > __SHIFTOUT_MASK(div->div))
+ return ERANGE;
+ } else {
+ return EINVAL;
+ }
+
+ val &= ~div->div;
+ val |= __SHIFTIN(raw_div, div->div);
+ CCU_WRITE(sc, div->reg, val);
+
+ return 0;
}
int
Home |
Main Index |
Thread Index |
Old Index