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